import of dnsmasq-2.6.tar.gz
diff --git a/src/Makefile b/src/Makefile
index c2cb07f..77229d7 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -3,8 +3,8 @@
 
 CFLAGS?= -O2
 
-OBJS = cache.o rfc1035.o util.o option.o forward.o \
-       network.o dnsmasq.o dhcp.o lease.o rfc2131.o
+OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o \
+       network.o dnsmasq.o dhcp.o lease.o rfc2131.o 
 
 .c.o: dnsmasq.h config.h 
 	$(CC) $(CFLAGS) $(RPM_OPT_FLAGS) -Wall -W -c $*.c 
diff --git a/src/config.h b/src/config.h
index ea503f9..ad9e08d 100644
--- a/src/config.h
+++ b/src/config.h
@@ -12,12 +12,13 @@
 
 /* Author's email: simon@thekelleys.org.uk */
 
-#define VERSION "2.5"
+#define VERSION "2.6"
 
 #define FTABSIZ 150 /* max number of outstanding requests */
 #define TIMEOUT 20 /* drop queries after TIMEOUT seconds */
 #define LOGRATE 120 /* log table overflows every LOGRATE seconds */
 #define CACHESIZ 150 /* default cache size */
+#define MAXTOK 50 /* token in DHCP leases */
 #define MAXLEASES 150 /* maximum number of DHCP leases */
 #define SMALLDNAME 40 /* most domain names are smaller than this */
 #define HOSTSFILE "/etc/hosts"
@@ -121,6 +122,10 @@
    work on other systems by teaching dnsmasq_time() in utils.c how to
    read the system uptime.
 
+HAVE_ISC_READER 
+   define this to include the old ISC dhcpcd integration. Note that you cannot
+   set both HAVE_ISC_READER and HAVE_BROKEN_RTC.
+
 HAVE_GETOPT_LONG
    define this if you have GNU libc or GNU getopt. 
 
@@ -175,6 +180,16 @@
 
 */
 
+/* platform independent options. */
+#undef HAVE_BROKEN_RTC
+#define HAVE_ISC_READER
+
+#if defined(HAVE_BROKEN_RTC) && defined(HAVE_ISC_READER)
+#  error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
+#endif
+
+/* platform dependent options. */
+
 /* Must preceed __linux__ since uClinux defines __linux__ too. */
 #if defined(__uClinux__) || defined(__UCLIBC__)
 #undef HAVE_LINUX_IPV6_PROC
@@ -255,6 +270,7 @@
 #define HAVE_SOCKADDR_SA_LEN
 #undef HAVE_PSELECT
 #define HAVE_BPF
+#define BIND_8_COMPAT
 /* Define before sys/socket.h is included so we get socklen_t */
 #define _BSD_SOCKLEN_T_
 /* The two below are not defined in Mac OS X arpa/nameserv.h */
@@ -287,3 +303,4 @@
 
 
 
+
diff --git a/src/dhcp.c b/src/dhcp.c
index f4f71a6..02e42b9 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -362,6 +362,10 @@
   start = ntohl(context->start.s_addr);
   end = ntohl(context->end.s_addr);
 
+  /* static leases only. */
+  if (start == end)
+    return 0;
+
   if (addr < start)
     return 0;
 
@@ -382,7 +386,11 @@
 
   struct dhcp_config *config;
   struct in_addr start = context->last;
