summaryrefslogtreecommitdiff
path: root/bin/nsupdate/nsupdate.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/nsupdate/nsupdate.c')
-rw-r--r--bin/nsupdate/nsupdate.c203
1 files changed, 110 insertions, 93 deletions
diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c
index 9923f89156be..b77938d080f7 100644
--- a/bin/nsupdate/nsupdate.c
+++ b/bin/nsupdate/nsupdate.c
@@ -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,20 +948,26 @@ 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:"
+static void
+version(void) {
+ fputs("nsupdate " VERSION "\n", stderr);
+}
+
+#define PARSE_ARGS_FMT "dDML:y:ghlovk:p:r:R::t:u:V"
static void
pre_parse_args(int argc, char **argv) {
@@ -964,7 +990,11 @@ pre_parse_args(int argc, char **argv) {
argv[0], isc_commandline_option);
fprintf(stderr, "usage: nsupdate [-dD] [-L level] [-l]"
"[-g | -o | -y keyname:secret | -k keyfile] "
- "[-v] [filename]\n");
+ "[-v] [-V] [filename]\n");
+ exit(1);
+
+ case 'V':
+ version();
exit(1);
default:
@@ -1077,22 +1107,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 +1396,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));
+
+ 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");
- get_address(server, (in_port_t)port, userserver);
+ memset(servers, 0, ns_total * sizeof(isc_sockaddr_t));
+ get_addresses(server, (in_port_t)port, servers, ns_total);
return (STATUS_MORE);
}
@@ -1985,6 +2004,7 @@ do_next_command(char *cmdline) {
}
if (strcasecmp(word, "help") == 0) {
fprintf(stdout,
+"nsupdate " VERSION ":\n"
"local address [port] (set local resolver)\n"
"server address [port] (set master server for zone)\n"
"send (send the update request)\n"
@@ -2005,6 +2025,10 @@ do_next_command(char *cmdline) {
"[update] del[ete] .... (remove the given record(s) from the zone)\n");
return (STATUS_MORE);
}
+ if (strcasecmp(word, "version") == 0) {
+ fprintf(stdout, "nsupdate " VERSION "\n");
+ return (STATUS_MORE);
+ }
fprintf(stderr, "incorrect section name: %s\n", word);
return (STATUS_SYNTAX);
}
@@ -2084,12 +2108,12 @@ check_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) {
if (tsig.error != 0) {
if (isc_buffer_remaininglength(b) < 1)
check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
- isc__buffer_putstr(b, "(" /*)*/);
+ isc_buffer_putstr(b, "(" /*)*/);
result = dns_tsigrcode_totext(tsig.error, b);
check_result(result, "dns_tsigrcode_totext");
if (isc_buffer_remaininglength(b) < 1)
check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
- isc__buffer_putstr(b, /*(*/ ")");
+ isc_buffer_putstr(b, /*(*/ ")");
}
}
@@ -2226,6 +2250,19 @@ send_update(dns_name_t *zonename, isc_sockaddr_t *master,
}
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;
dns_request_t *request = NULL;
@@ -2269,15 +2306,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 +2328,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 +2444,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 +2452,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 +2471,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 +2501,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 +2518,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 +2610,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 +2742,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 +2834,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 +2868,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 +2878,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 +2930,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