[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