Blame SOURCES/bind99-automatic-interface-scanning-rh1294506.patch

900526
From 5013230b31da1d94ce5682e5c5c38011da744971 Mon Sep 17 00:00:00 2001
900526
From: Tomas Hozza <thozza@redhat.com>
900526
Date: Wed, 11 May 2016 15:17:55 +0200
900526
Subject: [PATCH] Added support for automatic interface scan when new address
900526
 is assigned to any interface
900526
900526
Signed-off-by: Tomas Hozza <thozza@redhat.com>
900526
---
900526
 bin/named/config.c                |   1 +
900526
 bin/named/control.c               |   3 +
900526
 bin/named/include/named/control.h |   1 +
900526
 bin/named/include/named/server.h  |   8 +++
900526
 bin/named/interfacemgr.c          | 144 ++++++++++++++++++++++++++++++++++++++
900526
 bin/named/named.conf.docbook      |   1 +
900526
 bin/named/server.c                |  31 +++++++-
900526
 bin/named/statschannel.c          |   5 ++
900526
 bin/rndc/rndc.c                   |   1 +
900526
 bin/rndc/rndc.docbook             |  12 ++++
900526
 config.h.in                       |  12 ++++
900526
 configure.in                      |   5 +-
900526
 doc/arm/Bv9ARM-book.xml           |  22 +++++-
900526
 lib/isc/include/isc/socket.h      |  10 ++-
900526
 lib/isc/unix/socket.c             |  59 ++++++++++++++++
900526
 lib/isccfg/namedconf.c            |   1 +
900526
 16 files changed, 310 insertions(+), 6 deletions(-)
900526
900526
diff --git a/bin/named/config.c b/bin/named/config.c
900526
index f6d0263..b43c0fc 100644
900526
--- a/bin/named/config.c
900526
+++ b/bin/named/config.c
900526
@@ -52,6 +52,7 @@
900526
 /*% default configuration */
900526
 static char defaultconf[] = "\
900526
 options {\n\
900526
+	automatic-interface-scan yes;\n\
900526
 #	blackhole {none;};\n"
900526
 #ifndef WIN32
900526
 "	coresize default;\n\
900526
diff --git a/bin/named/control.c b/bin/named/control.c
900526
index 06eadce..86fa691 100644
900526
--- a/bin/named/control.c
900526
+++ b/bin/named/control.c
900526
@@ -185,6 +185,9 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) {
900526
 		   command_compare(command, NS_COMMAND_THAW)) {
900526
 		result = ns_server_freeze(ns_g_server, ISC_FALSE, command,
900526
 					  text);
900526
+	} else if (command_compare(command, NS_COMMAND_SCAN)) {
900526
+		result = ISC_R_SUCCESS;
900526
+		ns_server_scan_interfaces(ns_g_server);
900526
 	} else if (command_compare(command, NS_COMMAND_SYNC)) {
900526
 		result = ns_server_sync(ns_g_server, command, text);
900526
 	} else if (command_compare(command, NS_COMMAND_RECURSING)) {
900526
diff --git a/bin/named/include/named/control.h b/bin/named/include/named/control.h
900526
index d730a83..52ed583 100644
900526
--- a/bin/named/include/named/control.h
900526
+++ b/bin/named/include/named/control.h
900526
@@ -59,6 +59,7 @@
900526
 #define NS_COMMAND_NULL		"null"
900526
 #define NS_COMMAND_NOTIFY	"notify"
900526
 #define NS_COMMAND_VALIDATION	"validation"
900526
+#define NS_COMMAND_SCAN 	"scan"
900526
 #define NS_COMMAND_SIGN 	"sign"
900526
 #define NS_COMMAND_LOADKEYS 	"loadkeys"
900526
 #define NS_COMMAND_ADDZONE	"addzone"
900526
diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h
900526
index ff0bfd3..83622f4 100644
900526
--- a/bin/named/include/named/server.h
900526
+++ b/bin/named/include/named/server.h
900526
@@ -37,6 +37,7 @@
900526
 #define NS_EVENTCLASS		ISC_EVENTCLASS(0x4E43)
900526
 #define NS_EVENT_RELOAD		(NS_EVENTCLASS + 0)
900526
 #define NS_EVENT_CLIENTCONTROL	(NS_EVENTCLASS + 1)
900526
+#define NS_EVENT_IFSCAN		(NS_EVENTCLASS + 2)
900526
 
900526
 /*%
900526
  * Name server state.  Better here than in lots of separate global variables.
900526
@@ -114,6 +115,7 @@ struct ns_server {
900526
 	dns_name_t		*session_keyname;
900526
 	unsigned int		session_keyalg;
900526
 	isc_uint16_t		session_keybits;
900526
+	isc_boolean_t		interface_auto;
900526
 };
900526
 
900526
 #define NS_SERVER_MAGIC			ISC_MAGIC('S','V','E','R')
900526
@@ -201,6 +203,12 @@ ns_server_reloadwanted(ns_server_t *server);
900526
  */
900526
 
900526
 void
900526
+ns_server_scan_interfaces(ns_server_t *server);
900526
+/*%<
900526
+ * Trigger a interface scan.
900526
+ */
900526
+
900526
+void
900526
 ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush);
