Merge remote-tracking branch 'upstream/master' into HEAD
diff --git a/CHANGELOG b/CHANGELOG
index 23fc6d0..a4cb901 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -49,7 +49,20 @@
 	    sometimes reasons to do it. (Step forward, GFW).
 	    To avoid misuse, there's a hard limit on the TTL 
 	    floor of one hour. Thansk to RinSatsuki for the patch.
+
+	    Cope with multiple interfaces with the same link-local 
+	    address. (IPv6 addresses are scoped, so this is allowed.)
+	    Thanks to Cory Benfield for help with this.
+
+	    Add --dhcp-hostsdir. This allows addition of new host
+	    configurations to a running dnsmasq instance much more 
+	    cheaply than having dnsmasq re-read all its existing
+	    configuration each time. 
 	
+	    Don't reply to DHCPv6 SOLICIT messages if we're not 
+	    configured to do stateful DHCPv6. Thanks to Win King Wan 
+	    for the patch.
+
 	
 version 2.72
             Add ra-advrouter mode, for RFC-3775 mobile IPv6 support.
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 5cfa355..005b5cc 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -977,6 +977,15 @@
 using this option is the same as for --dhcp-hostsfile: the
 dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. Note that
 it is possible to encode the information in a
+.TP
+.B --dhcp-hostsdir=<path>
+This is exactly equivalent to dhcp-hostfile, except for the following. The path MUST be a
+directory, and not an individual file. Changed or new files within
+the directory are read automatically, without the need to send SIGHUP.
+If a file is deleted for changed after it has been read by dnsmasq, then the
+host record it contained will remain until dnsmasq recieves a SIGHUP, or 
+is restarted; ie host records are only added dynamically.
+.TP
 .B --dhcp-boot
 flag as DHCP options, using the options names bootfile-name,
 server-ip-address and tftp-server. This allows these to be included
diff --git a/po/de.po b/po/de.po
index e231737..4c93c5b 100644
--- a/po/de.po
+++ b/po/de.po
@@ -9,10 +9,10 @@
 # Simon Kelley <simon@thekelleys.org.uk>, 2005.
 msgid ""
 msgstr ""
-"Project-Id-Version: dnsmasq 2.70\n"
+"Project-Id-Version: dnsmasq 2.73\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2009-06-18 12:24+0100\n"
-"PO-Revision-Date: 2014-05-01 22:51+0100\n"
+"PO-Revision-Date: 2015-01-19 15:43+0100\n"
 "Last-Translator: Conrad Kostecki <ck@conrad-kostecki.de>\n"
 "Language-Team: German <de@li.org>\n"
 "Language: de\n"
@@ -20,12 +20,12 @@
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 1.6.5\n"
+"X-Generator: Poedit 1.7.3\n"
 "X-Poedit-SourceCharset: UTF-8\n"
 
 #: cache.c:505
 msgid "Internal error in cache."
-msgstr ""
+msgstr "Interner Fehler im Cache."
 
 #: cache.c:908
 #, c-format
@@ -126,7 +126,7 @@
 
 #: option.c:319
 msgid "Return ipaddr for all hosts in specified domains."
-msgstr "IP-Adresse für alle Hosts in angebenen Domänen festlegen."
+msgstr "IP-Adresse für alle Hosts in angegebenen Domänen festlegen."
 
 # FIXME: the English test is not to the point. Just use a shortened description
 # from the manpage instead. -- MA
@@ -310,18 +310,16 @@
 msgstr "Pfad zu resolv.conf festlegen (%s voreingestellt)."
 
 #: option.c:362
-#, fuzzy
 msgid "Specify path to file with server= options"
-msgstr "Dateipfad für Prozesskennung (PID) festlegen (Voreinstellung: %s)."
+msgstr " Dateipfad mit der Option server= angeben"
 
 #: option.c:363
 msgid "Specify address(es) of upstream servers with optional domains."
 msgstr "Adresse(n) vorgelagerter Server festlegen, optional mit Domänen."
 
 #: option.c:364
-#, fuzzy
 msgid "Specify address of upstream servers for reverse address queries"
-msgstr "Adresse(n) vorgelagerter Server festlegen, optional mit Domänen."
+msgstr "Adresse(n) vorgelagerter Server festlegen, für reverse Adressanfragen"
 
 #: option.c:365
 msgid "Never forward queries to specified domains."
@@ -657,23 +655,23 @@
 
 #: option.c:446
 msgid "Activate DNSSEC validation"
