]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] try multiple addresses per server name in nsupdate
authorEvan Hunt <each@isc.org>
Wed, 12 Feb 2014 05:29:10 +0000 (21:29 -0800)
committerEvan Hunt <each@isc.org>
Wed, 12 Feb 2014 05:29:10 +0000 (21:29 -0800)
3736. [bug] nsupdate: When specifying a server by name,
fall back to alternate addresses if the first
address for that name is not reachable. [RT #25784]

CHANGES
bin/nsupdate/nsupdate.c
lib/bind9/getaddresses.c

diff --git a/CHANGES b/CHANGES
index 379013f5674bae5bfc9a0dbefc2c1d7d89185b90..22b92aa2c303752a220044f919f7639520127cc0 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+3736.  [bug]           nsupdate: When specifying a server by name,
+                       fall back to alternate addresses if the first
+                       address for that name is not reachable. [RT #25784]
+                       
 3735.  [cleanup]       Merged the libiscpk11 library into libisc
                        to simplify dependencies. [RT #35205]
 
index 3f5b0faa808971c62b4930cbcda2fb5c9d016b1f..219f6281b63f260617af5b697942ee39299480c5 100644 (file)
@@ -118,6 +118,9 @@ extern int h_errno;
 
 #define DNSDEFAULTPORT 53
 
+/* Number of addresses to request from bind9_getaddresses() */
+#define MAX_SERVERADDRS 4
+
 static isc_uint16_t dnsport = DNSDEFAULTPORT;
 
 #ifndef RESOLV_CONF
@@ -156,13 +159,11 @@ static dns_tsigkey_t *tsigkey = NULL;
 static dst_key_t *sig0key = NULL;
 static lwres_context_t *lwctx = NULL;
 static lwres_conf_t *lwconf;
-static isc_sockaddr_t *servers;
+static isc_sockaddr_t *servers = NULL;
+static isc_boolean_t default_servers = ISC_TRUE;
 static int ns_inuse = 0;
 static int ns_total = 0;
-static isc_sockaddr_t *userserver = NULL;
 static isc_sockaddr_t *localaddr = NULL;
-static isc_sockaddr_t *serveraddr = NULL;
-static isc_sockaddr_t tempaddr;
 static const char *keyfile = NULL;
 static char *keystr = NULL;
 static isc_entropy_t *entropy = NULL;
@@ -713,8 +714,8 @@ static void
 doshutdown(void) {
        isc_task_detach(&global_task);
 
-       if (userserver != NULL)
-               isc_mem_put(mctx, userserver, sizeof(isc_sockaddr_t));
+       if (servers != NULL)
+               isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t));
 
        if (localaddr != NULL)
                isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t));
@@ -743,8 +744,6 @@ doshutdown(void) {
        lwres_conf_clear(lwctx);
        lwres_context_destroy(&lwctx);
 
-       isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t));
-
        ddebug("Destroying request manager");
        dns_requestmgr_detach(&requestmgr);
 
@@ -825,17 +824,37 @@ setup_system(void) {
        (void)lwres_conf_parse(lwctx, RESOLV_CONF);
        lwconf = lwres_conf_get(lwctx);
 
-       ns_total = lwconf->nsnext;
-       if (ns_total <= 0) {
-               /* No name servers in resolv.conf; default to loopback. */
-               struct in_addr localhost;
-               ns_total = 1;
+       ns_inuse = 0;
+       if (local_only || lwconf->nsnext <= 0) {
+               struct in_addr in;
+               struct in6_addr in6;
+
+               if (local_only && keyfile == NULL)
+                       keyfile = SESSION_KEYFILE;
+
+               default_servers = ISC_FALSE;
+
+               if (servers != NULL)
+                       isc_mem_put(mctx, servers,
+                                   ns_total * sizeof(isc_sockaddr_t));
+
+               ns_total = (have_ipv4 ? 1 : 0) + (have_ipv6 ? 1 : 0);
                servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
                if (servers == NULL)
                        fatal("out of memory");
-               localhost.s_addr = htonl(INADDR_LOOPBACK);
-               isc_sockaddr_fromin(&servers[0], &localhost, dnsport);
+
+               if (have_ipv4) {
+                       in.s_addr = htonl(INADDR_LOOPBACK);
+                       isc_sockaddr_fromin(&servers[0], &in, dnsport);
+               }
+               if (have_ipv6) {
+                       memset(&in6, 0, sizeof(in6));
+                       in6.s6_addr[15] = 1;
+                       isc_sockaddr_fromin6(&servers[(have_ipv4 ? 1 : 0)],
+                                            &in6, dnsport);
+               }
        } else {
+               ns_total = lwconf->nsnext;
                servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
                if (servers == NULL)
                        fatal("out of memory");
@@ -845,13 +864,14 @@ setup_system(void) {
                                struct in_addr in4;
                                memmove(&in4,
                                        lwconf->nameservers[i].address, 4);
-                               isc_sockaddr_fromin(&servers[i], &in4, dnsport);
+                               isc_sockaddr_fromin(&servers[i],
+                                                   &in4, dnsport);
                        } else {
                                struct in6_addr in6;
                                memmove(&in6,
                                        lwconf->nameservers[i].address, 16);
-                               isc_sockaddr_fromin6(&servers[i], &in6,
-                                                    dnsport);
+                               isc_sockaddr_fromin6(&servers[i],
+                                                    &in6, dnsport);
                        }
                }
        }
@@ -928,17 +948,18 @@ setup_system(void) {
 }
 
 static void
-get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
+get_addresses(char *host, in_port_t port,
+             isc_sockaddr_t *sockaddr, int naddrs)
+{
        int count;
        isc_result_t result;
 
        isc_app_block();
-       result = bind9_getaddresses(host, port, sockaddr, 1, &count);
+       result = bind9_getaddresses(host, port, sockaddr, naddrs, &count);
        isc_app_unblock();
        if (result != ISC_R_SUCCESS)
                fatal("couldn't get address for '%s': %s",
                      host, isc_result_totext(result));
-       INSIST(count == 1);
 }
 
 #define PARSE_ARGS_FMT "dDML:y:ghlovk:p:Pr:R::t:Tu:"
@@ -1104,22 +1125,6 @@ parse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) {
                exit(1);
        }
 
