about summary refs log tree commit diff
path: root/src/dhcp/nm-dhcp-systemd.c
diff options
context:
space:
mode:
authorSebastien Bacher <seb128@ubuntu.com>2019-03-12 15:13:33 +0100
committerSebastien Bacher <seb128@ubuntu.com>2019-03-12 15:13:33 +0100
commitdd428301eb6f02542015121d7b08d9997f137e50 (patch)
tree5530189f63510287d65268fc36025bdbc9414c00 /src/dhcp/nm-dhcp-systemd.c
parentbbae86d3d2997a853ca0365e8eb7a3ca7489ee09 (diff)
New upstream version 1.15.91
Diffstat (limited to 'src/dhcp/nm-dhcp-systemd.c')
-rw-r--r--src/dhcp/nm-dhcp-systemd.c143
1 files changed, 82 insertions, 61 deletions
diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c
index bcbe916f..70ed8715 100644
--- a/src/dhcp/nm-dhcp-systemd.c
+++ b/src/dhcp/nm-dhcp-systemd.c
@@ -18,9 +18,7 @@
 
 #include "nm-default.h"
 
-#include <string.h>
 #include <stdlib.h>
-#include <errno.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <netinet/in.h>
@@ -269,28 +267,35 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx,
 	gint64 ts_time = time (NULL);
 	struct in_addr a_address;
 	struct in_addr a_netmask;
-	struct in_addr a_router;
+	const struct in_addr *a_router;
 	guint32 a_plen;
 	guint32 a_lifetime;
 
 	g_return_val_if_fail (lease != NULL, NULL);
 
-	ip4_config = nm_ip4_config_new (multi_idx, ifindex);
-
-	options = out_options ? create_options_dict () : NULL;
-
 	if (sd_dhcp_lease_get_address (lease, &a_address) < 0) {
 		nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "could not get address from lease");
 		return NULL;
 	}
-	nm_utils_inet4_ntop (a_address.s_addr, addr_str);
-	LOG_LEASE (LOGD_DHCP4, "address %s", addr_str);
-	add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, addr_str);
 
 	if (sd_dhcp_lease_get_netmask (lease, &a_netmask) < 0) {
 		nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "could not get netmask from lease");
 		return NULL;
 	}
+
+	if (sd_dhcp_lease_get_lifetime (lease, &a_lifetime) < 0) {
+		nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "could not get lifetime from lease");
+		return NULL;
+	}
+
+	ip4_config = nm_ip4_config_new (multi_idx, ifindex);
+
+	options = out_options ? create_options_dict () : NULL;
+
+	nm_utils_inet4_ntop (a_address.s_addr, addr_str);
+	LOG_LEASE (LOGD_DHCP4, "address %s", addr_str);
+	add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, addr_str);
+
 	a_plen = nm_utils_ip4_netmask_to_prefix (a_netmask.s_addr);
 	LOG_LEASE (LOGD_DHCP4, "plen %u", (guint) a_plen);
 	add_option (options,
@@ -298,10 +303,6 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx,
 	            SD_DHCP_OPTION_SUBNET_MASK,
 	            nm_utils_inet4_ntop (a_netmask.s_addr, addr_str));
 
-	if (sd_dhcp_lease_get_lifetime (lease, &a_lifetime) < 0) {
-		nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "could not get lifetime from lease");
-		return NULL;
-	}
 	LOG_LEASE (LOGD_DHCP4, "expires in %u seconds (at %lld)",
 	           (guint) a_lifetime,
 	           (long long) (ts_time + a_lifetime));
@@ -325,41 +326,44 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx,
 	if (num > 0) {
 		nm_gstring_prepare (&str);
 		for (i = 0; i < num; i++) {
-			if (addr_list[i].s_addr) {
-				nm_ip4_config_add_nameserver (ip4_config, addr_list[i].s_addr);
-				s = nm_utils_inet4_ntop (addr_list[i].s_addr, addr_str);
-				LOG_LEASE (LOGD_DHCP4, "nameserver '%s'", s);
-				g_string_append_printf (str, "%s%s", str->len ? " " : "", s);
+			nm_utils_inet4_ntop (addr_list[i].s_addr, addr_str);
+			g_string_append (nm_gstring_add_space_delimiter (str), addr_str);
+
+			if (   addr_list[i].s_addr == 0
+			    || nm_ip4_addr_is_localhost (addr_list[i].s_addr)) {
+				/* Skip localhost addresses, like also networkd does.
+				 * See https://github.com/systemd/systemd/issues/4524. */
+				continue;
 			}
+			nm_ip4_config_add_nameserver (ip4_config, addr_list[i].s_addr);
 		}
-		if (str->len)
-			add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME_SERVER, str->str);
+		LOG_LEASE (LOGD_DHCP4, "nameserver '%s'", str->str);
+		add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME_SERVER, str->str);
 	}
 
 	num = sd_dhcp_lease_get_search_domains (lease, (char ***) &search_domains);
 	if (num > 0) {
 		nm_gstring_prepare (&str);
 		for (i = 0; i < num; i++) {
+			g_string_append (nm_gstring_add_space_delimiter (str), search_domains[i]);
 			nm_ip4_config_add_search (ip4_config, search_domains[i]);
-			g_string_append_printf (str, "%s%s", str->len ? " " : "", search_domains[i]);
-			LOG_LEASE (LOGD_DHCP4, "domain search '%s'", search_domains[i]);
 		}
+		LOG_LEASE (LOGD_DHCP4, "domain search '%s'", str->str);
 		add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST, str->str);
 	}
 