-msgstr ""
+msgstr "Aktiviere DNSSEC-Validierung"
 
 #: option.c:447
 msgid "Specify trust anchor key digest."
-msgstr ""
+msgstr "Spezifiziere Vertrauensursprung (Trust Anchor) der Schlüssel-Prüfdaten (Key Digest)."
 
 #: option.c:448
 msgid "Disable upstream checking for DNSSEC debugging."
-msgstr ""
+msgstr "Deaktiviere die Überprüfung vorgelagerter Server für DNSSEC-Debugging"
 
 #: option.c:449
 msgid "Ensure answers without DNSSEC are in unsigned zones."
-msgstr ""
+msgstr "Stellt sicher, dass Antworten ohne DNSSEC sich in einer unsignierten Zone befinden."
 
 #: option.c:450
 msgid "Don't check DNSSEC signature timestamps until first cache-reload"
-msgstr ""
+msgstr "DNSSEC Signatur-Zeitstempel nicht prüfen, bis erstmalig der Cache neugeladen wird"
 
 #: option.c:452
 msgid "Specify DHCPv6 prefix class"
@@ -697,11 +695,11 @@
 
 #: option.c:458
 msgid "Accept queries only from directly-connected networks"
-msgstr ""
+msgstr "Akzeptiere nur Anfragen von direkt verbundenen Netzwerken"
 
 #: option.c:459
 msgid "Detect and remove DNS forwarding loops"
-msgstr ""
+msgstr "Erkennen und Entfernen von DNS-Weiterleitungsschleifen"
 
 #: option.c:661
 #, c-format
@@ -958,18 +956,16 @@
 msgstr "Unzulässiger Name in host-record"
 
 #: option.c:3826
-#, fuzzy
 msgid "bad trust anchor"
-msgstr "unzulässiger Portbereich"
+msgstr "unzulässiger Vertrauensursprung (Trust Anchor)"
 
 #: option.c:3840
 msgid "bad HEX in trust anchor"
-msgstr ""
+msgstr "unzulässiger Hexwert in Vertrauensursprung (Trust Anchor)"
 
 #: option.c:3850
-#, fuzzy
 msgid "unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"
-msgstr "unzulässige Option (prüfen Sie, ob dnsmasq mit DHCP/TFTP/DBus-Unterstützt übersetzt wurde)"
+msgstr "Nicht unterstützte Option (prüfen Sie, ob DNSMasq mit DHCP/TFTP/DNSSEC/DBus-Unterstützung übersetzt wurde)"
 
 #: option.c:3909
 msgid "missing \""
@@ -988,7 +984,6 @@
 msgstr "fehler Parameter"
 
 #: option.c:3972
-#, fuzzy
 msgid "illegal option"
 msgstr "unzulässige Option"
 
@@ -1110,7 +1105,7 @@
 
 #: forward.c:1132 forward.c:1663
 msgid "Ignoring query from non-local network"
-msgstr ""
+msgstr "Ignoriere Anfragen vom nicht lokalen Netzwerk"
 
 #: forward.c:2101
 #, c-format
@@ -1189,9 +1184,9 @@
 msgstr "Benutze Namensserver %s#%d für %s %s"
 
 #: network.c:1483
-#, fuzzy, c-format
+#, c-format
 msgid "NOT using nameserver %s#%d - query loop detected"
-msgstr "Benutze Namensserver %s#%d für %s %s"
+msgstr "Benutze Namensserver %s#%d NICHT - Anfragenschleife festgetellt"
 
 #: network.c:1486
 #, c-format
@@ -1205,16 +1200,15 @@
 
 #: dnsmasq.c:154
 msgid "No trust anchors provided for DNSSEC"
-msgstr ""
+msgstr "Keine Vertrauensursprünge (Trust Anchor) für DNSSEC verfügbar"
 
 #: dnsmasq.c:157
 msgid "Cannot reduce cache size from default when DNSSEC enabled"
-msgstr ""
+msgstr "Kann die Standard Cachegröße nicht verkleinern, wenn DNSSEC aktiviert ist"
 
 #: dnsmasq.c:159
-#, fuzzy
 msgid "DNSSEC not available: set HAVE_DNSSEC in src/config.h"