900526
 /*%<
900526
  * Inform the server that the zones should be flushed to disk on shutdown.
900526
diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c
900526
index 4f6b0f3..a9aa4a4 100644
900526
--- a/bin/named/interfacemgr.c
900526
+++ b/bin/named/interfacemgr.c
900526
@@ -33,6 +33,28 @@
900526
 #include <named/client.h>
900526
 #include <named/log.h>
900526
 #include <named/interfacemgr.h>
900526
+#include <named/server.h>
900526
+
900526
+#ifdef HAVE_NET_ROUTE_H
900526
+#include <net/route.h>
900526
+#if defined(RTM_VERSION) && defined(RTM_NEWADDR) && defined(RTM_DELADDR)
900526
+#define USE_ROUTE_SOCKET 1
900526
+#define ROUTE_SOCKET_PROTOCOL PF_ROUTE
900526
+#define MSGHDR rt_msghdr
900526
+#define MSGTYPE rtm_type
900526
+#endif
900526
+#endif
900526
+
900526
+#if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H)
900526
+#include <linux/netlink.h>
900526
+#include <linux/rtnetlink.h>
900526
+#if defined(RTM_NEWADDR) && defined(RTM_DELADDR)
900526
+#define USE_ROUTE_SOCKET 1
900526
+#define ROUTE_SOCKET_PROTOCOL PF_NETLINK
900526
+#define MSGHDR nlmsghdr
900526
+#define MSGTYPE nlmsg_type
900526
+#endif
900526
+#endif
900526
 
900526
 #define IFMGR_MAGIC			ISC_MAGIC('I', 'F', 'M', 'G')
900526
 #define NS_INTERFACEMGR_VALID(t)	ISC_MAGIC_VALID(t, IFMGR_MAGIC)
900526
@@ -55,6 +77,11 @@ struct ns_interfacemgr {
900526
 	dns_aclenv_t		aclenv;		/*%< Localhost/localnets ACLs */
900526
 	ISC_LIST(ns_interface_t) interfaces;	/*%< List of interfaces. */
900526
 	ISC_LIST(isc_sockaddr_t) listenon;
900526
+#ifdef USE_ROUTE_SOCKET
900526
+	isc_task_t *		task;
900526
+	isc_socket_t *		route;
900526
+	unsigned char		buf[2048];
900526
+#endif
900526
 };
900526
 
900526
 static void
900526
@@ -63,6 +90,71 @@ purge_old_interfaces(ns_interfacemgr_t *mgr);
900526
 static void
900526
 clearlistenon(ns_interfacemgr_t *mgr);
900526
 
