Blob Blame History Raw
From 31fe84e467732463eabc8f70c2a419008e7a227c Mon Sep 17 00:00:00 2001
From: Scott Shambarger <devel@shambarger.net>
Date: Thu, 9 Jan 2014 14:26:53 -0800
Subject: [PATCH] core: Add host route for DHCP4 server if outside assigned
 subnet (bgo #721767)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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.

https://bugzilla.gnome.org/show_bug.cgi?id=721767
https://bugzilla.redhat.com/show_bug.cgi?id=983325

Signed-off-by: Thomas Haller <thaller@redhat.com>
Signed-off-by: Jiří Klimeš <jklimes@redhat.com>
---
 src/dhcp-manager/nm-dhcp-client.c | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index edea8f8..75cd818 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -1200,8 +1200,8 @@ ip4_options_to_config (NMDHCPClient *self)
 
 			for (s = routers; *s; s++) {
 				/* FIXME: how to handle multiple routers? */
-				if (inet_pton (AF_INET, *s, &tmp_addr) > 0) {
-					nm_ip4_config_set_gateway (ip4_config, tmp_addr);
+				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
@@ -1211,6 +1211,41 @@ ip4_options_to_config (NMDHCPClient *self)
 		}
 	}
 
+	/*
+	 * 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 (priv->options, "new_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;
+				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 (priv->options, "new_dhcp_lease_time");
 	if (str) {
 		address.lifetime = address.preferred = strtoul (str, NULL, 10);
-- 
1.7.11.7