import of dnsmasq-2.1.tar.gz
diff --git a/CHANGELOG b/CHANGELOG
index a86b333..467b653 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -666,4 +666,50 @@
 	     domains and IPv6 queries. Thanks to Roy Marples for
 	     helping to track that one down.
 
-	      
+release 2.1  
+	     Tweak include files to allow compilation on FreeBSD 5
+             
+             Fix unaligned access warnings on BSD/Alpha.
+
+	     Allow empty DHCP options, like so: dhpc-option=44
+ 
+             Allow single-byte DHCP options like so: dhcp-option=20,1
+
+	     Allow comments on the same line as options in
+	     /etc/dnsmasq.conf
+
+	     Don't complain when the same name and address is
+	     allocated to a host using DHCP and /etc/hosts.
+	     
+	     Added to the example configuration the dnsmasq equivalent
+	     of the ISC dhcpd settings given in 
+             http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
+
+	     Fixed long-existing strangeness in Linux IPv6 interface
+	     discovery code. The flags field in /proc/net/if_inet6 is
+	     _not_ the interface flags.
+
+	     Fail gracefully when getting an ENODEV error when trying
+	     to bind an IPv6 socket, rather than bailing out.
+
+	     Allow the name->address mapping for static DHCP leases to
+	     be set by /etc/hosts. It's now possible to have
+     	        dhcp-host=<mac addr>,wibble
+	     or even
+                dhcp-host=wibble
+	     and in /etc/hosts have
+	        wibble 1.2.3.4
+	     and for the correct thing to happen. Note that some sort
+	     of dhcp-host line is still needed, it's not possible for
+	     random host to claim an address in /etc/hosts without
+	     some explicit configuration.
+
+	     Make 0.0.0.0 in a dhcp-option to mean "the machine
+	     running dnsmasq".
+    		    
+             Fix lease time spec when specified in dhcp-range and not
+	     in dhcp-host, previously this was always one hour.
+
+             Fix problem with setting domains as "local only".
+
+	     Added support for max message size DHCP option.
diff --git a/FAQ b/FAQ
index 94af7d1..cbf7a66 100644
--- a/FAQ
+++ b/FAQ
@@ -154,6 +154,34 @@
    registries pull the same stunt; there is a list of them all, and
    the addresses to block, at http://winware.org/bogus-domains.txt
 
+Q: This new DHCP server is well and good, but it doesn't work for me.
+   What's the problem?
+
+A: There are a couple of configuration gotchas which have been
+   encountered by people moving from the ISC dhcpd to the dnsmasq
+   integrated DHCP daemon. Both are related to differences in 
+   in the way the two daemons bypass the IP stack to do "ground up"
+   IP configuration and can lead to the dnsmasq daemon failing
+   whilst the ISC one works.
+
+   The first thing to check is the broadcast address set for the
+   ethernet interface. This is normally the adddress on the connected
+   network with all ones in the host part. For instance if the 
+   address of the ethernet interface is 192.168.55.7 and the netmask
+   is 255.255.255.0 then the broadcast address should be
+   192.168.55.255. Having a broadcast address which is not on the
+   network to which the interface is connected kills things stone
+   dead.
+
+   The second potential problem relates to firewall rules: since the ISC 
+   daemon in some configurations bypasses the kernel firewall rules 
+   entirely, the ability to run the ISC daemon does not indicate 
+   that the current configuration is OK for the dnsmasq daemon.
+   For the dnsmasq daemon to operate it's vital that UDP packets to 
+   and from ports 67 and 68 and broadcast packets with source 
+   address 0.0.0.0 and destination address 255.255.255.255 are not 
+   dropped by iptables/ipchains.
+  
 
 
 
diff --git a/UPGRADING_to_2.0 b/UPGRADING_to_2.0
index d17940c..e1204fa 100644
--- a/UPGRADING_to_2.0
+++ b/UPGRADING_to_2.0
@@ -40,7 +40,7 @@
 
 To enable DHCP, simply add a line like this to /etc/dnsmasq.conf
 