900526
+#ifdef USE_ROUTE_SOCKET
900526
+static void
900526
+route_event(isc_task_t *task, isc_event_t *event) {
900526
+	isc_socketevent_t *sevent = NULL;
900526
+	ns_interfacemgr_t *mgr = NULL;
900526
+	isc_region_t r;
900526
+	isc_result_t result;
900526
+	struct MSGHDR *rtm;
900526
+
900526
+	UNUSED(task);
900526
+
900526
+	REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
900526
+	mgr = event->ev_arg;
900526
+	sevent = (isc_socketevent_t *)event;
900526
+
900526
+	if (sevent->result != ISC_R_SUCCESS) {
900526
+		if (sevent->result != ISC_R_CANCELED)
900526
+			isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
900526
+				      "automatic interface scanning "
900526
+				      "terminated: %s",
900526
+				      isc_result_totext(sevent->result));
900526
+		ns_interfacemgr_detach(&mgr);
900526
+		isc_event_free(&event);
900526
+		return;
900526
+	}
900526
+
900526
+	rtm = (struct MSGHDR *)mgr->buf;
900526
+#ifdef RTM_VERSION
900526
+	if (rtm->rtm_version != RTM_VERSION) {
900526
+		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
900526
+			      "automatic interface rescanning disabled: "
900526
+			      "rtm->rtm_version mismatch (%u != %u) "
900526
+			      "recompile required", rtm->rtm_version,
900526
+			      RTM_VERSION);
900526
+		isc_task_detach(&mgr->task);
900526
+		isc_socket_detach(&mgr->route);
900526
+		ns_interfacemgr_detach(&mgr);
900526
+		isc_event_free(&event);
900526
+		return;
900526
+	}
900526
+#endif
900526
+
900526
+	switch (rtm->MSGTYPE) {
900526
+	case RTM_NEWADDR:
900526
+	case RTM_DELADDR:
900526
+		if (ns_g_server->interface_auto)
900526
+			ns_server_scan_interfaces(ns_g_server);
900526
+		break;
900526
+	default:
900526
+		break;
900526
+	}
900526
+
900526
+	/*
900526
+	 * Look for next route event.
900526
+	 */
900526
+	r.base = mgr->buf;
900526
+	r.length = sizeof(mgr->buf);
900526
+	result = isc_socket_recv(mgr->route, &r, 1, mgr->task,
900526
+				 route_event, mgr);
900526
+	if (result != ISC_R_SUCCESS)
900526
+		ns_interfacemgr_detach(&mgr);
900526
+	isc_event_free(&event);
900526
+}
900526
+#endif
900526
+
900526
 isc_result_t
900526
 ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
900526
 		       isc_socketmgr_t *socketmgr,
900526
@@ -112,11 +204,52 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
900526
 	mgr->aclenv.geoip = ns_g_geoip;
900526
 #endif
900526
 
900526
+#ifdef USE_ROUTE_SOCKET
900526
+	mgr->route = NULL;
900526
+	result = isc_socket_create(mgr->socketmgr, ROUTE_SOCKET_PROTOCOL,
900526
+				   isc_sockettype_raw, &mgr->route);
900526
+	switch (result) {
900526
+	case ISC_R_NOPERM:
900526
+	case ISC_R_SUCCESS:
900526
+	case ISC_R_NOTIMPLEMENTED:
900526
+	case ISC_R_FAMILYNOSUPPORT:
900526
+	    break;
900526
+	default:
900526
+		goto cleanup_aclenv;
900526
+	}
900526
+
900526
+	mgr->task = NULL;
900526
+	if (mgr->route != NULL) {
900526
+		result = isc_task_create(taskmgr, 0, &mgr->task);
900526
+		if (result != ISC_R_SUCCESS)
900526
+			goto cleanup_route;
900526
+	}
900526
+	mgr->references = (mgr->route != NULL) ? 2 : 1;
900526
+#else
900526
 	mgr->references = 1;
900526
+#endif
900526
 	mgr->magic = IFMGR_MAGIC;
900526
 	*mgrp = mgr;
900526
+
900526
+#ifdef USE_ROUTE_SOCKET
900526
+	if (mgr->route != NULL) {
900526
+		isc_region_t r = { mgr->buf, sizeof(mgr->buf) };
900526
+
900526
+		result = isc_socket_recv(mgr->route, &r, 1, mgr->task,
900526
+					 route_event, mgr);
900526
+		if (result != ISC_R_SUCCESS)
900526
+			ns_interfacemgr_detach(&mgr);
900526
+	}
900526
+#endif
900526
 	return (ISC_R_SUCCESS);
900526
 
