dhcp: make dhclient lease parsing code testable
This commit is contained in:
@@ -25,6 +25,8 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include "nm-dhcp-dhclient-utils.h"
|
||||
#include "nm-ip4-config.h"
|
||||
#include "nm-utils.h"
|
||||
|
||||
#define CLIENTID_TAG "send dhcp-client-identifier"
|
||||
#define CLIENTID_FORMAT CLIENTID_TAG " \"%s\"; # added by NetworkManager"
|
||||
@@ -424,3 +426,234 @@ nm_dhcp_dhclient_save_duid (const char *leasefile,
|
||||
return success;
|
||||
}
|
||||
|
||||
static void
|
||||
add_lease_option (GHashTable *hash, char *line)
|
||||
{
|
||||
char *spc;
|
||||
size_t len;
|
||||
|
||||
/* Find the space after "option" */
|
||||
spc = strchr (line, ' ');
|
||||
if (!spc)
|
||||
return;
|
||||
|
||||
/* Find the option tag's data, which is after the second space */
|
||||
if (g_str_has_prefix (line, "option ")) {
|
||||
while (g_ascii_isspace (*spc))
|
||||
spc++;
|
||||
spc = strchr (spc + 1, ' ');
|
||||
if (!spc)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Split the line at the space */
|
||||
*spc = '\0';
|
||||
spc++;
|
||||
|
||||
/* Kill the ';' at the end of the line, if any */
|
||||
len = strlen (spc);
|
||||
if (*(spc + len - 1) == ';')
|
||||
*(spc + len - 1) = '\0';
|
||||
|
||||
/* Strip leading quote */
|
||||
while (g_ascii_isspace (*spc))
|
||||
spc++;
|
||||
if (*spc == '"')
|
||||
spc++;
|
||||
|
||||
/* Strip trailing quote */
|
||||
len = strlen (spc);
|
||||
if (len > 0 && spc[len - 1] == '"')
|
||||
spc[len - 1] = '\0';
|
||||
|
||||
if (spc[0])
|
||||
g_hash_table_insert (hash, g_strdup (line), g_strdup (spc));
|
||||
}
|
||||
|
||||
#define LEASE_INVALID G_MININT64
|
||||
static GTimeSpan
|
||||
lease_validity_span (const char *str_expire, GDateTime *now)
|
||||
{
|
||||
GDateTime *expire = NULL;
|
||||
struct tm expire_tm;
|
||||
GTimeSpan span;
|
||||
|
||||
g_return_val_if_fail (now != NULL, LEASE_INVALID);
|
||||
g_return_val_if_fail (str_expire != NULL, LEASE_INVALID);
|
||||
|
||||
/* Skip initial number (day of week?) */
|
||||
if (!isdigit (*str_expire++))
|
||||
return LEASE_INVALID;
|
||||
if (!isspace (*str_expire++))
|
||||
return LEASE_INVALID;
|
||||
/* Read lease expiration (in UTC) */
|
||||
if (!strptime (str_expire, "%t%Y/%m/%d %H:%M:%S", &expire_tm))
|
||||
return LEASE_INVALID;
|
||||
|
||||
expire = g_date_time_new_utc (expire_tm.tm_year + 1900,
|
||||
expire_tm.tm_mon + 1,
|
||||
expire_tm.tm_mday,
|
||||
expire_tm.tm_hour,
|
||||
expire_tm.tm_min,
|
||||
expire_tm.tm_sec);
|
||||
if (!expire)
|
||||
return LEASE_INVALID;
|
||||
|
||||
span = g_date_time_difference (expire, now);
|
||||
g_date_time_unref (expire);
|
||||
|
||||
/* GDateTime only supports a range of less then 10000 years, so span can
|
||||
* not overflow or be equal to LEASE_INVALID */
|
||||
return span;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_dhcp_dhclient_read_lease_ip_configs:
|
||||
* @iface: the interface name to match leases with
|
||||
* @contents: the contents of a dhclient leasefile
|
||||
* @ipv6: whether to read IPv4 or IPv6 leases
|
||||
* @now: the current UTC date/time; pass %NULL to automatically use current
|
||||
* UTC time. Testcases may need a different value for 'now'
|
||||
*
|
||||
* Reads dhclient leases from @contents and parses them into either
|
||||
* #NMIP4Config or #NMIP6Config objects depending on the value of @ipv6.
|
||||
*
|
||||
* Returns: a #GSList of #NMIP4Config objects (if @ipv6 is %FALSE) or a list of
|
||||
* #NMIP6Config objects (if @ipv6 is %TRUE) containing the lease data.
|
||||
*/
|
||||
GSList *
|
||||
nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
|
||||
const char *contents,
|
||||
gboolean ipv6,
|
||||
GDateTime *now)
|
||||
{
|
||||
GSList *parsed = NULL, *iter, *leases = NULL;
|
||||
char **line, **split = NULL;
|
||||
GHashTable *hash = NULL;
|
||||
|
||||
g_return_val_if_fail (contents != NULL, NULL);
|
||||
|
||||
split = g_strsplit_set (contents, "\n\r", -1);
|
||||
if (!split)
|
||||
return NULL;
|
||||
|
||||
for (line = split; line && *line; line++) {
|
||||
*line = g_strstrip (*line);
|
||||
|
||||
if (*line[0] == '#') {
|
||||
/* Comment */
|
||||
} else if (!strcmp (*line, "}")) {
|
||||
/* Lease ends */
|
||||
parsed = g_slist_append (parsed, hash);
|
||||
hash = NULL;
|
||||
} else if (!strcmp (*line, "lease {")) {
|
||||
/* Beginning of a new lease */
|
||||
if (hash) {
|
||||
/* Ignore malformed lease that doesn't end before new one starts */
|
||||
g_hash_table_destroy (hash);
|
||||
}
|
||||
|
||||
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
} else if (hash && strlen (*line))
|
||||
add_lease_option (hash, *line);
|
||||
}
|
||||
g_strfreev (split);
|
||||
|
||||
/* Check if the last lease in the file was properly ended */
|
||||
if (hash) {
|
||||
/* Ignore malformed lease that doesn't end before new one starts */
|
||||
g_hash_table_destroy (hash);
|
||||
hash = NULL;
|
||||
}
|
||||
|
||||
if (now)
|
||||
g_date_time_ref (now);
|
||||
else
|
||||
now = g_date_time_new_now_utc ();
|
||||
|
||||
for (iter = parsed; iter; iter = g_slist_next (iter)) {
|
||||
NMIP4Config *ip4;
|
||||
NMPlatformIP4Address address;
|
||||
const char *value;
|
||||
GTimeSpan expiry;
|
||||
guint32 tmp, gw = 0;
|
||||
|
||||
hash = iter->data;
|
||||
|
||||
/* Make sure this lease is for the interface we want */
|
||||
value = g_hash_table_lookup (hash, "interface");
|
||||
if (!value || strcmp (value, iface))
|
||||
continue;
|
||||
|
||||
value = g_hash_table_lookup (hash, "expire");
|
||||
if (!value)
|
||||
continue;
|
||||
expiry = lease_validity_span (value, now);
|
||||
if (expiry == LEASE_INVALID)
|
||||
continue;
|
||||
|
||||
/* scale expiry to seconds (and CLAMP into the range of guint32) */
|
||||
expiry = CLAMP (expiry / G_TIME_SPAN_SECOND, 0, G_MAXUINT32-1);
|
||||
if (expiry <= 0) {
|
||||
/* the address is already expired. Don't even add it. */
|
||||
continue;
|
||||
}
|
||||
|
||||
memset (&address, 0, sizeof (address));
|
||||
|
||||
/* IP4 address */
|
||||
value = g_hash_table_lookup (hash, "fixed-address");
|
||||
if (!value)
|
||||
continue;
|
||||
if (!inet_pton (AF_INET, value, &address.address))
|
||||
continue;
|
||||
|
||||
/* Gateway */
|
||||
value = g_hash_table_lookup (hash, "option routers");
|
||||
if (!value)
|
||||
continue;
|
||||
if (!inet_pton (AF_INET, value, &gw))
|
||||
continue;
|
||||
|
||||
/* Netmask */
|
||||
value = g_hash_table_lookup (hash, "option subnet-mask");
|
||||
if (value && inet_pton (AF_INET, value, &tmp))
|
||||
address.plen = nm_utils_ip4_netmask_to_prefix (tmp);
|
||||
|
||||
/* Get default netmask for the IP according to appropriate class. */
|
||||
if (!address.plen)
|
||||
address.plen = nm_utils_ip4_get_default_prefix (address.address);
|
||||
|
||||
address.lifetime = address.preferred = expiry;
|
||||
|
||||
ip4 = nm_ip4_config_new ();
|
||||
nm_ip4_config_add_address (ip4, &address);
|
||||
nm_ip4_config_set_gateway (ip4, gw);
|
||||
|
||||
value = g_hash_table_lookup (hash, "option domain-name-servers");
|
||||
if (value) {
|
||||
char **dns, **dns_iter;
|
||||
|
||||
dns = g_strsplit_set (value, ",", -1);
|
||||
for (dns_iter = dns; dns_iter && *dns_iter; dns_iter++) {
|
||||
if (inet_pton (AF_INET, *dns_iter, &tmp))
|
||||
nm_ip4_config_add_nameserver (ip4, tmp);
|
||||
}
|
||||
if (dns)
|
||||
g_strfreev (dns);
|
||||
}
|
||||
|
||||
value = g_hash_table_lookup (hash, "option domain-name");
|
||||
if (value && value[0])
|
||||
nm_ip4_config_add_domain (ip4, value);
|
||||
|
||||
/* FIXME: static routes */
|
||||
|
||||
leases = g_slist_append (leases, ip4);
|
||||
}
|
||||
|
||||
g_date_time_unref (now);
|
||||
g_slist_free_full (parsed, (GDestroyNotify) g_hash_table_destroy);
|
||||
return leases;
|
||||
}
|
||||
|
||||
|
@@ -44,5 +44,10 @@ gboolean nm_dhcp_dhclient_save_duid (const char *leasefile,
|
||||
const char *escaped_duid,
|
||||
GError **error);
|
||||
|
||||
GSList *nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
|
||||
const char *contents,
|
||||
gboolean ipv6,
|
||||
GDateTime *now);
|
||||
|
||||
#endif /* NM_DHCP_DHCLIENT_UTILS_H */
|
||||
|
||||
|
@@ -136,245 +136,31 @@ get_dhclient_leasefile (const char *iface,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
add_lease_option (GHashTable *hash, char *line)
|
||||
{
|
||||
char *spc;
|
||||
|
||||
spc = strchr (line, ' ');
|
||||
if (!spc) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP lease file line '%s' did not contain a space", line);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If it's an 'option' line, split at second space */
|
||||
if (g_str_has_prefix (line, "option ")) {
|
||||
spc = strchr (spc + 1, ' ');
|
||||
if (!spc) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP lease file option line '%s' did not contain a second space",
|
||||
line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Split the line at the space */
|
||||
*spc = '\0';
|
||||
spc++;
|
||||
|
||||
/* Kill the ';' at the end of the line, if any */
|
||||
if (*(spc + strlen (spc) - 1) == ';')
|
||||
*(spc + strlen (spc) - 1) = '\0';
|
||||
|
||||
/* Treat 'interface' specially */
|
||||
if (g_str_has_prefix (line, "interface")) {
|
||||
if (*(spc) == '"')
|
||||
spc++; /* Jump past the " */
|
||||
if (*(spc + strlen (spc) - 1) == '"')
|
||||
*(spc + strlen (spc) - 1) = '\0'; /* Kill trailing " */
|
||||
}
|
||||
|
||||
g_hash_table_insert (hash, g_strdup (line), g_strdup (spc));
|
||||
}
|
||||
|
||||
static GTimeSpan
|
||||
lease_validity_span (const char *str_expire)
|
||||
{
|
||||
GDateTime *expire = NULL, *now = NULL;
|
||||
struct tm expire_tm;
|
||||
GTimeSpan span = -1;
|
||||
|
||||
g_return_val_if_fail (str_expire != NULL, FALSE);
|
||||
|
||||
/* Skip initial number (day of week?) */
|
||||
if (!isdigit (*str_expire++))
|
||||
return -1;
|
||||
if (!isspace (*str_expire++))
|
||||
return -1;
|
||||
/* Read lease expiration (in UTC) */
|
||||
if (!strptime (str_expire, "%t%Y/%m/%d %H:%M:%S", &expire_tm)) {
|
||||
nm_log_warn (LOGD_DHCP, "couldn't parse DHCP lease file expire time '%s'",
|
||||
str_expire);
|
||||
return -1;
|
||||
}
|
||||
|
||||
expire = g_date_time_new_utc (expire_tm.tm_year + 1900,
|
||||
expire_tm.tm_mon + 1,
|
||||
expire_tm.tm_mday,
|
||||
expire_tm.tm_hour,
|
||||
expire_tm.tm_min,
|
||||
expire_tm.tm_sec);
|
||||
g_warn_if_fail (expire);
|
||||
if (expire) {
|
||||
now = g_date_time_new_now_utc ();
|
||||
span = g_date_time_difference (expire, now);
|
||||
g_date_time_unref (expire);
|
||||
g_date_time_unref (now);
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
GSList *
|
||||
nm_dhcp_dhclient_get_lease_ip_configs (const char *iface,
|
||||
const char *uuid,
|
||||
gboolean ipv6)
|
||||
{
|
||||
GSList *parsed = NULL, *iter, *leases = NULL;
|
||||
char *contents = NULL;
|
||||
char *leasefile;
|
||||
char **line, **split = NULL;
|
||||
GHashTable *hash = NULL;
|
||||
|
||||
/* IPv6 not supported */
|
||||
if (ipv6)
|
||||
return NULL;
|
||||
GSList *leases = NULL;
|
||||
|
||||
leasefile = get_dhclient_leasefile (iface, uuid, FALSE, NULL);
|
||||
if (!leasefile)
|
||||
return NULL;
|
||||
|
||||
if (!g_file_test (leasefile, G_FILE_TEST_EXISTS))
|
||||
goto out;
|
||||
if ( g_file_test (leasefile, G_FILE_TEST_EXISTS)
|
||||
&& g_file_get_contents (leasefile, &contents, NULL, NULL)
|
||||
&& contents
|
||||
&& contents[0])
|
||||
leases = nm_dhcp_dhclient_read_lease_ip_configs (iface, contents, ipv6, NULL);
|
||||
|
||||
if (!g_file_get_contents (leasefile, &contents, NULL, NULL))
|
||||
goto out;
|
||||
|
||||
split = g_strsplit_set (contents, "\n\r", -1);
|
||||
g_free (contents);
|
||||
if (!split)
|
||||
goto out;
|
||||
|
||||
for (line = split; line && *line; line++) {
|
||||
*line = g_strstrip (*line);
|
||||
|
||||
if (!strcmp (*line, "}")) {
|
||||
/* Lease ends */
|
||||
parsed = g_slist_append (parsed, hash);
|
||||
hash = NULL;
|
||||
} else if (!strcmp (*line, "lease {")) {
|
||||
/* Beginning of a new lease */
|
||||
if (hash) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP lease file %s malformed; new lease started "
|
||||
"without ending previous lease",
|
||||
leasefile);
|
||||
g_hash_table_destroy (hash);
|
||||
}
|
||||
|
||||
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
} else if (strlen (*line))
|
||||
add_lease_option (hash, *line);
|
||||
}
|
||||
g_strfreev (split);
|
||||
|
||||
/* Check if the last lease in the file was properly ended */
|
||||
if (hash) {
|
||||
nm_log_warn (LOGD_DHCP, "DHCP lease file %s malformed; new lease started "
|
||||
"without ending previous lease",
|
||||
leasefile);
|
||||
g_hash_table_destroy (hash);
|
||||
hash = NULL;
|
||||
}
|
||||
|
||||
for (iter = parsed; iter; iter = g_slist_next (iter)) {
|
||||
NMIP4Config *ip4;
|
||||
NMPlatformIP4Address address;
|
||||
const char *data;
|
||||
GTimeSpan expiry;
|
||||
guint32 tmp;
|
||||
guint32 plen;
|
||||
|
||||
hash = iter->data;
|
||||
|
||||
/* Make sure this lease is for the interface we want */
|
||||
data = g_hash_table_lookup (hash, "interface");
|
||||
if (!data || strcmp (data, iface))
|
||||
continue;
|
||||
|
||||
data = g_hash_table_lookup (hash, "expire");
|
||||
if (!data)
|
||||
continue;
|
||||
expiry = lease_validity_span (data);
|
||||
|
||||
data = g_hash_table_lookup (hash, "fixed-address");
|
||||
if (!data)
|
||||
continue;
|
||||
|
||||
ip4 = nm_ip4_config_new ();
|
||||
memset (&address, 0, sizeof (address));
|
||||
|
||||
/* IP4 address */
|
||||
if (!inet_pton (AF_INET, data, &tmp)) {
|
||||
nm_log_warn (LOGD_DHCP, "couldn't parse DHCP lease file IP4 address '%s'", data);
|
||||
goto error;
|
||||
}
|
||||
address.address = tmp;
|
||||
|
||||
/* Netmask */
|
||||
data = g_hash_table_lookup (hash, "option subnet-mask");
|
||||
if (data) {
|
||||
if (!inet_pton (AF_INET, data, &tmp)) {
|
||||
nm_log_warn (LOGD_DHCP, "couldn't parse DHCP lease file IP4 subnet mask '%s'", data);
|
||||
goto error;
|
||||
}
|
||||
plen = nm_utils_ip4_netmask_to_prefix (tmp);
|
||||
} else {
|
||||
/* Get default netmask for the IP according to appropriate class. */
|
||||
plen = nm_utils_ip4_get_default_prefix (address.address);
|
||||
}
|
||||
address.plen = plen;
|
||||
address.lifetime = address.preferred = expiry / G_TIME_SPAN_SECOND;
|
||||
nm_ip4_config_add_address (ip4, &address);
|
||||
|
||||
/* Gateway */
|
||||
data = g_hash_table_lookup (hash, "option routers");
|
||||
if (data) {
|
||||
if (!inet_pton (AF_INET, data, &tmp)) {
|
||||
nm_log_warn (LOGD_DHCP, "couldn't parse DHCP lease file IP4 gateway '%s'", data);
|
||||
goto error;
|
||||
}
|
||||
nm_ip4_config_set_gateway (ip4, tmp);
|
||||
}
|
||||
|
||||
data = g_hash_table_lookup (hash, "option domain-name-servers");
|
||||
if (data) {
|
||||
char **dns, **dns_iter;
|
||||
|
||||
dns = g_strsplit_set (data, ",", -1);
|
||||
for (dns_iter = dns; dns_iter && *dns_iter; dns_iter++) {
|
||||
if (inet_pton (AF_INET, *dns_iter, &tmp))
|
||||
nm_ip4_config_add_nameserver (ip4, tmp);
|
||||
}
|
||||
if (dns)
|
||||
g_strfreev (dns);
|
||||
}
|
||||
|
||||
data = g_hash_table_lookup (hash, "option domain-name");
|
||||
if (data) {
|
||||
char *unquoted, *p;
|
||||
|
||||
/* strip quotes */
|
||||
p = unquoted = g_strdup (data[0] == '"' ? data + 1 : data);
|
||||
if ((strlen (p) > 1) && (p[strlen (p) - 1] == '"'))
|
||||
p[strlen (p) - 1] = '\0';
|
||||
|
||||
nm_ip4_config_add_domain (ip4, unquoted);
|
||||
g_free (unquoted);
|
||||
}
|
||||
|
||||
leases = g_slist_append (leases, ip4);
|
||||
continue;
|
||||
|
||||
error:
|
||||
g_object_unref (ip4);
|
||||
}
|
||||
|
||||
out:
|
||||
g_slist_free_full (parsed, (GDestroyNotify) g_hash_table_destroy);
|
||||
g_free (leasefile);
|
||||
g_free (contents);
|
||||
|
||||
return leases;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
merge_dhclient_config (const char *iface,
|
||||
const char *conf_file,
|
||||
|
@@ -4,6 +4,8 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/libnm-util \
|
||||
-I${top_builddir}/libnm-util \
|
||||
-I$(top_srcdir)/src/dhcp-manager \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/src/platform \
|
||||
$(GLIB_CFLAGS) \
|
||||
-DTESTDIR="\"$(abs_srcdir)\""
|
||||
|
||||
@@ -22,5 +24,9 @@ check-local: test-dhcp-dhclient
|
||||
|
||||
EXTRA_DIST = \
|
||||
test-dhclient-duid.leases \
|
||||
test-dhclient-commented-duid.leases
|
||||
test-dhclient-commented-duid.leases \
|
||||
leases/basic.leases \
|
||||
leases/malformed1.leases \
|
||||
leases/malformed2.leases \
|
||||
leases/malformed3.leases
|
||||
|
||||
|
31
src/dhcp-manager/tests/leases/basic.leases
Normal file
31
src/dhcp-manager/tests/leases/basic.leases
Normal file
@@ -0,0 +1,31 @@
|
||||
lease {
|
||||
interface "wlan0";
|
||||
fixed-address 192.168.1.180;
|
||||
option subnet-mask 255.255.255.0;
|
||||
option routers 192.168.1.1;
|
||||
option dhcp-lease-time 600;
|
||||
option dhcp-message-type 5;
|
||||
option domain-name-servers 192.168.1.1;
|
||||
option dhcp-server-identifier 192.168.1.1;
|
||||
option broadcast-address 192.168.1.255;
|
||||
renew 5 2013/11/01 19:56:15;
|
||||
rebind 5 2013/11/01 20:00:44;
|
||||
expire 5 2013/11/01 20:01:59;
|
||||
}
|
||||
lease {
|
||||
interface "wlan0";
|
||||
fixed-address 10.77.52.141;
|
||||
option subnet-mask 255.0.0.0;
|
||||
option dhcp-lease-time 1200;
|
||||
option routers 10.77.52.254;
|
||||
option dhcp-message-type 5;
|
||||
option dhcp-server-identifier 10.77.52.254;
|
||||
option domain-name-servers 8.8.8.8,8.8.4.4;
|
||||
option dhcp-renewal-time 600;
|
||||
option dhcp-rebinding-time 1050;
|
||||
option domain-name "morriesguest.local";
|
||||
renew 5 2013/11/01 20:01:08;
|
||||
rebind 5 2013/11/01 20:05:00;
|
||||
expire 5 2013/11/01 20:06:15;
|
||||
}
|
||||
|
15
src/dhcp-manager/tests/leases/malformed1.leases
Normal file
15
src/dhcp-manager/tests/leases/malformed1.leases
Normal file
@@ -0,0 +1,15 @@
|
||||
# missing fixed-address option
|
||||
lease {
|
||||
interface "wlan0";
|
||||
option subnet-mask 255.255.255.0;
|
||||
option routers 192.168.1.1;
|
||||
option dhcp-lease-time 600;
|
||||
option dhcp-message-type 5;
|
||||
option domain-name-servers 192.168.1.1;
|
||||
option dhcp-server-identifier 192.168.1.1;
|
||||
option broadcast-address 192.168.1.255;
|
||||
renew 5 2013/11/01 19:56:15;
|
||||
rebind 5 2013/11/01 20:00:44;
|
||||
expire 5 2013/11/01 20:01:59;
|
||||
}
|
||||
|
15
src/dhcp-manager/tests/leases/malformed2.leases
Normal file
15
src/dhcp-manager/tests/leases/malformed2.leases
Normal file
@@ -0,0 +1,15 @@
|
||||
# missing routers option
|
||||
lease {
|
||||
interface "wlan0";
|
||||
fixed-address 192.168.1.180;
|
||||
option subnet-mask 255.255.255.0;
|
||||
option dhcp-lease-time 600;
|
||||
option dhcp-message-type 5;
|
||||
option domain-name-servers 192.168.1.1;
|
||||
option dhcp-server-identifier 192.168.1.1;
|
||||
option broadcast-address 192.168.1.255;
|
||||
renew 5 2013/11/01 19:56:15;
|
||||
rebind 5 2013/11/01 20:00:44;
|
||||
expire 5 2013/11/01 20:01:59;
|
||||
}
|
||||
|
15
src/dhcp-manager/tests/leases/malformed3.leases
Normal file
15
src/dhcp-manager/tests/leases/malformed3.leases
Normal file
@@ -0,0 +1,15 @@
|
||||
# missing expire time
|
||||
lease {
|
||||
interface "wlan0";
|
||||
fixed-address 192.168.1.180;
|
||||
option subnet-mask 255.255.255.0;
|
||||
option routers 192.168.1.1;
|
||||
option dhcp-lease-time 600;
|
||||
option dhcp-message-type 5;
|
||||
option domain-name-servers 192.168.1.1;
|
||||
option dhcp-server-identifier 192.168.1.1;
|
||||
option broadcast-address 192.168.1.255;
|
||||
renew 5 2013/11/01 19:56:15;
|
||||
rebind 5 2013/11/01 20:00:44;
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "nm-dhcp-dhclient-utils.h"
|
||||
#include "nm-utils.h"
|
||||
#include "nm-ip4-config.h"
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
@@ -454,6 +455,128 @@ test_write_existing_commented_duid (void)
|
||||
|
||||
/*******************************************/
|
||||
|
||||
static void
|
||||
test_read_lease_ip4_config_basic (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
char *contents = NULL;
|
||||
gboolean success;
|
||||
const char *path = TESTDIR "/leases/basic.leases";
|
||||
GSList *leases;
|
||||
GDateTime *now;
|
||||
NMIP4Config *config;
|
||||
const NMPlatformIP4Address *addr;
|
||||
guint32 expected_addr;
|
||||
|
||||
success = g_file_get_contents (path, &contents, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (success);
|
||||
|
||||
/* Date from before the least expiration */
|
||||
now = g_date_time_new_utc (2013, 11, 1, 19, 55, 32);
|
||||
leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", contents, FALSE, now);
|
||||
g_assert_cmpint (g_slist_length (leases), ==, 2);
|
||||
|
||||
/* IP4Config #1 */
|
||||
config = g_slist_nth_data (leases, 0);
|
||||
g_assert (NM_IS_IP4_CONFIG (config));
|
||||
|
||||
/* Address */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1);
|
||||
g_assert (inet_aton ("192.168.1.180", (struct in_addr *) &expected_addr));
|
||||
addr = nm_ip4_config_get_address (config, 0);
|
||||
g_assert_cmpint (addr->address, ==, expected_addr);
|
||||
g_assert_cmpint (addr->plen, ==, 24);
|
||||
|
||||
/* Gateway */
|
||||
g_assert (inet_aton ("192.168.1.1", (struct in_addr *) &expected_addr));
|
||||
g_assert_cmpint (nm_ip4_config_get_gateway (config), ==, expected_addr);
|
||||
|
||||
/* DNS */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 1);
|
||||
g_assert (inet_aton ("192.168.1.1", (struct in_addr *) &expected_addr));
|
||||
g_assert_cmpint (nm_ip4_config_get_nameserver (config, 0), ==, expected_addr);
|
||||
|
||||
g_assert_cmpint (nm_ip4_config_get_num_domains (config), ==, 0);
|
||||
|
||||
/* IP4Config #2 */
|
||||
config = g_slist_nth_data (leases, 1);
|
||||
g_assert (NM_IS_IP4_CONFIG (config));
|
||||
|
||||
/* Address */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1);
|
||||
g_assert (inet_aton ("10.77.52.141", (struct in_addr *) &expected_addr));
|
||||
addr = nm_ip4_config_get_address (config, 0);
|
||||
g_assert_cmpint (addr->address, ==, expected_addr);
|
||||
g_assert_cmpint (addr->plen, ==, 8);
|
||||
|
||||
/* Gateway */
|
||||
g_assert (inet_aton ("10.77.52.254", (struct in_addr *) &expected_addr));
|
||||
g_assert_cmpint (nm_ip4_config_get_gateway (config), ==, expected_addr);
|
||||
|
||||
/* DNS */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 2);
|
||||
g_assert (inet_aton ("8.8.8.8", (struct in_addr *) &expected_addr));
|
||||
g_assert_cmpint (nm_ip4_config_get_nameserver (config, 0), ==, expected_addr);
|
||||
g_assert (inet_aton ("8.8.4.4", (struct in_addr *) &expected_addr));
|
||||
g_assert_cmpint (nm_ip4_config_get_nameserver (config, 1), ==, expected_addr);
|
||||
|
||||
/* Domains */
|
||||
g_assert_cmpint (nm_ip4_config_get_num_domains (config), ==, 1);
|
||||
g_assert_cmpstr (nm_ip4_config_get_domain (config, 0), ==, "morriesguest.local");
|
||||
|
||||
g_slist_free_full (leases, g_object_unref);
|
||||
g_date_time_unref (now);
|
||||
g_free (contents);
|
||||
}
|
||||
|
||||
static void
|
||||
test_read_lease_ip4_config_expired (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
char *contents = NULL;
|
||||
gboolean success;
|
||||
const char *path = TESTDIR "/leases/basic.leases";
|
||||
GSList *leases;
|
||||
GDateTime *now;
|
||||
|
||||
success = g_file_get_contents (path, &contents, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (success);
|
||||
|
||||
/* Date from *after* the lease expiration */
|
||||
now = g_date_time_new_utc (2013, 12, 1, 19, 55, 32);
|
||||
leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", contents, FALSE, now);
|
||||
g_assert (leases == NULL);
|
||||
|
||||
g_date_time_unref (now);
|
||||
g_free (contents);
|
||||
}
|
||||
|
||||
static void
|
||||
test_read_lease_ip4_config_expect_failure (gconstpointer user_data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
char *contents = NULL;
|
||||
gboolean success;
|
||||
GSList *leases;
|
||||
GDateTime *now;
|
||||
|
||||
success = g_file_get_contents ((const char *) user_data, &contents, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (success);
|
||||
|
||||
/* Date from before the least expiration */
|
||||
now = g_date_time_new_utc (2013, 11, 1, 1, 1, 1);
|
||||
leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", contents, FALSE, now);
|
||||
g_assert (leases == NULL);
|
||||
|
||||
g_date_time_unref (now);
|
||||
g_free (contents);
|
||||
}
|
||||
|
||||
/*******************************************/
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@@ -477,6 +600,18 @@ main (int argc, char **argv)
|
||||
g_test_add_func ("/dhcp/dhclient/write_existing_duid", test_write_existing_duid);
|
||||
g_test_add_func ("/dhcp/dhclient/write_existing_commented_duid", test_write_existing_commented_duid);
|
||||
|
||||
g_test_add_func ("/dhcp/dhclient/leases/ip4-config/basic", test_read_lease_ip4_config_basic);
|
||||
g_test_add_func ("/dhcp/dhclient/leases/ip4-config/expired", test_read_lease_ip4_config_expired);
|
||||
g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-address",
|
||||
TESTDIR "/leases/malformed1.leases",
|
||||
test_read_lease_ip4_config_expect_failure);
|
||||
g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-gateway",
|
||||
TESTDIR "/leases/malformed2.leases",
|
||||
test_read_lease_ip4_config_expect_failure);
|
||||
g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-expire",
|
||||
TESTDIR "/leases/malformed3.leases",
|
||||
test_read_lease_ip4_config_expect_failure);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user