mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-26 22:50:08 +01:00
merge: DHCP client code cleanups and simplification (bgo #732965)
In preparation for library-based DHCP clients, remove some assupmtions that all DHCP clients are subprocesses, and that all DHCP options get passed back NM via D-Bus. https://bugzilla.gnome.org/show_bug.cgi?id=732965
This commit is contained in:
commit
afebbb6ef8
14 changed files with 1897 additions and 2263 deletions
|
|
@ -97,6 +97,8 @@ nm_sources = \
|
|||
\
|
||||
dhcp-manager/nm-dhcp-client.c \
|
||||
dhcp-manager/nm-dhcp-client.h \
|
||||
dhcp-manager/nm-dhcp-utils.c \
|
||||
dhcp-manager/nm-dhcp-utils.h \
|
||||
dhcp-manager/nm-dhcp-dhclient.c \
|
||||
dhcp-manager/nm-dhcp-dhclient.h \
|
||||
dhcp-manager/nm-dhcp-dhclient-utils.c \
|
||||
|
|
|
|||
|
|
@ -241,7 +241,6 @@ typedef struct {
|
|||
/* DHCPv4 tracking */
|
||||
NMDHCPClient * dhcp4_client;
|
||||
gulong dhcp4_state_sigid;
|
||||
gulong dhcp4_timeout_sigid;
|
||||
NMDHCP4Config * dhcp4_config;
|
||||
NMIP4Config * vpn4_config; /* routes added by a VPN which uses this device */
|
||||
|
||||
|
|
@ -279,7 +278,6 @@ typedef struct {
|
|||
NMDHCPClient * dhcp6_client;
|
||||
NMRDiscDHCPLevel dhcp6_mode;
|
||||
gulong dhcp6_state_sigid;
|
||||
gulong dhcp6_timeout_sigid;
|
||||
NMDHCP6Config * dhcp6_config;
|
||||
/* IP6 config from DHCP */
|
||||
NMIP6Config * dhcp6_ip6_config;
|
||||
|
|
@ -2591,11 +2589,6 @@ dhcp4_cleanup (NMDevice *self, gboolean stop, gboolean release)
|
|||
priv->dhcp4_state_sigid = 0;
|
||||
}
|
||||
|
||||
if (priv->dhcp4_timeout_sigid) {
|
||||
g_signal_handler_disconnect (priv->dhcp4_client, priv->dhcp4_timeout_sigid);
|
||||
priv->dhcp4_timeout_sigid = 0;
|
||||
}
|
||||
|
||||
nm_device_remove_pending_action (self, PENDING_ACTION_DHCP4, FALSE);
|
||||
|
||||
if (stop)
|
||||
|
|
@ -2610,14 +2603,6 @@ dhcp4_cleanup (NMDevice *self, gboolean stop, gboolean release)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp4_add_option_cb (gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
nm_dhcp4_config_add_option (NM_DHCP4_CONFIG (user_data),
|
||||
(const char *) key,
|
||||
(const char *) value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_config_merge_and_apply (NMDevice *self,
|
||||
NMIP4Config *config,
|
||||
|
|
@ -2689,35 +2674,48 @@ dhcp4_fail (NMDevice *device, gboolean timeout)
|
|||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
|
||||
|
||||
nm_dhcp4_config_reset (priv->dhcp4_config);
|
||||
|
||||
dhcp4_cleanup (device, TRUE, FALSE);
|
||||
if (timeout || (priv->ip4_state == IP_CONF))
|
||||
nm_device_activate_schedule_ip4_config_timeout (device);
|
||||
else if (priv->ip4_state == IP_FAIL)
|
||||
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp4_update_config (NMDevice *self, NMDHCP4Config *config, GHashTable *options)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
const char *key, *value;
|
||||
|
||||
/* Update the DHCP4 config object with new DHCP options */
|
||||
nm_dhcp4_config_reset (config);
|
||||
|
||||
g_hash_table_iter_init (&iter, options);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value))
|
||||
nm_dhcp4_config_add_option (config, key, value);
|
||||
|
||||
g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP4_CONFIG);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp4_state_changed (NMDHCPClient *client,
|
||||
NMDHCPState state,
|
||||
NMDhcpState state,
|
||||
NMIP4Config *ip4_config,
|
||||
GHashTable *options,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMDevice *device = NM_DEVICE (user_data);
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
|
||||
NMIP4Config *config;
|
||||
|
||||
g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == FALSE);
|
||||
g_return_if_fail (!ip4_config || NM_IS_IP4_CONFIG (ip4_config));
|
||||
|
||||
nm_log_dbg (LOGD_DHCP4, "(%s): new DHCPv4 client state %d",
|
||||
nm_device_get_iface (device), state);
|
||||
|
||||
switch (state) {
|
||||
case DHC_BOUND4: /* lease obtained */
|
||||
case DHC_RENEW4: /* lease renewed */
|
||||
case DHC_REBOOT: /* have valid lease, but now obtained a different one */
|
||||
case DHC_REBIND4: /* new, different lease */
|
||||
config = nm_dhcp_client_get_ip4_config (priv->dhcp4_client, FALSE);
|
||||
if (!config) {
|
||||
case NM_DHCP_STATE_BOUND:
|
||||
if (!ip4_config) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): failed to get IPv4 config in response to DHCP event.",
|
||||
nm_device_get_ip_iface (device));
|
||||
nm_device_state_changed (device,
|
||||
|
|
@ -2726,26 +2724,18 @@ dhcp4_state_changed (NMDHCPClient *client,
|
|||
break;
|
||||
}
|
||||
|
||||
/* Update the DHCP4 config object with new DHCP options */
|
||||
nm_dhcp4_config_reset (priv->dhcp4_config);
|
||||
nm_dhcp_client_foreach_option (priv->dhcp4_client,
|
||||
dhcp4_add_option_cb,
|
||||
priv->dhcp4_config);
|
||||
g_object_notify (G_OBJECT (device), NM_DEVICE_DHCP4_CONFIG);
|
||||
dhcp4_update_config (device, priv->dhcp4_config, options);
|
||||
|
||||
if (priv->ip4_state == IP_CONF)
|
||||
nm_device_activate_schedule_ip4_config_result (device, config);
|
||||
nm_device_activate_schedule_ip4_config_result (device, ip4_config);
|
||||
else if (priv->ip4_state == IP_DONE)
|
||||
dhcp4_lease_change (device, config);
|
||||
g_object_unref (config);
|
||||
|
||||
dhcp4_lease_change (device, ip4_config);
|
||||
break;
|
||||
case DHC_TIMEOUT: /* timed out contacting DHCP server */
|
||||
case NM_DHCP_STATE_TIMEOUT:
|
||||
dhcp4_fail (device, TRUE);
|
||||
break;
|
||||
case DHC_END: /* dhclient exited normally */
|
||||
case DHC_FAIL: /* all attempts to contact server timed out, sleeping */
|
||||
case DHC_ABEND: /* dhclient exited abnormally */
|
||||
case NM_DHCP_STATE_DONE:
|
||||
case NM_DHCP_STATE_FAIL:
|
||||
/* dhclient quit and can't get/renew a lease; so kill the connection */
|
||||
dhcp4_fail (device, FALSE);
|
||||
break;
|
||||
|
|
@ -2754,18 +2744,6 @@ dhcp4_state_changed (NMDHCPClient *client,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp4_timeout (NMDHCPClient *client, gpointer user_data)
|
||||
{
|
||||
NMDevice *device = NM_DEVICE (user_data);
|
||||
|
||||
g_return_if_fail (nm_device_get_act_request (device) != NULL);
|
||||
g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == FALSE);
|
||||
|
||||
nm_dhcp_client_stop (client, FALSE);
|
||||
dhcp4_fail (device, TRUE);
|
||||
}
|
||||
|
||||
static NMActStageReturn
|
||||
dhcp4_start (NMDevice *self,
|
||||
NMConnection *connection,
|
||||
|
|
@ -2791,10 +2769,13 @@ dhcp4_start (NMDevice *self,
|
|||
g_warn_if_fail (priv->dhcp4_client == NULL);
|
||||
priv->dhcp4_client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (),
|
||||
nm_device_get_ip_iface (self),
|
||||
nm_device_get_ip_ifindex (self),
|
||||
tmp,
|
||||
nm_connection_get_uuid (connection),
|
||||
nm_device_get_priority (self),
|
||||
s_ip4,
|
||||
nm_setting_ip4_config_get_dhcp_send_hostname (s_ip4),
|
||||
nm_setting_ip4_config_get_dhcp_hostname (s_ip4),
|
||||
nm_setting_ip4_config_get_dhcp_client_id (s_ip4),
|
||||
priv->dhcp_timeout,
|
||||
priv->dhcp_anycast_address);
|
||||
|
||||
|
|
@ -2810,10 +2791,6 @@ dhcp4_start (NMDevice *self,
|
|||
NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
|
||||
G_CALLBACK (dhcp4_state_changed),
|
||||
self);
|
||||
priv->dhcp4_timeout_sigid = g_signal_connect (priv->dhcp4_client,
|
||||
NM_DHCP_CLIENT_SIGNAL_TIMEOUT,
|
||||
G_CALLBACK (dhcp4_timeout),
|
||||
self);
|
||||
|
||||
nm_device_add_pending_action (self, PENDING_ACTION_DHCP4, TRUE);
|
||||
|
||||
|
|
@ -3037,11 +3014,6 @@ dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release)
|
|||
priv->dhcp6_state_sigid = 0;
|
||||
}
|
||||
|
||||
if (priv->dhcp6_timeout_sigid) {
|
||||
g_signal_handler_disconnect (priv->dhcp6_client, priv->dhcp6_timeout_sigid);
|
||||
priv->dhcp6_timeout_sigid = 0;
|
||||
}
|
||||
|
||||
nm_device_remove_pending_action (self, PENDING_ACTION_DHCP6, FALSE);
|
||||
|
||||
if (stop)
|
||||
|
|
@ -3056,14 +3028,6 @@ dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp6_add_option_cb (gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
nm_dhcp6_config_add_option (NM_DHCP6_CONFIG (user_data),
|
||||
(const char *) key,
|
||||
(const char *) value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_config_merge_and_apply (NMDevice *self,
|
||||
gboolean commit,
|
||||
|
|
@ -3139,43 +3103,67 @@ dhcp6_fail (NMDevice *device, gboolean timeout)
|
|||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
|
||||
|
||||
nm_dhcp6_config_reset (priv->dhcp6_config);
|
||||
|
||||
dhcp6_cleanup (device, TRUE, FALSE);
|
||||
if (timeout || (priv->ip6_state == IP_CONF))
|
||||
nm_device_activate_schedule_ip6_config_timeout (device);
|
||||
else if (priv->ip6_state == IP_FAIL)
|
||||
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp6_timeout (NMDevice *self, NMDHCPClient *client)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_MANAGED)
|
||||
dhcp6_fail (self, TRUE);
|
||||
else {
|
||||
/* not a hard failure; just live with the RA info */
|
||||
dhcp6_cleanup (self, TRUE, FALSE);
|
||||
if (priv->ip6_state == IP_CONF)
|
||||
nm_device_activate_schedule_ip6_config_result (self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp6_update_config (NMDevice *self, NMDHCP6Config *config, GHashTable *options)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
const char *key, *value;
|
||||
|
||||
/* Update the DHCP6 config object with new DHCP options */
|
||||
nm_dhcp6_config_reset (config);
|
||||
|
||||
g_hash_table_iter_init (&iter, options);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value))
|
||||
nm_dhcp6_config_add_option (config, key, value);
|
||||
|
||||
g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp6_state_changed (NMDHCPClient *client,
|
||||
NMDHCPState state,
|
||||
NMDhcpState state,
|
||||
NMIP6Config *ip6_config,
|
||||
GHashTable *options,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMDevice *device = NM_DEVICE (user_data);
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
|
||||
|
||||
g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == TRUE);
|
||||
g_return_if_fail (!ip6_config || NM_IS_IP6_CONFIG (ip6_config));
|
||||
|
||||
nm_log_dbg (LOGD_DHCP6, "(%s): new DHCPv6 client state %d",
|
||||
nm_device_get_iface (device), state);
|
||||
|
||||
switch (state) {
|
||||
case DHC_BOUND6:
|
||||
case DHC_RENEW6: /* lease renewed */
|
||||
case DHC_REBOOT: /* have valid lease, but now obtained a different one */
|
||||
case DHC_REBIND6: /* new, different lease */
|
||||
case NM_DHCP_STATE_BOUND:
|
||||
g_clear_object (&priv->dhcp6_ip6_config);
|
||||
priv->dhcp6_ip6_config = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, FALSE);
|
||||
|
||||
/* Update the DHCP6 config object with new DHCP options */
|
||||
nm_dhcp6_config_reset (priv->dhcp6_config);
|
||||
if (priv->dhcp6_ip6_config) {
|
||||
nm_dhcp_client_foreach_option (priv->dhcp6_client,
|
||||
dhcp6_add_option_cb,
|
||||
priv->dhcp6_config);
|
||||
if (ip6_config) {
|
||||
priv->dhcp6_ip6_config = g_object_ref (ip6_config);
|
||||
dhcp6_update_config (device, priv->dhcp6_config, options);
|
||||
}
|
||||
g_object_notify (G_OBJECT (device), NM_DEVICE_DHCP6_CONFIG);
|
||||
|
||||
if (priv->ip6_state == IP_CONF) {
|
||||
if (priv->dhcp6_ip6_config == NULL) {
|
||||
|
|
@ -3187,10 +3175,10 @@ dhcp6_state_changed (NMDHCPClient *client,
|
|||
} else if (priv->ip6_state == IP_DONE)
|
||||
dhcp6_lease_change (device);
|
||||
break;
|
||||
case DHC_TIMEOUT: /* timed out contacting DHCP server */
|
||||
dhcp6_fail (device, TRUE);
|
||||
case NM_DHCP_STATE_TIMEOUT:
|
||||
dhcp6_timeout (device, client);
|
||||
break;
|
||||
case DHC_END: /* dhclient exited normally */
|
||||
case NM_DHCP_STATE_DONE:
|
||||
/* In IPv6 info-only mode, the client doesn't handle leases so it
|
||||
* may exit right after getting a response from the server. That's
|
||||
* normal. In that case we just ignore the exit.
|
||||
|
|
@ -3198,8 +3186,7 @@ dhcp6_state_changed (NMDHCPClient *client,
|
|||
if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_OTHERCONF)
|
||||
break;
|
||||
/* Otherwise, fall through */
|
||||
case DHC_FAIL: /* all attempts to contact server timed out, sleeping */
|
||||
case DHC_ABEND: /* dhclient exited abnormally */
|
||||
case NM_DHCP_STATE_FAIL:
|
||||
/* dhclient quit and can't get/renew a lease; so kill the connection */
|
||||
dhcp6_fail (device, FALSE);
|
||||
break;
|
||||
|
|
@ -3208,30 +3195,6 @@ dhcp6_state_changed (NMDHCPClient *client,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp6_timeout (NMDHCPClient *client, gpointer user_data)
|
||||
{
|
||||
NMDevice *device = NM_DEVICE (user_data);
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
|
||||
|
||||
g_return_if_fail (nm_device_get_act_request (device) != NULL);
|
||||
g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == TRUE);
|
||||
|
||||
nm_dhcp_client_stop (client, FALSE);
|
||||
if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_MANAGED)
|
||||
dhcp6_fail (device, TRUE);
|
||||
else {
|
||||
/* not a hard failure; just live with the RA info */
|
||||
nm_dhcp6_config_reset (priv->dhcp6_config);
|
||||
if (priv->dhcp6_ip6_config)
|
||||
g_object_unref (priv->dhcp6_ip6_config);
|
||||
priv->dhcp6_ip6_config = NULL;
|
||||
|
||||
if (priv->ip6_state == IP_CONF)
|
||||
nm_device_activate_schedule_ip6_config_result (device);
|
||||
}
|
||||
}
|
||||
|
||||
static NMActStageReturn
|
||||
dhcp6_start (NMDevice *self,
|
||||
NMConnection *connection,
|
||||
|
|
@ -3248,7 +3211,8 @@ dhcp6_start (NMDevice *self,
|
|||
g_assert (connection);
|
||||
}
|
||||
|
||||
/* Begin a DHCP transaction on the interface */
|
||||
s_ip6 = nm_connection_get_setting_ip6_config (connection);
|
||||
g_assert (s_ip6);
|
||||
|
||||
/* Clear old exported DHCP options */
|
||||
if (priv->dhcp6_config)
|
||||
|
|
@ -3268,13 +3232,15 @@ dhcp6_start (NMDevice *self,
|
|||
|
||||
priv->dhcp6_client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (),
|
||||
nm_device_get_ip_iface (self),
|
||||
nm_device_get_ip_ifindex (self),
|
||||
tmp,
|
||||
nm_connection_get_uuid (connection),
|
||||
nm_device_get_priority (self),
|
||||
nm_connection_get_setting_ip6_config (connection),
|
||||
nm_setting_ip6_config_get_dhcp_hostname (s_ip6),
|
||||
priv->dhcp_timeout,
|
||||
priv->dhcp_anycast_address,
|
||||
(dhcp_opt == NM_RDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE);
|
||||
(dhcp_opt == NM_RDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE,
|
||||
nm_setting_ip6_config_get_ip6_privacy (s_ip6));
|
||||
if (tmp)
|
||||
g_byte_array_free (tmp, TRUE);
|
||||
|
||||
|
|
@ -3283,10 +3249,6 @@ dhcp6_start (NMDevice *self,
|
|||
NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
|
||||
G_CALLBACK (dhcp6_state_changed),
|
||||
self);
|
||||
priv->dhcp6_timeout_sigid = g_signal_connect (priv->dhcp6_client,
|
||||
NM_DHCP_CLIENT_SIGNAL_TIMEOUT,
|
||||
G_CALLBACK (dhcp6_timeout),
|
||||
self);
|
||||
|
||||
s_ip6 = nm_connection_get_setting_ip6_config (connection);
|
||||
if (!nm_setting_ip6_config_get_may_fail (s_ip6) ||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -35,43 +35,24 @@
|
|||
#define NM_DHCP_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_CLIENT, NMDHCPClientClass))
|
||||
|
||||
#define NM_DHCP_CLIENT_INTERFACE "iface"
|
||||
#define NM_DHCP_CLIENT_IFINDEX "ifindex"
|
||||
#define NM_DHCP_CLIENT_HWADDR "hwaddr"
|
||||
#define NM_DHCP_CLIENT_IPV6 "ipv6"
|
||||
#define NM_DHCP_CLIENT_UUID "uuid"
|
||||
#define NM_DHCP_CLIENT_PRIORITY "priority"
|
||||
#define NM_DHCP_CLIENT_TIMEOUT "timeout"
|
||||
|
||||
#define NM_DHCP_CLIENT_SIGNAL_TIMEOUT "timeout"
|
||||
#define NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED "state-changed"
|
||||
#define NM_DHCP_CLIENT_SIGNAL_REMOVE "remove"
|
||||
|
||||
typedef enum {
|
||||
DHC_NBI = 0, /* no broadcast interfaces found */
|
||||
DHC_PREINIT, /* configuration started */
|
||||
DHC_PREINIT6, /* configuration started */
|
||||
DHC_BOUND4, /* IPv4 lease obtained */
|
||||
DHC_BOUND6, /* IPv6 lease obtained */
|
||||
DHC_IPV4LL, /* IPv4LL address obtained */
|
||||
DHC_RENEW4, /* IPv4 lease renewed */
|
||||
DHC_RENEW6, /* IPv6 lease renewed */
|
||||
DHC_REBOOT, /* have valid lease, but now obtained a different one */
|
||||
DHC_REBIND4, /* IPv4 new/different lease */
|
||||
DHC_REBIND6, /* IPv6 new/different lease */
|
||||
DHC_DEPREF6, /* IPv6 lease depreferred */
|
||||
DHC_STOP, /* remove old lease */
|
||||
DHC_STOP6, /* remove old lease */
|
||||
DHC_MEDIUM, /* media selection begun */
|
||||
DHC_TIMEOUT, /* timed out contacting DHCP server */
|
||||
DHC_FAIL, /* all attempts to contact server timed out, sleeping */
|
||||
DHC_EXPIRE, /* lease has expired, renewing */
|
||||
DHC_EXPIRE6, /* lease has expired, renewing */
|
||||
DHC_RELEASE, /* releasing lease */
|
||||
DHC_RELEASE6, /* releasing lease */
|
||||
DHC_START, /* sent when dhclient started OK */
|
||||
DHC_ABEND, /* dhclient exited abnormally */
|
||||
DHC_END, /* dhclient exited normally */
|
||||
DHC_END_OPTIONS, /* last option in subscription sent */
|
||||
} NMDHCPState;
|
||||
NM_DHCP_STATE_UNKNOWN = 0,
|
||||
NM_DHCP_STATE_BOUND, /* lease changed (state_is_bound) */
|
||||
NM_DHCP_STATE_TIMEOUT, /* TIMEOUT */
|
||||
NM_DHCP_STATE_DONE, /* END */
|
||||
NM_DHCP_STATE_FAIL, /* failed or quit unexpectedly */
|
||||
__NM_DHCP_STATE_MAX,
|
||||
NM_DHCP_STATE_MAX = __NM_DHCP_STATE_MAX - 1,
|
||||
} NMDhcpState;
|
||||
|
||||
typedef struct {
|
||||
GObject parent;
|
||||
|
|
@ -82,20 +63,21 @@ typedef struct {
|
|||
|
||||
/* Methods */
|
||||
|
||||
GPid (*ip4_start) (NMDHCPClient *self,
|
||||
const char *dhcp_client_id,
|
||||
GByteArray *anycast_addr,
|
||||
const char *hostname);
|
||||
gboolean (*ip4_start) (NMDHCPClient *self,
|
||||
const char *dhcp_client_id,
|
||||
GByteArray *anycast_addr,
|
||||
const char *hostname);
|
||||
|
||||
GPid (*ip6_start) (NMDHCPClient *self,
|
||||
GByteArray *anycast_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only,
|
||||
const GByteArray *duid);
|
||||
gboolean (*ip6_start) (NMDHCPClient *self,
|
||||
GByteArray *anycast_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const GByteArray *duid);
|
||||
|
||||
void (*stop) (NMDHCPClient *self,
|
||||
gboolean release,
|
||||
const GByteArray *duid);
|
||||
void (*stop) (NMDHCPClient *self,
|
||||
gboolean release,
|
||||
const GByteArray *duid);
|
||||
|
||||
/**
|
||||
* get_duid:
|
||||
|
|
@ -109,21 +91,30 @@ typedef struct {
|
|||
GByteArray * (*get_duid) (NMDHCPClient *self);
|
||||
|
||||
/* Signals */
|
||||
void (*state_changed) (NMDHCPClient *self, NMDHCPState state);
|
||||
void (*timeout) (NMDHCPClient *self);
|
||||
void (*remove) (NMDHCPClient *self);
|
||||
void (*state_changed) (NMDHCPClient *self,
|
||||
NMDhcpState state,
|
||||
GObject *ip_config,
|
||||
GHashTable *options);
|
||||
} NMDHCPClientClass;
|
||||
|
||||
GType nm_dhcp_client_get_type (void);
|
||||
|
||||
GPid nm_dhcp_client_get_pid (NMDHCPClient *self);
|
||||
pid_t nm_dhcp_client_get_pid (NMDHCPClient *self);
|
||||
|
||||
const char *nm_dhcp_client_get_iface (NMDHCPClient *self);
|
||||
|
||||
int nm_dhcp_client_get_ifindex (NMDHCPClient *self);
|
||||
|
||||
gboolean nm_dhcp_client_get_ipv6 (NMDHCPClient *self);
|
||||
|
||||
const char *nm_dhcp_client_get_uuid (NMDHCPClient *self);
|
||||
|
||||
const GByteArray *nm_dhcp_client_get_duid (NMDHCPClient *self);
|
||||
|
||||
const GByteArray *nm_dhcp_client_get_hw_addr (NMDHCPClient *self);
|
||||
|
||||
guint32 nm_dhcp_client_get_priority (NMDHCPClient *self);
|
||||
|
||||
gboolean nm_dhcp_client_start_ip4 (NMDHCPClient *self,
|
||||
const char *dhcp_client_id,
|
||||
GByteArray *dhcp_anycast_addr,
|
||||
|
|
@ -132,7 +123,8 @@ gboolean nm_dhcp_client_start_ip4 (NMDHCPClient *self,
|
|||
gboolean nm_dhcp_client_start_ip6 (NMDHCPClient *self,
|
||||
GByteArray *dhcp_anycast_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only);
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy);
|
||||
|
||||
void nm_dhcp_client_stop (NMDHCPClient *self, gboolean release);
|
||||
|
||||
|
|
@ -140,18 +132,17 @@ void nm_dhcp_client_new_options (NMDHCPClient *self,
|
|||
GHashTable *options,
|
||||
const char *reason);
|
||||
|
||||
gboolean nm_dhcp_client_foreach_option (NMDHCPClient *self,
|
||||
GHFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
NMIP4Config *nm_dhcp_client_get_ip4_config (NMDHCPClient *self, gboolean test);
|
||||
|
||||
NMIP6Config *nm_dhcp_client_get_ip6_config (NMDHCPClient *self, gboolean test);
|
||||
|
||||
/* Backend helpers */
|
||||
/* Backend helpers for subclasses */
|
||||
void nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name);
|
||||
|
||||
void nm_dhcp_client_stop_pid (GPid pid, const char *iface);
|
||||
void nm_dhcp_client_stop_pid (pid_t pid, const char *iface);
|
||||
|
||||
void nm_dhcp_client_watch_child (NMDHCPClient *self, pid_t pid);
|
||||
|
||||
void nm_dhcp_client_set_state (NMDHCPClient *self,
|
||||
NMDhcpState new_state,
|
||||
GObject *ip_config, /* NMIP4Config or NMIP6Config */
|
||||
GHashTable *options); /* str:str hash */
|
||||
|
||||
#endif /* NM_DHCP_CLIENT_H */
|
||||
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ dhclient_child_setup (gpointer user_data G_GNUC_UNUSED)
|
|||
nm_unblock_posix_signals (NULL);
|
||||
}
|
||||
|
||||
static GPid
|
||||
static gboolean
|
||||
dhclient_start (NMDHCPClient *client,
|
||||
const char *mode_opt,
|
||||
const GByteArray *duid,
|
||||
|
|
@ -332,7 +332,7 @@ dhclient_start (NMDHCPClient *client,
|
|||
{
|
||||
NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
|
||||
GPtrArray *argv = NULL;
|
||||
GPid pid = -1;
|
||||
pid_t pid;
|
||||
GError *error = NULL;
|
||||
const char *iface, *uuid, *system_bus_address;
|
||||
char *binary_name, *cmd_str, *pid_file = NULL, *system_bus_address_env = NULL;
|
||||
|
|
@ -340,7 +340,7 @@ dhclient_start (NMDHCPClient *client,
|
|||
guint log_domain;
|
||||
char *escaped, *preferred_leasefile_path = NULL;
|
||||
|
||||
g_return_val_if_fail (priv->pid_file == NULL, -1);
|
||||
g_return_val_if_fail (priv->pid_file == NULL, FALSE);
|
||||
|
||||
iface = nm_dhcp_client_get_iface (client);
|
||||
uuid = nm_dhcp_client_get_uuid (client);
|
||||
|
|
@ -350,7 +350,7 @@ dhclient_start (NMDHCPClient *client,
|
|||
|
||||
if (!g_file_test (priv->path, G_FILE_TEST_EXISTS)) {
|
||||
nm_log_warn (log_domain, "%s does not exist.", priv->path);
|
||||
return -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pid_file = g_strdup_printf (LOCALSTATEDIR "/run/dhclient%s-%s.pid",
|
||||
|
|
@ -404,7 +404,8 @@ dhclient_start (NMDHCPClient *client,
|
|||
iface, priv->lease_file,
|
||||
error ? error->code : -1,
|
||||
error && error->message ? error->message : "(unknown)");
|
||||
return -1;
|
||||
g_free (pid_file);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -456,22 +457,24 @@ dhclient_start (NMDHCPClient *client,
|
|||
nm_log_dbg (log_domain, "running: %s", cmd_str);
|
||||
g_free (cmd_str);
|
||||
|
||||
if (!g_spawn_async (NULL, (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
if (g_spawn_async (NULL, (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
&dhclient_child_setup, NULL, &pid, &error)) {
|
||||
g_assert (pid > 0);
|
||||
nm_log_info (log_domain, "dhclient started with pid %d", pid);
|
||||
nm_dhcp_client_watch_child (client, pid);
|
||||
priv->pid_file = pid_file;
|
||||
} else {
|
||||
nm_log_warn (log_domain, "dhclient failed to start: '%s'", error->message);
|
||||
g_error_free (error);
|
||||
pid = -1;
|
||||
} else {
|
||||
nm_log_info (log_domain, "dhclient started with pid %d", pid);
|
||||
priv->pid_file = pid_file;
|
||||
g_free (pid_file);
|
||||
}
|
||||
|
||||
g_ptr_array_free (argv, TRUE);
|
||||
g_free (system_bus_address_env);
|
||||
return pid;
|
||||
return pid > 0 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static GPid
|
||||
static gboolean
|
||||
ip4_start (NMDHCPClient *client,
|
||||
const char *dhcp_client_id,
|
||||
GByteArray *dhcp_anycast_addr,
|
||||
|
|
@ -486,17 +489,18 @@ ip4_start (NMDHCPClient *client,
|
|||
priv->conf_file = create_dhclient_config (iface, FALSE, uuid, dhcp_client_id, dhcp_anycast_addr, hostname);
|
||||
if (!priv->conf_file) {
|
||||
nm_log_warn (LOGD_DHCP4, "(%s): error creating dhclient configuration file.", iface);
|
||||
return -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return dhclient_start (client, NULL, NULL, FALSE);
|
||||
}
|
||||
|
||||
static GPid
|
||||
static gboolean
|
||||
ip6_start (NMDHCPClient *client,
|
||||
GByteArray *dhcp_anycast_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const GByteArray *duid)
|
||||
{
|
||||
NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
|
||||
|
|
@ -508,7 +512,7 @@ ip6_start (NMDHCPClient *client,
|
|||
priv->conf_file = create_dhclient_config (iface, TRUE, uuid, NULL, dhcp_anycast_addr, hostname);
|
||||
if (!priv->conf_file) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): error creating dhclient6 configuration file.", iface);
|
||||
return -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE);
|
||||
|
|
@ -533,7 +537,7 @@ stop (NMDHCPClient *client, gboolean release, const GByteArray *duid)
|
|||
}
|
||||
|
||||
if (release) {
|
||||
GPid rpid;
|
||||
pid_t rpid;
|
||||
|
||||
rpid = dhclient_start (client, NULL, duid, TRUE);
|
||||
if (rpid > 0) {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ dhcpcd_child_setup (gpointer user_data G_GNUC_UNUSED)
|
|||
nm_unblock_posix_signals (NULL);
|
||||
}
|
||||
|
||||
static GPid
|
||||
static gboolean
|
||||
ip4_start (NMDHCPClient *client,
|
||||
const char *dhcp_client_id,
|
||||
GByteArray *dhcp_anycast_addr,
|
||||
|
|
@ -94,12 +94,12 @@ ip4_start (NMDHCPClient *client,
|
|||
{
|
||||
NMDHCPDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (client);
|
||||
GPtrArray *argv = NULL;
|
||||
GPid pid = -1;
|
||||
pid_t pid = -1;
|
||||
GError *error = NULL;
|
||||
char *pid_contents = NULL, *binary_name, *cmd_str;
|
||||
const char *iface;
|
||||
|
||||
g_return_val_if_fail (priv->pid_file == NULL, -1);
|
||||
g_return_val_if_fail (priv->pid_file == NULL, FALSE);
|
||||
|
||||
iface = nm_dhcp_client_get_iface (client);
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ ip4_start (NMDHCPClient *client,
|
|||
|
||||
if (!g_file_test (priv->path, G_FILE_TEST_EXISTS)) {
|
||||
nm_log_warn (LOGD_DHCP4, "%s does not exist.", priv->path);
|
||||
return -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Kill any existing dhcpcd from the pidfile */
|
||||
|
|
@ -152,28 +152,31 @@ ip4_start (NMDHCPClient *client,
|
|||
nm_log_dbg (LOGD_DHCP4, "running: %s", cmd_str);
|
||||
g_free (cmd_str);
|
||||
|
||||
if (!g_spawn_async (NULL, (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
&dhcpcd_child_setup, NULL, &pid, &error)) {
|
||||
if (g_spawn_async (NULL, (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
&dhcpcd_child_setup, NULL, &pid, &error)) {
|
||||
g_assert (pid > 0);
|
||||
nm_log_info (LOGD_DHCP4, "dhcpcd started with pid %d", pid);
|
||||
nm_dhcp_client_watch_child (client, pid);
|
||||
} else {
|
||||
nm_log_warn (LOGD_DHCP4, "dhcpcd failed to start. error: '%s'", error->message);
|
||||
g_error_free (error);
|
||||
pid = -1;
|
||||
} else
|
||||
nm_log_info (LOGD_DHCP4, "dhcpcd started with pid %d", pid);
|
||||
}
|
||||
|
||||
g_free (pid_contents);
|
||||
g_ptr_array_free (argv, TRUE);
|
||||
return pid;
|
||||
return pid > 0 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static GPid
|
||||
static gboolean
|
||||
ip6_start (NMDHCPClient *client,
|
||||
GByteArray *dhcp_anycast_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const GByteArray *duid)
|
||||
{
|
||||
nm_log_warn (LOGD_DHCP6, "the dhcpcd backend does not support IPv6.");
|
||||
return -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -142,16 +142,14 @@ get_client_for_pid (NMDHCPManager *manager, GPid pid)
|
|||
}
|
||||
|
||||
static NMDHCPClient *
|
||||
get_client_for_iface (NMDHCPManager *manager,
|
||||
const char *iface,
|
||||
gboolean ip6)
|
||||
get_client_for_ifindex (NMDHCPManager *manager, int ifindex, gboolean ip6)
|
||||
{
|
||||
NMDHCPManagerPrivate *priv;
|
||||
GHashTableIter iter;
|
||||
gpointer value;
|
||||
|
||||
g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), NULL);
|
||||
g_return_val_if_fail (iface, NULL);
|
||||
g_return_val_if_fail (ifindex > 0, NULL);
|
||||
|
||||
priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
|
||||
|
||||
|
|
@ -159,8 +157,8 @@ get_client_for_iface (NMDHCPManager *manager,
|
|||
while (g_hash_table_iter_next (&iter, NULL, &value)) {
|
||||
NMDHCPClient *candidate = NM_DHCP_CLIENT (value);
|
||||
|
||||
if ( !strcmp (iface, nm_dhcp_client_get_iface (candidate))
|
||||
&& (nm_dhcp_client_get_ipv6 (candidate) == ip6))
|
||||
if ( nm_dhcp_client_get_ifindex (candidate) == ifindex
|
||||
&& nm_dhcp_client_get_ipv6 (candidate) == ip6)
|
||||
return candidate;
|
||||
}
|
||||
|
||||
|
|
@ -339,49 +337,40 @@ get_client_type (const char *client, GError **error)
|
|||
return G_TYPE_INVALID;
|
||||
}
|
||||
|
||||
#define REMOVE_ID_TAG "remove-id"
|
||||
#define TIMEOUT_ID_TAG "timeout-id"
|
||||
static void client_state_changed (NMDHCPClient *client,
|
||||
NMDhcpState state,
|
||||
GObject *ip_config,
|
||||
GHashTable *options,
|
||||
NMDHCPManager *self);
|
||||
|
||||
static void
|
||||
remove_client (NMDHCPManager *self, NMDHCPClient *client)
|
||||
{
|
||||
NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
||||
guint id;
|
||||
|
||||
id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (client), REMOVE_ID_TAG));
|
||||
if (id)
|
||||
g_signal_handler_disconnect (client, id);
|
||||
|
||||
id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (client), TIMEOUT_ID_TAG));
|
||||
if (id)
|
||||
g_signal_handler_disconnect (client, id);
|
||||
g_signal_handlers_disconnect_by_func (client, client_state_changed, self);
|
||||
|
||||
/* Stopping the client is left up to the controlling device
|
||||
* explicitly since we may want to quit NetworkManager but not terminate
|
||||
* the DHCP client.
|
||||
*/
|
||||
|
||||
g_hash_table_remove (priv->clients, client);
|
||||
g_hash_table_remove (NM_DHCP_MANAGER_GET_PRIVATE (self)->clients, client);
|
||||
}
|
||||
|
||||
static void
|
||||
add_client (NMDHCPManager *self, NMDHCPClient *client)
|
||||
client_state_changed (NMDHCPClient *client,
|
||||
NMDhcpState state,
|
||||
GObject *ip_config,
|
||||
GHashTable *options,
|
||||
NMDHCPManager *self)
|
||||
{
|
||||
NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
||||
guint id;
|
||||
|
||||
id = g_signal_connect_swapped (client, NM_DHCP_CLIENT_SIGNAL_REMOVE, G_CALLBACK (remove_client), self);
|
||||
g_object_set_data (G_OBJECT (client), REMOVE_ID_TAG, GUINT_TO_POINTER (id));
|
||||
|
||||
id = g_signal_connect_swapped (client, NM_DHCP_CLIENT_SIGNAL_TIMEOUT, G_CALLBACK (remove_client), self);
|
||||
g_object_set_data (G_OBJECT (client), TIMEOUT_ID_TAG, GUINT_TO_POINTER (id));
|
||||
|
||||
g_hash_table_insert (priv->clients, client, g_object_ref (client));
|
||||
if (state >= NM_DHCP_STATE_TIMEOUT)
|
||||
remove_client (self, client);
|
||||
}
|
||||
|
||||
static NMDHCPClient *
|
||||
client_start (NMDHCPManager *self,
|
||||
const char *iface,
|
||||
int ifindex,
|
||||
const GByteArray *hwaddr,
|
||||
const char *uuid,
|
||||
guint priority,
|
||||
|
|
@ -390,7 +379,8 @@ client_start (NMDHCPManager *self,
|
|||
guint32 timeout,
|
||||
GByteArray *dhcp_anycast_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only)
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy)
|
||||
{
|
||||
NMDHCPManagerPrivate *priv;
|
||||
NMDHCPClient *client;
|
||||
|
|
@ -398,7 +388,7 @@ client_start (NMDHCPManager *self,
|
|||
|
||||
g_return_val_if_fail (self, NULL);
|
||||
g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
|
||||
g_return_val_if_fail (iface != NULL, NULL);
|
||||
g_return_val_if_fail (ifindex > 0, NULL);
|
||||
g_return_val_if_fail (uuid != NULL, NULL);
|
||||
|
||||
priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
||||
|
|
@ -407,32 +397,34 @@ client_start (NMDHCPManager *self,
|
|||
g_return_val_if_fail (priv->client_type != 0, NULL);
|
||||
|
||||
/* Kill any old client instance */
|
||||
client = get_client_for_iface (self, iface, ipv6);
|
||||
client = get_client_for_ifindex (self, ifindex, ipv6);
|
||||
if (client) {
|
||||
nm_dhcp_client_stop (client, FALSE);
|
||||
g_object_ref (client);
|
||||
remove_client (self, client);
|
||||
nm_dhcp_client_stop (client, FALSE);
|
||||
g_object_unref (client);
|
||||
}
|
||||
|
||||
/* And make a new one */
|
||||
client = g_object_new (priv->client_type,
|
||||
NM_DHCP_CLIENT_INTERFACE, iface,
|
||||
NM_DHCP_CLIENT_IFINDEX, ifindex,
|
||||
NM_DHCP_CLIENT_HWADDR, hwaddr,
|
||||
NM_DHCP_CLIENT_IPV6, ipv6,
|
||||
NM_DHCP_CLIENT_UUID, uuid,
|
||||
NM_DHCP_CLIENT_PRIORITY, priority,
|
||||
NM_DHCP_CLIENT_TIMEOUT, timeout ? timeout : DHCP_TIMEOUT,
|
||||
NULL);
|
||||
g_return_val_if_fail (client != NULL, NULL);
|
||||
add_client (self, client);
|
||||
g_hash_table_insert (NM_DHCP_MANAGER_GET_PRIVATE (self)->clients, client, g_object_ref (client));
|
||||
g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self);
|
||||
|
||||
if (ipv6)
|
||||
success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, hostname, info_only);
|
||||
success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, hostname, info_only, privacy);
|
||||
else
|
||||
success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname);
|
||||
|
||||
if (!success) {
|
||||
remove_client (self, client);
|
||||
g_object_unref (client);
|
||||
client = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -452,51 +444,50 @@ get_send_hostname (NMDHCPManager *self, const char *setting_hostname)
|
|||
NMDHCPClient *
|
||||
nm_dhcp_manager_start_ip4 (NMDHCPManager *self,
|
||||
const char *iface,
|
||||
int ifindex,
|
||||
const GByteArray *hwaddr,
|
||||
const char *uuid,
|
||||
guint priority,
|
||||
NMSettingIP4Config *s_ip4,
|
||||
gboolean send_hostname,
|
||||
const char *dhcp_hostname,
|
||||
const char *dhcp_client_id,
|
||||
guint32 timeout,
|
||||
GByteArray *dhcp_anycast_addr)
|
||||
{
|
||||
const char *hostname = NULL, *method;
|
||||
gboolean send_hostname;
|
||||
const char *hostname = NULL;
|
||||
|
||||
g_return_val_if_fail (self, NULL);
|
||||
g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
|
||||
|
||||
method = nm_setting_ip4_config_get_method (s_ip4);
|
||||
g_return_val_if_fail (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0, NULL);
|
||||
|
||||
send_hostname = nm_setting_ip4_config_get_dhcp_send_hostname (s_ip4);
|
||||
if (send_hostname)
|
||||
hostname = get_send_hostname (self, nm_setting_ip4_config_get_dhcp_hostname (s_ip4));
|
||||
|
||||
return client_start (self, iface, hwaddr, uuid, priority, FALSE,
|
||||
nm_setting_ip4_config_get_dhcp_client_id (s_ip4),
|
||||
timeout, dhcp_anycast_addr, hostname, FALSE);
|
||||
hostname = get_send_hostname (self, dhcp_hostname);
|
||||
return client_start (self, iface, ifindex, hwaddr, uuid, priority, FALSE,
|
||||
dhcp_client_id, timeout, dhcp_anycast_addr, hostname,
|
||||
FALSE, 0);
|
||||
}
|
||||
|
||||
/* Caller owns a reference to the NMDHCPClient on return */
|
||||
NMDHCPClient *
|
||||
nm_dhcp_manager_start_ip6 (NMDHCPManager *self,
|
||||
const char *iface,
|
||||
int ifindex,
|
||||
const GByteArray *hwaddr,
|
||||
const char *uuid,
|
||||
guint priority,
|
||||
NMSettingIP6Config *s_ip6,
|
||||
const char *dhcp_hostname,
|
||||
guint32 timeout,
|
||||
GByteArray *dhcp_anycast_addr,
|
||||
gboolean info_only)
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy)
|
||||
{
|
||||
const char *hostname;
|
||||
|
||||
g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
|
||||
|
||||
hostname = get_send_hostname (self, nm_setting_ip6_config_get_dhcp_hostname (s_ip6));
|
||||
hostname = dhcp_hostname ? get_send_hostname (self, dhcp_hostname) : NULL;
|
||||
|
||||
return client_start (self, iface, hwaddr, uuid, priority, TRUE,
|
||||
NULL, timeout, dhcp_anycast_addr, hostname, info_only);
|
||||
return client_start (self, iface, ifindex, hwaddr, uuid, priority, TRUE,
|
||||
NULL, timeout, dhcp_anycast_addr, hostname, info_only,
|
||||
privacy);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -532,35 +523,6 @@ nm_dhcp_manager_get_lease_ip_configs (NMDHCPManager *self,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
NMIP4Config *
|
||||
nm_dhcp_manager_test_ip4_options_to_config (const char *dhcp_client,
|
||||
const char *iface,
|
||||
GHashTable *options,
|
||||
const char *reason)
|
||||
{
|
||||
NMDHCPClient *client;
|
||||
NMIP4Config *config;
|
||||
GType client_type;
|
||||
GError *error = NULL;
|
||||
|
||||
client_type = get_client_type (dhcp_client, &error);
|
||||
if (!client_type) {
|
||||
nm_log_err (LOGD_DHCP4, "error: %s", error ? error->message : "(unknown)");
|
||||
g_clear_error (&error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
client = (NMDHCPClient *) g_object_new (client_type,
|
||||
NM_DHCP_CLIENT_INTERFACE, iface,
|
||||
NULL);
|
||||
g_return_val_if_fail (client != NULL, NULL);
|
||||
nm_dhcp_client_new_options (client, options, reason);
|
||||
config = nm_dhcp_client_get_ip4_config (client, TRUE);
|
||||
g_object_unref (client);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
||||
NMDHCPManager *
|
||||
|
|
|
|||
|
|
@ -25,9 +25,6 @@
|
|||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <nm-setting-ip4-config.h>
|
||||
#include <nm-setting-ip6-config.h>
|
||||
|
||||
#include "nm-dhcp-client.h"
|
||||
#include "nm-ip4-config.h"
|
||||
#include "nm-dhcp4-config.h"
|
||||
|
|
@ -66,22 +63,27 @@ void nm_dhcp_manager_set_default_hostname (NMDHCPManager *manager,
|
|||
|
||||
NMDHCPClient * nm_dhcp_manager_start_ip4 (NMDHCPManager *manager,
|
||||
const char *iface,
|
||||
int ifindex,
|
||||
const GByteArray *hwaddr,
|
||||
const char *uuid,
|
||||
guint priority,
|
||||
NMSettingIP4Config *s_ip4,
|
||||
gboolean send_hostname,
|
||||
const char *dhcp_hostname,
|
||||
const char *dhcp_client_id,
|
||||
guint32 timeout,
|
||||
GByteArray *dhcp_anycast_addr);
|
||||
|
||||
NMDHCPClient * nm_dhcp_manager_start_ip6 (NMDHCPManager *manager,
|
||||
const char *iface,
|
||||
int ifindex,
|
||||
const GByteArray *hwaddr,
|
||||
const char *uuid,
|
||||
guint priority,
|
||||
NMSettingIP6Config *s_ip6,
|
||||
const char *dhcp_hostname,
|
||||
guint32 timeout,
|
||||
GByteArray *dhcp_anycast_addr,
|
||||
gboolean info_only);
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy);
|
||||
|
||||
GSList * nm_dhcp_manager_get_lease_ip_configs (NMDHCPManager *self,
|
||||
const char *iface,
|
||||
|
|
@ -89,11 +91,6 @@ GSList * nm_dhcp_manager_get_lease_ip_configs (NMDHCPManager *self,
|
|||
gboolean ipv6);
|
||||
|
||||
/* For testing only */
|
||||
NMIP4Config *nm_dhcp_manager_test_ip4_options_to_config (const char *dhcp_client,
|
||||
const char *iface,
|
||||
GHashTable *options,
|
||||
const char *reason);
|
||||
|
||||
extern const char* nm_dhcp_helper_path;
|
||||
|
||||
#endif /* NM_DHCP_MANAGER_H */
|
||||
|
|
|
|||
685
src/dhcp-manager/nm-dhcp-utils.c
Normal file
685
src/dhcp-manager/nm-dhcp-utils.c
Normal file
|
|
@ -0,0 +1,685 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2005 - 2010 Red Hat, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "nm-logging.h"
|
||||
#include "nm-dhcp-utils.h"
|
||||
#include "nm-utils.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
|
||||
/********************************************/
|
||||
|
||||
static gboolean
|
||||
ip4_process_dhcpcd_rfc3442_routes (const char *str,
|
||||
guint priority,
|
||||
NMIP4Config *ip4_config,
|
||||
guint32 *gwaddr)
|
||||
{
|
||||
char **routes, **r;
|
||||
gboolean have_routes = FALSE;
|
||||
|
||||
routes = g_strsplit (str, " ", 0);
|
||||
if (g_strv_length (routes) == 0)
|
||||
goto out;
|
||||
|
||||
if ((g_strv_length (routes) % 2) != 0) {
|
||||
nm_log_warn (LOGD_DHCP4, " classless static routes provided, but invalid");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (r = routes; *r; r += 2) {
|
||||
char *slash;
|
||||
NMPlatformIP4Route route;
|
||||
int rt_cidr = 32;
|
||||
guint32 rt_addr, rt_route;
|
||||
|
||||
slash = strchr(*r, '/');
|
||||
if (slash) {
|
||||
*slash = '\0';
|
||||
errno = 0;
|
||||
rt_cidr = strtol (slash + 1, NULL, 10);
|
||||
if ((errno == EINVAL) || (errno == ERANGE)) {
|
||||
nm_log_warn (LOGD_DHCP4, "DHCP provided invalid classless static route cidr: '%s'", slash + 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (inet_pton (AF_INET, *r, &rt_addr) <= 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "DHCP provided invalid classless static route address: '%s'", *r);
|
||||
continue;
|
||||
}
|
||||
if (inet_pton (AF_INET, *(r + 1), &rt_route) <= 0) {
|
||||
nm_log_warn (LOGD_DHCP4, "DHCP provided invalid classless static route gateway: '%s'", *(r + 1));
|
||||
continue;
|
||||
}
|
||||
|
||||
have_routes = TRUE;
|
||||
if (rt_cidr == 0 && rt_addr == 0) {
|
||||
/* FIXME: how to handle multiple routers? */
|
||||
*gwaddr = rt_route;
|
||||
} else {
|
||||
nm_log_info (LOGD_DHCP4, " classless static route %s/%d gw %s", *r, rt_cidr, *(r + 1));
|
||||
memset (&route, 0, sizeof (route));
|
||||
route.network = rt_addr;
|
||||
route.plen = rt_cidr;
|
||||
route.gateway = rt_route;
|
||||
route.source = NM_PLATFORM_SOURCE_DHCP;
|
||||
route.metric = priority;
|
||||
nm_ip4_config_add_route (ip4_config, &route);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
g_strfreev (routes);
|
||||
return have_routes;
|
||||
}
|
||||
|
||||
static const char **
|
||||
process_dhclient_rfc3442_route (const char **octets,
|
||||
NMPlatformIP4Route *route,
|
||||
gboolean *success)
|
||||
{
|
||||
const char **o = octets;
|
||||
int addr_len = 0, i = 0;
|
||||
long int tmp;
|
||||
char *next_hop;
|
||||
guint32 tmp_addr;
|
||||
|
||||
*success = FALSE;
|
||||
|
||||
if (!*o)
|
||||
return o; /* no prefix */
|
||||
|
||||
tmp = strtol (*o, NULL, 10);
|
||||
if (tmp < 0 || tmp > 32) /* 32 == max IP4 prefix length */
|
||||
return o;
|
||||
|
||||
memset (route, 0, sizeof (*route));
|
||||
route->plen = tmp;
|
||||
o++;
|
||||
|
||||
if (tmp > 0)
|
||||
addr_len = ((tmp - 1) / 8) + 1;
|
||||
|
||||
/* ensure there's at least the address + next hop left */
|
||||
if (g_strv_length ((char **) o) < addr_len + 4)
|
||||
goto error;
|
||||
|
||||
if (tmp) {
|
||||
const char *addr[4] = { "0", "0", "0", "0" };
|
||||
char *str_addr;
|
||||
|
||||
for (i = 0; i < addr_len; i++)
|
||||
addr[i] = *o++;
|
||||
|
||||
str_addr = g_strjoin (".", addr[0], addr[1], addr[2], addr[3], NULL);
|
||||
if (inet_pton (AF_INET, str_addr, &tmp_addr) <= 0) {
|
||||
g_free (str_addr);
|
||||
goto error;
|
||||
}
|
||||
tmp_addr &= nm_utils_ip4_prefix_to_netmask ((guint32) tmp);
|
||||
route->network = tmp_addr;
|
||||
}
|
||||
|
||||
/* Handle next hop */
|
||||
next_hop = g_strjoin (".", o[0], o[1], o[2], o[3], NULL);
|
||||
if (inet_pton (AF_INET, next_hop, &tmp_addr) <= 0) {
|
||||
g_free (next_hop);
|
||||
goto error;
|
||||
}
|
||||
route->gateway = tmp_addr;
|
||||
g_free (next_hop);
|
||||
|
||||
*success = TRUE;
|
||||
return o + 4; /* advance to past the next hop */
|
||||
|
||||
error:
|
||||
return o;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_process_dhclient_rfc3442_routes (const char *str,
|
||||
guint priority,
|
||||
NMIP4Config *ip4_config,
|
||||
guint32 *gwaddr)
|
||||
{
|
||||
char **octets, **o;
|
||||
gboolean have_routes = FALSE;
|
||||
NMPlatformIP4Route route;
|
||||
gboolean success;
|
||||
|
||||
o = octets = g_strsplit_set (str, " .", 0);
|
||||
if (g_strv_length (octets) < 5) {
|
||||
nm_log_warn (LOGD_DHCP4, "ignoring invalid classless static routes '%s'", str);
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (*o) {
|
||||
memset (&route, 0, sizeof (route));
|
||||
o = (char **) process_dhclient_rfc3442_route ((const char **) o, &route, &success);
|
||||
if (!success) {
|
||||
nm_log_warn (LOGD_DHCP4, "ignoring invalid classless static routes");
|
||||
break;
|
||||
}
|
||||
|
||||
have_routes = TRUE;
|
||||
if (!route.plen) {
|
||||
/* gateway passed as classless static route */
|
||||
*gwaddr = route.gateway;
|
||||
} else {
|
||||
char addr[INET_ADDRSTRLEN];
|
||||
|
||||
/* normal route */
|
||||
route.source = NM_PLATFORM_SOURCE_DHCP;
|
||||
route.metric = priority;
|
||||
nm_ip4_config_add_route (ip4_config, &route);
|
||||
|
||||
nm_log_info (LOGD_DHCP4, " classless static route %s/%d gw %s",
|
||||
nm_utils_inet4_ntop (route.network, addr), route.plen,
|
||||
nm_utils_inet4_ntop (route.gateway, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
g_strfreev (octets);
|
||||
return have_routes;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_process_classless_routes (GHashTable *options,
|
||||
guint priority,
|
||||
NMIP4Config *ip4_config,
|
||||
guint32 *gwaddr)
|
||||
{
|
||||
const char *str, *p;
|
||||
|
||||
g_return_val_if_fail (options != NULL, FALSE);
|
||||
g_return_val_if_fail (ip4_config != NULL, FALSE);
|
||||
|
||||
*gwaddr = 0;
|
||||
|
||||
/* dhcpd/dhclient in Fedora has support for rfc3442 implemented using a
|
||||
* slightly different format:
|
||||
*
|
||||
* option classless-static-routes = array of (destination-descriptor ip-address);
|
||||
*
|
||||
* which results in:
|
||||
*
|
||||
* 0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6
|
||||
*
|
||||
* dhcpcd supports classless static routes natively and uses this same
|
||||
* option identifier with the following format:
|
||||
*
|
||||
* 192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41
|
||||
*/
|
||||
str = g_hash_table_lookup (options, "classless_static_routes");
|
||||
|
||||
/* dhclient doesn't have actual support for rfc3442 classless static routes
|
||||
* upstream. Thus, people resort to defining the option in dhclient.conf
|
||||
* and using arbitrary formats like so:
|
||||
*
|
||||
* option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
|
||||
*
|
||||
* See https://lists.isc.org/pipermail/dhcp-users/2008-December/007629.html
|
||||
*/
|
||||
if (!str)
|
||||
str = g_hash_table_lookup (options, "rfc3442_classless_static_routes");
|
||||
|
||||
/* Microsoft version; same as rfc3442 but with a different option # (249) */
|
||||
if (!str)
|
||||
str = g_hash_table_lookup (options, "ms_classless_static_routes");
|
||||
|
||||
if (!str || !strlen (str))
|
||||
return FALSE;
|
||||
|
||||
p = str;
|
||||
while (*p) {
|
||||
if (!g_ascii_isdigit (*p) && (*p != ' ') && (*p != '.') && (*p != '/')) {
|
||||
nm_log_warn (LOGD_DHCP4, "ignoring invalid classless static routes '%s'", str);
|
||||
return FALSE;
|
||||
}
|
||||
p++;
|
||||
};
|
||||
|
||||
if (strchr (str, '/')) {
|
||||
/* dhcpcd format */
|
||||
return ip4_process_dhcpcd_rfc3442_routes (str, priority, ip4_config, gwaddr);
|
||||
}
|
||||
|
||||
return ip4_process_dhclient_rfc3442_routes (str, priority, ip4_config, gwaddr);
|
||||
}
|
||||
|
||||
static void
|
||||
process_classful_routes (GHashTable *options, guint priority, NMIP4Config *ip4_config)
|
||||
{
|
||||
const char *str;
|
||||
char **searches, **s;
|
||||
|
||||
str = g_hash_table_lookup (options, "static_routes");
|
||||
if (!str)
|
||||
return;
|
||||
|
||||
searches = g_strsplit (str, " ", 0);
|
||||
if ((g_strv_length (searches) % 2)) {
|
||||
nm_log_info (LOGD_DHCP, " static routes provided, but invalid");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (s = searches; *s; s += 2) {
|
||||
NMPlatformIP4Route route;
|
||||
guint32 rt_addr, rt_route;
|
||||
|
||||
if (inet_pton (AF_INET, *s, &rt_addr) <= 0) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP provided invalid static route address: '%s'", *s);
|
||||
continue;
|
||||
}
|
||||
if (inet_pton (AF_INET, *(s + 1), &rt_route) <= 0) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP provided invalid static route gateway: '%s'", *(s + 1));
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME: ensure the IP address and route are sane
|
||||
|
||||
memset (&route, 0, sizeof (route));
|
||||
route.network = rt_addr;
|
||||
/* RFC 2132, updated by RFC 3442:
|
||||
The Static Routes option (option 33) does not provide a subnet mask
|
||||
for each route - it is assumed that the subnet mask is implicit in
|
||||
whatever network number is specified in each route entry */
|
||||
route.plen = nm_utils_ip4_get_default_prefix (rt_addr);
|
||||
if (rt_addr & ~nm_utils_ip4_prefix_to_netmask (route.plen)) {
|
||||
/* RFC 943: target not "this network"; using host routing */
|
||||
route.plen = 32;
|
||||
}
|
||||
route.gateway = rt_route;
|
||||
route.source = NM_PLATFORM_SOURCE_DHCP;
|
||||
route.metric = priority;
|
||||
|
||||
nm_ip4_config_add_route (ip4_config, &route);
|
||||
nm_log_info (LOGD_DHCP, " static route %s",
|
||||
nm_platform_ip4_route_to_string (&route));
|
||||
}
|
||||
|
||||
out:
|
||||
g_strfreev (searches);
|
||||
}
|
||||
|
||||
static void
|
||||
process_domain_search (const char *str, GFunc add_func, gpointer user_data)
|
||||
{
|
||||
char **searches, **s;
|
||||
char *unescaped, *p;
|
||||
int i;
|
||||
|
||||
g_return_if_fail (str != NULL);
|
||||
g_return_if_fail (add_func != NULL);
|
||||
|
||||
p = unescaped = g_strdup (str);
|
||||
do {
|
||||
p = strstr (p, "\\032");
|
||||
if (!p)
|
||||
break;
|
||||
|
||||
/* Clear the escaped space with real spaces */
|
||||
for (i = 0; i < 4; i++)
|
||||
*p++ = ' ';
|
||||
} while (*p++);
|
||||
|
||||
if (strchr (unescaped, '\\')) {
|
||||
nm_log_warn (LOGD_DHCP, " invalid domain search: '%s'", unescaped);
|
||||
goto out;
|
||||
}
|
||||
|
||||
searches = g_strsplit (unescaped, " ", 0);
|
||||
for (s = searches; *s; s++) {
|
||||
if (strlen (*s)) {
|
||||
nm_log_info (LOGD_DHCP, " domain search '%s'", *s);
|
||||
add_func (*s, user_data);
|
||||
}
|
||||
}
|
||||
g_strfreev (searches);
|
||||
|
||||
out:
|
||||
g_free (unescaped);
|
||||
}
|
||||
|
||||
static void
|
||||
ip4_add_domain_search (gpointer data, gpointer user_data)
|
||||
{
|
||||
nm_ip4_config_add_search (NM_IP4_CONFIG (user_data), (const char *) data);
|
||||
}
|
||||
|
||||
NMIP4Config *
|
||||
nm_dhcp_utils_ip4_config_from_options (const char *iface,
|
||||
GHashTable *options,
|
||||
guint priority)
|
||||
{
|
||||
NMIP4Config *ip4_config = NULL;
|
||||
guint32 tmp_addr;
|
||||
NMPlatformIP4Address address;
|
||||
char *str = NULL;
|
||||
guint32 gwaddr = 0, plen = 0;
|
||||
|
||||
g_return_val_if_fail (options != NULL, NULL);
|
||||
|
||||
ip4_config = nm_ip4_config_new ();
|
||||
memset (&address, 0, sizeof (address));
|
||||
address.timestamp = nm_utils_get_monotonic_timestamp_s ();
|
||||
|
||||
str = g_hash_table_lookup (options, "ip_address");
|
||||
if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) {
|
||||
address.address = tmp_addr;
|
||||
nm_log_info (LOGD_DHCP4, " address %s", str);
|
||||
} else
|
||||
goto error;
|
||||
|
||||
str = g_hash_table_lookup (options, "subnet_mask");
|
||||
if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) {
|
||||
plen = nm_utils_ip4_netmask_to_prefix (tmp_addr);
|
||||
nm_log_info (LOGD_DHCP4, " plen %d (%s)", plen, str);
|
||||
} else {
|
||||
/* Get default netmask for the IP according to appropriate class. */
|
||||
plen = nm_utils_ip4_get_default_prefix (address.address);
|
||||
nm_log_info (LOGD_DHCP4, " plen %d (default)", plen);
|
||||
}
|
||||
address.plen = plen;
|
||||
|
||||
/* Routes: if the server returns classless static routes, we MUST ignore
|
||||
* the 'static_routes' option.
|
||||
*/
|
||||
if (!ip4_process_classless_routes (options, priority, ip4_config, &gwaddr))
|
||||
process_classful_routes (options, priority, ip4_config);
|
||||
|
||||
if (gwaddr) {
|
||||
nm_log_info (LOGD_DHCP4, " gateway %s", nm_utils_inet4_ntop (gwaddr, NULL));
|
||||
nm_ip4_config_set_gateway (ip4_config, gwaddr);
|
||||
} else {
|
||||
/* If the gateway wasn't provided as a classless static route with a
|
||||
* subnet length of 0, try to find it using the old-style 'routers' option.
|
||||
*/
|
||||
str = g_hash_table_lookup (options, "routers");
|
||||
if (str) {
|
||||
char **routers = g_strsplit (str, " ", 0);
|
||||
char **s;
|
||||
|
||||
for (s = routers; *s; s++) {
|
||||
/* FIXME: how to handle multiple routers? */
|
||||
if (inet_pton (AF_INET, *s, &gwaddr) > 0) {
|
||||
nm_ip4_config_set_gateway (ip4_config, gwaddr);
|
||||
nm_log_info (LOGD_DHCP4, " gateway %s", *s);
|
||||
break;
|
||||
} else
|
||||
nm_log_warn (LOGD_DHCP4, "ignoring invalid gateway '%s'", *s);
|
||||
}
|
||||
g_strfreev (routers);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 2132, section 9.7
|
||||
* DHCP clients use the contents of the 'server identifier' field
|
||||
* as the destination address for any DHCP messages unicast to
|
||||
* the DHCP server.
|
||||
*
|
||||
* Some ISP's provide leases from central servers that are on
|
||||
* different subnets that the address offered. If the host
|
||||
* does not configure the interface as the default route, the
|
||||
* dhcp server may not be reachable via unicast, and a host
|
||||
* specific route is needed.
|
||||
**/
|
||||
str = g_hash_table_lookup (options, "dhcp_server_identifier");
|
||||
if (str) {
|
||||
if (inet_pton (AF_INET, str, &tmp_addr) > 0) {
|
||||
NMPlatformIP4Route route;
|
||||
guint32 mask = nm_utils_ip4_prefix_to_netmask (address.plen);
|
||||
|
||||
nm_log_info (LOGD_DHCP4, " server identifier %s", str);
|
||||
if ((tmp_addr & mask) != (address.address & mask)) {
|
||||
/* DHCP server not on assigned subnet, route needed */
|
||||
memset (&route, 0, sizeof (route));
|
||||
route.network = tmp_addr;
|
||||
route.plen = 32;
|
||||
/* this will be a device route if gwaddr is 0 */
|
||||
route.gateway = gwaddr;
|
||||
route.source = NM_PLATFORM_SOURCE_DHCP;
|
||||
route.metric = priority;
|
||||
nm_ip4_config_add_route (ip4_config, &route);
|
||||
nm_log_dbg (LOGD_IP, "adding route for server identifier: %s",
|
||||
nm_platform_ip4_route_to_string (&route));
|
||||
}
|
||||
}
|
||||
else
|
||||
nm_log_warn (LOGD_DHCP4, "ignoring invalid server identifier '%s'", str);
|
||||
}
|
||||
|
||||
str = g_hash_table_lookup (options, "dhcp_lease_time");
|
||||
if (str) {
|
||||
address.lifetime = address.preferred = strtoul (str, NULL, 10);
|
||||
nm_log_info (LOGD_DHCP4, " lease time %d", address.lifetime);
|
||||
}
|
||||
|
||||
address.source = NM_PLATFORM_SOURCE_DHCP;
|
||||
nm_ip4_config_add_address (ip4_config, &address);
|
||||
|
||||
str = g_hash_table_lookup (options, "host_name");
|
||||
if (str)
|
||||
nm_log_info (LOGD_DHCP4, " hostname '%s'", str);
|
||||
|
||||
str = g_hash_table_lookup (options, "domain_name_servers");
|
||||
if (str) {
|
||||
char **searches = g_strsplit (str, " ", 0);
|
||||
char **s;
|
||||
|
||||
for (s = searches; *s; s++) {
|
||||
if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
|
||||
nm_ip4_config_add_nameserver (ip4_config, tmp_addr);
|
||||
nm_log_info (LOGD_DHCP4, " nameserver '%s'", *s);
|
||||
} else
|
||||
nm_log_warn (LOGD_DHCP4, "ignoring invalid nameserver '%s'", *s);
|
||||
}
|
||||
g_strfreev (searches);
|
||||
}
|
||||
|
||||
str = g_hash_table_lookup (options, "domain_name");
|
||||
if (str) {
|
||||
char **domains = g_strsplit (str, " ", 0);
|
||||
char **s;
|
||||
|
||||
for (s = domains; *s; s++) {
|
||||
nm_log_info (LOGD_DHCP4, " domain name '%s'", *s);
|
||||
nm_ip4_config_add_domain (ip4_config, *s);
|
||||
}
|
||||
g_strfreev (domains);
|
||||
}
|
||||
|
||||
str = g_hash_table_lookup (options, "domain_search");
|
||||
if (str)
|
||||
process_domain_search (str, ip4_add_domain_search, ip4_config);
|
||||
|
||||
str = g_hash_table_lookup (options, "netbios_name_servers");
|
||||
if (str) {
|
||||
char **searches = g_strsplit (str, " ", 0);
|
||||
char **s;
|
||||
|
||||
for (s = searches; *s; s++) {
|
||||
if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
|
||||
nm_ip4_config_add_wins (ip4_config, tmp_addr);
|
||||
nm_log_info (LOGD_DHCP4, " wins '%s'", *s);
|
||||
} else
|
||||
nm_log_warn (LOGD_DHCP4, "ignoring invalid WINS server '%s'", *s);
|
||||
}
|
||||
g_strfreev (searches);
|
||||
}
|
||||
|
||||
str = g_hash_table_lookup (options, "interface_mtu");
|
||||
if (str) {
|
||||
int int_mtu;
|
||||
|
||||
errno = 0;
|
||||
int_mtu = strtol (str, NULL, 10);
|
||||
if ((errno == EINVAL) || (errno == ERANGE))
|
||||
goto error;
|
||||
|
||||
if (int_mtu > 576)
|
||||
nm_ip4_config_set_mtu (ip4_config, int_mtu);
|
||||
}
|
||||
|
||||
str = g_hash_table_lookup (options, "nis_domain");
|
||||
if (str) {
|
||||
nm_log_info (LOGD_DHCP4, " NIS domain '%s'", str);
|
||||
nm_ip4_config_set_nis_domain (ip4_config, str);
|
||||
}
|
||||
|
||||
str = g_hash_table_lookup (options, "nis_servers");
|
||||
if (str) {
|
||||
char **searches = g_strsplit (str, " ", 0);
|
||||
char **s;
|
||||
|
||||
for (s = searches; *s; s++) {
|
||||
if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
|
||||
nm_ip4_config_add_nis_server (ip4_config, tmp_addr);
|
||||
nm_log_info (LOGD_DHCP4, " nis '%s'", *s);
|
||||
} else
|
||||
nm_log_warn (LOGD_DHCP4, "ignoring invalid NIS server '%s'", *s);
|
||||
}
|
||||
g_strfreev (searches);
|
||||
}
|
||||
|
||||
return ip4_config;
|
||||
|
||||
error:
|
||||
g_object_unref (ip4_config);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/********************************************/
|
||||
|
||||
static void
|
||||
ip6_add_domain_search (gpointer data, gpointer user_data)
|
||||
{
|
||||
nm_ip6_config_add_search (NM_IP6_CONFIG (user_data), (const char *) data);
|
||||
}
|
||||
|
||||
NMIP6Config *
|
||||
nm_dhcp_utils_ip6_config_from_options (const char *iface,
|
||||
GHashTable *options,
|
||||
guint priority,
|
||||
gboolean info_only)
|
||||
{
|
||||
NMIP6Config *ip6_config = NULL;
|
||||
struct in6_addr tmp_addr;
|
||||
NMPlatformIP6Address address;
|
||||
char *str = NULL;
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_return_val_if_fail (options != NULL, NULL);
|
||||
|
||||
memset (&address, 0, sizeof (address));
|
||||
address.plen = 128;
|
||||
address.timestamp = nm_utils_get_monotonic_timestamp_s ();
|
||||
|
||||
g_hash_table_iter_init (&iter, options);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
||||
nm_log_dbg (LOGD_DHCP6, "(%s): option '%s'=>'%s'",
|
||||
iface, (const char *) key, (const char *) value);
|
||||
}
|
||||
|
||||
ip6_config = nm_ip6_config_new ();
|
||||
|
||||
str = g_hash_table_lookup (options, "max_life");
|
||||
if (str) {
|
||||
address.lifetime = strtoul (str, NULL, 10);
|
||||
nm_log_info (LOGD_DHCP6, " valid_lft %d", address.lifetime);
|
||||
}
|
||||
|
||||
str = g_hash_table_lookup (options, "preferred_life");
|
||||
if (str) {
|
||||
address.preferred = strtoul (str, NULL, 10);
|
||||
nm_log_info (LOGD_DHCP6, " preferred_lft %d", address.preferred);
|
||||
}
|
||||
|
||||
str = g_hash_table_lookup (options, "ip6_address");
|
||||
if (str) {
|
||||
if (!inet_pton (AF_INET6, str, &tmp_addr)) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): DHCP returned invalid address '%s'",
|
||||
iface, str);
|
||||
goto error;
|
||||
}
|
||||
|
||||
address.address = tmp_addr;
|
||||
address.source = NM_PLATFORM_SOURCE_DHCP;
|
||||
nm_ip6_config_add_address (ip6_config, &address);
|
||||
nm_log_info (LOGD_DHCP6, " address %s", str);
|
||||
} else if (info_only == FALSE) {
|
||||
/* No address in Managed mode is a hard error */
|
||||
goto error;
|
||||
}
|
||||
|
||||
str = g_hash_table_lookup (options, "host_name");
|
||||
if (str)
|
||||
nm_log_info (LOGD_DHCP6, " hostname '%s'", str);
|
||||
|
||||
str = g_hash_table_lookup (options, "dhcp6_name_servers");
|
||||
if (str) {
|
||||
char **searches = g_strsplit (str, " ", 0);
|
||||
char **s;
|
||||
|
||||
for (s = searches; *s; s++) {
|
||||
if (inet_pton (AF_INET6, *s, &tmp_addr) > 0) {
|
||||
nm_ip6_config_add_nameserver (ip6_config, &tmp_addr);
|
||||
nm_log_info (LOGD_DHCP6, " nameserver '%s'", *s);
|
||||
} else
|
||||
nm_log_warn (LOGD_DHCP6, "ignoring invalid nameserver '%s'", *s);
|
||||
}
|
||||
g_strfreev (searches);
|
||||
}
|
||||
|
||||
str = g_hash_table_lookup (options, "dhcp6_domain_search");
|
||||
if (str)
|
||||
process_domain_search (str, ip6_add_domain_search, ip6_config);
|
||||
|
||||
return ip6_config;
|
||||
|
||||
error:
|
||||
g_object_unref (ip6_config);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *
|
||||
nm_dhcp_utils_duid_to_string (const GByteArray *duid)
|
||||
{
|
||||
guint32 i = 0;
|
||||
GString *s;
|
||||
|
||||
g_return_val_if_fail (duid != NULL, NULL);
|
||||
|
||||
s = g_string_sized_new (MIN (duid->len * 3, 50));
|
||||
while (i < duid->len) {
|
||||
if (s->len)
|
||||
g_string_append_c (s, ':');
|
||||
g_string_append_printf (s, "%02x", duid->data[i++]);
|
||||
}
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
39
src/dhcp-manager/nm-dhcp-utils.h
Normal file
39
src/dhcp-manager/nm-dhcp-utils.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef NM_DHCP_UTILS_H
|
||||
#define NM_DHCP_UTILS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <nm-ip4-config.h>
|
||||
#include <nm-ip6-config.h>
|
||||
|
||||
NMIP4Config *nm_dhcp_utils_ip4_config_from_options (const char *iface,
|
||||
GHashTable *options,
|
||||
guint priority);
|
||||
|
||||
NMIP6Config *nm_dhcp_utils_ip6_config_from_options (const char *iface,
|
||||
GHashTable *options,
|
||||
guint priority,
|
||||
gboolean info_only);
|
||||
|
||||
char * nm_dhcp_utils_duid_to_string (const GByteArray *duid);
|
||||
|
||||
#endif /* NM_DHCP_UTILS_H */
|
||||
|
||||
|
|
@ -3,6 +3,7 @@ AM_CPPFLAGS = \
|
|||
-I${top_srcdir}/libnm-util \
|
||||
-I${top_builddir}/libnm-util \
|
||||
-I$(top_srcdir)/src/dhcp-manager \
|
||||
-I$(top_srcdir)/src/logging \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/src/platform \
|
||||
-DG_LOG_DOMAIN=\""NetworkManager"\" \
|
||||
|
|
@ -10,9 +11,11 @@ AM_CPPFLAGS = \
|
|||
$(GLIB_CFLAGS) \
|
||||
-DTESTDIR="\"$(abs_srcdir)\""
|
||||
|
||||
noinst_PROGRAMS = test-dhcp-dhclient
|
||||
noinst_PROGRAMS = \
|
||||
test-dhcp-dhclient \
|
||||
test-dhcp-options
|
||||
|
||||
####### policy /etc/hosts test #######
|
||||
####### dhclient leases test #######
|
||||
|
||||
test_dhcp_dhclient_SOURCES = \
|
||||
test-dhcp-dhclient.c
|
||||
|
|
@ -20,7 +23,17 @@ test_dhcp_dhclient_SOURCES = \
|
|||
test_dhcp_dhclient_LDADD = \
|
||||
$(top_builddir)/src/libNetworkManager.la
|
||||
|
||||
TESTS = test-dhcp-dhclient
|
||||
####### DHCP options test #######
|
||||
|
||||
test_dhcp_options_SOURCES = \
|
||||
test-dhcp-options.c
|
||||
|
||||
test_dhcp_options_LDADD = \
|
||||
$(top_builddir)/src/libNetworkManager.la
|
||||
|
||||
#################################
|
||||
|
||||
TESTS = test-dhcp-dhclient test-dhcp-options
|
||||
|
||||
EXTRA_DIST = \
|
||||
test-dhclient-duid.leases \
|
||||
|
|
|
|||
683
src/dhcp-manager/tests/test-dhcp-options.c
Normal file
683
src/dhcp-manager/tests/test-dhcp-options.c
Normal file
|
|
@ -0,0 +1,683 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2008 - 2014 Red Hat, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <nm-utils.h>
|
||||
|
||||
#include "nm-dhcp-utils.h"
|
||||
#include "nm-logging.h"
|
||||
|
||||
#include "nm-test-utils.h"
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *value;
|
||||
} Option;
|
||||
|
||||
static GHashTable *
|
||||
fill_table (const Option *test_options, GHashTable *table)
|
||||
{
|
||||
const Option *opt;
|
||||
|
||||
if (!table)
|
||||
table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
|
||||
for (opt = test_options; opt->name; opt++)
|
||||
g_hash_table_insert (table, (gpointer) opt->name, (gpointer) opt->value);
|
||||
return table;
|
||||
}
|
||||
|
||||
static const Option generic_options[] = {
|
||||
{ "subnet_mask", "255.255.255.0" },
|
||||
{ "ip_address", "192.168.1.106" },
|
||||
{ "network_number", "192.168.1.0" },
|
||||
{ "expiry", "1232324877" },
|
||||
{ "dhcp_lease_time", "3600" },
|
||||
{ "dhcp_server_identifier", "192.168.1.1" },
|
||||
{ "routers", "192.168.1.1" },
|
||||
{ "domain_name_servers", "216.254.95.2 216.231.41.2" },
|
||||
{ "dhcp_message_type", "5" },
|
||||
{ "broadcast_address", "192.168.1.255" },
|
||||
{ "domain_search", "foobar.com blah.foobar.com" },
|
||||
{ "host_name", "nmreallywhipsthe" },
|
||||
{ "domain_name", "lamasass.com" },
|
||||
{ "interface_mtu", "987" },
|
||||
{ "static_routes", "10.1.1.5 10.1.1.1 100.99.88.56 10.1.1.1" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
test_generic_options (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const NMPlatformIP4Address *address;
|
||||
const NMPlatformIP4Route *route;
|
||||
guint32 tmp;
|
||||
const char *expected_addr = "192.168.1.106";
|
||||
const char *expected_gw = "192.168.1.1";
|
||||
const char *expected_dns1 = "216.254.95.2";
|
||||
const char *expected_dns2 = "216.231.41.2";
|
||||
const char *expected_search1 = "foobar.com";
|
||||
const char *expected_search2 = "blah.foobar.com";
|
||||
const char *expected_route1_dest = "10.1.1.5";
|
||||
const char *expected_route1_gw = "10.1.1.1";
|
||||
const char *expected_route2_dest = "100.99.88.56";
|
||||
const char *expected_route2_gw = "10.1.1.1";
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
|
||||
/* IP4 address */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1);
|
||||
address = nm_ip4_config_get_address (ip4_config, 0);
|
||||
g_assert (inet_pton (AF_INET, expected_addr, &tmp) > 0);
|
||||
g_assert (address->address == tmp);
|
||||
g_assert (address->peer_address == 0);
|
||||
g_assert_cmpint (address->plen, ==, 24);
|
||||
|
||||
/* Gateway */
|
||||
g_assert (inet_pton (AF_INET, expected_gw, &tmp) > 0);
|
||||
g_assert (nm_ip4_config_get_gateway (ip4_config) == tmp);
|
||||
|
||||
g_assert_cmpint (nm_ip4_config_get_num_wins (ip4_config), ==, 0);
|
||||
|
||||
g_assert_cmpint (nm_ip4_config_get_mtu (ip4_config), ==, 987);
|
||||
|
||||
/* Domain searches */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_searches (ip4_config), ==, 2);
|
||||
g_assert_cmpstr (nm_ip4_config_get_search (ip4_config, 0), ==, expected_search1);
|
||||
g_assert_cmpstr (nm_ip4_config_get_search (ip4_config, 1), ==, expected_search2);
|
||||
|
||||
/* DNS servers */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_nameservers (ip4_config), ==, 2);
|
||||
g_assert (inet_pton (AF_INET, expected_dns1, &tmp) > 0);
|
||||
g_assert (nm_ip4_config_get_nameserver (ip4_config, 0) == tmp);
|
||||
g_assert (inet_pton (AF_INET, expected_dns2, &tmp) > 0);
|
||||
g_assert (nm_ip4_config_get_nameserver (ip4_config, 1) == tmp);
|
||||
|
||||
/* Routes */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
|
||||
|
||||
/* Route #1 */
|
||||
route = nm_ip4_config_get_route (ip4_config, 0);
|
||||
g_assert (inet_pton (AF_INET, expected_route1_dest, &tmp) > 0);
|
||||
g_assert (route->network == tmp);
|
||||
g_assert (inet_pton (AF_INET, expected_route1_gw, &tmp) > 0);
|
||||
g_assert (route->gateway == tmp);
|
||||
g_assert_cmpint (route->plen, ==, 32);
|
||||
g_assert_cmpint (route->metric, ==, 0);
|
||||
|
||||
/* Route #2 */
|
||||
route = nm_ip4_config_get_route (ip4_config, 1);
|
||||
g_assert (inet_pton (AF_INET, expected_route2_dest, &tmp) > 0);
|
||||
g_assert (route->network == tmp);
|
||||
g_assert (inet_pton (AF_INET, expected_route2_gw, &tmp) > 0);
|
||||
g_assert (route->gateway == tmp);
|
||||
g_assert_cmpint (route->plen, ==, 32);
|
||||
g_assert_cmpint (route->metric, ==, 0);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_wins_options (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const NMPlatformIP4Address *address;
|
||||
guint32 tmp;
|
||||
const char *expected_wins1 = "63.12.199.5";
|
||||
const char *expected_wins2 = "150.4.88.120";
|
||||
static const Option data[] = {
|
||||
{ "netbios_name_servers", "63.12.199.5 150.4.88.120" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
|
||||
/* IP4 address */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1);
|
||||
address = nm_ip4_config_get_address (ip4_config, 0);
|
||||
g_assert (address);
|
||||
g_assert_cmpint (nm_ip4_config_get_num_wins (ip4_config), ==, 2);
|
||||
g_assert (inet_pton (AF_INET, expected_wins1, &tmp) > 0);
|
||||
g_assert (nm_ip4_config_get_wins (ip4_config, 0) == tmp);
|
||||
g_assert (inet_pton (AF_INET, expected_wins2, &tmp) > 0);
|
||||
g_assert (nm_ip4_config_get_wins (ip4_config, 1) == tmp);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
ip4_test_route (NMIP4Config *ip4_config,
|
||||
guint route_num,
|
||||
const char *expected_dest,
|
||||
const char *expected_gw,
|
||||
guint expected_prefix)
|
||||
{
|
||||
const NMPlatformIP4Route *route;
|
||||
guint32 tmp;
|
||||
|
||||
route = nm_ip4_config_get_route (ip4_config, route_num);
|
||||
g_assert (inet_pton (AF_INET, expected_dest, &tmp) > 0);
|
||||
g_assert (route->network == tmp);
|
||||
g_assert (inet_pton (AF_INET, expected_gw, &tmp) > 0);
|
||||
g_assert (route->gateway == tmp);
|
||||
g_assert_cmpint (route->plen, ==, expected_prefix);
|
||||
g_assert_cmpint (route->metric, ==, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
ip4_test_gateway (NMIP4Config *ip4_config, const char *expected_gw)
|
||||
{
|
||||
guint32 tmp;
|
||||
|
||||
g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1);
|
||||
g_assert (inet_pton (AF_INET, expected_gw, &tmp) > 0);
|
||||
g_assert (nm_ip4_config_get_gateway (ip4_config) == tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
test_classless_static_routes_1 (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
const char *expected_route2_dest = "10.0.0.0";
|
||||
const char *expected_route2_gw = "10.17.66.41";
|
||||
static const Option data[] = {
|
||||
/* dhclient custom format */
|
||||
{ "rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 8 10 10 17 66 41" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
|
||||
/* IP4 routes */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
|
||||
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
|
||||
ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 8);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_classless_static_routes_2 (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
const char *expected_route2_dest = "10.0.0.0";
|
||||
const char *expected_route2_gw = "10.17.66.41";
|
||||
static const Option data[] = {
|
||||
/* dhcpcd format */
|
||||
{ "classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
|
||||
/* IP4 routes */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
|
||||
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
|
||||
ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 8);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_fedora_dhclient_classless_static_routes (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "129.210.177.128";
|
||||
const char *expected_route1_gw = "192.168.0.113";
|
||||
const char *expected_route2_dest = "2.0.0.0";
|
||||
const char *expected_route2_gw = "10.34.255.6";
|
||||
const char *expected_gateway = "192.168.0.113";
|
||||
static const Option data[] = {
|
||||
/* Fedora dhclient format */
|
||||
{ "classless_static_routes", "0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
|
||||
/* IP4 routes */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
|
||||
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 25);
|
||||
ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 7);
|
||||
|
||||
/* Gateway */
|
||||
ip4_test_gateway (ip4_config, expected_gateway);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhclient_invalid_classless_routes_1 (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
static const Option data[] = {
|
||||
/* dhclient format */
|
||||
{ "rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 45 10 17 66 41" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*ignoring invalid classless static routes*");
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* IP4 routes */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1);
|
||||
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhcpcd_invalid_classless_routes_1 (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "10.1.1.5";
|
||||
const char *expected_route1_gw = "10.1.1.1";
|
||||
const char *expected_route2_dest = "100.99.88.56";
|
||||
const char *expected_route2_gw = "10.1.1.1";
|
||||
static const Option data[] = {
|
||||
/* dhcpcd format */
|
||||
{ "classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.adfadf/44 10.17.66.41" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*ignoring invalid classless static routes*");
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* Test falling back to old-style static routes if the classless static
|
||||
* routes are invalid.
|
||||
*/
|
||||
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
|
||||
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 32);
|
||||
ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 32);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhclient_invalid_classless_routes_2 (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "10.1.1.5";
|
||||
const char *expected_route1_gw = "10.1.1.1";
|
||||
const char *expected_route2_dest = "100.99.88.56";
|
||||
const char *expected_route2_gw = "10.1.1.1";
|
||||
static const Option data[] = {
|
||||
{ "rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*ignoring invalid classless static routes*");
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* Test falling back to old-style static routes if the classless static
|
||||
* routes are invalid.
|
||||
*/
|
||||
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
|
||||
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 32);
|
||||
ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 32);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhcpcd_invalid_classless_routes_2 (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "10.1.1.5";
|
||||
const char *expected_route1_gw = "10.1.1.1";
|
||||
const char *expected_route2_dest = "100.99.88.56";
|
||||
const char *expected_route2_gw = "10.1.1.1";
|
||||
static const Option data[] = {
|
||||
{ "classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*ignoring invalid classless static routes*");
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* Test falling back to old-style static routes if the classless static
|
||||
* routes are invalid.
|
||||
*/
|
||||
|
||||
/* Routes */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
|
||||
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 32);
|
||||
ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 32);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhclient_invalid_classless_routes_3 (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
static const Option data[] = {
|
||||
{ "rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*ignoring invalid classless static routes*");
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* IP4 routes */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1);
|
||||
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhcpcd_invalid_classless_routes_3 (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
static Option data[] = {
|
||||
{ "classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*DHCP provided invalid classless static route*");
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* IP4 routes */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1);
|
||||
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhclient_gw_in_classless_routes (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
const char *expected_gateway = "192.2.3.4";
|
||||
static Option data[] = {
|
||||
{ "rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
|
||||
/* IP4 routes */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1);
|
||||
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
|
||||
|
||||
/* Gateway */
|
||||
ip4_test_gateway (ip4_config, expected_gateway);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhcpcd_gw_in_classless_routes (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
const char *expected_gateway = "192.2.3.4";
|
||||
static Option data[] = {
|
||||
{ "classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
|
||||
/* IP4 routes */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1);
|
||||
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
|
||||
|
||||
/* Gateway */
|
||||
ip4_test_gateway (ip4_config, expected_gateway);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_escaped_domain_searches (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_search0 = "host1";
|
||||
const char *expected_search1 = "host2";
|
||||
const char *expected_search2 = "host3";
|
||||
static const Option data[] = {
|
||||
{ "domain_search", "host1\\032host2\\032host3" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
|
||||
/* domain searches */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_searches (ip4_config), ==, 3);
|
||||
g_assert_cmpstr (nm_ip4_config_get_search (ip4_config, 0), ==, expected_search0);
|
||||
g_assert_cmpstr (nm_ip4_config_get_search (ip4_config, 1), ==, expected_search1);
|
||||
g_assert_cmpstr (nm_ip4_config_get_search (ip4_config, 2), ==, expected_search2);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_invalid_escaped_domain_searches (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
static const Option data[] = {
|
||||
{ "domain_search", "host1\\aahost2\\032host3" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*invalid domain search*");
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* domain searches */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_searches (ip4_config), ==, 0);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip4_missing_prefix (const char *ip, guint32 expected_prefix)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const NMPlatformIP4Address *address;
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
g_hash_table_insert (options, "ip_address", (gpointer) ip);
|
||||
g_hash_table_remove (options, "subnet_mask");
|
||||
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
|
||||
g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1);
|
||||
address = nm_ip4_config_get_address (ip4_config, 0);
|
||||
g_assert (address);
|
||||
g_assert_cmpint (address->plen, ==, expected_prefix);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip4_missing_prefix_24 (void)
|
||||
{
|
||||
test_ip4_missing_prefix ("192.168.1.10", 24);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip4_missing_prefix_16 (void)
|
||||
{
|
||||
test_ip4_missing_prefix ("172.16.54.50", 16);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip4_missing_prefix_8 (void)
|
||||
{
|
||||
test_ip4_missing_prefix ("10.1.2.3", 8);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip4_prefix_classless (void)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const NMPlatformIP4Address *address;
|
||||
|
||||
/* Ensure that the missing-subnet-mask handler doesn't mangle classless
|
||||
* subnet masks at all. The handler should trigger only if the server
|
||||
* doesn't send the subnet mask.
|
||||
*/
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
g_hash_table_insert (options, "ip_address", "172.16.54.22");
|
||||
g_hash_table_insert (options, "subnet_mask", "255.255.252.0");
|
||||
|
||||
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
|
||||
g_assert (ip4_config);
|
||||
|
||||
g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1);
|
||||
address = nm_ip4_config_get_address (ip4_config, 0);
|
||||
g_assert (address);
|
||||
g_assert_cmpint (address->plen, ==, 22);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
NMTST_DEFINE ();
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
nmtst_init_assert_logging (&argc, &argv);
|
||||
nm_logging_setup ("WARN", "DEFAULT", NULL, NULL);
|
||||
|
||||
g_test_add_func ("/dhcp/generic-options", test_generic_options);
|
||||
g_test_add_func ("/dhcp/wins-options", test_wins_options);
|
||||
g_test_add_func ("/dhcp/classless-static-routes-1", test_classless_static_routes_1);
|
||||
g_test_add_func ("/dhcp/classless-static-routes-2", test_classless_static_routes_2);
|
||||
g_test_add_func ("/dhcp/fedora-dhclient-classless-static-routes", test_fedora_dhclient_classless_static_routes);
|
||||
g_test_add_func ("/dhcp/dhclient-invalid-classless-routes-1", test_dhclient_invalid_classless_routes_1);
|
||||
g_test_add_func ("/dhcp/dhcpcd-invalid-classless-routes-1", test_dhcpcd_invalid_classless_routes_1);
|
||||
g_test_add_func ("/dhcp/dhclient-invalid-classless-routes-2", test_dhclient_invalid_classless_routes_2);
|
||||
g_test_add_func ("/dhcp/dhcpcd-invalid-classless-routes-2", test_dhcpcd_invalid_classless_routes_2);
|
||||
g_test_add_func ("/dhcp/dhclient-invalid-classless-routes-3", test_dhclient_invalid_classless_routes_3);
|
||||
g_test_add_func ("/dhcp/dhcpcd-invalid-classless-routes-3", test_dhcpcd_invalid_classless_routes_3);
|
||||
g_test_add_func ("/dhcp/dhclient-gw-in-classless-routes", test_dhclient_gw_in_classless_routes);
|
||||
g_test_add_func ("/dhcp/dhcpcd-gw-in-classless-routes", test_dhcpcd_gw_in_classless_routes);
|
||||
g_test_add_func ("/dhcp/escaped-domain-searches", test_escaped_domain_searches);
|
||||
g_test_add_func ("/dhcp/invalid-escaped-domain-searches", test_invalid_escaped_domain_searches);
|
||||
g_test_add_func ("/dhcp/ip4-missing-prefix-24", test_ip4_missing_prefix_24);
|
||||
g_test_add_func ("/dhcp/ip4-missing-prefix-16", test_ip4_missing_prefix_16);
|
||||
g_test_add_func ("/dhcp/ip4-missing-prefix-8", test_ip4_missing_prefix_8);
|
||||
g_test_add_func ("/dhcp/ip4-prefix-classless", test_ip4_prefix_classless);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
|
|
@ -14,7 +14,6 @@ AM_CPPFLAGS = \
|
|||
$(DBUS_CFLAGS)
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
test-dhcp-options \
|
||||
test-general \
|
||||
test-general-with-expect \
|
||||
test-ip4-config \
|
||||
|
|
@ -22,19 +21,6 @@ noinst_PROGRAMS = \
|
|||
test-dcb \
|
||||
test-resolvconf-capture
|
||||
|
||||
####### DHCP options test #######
|
||||
|
||||
test_dhcp_options_SOURCES = \
|
||||
test-dhcp-options.c
|
||||
|
||||
test_dhcp_options_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
-DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \
|
||||
-DDHCPCD_PATH=\"$(DHCPCD_PATH)\"
|
||||
|
||||
test_dhcp_options_LDADD = \
|
||||
$(top_builddir)/src/libNetworkManager.la
|
||||
|
||||
####### ip4 config test #######
|
||||
|
||||
test_ip4_config_SOURCES = \
|
||||
|
|
|
|||
|
|
@ -1,937 +0,0 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* nm-dhcp-manager.c - Handle the DHCP daemon for NetworkManager
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2008 - 2011 Red Hat, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <dbus/dbus-glib.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <nm-utils.h>
|
||||
|
||||
#include "nm-dhcp-manager.h"
|
||||
#include "nm-logging.h"
|
||||
|
||||
#include "nm-test-utils.h"
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *value;
|
||||
} Option;
|
||||
|
||||
static void
|
||||
destroy_gvalue (gpointer data)
|
||||
{
|
||||
GValue *value = (GValue *) data;
|
||||
|
||||
g_value_unset (value);
|
||||
g_slice_free (GValue, value);
|
||||
}
|
||||
|
||||
static GValue *
|
||||
string_to_byte_array_gvalue (const char *str)
|
||||
{
|
||||
GByteArray *array;
|
||||
GValue *val;
|
||||
|
||||
array = g_byte_array_sized_new (strlen (str));
|
||||
g_byte_array_append (array, (const guint8 *) str, strlen (str));
|
||||
|
||||
val = g_slice_new0 (GValue);
|
||||
g_value_init (val, DBUS_TYPE_G_UCHAR_ARRAY);
|
||||
g_value_take_boxed (val, array);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static GHashTable *
|
||||
fill_table (Option *test_options, GHashTable *table)
|
||||
{
|
||||
Option *opt;
|
||||
|
||||
if (!table)
|
||||
table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, destroy_gvalue);
|
||||
for (opt = test_options; opt->name; opt++) {
|
||||
g_hash_table_insert (table,
|
||||
(gpointer) opt->name,
|
||||
string_to_byte_array_gvalue (opt->value));
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
static Option generic_options[] = {
|
||||
{ "new_subnet_mask", "255.255.255.0" },
|
||||
{ "new_ip_address", "192.168.1.106" },
|
||||
{ "new_network_number", "192.168.1.0" },
|
||||
{ "interface", "eth0" },
|
||||
{ "reason", "BOUND" },
|
||||
{ "new_expiry", "1232324877" },
|
||||
{ "new_dhcp_lease_time", "3600" },
|
||||
{ "new_dhcp_server_identifier", "192.168.1.1" },
|
||||
{ "new_routers", "192.168.1.1" },
|
||||
{ "new_domain_name_servers", "216.254.95.2 216.231.41.2" },
|
||||
{ "new_dhcp_message_type", "5" },
|
||||
{ "new_broadcast_address", "192.168.1.255" },
|
||||
{ "new_domain_search", "foobar.com blah.foobar.com" },
|
||||
{ "new_host_name", "nmreallywhipsthe" },
|
||||
{ "new_domain_name", "lamasass.com" },
|
||||
{ "new_interface_mtu", "987" },
|
||||
{ "new_static_routes", "10.1.1.5 10.1.1.1 100.99.88.56 10.1.1.1" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
test_generic_options (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const NMPlatformIP4Address *address;
|
||||
const NMPlatformIP4Route *route;
|
||||
guint32 tmp;
|
||||
const char *expected_addr = "192.168.1.106";
|
||||
const char *expected_gw = "192.168.1.1";
|
||||
const char *expected_dns1 = "216.254.95.2";
|
||||
const char *expected_dns2 = "216.231.41.2";
|
||||
const char *expected_search1 = "foobar.com";
|
||||
const char *expected_search2 = "blah.foobar.com";
|
||||
const char *expected_route1_dest = "10.1.1.5";
|
||||
const char *expected_route1_gw = "10.1.1.1";
|
||||
const char *expected_route2_dest = "100.99.88.56";
|
||||
const char *expected_route2_gw = "10.1.1.1";
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-generic", "failed to parse DHCP4 options");
|
||||
|
||||
/* IP4 address */
|
||||
ASSERT (nm_ip4_config_get_num_addresses (ip4_config) == 1,
|
||||
"dhcp-generic", "unexpected number of IP addresses");
|
||||
address = nm_ip4_config_get_address (ip4_config, 0);
|
||||
|
||||
ASSERT (inet_pton (AF_INET, expected_addr, &tmp) > 0,
|
||||
"dhcp-generic", "couldn't convert expected IP address");
|
||||
ASSERT (address->address == tmp,
|
||||
"dhcp-generic", "unexpected IP address");
|
||||
ASSERT (address->peer_address == 0,
|
||||
"dhcp-generic", "unexpected PTP address");
|
||||
|
||||
ASSERT (address->plen == 24,
|
||||
"dhcp-generic", "unexpected IP address prefix length");
|
||||
|
||||
/* Gateway */
|
||||
ASSERT (inet_pton (AF_INET, expected_gw, &tmp) > 0,
|
||||
"dhcp-generic", "couldn't convert expected IP gateway");
|
||||
ASSERT (nm_ip4_config_get_gateway (ip4_config) == tmp,
|
||||
"dhcp-generic", "unexpected IP gateway");
|
||||
|
||||
ASSERT (nm_ip4_config_get_num_wins (ip4_config) == 0,
|
||||
"dhcp-generic", "unexpected number of WINS servers");
|
||||
|
||||
ASSERT (nm_ip4_config_get_mtu (ip4_config) == 987,
|
||||
"dhcp-generic", "unexpected MTU");
|
||||
|
||||
/* Domain searches */
|
||||
ASSERT (nm_ip4_config_get_num_searches (ip4_config) == 2,
|
||||
"dhcp-generic", "unexpected number of domain searches");
|
||||
ASSERT (strcmp (nm_ip4_config_get_search (ip4_config, 0), expected_search1) == 0,
|
||||
"dhcp-generic", "unexpected domain search #1");
|
||||
ASSERT (strcmp (nm_ip4_config_get_search (ip4_config, 1), expected_search2) == 0,
|
||||
"dhcp-generic", "unexpected domain search #2");
|
||||
|
||||
/* DNS servers */
|
||||
ASSERT (nm_ip4_config_get_num_nameservers (ip4_config) == 2,
|
||||
"dhcp-generic", "unexpected number of domain name servers");
|
||||
ASSERT (inet_pton (AF_INET, expected_dns1, &tmp) > 0,
|
||||
"dhcp-generic", "couldn't convert expected DNS server address #1");
|
||||
ASSERT (nm_ip4_config_get_nameserver (ip4_config, 0) == tmp,
|
||||
"dhcp-generic", "unexpected domain name server #1");
|
||||
ASSERT (inet_pton (AF_INET, expected_dns2, &tmp) > 0,
|
||||
"dhcp-generic", "couldn't convert expected DNS server address #2");
|
||||
ASSERT (nm_ip4_config_get_nameserver (ip4_config, 1) == tmp,
|
||||
"dhcp-generic", "unexpected domain name server #2");
|
||||
|
||||
/* Routes */
|
||||
ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
|
||||
"dhcp-generic", "unexpected number of routes");
|
||||
|
||||
/* Route #1 */
|
||||
route = nm_ip4_config_get_route (ip4_config, 0);
|
||||
ASSERT (inet_pton (AF_INET, expected_route1_dest, &tmp) > 0,
|
||||
"dhcp-generic", "couldn't convert expected route destination #1");
|
||||
ASSERT (route->network == tmp,
|
||||
"dhcp-generic", "unexpected route #1 destination");
|
||||
|
||||
ASSERT (inet_pton (AF_INET, expected_route1_gw, &tmp) > 0,
|
||||
"dhcp-generic", "couldn't convert expected route next hop #1");
|
||||
ASSERT (route->gateway == tmp,
|
||||
"dhcp-generic", "unexpected route #1 next hop");
|
||||
|
||||
ASSERT (route->plen == 32,
|
||||
"dhcp-generic", "unexpected route #1 prefix");
|
||||
ASSERT (route->metric == 0,
|
||||
"dhcp-generic", "unexpected route #1 metric");
|
||||
|
||||
/* Route #2 */
|
||||
route = nm_ip4_config_get_route (ip4_config, 1);
|
||||
ASSERT (inet_pton (AF_INET, expected_route2_dest, &tmp) > 0,
|
||||
"dhcp-generic", "couldn't convert expected route destination #2");
|
||||
ASSERT (route->network == tmp,
|
||||
"dhcp-generic", "unexpected route #2 destination");
|
||||
|
||||
ASSERT (inet_pton (AF_INET, expected_route2_gw, &tmp) > 0,
|
||||
"dhcp-generic", "couldn't convert expected route next hop #2");
|
||||
ASSERT (route->gateway == tmp,
|
||||
"dhcp-generic", "unexpected route #2 next hop");
|
||||
|
||||
ASSERT (route->plen == 32,
|
||||
"dhcp-generic", "unexpected route #2 prefix");
|
||||
ASSERT (route->metric == 0,
|
||||
"dhcp-generic", "unexpected route #2 metric");
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static Option wins_options[] = {
|
||||
{ "new_netbios_name_servers", "63.12.199.5 150.4.88.120" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
test_wins_options (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const NMPlatformIP4Address *address;
|
||||
guint32 tmp;
|
||||
const char *expected_wins1 = "63.12.199.5";
|
||||
const char *expected_wins2 = "150.4.88.120";
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (wins_options, options);
|
||||
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-wins", "failed to parse DHCP4 options");
|
||||
|
||||
/* IP4 address */
|
||||
ASSERT (nm_ip4_config_get_num_addresses (ip4_config) == 1,
|
||||
"dhcp-wins", "unexpected number of IP addresses");
|
||||
address = nm_ip4_config_get_address (ip4_config, 0);
|
||||
ASSERT (address != NULL, "dhcp-wins", "unexpectedly did not get address #0");
|
||||
|
||||
ASSERT (nm_ip4_config_get_num_wins (ip4_config) == 2,
|
||||
"dhcp-wins", "unexpected number of WINS servers");
|
||||
ASSERT (inet_pton (AF_INET, expected_wins1, &tmp) > 0,
|
||||
"dhcp-wins", "couldn't convert expected WINS server address #1");
|
||||
ASSERT (nm_ip4_config_get_wins (ip4_config, 0) == tmp,
|
||||
"dhcp-wins", "unexpected WINS server #1");
|
||||
ASSERT (inet_pton (AF_INET, expected_wins2, &tmp) > 0,
|
||||
"dhcp-wins", "couldn't convert expected WINS server address #1");
|
||||
ASSERT (nm_ip4_config_get_wins (ip4_config, 1) == tmp,
|
||||
"dhcp-wins", "unexpected WINS server #1");
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
ip4_test_route (const char *test,
|
||||
NMIP4Config *ip4_config,
|
||||
guint route_num,
|
||||
const char *expected_dest,
|
||||
const char *expected_gw,
|
||||
guint expected_prefix)
|
||||
{
|
||||
const NMPlatformIP4Route *route;
|
||||
guint32 tmp;
|
||||
|
||||
route = nm_ip4_config_get_route (ip4_config, route_num);
|
||||
ASSERT (inet_pton (AF_INET, expected_dest, &tmp) > 0,
|
||||
test, "couldn't convert expected route destination #1");
|
||||
ASSERT (route->network == tmp,
|
||||
test, "unexpected route %d destination", route_num + 1);
|
||||
|
||||
ASSERT (inet_pton (AF_INET, expected_gw, &tmp) > 0,
|
||||
test, "couldn't convert expected route next hop %d",
|
||||
route_num + 1);
|
||||
ASSERT (route->gateway == tmp,
|
||||
test, "unexpected route %d next hop", route_num + 1);
|
||||
|
||||
ASSERT (route->plen == expected_prefix,
|
||||
test, "unexpected route %d prefix", route_num + 1);
|
||||
ASSERT (route->metric == 0,
|
||||
test, "unexpected route %d metric", route_num + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
ip4_test_gateway (const char *test,
|
||||
NMIP4Config *ip4_config,
|
||||
const char *expected_gw)
|
||||
{
|
||||
guint32 tmp;
|
||||
|
||||
ASSERT (nm_ip4_config_get_num_addresses (ip4_config) == 1,
|
||||
test, "unexpected number of IP addresses");
|
||||
ASSERT (inet_pton (AF_INET, expected_gw, &tmp) > 0,
|
||||
test, "couldn't convert expected IP gateway");
|
||||
ASSERT (nm_ip4_config_get_gateway (ip4_config) == tmp,
|
||||
test, "unexpected IP gateway");
|
||||
}
|
||||
|
||||
static void
|
||||
test_classless_static_routes_1 (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
const char *expected_route2_dest = "10.0.0.0";
|
||||
const char *expected_route2_gw = "10.17.66.41";
|
||||
static Option data[] = {
|
||||
/* dhclient custom format */
|
||||
{ "new_rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 8 10 10 17 66 41" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-classless-1", "failed to parse DHCP4 options");
|
||||
|
||||
/* IP4 routes */
|
||||
ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
|
||||
"dhcp-classless-1", "unexpected number of IP routes");
|
||||
ip4_test_route ("dhcp-classless-1", ip4_config, 0,
|
||||
expected_route1_dest, expected_route1_gw, 24);
|
||||
ip4_test_route ("dhcp-classless-1", ip4_config, 1,
|
||||
expected_route2_dest, expected_route2_gw, 8);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_classless_static_routes_2 (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
const char *expected_route2_dest = "10.0.0.0";
|
||||
const char *expected_route2_gw = "10.17.66.41";
|
||||
static Option data[] = {
|
||||
/* dhcpcd format */
|
||||
{ "new_classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-classless-2", "failed to parse DHCP4 options");
|
||||
|
||||
/* IP4 routes */
|
||||
ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
|
||||
"dhcp-classless-2", "unexpected number of IP routes");
|
||||
ip4_test_route ("dhcp-classless-2", ip4_config, 0,
|
||||
expected_route1_dest, expected_route1_gw, 24);
|
||||
ip4_test_route ("dhcp-classless-2", ip4_config, 1,
|
||||
expected_route2_dest, expected_route2_gw, 8);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_fedora_dhclient_classless_static_routes (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "129.210.177.128";
|
||||
const char *expected_route1_gw = "192.168.0.113";
|
||||
const char *expected_route2_dest = "2.0.0.0";
|
||||
const char *expected_route2_gw = "10.34.255.6";
|
||||
const char *expected_gateway = "192.168.0.113";
|
||||
static Option data[] = {
|
||||
/* Fedora dhclient format */
|
||||
{ "new_classless_static_routes", "0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-fedora-dhclient-classless", "failed to parse DHCP4 options");
|
||||
|
||||
/* IP4 routes */
|
||||
ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
|
||||
"dhcp-fedora-dhclient-classless", "unexpected number of IP routes");
|
||||
ip4_test_route ("dhcp-fedora-dhclient-classless", ip4_config, 0,
|
||||
expected_route1_dest, expected_route1_gw, 25);
|
||||
ip4_test_route ("dhcp-fedora-dhclient-classless", ip4_config, 1,
|
||||
expected_route2_dest, expected_route2_gw, 7);
|
||||
|
||||
/* Gateway */
|
||||
ip4_test_gateway ("dhcp-fedora-dhclient-classless", ip4_config, expected_gateway);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhclient_invalid_classless_routes_1 (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
static Option data[] = {
|
||||
/* dhclient format */
|
||||
{ "new_rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 45 10 17 66 41" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*ignoring invalid classless static routes*");
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-dhclient-classless-invalid-1", "failed to parse DHCP4 options");
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* IP4 routes */
|
||||
ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 1,
|
||||
"dhcp-dhclient-classless-invalid-1", "unexpected number of IP routes");
|
||||
|
||||
ip4_test_route ("dhcp-dhclient-classless-invalid-1", ip4_config, 0,
|
||||
expected_route1_dest, expected_route1_gw, 24);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhcpcd_invalid_classless_routes_1 (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "10.1.1.5";
|
||||
const char *expected_route1_gw = "10.1.1.1";
|
||||
const char *expected_route2_dest = "100.99.88.56";
|
||||
const char *expected_route2_gw = "10.1.1.1";
|
||||
static Option data[] = {
|
||||
/* dhcpcd format */
|
||||
{ "new_classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.adfadf/44 10.17.66.41" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*ignoring invalid classless static routes*");
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-dhcpcd-classless-invalid-1", "failed to parse DHCP4 options");
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* Test falling back to old-style static routes if the classless static
|
||||
* routes are invalid.
|
||||
*/
|
||||
ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
|
||||
"dhcp-dhcpcdp-classless-invalid-1", "unexpected number of routes");
|
||||
ip4_test_route ("dhcp-dhcpcdp-classless-invalid-1", ip4_config, 0,
|
||||
expected_route1_dest, expected_route1_gw, 32);
|
||||
ip4_test_route ("dhcp-dhcpcdp-classless-invalid-1", ip4_config, 1,
|
||||
expected_route2_dest, expected_route2_gw, 32);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhclient_invalid_classless_routes_2 (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "10.1.1.5";
|
||||
const char *expected_route1_gw = "10.1.1.1";
|
||||
const char *expected_route2_dest = "100.99.88.56";
|
||||
const char *expected_route2_gw = "10.1.1.1";
|
||||
static Option data[] = {
|
||||
{ "new_rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*ignoring invalid classless static routes*");
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-dhclient-classless-invalid-2", "failed to parse DHCP4 options");
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* Test falling back to old-style static routes if the classless static
|
||||
* routes are invalid.
|
||||
*/
|
||||
ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
|
||||
"dhcp-dhclient-classless-invalid-2", "unexpected number of routes");
|
||||
ip4_test_route ("dhcp-dhclient-classless-invalid-2", ip4_config, 0,
|
||||
expected_route1_dest, expected_route1_gw, 32);
|
||||
ip4_test_route ("dhcp-dhclient-classless-invalid-2", ip4_config, 1,
|
||||
expected_route2_dest, expected_route2_gw, 32);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhcpcd_invalid_classless_routes_2 (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "10.1.1.5";
|
||||
const char *expected_route1_gw = "10.1.1.1";
|
||||
const char *expected_route2_dest = "100.99.88.56";
|
||||
const char *expected_route2_gw = "10.1.1.1";
|
||||
static Option data[] = {
|
||||
{ "new_classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*ignoring invalid classless static routes*");
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-dhcpcd-classless-invalid-2", "failed to parse DHCP4 options");
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* Test falling back to old-style static routes if the classless static
|
||||
* routes are invalid.
|
||||
*/
|
||||
|
||||
/* Routes */
|
||||
ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
|
||||
"dhcp-dhcpcd-classless-invalid-2", "unexpected number of routes");
|
||||
ip4_test_route ("dhcp-dhcpcd-classless-invalid-2", ip4_config, 0,
|
||||
expected_route1_dest, expected_route1_gw, 32);
|
||||
ip4_test_route ("dhcp-dhcpcd-classless-invalid-2", ip4_config, 1,
|
||||
expected_route2_dest, expected_route2_gw, 32);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhclient_invalid_classless_routes_3 (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
static Option data[] = {
|
||||
{ "new_rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*ignoring invalid classless static routes*");
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-dhclient-classless-invalid-3", "failed to parse DHCP4 options");
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* IP4 routes */
|
||||
ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 1,
|
||||
"dhcp-dhclient-classless-invalid-3", "unexpected number of IP routes");
|
||||
ip4_test_route ("dhcp-dhclient-classless-invalid-3", ip4_config, 0,
|
||||
expected_route1_dest, expected_route1_gw, 24);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhcpcd_invalid_classless_routes_3 (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
static Option data[] = {
|
||||
{ "new_classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*DHCP provided invalid classless static route*");
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-dhcpcd-classless-invalid-3", "failed to parse DHCP4 options");
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* IP4 routes */
|
||||
ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 1,
|
||||
"dhcp-dhcpcd-classless-invalid-3", "unexpected number of IP routes");
|
||||
ip4_test_route ("dhcp-dhcpcd-classless-invalid-3", ip4_config, 0,
|
||||
expected_route1_dest, expected_route1_gw, 24);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhclient_gw_in_classless_routes (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
const char *expected_gateway = "192.2.3.4";
|
||||
static Option data[] = {
|
||||
{ "new_rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-dhclient-classless-gateway", "failed to parse DHCP4 options");
|
||||
|
||||
/* IP4 routes */
|
||||
ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 1,
|
||||
"dhcp-dhclient-classless-gateway", "unexpected number of IP routes");
|
||||
ip4_test_route ("dhcp-dhclient-classless-gateway", ip4_config, 0,
|
||||
expected_route1_dest, expected_route1_gw, 24);
|
||||
|
||||
/* Gateway */
|
||||
ip4_test_gateway ("dhcp-dhclient-classless-gateway", ip4_config, expected_gateway);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dhcpcd_gw_in_classless_routes (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_route1_dest = "192.168.10.0";
|
||||
const char *expected_route1_gw = "192.168.1.1";
|
||||
const char *expected_gateway = "192.2.3.4";
|
||||
static Option data[] = {
|
||||
{ "new_classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (data, options);
|
||||
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-dhcpcd-classless-gateway", "failed to parse DHCP4 options");
|
||||
|
||||
/* IP4 routes */
|
||||
ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 1,
|
||||
"dhcp-dhcpcd-classless-gateway", "unexpected number of IP routes");
|
||||
ip4_test_route ("dhcp-dhcpcd-classless-gateway", ip4_config, 0,
|
||||
expected_route1_dest, expected_route1_gw, 24);
|
||||
|
||||
/* Gateway */
|
||||
ip4_test_gateway ("dhcp-dhcpcd-classless-gateway", ip4_config, expected_gateway);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static Option escaped_searches_options[] = {
|
||||
{ "new_domain_search", "host1\\032host2\\032host3" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
test_escaped_domain_searches (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const char *expected_search0 = "host1";
|
||||
const char *expected_search1 = "host2";
|
||||
const char *expected_search2 = "host3";
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (escaped_searches_options, options);
|
||||
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-escaped-domain-searches", "failed to parse DHCP4 options");
|
||||
|
||||
/* domain searches */
|
||||
ASSERT (nm_ip4_config_get_num_searches (ip4_config) == 3,
|
||||
"dhcp-escaped-domain-searches", "unexpected number of searches");
|
||||
ASSERT (!strcmp (nm_ip4_config_get_search (ip4_config, 0), expected_search0),
|
||||
"dhcp-escaped-domain-searches", "unexpected domain search #1");
|
||||
ASSERT (!strcmp (nm_ip4_config_get_search (ip4_config, 1), expected_search1),
|
||||
"dhcp-escaped-domain-searches", "unexpected domain search #1");
|
||||
ASSERT (!strcmp (nm_ip4_config_get_search (ip4_config, 2), expected_search2),
|
||||
"dhcp-escaped-domain-searches", "unexpected domain search #1");
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static Option invalid_escaped_searches_options[] = {
|
||||
{ "new_domain_search", "host1\\aahost2\\032host3" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
test_invalid_escaped_domain_searches (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
options = fill_table (invalid_escaped_searches_options, options);
|
||||
|
||||
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
|
||||
"*invalid domain search*");
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-invalid-escaped-domain-searches", "failed to parse DHCP4 options");
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* domain searches */
|
||||
ASSERT (nm_ip4_config_get_num_searches (ip4_config) == 0,
|
||||
"dhcp-invalid-escaped-domain-searches", "unexpected domain searches");
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip4_missing_prefix (const char *client, const char *ip, guint32 expected_prefix)
|
||||
{
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const NMPlatformIP4Address *address;
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
g_hash_table_insert (options, "new_ip_address", string_to_byte_array_gvalue (ip));
|
||||
g_hash_table_remove (options, "new_subnet_mask");
|
||||
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-ip4-missing-prefix", "failed to parse DHCP4 options");
|
||||
|
||||
ASSERT (nm_ip4_config_get_num_addresses (ip4_config) == 1,
|
||||
"dhcp-ip4-missing-prefix", "unexpected number of IP4 addresses (not 1)");
|
||||
|
||||
address = nm_ip4_config_get_address (ip4_config, 0);
|
||||
ASSERT (address,
|
||||
"dhcp-ip4-missing-prefix", "missing IP4 address #1");
|
||||
|
||||
ASSERT (address->plen == expected_prefix,
|
||||
"dhcp-ip4-missing-prefix", "unexpected IP4 address prefix %d (expected %d)",
|
||||
address->plen, expected_prefix);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip4_missing_prefix_24 (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
|
||||
test_ip4_missing_prefix (client, "192.168.1.10", 24);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip4_missing_prefix_16 (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
|
||||
test_ip4_missing_prefix (client, "172.16.54.50", 16);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip4_missing_prefix_8 (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
|
||||
test_ip4_missing_prefix (client, "10.1.2.3", 8);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip4_prefix_classless (gconstpointer test_data)
|
||||
{
|
||||
const char *client = test_data;
|
||||
GHashTable *options;
|
||||
NMIP4Config *ip4_config;
|
||||
const NMPlatformIP4Address *address;
|
||||
|
||||
/* Ensure that the missing-subnet-mask handler doesn't mangle classless
|
||||
* subnet masks at all. The handler should trigger only if the server
|
||||
* doesn't send the subnet mask.
|
||||
*/
|
||||
|
||||
options = fill_table (generic_options, NULL);
|
||||
g_hash_table_insert (options, "new_ip_address", string_to_byte_array_gvalue ("172.16.54.22"));
|
||||
g_hash_table_insert (options, "new_subnet_mask", string_to_byte_array_gvalue ("255.255.252.0"));
|
||||
|
||||
ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
|
||||
ASSERT (ip4_config != NULL,
|
||||
"dhcp-ip4-prefix-classless", "failed to parse DHCP4 options");
|
||||
|
||||
ASSERT (nm_ip4_config_get_num_addresses (ip4_config) == 1,
|
||||
"dhcp-ip4-prefix-classless", "unexpected number of IP4 addresses (not 1)");
|
||||
|
||||
address = nm_ip4_config_get_address (ip4_config, 0);
|
||||
ASSERT (address,
|
||||
"dhcp-ip4-prefix-classless", "missing IP4 address #1");
|
||||
|
||||
ASSERT (address->plen == 22,
|
||||
"dhcp-ip4-prefix-classless", "unexpected IP4 address prefix %d (expected 22)",
|
||||
address->plen);
|
||||
|
||||
g_hash_table_destroy (options);
|
||||
}
|
||||
|
||||
NMTST_DEFINE ();
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
char *path;
|
||||
const char *clients[2][2] = { {DHCLIENT_PATH, "dhclient"}, {DHCPCD_PATH, "dhcpcd"} };
|
||||
guint32 i;
|
||||
|
||||
nmtst_init_assert_logging (&argc, &argv);
|
||||
nm_logging_setup ("WARN", "DEFAULT", NULL, NULL);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
const char *client_path = clients[i][0];
|
||||
const char *client = clients[i][1];
|
||||
|
||||
if (!client_path || !strlen (client_path))
|
||||
continue;
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/generic-options", client);
|
||||
g_test_add_data_func (path, client, test_generic_options);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/wins-options", client);
|
||||
g_test_add_data_func (path, client, test_wins_options);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/classless-static-routes-1", client);
|
||||
g_test_add_data_func (path, client, test_classless_static_routes_1);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/classless-static-routes-2", client);
|
||||
g_test_add_data_func (path, client, test_classless_static_routes_2);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/fedora-dhclient-classless-static-routes", client);
|
||||
g_test_add_data_func (path, client, test_fedora_dhclient_classless_static_routes);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/dhclient-invalid-classless-routes-1", client);
|
||||
g_test_add_data_func (path, client, test_dhclient_invalid_classless_routes_1);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/dhcpcd-invalid-classless-routes-1", client);
|
||||
g_test_add_data_func (path, client, test_dhcpcd_invalid_classless_routes_1);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/dhclient-invalid-classless-routes-2", client);
|
||||
g_test_add_data_func (path, client, test_dhclient_invalid_classless_routes_2);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/dhcpcd-invalid-classless-routes-2", client);
|
||||
g_test_add_data_func (path, client, test_dhcpcd_invalid_classless_routes_2);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/dhclient-invalid-classless-routes-3", client);
|
||||
g_test_add_data_func (path, client, test_dhclient_invalid_classless_routes_3);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/dhcpcd-invalid-classless-routes-3", client);
|
||||
g_test_add_data_func (path, client, test_dhcpcd_invalid_classless_routes_3);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/dhclient-gw-in-classless-routes", client);
|
||||
g_test_add_data_func (path, client, test_dhclient_gw_in_classless_routes);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/dhcpcd-gw-in-classless-routes", client);
|
||||
g_test_add_data_func (path, client, test_dhcpcd_gw_in_classless_routes);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/escaped-domain-searches", client);
|
||||
g_test_add_data_func (path, client, test_escaped_domain_searches);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/invalid-escaped-domain-searches", client);
|
||||
g_test_add_data_func (path, client, test_invalid_escaped_domain_searches);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/ip4-missing-prefix-24", client);
|
||||
g_test_add_data_func (path, client, test_ip4_missing_prefix_24);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/ip4-missing-prefix-16", client);
|
||||
g_test_add_data_func (path, client, test_ip4_missing_prefix_16);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/ip4-missing-prefix-8", client);
|
||||
g_test_add_data_func (path, client, test_ip4_missing_prefix_8);
|
||||
g_free (path);
|
||||
|
||||
path = g_strdup_printf ("/dhcp/%s/ip4-prefix-classless", client);
|
||||
g_test_add_data_func (path, client, test_ip4_prefix_classless);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
Loading…
Add table
Reference in a new issue