900526
+#ifdef USE_ROUTE_SOCKET
900526
+ cleanup_route:
900526
+	if (mgr->route != NULL)
900526
+		isc_socket_detach(&mgr->route);
900526
+ cleanup_aclenv:
900526
+	dns_aclenv_destroy(&mgr->aclenv);
900526
+#endif
900526
  cleanup_listenon:
900526
 	ns_listenlist_detach(&mgr->listenon4);
900526
 	ns_listenlist_detach(&mgr->listenon6);
900526
@@ -128,6 +261,13 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
900526
 static void
900526
 ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) {
900526
 	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
900526
+
900526
+#ifdef USE_ROUTE_SOCKET
900526
+	if (mgr->route != NULL)
900526
+		isc_socket_detach(&mgr->route);
900526
+	if (mgr->task != NULL)
900526
+		isc_task_detach(&mgr->task);
900526
+#endif
900526
 	dns_aclenv_destroy(&mgr->aclenv);
900526
 	ns_listenlist_detach(&mgr->listenon4);
900526
 	ns_listenlist_detach(&mgr->listenon6);
900526
@@ -179,6 +319,10 @@ ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) {
900526
 	 * consider all interfaces "old".
900526
 	 */
900526
 	mgr->generation++;
900526
+#ifdef USE_ROUTE_SOCKET
900526
+	if (mgr->route != NULL)
900526
+		isc_socket_cancel(mgr->route, mgr->task, ISC_SOCKCANCEL_RECV);
900526
+#endif
900526
 	purge_old_interfaces(mgr);
900526
 }
900526
 
900526
diff --git a/bin/named/named.conf.docbook b/bin/named/named.conf.docbook
900526
index 8c23e52..a8cd31e 100644
900526
--- a/bin/named/named.conf.docbook
900526
+++ b/bin/named/named.conf.docbook
900526
@@ -373,6 +373,7 @@ options {
900526
 	zero-no-soa-ttl <replaceable>boolean</replaceable>;
900526
 	zero-no-soa-ttl-cache <replaceable>boolean</replaceable>;
900526
 	dnssec-secure-to-insecure <replaceable>boolean</replaceable>;
900526
+	automatic-interface-scan <replaceable>boolean</replaceable>;
900526
 	deny-answer-addresses {
900526
 		<replaceable>address_match_list</replaceable>
900526
 	} <optional> except-from { <replaceable>namelist</replaceable> } </optional>;
900526
diff --git a/bin/named/server.c b/bin/named/server.c
900526
index 24b31c3..942bab6 100644
900526
--- a/bin/named/server.c
900526
+++ b/bin/named/server.c
900526
@@ -4485,8 +4485,9 @@ adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
900526
 }
900526
 
900526
 /*
900526
- * This event callback is invoked to do periodic network
900526
- * interface scanning.
900526
+ * This event callback is invoked to do periodic network interface
900526
+ * scanning.  It is also called by ns_server_scan_interfaces(),
900526
+ * invoked by "rndc scan"
900526
  */
900526
 static void