-dhcp-range=192.168.0.100,192,168.0.200,12h
+dhcp-range=192.168.0.100,192.168.0.200,12h
 
 which tells dnsmasq to us the addresses 192.168.0.100 to 192.168.0.200
 for dynamic IP addresses, and to issue twelve hour leases.
@@ -60,6 +60,8 @@
 
 
 For more complex DHCP configuration, refer to the doc/setup.html, the
-dnsmasq manpage and the annotated example configuration file.
+dnsmasq manpage and the annotated example configuration file. Also
+note that for some ISC dhcpd to dnsmasq DHCP upgrades there may be
+firewall issues: see the FAQ for details of this.
 
 
diff --git a/dnsmasq-mdk.spec b/dnsmasq-mdk.spec
index 5ec3664..3829703 100644
--- a/dnsmasq-mdk.spec
+++ b/dnsmasq-mdk.spec
@@ -5,7 +5,7 @@
 ###############################################################################
 
 Name: dnsmasq
-Version: 2.0
+Version: 2.1
 Release: 1
 Copyright: GPL
 Group: System Environment/Daemons
diff --git a/dnsmasq-rh.spec b/dnsmasq-rh.spec
index 2114ac5..16cb3e6 100644
--- a/dnsmasq-rh.spec
+++ b/dnsmasq-rh.spec
@@ -5,7 +5,7 @@
 ###############################################################################
 
 Name: dnsmasq
-Version: 2.0
+Version: 2.1
 Release: 1
 Copyright: GPL
 Group: System Environment/Daemons
diff --git a/dnsmasq-suse.spec b/dnsmasq-suse.spec
index 1961942..4a811b6 100644
--- a/dnsmasq-suse.spec
+++ b/dnsmasq-suse.spec
@@ -5,7 +5,7 @@
 ###############################################################################
 
 Name: dnsmasq
-Version: 2.0
+Version: 2.1
 Release: 1
 Copyright: GPL
 Group: Productivity/Networking/DNS/Servers
@@ -100,7 +100,7 @@
 
 %files
 %defattr(-,root,root)
-%doc CHANGELOG COPYING FAQ doc.html setup.html UPGRADING_to_2.0
+%doc CHANGELOG COPYING FAQ doc.html setup.html UPGRADING_to_2.0 rpm/README.susefirewall
 %config /etc/init.d/dnsmasq
 %config /etc/dnsmasq.conf
 /usr/sbin/rcdnsmasq
diff --git a/dnsmasq.8 b/dnsmasq.8
index af4cd29..69f12b5 100644
--- a/dnsmasq.8
+++ b/dnsmasq.8
@@ -251,7 +251,7 @@
 .B --dhcp-host=lap,192.168.0.199 
 tells
 dnsmasq to always allocate the machine lap the IP address
-192.168.0.199. Addresses allocated like this are not contrained to be
+192.168.0.199. Addresses allocated like this are not constrained to be
 in the range given by the --dhcp-range option, but they must be on the
 network being served by the DHCP server. It is allowed to use client identifiers rather than
 hardware addresses to identify hosts by prefixing with 'id:'. Thus: 
@@ -259,8 +259,12 @@
 refers to the host with client identifier 01:02:03:04. It is also
 allowed to specify the client ID as text, like this:
 .B --dhcp-host=id:clientidastext,.....
+If a name appears in /etc/hosts, the associated address can be
+allocated to a DHCP lease, but only if a 
+.B --dhcp-host
+option specifying the name also exists.
 .TP
-.B \-O, --dhcp-option=<opt>,<value>[,<value>]
+.B \-O, --dhcp-option=<opt>,[<value>[,<value>]]
 Specfify different or extra options to DHCP clients. By default,
 dnsmasq sends some standard options to DHCP clients, the netmask and
 broadcast address are set to the same as the host running dnsmasq, and
@@ -273,6 +277,8 @@
 .B --dhcp-option=3,192.168.4.4
 and to set the time-server address to 192.168.0.4, do
 .B dhcp-option=42,192.168.0.4
