From ee9c73a923909e23a649407be77e25235d769e25 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Fri, 11 May 2018 22:08:45 +0200 Subject: New upstream version 1.10.8 --- src/dhcp/nm-dhcp-dhclient-utils.c | 330 +++++++++++++++++++++++++++++++------- 1 file changed, 273 insertions(+), 57 deletions(-) (limited to 'src/dhcp/nm-dhcp-dhclient-utils.c') diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index 52923310..4df90d76 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -125,7 +125,7 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname, gboolean * as long as all the characters are printable. */ for (i = 1; (p[0] == 0) && i < l; i++) { - if (!g_ascii_isprint (p[i]) || p[i] == '\\' || p[i] == '"') + if (!g_ascii_isprint (p[i])) break; } @@ -138,9 +138,8 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname, gboolean g_string_append_printf (str, "%02x", (guint8) p[i]); } } else { - /* Printable; just add to the line with type 0 */ + /* Printable; just add to the line minus the 'type' */ g_string_append_c (str, '"'); - g_string_append (str, "\\x00"); g_string_append_len (str, p + 1, l - 1); g_string_append_c (str, '"'); } @@ -178,60 +177,31 @@ read_client_id (const char *str) { gs_free char *s = NULL; char *p; - int i = 0, j = 0; nm_assert (!strncmp (str, CLIENTID_TAG, NM_STRLEN (CLIENTID_TAG))); - str += NM_STRLEN (CLIENTID_TAG); - if (!g_ascii_isspace (*str)) - return NULL; + str += NM_STRLEN (CLIENTID_TAG); while (g_ascii_isspace (*str)) str++; if (*str == '"') { - /* Parse string literal with escape sequences */ s = g_strdup (str + 1); p = strrchr (s, '"'); if (p) *p = '\0'; else return NULL; + } else + s = g_strdup (str); - if (!s[0]) - return NULL; - - while (s[i]) { - if ( s[i] == '\\' - && s[i + 1] == 'x' - && g_ascii_isxdigit (s[i + 2]) - && g_ascii_isxdigit (s[i + 3])) { - s[j++] = (g_ascii_xdigit_value (s[i + 2]) << 4) - + g_ascii_xdigit_value (s[i + 3]); - i += 4; - continue; - } - if ( s[i] == '\\' - && s[i + 1] >= '0' && s[i + 1] <= '7' - && s[1 + 2] >= '0' && s[i + 2] <= '7' - && s[1 + 3] >= '0' && s[i + 3] <= '7') { - s[j++] = ((s[i + 1] - '0') << 6) - + ((s[i + 2] - '0') << 3) - + ( s[i + 3] - '0'); - i += 4; - continue; - } - s[j++] = s[i++]; - } - return g_bytes_new_take (g_steal_pointer (&s), j); - } - - /* Otherwise, try to read a hexadecimal sequence */ - s = g_strdup (str); g_strchomp (s); if (s[strlen (s) - 1] == ';') s[strlen (s) - 1] = '\0'; - return nm_utils_hexstr2bin (s); + if (!s[0]) + return NULL; + + return nm_dhcp_utils_client_id_string_to_bytes (s); } GBytes * @@ -309,7 +279,6 @@ nm_dhcp_dhclient_create_config (const char *interface, g_return_val_if_fail (!anycast_addr || nm_utils_hwaddr_valid (anycast_addr, ETH_ALEN), NULL); g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), NULL); - nm_assert (!out_new_client_id || !*out_new_client_id); new_contents = g_string_new (_("# Created by NetworkManager\n")); fqdn_opts = g_ptr_array_sized_new (5); @@ -363,8 +332,6 @@ nm_dhcp_dhclient_create_config (const char *interface, continue; /* Otherwise capture and return the existing client id */ - if (out_new_client_id) - g_clear_pointer (out_new_client_id, g_bytes_unref); NM_SET_OUT (out_new_client_id, read_client_id (p)); } @@ -477,20 +444,14 @@ nm_dhcp_dhclient_create_config (const char *interface, /* Roughly follow what dhclient's quotify_buf() and pretty_escape() functions do */ char * -nm_dhcp_dhclient_escape_duid (GBytes *duid) +nm_dhcp_dhclient_escape_duid (const GByteArray *duid) { char *escaped; - const guint8 *s, *s0; - gsize len; + const guint8 *s = duid->data; char *d; - g_return_val_if_fail (duid, NULL); - - s0 = g_bytes_get_data (duid, &len); - s = s0; - - d = escaped = g_malloc ((len * 4) + 1); - while (s < (s0 + len)) { + d = escaped = g_malloc0 ((duid->len * 4) + 1); + while (s < (duid->data + duid->len)) { if (!g_ascii_isprint (*s)) { *d++ = '\\'; *d++ = '0' + ((*s >> 6) & 0x7); @@ -504,7 +465,6 @@ nm_dhcp_dhclient_escape_duid (GBytes *duid) } else *d++ = *s++; } - *d++ = '\0'; return escaped; } @@ -516,7 +476,7 @@ isoctal (const guint8 *p) && p[2] >= '0' && p[2] <= '7'); } -GBytes * +GByteArray * nm_dhcp_dhclient_unescape_duid (const char *duid) { GByteArray *unescaped; @@ -547,7 +507,7 @@ nm_dhcp_dhclient_unescape_duid (const char *duid) g_byte_array_append (unescaped, &p[i], 1); } - return g_byte_array_free_to_bytes (unescaped); + return unescaped; error: g_byte_array_free (unescaped, TRUE); @@ -556,10 +516,10 @@ error: #define DUID_PREFIX "default-duid \"" -GBytes * +GByteArray * nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error) { - GBytes *duid = NULL; + GByteArray *duid = NULL; char *contents; char **line, **split, *p, *e; @@ -643,3 +603,259 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, g_string_free (s, TRUE); 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: + * @multi_idx: the multi index instance for the ip config object + * @addr_family: whether to read IPv4 or IPv6 leases + * @iface: the interface name to match leases with + * @ifindex: interface index of @iface + * @route_table: the route table for the default route. + * @route_metric: the route metric for the default route. + * @contents: the contents of a dhclient leasefile + * @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 @addr_family. + * + * Returns: a #GSList of #NMIP4Config objects (if @addr_family is %AF_INET) or a list of + * #NMIP6Config objects (if @addr_family is %AF_INET6) containing the lease data. + */ +GSList * +nm_dhcp_dhclient_read_lease_ip_configs (NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + guint32 route_table, + guint32 route_metric, + const char *contents, + GDateTime *now) +{ + GSList *parsed = NULL, *iter, *leases = NULL; + char **line, **split = NULL; + GHashTable *hash = NULL; + gint32 now_monotonic_ts; + + g_return_val_if_fail (contents != NULL, NULL); + nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + + 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 (nm_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 (); + now_monotonic_ts = nm_utils_get_monotonic_timestamp_s (); + + 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, NM_PLATFORM_LIFETIME_PERMANENT-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; + address.peer_address = address.address; + + /* 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.timestamp = now_monotonic_ts; + address.lifetime = address.preferred = expiry; + address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; + + ip4 = nm_ip4_config_new (multi_idx, ifindex); + nm_ip4_config_add_address (ip4, &address); + + { + const NMPlatformIP4Route r = { + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .gateway = gw, + .table_coerced = nm_platform_route_table_coerce (route_table), + .metric = route_metric, + }; + + nm_ip4_config_add_route (ip4, &r, NULL); + } + + 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; +} + -- cgit 1.3.0-6-gf8a5 From 04bc9e1cd3544445d883ad29ea108c1645c8e7b7 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Mon, 4 Jun 2018 00:07:45 +0200 Subject: New upstream version 1.11.4 --- src/dhcp/nm-dhcp-dhclient-utils.c | 331 +++++++------------------------------- 1 file changed, 57 insertions(+), 274 deletions(-) (limited to 'src/dhcp/nm-dhcp-dhclient-utils.c') diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index 4df90d76..16a76d23 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -95,7 +95,6 @@ grab_request_options (GPtrArray *store, const char* line) return end; } - static void add_hostname4 (GString *str, const char *hostname, gboolean use_fqdn) { @@ -125,7 +124,7 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname, gboolean * as long as all the characters are printable. */ for (i = 1; (p[0] == 0) && i < l; i++) { - if (!g_ascii_isprint (p[i])) + if (!g_ascii_isprint (p[i]) || p[i] == '\\' || p[i] == '"') break; } @@ -138,8 +137,9 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname, gboolean g_string_append_printf (str, "%02x", (guint8) p[i]); } } else { - /* Printable; just add to the line minus the 'type' */ + /* Printable; just add to the line with type 0 */ g_string_append_c (str, '"'); + g_string_append (str, "\\x00"); g_string_append_len (str, p + 1, l - 1); g_string_append_c (str, '"'); } @@ -177,31 +177,60 @@ read_client_id (const char *str) { gs_free char *s = NULL; char *p; + int i = 0, j = 0; nm_assert (!strncmp (str, CLIENTID_TAG, NM_STRLEN (CLIENTID_TAG))); - str += NM_STRLEN (CLIENTID_TAG); + + if (!g_ascii_isspace (*str)) + return NULL; while (g_ascii_isspace (*str)) str++; if (*str == '"') { + /* Parse string literal with escape sequences */ s = g_strdup (str + 1); p = strrchr (s, '"'); if (p) *p = '\0'; else return NULL; - } else - s = g_strdup (str); + if (!s[0]) + return NULL; + + while (s[i]) { + if ( s[i] == '\\' + && s[i + 1] == 'x' + && g_ascii_isxdigit (s[i + 2]) + && g_ascii_isxdigit (s[i + 3])) { + s[j++] = (g_ascii_xdigit_value (s[i + 2]) << 4) + + g_ascii_xdigit_value (s[i + 3]); + i += 4; + continue; + } + if ( s[i] == '\\' + && s[i + 1] >= '0' && s[i + 1] <= '7' + && s[1 + 2] >= '0' && s[i + 2] <= '7' + && s[1 + 3] >= '0' && s[i + 3] <= '7') { + s[j++] = ((s[i + 1] - '0') << 6) + + ((s[i + 2] - '0') << 3) + + ( s[i + 3] - '0'); + i += 4; + continue; + } + s[j++] = s[i++]; + } + return g_bytes_new_take (g_steal_pointer (&s), j); + } + + /* Otherwise, try to read a hexadecimal sequence */ + s = g_strdup (str); g_strchomp (s); if (s[strlen (s) - 1] == ';') s[strlen (s) - 1] = '\0'; - if (!s[0]) - return NULL; - - return nm_dhcp_utils_client_id_string_to_bytes (s); + return nm_utils_hexstr2bin (s); } GBytes * @@ -279,6 +308,7 @@ nm_dhcp_dhclient_create_config (const char *interface, g_return_val_if_fail (!anycast_addr || nm_utils_hwaddr_valid (anycast_addr, ETH_ALEN), NULL); g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), NULL); + nm_assert (!out_new_client_id || !*out_new_client_id); new_contents = g_string_new (_("# Created by NetworkManager\n")); fqdn_opts = g_ptr_array_sized_new (5); @@ -332,6 +362,8 @@ nm_dhcp_dhclient_create_config (const char *interface, continue; /* Otherwise capture and return the existing client id */ + if (out_new_client_id) + g_clear_pointer (out_new_client_id, g_bytes_unref); NM_SET_OUT (out_new_client_id, read_client_id (p)); } @@ -444,14 +476,20 @@ nm_dhcp_dhclient_create_config (const char *interface, /* Roughly follow what dhclient's quotify_buf() and pretty_escape() functions do */ char * -nm_dhcp_dhclient_escape_duid (const GByteArray *duid) +nm_dhcp_dhclient_escape_duid (GBytes *duid) { char *escaped; - const guint8 *s = duid->data; + const guint8 *s, *s0; + gsize len; char *d; - d = escaped = g_malloc0 ((duid->len * 4) + 1); - while (s < (duid->data + duid->len)) { + g_return_val_if_fail (duid, NULL); + + s0 = g_bytes_get_data (duid, &len); + s = s0; + + d = escaped = g_malloc ((len * 4) + 1); + while (s < (s0 + len)) { if (!g_ascii_isprint (*s)) { *d++ = '\\'; *d++ = '0' + ((*s >> 6) & 0x7); @@ -465,6 +503,7 @@ nm_dhcp_dhclient_escape_duid (const GByteArray *duid) } else *d++ = *s++; } + *d++ = '\0'; return escaped; } @@ -476,7 +515,7 @@ isoctal (const guint8 *p) && p[2] >= '0' && p[2] <= '7'); } -GByteArray * +GBytes * nm_dhcp_dhclient_unescape_duid (const char *duid) { GByteArray *unescaped; @@ -507,7 +546,7 @@ nm_dhcp_dhclient_unescape_duid (const char *duid) g_byte_array_append (unescaped, &p[i], 1); } - return unescaped; + return g_byte_array_free_to_bytes (unescaped); error: g_byte_array_free (unescaped, TRUE); @@ -516,10 +555,10 @@ error: #define DUID_PREFIX "default-duid \"" -GByteArray * +GBytes * nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error) { - GByteArray *duid = NULL; + GBytes *duid = NULL; char *contents; char **line, **split, *p, *e; @@ -603,259 +642,3 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, g_string_free (s, TRUE); 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: - * @multi_idx: the multi index instance for the ip config object - * @addr_family: whether to read IPv4 or IPv6 leases - * @iface: the interface name to match leases with - * @ifindex: interface index of @iface - * @route_table: the route table for the default route. - * @route_metric: the route metric for the default route. - * @contents: the contents of a dhclient leasefile - * @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 @addr_family. - * - * Returns: a #GSList of #NMIP4Config objects (if @addr_family is %AF_INET) or a list of - * #NMIP6Config objects (if @addr_family is %AF_INET6) containing the lease data. - */ -GSList * -nm_dhcp_dhclient_read_lease_ip_configs (NMDedupMultiIndex *multi_idx, - int addr_family, - const char *iface, - int ifindex, - guint32 route_table, - guint32 route_metric, - const char *contents, - GDateTime *now) -{ - GSList *parsed = NULL, *iter, *leases = NULL; - char **line, **split = NULL; - GHashTable *hash = NULL; - gint32 now_monotonic_ts; - - g_return_val_if_fail (contents != NULL, NULL); - nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - - 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 (nm_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 (); - now_monotonic_ts = nm_utils_get_monotonic_timestamp_s (); - - 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, NM_PLATFORM_LIFETIME_PERMANENT-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; - address.peer_address = address.address; - - /* 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.timestamp = now_monotonic_ts; - address.lifetime = address.preferred = expiry; - address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; - - ip4 = nm_ip4_config_new (multi_idx, ifindex); - nm_ip4_config_add_address (ip4, &address); - - { - const NMPlatformIP4Route r = { - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .gateway = gw, - .table_coerced = nm_platform_route_table_coerce (route_table), - .metric = route_metric, - }; - - nm_ip4_config_add_route (ip4, &r, NULL); - } - - 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; -} - -- cgit 1.3.0-6-gf8a5