900526
 interface_timer_tick(isc_task_t *task, isc_event_t *event) {
900526
@@ -4494,7 +4495,14 @@ interface_timer_tick(isc_task_t *task, isc_event_t *event) {
900526
 	ns_server_t *server = (ns_server_t *) event->ev_arg;
900526
 	INSIST(task == server->task);
900526
 	UNUSED(task);
900526
+
900526
+	if (event->ev_type == NS_EVENT_IFSCAN)
900526
+		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
900526
+			      NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
900526
+			      "automatic interface rescan");
900526
+
900526
 	isc_event_free(&event);
900526
+
900526
 	/*
900526
 	 * XXX should scan interfaces unlocked and get exclusive access
900526
 	 * only to replace ACLs.
900526
@@ -5419,6 +5427,14 @@ load_configuration(const char *filename, ns_server_t *server,
900526
 	server->interface_interval = interface_interval;
900526
 
900526
 	/*
900526
+	 * Enable automatic interface scans.
900526
+	 */
900526
+	obj = NULL;
900526
+	result = ns_config_get(maps, "automatic-interface-scan", &obj);
900526
+	INSIST(result == ISC_R_SUCCESS);
900526
+	server->interface_auto = cfg_obj_asboolean(obj);
900526
+
900526
+	/*
900526
 	 * Configure the dialup heartbeat timer.
900526
 	 */
900526
 	obj = NULL;
900526
@@ -6637,6 +6653,17 @@ ns_server_reloadwanted(ns_server_t *server) {
900526
 	UNLOCK(&server->reload_event_lock);
900526
 }
900526
 
900526
+void
900526
+ns_server_scan_interfaces(ns_server_t *server) {
900526
+	isc_event_t *event;
900526
+
900526
+	event = isc_event_allocate(ns_g_mctx, server, NS_EVENT_IFSCAN,
900526
+				   interface_timer_tick, server,
900526
+				   sizeof(isc_event_t));
900526
+	if (event != NULL)
900526
+		isc_task_send(server->task, &event);
900526
+}
900526
+
900526
 static char *
900526
 next_token(char **stringp, const char *delim) {
900526
 	char *res;
900526
diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c
900526
index 37e98a8..b985f62 100644
900526
--- a/bin/named/statschannel.c
900526
+++ b/bin/named/statschannel.c
900526
@@ -341,6 +341,7 @@ init_desc(void) {
900526
 	SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open");
900526
 	SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open");
900526
 	SET_SOCKSTATDESC(unixopen, "Unix domain sockets opened", "UnixOpen");
900526
+	SET_SOCKSTATDESC(rawopen, "Raw sockets opened", "RawOpen");
900526
 	SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures",
900526
 			 "UDP4OpenFail");
900526
 	SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures",
900526
@@ -351,6 +352,8 @@ init_desc(void) {
900526
 			 "TCP6OpenFail");
900526
 	SET_SOCKSTATDESC(unixopenfail, "Unix domain socket open failures",
900526
 			 "UnixOpenFail");
900526
+	SET_SOCKSTATDESC(rawopenfail, "Raw socket open failures",
900526
+			 "RawOpenFail");
900526
 	SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close");
900526
 	SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close");
900526
 	SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close");
900526
@@ -358,6 +361,7 @@ init_desc(void) {
900526
 	SET_SOCKSTATDESC(unixclose, "Unix domain sockets closed", "UnixClose");
900526
 	SET_SOCKSTATDESC(fdwatchclose, "FDwatch sockets closed",
900526
 			 "FDWatchClose");
900526
+	SET_SOCKSTATDESC(rawclose, "Raw sockets closed", "RawClose");
900526
 	SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures",
900526
 			 "UDP4BindFail");
900526
 	SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures",
900526
@@ -424,6 +428,7 @@ init_desc(void) {
900526
 			 "UnixRecvErr");
900526
 	SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors",
900526
 			 "FDwatchRecvErr");
900526
+	SET_SOCKSTATDESC(rawrecvfail, "Raw recv errors", "RawRecvErr");
900526
 	INSIST(i == isc_sockstatscounter_max);
900526
 
900526
 	/* Initialize DNSSEC statistics */
900526
diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c
900526
index 9a007e2..be198b1 100644
900526
--- a/bin/rndc/rndc.c
900526
+++ b/bin/rndc/rndc.c
900526
@@ -160,6 +160,7 @@ command is one of the following:\n\
900526
 		Add zone to given view. Requires new-zone-file option.\n\
900526
   delzone [\"file\"] zone [class [view]]\n\
900526
 		Removes zone from given view. Requires new-zone-file option.\n\
900526
+  scan		Scan available network interfaces for changes.\n\
900526
   signing -list zone [class [view]]\n\
900526
 		List the private records showing the state of DNSSEC\n\
900526
 		signing in the given zone.\n\
900526
diff --git a/bin/rndc/rndc.docbook b/bin/rndc/rndc.docbook
900526
index 1789aaa..5b37b7f 100644
900526
--- a/bin/rndc/rndc.docbook
900526
+++ b/bin/rndc/rndc.docbook
900526
@@ -330,6 +330,18 @@
900526
       </varlistentry>
900526
 
900526
       <varlistentry>
900526
+        <term><userinput>scan</userinput></term>
900526
+        <listitem>
900526
+          <para>
900526
+             Scan the list of available network interfaces
900526
+             for changes, without performing a full
900526
+             <command>reconfig</command> or waiting for the
900526
+             <command>interface-interval</command> timer.
900526
+          </para>
900526
+        </listitem>
900526
+      </varlistentry>
900526
+
900526
+      <varlistentry>
900526
         <term><userinput>sync <optional>-clean</optional> <optional><replaceable>zone</replaceable> <optional><replaceable>class</replaceable> <optional><replaceable>view</replaceable></optional></optional></optional></userinput></term>
900526
         <listitem>
900526
           <para>
900526
diff --git a/config.h.in b/config.h.in
900526
index 6ed8381..3515f69 100644
900526
--- a/config.h.in
900526
+++ b/config.h.in
900526
@@ -280,6 +280,12 @@ int sigwait(const unsigned int *set, int *sig);
900526
 /* Define to 1 if you have the <linux/capability.h> header file. */
900526
 #undef HAVE_LINUX_CAPABILITY_H
900526
 
900526
+/* Define to 1 if you have the <linux/netlink.h> header file. */
900526
+#undef HAVE_LINUX_NETLINK_H
900526
+
900526
+/* Define to 1 if you have the <linux/rtnetlink.h> header file. */
900526
+#undef HAVE_LINUX_RTNETLINK_H
900526
+
900526
 /* Define to 1 if you have the <linux/types.h> header file. */
900526
 #undef HAVE_LINUX_TYPES_H
900526
 
900526
@@ -295,6 +301,9 @@ int sigwait(const unsigned int *set, int *sig);
900526
 /* Define to 1 if you have the <net/if6.h> header file. */
900526
 #undef HAVE_NET_IF6_H
900526
 
900526
+/* Define to 1 if you have the <net/route.h> header file. */
900526
+#undef HAVE_NET_ROUTE_H
900526
+
900526
 /* Define if your OpenSSL version supports ECDSA. */
900526
 #undef HAVE_OPENSSL_ECDSA
900526
 
900526
@@ -358,6 +367,9 @@ int sigwait(const unsigned int *set, int *sig);
900526
 /* Define to 1 if you have the <sys/select.h> header file. */
900526
 #undef HAVE_SYS_SELECT_H
900526
 
900526
+/* Define to 1 if you have the <sys/socket.h> header file. */
900526
+#undef HAVE_SYS_SOCKET_H
900526
+
900526
 /* Define to 1 if you have the <sys/sockio.h> header file. */
900526
 #undef HAVE_SYS_SOCKIO_H
900526
 
900526
diff --git a/configure.in b/configure.in
900526
index d72093f..38e626d 100644
900526
--- a/configure.in
900526
+++ b/configure.in
900526
@@ -375,11 +375,14 @@ fi
900526
 
900526
 AC_HEADER_STDC
900526
 
900526
-AC_CHECK_HEADERS(fcntl.h regex.h sys/time.h unistd.h sys/sockio.h sys/select.h sys/param.h sys/sysctl.h net/if6.h,,,
900526
+AC_CHECK_HEADERS(fcntl.h regex.h sys/time.h unistd.h sys/sockio.h sys/select.h sys/param.h sys/sysctl.h net/if6.h sys/socket.h net/route.h linux/netlink.h linux/rtnetlink.h,,,
900526
 [$ac_includes_default
900526
 #ifdef HAVE_SYS_PARAM_H
900526
 # include <sys/param.h>
900526
 #endif
900526
+#ifdef HAVE_SYS_SOCKET_H
900526
+# include <sys/socket.h>
900526
+#endif
900526
 ])
900526
 
900526
 AC_C_CONST
900526
diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml
900526
index 92c7b72..4c47d92 100644
900526
--- a/doc/arm/Bv9ARM-book.xml
900526
+++ b/doc/arm/Bv9ARM-book.xml
900526
@@ -4964,7 +4964,9 @@ badresp:1,adberr:0,findfail:0,valfail:0]
900526
 	<optional> policy given | disabled | passthru | nxdomain | nodata | cname <replaceable>domain</replaceable> </optional>
900526
 	<optional> recursive-only <replaceable>yes_or_no</replaceable> </optional> <optional> max-policy-ttl <replaceable>number</replaceable> </optional> ;
900526
     } <optional> recursive-only <replaceable>yes_or_no</replaceable> </optional> <optional> max-policy-ttl <replaceable>number</replaceable> </optional>
900526
-	<optional> break-dnssec <replaceable>yes_or_no</replaceable> </optional> <optional> min-ns-dots <replaceable>number</replaceable> </optional> ; </optional>
900526
+    <optional> break-dnssec <replaceable>yes_or_no</replaceable> </optional> <optional> min-ns-dots <replaceable>number</replaceable> </optional>
900526
+      <optional> automatic-interface-scan <replaceable>yes_or_no</replaceable> </optional>
900526
+    ; </optional>
900526
 };
