[nsd-users] [PATCH] Source address selection for nsd-notify, +relevant nsdc changes

list-nsd at pwns.ms list-nsd at pwns.ms
Thu Aug 7 03:39:28 UTC 2008


nsd-notify, prior to this patch, lets the OS select the source address;
unfortunately, the OS-selected address in many cases will differ from
the address nsd listens on (in my configuration, I have a server with
three IP addresses - recursive DNS, authorative DNS, host IP address;
NSD just listens on the authorative one).

This patch adds a '-s' options to nsd-notify allowing selection of
source address; multiple -s options may be given, nsd-notify will try to
bind to them in order. It supports setting both the v4 and v6 source
address.

The manpage is updated accordingly.

nsdc is modified to pass nsd-notify an IP address included in the config
file, except for 127.0.0.1 and ::1.

Index: nsdc.sh.in
===================================================================
--- nsdc.sh.in	(revision 2759)
+++ nsdc.sh.in	(working copy)
@@ -221,7 +221,8 @@
 				port="-p "`echo ${ip_spec} | sed -e 's/[^@]*@\([0-9]*\)/\1/'`
 				ipaddr=`echo ${ip_spec} | sed -e 's/\([^@]*\)@[0-9]*/\1/'`
 			fi
-			${sbindir}/nsd-notify ${port} ${secret} -z ${zonename} ${ipaddr}
+			source="-s "`${nsd_checkconf} -o ip-address ${configfile} | egrep -v "127.0.0.1|::1"`
+			${sbindir}/nsd-notify ${source} ${port} ${secret} -z ${zonename} ${ipaddr}
 		fi
 	done
 }
Index: nsd-notify.8
===================================================================
--- nsd-notify.8	(revision 2759)
+++ nsd-notify.8	(working copy)
@@ -11,6 +11,8 @@
 .RB [ \-4 ]
 .RB [ \-6 ]
 .RB [ \-h ]