-	if (   sd_dhcp_lease_get_domainname (lease, &s) >= 0
-	    && s) {
+	if (sd_dhcp_lease_get_domainname (lease, &s) >= 0) {
 		gs_strfreev char **domains = NULL;
 		char **d;
 
+		LOG_LEASE (LOGD_DHCP4, "domain name '%s'", s);
+		add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME, s);
+
 		/* Multiple domains sometimes stuffed into option 15 "Domain Name".
 		 * As systemd escapes such characters, split them at \\032. */
 		domains = g_strsplit (s, "\\032", 0);
-		for (d = domains; *d; d++) {
-			LOG_LEASE (LOGD_DHCP4, "domain name '%s'", *d);
+		for (d = domains; *d; d++)
 			nm_ip4_config_add_domain (ip4_config, *d);
-		}
-		add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME, s);
 	}
 
 	if (sd_dhcp_lease_get_hostname (lease, &s) >= 0) {
@@ -479,45 +483,66 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx,
 			add_option (options, dhcp4_requests, SD_DHCP_OPTION_STATIC_ROUTE, str_static->str);
 	}
 
-	/* FIXME: internal client only supports returing the first router. */
-	if (sd_dhcp_lease_get_router (lease, &a_router) >= 0) {
-		s = nm_utils_inet4_ntop (a_router.s_addr, addr_str);
-		LOG_LEASE (LOGD_DHCP4, "gateway %s", s);
-		add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROUTER, s);
-
-		/* If the DHCP server returns both a Classless Static Routes option and a
-		 * Router option, the DHCP client MUST ignore the Router option [RFC 3442].
-		 *
-		 * Be more lenient and ignore the Router option only if Classless Static
-		 * Routes contain a default gateway (as other DHCP backends do).
-		 */
-		if (!has_router_from_classless) {
+	num = sd_dhcp_lease_get_router (lease, &a_router);
+	if (num > 0) {
+		guint32 default_route_metric = route_metric;
+
+		nm_gstring_prepare (&str);
+		for (i = 0; i < num; i++) {
+			guint32 m;
+
+			s = nm_utils_inet4_ntop (a_router[i].s_addr, addr_str);
+			g_string_append (nm_gstring_add_space_delimiter (str), s);
+
+			if (a_router[i].s_addr == 0) {
+				/* silently skip 0.0.0.0 */
+				continue;
+			}
+
+			if (has_router_from_classless) {
+				/* If the DHCP server returns both a Classless Static Routes option and a
+				 * Router option, the DHCP client MUST ignore the Router option [RFC 3442].
+				 *
+				 * Be more lenient and ignore the Router option only if Classless Static
+				 * Routes contain a default gateway (as other DHCP backends do).
+				 */
+				continue;
+			}
+
+			/* if there are multiple default routes, we add them with differing
+			 * metrics. */
+			m = default_route_metric;
+			if (default_route_metric < G_MAXUINT32)
+				default_route_metric++;
+
 			nm_ip4_config_add_route (ip4_config,
 			                         &((const NMPlatformIP4Route) {
 			                             .rt_source     = NM_IP_CONFIG_SOURCE_DHCP,
-			                             .gateway       = a_router.s_addr,
+			                             .gateway       = a_router[i].s_addr,
 			                             .table_coerced = nm_platform_route_table_coerce (route_table),
-			                             .metric        = route_metric,
+			                             .metric        = m,
 			                         }),
 			                         NULL);
 		}
+		LOG_LEASE (LOGD_DHCP4, "router %s", str->str);
+		add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROUTER, str->str);
 	}
 
 	if (   sd_dhcp_lease_get_mtu (lease, &mtu) >= 0
 	    && mtu) {
-		nm_ip4_config_set_mtu (ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP);
-		add_option_u64 (options, dhcp4_requests, SD_DHCP_OPTION_INTERFACE_MTU, mtu);
 		LOG_LEASE (LOGD_DHCP4, "mtu %u", mtu);
+		add_option_u64 (options, dhcp4_requests, SD_DHCP_OPTION_INTERFACE_MTU, mtu);
+		nm_ip4_config_set_mtu (ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP);
 	}
 
 	num = sd_dhcp_lease_get_ntp (lease, &addr_list);
 	if (num > 0) {
 		nm_gstring_prepare (&str);
 		for (i = 0; i < num; i++) {
-			s = nm_utils_inet4_ntop (addr_list[i].s_addr, addr_str);
-			LOG_LEASE (LOGD_DHCP4, "ntp server '%s'", s);
-			g_string_append_printf (str, "%s%s", str->len ? " " : "", s);
+			nm_utils_inet4_ntop (addr_list[i].s_addr, addr_str);
+			g_string_append (nm_gstring_add_space_delimiter (str), addr_str);
 		}
+		LOG_LEASE (LOGD_DHCP4, "ntp server '%s'", str->str);
 		add_option (options, dhcp4_requests, SD_DHCP_OPTION_NTP_SERVER, str->str);
 	}
 