900526
 </programlisting>
900526
 
900526
@@ -5726,6 +5728,23 @@ options {
900526
           <variablelist>
900526
 
900526
             <varlistentry>
900526
+	      <term><command>automatic-interface-scan</command></term>
900526
+	      <listitem>
900526
+		<para>
900526
+		  If <userinput>yes</userinput> and supported by the OS,
900526
+		  automatically rescan network interfaces when the interface
900526
+		  addresses are added or removed.  The default is
900526
+		  <userinput>yes</userinput>.
900526
+		</para>
900526
+		<para>
900526
+		  Currently the OS needs to support routing sockets for
900526
+		  <command>automatic-interface-scan</command> to be
900526
+		  supported.
900526
+		</para>
900526
+	      </listitem>
900526
+	    </varlistentry>
900526
+
900526
+	    <varlistentry>
900526
               <term><command>allow-new-zones</command></term>
900526
               <listitem>
900526
                 <para>
900526
@@ -10494,6 +10513,7 @@ zone <replaceable>zone_name</replaceable> <optional><replaceable>class
900526
     <optional> allow-query-on { <replaceable>address_match_list</replaceable> }; </optional>
900526
     <optional> allow-transfer { <replaceable>address_match_list</replaceable> }; </optional>
900526
     <optional> allow-update-forwarding { <replaceable>address_match_list</replaceable> }; </optional>
900526
+    <optional> automatic-interface-scan { <replaceable>yes_or_no</replaceable> }; </optional>
900526
     <optional> dnssec-update-mode ( <replaceable>maintain</replaceable> | <replaceable>no-resign</replaceable> ); </optional>
900526
     <optional> update-check-ksk <replaceable>yes_or_no</replaceable>; </optional>
900526
     <optional> dnssec-dnskey-kskonly <replaceable>yes_or_no</replaceable>; </optional>
900526
diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h
900526
index c5a753a..1cd90bb 100644
900526
--- a/lib/isc/include/isc/socket.h
900526
+++ b/lib/isc/include/isc/socket.h
900526
@@ -150,7 +150,12 @@ enum {
900526
 	isc_sockstatscounter_unixrecvfail = 50,
900526
 	isc_sockstatscounter_fdwatchrecvfail = 51,
900526
 
900526
-	isc_sockstatscounter_max = 52
900526
+	isc_sockstatscounter_rawopen = 52,
900526
+	isc_sockstatscounter_rawopenfail = 53,
900526
+	isc_sockstatscounter_rawclose = 54,
900526
+	isc_sockstatscounter_rawrecvfail = 55,
900526
+
900526
+	isc_sockstatscounter_max = 56
900526
 };
900526
 
900526
 /***
900526
@@ -221,7 +226,8 @@ typedef enum {
900526
 	isc_sockettype_udp = 1,
900526
 	isc_sockettype_tcp = 2,
900526
 	isc_sockettype_unix = 3,
900526
-	isc_sockettype_fdwatch = 4
900526
+	isc_sockettype_fdwatch = 4,
900526
+	isc_sockettype_raw = 5
900526
 } isc_sockettype_t;
900526
 
900526
 /*@{*/
900526
diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c
900526
index 82d0d16..cbc506b 100644
900526
--- a/lib/isc/unix/socket.c
900526
+++ b/lib/isc/unix/socket.c
900526
@@ -28,6 +28,11 @@
900526
 #include <sys/time.h>
900526
 #include <sys/uio.h>
900526
 
900526
+#if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H)
900526
+#include <linux/netlink.h>
900526
+#include <linux/rtnetlink.h>
900526
+#endif
900526
+
900526
 #include <errno.h>
900526
 #include <fcntl.h>
900526
 #include <stddef.h>
900526
@@ -708,6 +713,18 @@ static const isc_statscounter_t fdwatchstatsindex[] = {
900526
 	isc_sockstatscounter_fdwatchsendfail,
900526
 	isc_sockstatscounter_fdwatchrecvfail
900526
 };
900526
+static const isc_statscounter_t rawstatsindex[] = {
900526
+	isc_sockstatscounter_rawopen,
900526
+	isc_sockstatscounter_rawopenfail,
900526
+	isc_sockstatscounter_rawclose,
900526
+	-1,
900526
+	-1,
900526
+	-1,
900526
+	-1,
900526
+	-1,
900526
+	-1,
900526
+	isc_sockstatscounter_rawrecvfail,
900526
+};
900526
 
900526
 #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) || \
900526
     defined(USE_WATCHER_THREAD)
900526
@@ -1744,6 +1761,7 @@ doio_recv(isc__socket_t *sock, isc_socketevent_t *dev) {
900526
 			return (DOIO_EOF);
900526
 		break;
900526
 	case isc_sockettype_udp:
900526
+	case isc_sockettype_raw:
900526
 		break;
900526
 	case isc_sockettype_fdwatch:
900526
 	default:
900526
@@ -2306,6 +2324,44 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock,
900526
 		case isc_sockettype_unix:
900526
 			sock->fd = socket(sock->pf, SOCK_STREAM, 0);
900526
 			break;
900526
+		case isc_sockettype_raw:
900526
+			errno = EPFNOSUPPORT;
900526
+			/*
900526
+			 * PF_ROUTE is a alias for PF_NETLINK on linux.
900526
+			 */
900526
+#if defined(PF_ROUTE)
900526
+			if (sock->fd == -1 && sock->pf == PF_ROUTE) {
900526
+#ifdef NETLINK_ROUTE
900526
+				sock->fd = socket(sock->pf, SOCK_RAW,
900526
+						  NETLINK_ROUTE);
900526
+#else
900526
+				sock->fd = socket(sock->pf, SOCK_RAW, 0);
900526
+#endif
900526
+				if (sock->fd != -1) {
900526
+#ifdef NETLINK_ROUTE
900526
+					struct sockaddr_nl sa;
900526
+					int n;
900526
+
900526
+					/*
900526
+					 * Do an implicit bind.
900526
+					 */
900526
+					memset(&sa, 0, sizeof(sa));
900526
+					sa.nl_family = AF_NETLINK;
900526
+					sa.nl_groups = RTMGRP_IPV4_IFADDR |
900526
+						       RTMGRP_IPV6_IFADDR;
900526
+					n = bind(sock->fd,
900526
+						 (struct sockaddr *) &sa,
900526
+						 sizeof(sa));
900526
+					if (n < 0) {
900526
+						close(sock->fd);
900526
+						sock->fd = -1;
900526
+					}
900526
+#endif
900526
+					sock->bound = 1;
900526
+				}
900526
+			}
900526
+ #endif
900526
+			break;
900526
 		case isc_sockettype_fdwatch:
900526
 			/*
900526
 			 * We should not be called for isc_sockettype_fdwatch
900526
@@ -2602,6 +2658,9 @@ socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type,
900526
 	case isc_sockettype_unix:
900526
 		sock->statsindex = unixstatsindex;
900526
 		break;
900526
+	case isc_sockettype_raw:
900526
+		sock->statsindex = rawstatsindex;
900526
+		break;
900526
 	default:
900526
 		INSIST(0);
900526
 	}
900526
diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
900526
index f5ff8e3..f49ff70 100644
900526
--- a/lib/isccfg/namedconf.c
900526
+++ b/lib/isccfg/namedconf.c
900526
@@ -931,6 +931,7 @@ bindkeys_clauses[] = {
900526
  */
900526
 static cfg_clausedef_t
900526
 options_clauses[] = {
900526
+	{ "automatic-interface-scan", &cfg_type_boolean, 0 },
900526
 	{ "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
900526
 	{ "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
900526
 	{ "bindkeys-file", &cfg_type_qstring, 0 },
900526
-- 
900526
2.5.5
900526