changeset 1321:6b6deaa097de draft

Although RFC2131 requires a ServerID we can actually work without one. Some broken servers don't send a ServerID, so make the requirement optional. We default to requiring ServerID in dhcpcd.conf though as some other broken servers NAK incorrectly without a ServerID.
author Roy Marples <roy@marples.name>
date Wed, 13 May 2009 19:17:21 +0000
parents 8c7fd91fb635
children ba7d6f1ebe43
files dhcpcd.c dhcpcd.conf
diffstat 2 files changed, 52 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/dhcpcd.c	Wed May 13 18:49:49 2009 +0000
+++ b/dhcpcd.c	Wed May 13 19:17:21 2009 +0000
@@ -365,19 +365,6 @@
 }
 
 void
-start_rebind(void *arg)
-{
-	struct interface *iface = arg;
-
-	syslog(LOG_ERR, "%s: failed to renew, attmepting to rebind",
-	    iface->name);
-	iface->state->state = DHS_REBIND;
-	delete_timeout(send_renew, iface);
-	iface->state->lease.server.s_addr = 0;
-	send_rebind(iface);
-}
-
-void
 start_expire(void *arg)
 {
 	struct interface *iface = arg;
@@ -413,10 +400,11 @@
 
 	if (strcmp(msg, "NAK:") == 0)
 		a = get_option_string(dhcp, DHO_MESSAGE);
-	else {
+	else if (dhcp->yiaddr != 0) {
 		addr.s_addr = dhcp->yiaddr;
 		a = xstrdup(inet_ntoa(addr));
-	}
+	} else
+		a = NULL;
 	r = get_option_addr(&addr.s_addr, dhcp, DHO_SERVERID);
 	if (dhcp->servername[0] && r == 0)
 		syslog(lvl, "%s: %s %s from %s `%s'", iface->name, msg, a,
@@ -424,8 +412,10 @@
 	else if (r == 0)
 		syslog(lvl, "%s: %s %s from %s",
 		    iface->name, msg, a, inet_ntoa(addr));
+	else if (a != NULL)
+		syslog(lvl, "%s: %s %s", iface->name, msg, a);
 	else
-		syslog(lvl, "%s: %s %s", iface->name, msg, a);
+		syslog(lvl, "%s: %s", iface->name, msg);
 	free(a);
 }
 
@@ -457,15 +447,16 @@
 	/* We may have found a BOOTP server */
 	if (get_option_uint8(&type, dhcp, DHO_MESSAGETYPE) == -1) 
 		type = 0;
-	else if (get_option_addr(&addr.s_addr, dhcp, DHO_SERVERID) == -1) {
-		/* We should ignore invalid NAK messages without a ServerID */
-		syslog(LOG_WARNING, "%s: ignoring DHCP message; no Server ID",
-		    iface->name);
-		return;
-	}
 
-	/* We should restart on a NAK */
 	if (type == DHCP_NAK) {
+		/* For NAK, only check if we require the ServerID */
+		if (has_option_mask(ifo->requiremask, DHO_SERVERID) &&
+		    get_option_addr(&addr.s_addr, dhcp, DHO_SERVERID) == -1)
+		{
+			log_dhcp(LOG_WARNING, "reject NAK", iface, dhcp);
+			return;
+		}
+		/* We should restart on a NAK */
 		log_dhcp(LOG_WARNING, "NAK:", iface, dhcp);
 		drop_config(iface, "NAK");
 		unlink(iface->leasefile);
@@ -482,27 +473,31 @@
 		return;
 	}
 
-	/* No NAK, so reset the backoff */
-	state->nakoff = 1;
-
 	/* Ensure that all required options are present */
 	for (i = 1; i < 255; i++) {
 		if (has_option_mask(ifo->requiremask, i) &&
 		    get_option_uint8(&tmp, dhcp, i) != 0)
 		{
-			log_dhcp(LOG_WARNING, "reject", iface, dhcp);
+			/* If we are bootp, then ignore the need for serverid.
+			 * To ignore bootp, require dhcp_message_type instead. */
+			if (type == 0 && i == DHO_SERVERID)
+				continue;
+			log_dhcp(LOG_WARNING, "reject DHCP", iface, dhcp);
 			return;
 		}
-	}
+	}		
+
+	/* No NAK, so reset the backoff */
+	state->nakoff = 1;
 
 	if ((type == 0 || type == DHCP_OFFER) &&
 	    state->state == DHS_DISCOVER)
 	{
 		lease->frominfo = 0;
 		lease->addr.s_addr = dhcp->yiaddr;
-		lease->server.s_addr = 0;
+		lease->server.s_addr = INADDR_ANY;
 		if (type != 0)
-			lease->server.s_addr = addr.s_addr;
+			get_option_addr(&lease->server.s_addr, dhcp, DHO_SERVERID);
 		log_dhcp(LOG_INFO, "offered", iface, dhcp);
 		free(state->offer);
 		state->offer = dhcp;
@@ -871,6 +866,21 @@
 	send_renew(iface);
 }
 
+void
+start_rebind(void *arg)
+{
+	struct interface *iface = arg;
+
+	syslog(LOG_ERR, "%s: failed to renew, attmepting to rebind",
+	    iface->name);
+	iface->state->state = DHS_REBIND;
+	delete_timeout(send_renew, iface);
+	iface->state->lease.server.s_addr = 0;
+	if (iface->raw_fd == -1)
+		open_sockets(iface);
+	send_rebind(iface);
+}
+
 static void
 start_timeout(void *arg)
 {
--- a/dhcpcd.conf	Wed May 13 18:49:49 2009 +0000
+++ b/dhcpcd.conf	Wed May 13 19:17:21 2009 +0000
@@ -1,19 +1,25 @@
 # A sample configuration for dhcpcd.
 # See dhcpcd.conf(5) for details.
 
-# We normally want to inform the DHCP server of our hostname for DDNS.
+# Inform the DHCP server of our hostname for DDNS.
 hostname
 
-# A list of options we should request from the DHCP server.
+# A list of options to request from the DHCP server.
 option domain_name_servers, domain_name, domain_search, host_name
-# Most distros have ntp support.
+# Most distributions have NTP support.
 option ntp_servers
 
-# We should behave nicely on networks and respect their MTU.
+# Behave nicely on networks and respect their MTU.
 # However, a lot of buggy DHCP servers set invalid MTUs so this is not
 # enabled by default.
 #option interface_mtu
 
-# We provide a hook script to lookup the hostname if not set by the DHCP
-# server, but we should not run it by default.
+# A ServerID is required by RFC2131.
+# Some broken DHCP servers do not send one and dhcpcd can work without it.
+# Some broken DHCP servers NAK incorrectly and do not include a ServerID either so
+# the default is to require a ServerID.
+require dhcp_server_identifier
+
+# A hook script is provided to lookup the hostname if not set by the DHCP
+# server, but it should not be run by default.
 nohook lookup-hostname