+The special address 0.0.0.0 is taken to mean "the address of the
+machine running dnsmasq".
 Be careful: no checking is done that the correct type of data for the
 option number is sent, and there are option numbers for which it is not
 possible to generate the correct data type; it is quite possible to
diff --git a/dnsmasq.conf.example b/dnsmasq.conf.example
index 72e9cf6..7fbe669 100644
--- a/dnsmasq.conf.example
+++ b/dnsmasq.conf.example
@@ -31,6 +31,13 @@
 # somewhere other that /etc/resolv.conf 
 #resolv-file=
 
+# By  default,  dnsmasq  will  send queries to any of the upstream
+# servers it knows about and tries to favour servers to are  known
+# to  be  up.  Uncommenting this forces dnsmasq to try each query
+# with  each  server  strictly  in  the  order  they   appear   in
+# /etc/resolv.conf
+#strict-order
+
 # If you don't want dnsmasq to read /etc/resolv.conf or any other
 # file, getting its servers for this file instead (see below), then
 # uncomment this
@@ -88,9 +95,10 @@
 #dhcp-range=192.168.0.50,192.168.0.150,12h
 
 # Supply parameters for specified hosts using DHCP. There are lots
-# of valid alternatives, do we will give examples of each. Note that
+# of valid alternatives, so we will give examples of each. Note that
 # IP addresses DO NOT have to be in the range given above, they just
-# need to be on the same network. 
+# need to be on the same network. The order of the parameters in these
+# do not matter, it's permissble to give name,adddress and MAC in any order
 
 # Always allocate the host with ethernet address 11:22:33:44:55:66 
 # The IP address 192.168.0.60
@@ -116,15 +124,54 @@
 # the IP address 192.168.0.60
 #dhcp-host=id:marjorie,192.168.0.60
 
+# Enable the address given for "judge" in /etc/hosts
+# to be given to a machine presenting the name "judge" when
+# it asks for a DHCP lease.
+#dhcp-host=judge
+
 # Send options to hosts which ask for a DHCP lease.
 # See RFC 2132 for details of available options.
+# Note that all the common settings, such as netmask and
+# broadcast address, DNS server and default route, are given
+# sane defaults by dnsmasq. You very likely will not need any
+# any dhcp-options. If you use Windows clients and Samba, there
+# are some options which are recommended, they are detailed at the
+# end of this section.
+# For reference, the common options are:
+# subnet mask - 1
+# default router - 3
+# DNS server - 6
+# broadcast address - 28
 
 # Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
 #dhcp-option=42,192.168.0.4,10.10.0.5
 
+# Set the NTP time server address to be the same machine as 
+# is running dnsmasq
+#dhcp-option=42,0.0.0.0
+
 # Set the NIS domain name to "welly"
 #dhcp-option=40,welly
 
+# Set the default time-to-live to 50
+#dhcp-option=23,50
+
+# Set the "all subnets are local" flag
+#dhcp-option=27,1
+
+# The following DHCP options set up dnsmasq in the same way as is specified
+# for the ISC dhcpcd in 
+# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
+# adapted for a typical dnsmasq installation where the host running
+# dnsmasq is also the host running samba.
+# you may want to uncomment them if you use Windows clients and Samba.
+#dhcp-option=19,0           # option ip-forwarding off 
+#dhcp-option=44,0.0.0.0     # set netbios-over-TCP/IP nameserver(s) aka WINS server(s)
+#dhcp-option=45,0.0.0.0     # netbios datagram distribution server
+#dhcp-option=46,8           # netbios node type
+#dhcp-option=47             # empty netbios scope.
+ 
+
 # Set the boot filename and tftpd server name and address
 # for BOOTP. You will only need this is you want to
 # boot machines over the network.
@@ -133,14 +180,10 @@
 # The DHCP server needs somewhere on disk to keep its lease database.
 # This defaults to a sane location, but if you want to change it, use
 # the line below.