@@ -826,6 +851,7 @@ lease_to_ip6_config (NMDedupMultiIndex *multi_idx,
 	sd_dhcp6_lease_reset_address_iter (lease);
 	nm_gstring_prepare (&str);
 	while (sd_dhcp6_lease_get_address (lease, &tmp_addr, &lft_pref, &lft_valid) >= 0) {
+		char sbuf[400];
 		const NMPlatformIP6Address address = {
 			.plen        = 128,
 			.address     = tmp_addr,
@@ -838,15 +864,12 @@ lease_to_ip6_config (NMDedupMultiIndex *multi_idx,
 		nm_ip6_config_add_address (ip6_config, &address);
 
 		nm_utils_inet6_ntop (&tmp_addr, addr_str);
-		if (str->len)
-			g_string_append_c (str, ' ');
-		g_string_append (str, addr_str);
+		g_string_append (nm_gstring_add_space_delimiter (str), addr_str);
 
 		LOG_LEASE (LOGD_DHCP6,
 		           "address %s",
-		           nm_platform_ip6_address_to_string (&address, NULL, 0));
+		           nm_platform_ip6_address_to_string (&address, sbuf, sizeof (sbuf)));
 	};
-
 	if (str->len)
 		add_option (options, dhcp6_requests, DHCP6_OPTION_IP_ADDRESS, str->str);
 
@@ -863,13 +886,11 @@ lease_to_ip6_config (NMDedupMultiIndex *multi_idx,
 	if (num > 0) {
 		nm_gstring_prepare (&str);
 		for (i = 0; i < num; i++) {
-			nm_ip6_config_add_nameserver (ip6_config, &dns[i]);
 			nm_utils_inet6_ntop (&dns[i], addr_str);
-			if (str->len)
-				g_string_append_c (str, ' ');
-			g_string_append (str, addr_str);
-			LOG_LEASE (LOGD_DHCP6, "nameserver %s", addr_str);
+			g_string_append (nm_gstring_add_space_delimiter (str), addr_str);
+			nm_ip6_config_add_nameserver (ip6_config, &dns[i]);
 		}
+		LOG_LEASE (LOGD_DHCP6, "nameserver %s", str->str);
 		add_option (options, dhcp6_requests, SD_DHCP6_OPTION_DNS_SERVERS, str->str);
 	}
 
@@ -877,10 +898,10 @@ lease_to_ip6_config (NMDedupMultiIndex *multi_idx,
 	if (num > 0) {
 		nm_gstring_prepare (&str);
 		for (i = 0; i < num; i++) {
+			g_string_append (nm_gstring_add_space_delimiter (str), domains[i]);
 			nm_ip6_config_add_search (ip6_config, domains[i]);
-			g_string_append_printf (str, "%s%s", str->len ? " " : "", domains[i]);
-			LOG_LEASE (LOGD_DHCP6, "domain name '%s'", domains[i]);
 		}
+		LOG_LEASE (LOGD_DHCP6, "domain name '%s'", str->str);
 		add_option (options, dhcp6_requests, SD_DHCP6_OPTION_DOMAIN_LIST, str->str);
 	}