-       if (local_only) {
-               struct in_addr localhost;
-
-               if (keyfile == NULL)
-                       keyfile = SESSION_KEYFILE;
-
-               if (userserver == NULL) {
-                       userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
-                       if (userserver == NULL)
-                               fatal("out of memory");
-               }
-
-               localhost.s_addr = htonl(INADDR_LOOPBACK);
-               isc_sockaddr_fromin(userserver, &localhost, dnsport);
-       }
-
 #ifdef GSSAPI
        if (usegsstsig && (keyfile != NULL || keystr != NULL)) {
                fprintf(stderr, "%s: cannot specify -g with -k or -y\n",
@@ -1409,13 +1414,18 @@ evaluate_server(char *cmdline) {
                }
        }
 
-       if (userserver == NULL) {
-               userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
-               if (userserver == NULL)
-                       fatal("out of memory");
-       }
+       if (servers != NULL)
+               isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t));
 
-       get_address(server, (in_port_t)port, userserver);
+       default_servers = ISC_FALSE;
+
+       ns_total = MAX_SERVERADDRS;
+       servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
+       if (servers == NULL)
+               fatal("out of memory");
+
+       memset(servers, 0, ns_total * sizeof(isc_sockaddr_t));
+       get_addresses(server, (in_port_t)port, servers, ns_total);
 
        return (STATUS_MORE);
 }
@@ -2252,6 +2262,19 @@ send_update(dns_name_t *zonename, isc_sockaddr_t *master,
        requests++;
 }
 
+static void
+next_server(const char *caller, isc_sockaddr_t *addr, isc_result_t eresult) {
+       char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+
+       isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
+       fprintf(stderr, "; Communication with %s failed: %s\n",
+               addrbuf, isc_result_totext(eresult));
+       if (++ns_inuse >= ns_total)
+               fatal("could not reach any name server");
+       else
+               ddebug("%s: trying next server", caller);
+}
+
 static void
 recvsoa(isc_task_t *task, isc_event_t *event) {
        dns_requestevent_t *reqev = NULL;
@@ -2296,15 +2319,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
        }
 
        if (eresult != ISC_R_SUCCESS) {
-               char addrbuf[ISC_SOCKADDR_FORMATSIZE];
-
-               isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
-               fprintf(stderr, "; Communication with %s failed: %s\n",
-                       addrbuf, isc_result_totext(eresult));
-               if (userserver != NULL)
-                       fatal("could not talk to specified name server");
-               else if (++ns_inuse >= lwconf->nsnext)
-                       fatal("could not talk to any default name server");
+               next_server("recvsoa", addr, eresult);
                ddebug("Destroying request [%p]", request);
                dns_request_destroy(&request);
                dns_message_renderreset(soaquery);
@@ -2326,7 +2341,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
        check_result(result, "dns_message_create");
        result = dns_request_getresponse(request, rcvmsg,
                                         DNS_MESSAGEPARSE_PRESERVEORDER);
-       if (result == DNS_R_TSIGERRORSET && userserver != NULL) {
+       if (result == DNS_R_TSIGERRORSET && servers != NULL) {
                dns_message_destroy(&rcvmsg);
                ddebug("Destroying request [%p]", request);
                dns_request_destroy(&request);
@@ -2442,9 +2457,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
                fprintf(stderr, "The master is: %s\n", namestr);
        }
 
-       if (userserver != NULL)
-               serveraddr = userserver;
-       else {
+       if (servers == NULL) {
                char serverstr[DNS_NAME_MAXTEXT+1];
                isc_buffer_t buf;
 
@@ -2452,8 +2465,14 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
                result = dns_name_totext(&master, ISC_TRUE, &buf);
                check_result(result, "dns_name_totext");
                serverstr[isc_buffer_usedlength(&buf)] = 0;
-               get_address(serverstr, dnsport, &tempaddr);
-               serveraddr = &tempaddr;
+
+               ns_total = MAX_SERVERADDRS;
+               servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
+               if (servers == NULL)
+                       fatal("out of memory");
+
+               memset(servers, 0, ns_total * sizeof(isc_sockaddr_t));
+               get_addresses(serverstr, dnsport, servers, ns_total);
        }
        dns_rdata_freestruct(&soa);
 
@@ -2465,11 +2484,11 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
                dns_name_dup(&master, mctx, &restart_master);
                start_gssrequest(&master);
        } else {
-               send_update(zonename, serveraddr, localaddr);
+               send_update(zonename, &servers[ns_inuse], localaddr);
                setzoneclass(dns_rdataclass_none);
        }
 #else
-       send_update(zonename, serveraddr, localaddr);
+       send_update(zonename, &servers[ns_inuse], localaddr);
        setzoneclass(dns_rdataclass_none);
 #endif
 
@@ -2495,10 +2514,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
        dns_request_destroy(&request);
        dns_message_renderreset(soaquery);
        dns_message_settsigkey(soaquery, NULL);
-       if (userserver != NULL)
-               sendrequest(localaddr, userserver, soaquery, &request);
-       else
-               sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
+       sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
        goto out;
 }
 
@@ -2515,7 +2531,7 @@ sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
        reqinfo->msg = msg;
        reqinfo->addr = destaddr;
        result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0,
-                                       (userserver != NULL) ? tsigkey : NULL,
+                                       default_servers ? NULL : tsigkey,
                                        FIND_TIMEOUT * 20, FIND_TIMEOUT, 3,
                                        global_task, recvsoa, reqinfo, request);
        check_result(result, "dns_request_createvia");