-#dhcp-leasefile=/var/lib/dnsmasq/leases
-
-# Override the default route (which is normally automagically set
-# to be the machine running dnsmasq
-#dhcp-option=2,192,168.4.4
+#dhcp-leasefile=/var/lib/misc/dnsmasq.leases
 
 # Set the cachesize here.
-#cache-size=600
+#cache-size=150
 
 # If you want to disable negative caching, uncomment this.
 #no-negcache
diff --git a/rpm/README.susefirewall b/rpm/README.susefirewall
new file mode 100644
index 0000000..2f19ca6
--- /dev/null
+++ b/rpm/README.susefirewall
@@ -0,0 +1,27 @@
+This is a patch against SuSEfirewall2-3.1-206 (SuSE 9.x and older)
+It fixes the depancy from the dns daemon name 'named'
+After appending the patch, the SuSEfirewall is again able to autodetect 
+the dnsmasq named service.
+This is a very old bug in the SuSEfirewall script.
+The SuSE people think the name of the dns server will allways 'named'
+
+
+--- /sbin/SuSEfirewall2.orig	2004-01-23 13:30:09.000000000 +0100
++++ /sbin/SuSEfirewall2	2004-01-23 13:31:56.000000000 +0100
+@@ -764,7 +764,7 @@
+     echo 'FW_ALLOW_INCOMING_HIGHPORTS_UDP should be set to yes, if you are running a DNS server!'
+ 
+ test "$FW_SERVICE_AUTODETECT" = yes -o "$FW_SERVICE_AUTODETECT" = dmz -o "$FW_SERVICE_AUTODETECT" = ext && {
+-    test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv named && {
++    test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv dnsmasq && {
+ 	echo -e 'Warning: detected activated named, enabling FW_SERVICE_DNS!
+ You still have to allow tcp/udp port 53 on internal, dmz and/or external.'
+ 	FW_SERVICE_DNS=$FW_SERVICE_AUTODETECT
+@@ -878,7 +878,7 @@
+ test -e /etc/resolv.conf || echo "Warning: /etc/resolv.conf not found"
+ # Get ports/IP bindings of NAMED/SQUID
+ test "$FW_SERVICE_DNS" = yes -o "$FW_SERVICE_DNS" = dmz -o "$FW_SERVICE_DNS" = ext -o "$START_NAMED" = yes && DNS_PORT=`$LSOF -i -n -P | \
+-    $AWK -F: '/^named .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
++    $AWK -F: '/^dnsmasq .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
+ test "$FW_SERVICE_SQUID" = yes -o "$FW_SERVICE_SQUID" = dmz -o "$FW_SERVICE_SQUID" = ext -o "$START_SQUID" = yes && SQUID_PORT=`$LSOF -i -n -P | \
+     $AWK -F: '/^squid .* UDP/ {print $2}'| $SORT -un`
diff --git a/src/cache.c b/src/cache.c
index 948207e..7a78d7e 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -639,7 +639,10 @@
   if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4)))
     {
       if (crec->flags & F_HOSTS)
-	syslog(LOG_WARNING, "Ignoring DHCP lease for %s because it clashes with an /etc/hosts entry.", host_name);
+	{
+	  if (crec->addr.addr.addr4.s_addr != host_address->s_addr)
+	    syslog(LOG_WARNING, "Not naming DHCP lease for %s because it clashes with an /etc/hosts entry.", host_name);
+	}
       else if (!(crec->flags & F_DHCP))
 	{
 	  if (crec->flags & F_NEG)
@@ -650,7 +653,7 @@
 	      goto newrec;
 	    }
 	  else
-	    syslog(LOG_WARNING, "Ignoring DHCP lease for %s because it clashes with a cached name.", cache_get_name(crec));
+	    syslog(LOG_WARNING, "Not naming DHCP lease for %s because it clashes with a cached name.", cache_get_name(crec));
 	}
       return;
     }
@@ -671,7 +674,7 @@
 	crec->flags |= F_IMMORTAL;
       else
 	crec->ttd = ttd;
-      memcpy(&crec->addr, host_address, INADDRSZ);
+      crec->addr.addr.addr4 = *host_address;
       crec->name.namep = host_name;
       crec->prev = dhcp_inuse;
       dhcp_inuse = crec;
diff --git a/src/config.h b/src/config.h
index 07f7b5f..39d2375 100644
--- a/src/config.h
+++ b/src/config.h
@@ -12,7 +12,7 @@
 
 /* Author's email: simon@thekelleys.org.uk */
 
-#define VERSION "2.0"
+#define VERSION "2.1"
 
 #define FTABSIZ 150 /* max number of outstanding requests */
 #define TIMEOUT 40 /* drop queries after TIMEOUT seconds */
diff --git a/src/dhcp.c b/src/dhcp.c
index cbc8bbf..102d1a7 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -269,5 +269,18 @@
   return NULL;
 }
 
-      
+void set_configs_from_cache(struct dhcp_config *configs)
+/* Some people like to keep all static IP addresses in /etc/hosts.
+   This goes through /etc/hosts and sets static addresses for any DHCP config
+   records which don't have an address and whose name matches. */
+{
+  struct dhcp_config *config;
+  struct crec *crec;
+ 
+  for (config = configs; config; config = config->next)
+    if (config->addr.s_addr == 0 && config->hostname && 
+	(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
+	(crec->flags & F_HOSTS))
+      config->addr = crec->addr.addr.addr4;
+}
     
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 2a7615b..99cbed0 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -158,6 +158,7 @@
 	if (!dhcp_tmp->iface)
 	  die("No suitable interface for DHCP service at address %s", inet_ntoa(dhcp_tmp->start));
             
+      set_configs_from_cache(dhcp_configs);
       leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, time(NULL), dhcp_configs);
       lease_update_dns(1); /* must follow cache_init and lease_init */
     }
@@ -270,6 +271,7 @@
       if (sighup)
 	{
 	  cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
+	  set_configs_from_cache(dhcp_configs);
 	  lease_update_dns(1);
 	  if (resolv && (options & OPT_NO_POLL))
 	    servers = last_server = 
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index ba50040..f298f92 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -16,6 +16,8 @@
 #define _XOPEN_SOURCE 600
 /* but then DNS headers don't compile without.... */
 #define _BSD_SOURCE
+/* and also, on FreeBSD 5.0 ..... */
+#define __BSD_VISIBLE 1
 
 /* get these before config.h  for IPv6 stuff... */
 #include <sys/types.h>
@@ -26,7 +28,6 @@
 
 #include "config.h"
 
-#include <netinet/in.h>
 #include <arpa/nameser.h>
 #include <arpa/inet.h>
 #include <sys/stat.h>
@@ -229,8 +230,7 @@
 };
 
 struct dhcp_opt {
-  unsigned char opt;
-  unsigned char len;
+  int opt, len, is_addr;
   unsigned char *val;
   struct dhcp_opt *next;
  };
@@ -360,6 +360,7 @@
 				unsigned char *clid, int clid_len,
 				unsigned char *hwaddr, char *hostname);
 
+void set_configs_from_cache(struct dhcp_config *configs);
 /* lease.c */
 void lease_update_dns(int force_dns);
 int lease_init(char *lease_file, char *domain, char *buff, 
diff --git a/src/forward.c b/src/forward.c
index cbbc5e0..e14287d 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -132,6 +132,7 @@
 			flags = 0; /* may be better match from previous literal */
 			domain = serv->domain;
 			matchlen = domainlen;
+			type = SERV_HAS_DOMAIN;
 		      }
 		  } 
 	      }
diff --git a/src/network.c b/src/network.c
index a3bbdbc..43dd402 100644
--- a/src/network.c
+++ b/src/network.c
@@ -76,12 +76,14 @@
      specific addresses even if BIND is running and has bound *:53 */
   opt = 1;
   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
-      bind(fd, &addr->sa, sa_len(addr)))
+      bind(fd, &addr->sa, sa_len(addr)) == -1)
     {
       int errsave = errno;
       close(fd);
       errno = errsave;
-      return "failed to bind socket: %s";
+      /* IPv6 interfaces sometimes return ENODEV to bind() for unknown
+	 (to me) reasons. Don't treat that as fatal. */
+      return errno == ENODEV ? NULL : "failed to bind socket: %s";
     }
 
   /* If OK, add it to the head of the list */
@@ -119,6 +121,7 @@
   struct irec *iface, *prev;
   char *buf, *ptr, *err = NULL;
   struct ifconf ifc;
+  struct ifreq *ifr = NULL;
   int fd = socket(PF_INET, SOCK_DGRAM, 0);
   int rawfd = -1;
   
@@ -158,12 +161,22 @@
 
   for (ptr = buf; ptr < buf + ifc.ifc_len; )
     {
-      struct ifreq *ifr = (struct ifreq *) ptr;
       union mysockaddr addr;
-
 #ifdef HAVE_SOCKADDR_SA_LEN
-      ptr += ifr->ifr_addr.sa_len + IF_NAMESIZE;
+      /* subsequent entries may not be aligned, so copy into
+	 an aligned buffer to avoid nasty complaints about 
+	 unaligned accesses. */
+      int ifr_len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
+      if (!(ifr = realloc(ifr, ifr_len)))
+	{
+	  err = "cannot allocate buffer";
+	  goto end;
+	}
+      
+      memcpy(ifr, ptr, ifr_len);
+      ptr += ifr_len;
 #else
+      ifr = (struct ifreq *)ptr;
       ptr += sizeof(struct ifreq);
 #endif
 
@@ -198,6 +211,54 @@
 			   &addr, names, addrs, except)))
 	goto end;
 
+#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
+      /* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
+      /* This code snarfed from net-tools 1.60 and certainly linux specific, though
+	 it shouldn't break on other Unices, and their SIOGIFCONF might work. */
+      {
+	FILE *f = fopen(IP6INTERFACES, "r");
+	int found = 0;
+	
+	if (f)
+	  {
+	    unsigned int plen, scope, flags, if_idx;
+	    char devname[20], addrstring[32];
+	    
+	    while (fscanf(f, "%32s %02x %02x %02x %02x %20s\n",
+			  addrstring, &if_idx, &plen, &scope, &flags, devname) != EOF) 
+	      {
+		if (strcmp(devname, ifr->ifr_name) == 0)
+		  {
+		    int i;
+		    unsigned char *addr6p = (unsigned char *) &addr.in6.sin6_addr;
+		    memset(&addr, 0, sizeof(addr));
+		    addr.sa.sa_family = AF_INET6;
+		    for (i=0; i<16; i++)
+		      {
+			unsigned int byte;
+			sscanf(addrstring+i+i, "%02x", &byte);
+			addr6p[i] = byte;
+		      }
+		    addr.in6.sin6_port = htons(port);
+		    addr.in6.sin6_flowinfo = htonl(0);
+		    addr.in6.sin6_scope_id = htonl(scope);
+		    
+		    found = 1;
+		    break;
+		  }
+	      }
+	    
+	    fclose(f);
+	  }
+	
+	if (found && 
+	    (err = add_iface(interfacep, ifr->ifr_flags,  ifr->ifr_name,
+			     &addr, names, addrs, except)))
+	  goto end;
+      }
+      
+#endif /* LINUX */
+	
       /* dhcp is non-null only on the first call: set up the relevant 
 	 interface-related DHCP stuff here. DHCP is IPv4 only.
 	 Because errors here are ultimately fatal we can return directly and not bother
@@ -289,32 +350,48 @@
 	      }
 
 	}
-    }
+      }
 
 #ifdef HAVE_BPF
   /* now go through the interfaces again, looking for AF_LINK records
      to get hardware addresses from */
   for (ptr = buf; ptr < buf + ifc.ifc_len; )
     {
-      struct ifreq *ifr = (struct ifreq *) ptr;
       struct dhcp_context *context;
       
 #ifdef HAVE_SOCKADDR_SA_LEN
-      ptr += ifr->ifr_addr.sa_len + IF_NAMESIZE;
+      /* subsequent entries may not be aligned, so copy into
+	 an aligned buffer to avoid nasty complaints about 
+	 unaligned accesses. */
+      int ifr_len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
+      if (!(ifr = realloc(ifr, ifr_len)))
+	{
+	  err = "cannot allocate buffer";
+	  goto end;
+	}
+      
+      memcpy(ifr, ptr, ifr_len);
+      ptr += ifr_len;
 #else
+      ifr = (struct ifreq *)ptr;
       ptr += sizeof(struct ifreq);
 #endif
+      
       if (ifr->ifr_addr.sa_family == AF_LINK)
 	for (context = dhcp; context; context = context->next)
 	  if (context->iface && strcmp(context->iface, ifr->ifr_name) == 0)
 	    memcpy(context->hwaddr, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
     }
 #endif
-
+  
  end:
   errsave = errno; /* since errno gets overwritten by close */
   if (buf)
     free(buf);
+#ifdef HAVE_SOCKADDR_SA_LEN
+  if (ifr)
+    free(ifr);
+#endif
   close(fd);
   if (err)
     { 
@@ -322,54 +399,6 @@
       return err;
     }
 
-#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
-  /* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
-  /* This code snarfed from net-tools 1.60 and certainly linux specific, though
-     it shouldn't break on other Unices, and their SIOGIFCONF might work. */
-  {
-    FILE *f = fopen(IP6INTERFACES, "r");
-    
-    if (f)
-      {
-	union mysockaddr addr;
-	unsigned int plen, scope, flags, if_idx;
-	char devname[20], addrstring[32];
-	
-	while (fscanf(f, "%32s %02x %02x %02x %02x %20s\n",
-		      addrstring, &if_idx, &plen, &scope, &flags, devname) != EOF) 
-	  {
-	    int i;
-	    unsigned char *addr6p = (unsigned char *) &addr.in6.sin6_addr;
-	    memset(&addr, 0, sizeof(addr));
-	    addr.sa.sa_family = AF_INET6;
-	    for (i=0; i<16; i++)
-	      {
-		unsigned int byte;
-		sscanf(addrstring+i+i, "%02x", &byte);
-		addr6p[i] = byte;
-	      }
-#ifdef HAVE_SOCKADDR_SA_LEN 
-	    /* For completeness - should never be defined on Linux. */
-	    addr.in6.sin6_len = sizeof(struct sockaddr_in6);
-#endif
-	    addr.in6.sin6_port = htons(port);
-	    addr.in6.sin6_flowinfo = htonl(0);
-	    addr.in6.sin6_scope_id = htonl(scope);
-	    
-	    if ((err = add_iface(interfacep, flags,  devname, &addr, names, addrs, except)))
-	      {
-		errsave = errno;
-		fclose(f);
-		errno = errsave;
-		return err;
-	      }
-	  }
-	
-	fclose(f);
-      }
-  }
-#endif /* LINUX */
-
   /* now remove interfaces which were not found on this scan */
   for(prev = NULL, iface = *interfacep; iface; )
     {
diff --git a/src/option.c b/src/option.c
index 3a92671..7a1df98 100644
--- a/src/option.c
+++ b/src/option.c
@@ -175,14 +175,18 @@
 	  else
 	    {
 	      char *p;
+	      /* dump comments */
+	      for (p = buff; *p; p++)
+		if (*p == '#')
+		  *p = 0;
 	      /* fgets gets end of line char too. */
 	      while (strlen(buff) > 0 && 
 		     (buff[strlen(buff)-1] == '\n' || 
 		      buff[strlen(buff)-1] == ' ' || 
 		      buff[strlen(buff)-1] == '\t'))
 		buff[strlen(buff)-1] = 0;
-	      if (*buff == '#' || *buff == 0)
-		continue; /* comment */
+	      if (*buff == 0)
+		continue; 
 	      if ((p=strchr(buff, '=')))
 		{
 		  optarg = p+1;
@@ -639,7 +643,7 @@
 		new->clid = NULL;
 		new->hostname = NULL;
 		new->addr.s_addr = 0;
-		new->lease_time = DEFLEASE; 
+		new->lease_time = 0; 
 		
 		a[0] = optarg;
 		for (k = 1; k < 4; k++)
@@ -706,8 +710,8 @@
 			    {
 			    case 'h':
 			    case 'H':
-				fac *= 60;
-				/* fall through */
+			      fac *= 60;
+			      /* fall through */
 			    case 'm':
 			    case 'M':
 			      fac *= 60;
@@ -717,7 +721,7 @@
 			}
 		      
 		      for (cp = a[j]; *cp; cp++)
-			if (!isdigit(*cp))
+			if (!isdigit(*cp) && *cp != ' ')
 			  break;
 		      
 		      if (*cp)
@@ -739,24 +743,33 @@
 	      {
 		struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
 		char *cp, *comma = strchr(optarg, ',');
-		int addrs;
+		int addrs, is_addr;
 		
 		new->next = *dhcp_opts;
+		new->len = 0;
+		new->is_addr = 0;
 		*dhcp_opts = new;
 		
-		if (!comma || (*comma = 0) || (new->opt = atoi(optarg)) == 0)
+		if ((new->opt = atoi(optarg)) == 0)
 		  {
 		    option = '?';
 		    break;
 		  }
 		
+		if (!comma)
+		  break;
+		
+		*comma = 0;
+
 		/* check for non-address list characters */
-		for (addrs = 1, cp = comma+1; *cp; cp++)
+		for (addrs = 1, is_addr = 0, cp = comma+1; *cp; cp++)
 		  if (*cp == ',')
 		    addrs++;
 		  else if (!(*cp == '.' || *cp == ' ' || (*cp >='0' && *cp <= '9')))
 		    break;
-		
+		  else if (*cp == '.')
+		    is_addr = 1;
+		    
 		if (*cp)
 		  {
 		    /* text arg */
@@ -768,17 +781,28 @@
 		  {
 		    struct in_addr in;
 		    unsigned char *op;
-		    new->len = INADDRSZ * addrs;
-		    new->val = op =  safe_malloc(new->len);
-		    while (addrs--) 
+
+		    if (addrs == 1 && !is_addr)
 		      {
-			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;
+			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;
+			  }
 		      }
 		  }
 		break;
diff --git a/src/rfc2131.c b/src/rfc2131.c
index 427f627..67dc2be 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -139,7 +139,7 @@
      
   /* 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 : context->lease_time;
+  def_time = config && config->lease_time ? config->lease_time : context->lease_time;
   
   if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
     {
@@ -444,6 +444,9 @@
   if (!req_options)
     return p;
 
+  if (in_list(req_options, OPTION_MAXMESSAGE))
+    p = option_put(p, end, OPTION_MAXMESSAGE, 2, sizeof(struct udp_dhcp_packet));
+  
   if (in_list(req_options, OPTION_NETMASK) &&
       !option_find2(config_opts, OPTION_NETMASK))
     p = option_put(p, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
@@ -484,12 +487,34 @@
   for (i = 0; req_options[i] != OPTION_END; i++)
     {
       struct dhcp_opt *opt = option_find2(config_opts, req_options[i]);
-      if (req_options[i] != OPTION_HOSTNAME && opt && (p + opt->len + 2 < end))
+      if (req_options[i] != OPTION_HOSTNAME && 
+	  req_options[i] != OPTION_MAXMESSAGE &&
+	  opt && (p + opt->len + 2 < end))
 	{
 	  *(p++) = opt->opt;
 	  *(p++) = opt->len;
-	  memcpy(p, opt->val, opt->len);
-	  p += opt->len;
+	  if (opt->len != 0)
+	    {
+	      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, &context->serv_addr, INADDRSZ);
+		      else
+			memcpy(p, a, INADDRSZ);
+		      p += INADDRSZ;
+		    }
+		}
+	      else
+		{
+		  memcpy(p, opt->val, opt->len);
+		  p += opt->len;
+		}
+	    }
 	}
     }