-msgstr "DBus nicht verfügbar: setzen Sie HAVE_DBUS in src/config.h"
+msgstr "DNSSEC nicht verfügbar: setzen Sie HAVE_DNSSEC in src/config.h"
 
 #: dnsmasq.c:165
 msgid "TFTP server not available: set HAVE_TFTP in src/config.h"
@@ -1241,9 +1235,8 @@
 msgstr "Authoritatives DNS nicht verfügbar: Es muss HAVE_AUTH in src/config.h gesetzt sein"
 
 #: dnsmasq.c:193
-#, fuzzy
 msgid "Loop detection not available: set HAVE_LOOP in src/config.h"
-msgstr "TFTP-Server nicht verfügbar, setzen Sie HAVE_TFTP in src/config.h"
+msgstr "Loop-Erkennung nicht verfügbar, setzen Sie HAVE_LOOP in src/config.h"
 
 #: dnsmasq.c:201
 msgid "zone serial must be configured in --auth-soa"
@@ -1317,15 +1310,15 @@
 
 #: dnsmasq.c:672
 msgid "DNS service limited to local subnets"
-msgstr ""
+msgstr "DNS-Dienst auf lokale Subnetze eingeschränkt"
 
 #: dnsmasq.c:677
 msgid "DNSSEC validation enabled"
-msgstr ""
+msgstr "DNSSEC-Validierung aktiviert"
 
 #: dnsmasq.c:679
 msgid "DNSSEC signature timestamps not checked until first cache reload"
-msgstr ""
+msgstr "DNSSEC Signatur-Zeitstempel werden erst ab dem ersten Neuladen des Caches überprüft"
 
 #: dnsmasq.c:684
 #, c-format
@@ -1366,7 +1359,7 @@
 # FIXME: this and the next few must be full strings to be translatable - do not assemble in code"
 #: dnsmasq.c:753
 msgid "root is "
-msgstr "Wurzel ist"
+msgstr "Wurzel ist "
 
 #: dnsmasq.c:753
 msgid "enabled"
@@ -1432,7 +1425,7 @@
 
 #: dnsmasq.c:1151
 msgid "now checking DNSSEC signature timestamps"
-msgstr ""
+msgstr "Prüfe jetzt DNSSEC Signatur-Zeitstempel"
 
 #: dnsmasq.c:1218
 #, c-format
@@ -1506,7 +1499,7 @@
 #: dhcp.c:408
 #, c-format
 msgid "ARP-cache injection failed: %s"
-msgstr ""
+msgstr "APR-Cache Injektion fehlgeschlagen: %s"
 
 #: dhcp.c:506
 #, c-format
@@ -1763,13 +1756,13 @@
 msgstr "DHCP-Anfrage für nicht unterstützen Hardwaretyp (%d) auf %s empfangen"
 
 #: bpf.c:376
-#, fuzzy, c-format
+#, c-format
 msgid "cannot create PF_ROUTE socket: %s"
-msgstr "kann DHCP-Socket nicht erzeugen: %s"
+msgstr "Kann PF_ROUTE socket nicht erzeugen: %s"
 
 #: bpf.c:397
 msgid "Unknown protocol version from route socket"
-msgstr ""
+msgstr "Unbekannte Protokollversion vom Route Socket"
 
 #: helper.c:153
 msgid "lease() function missing in Lua script"
@@ -2020,50 +2013,50 @@
 #: blockdata.c:58
 #, c-format
 msgid "DNSSEC memory in use %u, max %u, allocated %u"
-msgstr ""
+msgstr "DNSSEC Speicher in Benutzung %u, Max %u, zugewiesen %u"
 
 #: tables.c:76
 msgid "error: fill_addr missused"
-msgstr ""
+msgstr "Fehler: fill_addr falsch verwendet"
 
 #: tables.c:105
-#, fuzzy, c-format
+#, c-format
 msgid "failed to access pf devices: %s"
-msgstr "konnte auf %s nicht zugreifen: %s"
+msgstr "konnte auf pf Geräte nicht zugreifen: %s"
 
 #: tables.c:119
-#, fuzzy, c-format
+#, c-format
 msgid "warning: no opened pf devices %s"
-msgstr "Warnung: Keine Adresse für die Schnittstelle %s gefunden"
+msgstr "Warnung: Keine geöffneten pf Geräte %s"
 
 #: tables.c:127
-#, fuzzy, c-format
+#, c-format
 msgid "error: cannot use table name %s"
-msgstr "kann Hostnamen nicht ermitteln: %s"
+msgstr "Fehler: Kann Tabellenname %s nicht benutzen"
 
 #: tables.c:135
 #, c-format
 msgid "error: cannot strlcpy table name %s"
