summaryrefslogtreecommitdiff
path: root/usr.sbin/bind/bin/nsupdate/nsupdate.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bind/bin/nsupdate/nsupdate.c')
-rw-r--r--usr.sbin/bind/bin/nsupdate/nsupdate.c444
1 files changed, 268 insertions, 176 deletions
diff --git a/usr.sbin/bind/bin/nsupdate/nsupdate.c b/usr.sbin/bind/bin/nsupdate/nsupdate.c
index 055ddd82eac..f78eb3bb320 100644
--- a/usr.sbin/bind/bin/nsupdate/nsupdate.c
+++ b/usr.sbin/bind/bin/nsupdate/nsupdate.c
@@ -1,28 +1,27 @@
/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2000-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
*/
-/* $ISC: nsupdate.c,v 1.103.2.15 2003/07/25 03:31:42 marka Exp $ */
+/* $ISC: nsupdate.c,v 1.103.2.15.2.16 2004/06/17 01:00:38 sra Exp $ */
#include <config.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
-#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
@@ -35,6 +34,7 @@
#include <isc/hash.h>
#include <isc/lex.h>
#include <isc/mem.h>
+#include <isc/parseint.h>
#include <isc/region.h>
#include <isc/sockaddr.h>
#include <isc/socket.h>
@@ -47,11 +47,13 @@
#include <dns/callbacks.h>
#include <dns/dispatch.h>
+#include <dns/dnssec.h>
#include <dns/events.h>
#include <dns/fixedname.h>
#include <dns/masterdump.h>
#include <dns/message.h>
#include <dns/name.h>
+#include <dns/rcode.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdatalist.h>
@@ -67,6 +69,8 @@
#include <lwres/lwres.h>
#include <lwres/net.h>
+#include <bind9/getaddresses.h>
+
#ifdef HAVE_ADDRINFO
#ifdef HAVE_GETADDRINFO
#ifdef HAVE_GAISTRERROR
@@ -83,8 +87,6 @@ extern int h_errno;
#define MAXCMD (4 * 1024)
#define MAXWIRE (64 * 1024)
-#define NAMEBUF 512
-#define WORDLEN 512
#define PACKETSIZE ((64 * 1024) - 1)
#define INITTEXT (2 * 1024)
#define MAXTEXT (128 * 1024)
@@ -114,11 +116,10 @@ static isc_timermgr_t *timermgr = NULL;
static dns_dispatch_t *dispatchv4 = NULL;
static dns_dispatch_t *dispatchv6 = NULL;
static dns_message_t *updatemsg = NULL;
-static dns_fixedname_t resolvdomain; /* from resolv.conf's domain line */
-static dns_name_t *origin; /* Points to one of above, or dns_rootname */
static dns_fixedname_t fuserzone;
static dns_name_t *userzone = NULL;
-static dns_tsigkey_t *key = NULL;
+static dns_tsigkey_t *tsigkey = NULL;
+static dst_key_t *sig0key;
static lwres_context_t *lwctx = NULL;
static lwres_conf_t *lwconf;
static isc_sockaddr_t *servers;
@@ -134,6 +135,12 @@ static isc_boolean_t interactive = ISC_TRUE;
static isc_boolean_t seenerror = ISC_FALSE;
static const dns_master_style_t *style;
static int requests = 0;
+static unsigned int timeout = 300;
+static unsigned int udp_timeout = 3;
+static unsigned int udp_retries = 3;
+static dns_rdataclass_t defaultclass = dns_rdataclass_in;
+static dns_rdataclass_t zoneclass = dns_rdataclass_none;
+static dns_message_t *answer = NULL;
typedef struct nsu_requestinfo {
dns_message_t *msg;
@@ -157,6 +164,23 @@ ddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
#define STATUS_QUIT (isc_uint16_t)2
#define STATUS_SYNTAX (isc_uint16_t)3
+static dns_rdataclass_t
+getzoneclass(void) {
+ if (zoneclass == dns_rdataclass_none)
+ zoneclass = defaultclass;
+ return (zoneclass);
+}
+
+static isc_boolean_t
+setzoneclass(dns_rdataclass_t rdclass) {
+ if (zoneclass == dns_rdataclass_none ||
+ rdclass == dns_rdataclass_none)
+ zoneclass = rdclass;
+ if (zoneclass != rdclass)
+ return (ISC_FALSE);
+ return (ISC_TRUE);
+}
+
static void
fatal(const char *format, ...) {
va_list args;
@@ -242,20 +266,6 @@ nsu_strsep(char **stringp, const char *delim) {
return (string);
}
-static unsigned int
-count_dots(char *s, isc_boolean_t *last_was_dot) {
- int i = 0;
- *last_was_dot = ISC_FALSE;
- while (*s != 0) {
- if (*s++ == '.') {
- i++;
- *last_was_dot = ISC_TRUE;
- } else
- *last_was_dot = ISC_FALSE;
- }
- return (i);
-}
-
static void
reset_system(void) {
isc_result_t result;
@@ -320,7 +330,7 @@ setup_keystr(void) {
debug("keycreate");
result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name,
secret, secretlen, ISC_TRUE, NULL,
- 0, 0, mctx, NULL, &key);
+ 0, 0, mctx, NULL, &tsigkey);
if (result != ISC_R_SUCCESS)
fprintf(stderr, "could not create key from %s: %s\n",
keystr, dns_result_totext(result));
@@ -336,23 +346,27 @@ setup_keyfile(void) {
debug("Creating key...");
- result = dst_key_fromnamedfile(keyfile, DST_TYPE_PRIVATE, mctx,
+ result = dst_key_fromnamedfile(keyfile,
+ DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
&dstkey);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "could not read key from %s: %s\n",
keyfile, isc_result_totext(result));
return;
}
- result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
- dns_tsig_hmacmd5_name,
- dstkey, ISC_FALSE, NULL,
- 0, 0, mctx, NULL, &key);
- if (result != ISC_R_SUCCESS) {
- fprintf(stderr, "could not create key from %s: %s\n",
- keyfile, isc_result_totext(result));
- dst_key_free(&dstkey);
- return;
- }
+ if (dst_key_alg(dstkey) == DST_ALG_HMACMD5) {
+ result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
+ dns_tsig_hmacmd5_name,
+ dstkey, ISC_FALSE, NULL,
+ 0, 0, mctx, NULL, &tsigkey);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "could not create key from %s: %s\n",
+ keyfile, isc_result_totext(result));
+ dst_key_free(&dstkey);
+ return;
+ }
+ } else
+ sig0key = dstkey;
}
static void
@@ -365,9 +379,14 @@ doshutdown(void) {
if (localaddr != NULL)
isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t));
- if (key != NULL) {
- ddebug("Freeing key");
- dns_tsigkey_detach(&key);
+ if (tsigkey != NULL) {
+ ddebug("Freeing TSIG key");
+ dns_tsigkey_detach(&tsigkey);
+ }
+
+ if (sig0key != NULL) {
+ ddebug("Freeing SIG(0) key");
+ dst_key_free(&sig0key);
}
if (updatemsg != NULL)
@@ -430,7 +449,6 @@ static void
setup_system(void) {
isc_result_t result;
isc_sockaddr_t bind_any, bind_any6;
- isc_buffer_t buf;
lwres_result_t lwresult;
unsigned int attrs, attrmask;
int i;
@@ -549,20 +567,6 @@ setup_system(void) {
dispatchv4, dispatchv6, &requestmgr);
check_result(result, "dns_requestmgr_create");
- if (lwconf->domainname != NULL) {
- dns_fixedname_init(&resolvdomain);
- isc_buffer_init(&buf, lwconf->domainname,
- strlen(lwconf->domainname));
- isc_buffer_add(&buf, strlen(lwconf->domainname));
- result = dns_name_fromtext(dns_fixedname_name(&resolvdomain),
- &buf, dns_rootname, ISC_FALSE,
- NULL);
- check_result(result, "dns_name_fromtext");
- origin = dns_fixedname_name(&resolvdomain);
- }
- else
- origin = dns_rootname;
-
if (keystr != NULL)
setup_keystr();
else if (keyfile != NULL)
@@ -571,74 +575,16 @@ setup_system(void) {
static void
get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
- struct in_addr in4;
- struct in6_addr in6;
-#ifdef USE_GETADDRINFO
- struct addrinfo *res = NULL, hints;
- int result;
-#else
- struct hostent *he;
-#endif
-
- ddebug("get_address()");
+ int count;
+ isc_result_t result;
- /*
- * Assume we have v4 if we don't have v6, since setup_libs
- * fatal()'s out if we don't have either.
- */
- if (have_ipv6 && inet_pton(AF_INET6, host, &in6) == 1)
- isc_sockaddr_fromin6(sockaddr, &in6, port);
- else if (inet_pton(AF_INET, host, &in4) == 1)
- isc_sockaddr_fromin(sockaddr, &in4, port);
- else {
-#ifdef USE_GETADDRINFO
- memset(&hints, 0, sizeof(hints));
- if (!have_ipv6)
- hints.ai_family = PF_INET;
- else if (!have_ipv4)
- hints.ai_family = PF_INET6;
- else {
- hints.ai_family = PF_UNSPEC;
-#ifdef AI_ADDRCONFIG
- hints.ai_flags = AI_ADDRCONFIG;
-#endif
- }
- debug ("before getaddrinfo()");
- isc_app_block();
-#ifdef AI_ADDRCONFIG
- again:
-#endif
- result = getaddrinfo(host, NULL, &hints, &res);
-#ifdef AI_ADDRCONFIG
- if (result == EAI_BADFLAGS &&
- (hints.ai_flags & AI_ADDRCONFIG) != 0) {
- hints.ai_flags &= ~AI_ADDRCONFIG;
- goto again;
- }
-#endif
- isc_app_unblock();
- if (result != 0) {
- fatal("couldn't find server '%s': %s",
- host, gai_strerror(result));
- }
- memcpy(&sockaddr->type.sa,res->ai_addr, res->ai_addrlen);
- sockaddr->length = res->ai_addrlen;
- isc_sockaddr_setport(sockaddr, port);
- freeaddrinfo(res);
-#else
- debug ("before gethostbyname()");
- isc_app_block();
- he = gethostbyname(host);
- isc_app_unblock();
- if (he == NULL)
- fatal("couldn't find server '%s' (h_errno=%d)",
- host, h_errno);
- INSIST(he->h_addrtype == AF_INET);
- isc_sockaddr_fromin(sockaddr,
- (struct in_addr *)(he->h_addr_list[0]),
- port);
-#endif
- }
+ isc_app_block();
+ result = bind9_getaddresses(host, port, sockaddr, 1, &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);
}
static void
@@ -647,7 +593,8 @@ parse_args(int argc, char **argv) {
isc_result_t result;
debug("parse_args");
- while ((ch = isc_commandline_parse(argc, argv, "dDMy:vk:")) != -1) {
+ while ((ch = isc_commandline_parse(argc, argv, "dDMy:vk:r:t:u:")) != -1)
+ {
switch (ch) {
case 'd':
debugging = ISC_TRUE;
@@ -672,6 +619,34 @@ parse_args(int argc, char **argv) {
case 'k':
keyfile = isc_commandline_argument;
break;
+ case 't':
+ result = isc_parse_uint32(&timeout,
+ isc_commandline_argument, 10);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "bad timeout '%s'\n", isc_commandline_argument);
+ exit(1);
+ }
+ if (timeout == 0)
+ timeout = ULONG_MAX;
+ break;
+ case 'u':
+ result = isc_parse_uint32(&udp_timeout,
+ isc_commandline_argument, 10);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "bad udp timeout '%s'\n", isc_commandline_argument);
+ exit(1);
+ }
+ if (udp_timeout == 0)
+ udp_timeout = ULONG_MAX;
+ break;
+ case 'r':
+ result = isc_parse_uint32(&udp_retries,
+ isc_commandline_argument, 10);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "bad udp retries '%s'\n", isc_commandline_argument);
+ exit(1);
+ }
+ break;
default:
fprintf(stderr, "%s: invalid argument -%c\n",
argv[0], ch);
@@ -710,9 +685,6 @@ parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) {
char *word;
isc_buffer_t *namebuf = NULL;
isc_buffer_t source;
- unsigned int dots;
- isc_boolean_t last;
- dns_name_t *rn;
word = nsu_strsep(cmdlinep, " \t\r\n");
if (*word == 0) {
@@ -722,21 +694,14 @@ parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) {
result = dns_message_gettempname(msg, namep);
check_result(result, "dns_message_gettempname");
- result = isc_buffer_allocate(mctx, &namebuf, NAMEBUF);
+ result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
check_result(result, "isc_buffer_allocate");
dns_name_init(*namep, NULL);
dns_name_setbuffer(*namep, namebuf);
dns_message_takebuffer(msg, &namebuf);
isc_buffer_init(&source, word, strlen(word));
isc_buffer_add(&source, strlen(word));
- dots = count_dots(word, &last);
- if (dots > lwconf->ndots || last)
- rn = dns_rootname;
- else if (userzone != NULL)
- rn = userzone;
- else
- rn = origin;
- result = dns_name_fromtext(*namep, &source, rn,
+ result = dns_name_fromtext(*namep, &source, dns_rootname,
ISC_FALSE, NULL);
check_result(result, "dns_name_fromtext");
isc_buffer_invalidate(&source);
@@ -754,17 +719,12 @@ parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass,
isc_lex_t *lex = NULL;
dns_rdatacallbacks_t callbacks;
isc_result_t result;
- dns_name_t *rn;
while (*cmdline != 0 && isspace((unsigned char)*cmdline))
cmdline++;
if (*cmdline != 0) {
dns_rdatacallbacks_init(&callbacks);
- if (userzone != NULL)
- rn = userzone;
- else
- rn = origin;
result = isc_lex_create(mctx, strlen(cmdline), &lex);
check_result(result, "isc_lex_create");
isc_buffer_init(&source, cmdline, strlen(cmdline));
@@ -774,7 +734,7 @@ parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass,
result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
check_result(result, "isc_buffer_allocate");
result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex,
- rn, ISC_FALSE, mctx, buf,
+ dns_rootname, 0, mctx, buf,
&callbacks);
isc_lex_destroy(&lex);
if (result == ISC_R_SUCCESS) {
@@ -834,6 +794,10 @@ make_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) {
region.length = strlen(word);
result = dns_rdataclass_fromtext(&rdataclass, &region);
if (result == ISC_R_SUCCESS) {
+ if (!setzoneclass(rdataclass)) {
+ fprintf(stderr, "class mismatch: %s\n", word);
+ goto failure;
+ }
/*
* Now read the type.
*/
@@ -850,7 +814,7 @@ make_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) {
goto failure;
}
} else {
- rdataclass = dns_rdataclass_in;
+ rdataclass = getzoneclass();
result = dns_rdatatype_fromtext(&rdatatype, &region);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "invalid type: %s\n", word);
@@ -1072,11 +1036,11 @@ evaluate_key(char *cmdline) {
}
secretlen = isc_buffer_usedlength(&secretbuf);
- if (key != NULL)
- dns_tsigkey_detach(&key);
+ if (tsigkey != NULL)
+ dns_tsigkey_detach(&tsigkey);
result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name,
- secret, secretlen, ISC_TRUE, NULL, 0, 0,
- mctx, NULL, &key);
+ secret, secretlen, ISC_TRUE, NULL, 0, 0,
+ mctx, NULL, &tsigkey);
isc_mem_free(mctx, secret);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "could not create key from %s %s: %s\n",
@@ -1114,10 +1078,43 @@ evaluate_zone(char *cmdline) {
}
static isc_uint16_t
+evaluate_class(char *cmdline) {
+ char *word;
+ isc_textregion_t r;
+ isc_result_t result;
+ dns_rdataclass_t rdclass;
+
+ word = nsu_strsep(&cmdline, " \t\r\n");
+ if (*word == 0) {
+ fprintf(stderr, "could not read class name\n");
+ return (STATUS_SYNTAX);
+ }
+
+ r.base = word;
+ r.length = strlen(word);
+ result = dns_rdataclass_fromtext(&rdclass, &r);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "could not parse class name: %s\n", word);
+ return (STATUS_SYNTAX);
+ }
+ switch (rdclass) {
+ case dns_rdataclass_none:
+ case dns_rdataclass_any:
+ case dns_rdataclass_reserved0:
+ fprintf(stderr, "bad default class: %s\n", word);
+ return (STATUS_SYNTAX);
+ default:
+ defaultclass = rdclass;
+ }
+
+ return (STATUS_MORE);
+}
+
+static isc_uint16_t
update_addordelete(char *cmdline, isc_boolean_t isdelete) {
isc_result_t result;
dns_name_t *name = NULL;
- unsigned long ttl;
+ isc_uint32_t ttl;
char *word;
dns_rdataclass_t rdataclass;
dns_rdatatype_t rdatatype;
@@ -1125,7 +1122,6 @@ update_addordelete(char *cmdline, isc_boolean_t isdelete) {
dns_rdatalist_t *rdatalist = NULL;
dns_rdataset_t *rdataset = NULL;
isc_textregion_t region;
- char *endp;
isc_uint16_t retval;
ddebug("update_addordelete()");
@@ -1163,13 +1159,14 @@ update_addordelete(char *cmdline, isc_boolean_t isdelete) {
goto doneparsing;
}
}
- ttl = strtoul(word, &endp, 10);
- if (!isdigit((unsigned char)*word) || *endp != '\0') {
+ result = isc_parse_uint32(&ttl, word, 10);
+ if (result != ISC_R_SUCCESS) {
if (isdelete) {
ttl = 0;
goto parseclass;
} else {
- fprintf(stderr, "ttl '%s' is not legal\n", word);
+ fprintf(stderr, "ttl '%s': %s\n", word,
+ isc_result_totext(result));
goto failure;
}
}
@@ -1202,6 +1199,10 @@ update_addordelete(char *cmdline, isc_boolean_t isdelete) {
region.length = strlen(word);
result = dns_rdataclass_fromtext(&rdataclass, &region);
if (result == ISC_R_SUCCESS) {
+ if (!setzoneclass(rdataclass)) {
+ fprintf(stderr, "class mismatch: %s\n", word);
+ goto failure;
+ }
/*
* Now read the type.
*/
@@ -1226,7 +1227,7 @@ update_addordelete(char *cmdline, isc_boolean_t isdelete) {
goto failure;
}
} else {
- rdataclass = dns_rdataclass_in;
+ rdataclass = getzoneclass();
result = dns_rdatatype_fromtext(&rdatatype, &region);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "'%s' is not a valid class or type: "
@@ -1369,12 +1370,19 @@ get_next_command(void) {
return (evaluate_local(cmdline));
if (strcasecmp(word, "zone") == 0)
return (evaluate_zone(cmdline));
+ if (strcasecmp(word, "class") == 0)
+ return (evaluate_class(cmdline));
if (strcasecmp(word, "send") == 0)
return (STATUS_SEND);
if (strcasecmp(word, "show") == 0) {
show_message(updatemsg);
return (STATUS_MORE);
}
+ if (strcasecmp(word, "answer") == 0) {
+ if (answer != NULL)
+ show_message(answer);
+ return (STATUS_MORE);
+ }
if (strcasecmp(word, "key") == 0)
return (evaluate_key(cmdline));
fprintf(stderr, "incorrect section name: %s\n", word);
@@ -1402,10 +1410,32 @@ done_update(void) {
}
static void
+check_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) {
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_any_tsig_t tsig;
+
+ result = dns_rdataset_first(rdataset);
+ check_result(result, "dns_rdataset_first");
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &tsig, NULL);
+ check_result(result, "dns_rdata_tostruct");
+ if (tsig.error != 0) {
+ if (isc_buffer_remaininglength(b) < 1)
+ check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
+ 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, /*(*/ ")");
+ }
+}
+
+static void
update_completed(isc_task_t *task, isc_event_t *event) {
dns_requestevent_t *reqev = NULL;
isc_result_t result;
- dns_message_t *rcvmsg = NULL;
dns_request_t *request;
UNUSED(task);
@@ -1432,9 +1462,9 @@ update_completed(isc_task_t *task, isc_event_t *event) {
goto done;
}
- result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
+ result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer);
check_result(result, "dns_message_create");
- result = dns_request_getresponse(request, rcvmsg,
+ result = dns_request_getresponse(request, answer,
DNS_MESSAGEPARSE_PRESERVEORDER);
switch (result) {
case ISC_R_SUCCESS:
@@ -1452,8 +1482,23 @@ update_completed(isc_task_t *task, isc_event_t *event) {
check_result(result, "dns_request_getresponse");
}
- if (rcvmsg->rcode != dns_rcode_noerror)
+ if (answer->rcode != dns_rcode_noerror) {
seenerror = ISC_TRUE;
+ if (!debugging) {
+ char buf[64];
+ isc_buffer_t b;
+ dns_rdataset_t *rds;
+
+ isc_buffer_init(&b, buf, sizeof(buf) - 1);
+ result = dns_rcode_totext(answer->rcode, &b);
+ check_result(result, "dns_rcode_totext");
+ rds = dns_message_gettsig(answer, NULL);
+ if (rds != NULL)
+ check_tsig_error(rds, &b);
+ fprintf(stderr, "update failed: %.*s\n",
+ (int)isc_buffer_usedlength(&b), buf);
+ }
+ }
if (debugging) {
isc_buffer_t *buf = NULL;
int bufsz;
@@ -1469,7 +1514,7 @@ update_completed(isc_task_t *task, isc_event_t *event) {
isc_buffer_free(&buf);
result = isc_buffer_allocate(mctx, &buf, bufsz);
check_result(result, "isc_buffer_allocate");
- result = dns_message_totext(rcvmsg, style, 0, buf);
+ result = dns_message_totext(answer, style, 0, buf);
bufsz *= 2;
} while (result == ISC_R_NOSPACE);
check_result(result, "dns_message_totext");
@@ -1478,7 +1523,6 @@ update_completed(isc_task_t *task, isc_event_t *event) {
(char*)isc_buffer_base(buf));
isc_buffer_free(&buf);
}
- dns_message_destroy(&rcvmsg);
done:
dns_request_destroy(&request);
isc_event_free(&event);
@@ -1503,19 +1547,32 @@ send_update(dns_name_t *zonename, isc_sockaddr_t *master,
dns_name_clone(zonename, name);
result = dns_message_gettemprdataset(updatemsg, &rdataset);
check_result(result, "dns_message_gettemprdataset");
- dns_rdataset_makequestion(rdataset, dns_rdataclass_in,
- dns_rdatatype_soa);
+ dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa);
ISC_LIST_INIT(name->list);
ISC_LIST_APPEND(name->list, rdataset, link);
dns_message_addname(updatemsg, name, DNS_SECTION_ZONE);
if (usevc)
options |= DNS_REQUESTOPT_TCP;
- result = dns_request_createvia(requestmgr, updatemsg, srcaddr,
- master, options, key,
- FIND_TIMEOUT, global_task,
- update_completed, NULL, &request);
- check_result(result, "dns_request_createvia");
+ if (tsigkey == NULL && sig0key != NULL) {
+ result = dns_message_setsig0key(updatemsg, sig0key);
+ check_result(result, "dns_message_setsig0key");
+ }
+ if (debugging) {
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+
+ isc_sockaddr_format(master, addrbuf, sizeof(addrbuf));
+ fprintf(stderr, "Sending update to %s\n", addrbuf);
+ }
+ result = dns_request_createvia3(requestmgr, updatemsg, srcaddr,
+ master, options, tsigkey, timeout,
+ udp_timeout, udp_retries, global_task,
+ update_completed, NULL, &request);
+ check_result(result, "dns_request_createvia3");
+
+ if (debugging)
+ show_message(updatemsg);
+
requests++;
}
@@ -1578,6 +1635,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
isc_event_free(&event);
+ setzoneclass(dns_rdataclass_none);
return;
}
isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
@@ -1590,6 +1648,27 @@ 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) {
+ dns_message_destroy(&rcvmsg);
+ ddebug("Destroying request [%p]", request);
+ dns_request_destroy(&request);
+ reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t));
+ if (reqinfo == NULL)
+ fatal("out of memory");
+ reqinfo->msg = soaquery;
+ reqinfo->addr = addr;
+ dns_message_renderreset(soaquery);
+ ddebug("retrying soa request without TSIG");
+ result = dns_request_createvia3(requestmgr, soaquery,
+ localaddr, addr, 0, NULL,
+ FIND_TIMEOUT * 20,
+ FIND_TIMEOUT * 20, 3,
+ global_task, recvsoa, reqinfo,
+ &request);
+ check_result(result, "dns_request_createvia");
+ requests++;
+ return;
+ }
check_result(result, "dns_request_getresponse");
section = DNS_SECTION_ANSWER;
if (debugging) {
@@ -1735,6 +1814,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
dns_request_destroy(&request);
out:
+ setzoneclass(dns_rdataclass_none);
dns_rdata_freestruct(&soa);
dns_message_destroy(&rcvmsg);
ddebug("Out of recvsoa");
@@ -1752,9 +1832,10 @@ sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
fatal("out of memory");
reqinfo->msg = msg;
reqinfo->addr = destaddr;
- result = dns_request_createvia(requestmgr, msg, srcaddr, destaddr,
- 0, NULL, FIND_TIMEOUT, global_task,
- recvsoa, reqinfo, request);
+ result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0,
+ (userserver != NULL) ? tsigkey : NULL,
+ FIND_TIMEOUT * 20, FIND_TIMEOUT, 3,
+ global_task, recvsoa, reqinfo, request);
check_result(result, "dns_request_createvia");
requests++;
}
@@ -1767,10 +1848,17 @@ start_update(void) {
dns_request_t *request = NULL;
dns_message_t *soaquery = NULL;
dns_name_t *firstname;
+ dns_section_t section = DNS_SECTION_UPDATE;
ddebug("start_update()");
- result = dns_message_firstname(updatemsg, DNS_SECTION_UPDATE);
+ if (answer != NULL)
+ dns_message_destroy(&answer);
+ result = dns_message_firstname(updatemsg, section);
+ if (result == ISC_R_NOMORE) {
+ section = DNS_SECTION_PREREQUISITE;
+ result = dns_message_firstname(updatemsg, section);
+ }
if (result != ISC_R_SUCCESS) {
done_update();
return;
@@ -1778,6 +1866,7 @@ start_update(void) {
if (userzone != NULL && userserver != NULL) {
send_update(userzone, userserver, localaddr);
+ setzoneclass(dns_rdataclass_none);
return;
}
@@ -1793,11 +1882,10 @@ start_update(void) {
result = dns_message_gettemprdataset(soaquery, &rdataset);
check_result(result, "dns_message_gettemprdataset");
- dns_rdataset_makequestion(rdataset, dns_rdataclass_in,
- dns_rdatatype_soa);
+ dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa);
firstname = NULL;
- dns_message_currentname(updatemsg, DNS_SECTION_UPDATE, &firstname);
+ dns_message_currentname(updatemsg, section, &firstname);
dns_name_init(name, NULL);
dns_name_clone(firstname, name);
@@ -1817,6 +1905,8 @@ static void
cleanup(void) {
ddebug("cleanup()");
+ if (answer != NULL)
+ dns_message_destroy(&answer);
ddebug("Shutting down task manager");
isc_taskmgr_destroy(&taskmgr);
@@ -1869,6 +1959,8 @@ main(int argc, char **argv) {
input = stdin;
+ interactive = ISC_TF(isatty(0));
+
isc_app_start();
parse_args(argc, argv);