@@ -2607,10 +2623,10 @@ start_gssrequest(dns_name_t *master) {
                if (kserver == NULL)
                        fatal("out of memory");
        }
-       if (userserver == NULL)
-               get_address(namestr, dnsport, kserver);
+       if (servers == NULL)
+               get_addresses(namestr, dnsport, kserver, 1);
        else
-               (void)memmove(kserver, userserver, sizeof(isc_sockaddr_t));
+               memmove(kserver, &servers[ns_inuse], sizeof(isc_sockaddr_t));
 
        dns_fixedname_init(&fname);
        servname = dns_fixedname_name(&fname);
@@ -2739,20 +2755,11 @@ recvgss(isc_task_t *task, isc_event_t *event) {
        }
 
        if (eresult != ISC_R_SUCCESS) {
-               char addrbuf[ISC_SOCKADDR_FORMATSIZE];
-
-               isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
-               fprintf(stderr, "; Communication with %s failed: %s\n",
-                       addrbuf, isc_result_totext(eresult));
-               if (userserver != NULL)
-                       fatal("could not talk to specified name server");
-               else if (++ns_inuse >= lwconf->nsnext)
-                       fatal("could not talk to any default name server");
+               next_server("recvgss", addr, eresult);
                ddebug("Destroying request [%p]", request);
                dns_request_destroy(&request);
                dns_message_renderreset(tsigquery);
-               sendrequest(localaddr, &servers[ns_inuse], tsigquery,
-                           &request);
+               sendrequest(localaddr, &servers[ns_inuse], tsigquery, &request);
                isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
                isc_event_free(&event);
                return;
@@ -2840,7 +2847,7 @@ recvgss(isc_task_t *task, isc_event_t *event) {
                check_result(result, "dns_message_checksig");
 #endif /* 0 */
 
-               send_update(&tmpzonename, serveraddr, localaddr);
+               send_update(&tmpzonename, &servers[ns_inuse], localaddr);
                setzoneclass(dns_rdataclass_none);
                break;
 
@@ -2874,8 +2881,8 @@ start_update(void) {
        if (answer != NULL)
                dns_message_destroy(&answer);
 
-       if (userzone != NULL && userserver != NULL && ! usegsstsig) {
-               send_update(userzone, userserver, localaddr);
+       if (userzone != NULL && ! usegsstsig) {
+               send_update(userzone, &servers[ns_inuse], localaddr);
                setzoneclass(dns_rdataclass_none);
                return;
        }
@@ -2884,7 +2891,7 @@ start_update(void) {
                                    &soaquery);
        check_result(result, "dns_message_create");
 
-       if (userserver == NULL)
+       if (default_servers)
                soaquery->flags |= DNS_MESSAGEFLAG_RD;
 
        result = dns_message_gettempname(soaquery, &name);
@@ -2936,12 +2943,8 @@ start_update(void) {
        ISC_LIST_APPEND(name->list, rdataset, link);
        dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
 
-       if (userserver != NULL)
-               sendrequest(localaddr, userserver, soaquery, &request);
-       else {
-               ns_inuse = 0;
-               sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
-       }
+       ns_inuse = 0;
+       sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
 }
 
 static void
index a75e14ef650ecf3190b5251027135eefafa92f70..5a1a3145c7cd117306057fb886c61a779b3a1bb2 100644 (file)
@@ -129,7 +129,6 @@ bind9_getaddresses(const char *hostname, in_port_t port,
 
                        *addrcount = 1;
                        return (ISC_R_SUCCESS);
-                       
                }
        }
 #ifdef USE_GETADDRINFO