-msgstr ""
+msgstr "Fehler: Kann den Tabellennamen %s nicht strlcpy"
 
 #: tables.c:141
 #, c-format
 msgid "warning: pfr_add_tables: %s(%d)"
-msgstr ""
+msgstr "Warnung: pfr_add_tables: %s(%d)"
 
 #: tables.c:147
 msgid "info: table created"
-msgstr ""
+msgstr "Info: Tabelle erstellt"
 
 #: tables.c:158
 #, c-format
 msgid "warning: DIOCR%sADDRS: %s"
-msgstr ""
+msgstr "Warnung: DIOCR%sADDRS: %s"
 
 #: tables.c:162
-#, fuzzy, c-format
+#, c-format
 msgid "%d addresses %s"
-msgstr "Fehlerhafte Adresse"
+msgstr "%d Adressen %s"
 
 #~ msgid "no interface with address %s"
 #~ msgstr "keine Schnittstelle mit Adresse %s"
diff --git a/src/auth.c b/src/auth.c
index a327f16..59e05d3 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -413,7 +413,10 @@
 		peer_addr->in.sin_port = 0;
 #ifdef HAVE_IPV6
 	      else
-		peer_addr->in6.sin6_port = 0; 
+		{
+		  peer_addr->in6.sin6_port = 0; 
+		  peer_addr->in6.sin6_scope_id = 0;
+		}
 #endif
 	      
 	      for (peers = daemon->auth_peers; peers; peers = peers->next)
diff --git a/src/cache.c b/src/cache.c
index 945be07..09b6dbf 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -1642,11 +1642,11 @@
 
   if (option_bool(OPT_EXTRALOG))
     {
-      prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
+      int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
       if (flags & F_NOEXTRA)
-	my_syslog(LOG_INFO, "* %s %s %s %s %s", daemon->addrbuff2, source, name, verb, dest);
+	my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
       else
-	my_syslog(LOG_INFO, "%u %s %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, source, name, verb, dest);
+	my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
     }
   else
     my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index c0c0589..04cc982 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -142,6 +142,9 @@
       set_option_bool(OPT_NOWILD);
       reset_option_bool(OPT_CLEVERBIND);
     }
+
+  if (daemon->inotify_hosts)
+    die(_("dhcp-hostsdir not supported on this platform"), NULL, EC_BADCONF);
 #endif
   
   if (option_bool(OPT_DNSSEC_VALID))
@@ -316,13 +319,16 @@
 #ifdef HAVE_DNSSEC
       blockdata_init();
 #endif
+    }
 
 #ifdef HAVE_LINUX_NETWORK
-      if (!option_bool(OPT_NO_POLL))
-	inotify_dnsmasq_init();
+  if ((!option_bool(OPT_NO_POLL) && daemon->port != 0) ||
+      daemon->dhcp || daemon->doing_dhcp6)
+    inotify_dnsmasq_init();
+  else
+    daemon->inotifyfd = -1;
 #endif
