Commit bc4c81fb authored by Beniamino Galvani's avatar Beniamino Galvani

dhcp: merge branch 'bg/dhcp-reject-servers'

https://bugzilla.redhat.com/show_bug.cgi?id=1827410
!581
parents dbab673f b609088a
Pipeline #195259 passed with stages
in 27 minutes and 53 seconds
......@@ -2151,6 +2151,19 @@ _multilist_validate_fcn_is_domain (const char *domain, GError **error)
return domain;
}
static const char *
_multilist_validate_fcn_is_ipv4_addr_or_subnet (const char *value, GError **error)
{
if (!nm_utils_parse_inaddr_prefix_bin (AF_INET, value, NULL, NULL, NULL)) {
nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT,
_("invalid IPv4 or subnet \"%s\""),
value);
return NULL;
}
return value;
}
static gboolean
_set_fcn_gobject_bytes (ARGS_SET_FCN)
{
......@@ -3445,6 +3458,31 @@ _objlist_set_fcn_ip_config_routing_rules (NMSetting *setting,
return TRUE;
}
static guint
_multilist_get_num_fcn_ip_config_dhcp_reject_servers (NMSettingIPConfig *setting)
{
guint num;
nm_setting_ip_config_get_dhcp_reject_servers (setting, &num);
return num;
}
static gboolean
_multilist_remove_by_value_fcn_ip_config_dhcp_reject_servers (NMSettingIPConfig *setting,
const char *item)
{
const char *const *strv;
guint num;
gssize idx;
strv = nm_setting_ip_config_get_dhcp_reject_servers (setting, &num);
idx = nm_utils_strv_find_first ((char **) strv, num, item);
if (idx >= 0)
nm_setting_ip_config_remove_dhcp_reject_server (setting, idx);
return TRUE;
}
static gconstpointer
_get_fcn_olpc_mesh_ssid (ARGS_GET_FCN)
{
......@@ -5837,6 +5875,19 @@ static const NMMetaPropertyInfo *const property_infos_IP4_CONFIG[] = {
PROPERTY_INFO_WITH_DESC (NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER,
.property_type = &_pt_gobject_string,
),
PROPERTY_INFO (NM_SETTING_IP_CONFIG_DHCP_REJECT_SERVERS, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_REJECT_SERVERS,
.property_type = &_pt_multilist,
.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
PROPERTY_TYP_DATA_SUBTYPE (multilist,
.get_num_fcn_u = MULTILIST_GET_NUM_FCN_U (NMSettingIPConfig, _multilist_get_num_fcn_ip_config_dhcp_reject_servers),
.add2_fcn = MULTILIST_ADD2_FCN (NMSettingIPConfig, nm_setting_ip_config_add_dhcp_reject_server),
.remove_by_idx_fcn_u = MULTILIST_REMOVE_BY_IDX_FCN_U (NMSettingIPConfig, nm_setting_ip_config_remove_dhcp_reject_server),
.remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingIPConfig, _multilist_remove_by_value_fcn_ip_config_dhcp_reject_servers),
.validate_fcn = _multilist_validate_fcn_is_ipv4_addr_or_subnet,
.strsplit_plain = TRUE,
),
),
),
NULL
};
......
......@@ -228,6 +228,7 @@
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME_FLAGS N_("Flags for the DHCP hostname and FQDN. Currently, this property only includes flags to control the FQDN flags set in the DHCP FQDN option. Supported FQDN flags are NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) and NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE (0x4). When no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is set, the DHCP FQDN option will contain no flag. Otherwise, if no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is not set, the standard FQDN flags are set in the request: NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) for IPv4 and NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1) for IPv6. When this property is set to the default value NM_DHCP_HOSTNAME_FLAG_NONE (0x0), a global default is looked up in NetworkManager configuration. If that value is unset or also NM_DHCP_HOSTNAME_FLAG_NONE (0x0), then the standard FQDN flags described above are sent in the DHCP requests.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_IAID N_("A string containing the \"Identity Association Identifier\" (IAID) used by the DHCP client. The property is a 32-bit decimal value or a special value among \"mac\", \"perm-mac\", \"ifname\" and \"stable\". When set to \"mac\" (or \"perm-mac\"), the last 4 bytes of the current (or permanent) MAC address are used as IAID. When set to \"ifname\", the IAID is computed by hashing the interface name. The special value \"stable\" can be used to generate an IAID based on the stable-id (see connection.stable-id), a per-host key and the interface name. When the property is unset, the value from global configuration is used; if no global default is set then the IAID is assumed to be \"ifname\". Note that at the moment this property is ignored for IPv6 by dhclient, which always derives the IAID from the MAC address.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_REJECT_SERVERS N_("Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. \"192.168.122.0/24\"). This property is currently not implemented for DHCPv6.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER N_("The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server. Since 1.28")
......@@ -251,6 +252,7 @@
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME_FLAGS N_("Flags for the DHCP hostname and FQDN. Currently, this property only includes flags to control the FQDN flags set in the DHCP FQDN option. Supported FQDN flags are NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) and NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE (0x4). When no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is set, the DHCP FQDN option will contain no flag. Otherwise, if no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is not set, the standard FQDN flags are set in the request: NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) for IPv4 and NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1) for IPv6. When this property is set to the default value NM_DHCP_HOSTNAME_FLAG_NONE (0x0), a global default is looked up in NetworkManager configuration. If that value is unset or also NM_DHCP_HOSTNAME_FLAG_NONE (0x0), then the standard FQDN flags described above are sent in the DHCP requests.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_IAID N_("A string containing the \"Identity Association Identifier\" (IAID) used by the DHCP client. The property is a 32-bit decimal value or a special value among \"mac\", \"perm-mac\", \"ifname\" and \"stable\". When set to \"mac\" (or \"perm-mac\"), the last 4 bytes of the current (or permanent) MAC address are used as IAID. When set to \"ifname\", the IAID is computed by hashing the interface name. The special value \"stable\" can be used to generate an IAID based on the stable-id (see connection.stable-id), a per-host key and the interface name. When the property is unset, the value from global configuration is used; if no global default is set then the IAID is assumed to be \"ifname\". Note that at the moment this property is ignored for IPv6 by dhclient, which always derives the IAID from the MAC address.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_REJECT_SERVERS N_("Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. \"192.168.122.0/24\"). This property is currently not implemented for DHCPv6.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
......
......@@ -3633,6 +3633,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSettingIPConfig,
PROP_DAD_TIMEOUT,
PROP_DHCP_TIMEOUT,
PROP_DHCP_IAID,
PROP_DHCP_REJECT_SERVERS,
);
typedef struct {
......@@ -3642,6 +3643,7 @@ typedef struct {
GPtrArray *addresses; /* array of NMIPAddress */
GPtrArray *routes; /* array of NMIPRoute */
GPtrArray *routing_rules;
GArray *dhcp_reject_servers;
char *method;
char *gateway;
char *dhcp_hostname;
......@@ -4949,6 +4951,92 @@ nm_setting_ip_config_get_dhcp_iaid (NMSettingIPConfig *setting)
return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->dhcp_iaid;
}
/**
* nm_setting_ip_config_get_dhcp_reject_servers:
* @setting: the #NMSettingIPConfig
* @out_len: (allow-none) (out): the number of returned elements
*
* Returns: (array length=out_len zero-terminated=1) (transfer none):
* A %NULL terminated array of DHCP reject servers. Even if no reject
* servers are configured, this always returns a non %NULL value.
*
* Since: 1.28
*/
const char *const *
nm_setting_ip_config_get_dhcp_reject_servers (NMSettingIPConfig *setting, guint *out_len)
{
g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL);
return nm_strvarray_get_strv (&NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->dhcp_reject_servers,
out_len);
}
/**
* nm_setting_ip_config_add_dhcp_reject_server:
* @setting: the #NMSettingIPConfig
* @server: the DHCP reject server to add
*
* Adds a new DHCP reject server to the setting.
*
* Since: 1.28
**/
void
nm_setting_ip_config_add_dhcp_reject_server (NMSettingIPConfig *setting,
const char *server)
{
NMSettingIPConfigPrivate *priv;
g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
g_return_if_fail (server != NULL);
priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
nm_strvarray_add (nm_strvarray_ensure (&priv->dhcp_reject_servers), server);
_notify (setting, PROP_DHCP_REJECT_SERVERS);
}
/**
* nm_setting_ip_config_remove_dhcp_reject_server:
* @setting: the #NMSettingIPConfig
* @idx: index number of the DHCP reject server
*
* Removes the DHCP reject server at index @idx.
*
* Since: 1.28
**/
void
nm_setting_ip_config_remove_dhcp_reject_server (NMSettingIPConfig *setting, guint idx)
{
NMSettingIPConfigPrivate *priv;
g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
g_return_if_fail (priv->dhcp_reject_servers && idx < priv->dhcp_reject_servers->len);
g_array_remove_index (priv->dhcp_reject_servers, idx);
_notify (setting, PROP_DHCP_REJECT_SERVERS);
}
/**
* nm_setting_ip_config_clear_dhcp_reject_servers:
* @setting: the #NMSettingIPConfig
*
* Removes all configured DHCP reject servers.
*
* Since: 1.28
**/
void
nm_setting_ip_config_clear_dhcp_reject_servers (NMSettingIPConfig *setting)
{
NMSettingIPConfigPrivate *priv;
g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
if (nm_g_array_len (priv->dhcp_reject_servers) != 0) {
nm_clear_pointer (&priv->dhcp_reject_servers, g_array_unref);
_notify (setting, PROP_DHCP_REJECT_SERVERS);
}
}
static gboolean
verify_label (const char *label)
{
......@@ -5159,6 +5247,38 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
}
/* Validate reject servers */
if ( priv->dhcp_reject_servers
&& priv->dhcp_reject_servers->len != 0) {
if (NM_SETTING_IP_CONFIG_GET_FAMILY (setting) != AF_INET) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("the property is currently supported only for DHCPv4"));
g_prefix_error (error, "%s.%s: ",
nm_setting_get_name (setting),
NM_SETTING_IP_CONFIG_DHCP_REJECT_SERVERS);
return FALSE;
}
for (i = 0; i < priv->dhcp_reject_servers->len; i++) {
if (!nm_utils_parse_inaddr_prefix (NM_SETTING_IP_CONFIG_GET_FAMILY (setting),
g_array_index (priv->dhcp_reject_servers, const char *, i),
NULL,
NULL)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("'%s' is not a valid IP or subnet"),
g_array_index (priv->dhcp_reject_servers, const char *, i));
g_prefix_error (error, "%s.%s: ",
nm_setting_get_name (setting),
NM_SETTING_IP_CONFIG_DHCP_REJECT_SERVERS);
return FALSE;
}
}
}
/* Normalizable errors */
if (priv->gateway && priv->never_default) {
g_set_error (error,
......@@ -5434,6 +5554,9 @@ get_property (GObject *object, guint prop_id,
case PROP_DHCP_HOSTNAME_FLAGS:
g_value_set_uint (value, nm_setting_ip_config_get_dhcp_hostname_flags (setting));
break;
case PROP_DHCP_REJECT_SERVERS:
g_value_set_boxed (value, nm_strvarray_get_strv_non_empty (priv->dhcp_reject_servers, NULL));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -5540,6 +5663,9 @@ set_property (GObject *object, guint prop_id,
case PROP_DHCP_HOSTNAME_FLAGS:
priv->dhcp_hostname_flags = g_value_get_uint (value);
break;
case PROP_DHCP_REJECT_SERVERS:
nm_strvarray_set_strv (&priv->dhcp_reject_servers, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -5582,6 +5708,7 @@ finalize (GObject *object)
g_ptr_array_unref (priv->routes);
if (priv->routing_rules)
g_ptr_array_unref (priv->routing_rules);
nm_clear_pointer (&priv->dhcp_reject_servers, g_array_unref);
G_OBJECT_CLASS (nm_setting_ip_config_parent_class)->finalize (object);
}
......@@ -6004,5 +6131,24 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* NMSettingIPConfig:dhcp-reject-servers:
*
* Array of servers from which DHCP offers must be rejected. This property
* is useful to avoid getting a lease from misconfigured or rogue servers.
*
* For DHCPv4, each element must be an IPv4 address, optionally
* followed by a slash and a prefix length (e.g. "192.168.122.0/24").
*
* This property is currently not implemented for DHCPv6.
*
* Since: 1.28
**/
obj_properties[PROP_DHCP_REJECT_SERVERS] =
g_param_spec_boxed (NM_SETTING_IP_CONFIG_DHCP_REJECT_SERVERS, "", "",
G_TYPE_STRV,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
}
......@@ -350,6 +350,7 @@ char *nm_ip_routing_rule_to_string (const NMIPRoutingRule *self,
#define NM_SETTING_IP_CONFIG_DAD_TIMEOUT "dad-timeout"
#define NM_SETTING_IP_CONFIG_DHCP_TIMEOUT "dhcp-timeout"
#define NM_SETTING_IP_CONFIG_DHCP_IAID "dhcp-iaid"
#define NM_SETTING_IP_CONFIG_DHCP_REJECT_SERVERS "dhcp-reject-servers"
/* these are not real GObject properties. */
#define NM_SETTING_IP_CONFIG_ROUTING_RULES "routing-rules"
......@@ -529,6 +530,19 @@ const char *nm_setting_ip_config_get_dhcp_iaid (NMSettingIPConfig
NM_AVAILABLE_IN_1_22
NMDhcpHostnameFlags nm_setting_ip_config_get_dhcp_hostname_flags (NMSettingIPConfig *setting);
NM_AVAILABLE_IN_1_28
const char *const *nm_setting_ip_config_get_dhcp_reject_servers (NMSettingIPConfig *setting,
guint *out_len);
NM_AVAILABLE_IN_1_28
void nm_setting_ip_config_add_dhcp_reject_server (NMSettingIPConfig *setting,
const char *server);
NM_AVAILABLE_IN_1_28
void nm_setting_ip_config_remove_dhcp_reject_server (NMSettingIPConfig *setting,
guint idx);
NM_AVAILABLE_IN_1_28
void nm_setting_ip_config_clear_dhcp_reject_servers (NMSettingIPConfig *setting);
G_END_DECLS
#endif /* NM_SETTING_IP_CONFIG_H */
......@@ -139,22 +139,15 @@ gboolean
nm_setting_match_remove_interface_name_by_value (NMSettingMatch *setting,
const char *interface_name)
{
guint i;
g_return_val_if_fail (NM_IS_SETTING_MATCH (setting), FALSE);
g_return_val_if_fail (interface_name != NULL, FALSE);
g_return_val_if_fail (interface_name[0] != '\0', FALSE);
if (!setting->interface_name)
return FALSE;
for (i = 0; i < setting->interface_name->len; i++) {
if (nm_streq (interface_name, g_array_index (setting->interface_name, const char *, i))) {
g_array_remove_index (setting->interface_name, i);
_notify (setting, PROP_INTERFACE_NAME);
return TRUE;
}
if (nm_strvarray_remove_first (setting->interface_name, interface_name)) {
_notify (setting, PROP_INTERFACE_NAME);
return TRUE;
}
return FALSE;
}
......@@ -292,22 +285,15 @@ gboolean
nm_setting_match_remove_kernel_command_line_by_value (NMSettingMatch *setting,
const char *kernel_command_line)
{
guint i;
g_return_val_if_fail (NM_IS_SETTING_MATCH (setting), FALSE);
g_return_val_if_fail (kernel_command_line != NULL, FALSE);
g_return_val_if_fail (kernel_command_line[0] != '\0', FALSE);
if (!setting->kernel_command_line)
return FALSE;
for (i = 0; i < setting->kernel_command_line->len; i++) {
if (nm_streq (kernel_command_line, g_array_index (setting->kernel_command_line, const char *, i))) {
g_array_remove_index (setting->kernel_command_line, i);
_notify (setting, PROP_KERNEL_COMMAND_LINE);
return TRUE;
}
if (nm_strvarray_remove_first (setting->kernel_command_line, kernel_command_line)) {
_notify (setting, PROP_KERNEL_COMMAND_LINE);
return TRUE;
}
return FALSE;
}
......@@ -442,22 +428,15 @@ gboolean
nm_setting_match_remove_driver_by_value (NMSettingMatch *setting,
const char *driver)
{
guint i;
g_return_val_if_fail (NM_IS_SETTING_MATCH (setting), FALSE);
g_return_val_if_fail (driver != NULL, FALSE);
g_return_val_if_fail (driver[0] != '\0', FALSE);
if (!setting->driver)
return FALSE;
for (i = 0; i < setting->driver->len; i++) {
if (nm_streq (driver, g_array_index (setting->driver, const char *, i))) {
g_array_remove_index (setting->driver, i);
_notify (setting, PROP_DRIVER);
return TRUE;
}
if (nm_strvarray_remove_first (setting->driver, driver)) {
_notify (setting, PROP_DRIVER);
return TRUE;
}
return FALSE;
}
......@@ -592,22 +571,15 @@ gboolean
nm_setting_match_remove_path_by_value (NMSettingMatch *setting,
const char *path)
{
guint i;
g_return_val_if_fail (NM_IS_SETTING_MATCH (setting), FALSE);
g_return_val_if_fail (path != NULL, FALSE);
g_return_val_if_fail (path[0] != '\0', FALSE);
if (!setting->path)
return FALSE;
for (i = 0; i < setting->path->len; i++) {
if (nm_streq (path, g_array_index (setting->path, const char *, i))) {
g_array_remove_index (setting->path, i);
_notify (setting, PROP_PATH);
return TRUE;
}
if (nm_strvarray_remove_first (setting->path, path)) {
_notify (setting, PROP_PATH);
return TRUE;
}
return FALSE;
}
......
......@@ -3388,6 +3388,7 @@ test_connection_diff_a_only (void)
{ NM_SETTING_IP_CONFIG_DNS_PRIORITY, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_DHCP_IAID, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_DHCP_REJECT_SERVERS, NM_SETTING_DIFF_RESULT_IN_A },
{ NULL, NM_SETTING_DIFF_RESULT_UNKNOWN },
} },
};
......
......@@ -1749,5 +1749,9 @@ global:
libnm_1_28_0 {
global:
nm_setting_ip_config_add_dhcp_reject_server;
nm_setting_ip_config_clear_dhcp_reject_servers;
nm_setting_ip_config_get_dhcp_reject_servers;
nm_setting_ip_config_remove_dhcp_reject_server;
nm_setting_wireless_get_ap_isolation;
} libnm_1_26_4;
......@@ -36,6 +36,7 @@ global:
n_dhcp4_client_lease_get_yiaddr;
n_dhcp4_client_lease_get_siaddr;
n_dhcp4_client_lease_get_lifetime;
n_dhcp4_client_lease_get_server_identifier;
n_dhcp4_client_lease_query;
n_dhcp4_client_lease_select;
n_dhcp4_client_lease_accept;
......
......@@ -241,6 +241,32 @@ _c_public_ void n_dhcp4_client_lease_get_lifetime(NDhcp4ClientLease *lease, uint
*ns_lifetimep = lease->lifetime;
}
/**
* n_dhcp4_client_lease_get_server_identifier() - get the server identifier
* @lease: the lease to operate on
* @addr: return argument for the server identifier
*
* Gets the address contained in the server-identifier DHCP option, in network
* byte order.
*
* Return: 0 on success, negative error code on failure.
*/
_c_public_ int n_dhcp4_client_lease_get_server_identifier (NDhcp4ClientLease *lease, struct in_addr *addr) {
uint8_t *data;
size_t n_data;
int r;
r = n_dhcp4_incoming_query(lease->message, N_DHCP4_OPTION_SERVER_IDENTIFIER, &data, &n_data);
if (r)
return r;
if (n_data < sizeof(struct in_addr))
return N_DHCP4_E_MALFORMED;
memcpy(addr, data, sizeof(struct in_addr));
return 0;
}
/**
* n_dhcp4_client_lease_query() - query the lease for an option
* @lease: the lease to operate on
......
......@@ -171,6 +171,7 @@ void n_dhcp4_client_lease_get_siaddr(NDhcp4ClientLease *lease, struct in_addr *s
void n_dhcp4_client_lease_get_basetime(NDhcp4ClientLease *lease, uint64_t *ns_basetimep);
void n_dhcp4_client_lease_get_lifetime(NDhcp4ClientLease *lease, uint64_t *ns_lifetimep);
int n_dhcp4_client_lease_query(NDhcp4ClientLease *lease, uint8_t option, uint8_t **datap, size_t *n_datap);
int n_dhcp4_client_lease_get_server_identifier (NDhcp4ClientLease *lease, struct in_addr *addr);
int n_dhcp4_client_lease_select(NDhcp4ClientLease *lease);
int n_dhcp4_client_lease_accept(NDhcp4ClientLease *lease);
......
......@@ -2190,6 +2190,24 @@ nm_strvarray_set_strv (GArray **array, const char *const*strv)
nm_strvarray_add (*array, strv[0]);
}
static inline gboolean
nm_strvarray_remove_first (GArray *strv, const char *needle)
{
guint i;
nm_assert (needle);
if (strv) {
for (i = 0; i < strv->len; i++) {
if (nm_streq (needle, g_array_index (strv, const char *, i))) {
g_array_remove_index (strv, i);
return TRUE;
}
}
}
return FALSE;
}
/*****************************************************************************/
struct _NMVariantAttributeSpec {
......
......@@ -8876,6 +8876,7 @@ dhcp4_start (NMDevice *self)
NMSettingConnection *s_con;
GError *error = NULL;
const NMPlatformLink *pllink;
const char *const *reject_servers;
connection = nm_device_get_applied_connection (self);
g_return_val_if_fail (connection, FALSE);
......@@ -8898,6 +8899,7 @@ dhcp4_start (NMDevice *self)
client_id = dhcp4_get_client_id (self, connection, hwaddr);
vendor_class_identifier
= dhcp4_get_vendor_class_identifier (self, NM_SETTING_IP4_CONFIG (s_ip4));
reject_servers = nm_setting_ip_config_get_dhcp_reject_servers (s_ip4, NULL);
g_warn_if_fail (priv->dhcp_data_4.client == NULL);
priv->dhcp_data_4.client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (),
......@@ -8919,6 +8921,7 @@ dhcp4_start (NMDevice *self)
priv->dhcp_anycast_address,
NULL,
vendor_class_identifier,
reject_servers,
&error);
if (!priv->dhcp_data_4.client) {
_LOGW (LOGD_DHCP4, "failure to start DHCP: %s", error->message);
......
......@@ -52,6 +52,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDhcpClient,
PROP_HOSTNAME_FLAGS,
PROP_MUD_URL,
PROP_VENDOR_CLASS_IDENTIFIER,
PROP_REJECT_SERVERS,
);
typedef struct _NMDhcpClientPrivate {
......@@ -62,6 +63,7 @@ typedef struct _NMDhcpClientPrivate {
char * uuid;
GBytes * client_id;
char * hostname;
const char **reject_servers;
char * mud_url;
GBytes * vendor_class_identifier;
pid_t pid;
......@@ -332,6 +334,14 @@ nm_dhcp_client_get_vendor_class_identifier (NMDhcpClient *self)
return NM_DHCP_CLIENT_GET_PRIVATE (self)->vendor_class_identifier;
}
const char *const *
nm_dhcp_client_get_reject_servers (NMDhcpClient *self)
{
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
return (const char *const *) NM_DHCP_CLIENT_GET_PRIVATE (self)->reject_servers;
}
/*****************************************************************************/
static const char *state_table[NM_DHCP_STATE_MAX + 1] = {
......@@ -954,6 +964,38 @@ nm_dhcp_client_handle_event (gpointer unused,
return TRUE;
}
gboolean
nm_dhcp_client_server_id_is_rejected (NMDhcpClient *self, gconstpointer addr)
{
NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
in_addr_t addr4 = *(in_addr_t *) addr;
guint i;
/* IPv6 not implemented yet */
nm_assert (priv->addr_family == AF_INET);
if (!priv->reject_servers || !priv->reject_servers[0])
return FALSE;
for (i = 0; priv->reject_servers[i]; i++) {
in_addr_t r_addr;
in_addr_t mask;
int r_prefix;
if (!nm_utils_parse_inaddr_prefix_bin (AF_INET,
priv->reject_servers[i],
NULL,
&r_addr,
&r_prefix))