+.RB [ \-s
+.IR source ]
 .RB [ \-p
 .IR port ]
 .RB [ \-y
@@ -34,6 +36,10 @@
 .B \-h
 Print help information and exit.
 .TP 
+.B \-p\fI source
+Specify the source address used; multiple addresses may be 
+given, they will be tried in order.
+.TP
 .B \-p\fI port
 Specify the port to send to.
 .TP 
Index: nsd-notify.c
===================================================================
--- nsd-notify.c	(revision 2759)
+++ nsd-notify.c	(working copy)
@@ -28,6 +28,8 @@
 
 #include "query.h"
 
+enum { EXIST = 1, BOUND = 2 };
+
 extern char *optarg;
 extern int optind;
 
@@ -47,7 +49,7 @@
 static void 
 usage (void)
 {
-	fprintf(stderr, "usage: nsd-notify [-4] [-6] [-h] [-p port] [-y key:secret] "
+	fprintf(stderr, "usage: nsd-notify [-4] [-6] [-h] [-s source] [-p port] [-y key:secret] "
 		"-z zone servers\n\n");
 	fprintf(stderr, "\tSend NOTIFY to secondary servers to force a zone update.\n");
 	fprintf(stderr, "\tVersion %s. Report bugs to <%s>.\n\n", 
@@ -55,6 +57,7 @@
 	fprintf(stderr, "\t-4\t\tSend using IPv4.\n");
 	fprintf(stderr, "\t-6\t\tSend using IPv6.\n");
 	fprintf(stderr, "\t-h\t\tPrint this help information.\n");
+	fprintf(stderr, "\t-s\t\tSource address; multiple may be given.\n");
 	fprintf(stderr, "\t-p port\t\tPort number of secondary server.\n");
 	fprintf(stderr, "\t-y key:secret\tTSIG keyname and base64 secret blob.\n");
 	fprintf(stderr, "\t-z zone\t\tName of zone to be updated.\n");
@@ -185,14 +188,15 @@
 int 
 main (int argc, char *argv[])
 {
-	int c, udp_s;
+	int c, udp_4, udp_6, v4stat, v6stat; 
 	struct query q;
 	struct query answer;
 	const dname_type *zone = NULL;
 	struct addrinfo hints, *res0, *res;
 	int error;
 	int default_family = DEFAULT_AI_FAMILY;
-	const char *port = UDP_PORT;
+	const char *port = UDP_PORT, *source[16];
+	size_t nsource = 0, i;
 	region_type *region = region_create(xalloc, free);
 #ifdef TSIG
 	tsig_key_type *tsig_key = 0;
@@ -208,7 +212,7 @@
 #endif /* TSIG */
 	
 	/* Parse the command line... */
-	while ((c = getopt(argc, argv, "46hp:y:z:")) != -1) {
+	while ((c = getopt(argc, argv, "46hp:s:y:z:")) != -1) {
 		switch (c) {
 		case '4':
 			default_family = AF_INET;
@@ -221,6 +225,13 @@
 			log_msg(LOG_ERR, "IPv6 support not enabled\n");
 			exit(1);
 #endif /* !INET6 */
+		case 's':
+			if (nsource >= sizeof(source)/sizeof(source[0])) {
+				log_msg(LOG_ERR, "too many source addresses\n");
+				exit(1);
+			}
+			source[nsource++] = optarg;
+			break;
 		case 'p':
 			port = optarg;
 			break;
@@ -291,6 +302,72 @@
 	answer.packet = buffer_create(region, QIOBUFSZ);
 	memset(buffer_begin(answer.packet), 0, buffer_remaining(answer.packet));
 
+	if ((udp_4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
+		log_msg(LOG_ERR, "unable to create v4 socket");
+		exit(1);
+	}
+	#ifdef INET6
+	if ((udp_6 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
+		log_msg(LOG_ERR, "unable to create v6 socket");
+		exit(1);
+	}
+	#endif
+	
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = default_family;
+	hints.ai_socktype = SOCK_DGRAM;
+	hints.ai_protocol = IPPROTO_UDP;
+	for (v4stat = v6stat = i = 0; i < nsource; i++) {
+		error = getaddrinfo(source[i], NULL, &hints, &res0);
+		if (error) {
+			warning("bad source address %s: %s\n", source,
+				gai_strerror(error));
+			continue;
+		}
+		
+		for (res = res0; res; res = res->ai_next) {
+			if (res->ai_family == AF_INET && !(v4stat&BOUND)) {
+				v4stat |= EXIST; 
+				if (bind(udp_4, res->ai_addr,
+					res->ai_addrlen) == -1) {
+					warning("unable to bind to address %s: %s\n", source[i], strerror(errno));
+					continue;
+				} else
+					v4stat |= BOUND;
+			}
+
+			#ifdef INET6
+			if (res->ai_family == AF_INET6 && !(v6stat&BOUND)) {
+				v6stat |= EXIST;
+				if (bind(udp_6, res->ai_addr,
+					res->ai_addrlen) == -1) {
+					warning("unable to bind to address %s: %s\n", source[i], strerror(errno));
+					continue;
+				} else
+					v6stat |= BOUND;
+			}
+			#endif
+		}
+	}
+
+	if (nsource) { 
+		if (!(v4stat&EXIST) && !(v6stat&EXIST)) {
+			log_msg(LOG_ERR, "all source addresses given are invalid");
+			exit(1);
+		}
+		if (v4stat == EXIST) { /* exists but not bound */
+			log_msg(LOG_ERR, "unable to bind to any v4 source addresses.");
+			exit(1);
+		}
+		#ifdef INET6
+		if (v6stat == EXIST) { /* exists but not bound */
+			log_msg(LOG_ERR, "unable to bind to any v6 source addresses.");
+			exit(1);
+		}
+		#endif
+	}
+	
+
 	for (/*empty*/; *argv; argv++) {
 		/* Set up UDP */
 		memset(&hints, 0, sizeof(hints));
@@ -309,14 +386,9 @@
 				continue;
 			}
 
-			udp_s = socket(res->ai_family, res->ai_socktype,
-				       res->ai_protocol);
-			if (udp_s == -1) {
-				continue;
-			}
-
 			memcpy(&q.addr, res->ai_addr, res->ai_addrlen);
-			notify_host(udp_s, &q, &answer, res, zone, *argv);
+			notify_host(res->ai_family == AF_INET ? udp_4 : udp_6, 
+					&q, &answer, res, zone, *argv);
 		}
 		freeaddrinfo(res0);
 	}



More information about the nsd-users mailing list