-    }
-    
+       
   if (option_bool(OPT_DBUS))
 #ifdef HAVE_DBUS
     {
@@ -745,7 +751,7 @@
 #endif
 
 #ifdef HAVE_TFTP
-	if (option_bool(OPT_TFTP))
+  if (option_bool(OPT_TFTP))
     {
 #ifdef FD_SETSIZE
       if (FD_SETSIZE < (unsigned)max_fd)
@@ -870,7 +876,7 @@
 #if defined(HAVE_LINUX_NETWORK)
       FD_SET(daemon->netlinkfd, &rset);
       bump_maxfd(daemon->netlinkfd, &maxfd);
-      if (daemon->port != 0 && !option_bool(OPT_NO_POLL))
+      if (daemon->inotifyfd != -1)
 	{
 	  FD_SET(daemon->inotifyfd, &rset);
 	  bump_maxfd(daemon->inotifyfd, &maxfd);
@@ -943,8 +949,11 @@
 #endif
 
 #ifdef HAVE_LINUX_NETWORK
-      if (daemon->port != 0 && !option_bool(OPT_NO_POLL) && FD_ISSET(daemon->inotifyfd, &rset) && inotify_check())
-	poll_resolv(1, 1, now); 	  
+      if  (daemon->inotifyfd != -1 && FD_ISSET(daemon->inotifyfd, &rset) && inotify_check(now))
+	{
+	  if (daemon->port != 0 && !option_bool(OPT_NO_POLL))
+	    poll_resolv(1, 1, now);
+	} 	  
 #else
       /* Check for changes to resolv files once per second max. */
       /* Don't go silent for long periods if the clock goes backwards. */
@@ -1385,6 +1394,9 @@
       if (option_bool(OPT_ETHERS))
 	dhcp_read_ethers();
       reread_dhcp();
+#ifdef HAVE_LINUX_NETWORK
+      set_dhcp_inotify();
+#endif
       dhcp_update_configs(daemon->dhcp_conf);
       lease_update_from_configs(); 
       lease_update_file(now); 
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index f8275e3..d841fdc 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -550,13 +550,17 @@
 #endif
 };
 
-/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile */
+/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile and dhcp-hostsdir*/
 #define AH_DIR      1
 #define AH_INACTIVE 2
+#define AH_WD_DONE  4
 struct hostsfile {
   struct hostsfile *next;
   int flags;
   char *fname;
+#ifdef HAVE_LINUX_NETWORK
+  int wd; /* inotify watch descriptor */
+#endif
   unsigned int index; /* matches to cache entries for logging */
 };
 
@@ -961,7 +965,7 @@
   int doing_ra, doing_dhcp6;
   struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names; 
   struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
-  struct hostsfile *dhcp_hosts_file, *dhcp_opts_file;
+  struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, *inotify_hosts;
   int dhcp_max, tftp_max;
   int dhcp_server_port, dhcp_client_port;
   int start_tftp_port, end_tftp_port; 
@@ -1197,7 +1201,7 @@
 struct hostsfile *expand_filelist(struct hostsfile *list);
 char *parse_server(char *arg, union mysockaddr *addr, 
 		   union mysockaddr *source_addr, char *interface, int *flags);
-
+int option_read_hostsfile(char *file);
 /* forward.c */
 void reply_query(int fd, int family, time_t now);
 void receive_query(struct listener *listen, time_t now);
@@ -1486,5 +1490,8 @@
 /* inotify.c */
 #ifdef HAVE_LINUX_NETWORK
 void inotify_dnsmasq_init();
-int inotify_check(void);
+int inotify_check(time_t now);
+#  ifdef HAVE_DHCP
+void set_dhcp_inotify(void);
+#  endif
 #endif
diff --git a/src/dnssec.c b/src/dnssec.c
index afb3dca..d39ab85 100644
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -1818,11 +1818,14 @@
 	      struct blockdata *key;
 	      struct crec *crecp;
 	      char *wildname;
+	      int have_wildcard = 0;
 
 	      rc = validate_rrset(now, header, plen, class1, type1, name, keyname, &wildname, NULL, 0, 0, 0);
 	      
 	      if (rc == STAT_SECURE_WILDCARD)
 		{
+		  have_wildcard = 1;
+
 		  /* An attacker replay a wildcard answer with a different
 		     answer and overlay a genuine RR. To prove this
 		     hasn't happened, the answer must prove that
@@ -1913,7 +1916,11 @@
 			      p2 += 13; /* labels, orig_ttl, expiration, inception */
 			      GETSHORT(keytag, p2);
 			      
-			      if ((key = blockdata_alloc((char*)psave, rdlen2)))
+			      /* We don't cache sigs for wildcard answers, because to reproduce the
+				 answer from the cache will require one or more NSEC/NSEC3 records 
+				 which we don't cache. The lack of the RRSIG ensures that a query for
+				 this RRset asking for a secure answer will always be forwarded. */
+			      if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
 				{
 				  if (!(crecp = cache_insert(name, &a, now, ttl,  F_FORWARD | F_DNSKEY | F_DS)))
 				    blockdata_free(key);
diff --git a/src/forward.c b/src/forward.c
index 713a64c..b17bc34 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -737,7 +737,7 @@
       check_for_ignored_address(header, n, daemon->ignore_addr))
     return;
 
-  if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
+  if (RCODE(header) == REFUSED &&
       !option_bool(OPT_ORDER) &&
       forward->forwardall == 0)
     /* for broken servers, attempt to send to another one. */
diff --git a/src/inotify.c b/src/inotify.c
index 8373000..52a30d7 100644
--- a/src/inotify.c
+++ b/src/inotify.c
@@ -19,6 +19,11 @@
 
 #include <sys/inotify.h>
 
+#ifdef HAVE_DHCP
+static void check_for_dhcp_inotify(struct inotify_event *in, time_t now);
+#endif
+
+
 /* the strategy is to set a inotify on the directories containing
    resolv files, for any files in the directory which are close-write 
    or moved into the directory.
@@ -40,8 +45,6 @@
   struct resolvc *res;
 
   inotify_buffer = safe_malloc(INOTIFY_SZ);
-
-
   daemon->inotifyfd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
   
   if (daemon->inotifyfd == -1)
@@ -66,6 +69,7 @@
 	{
 	  *d = 0; /* make path just directory */
 	  res->wd = inotify_add_watch(daemon->inotifyfd, path, IN_CLOSE_WRITE | IN_MOVED_TO);
+
 	  res->file = d+1; /* pointer to filename */
 	  *d = '/';
 	  
@@ -78,7 +82,7 @@
     }
 }
 
-int inotify_check(void)
+int inotify_check(time_t now)
 {
   int hit = 0;
   
@@ -101,13 +105,116 @@
 	  for (res = daemon->resolv_files; res; res = res->next)
 	    if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
 	      hit = 1;
+
+#ifdef HAVE_DHCP
+	  if (daemon->dhcp || daemon->doing_dhcp6)
+	    check_for_dhcp_inotify(in, now);
+#endif
 	}
     }