-  
+
+  /* start == end means no dynamic leases. */
+  if (context->end.s_addr == context->start.s_addr)
+    return 0;
+
   do {
     if (context->last.s_addr == context->end.s_addr)
       context->last = context->start;
@@ -393,7 +401,7 @@
     if (!lease_find_by_addr(context->last))
       {
 	for (config = configs; config; config = config->next)
-	  if (config->addr.s_addr == context->last.s_addr)
+	  if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == context->last.s_addr)
 	    break;
 	
 	if (!config)
@@ -411,7 +419,7 @@
 {
   if (!context)
     return 1;
-  if (config->addr.s_addr == 0)
+  if (!(config->flags & CONFIG_ADDR))
     return 1;
   if ((config->addr.s_addr & context->netmask.s_addr) == (context->start.s_addr & context->netmask.s_addr))
     return 1;
@@ -428,28 +436,31 @@
   
   if (clid_len)
     for (config = configs; config; config = config->next)
-      {
-	if (config->clid_len == clid_len && 
-	    memcmp(config->clid, clid, clid_len) == 0 &&
-	    is_addr_in_context(context, config))
-	  return config;
-	
-	/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
-	   cope with that here */
-	if (*clid == 0 && config->clid_len == clid_len-1  &&
-	    memcmp(config->clid, clid+1, clid_len-1) == 0 &&
-	    is_addr_in_context(context, config))
-	  return config;
-      }
-    
+      if (config->flags & CONFIG_CLID)
+	{
+	  if (config->clid_len == clid_len && 
+	      memcmp(config->clid, clid, clid_len) == 0 &&
+	      is_addr_in_context(context, config))
+	    return config;
+	  
+	  /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
+	     cope with that here */
+	  if (*clid == 0 && config->clid_len == clid_len-1  &&
+	      memcmp(config->clid, clid+1, clid_len-1) == 0 &&
+	      is_addr_in_context(context, config))
+	    return config;
+	}
+  
   for (config = configs; config; config = config->next)
-    if (memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 &&
+    if ((config->flags & CONFIG_HWADDR) &&
+	memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 &&
 	is_addr_in_context(context, config))
       return config;
   
   if (hostname)
     for (config = configs; config; config = config->next)
-      if (config->hostname && hostname_isequal(config->hostname, hostname) &&
+      if ((config->flags & CONFIG_NAME) && 
+	  hostname_isequal(config->hostname, hostname) &&
 	  is_addr_in_context(context, config))
 	return config;
   
@@ -459,28 +470,29 @@
 struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
 {
   FILE *f = fopen(ETHERSFILE, "r");
-  unsigned int e0, e1, e2, e3, e4, e5;
-  char *ip, *cp, *name;
+  unsigned int flags, e0, e1, e2, e3, e4, e5;
+  char *ip, *cp;
   struct in_addr addr;
+  unsigned char hwaddr[ETHER_ADDR_LEN];
   struct dhcp_config *config;
+  int count = 0;
   
   if (!f)
-    die("failed to open " ETHERSFILE ":%s", NULL);
-  
+    {
+      syslog(LOG_ERR, "failed to read " ETHERSFILE ":%m");
+      return configs;
+    }
+
   while (fgets(buff, MAXDNAME, f))
     {
-      while (strlen(buff) > 0 && 
-	     (buff[strlen(buff)-1] == '\n' || 
-	      buff[strlen(buff)-1] == ' ' || 
-	      buff[strlen(buff)-1] == '\r' || 
-	      buff[strlen(buff)-1] == '\t'))
+      while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
 	buff[strlen(buff)-1] = 0;
       
       if ((*buff == '#') || (*buff == '+'))
 	continue;
       
-      for (ip = buff; *ip && *ip != ' ' && *ip != '\t'; ip++);
-      for(; *ip && (*ip == ' ' || *ip == '\t'); ip++)
+      for (ip = buff; *ip && !isspace(*ip); ip++);
+      for(; *ip && isspace(*ip); ip++)
 	*ip = 0;
       if (!*ip)
 	continue;
@@ -488,6 +500,13 @@
       if (!sscanf(buff, "%x:%x:%x:%x:%x:%x", &e0, &e1, &e2, &e3, &e4, &e5))
 	continue;
       
+      hwaddr[0] = e0;
+      hwaddr[1] = e1;
+      hwaddr[2] = e2;
+      hwaddr[3] = e3;
+      hwaddr[4] = e4;
+      hwaddr[5] = e5;
+
       /* check for name or dotted-quad */
       for (cp = ip; *cp; cp++)
 	if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
@@ -495,47 +514,64 @@
       
       if (!*cp)
 	{
-	  name = NULL;
 	  if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
 	    continue;
+	  flags = CONFIG_ADDR;
 	  
 	  for (config = configs; config; config = config->next)
-	    if (config->addr.s_addr == addr.s_addr)
+	    if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
 	      break;
 	}
       else 
 	{
 	  if (!canonicalise(ip))
 	    continue;
-	  name = ip;
-	  addr.s_addr = 0;
+	  flags = CONFIG_NAME;
 
 	  for (config = configs; config; config = config->next)
-	    if (config->hostname && hostname_isequal(config->hostname, name))
+	    if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, ip))
 	      break;
 	}
       
       if (!config)
 	{ 
-	  config = safe_malloc(sizeof(struct dhcp_config));
-	  config->clid_len = 0;
-	  config->clid = NULL; 
-	  config->lease_time = 0;
-	  config->hostname = safe_string_alloc(name);
-	  config->addr = addr;
-	  config->next = configs;
-	  configs = config;
+	  for (config = configs; config; config = config->next)
+	    if ((config->flags & CONFIG_HWADDR) && 
+		memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
+	      break;
+	  
+	  if (!config)
+	    {
+	      if (!(config = malloc(sizeof(struct dhcp_config))))
+		continue;
+	      config->flags = 0;
+	      config->next = configs;
+	      configs = config;
+	    }
+	  
+	  config->flags |= flags;
+	  
+	  if (flags & CONFIG_NAME)
+	    {
+	      if ((config->hostname = malloc(strlen(ip)+1)))
+		strcpy(config->hostname, ip);
+	      else
+		config->flags &= ~CONFIG_NAME;
+	    }
+	  
+	  if (flags & CONFIG_ADDR)
+	    config->addr = addr;
 	}
+      
+      config->flags |= CONFIG_HWADDR;
+      memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN);
 
-      config->hwaddr[0] = e0;
-      config->hwaddr[1] = e1;
-      config->hwaddr[2] = e2;
-      config->hwaddr[3] = e3;
-      config->hwaddr[4] = e4;
-      config->hwaddr[5] = e5;
+      count++;
     }
   
   fclose(f);
+
+  syslog(LOG_INFO, "read " ETHERSFILE " - %d addresses", count);
   return configs;
 }
 
@@ -549,10 +585,13 @@
   struct crec *crec;
   
   for (config = configs; config; config = config->next)
-    if (config->addr.s_addr == 0 && config->hostname && 
+    if (!(config->flags & CONFIG_ADDR) &&
+	(config->flags & CONFIG_NAME) && 
 	(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
 	(crec->flags & F_HOSTS))
-      config->addr = crec->addr.addr.addr4;
-  
+      {
+	config->addr = crec->addr.addr.addr4;
+	config->flags |= CONFIG_ADDR;
+      }
 }
 
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index c626ed9..3169e55 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -71,7 +71,7 @@
   int leasefd = -1, dhcpfd = -1, dhcp_raw_fd = -1;
   struct sigaction sigact;
   sigset_t sigmask;
-  
+
   sighup = 1; /* init cache the first time through */
   sigusr1 = 0; /* but don't dump */
   sigterm = 0; /* or die */
@@ -120,17 +120,14 @@
 #endif
 
   if (!lease_file)
-    lease_file = LEASEFILE;
-  else
     {
-      if (!dhcp)
-	{
-	  complain("********* dhcp-lease option set, but not dhcp-range.", NULL);
-	  complain("********* Are you trying to use the obsolete ISC dhcpd integration?", NULL);
-	  complain("********* Please configure the dnsmasq integrated DHCP server by using", NULL);
-	  complain("********* the \"dhcp-range\" option, and remove any other DHCP server.", NULL);
-	}
+      if (dhcp)
+	lease_file = LEASEFILE;
     }
+#ifndef HAVE_ISC_READER
+  else if (!dhcp)
+    die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
+#endif
   
   interfaces = enumerate_interfaces(if_names, if_addrs, if_except, port);
   if (options & OPT_NOWILD)
@@ -152,11 +149,6 @@
     {
       dhcp_init(&dhcpfd, &dhcp_raw_fd);
       leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
-      if (options & OPT_ETHERS)
-	dhcp_configs = dhcp_read_ethers(dhcp_configs, dnamebuff);
-      lease_update_from_configs(dhcp_configs, domain_suffix); /* must follow cache_init and lease_init */
-      lease_update_file(0, now); 
-      lease_update_dns();
     }
   
   setbuf(stdout, NULL);
@@ -248,7 +240,10 @@
 	sprintf(packet, "infinite");
       else
 	sprintf(packet, "%ds", (int)dhcp_tmp->lease_time);
-      syslog(LOG_INFO, "DHCP, IP range %s -- %s, lease time %s", 
+      syslog(LOG_INFO, 
+	     dhcp_tmp->start.s_addr == dhcp_tmp->end.s_addr ? 
+	     "DHCP, static leases only on %.0s%s, lease time %s" :
+	     "DHCP, IP range %s -- %s, lease time %s",
 	     dnamebuff, inet_ntoa(dhcp_tmp->end), packet);
     }
 
@@ -271,6 +266,8 @@
 	  cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
 	  if (dhcp)
 	    {
+	      if (options & OPT_ETHERS)
+		dhcp_configs = dhcp_read_ethers(dhcp_configs, dnamebuff);
 	      dhcp_update_configs(dhcp_configs);
 	      lease_update_from_configs(dhcp_configs, domain_suffix); 
 	      lease_update_file(0, now); 
@@ -350,11 +347,17 @@
       if (last == 0 || difftime(now, last) > 1.0)
 	{
 	  last = now;
+
+#ifdef HAVE_ISC_READER
+	  if (lease_file && !dhcp)
+	    load_dhcp(lease_file, domain_suffix, now, dnamebuff);
+#endif
+
 	  if (!(options & OPT_NO_POLL))
 	    {
 	      struct resolvc *res = resolv, *latest = NULL;
-	      time_t last_change = 0;
 	      struct stat statbuf;
+	      time_t last_change = 0;
 	      /* There may be more than one possible file. 
 		 Go through and find the one which changed _last_.
 		 Warn of any which can't be read. */
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index a67e488..edb10ad 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -238,15 +238,24 @@
 };
 
 struct dhcp_config {
+  unsigned int flags;
   int clid_len;          /* length of client identifier */
   unsigned char *clid;   /* clientid */
   unsigned char hwaddr[ETHER_ADDR_LEN]; 
-  char *hostname;
+  char *hostname, *netid;
   struct in_addr addr;
   unsigned int lease_time;
   struct dhcp_config *next;
 };
 
+#define CONFIG_DISABLE   1
+#define CONFIG_CLID      2
+#define CONFIG_HWADDR    4
+#define CONFIG_TIME      8
+#define CONFIG_NAME     16
+#define CONFIG_ADDR     32
+#define CONFIG_NETID    64
+
 struct dhcp_opt {
   int opt, len, is_addr;
   unsigned char *val;
@@ -406,3 +415,7 @@
 	       char *domain_suffix, char *dhcp_file, char *dhcp_sname, 
 	       struct in_addr dhcp_next_server, struct in_addr router);
 
+/* isc.c */
+#ifdef HAVE_ISC_READER
+void load_dhcp(char *file, char *suffix, time_t now, char *hostname);
+#endif
diff --git a/src/isc.c b/src/isc.c
new file mode 100644
index 0000000..a807eab
--- /dev/null
+++ b/src/isc.c
@@ -0,0 +1,249 @@
+/* dnsmasq is Copyright (c) 2000 - 2004 by Simon Kelley
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 dated June, 1991.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+
+/* Code in this file is based on contributions by John Volpe. */
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_ISC_READER
+
+struct isc_lease {
+  char *name, *fqdn;
+  time_t expires;
+  struct in_addr addr;
+  struct isc_lease *next;
+};
+
+static struct isc_lease *leases = NULL;
+static off_t lease_file_size = (off_t)0;
+static ino_t lease_file_inode = (ino_t)0;
+static int logged_lease = 0;
+
+static int next_token (char *token, int buffsize, FILE * fp)
+{
+  int c, count = 0;
+  char *cp = token;
+  
+  while((c = getc(fp)) != EOF)
+    {
+      if (c == '#')
+	do { c = getc(fp); } while (c != '\n' && c != EOF);
+      
+      if (c == ' ' || c == '\t' || c == '\n' || c == ';')
+	{
+	  if (count)
+	    break;
+	}
+      else if ((c != '"') && (count<buffsize-1))
+	{
+	  *cp++ = c;
+	  count++;
+	}
+    }
+  
+  *cp = 0;
+  return count ? 1 : 0;
+}
+
+void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
+{
+  char token[MAXTOK], *dot;
+  struct in_addr host_address;
+  time_t ttd, tts;
+  FILE *fp;
+  struct isc_lease *lease, *tmp, **up;
+  struct stat statbuf;
+
+  if (stat(file, &statbuf) == -1)
+    {
+      if (!logged_lease)
+	syslog(LOG_WARNING, "failed to access %s: %m", file);
+      logged_lease = 1;
+      return;
+    }
+  
+  logged_lease = 0;
+  
+  if ((statbuf.st_size <= lease_file_size) &&
+      (statbuf.st_ino == lease_file_inode))
+    return;
+  
+  lease_file_size = statbuf.st_size;
+  lease_file_inode = statbuf.st_ino;
+  
+  if (!(fp = fopen (file, "r")))
+    {
+      syslog (LOG_ERR, "failed to load %s: %m", file);
+      return;
+    }
+  
+  syslog (LOG_INFO, "reading %s", file);
+
+  while ((next_token(token, MAXTOK, fp)))
+    {
+      if (strcmp(token, "lease") == 0)
+        {
+          hostname[0] = '\0';
+	  ttd = tts = (time_t)(-1);
+	  if (next_token(token, MAXTOK, fp) && 
+	      (host_address.s_addr = inet_addr(token)) != (in_addr_t) -1)
+            {
+              if (next_token(token, MAXTOK, fp) && *token == '{')
+                {
+                  while (next_token(token, MAXTOK, fp) && *token != '}')
+                    {
+                      if ((strcmp(token, "client-hostname") == 0) ||
+			  (strcmp(token, "hostname") == 0))
+			{
+			  if (next_token(hostname, MAXDNAME, fp))
+			    if (!canonicalise(hostname))
+			      {
+				*hostname = 0;
+				syslog(LOG_ERR, "bad name in %s", file); 
+			      }
+			}
+                      else if ((strcmp(token, "ends") == 0) ||
+			       (strcmp(token, "starts") == 0))
+                        {
+                          struct tm lease_time;
+			  int is_ends = (strcmp(token, "ends") == 0);
+			  if (next_token(token, MAXTOK, fp) &&  /* skip weekday */
+			      next_token(token, MAXTOK, fp) &&  /* Get date from lease file */
+			      sscanf (token, "%d/%d/%d", 
+				      &lease_time.tm_year,
+				      &lease_time.tm_mon,
+				      &lease_time.tm_mday) == 3 &&
+			      next_token(token, MAXTOK, fp) &&
+			      sscanf (token, "%d:%d:%d:", 
+				      &lease_time.tm_hour,
+				      &lease_time.tm_min, 
+				      &lease_time.tm_sec) == 3)
+			    {
+			      /* There doesn't seem to be a universally available library function
+				 which converts broken-down _GMT_ time to seconds-in-epoch.
+				 The following was borrowed from ISC dhcpd sources, where
+                                 it is noted that it might not be entirely accurate for odd seconds.
+				 Since we're trying to get the same answer as dhcpd, that's just
+				 fine here. */
+			      static int months [11] = { 31, 59, 90, 120, 151, 181,
+							 212, 243, 273, 304, 334 };
+			      time_t time = ((((((365 * (lease_time.tm_year - 1970) + /* Days in years since '70 */
+						  (lease_time.tm_year - 1969) / 4 +   /* Leap days since '70 */
+						  (lease_time.tm_mon > 1                /* Days in months this year */
+						   ? months [lease_time.tm_mon - 2]
+						   : 0) +
+						  (lease_time.tm_mon > 2 &&         /* Leap day this year */
+						   !((lease_time.tm_year - 1972) & 3)) +
+						  lease_time.tm_mday - 1) * 24) +   /* Day of month */
+						lease_time.tm_hour) * 60) +
+					      lease_time.tm_min) * 60) + lease_time.tm_sec;
+			      if (is_ends)
+				ttd = time;
+			      else
+				tts = time;			    }
+                        }
+		    }
+		  
+		  /* missing info? */
+		  if (!*hostname)
+		    continue;
+		  if (ttd == (time_t)(-1))
+		    continue;
+		  
+		  /* We use 0 as infinite in ttd */
+		  if ((tts != -1) && (ttd == tts - 1))
+		    ttd = (time_t)0;
+		  else if (difftime(now, ttd) > 0)
+		    continue;
+
+		  if ((dot = strchr(hostname, '.')))
+		    { 
+		      if (!suffix || hostname_isequal(dot+1, suffix))
+			{
+			  syslog(LOG_WARNING, 
+				 "Ignoring DHCP lease for %s because it has an illegal domain part", 
+				 hostname);
+			  continue;
+			}
+		      *dot = 0;
+		    }
+
+		  for (lease = leases; lease; lease = lease->next)
+		    if (hostname_isequal(lease->name, hostname))
+		      {
+			lease->expires = ttd;
+			lease->addr = host_address;
+			break;
+		      }
+
+		  if (!lease && (lease = malloc(sizeof(struct isc_lease))))
+		    {
+		      lease->expires = ttd;
+		      lease->addr = host_address;
+		      lease->fqdn =  NULL;
+		      lease->next = leases;
+		      if (!(lease->name = malloc(strlen(hostname)+1)))
+			free(lease);
+		      else
+			{
+			  leases = lease;
+			  strcpy(lease->name, hostname);
+			  if (suffix && (lease->fqdn = malloc(strlen(hostname) + strlen(suffix) + 2)))
+			    {
+			      strcpy(lease->fqdn, hostname);
+			      strcat(lease->fqdn, ".");
+			      strcat(lease->fqdn, suffix);
+			    }
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+  fclose(fp);
+  
+  /* prune expired leases */
+  for (lease = leases, up = &leases; lease; lease = tmp)
+     {
+       tmp = lease->next;
+       if (lease->expires != (time_t)0 && difftime(now, lease->expires) > 0)
+	 {
+	   *up = lease->next; /* unlink */
+	   free(lease->name);
+	   if (lease->fqdn)
+	     free(lease->fqdn);
+	   free(lease);
+	 }
+       else
+	 up = &lease->next;
+     }
+
+     
+  /* remove all existing DHCP cache entries */
+  cache_unhash_dhcp();
+
+  for (lease = leases; lease; lease = lease->next)
+    {
+      if (lease->fqdn)
+	{
+	  cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires, F_REVERSE);
+	  cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires, 0);
+	}
+      else 
+	cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires, F_REVERSE);
+    }
+}
+
+#endif
+
diff --git a/src/option.c b/src/option.c
index 8fe6a44..2aab234 100644
--- a/src/option.c
+++ b/src/option.c
@@ -161,10 +161,10 @@
 {
   int option = 0, i;
   unsigned int flags = 0;
-  FILE *f = NULL;
-  char *conffile = CONFFILE;
+  FILE *file_save = NULL, *f = NULL;
+  char *file_name_save = NULL, *conffile = CONFFILE;
   int conffile_set = 0;
-  int lineno = 0;
+  int line_save = 0, lineno = 0;
   opterr = 0;
   
   *min_leasetime = UINT_MAX;
@@ -179,26 +179,38 @@
 #endif
       else
 	{ /* f non-NULL, reading from conffile. */
+	reread:
 	  if (!fgets(buff, MAXDNAME, f))
 	    {
 	      /* At end of file, all done */
 	      fclose(f);
+	      if (file_save)
+		{
+		  /* may be nested */
+		  conffile = file_name_save;
+		  f = file_save;
+		  file_save = NULL;
+		  lineno = line_save;
+		  goto reread;
+		}
 	      break;
 	    }
 	  else
 	    {
 	      char *p;
+	      int white;
 	      lineno++;
 	      /* dump comments */
-	      for (p = buff; *p; p++)
-		if (*p == '#')
-		  *p = 0;
+	      for (white = 1, p = buff; *p; p++)
+		if (white && *p == '#')
+		  { 
+		    *p = 0;
+		    break;
+		  }
+		else
+		  white = isspace(*p);
 	      /* fgets gets end of line char too. */
-	      while (strlen(buff) > 0 && 
-		     (buff[strlen(buff)-1] == '\n' || 
-		      buff[strlen(buff)-1] == ' ' ||  
-		      buff[strlen(buff)-1] == '\r' || 
-		      buff[strlen(buff)-1] == '\t'))
+	      while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
 		buff[strlen(buff)-1] = 0;
 	      if (*buff == 0)
 		continue; 
@@ -227,6 +239,7 @@
 	{ /* end of command line args, start reading conffile. */
 	  if (!conffile)
 	    break; /* "confile=" option disables */
+	fileopen:
 	  option = 0;
 	  if (!(f = fopen(conffile, "r")))
 	    {   
@@ -274,9 +287,27 @@
 	  switch (option)
 	    { 
 	     case 'C': 
+	       if (!f)
+		 {
+		   conffile = safe_string_alloc(optarg);
+		   conffile_set = 1;
+		   break;
+		 }
+	      
+	       /* nest conffiles one deep */
+	       if (file_save)
+		 {
+		   sprintf(buff, "nested includes not allowed at line %d of %s ", lineno, conffile);
+		   complain(buff, NULL);
+		   continue;
+		 }
+	       file_name_save = conffile;
+	       file_save = f;
+	       line_save = lineno;
 	       conffile = safe_string_alloc(optarg);
 	       conffile_set = 1;
-	       break;
+	       lineno = 0;
+	       goto fileopen;
 	      
 	    case 'x': 
 	      *runfile = safe_string_alloc(optarg);
@@ -643,11 +674,15 @@
 		    *(a[k]++) = 0;
 		  }
 		  
-		if ((k < 2) ||
-		    ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
-		    ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
+		if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
+		  option = '?';
+		else if (strcmp(a[1], "static") == 0)
+		  new->end = new->start;
+		else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
+		  option = '?';
+		  
+		if (option == '?')
 		  {
-		    option = '?';
 		    free(new);
 		    break;
 		  }
@@ -700,22 +735,17 @@
 	    case 'G':
 	      {
 		int j, k;
-		char *a[4] = { NULL, NULL, NULL, NULL };
+		char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
 		unsigned int e0, e1, e2, e3, e4, e5;
 		struct dhcp_config *new = safe_malloc(sizeof(struct dhcp_config));
 		struct in_addr in;
 
 		new->next = *dhcp_conf;
-				  
-		memset(new->hwaddr, 0, ETHER_ADDR_LEN);
-		new->clid_len = 0;
-		new->clid = NULL;
-		new->hostname = NULL;
-		new->addr.s_addr = 0;
-		new->lease_time = 0; 
+		new->flags = 0;		  
+		
 		
 		a[0] = optarg;
-		for (k = 1; k < 4; k++)
+		for (k = 1; k < 6; k++)
 		  {
 		    if (!(a[k] = strchr(a[k-1], ',')))
 		      break;
@@ -723,37 +753,60 @@
 		  }
 		   
 		for(j = 0; j < k; j++)
-		  if (strchr(a[j], ':')) /* ethernet address or binary CLID */
+		  if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
 		    {
 		      char *arg = a[j];
 		      if ((arg[0] == 'i' || arg[0] == 'I') &&
 			  (arg[1] == 'd' || arg[1] == 'D') &&
 			  arg[2] == ':')
 			{
-			  int s, len;
+			  int len;
 			  arg += 3; /* dump id: */
 			  if (strchr(arg, ':'))
 			    {
-			      s = (strlen(arg)/3) + 1;
-			      /* decode in place */
-			      for (len = 0; len < s; len++)
+			      /* decode hex in place */
+			      char *p = arg, *q = arg, *r;
+			      while (*p)
 				{
-				  if (arg[(len*3)+2] != ':')
-				    option = '?';
-				  arg[(len*3)+2] = 0;
-				  arg[len] = strtol(&arg[len*3], NULL, 16);
+				  for (r = p; *r && *r != ':'; r++);
+				  if (*r)
+				    {
+				      if (r != p)
+					{
+					  *r = 0;
+					  *(q++) = strtol(p, NULL, 16);
+					}
+				      p = r+1;
+				    }
+				  else
+				    {
+				      if (*p)
+					*(q++) = strtol(p, NULL, 16);
+				      break;
+				    }
 				}
+			      len = q - arg;
 			    }
 			  else
 			    len = strlen(arg);
 			  
+			  new->flags |= CONFIG_CLID;
 			  new->clid_len = len;
 			  new->clid = safe_malloc(len);
 			  memcpy(new->clid, arg, len);
 			}
+		      else if ((arg[0] == 'n' || arg[0] == 'N') &&
+			       (arg[1] == 'e' || arg[1] == 'E') &&
+			       (arg[2] == 't' || arg[3] == 'T') &&
+			       arg[3] == ':')
+			{
+			  new->flags |= CONFIG_NETID;
+			  new->netid = safe_string_alloc(arg+4);
+			}
 		      else if (sscanf(a[j], "%x:%x:%x:%x:%x:%x",
 				      &e0, &e1, &e2, &e3, &e4, &e5) == 6)
 			{
+			  new->flags |= CONFIG_HWADDR;
 			  new->hwaddr[0] = e0;
 			  new->hwaddr[1] = e1;
 			  new->hwaddr[2] = e2;
@@ -765,7 +818,10 @@
 			option = '?';
 		    }
 		  else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
-		    new->addr = in;
+		    {
+		      new->addr = in;
+		      new->flags |= CONFIG_ADDR;
+		    }
 		  else
 		    {
 		      char *cp, *lastp = NULL, last = 0;
@@ -800,19 +856,38 @@
 			  if (lastp)
 			    *lastp = last;
 			  if (strcmp(a[j], "infinite") == 0)
-			    new->lease_time = 0xffffffff;
+			    {
+			      new->lease_time = 0xffffffff;
+			      new->flags |= CONFIG_TIME;
+			    }
+			  else if (strcmp(a[j], "ignore") == 0)
+			    new->flags |= CONFIG_DISABLE;
 			  else
-			    new->hostname = safe_string_alloc(a[j]);
+			    {
+			      new->hostname = safe_string_alloc(a[j]);
+			      new->flags |= CONFIG_NAME;
+			    }
 			}
 		      else
-			new->lease_time = atoi(a[j]) * fac;  
+			{
+			  new->lease_time = atoi(a[j]) * fac; 
+			  new->flags |= CONFIG_TIME;
+			}
 		    }
 
 		if (option == '?')
-		  free(new);
+		  {
+		    if (new->flags & CONFIG_NAME)
+		      free(new->hostname);
+		    if (new->flags & CONFIG_CLID)
+		      free(new->clid);
+		    if (new->flags & CONFIG_NETID)
+		      free(new->netid);
+		    free(new);
+		  }
 		else
 		  {
-		    if (new->lease_time < *min_leasetime)
+		    if ((new->flags & CONFIG_TIME) && new->lease_time < *min_leasetime)
 		      *min_leasetime = new->lease_time;
 		    *dhcp_conf = new;
 		  }
@@ -823,7 +898,7 @@
 	      {
 		struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
 		char *cp, *comma;
-		int addrs, is_addr;
+		int addrs, digs, is_addr, is_hex, is_dec;
 		
 		new->next = *dhcp_opts;
 		new->len = 0;
@@ -853,58 +928,113 @@
 		    free(new);
 		    break;
 		  }
-
+		
+		*dhcp_opts = new;
+		
 		if (!comma)
-		  {
-		    *dhcp_opts = new;
-		    break;
-		  }
-
-		/* check for non-address list characters */
-		for (addrs = 1, is_addr = 0, cp = comma+1; *cp; cp++)
+		  break;
+		
+		/* characterise the value */
+		is_addr = is_hex = is_dec = 1;
+		addrs = digs = 1;
+		for (cp = comma+1; *cp; cp++)
 		  if (*cp == ',')
-		    addrs++;
-		  else if (!(*cp == '.' || *cp == ' ' || (*cp >='0' && *cp <= '9')))
-		    break;
+		    {
+		      addrs++;
+		      is_dec = is_hex = 0;
+		    }
+		  else if (*cp == ':')
+		    {
+		      digs++;
+		      is_dec = is_addr = 0;
+		    }
 		  else if (*cp == '.')
-		    is_addr = 1;
-		    
-		if (*cp)
+		    is_dec = is_hex = 0;
+		  else if (!(*cp >='0' && *cp <= '9'))
+		      {
+			is_dec = is_addr = 0;
+			if (!((*cp >='A' && *cp <= 'F') ||
+			      (*cp >='a' && *cp <= 'F')))
+			  is_hex = 0;
+		      }
+		
+		if (is_hex && digs > 1)
+		  {
+		    char *p = comma+1, *q, *r;
+		    new->len = digs;
+		    q = new->val = safe_malloc(new->len);
+		    while (*p)
+		      {
+			for (r = p; *r && *r != ':'; r++);
+			if (*r)
+			  {
+			    if (r != p)
+			      {
+				*r = 0;
+				*(q++) = strtol(p, NULL, 16);
+			      }
+			    p = r+1;
+			  }
+			else
+			  {
+			    if (*p)
+			      *(q++) = strtol(p, NULL, 16);
+			    break;
+			  }
+		      }
+		  }
+		else if (is_dec)
+		  {
+		    /* Given that we don't know the length,
+		       this applaing hack is the best available */
+		    unsigned int val = atoi(comma+1);
+		    if (val < 256)
+		      {
+			new->len = 1;
+			new->val = safe_malloc(1);
+			*(new->val) = val;
+		      }
+		    else if (val < 65536)
+		      {
+			new->len = 2;
+			new->val = safe_malloc(2);
+			*(new->val) = val>>8;
+			*(new->val+1) = val;
+		      }
+		    else
+		      {
+			new->len = 4;
+			new->val = safe_malloc(4);
+			*(new->val) = val>>24;
+			*(new->val+1) = val>>16;
+			*(new->val+2) = val>>8;
+			*(new->val+3) = val;
+		      }
+		  }
+		else if (is_addr)	
+		  {
+		    struct in_addr in;
+		    unsigned char *op;
+		    new->len = INADDRSZ * addrs;
+		    new->val = op = safe_malloc(new->len);
+		    new->is_addr = 1;
+		    while (addrs--) 
+		      {
+			cp = comma;
+			if ((comma = strchr(cp+1, ',')))
+			  *comma = 0;
+			in.s_addr = inet_addr(cp+1);
+			memcpy(op, &in, INADDRSZ);
+			op += INADDRSZ;
+		      }
+		  }
+		else
 		  {
 		    /* text arg */
 		    new->len = strlen(comma+1);
 		    new->val = safe_malloc(new->len);
 		    memcpy(new->val, comma+1, new->len);
 		  }
-		else
-		  {
-		    struct in_addr in;
-		    unsigned char *op;
-
-		    if (addrs == 1 && !is_addr)
-		      {
-			new->len = 1;
-			new->val = safe_malloc(1);
-			*(new->val) = atoi(comma+1);
-		      }
-		    else
-		      {
-			new->len = INADDRSZ * addrs;
-			new->val = op = safe_malloc(new->len);
-			new->is_addr = 1;
-			while (addrs--) 
-			  {
-			    cp = comma;
-			    if (cp && (comma = strchr(cp+1, ',')))
-			      *comma = 0;
-			    if (cp && (in.s_addr = inet_addr(cp+1)) == (in_addr_t)-1)
-			      option = '?';
-			    memcpy(op, &in, INADDRSZ);
-			    op += INADDRSZ;
-			  }
-		      }
-		  }
-		*dhcp_opts = new;
 		break;
 	      }
 
diff --git a/src/rfc2131.c b/src/rfc2131.c
index a4bd5c0..1b7364d 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -63,8 +63,12 @@
 				     char *domainname, char *hostname,
 				     struct in_addr router,
 				     struct in_addr iface_addr,
-				     int iface_mtu);
+				     int iface_mtu, char *netid);
 
+static int have_config(struct dhcp_config *config, unsigned int mask)
+{
+  return config && (config->flags & mask);
+}
 
 int dhcp_reply(struct dhcp_context *context, 
 	       struct in_addr iface_addr,
@@ -88,13 +92,27 @@
   char *message = NULL;
   unsigned int renewal_time, expires_time, def_time;
   struct dhcp_config *config;
- 
+  char *netid;
+  
   if (mess->op != BOOTREQUEST || 
-      mess->htype != ARPHRD_ETHER || 
       mess->hlen != ETHER_ADDR_LEN ||
       mess->cookie != htonl(DHCP_COOKIE))
-    return 0;	
+    return 0;
   
+  /* Token ring is supported when we have packet sockets
+     to make the HW headers for us. We don't have the code to build
+     token ring headers when using BPF. We rely on the fact that
+     token ring hwaddrs are the same size as ethernet hwaddrs. */
+
+#ifdef HAVE_BPF
+  if (mess->htype != ARPHRD_ETHER)
+    return 0;	
+#else
+  if (mess->htype != ARPHRD_ETHER && 
+      mess->htype != ARPHRD_IEEE802)
+    return 0;	
+#endif
+    
   mess->op = BOOTREPLY;
 
   if ((opt = option_find(mess, sz, OPTION_MAXMESSAGE)))
@@ -130,9 +148,9 @@
       memcpy(req_options, option_ptr(opt), len);
       req_options[len] = OPTION_END;
     }
-
+  
   if ((config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, NULL)) && 
-      config->hostname)
+      have_config(config, CONFIG_NAME))
     hostname = config->hostname;
   else if ((opt = option_find(mess, sz, OPTION_HOSTNAME)))
     {
@@ -164,7 +182,8 @@
      
   /* search again now we have a hostname */
   config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, hostname);
-  def_time = config && config->lease_time ? config->lease_time : context->lease_time;
+  def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
+  netid = have_config(config, CONFIG_NETID) ? config->netid : context->netid;
   
   if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
     {
@@ -219,11 +238,11 @@
       if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
 	lease_prune(lease, now);
       
-      if (config && config->addr.s_addr && 
+      if (have_config(config, CONFIG_ADDR) && 
 	  config->addr.s_addr == option_addr(opt).s_addr)
 	{
 	  syslog(LOG_WARNING, "disabling DHCP static address %s", inet_ntoa(config->addr));
-	  config->addr.s_addr = 0;
+	  config->flags &= ~CONFIG_ADDR ;
 	}
       
       return 0;
@@ -244,9 +263,9 @@
       if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))	 
 	mess->yiaddr = option_addr(opt);
       
-      log_packet("DISCOVER", opt ? &mess->yiaddr : NULL, mess->chaddr, iface_name, NULL);
-      
-      if (config && config->addr.s_addr && !lease_find_by_addr(config->addr))
+      if (have_config(config, CONFIG_DISABLE))
+	message = "ignored";
+      else if (have_config(config, CONFIG_ADDR) && !lease_find_by_addr(config->addr))
 	mess->yiaddr = config->addr;
       else if (lease && 
 	       ((lease->addr.s_addr & context->netmask.s_addr) == 
@@ -254,18 +273,19 @@
 	mess->yiaddr = lease->addr;
       else if ((!opt || !address_available(context, mess->yiaddr)) &&
 	       !address_allocate(context, dhcp_configs, &mess->yiaddr))
-	{
-	  syslog(LOG_WARNING, "address pool exhausted");
-	  return 0;
-	}
-	            
+	message = "no address available";
+	 
+      log_packet("DISCOVER", opt ? &mess->yiaddr : NULL, mess->chaddr, iface_name, message);          
+      if (message)
+	return 0;
+
       bootp_option_put(mess, dhcp_file, dhcp_sname);
       mess->siaddr = dhcp_next_server;
       p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
       p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
       p = option_put(p, end, OPTION_LEASE_TIME, 4, expires_time);
       p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix, 
-			 NULL, router, iface_addr, iface_mtu);
+			 NULL, router, iface_addr, iface_mtu, netid);
       p = option_put(p, end, OPTION_END, 0, 0);
       
       log_packet("OFFER" , &mess->yiaddr, mess->chaddr, iface_name, NULL);
@@ -297,7 +317,7 @@
 	  if (!lease)
 	    { 
 	      if (!address_available(context, mess->yiaddr) && 
-		  (!config || config->addr.s_addr == 0 || config->addr.s_addr != mess->yiaddr.s_addr))
+		  (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
 		message = "address unavailable";
 	      else if (!(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
 		message = "no leases left";
@@ -319,6 +339,9 @@
       if ((mess->yiaddr.s_addr & context->netmask.s_addr) != (context->start.s_addr & context->netmask.s_addr))
 	message = "wrong network";
       
+      if (have_config(config, CONFIG_DISABLE))
+	message = "disabled";
+
       log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
       
       if (message)
@@ -354,17 +377,23 @@
 	  p = option_put(p, end, OPTION_T2, 4, ((renewal_time * 7)/8) - fuzz);
 	}
       p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix, 
-			 hostname, router, iface_addr, iface_mtu);
+			 hostname, router, iface_addr, iface_mtu, netid);
       p = option_put(p, end, OPTION_END, 0, 0);
       return p - (unsigned char *)mess; 
       
     case DHCPINFORM:
+      if (have_config(config, CONFIG_DISABLE))
+	{
+	  log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, "ignored");
+	  return 0;
+	}
+      
       log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, NULL);
       
       p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
       p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
       p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix, 
-			 hostname, router, iface_addr, iface_mtu);
+			 hostname, router, iface_addr, iface_mtu, netid);
       p = option_put(p, end, OPTION_END, 0, 0);
       
       log_packet("ACK", &mess->ciaddr, mess->chaddr, iface_name, hostname);
@@ -524,11 +553,11 @@
   return 0;
 }
 
-static struct dhcp_opt *option_find2(struct dhcp_context *context, struct dhcp_opt *opts, int opt)
+static struct dhcp_opt *option_find2(char *netid, struct dhcp_opt *opts, int opt)
 {
   for (; opts; opts = opts->next)
     if (opts->opt == opt && 
-	(!opts->netid || (context->netid && strcmp(opts->netid, context->netid) == 0)))
+	(!opts->netid || (netid && strcmp(opts->netid, netid) == 0)))
       return opts;
   return NULL;
 }
@@ -540,7 +569,7 @@
 				     char *domainname, char *hostname,
 				     struct in_addr router, 
 				     struct in_addr iface_addr,
-				     int iface_mtu)
+				     int iface_mtu, char *netid)
 {
   int i;
   
@@ -553,24 +582,24 @@
 		   iface_mtu : DNSMASQ_PACKETSZ);
   
   if (in_list(req_options, OPTION_NETMASK) &&
-      !option_find2(context, config_opts, OPTION_NETMASK))
+      !option_find2(netid, config_opts, OPTION_NETMASK))
     p = option_put(p, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
   
   if (in_list(req_options, OPTION_BROADCAST) &&
-      !option_find2(context, config_opts, OPTION_BROADCAST))
+      !option_find2(netid, config_opts, OPTION_BROADCAST))
     p = option_put(p, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
   
   if (in_list(req_options, OPTION_ROUTER) &&
-      !option_find2(context, config_opts, OPTION_ROUTER))
+      !option_find2(netid, config_opts, OPTION_ROUTER))
     p = option_put(p, end, OPTION_ROUTER, INADDRSZ, 
 		   ntohl(router.s_addr));
 
   if (in_list(req_options, OPTION_DNSSERVER) &&
-      !option_find2(context, config_opts, OPTION_DNSSERVER))
+      !option_find2(netid, config_opts, OPTION_DNSSERVER))
     p = option_put(p, end, OPTION_DNSSERVER, INADDRSZ, ntohl(iface_addr.s_addr));
   
   if (domainname && in_list(req_options, OPTION_DOMAINNAME) && 
-      !option_find2(context, config_opts, OPTION_DOMAINNAME))
+      !option_find2(netid, config_opts, OPTION_DOMAINNAME))
     p = option_put_string(p, end, OPTION_DOMAINNAME, domainname);
  
   /* Note that we ignore attempts to set the hostname using 
@@ -580,38 +609,49 @@
   
   for (i = 0; req_options[i] != OPTION_END; i++)
     {
-      struct dhcp_opt *opt = option_find2(context, config_opts, req_options[i]);
-      if (req_options[i] != OPTION_HOSTNAME && 
-	  req_options[i] != OPTION_MAXMESSAGE &&
-	  opt && (p + opt->len + 3 < end))
+      struct dhcp_opt *opt;
+     
+      if (req_options[i] == OPTION_HOSTNAME || 
+	  req_options[i] == OPTION_MAXMESSAGE ||
+	  !(opt = option_find2(netid, config_opts, req_options[i])) || 
+	  (p + opt->len + 3 >= end))
+	continue;
+      
+      /* For the options we have default values on
+	 dhc-option=<optionno> means "don't include this option"
+	 not "include a zero-length option" */
+      if (opt->len == 0 && 
+	  (opt->opt == OPTION_NETMASK ||
+	   opt->opt == OPTION_BROADCAST ||
+	   opt->opt == OPTION_ROUTER ||
+	   opt->opt == OPTION_DNSSERVER))
+	continue;
+      
+      *(p++) = opt->opt;
+      *(p++) = opt->len;
+      if (opt->len == 0)
+	continue;
+	
+      if (opt->is_addr)
 	{
-	  *(p++) = opt->opt;
-	  *(p++) = opt->len;
-	  if (opt->len != 0)
+	  int j;
+	  struct in_addr *a = (struct in_addr *)opt->val;
+	  for (j = 0; j < opt->len; j+=INADDRSZ, a++)
 	    {
-	      if (opt->is_addr)
-		{
-		  int j;
-		  struct in_addr *a = (struct in_addr *)opt->val;
-		  for (j = 0; j < opt->len; j+=INADDRSZ, a++)
-		    {
-		      /* zero means "self" */
-		      if (a->s_addr == 0)
-			memcpy(p, &iface_addr, INADDRSZ);
-		      else
-			memcpy(p, a, INADDRSZ);
-		      p += INADDRSZ;
-		    }
-		}
+	      /* zero means "self" */
+	      if (a->s_addr == 0)
+		memcpy(p, &iface_addr, INADDRSZ);
 	      else
-		{
-		  memcpy(p, opt->val, opt->len);
-		  p += opt->len;
-		}
+		memcpy(p, a, INADDRSZ);
+	      p += INADDRSZ;
 	    }
 	}
-    }
-     
+      else
+	{
+	  memcpy(p, opt->val, opt->len);
+	  p += opt->len;
+	}
+    }     
   return p;
 }