[v9_9] try multiple addresses per server name in nsupdate

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]

(cherry picked from commit 842a3e6d0e)
This commit is contained in:
Evan Hunt 2014-02-11 21:30:17 -08:00
parent f58bb15f49
commit 1a58baf293
3 changed files with 96 additions and 90 deletions

View file

@ -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]
3734. [bug] Improve building with libtool. [RT #35314]
3732. [contrib] Fixed a type mismatch causing the ODBC DLZ

View 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:r:R::t:u:"
@ -1077,22 +1098,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",
@ -1382,13 +1387,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);
}
@ -2225,6 +2235,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;
@ -2269,15 +2292,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);
@ -2299,7 +2314,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);
@ -2415,9 +2430,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;
@ -2425,8 +2438,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);
@ -2438,11 +2457,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
@ -2468,10 +2487,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;
}
@ -2488,7 +2504,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");
@ -2580,10 +2596,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);
@ -2712,20 +2728,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;
@ -2813,7 +2820,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;
@ -2847,8 +2854,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;
}
@ -2857,7 +2864,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);
@ -2909,12 +2916,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

View file

@ -129,7 +129,6 @@ bind9_getaddresses(const char *hostname, in_port_t port,
*addrcount = 1;
return (ISC_R_SUCCESS);
}
}
#ifdef USE_GETADDRINFO