-
   return hit;
 }
 
-#endif
+#ifdef HAVE_DHCP 
+/* initialisation for dhcp-hostdir. Set inotify watch for each directory, and read pre-existing files */
+void set_dhcp_inotify(void)
+{
+  struct hostsfile *ah;
 
-  
+  for (ah = daemon->inotify_hosts; ah; ah = ah->next)
+    {
+       DIR *dir_stream = NULL;
+       struct dirent *ent;
+       struct stat buf;
+
+       if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
+	 {
+	   my_syslog(LOG_ERR, _("bad directory in dhcp-hostsdir %s"), ah->fname);
+	   continue;
+	 }
+
+       if (!(ah->flags & AH_WD_DONE))
+	 {
+	   ah->wd = inotify_add_watch(daemon->inotifyfd, ah->fname, IN_CLOSE_WRITE | IN_MOVED_TO);
+	   ah->flags |= AH_WD_DONE;
+	 }
+       /* Read contents of dir _after_ calling add_watch, in the ho[e of avoiding
+	  a race which misses files being added as we start */
+       if (ah->wd == -1 || !(dir_stream = opendir(ah->fname)))
+	 {
+	   my_syslog(LOG_ERR, _("failed to create inotify for %s"), ah->fname);
+	   continue;
+	 }
+
+       while ((ent = readdir(dir_stream)))
+	 {
+	   size_t lendir = strlen(ah->fname);
+	   size_t lenfile = strlen(ent->d_name);
+	   char *path;
+	   
+	   /* ignore emacs backups and dotfiles */
+	   if (lenfile == 0 || 
+	       ent->d_name[lenfile - 1] == '~' ||
+	       (ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
+	       ent->d_name[0] == '.')
+	     continue;
+	   
+	   if ((path = whine_malloc(lendir + lenfile + 2)))
+	     {
+	       strcpy(path, ah->fname);
+	       strcat(path, "/");
+	       strcat(path, ent->d_name);
+	       
+	       /* ignore non-regular files */
+	       if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode))
+		 option_read_hostsfile(path);
+	       
+	       free(path);
+	     }
+	 }
+    }
+}
+
+static void check_for_dhcp_inotify(struct inotify_event *in, time_t now)
+{
+  struct hostsfile *ah;
+
+  /* ignore emacs backups and dotfiles */
+  if (in->len == 0 || 
+      in->name[in->len - 1] == '~' ||
+      (in->name[0] == '#' && in->name[in->len - 1] == '#') ||
+      in->name[0] == '.')
+    return;
+
+  for (ah = daemon->inotify_hosts; ah; ah = ah->next)
+    if (ah->wd == in->wd)
+      {
+	size_t lendir = strlen(ah->fname);
+	char *path;
+	   
+	if ((path = whine_malloc(lendir + in->len + 2)))
+	  {
+	    strcpy(path, ah->fname);
+	    strcat(path, "/");
+	    strcat(path, in->name);
+	    
+	    if (option_read_hostsfile(path))
+	      {
+		/* Propogate the consequences of loading a new dhcp-host */
+		dhcp_update_configs(daemon->dhcp_conf);
+		lease_update_from_configs(); 
+		lease_update_file(now); 
+		lease_update_dns(1);
+	      }
+	    
+	    free(path);
+	  }
+	
+	return;
+      }
+}
+
+#endif /* DHCP */
+
+#endif  /* LINUX_NETWORK */
   
diff --git a/src/option.c b/src/option.c
index 8b99409..22e11c3 100644
--- a/src/option.c
+++ b/src/option.c
@@ -149,7 +149,7 @@
 #define LOPT_LOOP_DETECT   337
 #define LOPT_IGNORE_ADDR   338
 #define LOPT_MINCTTL       339
-
+#define LOPT_DHCP_INOTIFY  340
 
 #ifdef HAVE_GETOPT_LONG
 static const struct option opts[] =  
@@ -248,6 +248,7 @@
     { "interface-name", 1, 0, LOPT_INTNAME },
     { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
     { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
+    { "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY },
     { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
     { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
     { "stop-dns-rebind", 0, 0, LOPT_REBIND },
@@ -336,6 +337,7 @@
   { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
   { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
   { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
+  { LOPT_DHCP_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from a directory."), NULL }, 
   { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
   { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
   { 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
@@ -1710,8 +1712,9 @@
       break;
 #endif /* HAVE_DHCP */
 
-    case LOPT_DHCP_HOST: /* --dhcp-hostfile */
+    case LOPT_DHCP_HOST: /* --dhcp-hostsfile */
     case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
+    case LOPT_DHCP_INOTIFY: /* dhcp-hostsdir */
     case 'H': /* --addn-hosts */
       {
 	struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
@@ -1734,6 +1737,12 @@
 	    new->next = daemon->dhcp_opts_file;
 	    daemon->dhcp_opts_file = new;
 	  } 	  
+	else if (option == LOPT_DHCP_INOTIFY)
+	  {
+	    new->next = daemon->inotify_hosts;
+	    daemon->inotify_hosts = new;
+	  }
+	
 	break;
       }
       
@@ -4042,6 +4051,13 @@
   fclose(f);
 }
 
+#ifdef HAVE_DHCP
+int option_read_hostsfile(char *file)
+{
+  return one_file(file, LOPT_BANK);
+}
+#endif
+
 static int one_file(char *file, int hard_opt)
 {
   FILE *f;
@@ -4139,7 +4155,7 @@
 	    
 	    /* don't read this as a file */
 	    ah->flags |= AH_INACTIVE;
-
+	    
 	    if (!(dir_stream = opendir(ah->fname)))
 	      my_syslog(LOG_ERR, _("cannot access directory %s: %s"), 
 			ah->fname, strerror(errno));
diff --git a/src/rfc1035.c b/src/rfc1035.c
index 75c4266..262274f 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -1643,7 +1643,7 @@
 			      {
 				if (crecp->flags & F_NXDOMAIN)
 				  nxdomain = 1;
-				log_query(F_UPSTREAM, name, NULL, "secure no DS");	
+				log_query(F_UPSTREAM, name, NULL, "no DS");	
 			      }
 			    else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
 			      {			     			      
diff --git a/src/rfc3315.c b/src/rfc3315.c
index ddb390b..e593ec9 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -824,6 +824,19 @@
 	  }
 	else
 	  { 
+	    /* Windows 8 always requests an address even if the Managed bit
+	       in RA is 0 and it keeps retrying if it receives a reply
+	       stating that no addresses are available. We solve this 
+	       by not replying at all if we're not configured to give any 
+	       addresses by DHCPv6. RFC 3315 17.2.1. appears to allow this. */
+	    
+	    for (c = state->context; c; c = c->current)
+	      if (!(c->flags & CONTEXT_RA_STATELESS))
+		break;
+	    
+	    if (!c)
+	      return 0;
+	    
 	    /* no address, return error */
 	    o1 = new_opt6(OPTION6_STATUS_CODE);
 	    put_opt6_short(DHCP6NOADDRS);
diff --git a/src/util.c b/src/util.c
index a729f33..d532444 100644
--- a/src/util.c
+++ b/src/util.c
@@ -274,6 +274,7 @@
 #ifdef HAVE_IPV6      
       if (s1->sa.sa_family == AF_INET6 &&
 	  s1->in6.sin6_port == s2->in6.sin6_port &&
+	  s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
 	  IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
 	return 1;
 #endif