Detect FPU by checking CPUID features.
[dragonfly.git] / contrib / bind-9.5.2 / bin / nsupdate / nsupdate.c
blobc641f53806aa5c90c5684738b2242644dba4c224
1 /*
2 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: nsupdate.c,v 1.154.56.6 2009/04/30 07:12:15 marka Exp $ */
20 /*! \file */
22 #include <config.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <unistd.h>
30 #include <isc/app.h>
31 #include <isc/base64.h>
32 #include <isc/buffer.h>
33 #include <isc/commandline.h>
34 #include <isc/entropy.h>
35 #include <isc/event.h>
36 #include <isc/hash.h>
37 #include <isc/lex.h>
38 #include <isc/log.h>
39 #include <isc/mem.h>
40 #include <isc/parseint.h>
41 #include <isc/random.h>
42 #include <isc/region.h>
43 #include <isc/sockaddr.h>
44 #include <isc/socket.h>
45 #include <isc/stdio.h>
46 #include <isc/string.h>
47 #include <isc/task.h>
48 #include <isc/timer.h>
49 #include <isc/types.h>
50 #include <isc/util.h>
52 #include <dns/callbacks.h>
53 #include <dns/dispatch.h>
54 #include <dns/dnssec.h>
55 #include <dns/events.h>
56 #include <dns/fixedname.h>
57 #include <dns/log.h>
58 #include <dns/masterdump.h>
59 #include <dns/message.h>
60 #include <dns/name.h>
61 #include <dns/rcode.h>
62 #include <dns/rdata.h>
63 #include <dns/rdataclass.h>
64 #include <dns/rdatalist.h>
65 #include <dns/rdataset.h>
66 #include <dns/rdatastruct.h>
67 #include <dns/rdatatype.h>
68 #include <dns/request.h>
69 #include <dns/result.h>
70 #include <dns/tkey.h>
71 #include <dns/tsig.h>
73 #include <dst/dst.h>
75 #include <lwres/lwres.h>
76 #include <lwres/net.h>
78 #ifdef GSSAPI
79 #include <dst/gssapi.h>
80 #endif
81 #include <bind9/getaddresses.h>
84 #ifdef HAVE_ADDRINFO
85 #ifdef HAVE_GETADDRINFO
86 #ifdef HAVE_GAISTRERROR
87 #define USE_GETADDRINFO
88 #endif
89 #endif
90 #endif
92 #ifndef USE_GETADDRINFO
93 #ifndef ISC_PLATFORM_NONSTDHERRNO
94 extern int h_errno;
95 #endif
96 #endif
98 #define MAXCMD (4 * 1024)
99 #define MAXWIRE (64 * 1024)
100 #define PACKETSIZE ((64 * 1024) - 1)
101 #define INITTEXT (2 * 1024)
102 #define MAXTEXT (128 * 1024)
103 #define FIND_TIMEOUT 5
104 #define TTL_MAX 2147483647U /* Maximum signed 32 bit integer. */
106 #define DNSDEFAULTPORT 53
108 #ifndef RESOLV_CONF
109 #define RESOLV_CONF "/etc/resolv.conf"
110 #endif
112 static isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE;
113 static isc_boolean_t memdebugging = ISC_FALSE;
114 static isc_boolean_t have_ipv4 = ISC_FALSE;
115 static isc_boolean_t have_ipv6 = ISC_FALSE;
116 static isc_boolean_t is_dst_up = ISC_FALSE;
117 static isc_boolean_t usevc = ISC_FALSE;
118 static isc_boolean_t usegsstsig = ISC_FALSE;
119 static isc_boolean_t use_win2k_gsstsig = ISC_FALSE;
120 static isc_boolean_t tried_other_gsstsig = ISC_FALSE;
121 static isc_taskmgr_t *taskmgr = NULL;
122 static isc_task_t *global_task = NULL;
123 static isc_event_t *global_event = NULL;
124 static isc_log_t *lctx = NULL;
125 static isc_mem_t *mctx = NULL;
126 static dns_dispatchmgr_t *dispatchmgr = NULL;
127 static dns_requestmgr_t *requestmgr = NULL;
128 static isc_socketmgr_t *socketmgr = NULL;
129 static isc_timermgr_t *timermgr = NULL;
130 static dns_dispatch_t *dispatchv4 = NULL;
131 static dns_dispatch_t *dispatchv6 = NULL;
132 static dns_message_t *updatemsg = NULL;
133 static dns_fixedname_t fuserzone;
134 static dns_name_t *userzone = NULL;
135 static dns_name_t *zonename = NULL;
136 static dns_name_t tmpzonename;
137 static dns_name_t restart_master;
138 static dns_tsig_keyring_t *gssring = NULL;
139 static dns_tsigkey_t *tsigkey = NULL;
140 static dst_key_t *sig0key;
141 static lwres_context_t *lwctx = NULL;
142 static lwres_conf_t *lwconf;
143 static isc_sockaddr_t *servers;
144 static int ns_inuse = 0;
145 static int ns_total = 0;
146 static isc_sockaddr_t *userserver = NULL;
147 static isc_sockaddr_t *localaddr = NULL;
148 static isc_sockaddr_t *serveraddr = NULL;
149 static isc_sockaddr_t tempaddr;
150 static char *keystr = NULL, *keyfile = NULL;
151 static isc_entropy_t *entropy = NULL;
152 static isc_boolean_t shuttingdown = ISC_FALSE;
153 static FILE *input;
154 static isc_boolean_t interactive = ISC_TRUE;
155 static isc_boolean_t seenerror = ISC_FALSE;
156 static const dns_master_style_t *style;
157 static int requests = 0;
158 static unsigned int logdebuglevel = 0;
159 static unsigned int timeout = 300;
160 static unsigned int udp_timeout = 3;
161 static unsigned int udp_retries = 3;
162 static dns_rdataclass_t defaultclass = dns_rdataclass_in;
163 static dns_rdataclass_t zoneclass = dns_rdataclass_none;
164 static dns_message_t *answer = NULL;
166 typedef struct nsu_requestinfo {
167 dns_message_t *msg;
168 isc_sockaddr_t *addr;
169 } nsu_requestinfo_t;
171 static void
172 sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
173 dns_message_t *msg, dns_request_t **request);
174 static void
175 fatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
177 static void
178 debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
180 static void
181 ddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
183 #ifdef GSSAPI
184 static dns_fixedname_t fkname;
185 static isc_sockaddr_t *kserver = NULL;
186 static char servicename[DNS_NAME_FORMATSIZE];
187 static dns_name_t *keyname;
188 typedef struct nsu_gssinfo {
189 dns_message_t *msg;
190 isc_sockaddr_t *addr;
191 gss_ctx_id_t context;
192 } nsu_gssinfo_t;
194 static void
195 start_gssrequest(dns_name_t *master);
196 static void
197 send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
198 dns_message_t *msg, dns_request_t **request,
199 gss_ctx_id_t context);
200 static void
201 recvgss(isc_task_t *task, isc_event_t *event);
202 #endif /* GSSAPI */
204 static void
205 error(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
207 #define STATUS_MORE (isc_uint16_t)0
208 #define STATUS_SEND (isc_uint16_t)1
209 #define STATUS_QUIT (isc_uint16_t)2
210 #define STATUS_SYNTAX (isc_uint16_t)3
212 typedef struct entropysource entropysource_t;
214 struct entropysource {
215 isc_entropysource_t *source;
216 isc_mem_t *mctx;
217 ISC_LINK(entropysource_t) link;
220 static ISC_LIST(entropysource_t) sources;
222 static void
223 setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx)
225 isc_result_t result;
226 isc_entropysource_t *source = NULL;
227 entropysource_t *elt;
228 int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE;
230 REQUIRE(ectx != NULL);
232 if (*ectx == NULL) {
233 result = isc_entropy_create(mctx, ectx);
234 if (result != ISC_R_SUCCESS)
235 fatal("could not create entropy object");
236 ISC_LIST_INIT(sources);
239 if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
240 usekeyboard = ISC_ENTROPY_KEYBOARDYES;
241 randomfile = NULL;
244 result = isc_entropy_usebestsource(*ectx, &source, randomfile,
245 usekeyboard);
247 if (result != ISC_R_SUCCESS)
248 fatal("could not initialize entropy source: %s",
249 isc_result_totext(result));
251 if (source != NULL) {
252 elt = isc_mem_get(mctx, sizeof(*elt));
253 if (elt == NULL)
254 fatal("out of memory");
255 elt->source = source;
256 elt->mctx = mctx;
257 ISC_LINK_INIT(elt, link);
258 ISC_LIST_APPEND(sources, elt, link);
262 static void
263 cleanup_entropy(isc_entropy_t **ectx) {
264 entropysource_t *source;
265 while (!ISC_LIST_EMPTY(sources)) {
266 source = ISC_LIST_HEAD(sources);
267 ISC_LIST_UNLINK(sources, source, link);
268 isc_entropy_destroysource(&source->source);
269 isc_mem_put(source->mctx, source, sizeof(*source));
271 isc_entropy_detach(ectx);
275 static dns_rdataclass_t
276 getzoneclass(void) {
277 if (zoneclass == dns_rdataclass_none)
278 zoneclass = defaultclass;
279 return (zoneclass);
282 static isc_boolean_t
283 setzoneclass(dns_rdataclass_t rdclass) {
284 if (zoneclass == dns_rdataclass_none ||
285 rdclass == dns_rdataclass_none)
286 zoneclass = rdclass;
287 if (zoneclass != rdclass)
288 return (ISC_FALSE);
289 return (ISC_TRUE);
292 static void
293 fatal(const char *format, ...) {
294 va_list args;
296 va_start(args, format);
297 vfprintf(stderr, format, args);
298 va_end(args);
299 fprintf(stderr, "\n");
300 exit(1);
303 static void
304 error(const char *format, ...) {
305 va_list args;
307 va_start(args, format);
308 vfprintf(stderr, format, args);
309 va_end(args);
310 fprintf(stderr, "\n");
313 static void
314 debug(const char *format, ...) {
315 va_list args;
317 if (debugging) {
318 va_start(args, format);
319 vfprintf(stderr, format, args);
320 va_end(args);
321 fprintf(stderr, "\n");
325 static void
326 ddebug(const char *format, ...) {
327 va_list args;
329 if (ddebugging) {
330 va_start(args, format);
331 vfprintf(stderr, format, args);
332 va_end(args);
333 fprintf(stderr, "\n");
337 static inline void
338 check_result(isc_result_t result, const char *msg) {
339 if (result != ISC_R_SUCCESS)
340 fatal("%s: %s", msg, isc_result_totext(result));
343 static void *
344 mem_alloc(void *arg, size_t size) {
345 return (isc_mem_get(arg, size));
348 static void
349 mem_free(void *arg, void *mem, size_t size) {
350 isc_mem_put(arg, mem, size);
353 static char *
354 nsu_strsep(char **stringp, const char *delim) {
355 char *string = *stringp;
356 char *s;
357 const char *d;
358 char sc, dc;
360 if (string == NULL)
361 return (NULL);
363 for (; *string != '\0'; string++) {
364 sc = *string;
365 for (d = delim; (dc = *d) != '\0'; d++) {
366 if (sc == dc)
367 break;
369 if (dc == 0)
370 break;
373 for (s = string; *s != '\0'; s++) {
374 sc = *s;
375 for (d = delim; (dc = *d) != '\0'; d++) {
376 if (sc == dc) {
377 *s++ = '\0';
378 *stringp = s;
379 return (string);
383 *stringp = NULL;
384 return (string);
387 static void
388 reset_system(void) {
389 isc_result_t result;
391 ddebug("reset_system()");
392 /* If the update message is still around, destroy it */
393 if (updatemsg != NULL)
394 dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER);
395 else {
396 result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
397 &updatemsg);
398 check_result(result, "dns_message_create");
400 updatemsg->opcode = dns_opcode_update;
401 if (usegsstsig) {
402 if (tsigkey != NULL)
403 dns_tsigkey_detach(&tsigkey);
404 if (gssring != NULL)
405 dns_tsigkeyring_destroy(&gssring);
406 tried_other_gsstsig = ISC_FALSE;
410 static isc_uint16_t
411 parse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) {
412 isc_uint16_t digestbits = 0;
413 isc_result_t result;
414 char buf[20];
416 REQUIRE(hmac != NULL && *hmac == NULL);
417 REQUIRE(hmacstr != NULL);
419 if (len >= sizeof(buf))
420 fatal("unknown key type '%.*s'", (int)(len), hmacstr);
422 strncpy(buf, hmacstr, len);
423 buf[len] = 0;
425 if (strcasecmp(buf, "hmac-md5") == 0) {
426 *hmac = DNS_TSIG_HMACMD5_NAME;
427 } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
428 *hmac = DNS_TSIG_HMACMD5_NAME;
429 result = isc_parse_uint16(&digestbits, &buf[9], 10);
430 if (result != ISC_R_SUCCESS || digestbits > 128)
431 fatal("digest-bits out of range [0..128]");
432 digestbits = (digestbits +7) & ~0x7U;
433 } else if (strcasecmp(buf, "hmac-sha1") == 0) {
434 *hmac = DNS_TSIG_HMACSHA1_NAME;
435 } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
436 *hmac = DNS_TSIG_HMACSHA1_NAME;
437 result = isc_parse_uint16(&digestbits, &buf[10], 10);
438 if (result != ISC_R_SUCCESS || digestbits > 160)
439 fatal("digest-bits out of range [0..160]");
440 digestbits = (digestbits +7) & ~0x7U;
441 } else if (strcasecmp(buf, "hmac-sha224") == 0) {
442 *hmac = DNS_TSIG_HMACSHA224_NAME;
443 } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
444 *hmac = DNS_TSIG_HMACSHA224_NAME;
445 result = isc_parse_uint16(&digestbits, &buf[12], 10);
446 if (result != ISC_R_SUCCESS || digestbits > 224)
447 fatal("digest-bits out of range [0..224]");
448 digestbits = (digestbits +7) & ~0x7U;
449 } else if (strcasecmp(buf, "hmac-sha256") == 0) {
450 *hmac = DNS_TSIG_HMACSHA256_NAME;
451 } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
452 *hmac = DNS_TSIG_HMACSHA256_NAME;
453 result = isc_parse_uint16(&digestbits, &buf[12], 10);
454 if (result != ISC_R_SUCCESS || digestbits > 256)
455 fatal("digest-bits out of range [0..256]");
456 digestbits = (digestbits +7) & ~0x7U;
457 } else if (strcasecmp(buf, "hmac-sha384") == 0) {
458 *hmac = DNS_TSIG_HMACSHA384_NAME;
459 } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
460 *hmac = DNS_TSIG_HMACSHA384_NAME;
461 result = isc_parse_uint16(&digestbits, &buf[12], 10);
462 if (result != ISC_R_SUCCESS || digestbits > 384)
463 fatal("digest-bits out of range [0..384]");
464 digestbits = (digestbits +7) & ~0x7U;
465 } else if (strcasecmp(buf, "hmac-sha512") == 0) {
466 *hmac = DNS_TSIG_HMACSHA512_NAME;
467 } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
468 *hmac = DNS_TSIG_HMACSHA512_NAME;
469 result = isc_parse_uint16(&digestbits, &buf[12], 10);
470 if (result != ISC_R_SUCCESS || digestbits > 512)
471 fatal("digest-bits out of range [0..512]");
472 digestbits = (digestbits +7) & ~0x7U;
473 } else
474 fatal("unknown key type '%s'", buf);
475 return (digestbits);
478 static void
479 setup_keystr(void) {
480 unsigned char *secret = NULL;
481 int secretlen;
482 isc_buffer_t secretbuf;
483 isc_result_t result;
484 isc_buffer_t keynamesrc;
485 char *secretstr;
486 char *s, *n;
487 dns_fixedname_t fkeyname;
488 dns_name_t *keyname;
489 char *name;
490 dns_name_t *hmacname = NULL;
491 isc_uint16_t digestbits = 0;
493 dns_fixedname_init(&fkeyname);
494 keyname = dns_fixedname_name(&fkeyname);
496 debug("Creating key...");
498 s = strchr(keystr, ':');
499 if (s == NULL || s == keystr || s[1] == 0)
500 fatal("key option must specify [hmac:]keyname:secret");
501 secretstr = s + 1;
502 n = strchr(secretstr, ':');
503 if (n != NULL) {
504 if (n == secretstr || n[1] == 0)
505 fatal("key option must specify [hmac:]keyname:secret");
506 name = secretstr;
507 secretstr = n + 1;
508 digestbits = parse_hmac(&hmacname, keystr, s - keystr);
509 } else {
510 hmacname = DNS_TSIG_HMACMD5_NAME;
511 name = keystr;
512 n = s;
515 isc_buffer_init(&keynamesrc, name, n - name);
516 isc_buffer_add(&keynamesrc, n - name);
518 debug("namefromtext");
519 result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname,
520 ISC_FALSE, NULL);
521 check_result(result, "dns_name_fromtext");
523 secretlen = strlen(secretstr) * 3 / 4;
524 secret = isc_mem_allocate(mctx, secretlen);
525 if (secret == NULL)
526 fatal("out of memory");
528 isc_buffer_init(&secretbuf, secret, secretlen);
529 result = isc_base64_decodestring(secretstr, &secretbuf);
530 if (result != ISC_R_SUCCESS) {
531 fprintf(stderr, "could not create key from %s: %s\n",
532 keystr, isc_result_totext(result));
533 goto failure;
536 secretlen = isc_buffer_usedlength(&secretbuf);
538 debug("keycreate");
539 result = dns_tsigkey_create(keyname, hmacname, secret, secretlen,
540 ISC_TRUE, NULL, 0, 0, mctx, NULL, &tsigkey);
541 if (result != ISC_R_SUCCESS)
542 fprintf(stderr, "could not create key from %s: %s\n",
543 keystr, dns_result_totext(result));
544 else
545 dst_key_setbits(tsigkey->key, digestbits);
546 failure:
547 if (secret != NULL)
548 isc_mem_free(mctx, secret);
551 static void
552 setup_keyfile(void) {
553 dst_key_t *dstkey = NULL;
554 isc_result_t result;
555 dns_name_t *hmacname = NULL;
557 debug("Creating key...");
559 result = dst_key_fromnamedfile(keyfile,
560 DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
561 &dstkey);
562 if (result != ISC_R_SUCCESS) {
563 fprintf(stderr, "could not read key from %s: %s\n",
564 keyfile, isc_result_totext(result));
565 return;
567 switch (dst_key_alg(dstkey)) {
568 case DST_ALG_HMACMD5:
569 hmacname = DNS_TSIG_HMACMD5_NAME;
570 break;
571 case DST_ALG_HMACSHA1:
572 hmacname = DNS_TSIG_HMACSHA1_NAME;
573 break;
574 case DST_ALG_HMACSHA224:
575 hmacname = DNS_TSIG_HMACSHA224_NAME;
576 break;
577 case DST_ALG_HMACSHA256:
578 hmacname = DNS_TSIG_HMACSHA256_NAME;
579 break;
580 case DST_ALG_HMACSHA384:
581 hmacname = DNS_TSIG_HMACSHA384_NAME;
582 break;
583 case DST_ALG_HMACSHA512:
584 hmacname = DNS_TSIG_HMACSHA512_NAME;
585 break;
587 if (hmacname != NULL) {
588 result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
589 hmacname, dstkey, ISC_FALSE,
590 NULL, 0, 0, mctx, NULL,
591 &tsigkey);
592 if (result != ISC_R_SUCCESS) {
593 fprintf(stderr, "could not create key from %s: %s\n",
594 keyfile, isc_result_totext(result));
595 dst_key_free(&dstkey);
596 return;
598 } else
599 sig0key = dstkey;
602 static void
603 doshutdown(void) {
604 isc_task_detach(&global_task);
606 if (userserver != NULL)
607 isc_mem_put(mctx, userserver, sizeof(isc_sockaddr_t));
609 if (localaddr != NULL)
610 isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t));
612 if (tsigkey != NULL) {
613 ddebug("Freeing TSIG key");
614 dns_tsigkey_detach(&tsigkey);
617 if (sig0key != NULL) {
618 ddebug("Freeing SIG(0) key");
619 dst_key_free(&sig0key);
622 if (updatemsg != NULL)
623 dns_message_destroy(&updatemsg);
625 if (is_dst_up) {
626 ddebug("Destroy DST lib");
627 dst_lib_destroy();
628 is_dst_up = ISC_FALSE;
631 cleanup_entropy(&entropy);
633 lwres_conf_clear(lwctx);
634 lwres_context_destroy(&lwctx);
636 isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t));
638 ddebug("Destroying request manager");
639 dns_requestmgr_detach(&requestmgr);
641 ddebug("Freeing the dispatchers");
642 if (have_ipv4)
643 dns_dispatch_detach(&dispatchv4);
644 if (have_ipv6)
645 dns_dispatch_detach(&dispatchv6);
647 ddebug("Shutting down dispatch manager");
648 dns_dispatchmgr_destroy(&dispatchmgr);
652 static void
653 maybeshutdown(void) {
654 ddebug("Shutting down request manager");
655 dns_requestmgr_shutdown(requestmgr);
657 if (requests != 0)
658 return;
660 doshutdown();
663 static void
664 shutdown_program(isc_task_t *task, isc_event_t *event) {
665 REQUIRE(task == global_task);
666 UNUSED(task);
668 ddebug("shutdown_program()");
669 isc_event_free(&event);
671 shuttingdown = ISC_TRUE;
672 maybeshutdown();
675 static void
676 setup_system(void) {
677 isc_result_t result;
678 isc_sockaddr_t bind_any, bind_any6;
679 lwres_result_t lwresult;
680 unsigned int attrs, attrmask;
681 int i;
682 isc_logconfig_t *logconfig = NULL;
684 ddebug("setup_system()");
686 dns_result_register();
688 result = isc_net_probeipv4();
689 if (result == ISC_R_SUCCESS)
690 have_ipv4 = ISC_TRUE;
692 result = isc_net_probeipv6();
693 if (result == ISC_R_SUCCESS)
694 have_ipv6 = ISC_TRUE;
696 if (!have_ipv4 && !have_ipv6)
697 fatal("could not find either IPv4 or IPv6");
699 result = isc_log_create(mctx, &lctx, &logconfig);
700 check_result(result, "isc_log_create");
702 isc_log_setcontext(lctx);
703 dns_log_init(lctx);
704 dns_log_setcontext(lctx);
706 result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
707 check_result(result, "isc_log_usechannel");
709 isc_log_setdebuglevel(lctx, logdebuglevel);
711 lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1);
712 if (lwresult != LWRES_R_SUCCESS)
713 fatal("lwres_context_create failed");
715 (void)lwres_conf_parse(lwctx, RESOLV_CONF);
716 lwconf = lwres_conf_get(lwctx);
718 ns_total = lwconf->nsnext;
719 if (ns_total <= 0) {
720 /* No name servers in resolv.conf; default to loopback. */
721 struct in_addr localhost;
722 ns_total = 1;
723 servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
724 if (servers == NULL)
725 fatal("out of memory");
726 localhost.s_addr = htonl(INADDR_LOOPBACK);
727 isc_sockaddr_fromin(&servers[0], &localhost, DNSDEFAULTPORT);
728 } else {
729 servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
730 if (servers == NULL)
731 fatal("out of memory");
732 for (i = 0; i < ns_total; i++) {
733 if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4) {
734 struct in_addr in4;
735 memcpy(&in4, lwconf->nameservers[i].address, 4);
736 isc_sockaddr_fromin(&servers[i], &in4, DNSDEFAULTPORT);
737 } else {
738 struct in6_addr in6;
739 memcpy(&in6, lwconf->nameservers[i].address, 16);
740 isc_sockaddr_fromin6(&servers[i], &in6,
741 DNSDEFAULTPORT);
746 setup_entropy(mctx, NULL, &entropy);
748 result = isc_hash_create(mctx, entropy, DNS_NAME_MAXWIRE);
749 check_result(result, "isc_hash_create");
750 isc_hash_init();
752 result = dns_dispatchmgr_create(mctx, entropy, &dispatchmgr);
753 check_result(result, "dns_dispatchmgr_create");
755 result = isc_socketmgr_create(mctx, &socketmgr);
756 check_result(result, "dns_socketmgr_create");
758 result = isc_timermgr_create(mctx, &timermgr);
759 check_result(result, "dns_timermgr_create");
761 result = isc_taskmgr_create(mctx, 1, 0, &taskmgr);
762 check_result(result, "isc_taskmgr_create");
764 result = isc_task_create(taskmgr, 0, &global_task);
765 check_result(result, "isc_task_create");
767 result = isc_task_onshutdown(global_task, shutdown_program, NULL);
768 check_result(result, "isc_task_onshutdown");
770 result = dst_lib_init(mctx, entropy, 0);
771 check_result(result, "dst_lib_init");
772 is_dst_up = ISC_TRUE;
774 attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
775 attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
777 if (have_ipv6) {
778 attrs = DNS_DISPATCHATTR_UDP;
779 attrs |= DNS_DISPATCHATTR_MAKEQUERY;
780 attrs |= DNS_DISPATCHATTR_IPV6;
781 isc_sockaddr_any6(&bind_any6);
782 result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
783 &bind_any6, PACKETSIZE,
784 4, 2, 3, 5,
785 attrs, attrmask, &dispatchv6);
786 check_result(result, "dns_dispatch_getudp (v6)");
789 if (have_ipv4) {
790 attrs = DNS_DISPATCHATTR_UDP;
791 attrs |= DNS_DISPATCHATTR_MAKEQUERY;
792 attrs |= DNS_DISPATCHATTR_IPV4;
793 isc_sockaddr_any(&bind_any);
794 result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
795 &bind_any, PACKETSIZE,
796 4, 2, 3, 5,
797 attrs, attrmask, &dispatchv4);
798 check_result(result, "dns_dispatch_getudp (v4)");
801 result = dns_requestmgr_create(mctx, timermgr,
802 socketmgr, taskmgr, dispatchmgr,
803 dispatchv4, dispatchv6, &requestmgr);
804 check_result(result, "dns_requestmgr_create");
806 if (keystr != NULL)
807 setup_keystr();
808 else if (keyfile != NULL)
809 setup_keyfile();
812 static void
813 get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
814 int count;
815 isc_result_t result;
817 isc_app_block();
818 result = bind9_getaddresses(host, port, sockaddr, 1, &count);
819 isc_app_unblock();
820 if (result != ISC_R_SUCCESS)
821 fatal("couldn't get address for '%s': %s",
822 host, isc_result_totext(result));
823 INSIST(count == 1);
826 #define PARSE_ARGS_FMT "dDMl:y:govk:rR::t:u:"
828 static void
829 pre_parse_args(int argc, char **argv) {
830 int ch;
832 while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
833 switch (ch) {
834 case 'M': /* was -dm */
835 debugging = ISC_TRUE;
836 ddebugging = ISC_TRUE;
837 memdebugging = ISC_TRUE;
838 isc_mem_debugging = ISC_MEM_DEBUGTRACE |
839 ISC_MEM_DEBUGRECORD;
840 break;
842 case '?':
843 if (isc_commandline_option != '?')
844 fprintf(stderr, "%s: invalid argument -%c\n",
845 argv[0], isc_commandline_option);
846 fprintf(stderr, "usage: nsupdate [-d] "
847 "[-g | -o | -y keyname:secret | -k keyfile] "
848 "[-v] [filename]\n");
849 exit(1);
851 default:
852 break;
855 isc_commandline_reset = ISC_TRUE;
856 isc_commandline_index = 1;
859 static void
860 parse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) {
861 int ch;
862 isc_uint32_t i;
863 isc_result_t result;
865 debug("parse_args");
866 while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
867 switch (ch) {
868 case 'd':
869 debugging = ISC_TRUE;
870 break;
871 case 'D': /* was -dd */
872 debugging = ISC_TRUE;
873 ddebugging = ISC_TRUE;
874 break;
875 case 'M':
876 break;
877 case 'l':
878 result = isc_parse_uint32(&i, isc_commandline_argument,
879 10);
880 if (result != ISC_R_SUCCESS) {
881 fprintf(stderr, "bad library debug value "
882 "'%s'\n", isc_commandline_argument);
883 exit(1);
885 logdebuglevel = i;
886 break;
887 case 'y':
888 keystr = isc_commandline_argument;
889 break;
890 case 'v':
891 usevc = ISC_TRUE;
892 break;
893 case 'k':
894 keyfile = isc_commandline_argument;
895 break;
896 case 'g':
897 usegsstsig = ISC_TRUE;
898 use_win2k_gsstsig = ISC_FALSE;
899 break;
900 case 'o':
901 usegsstsig = ISC_TRUE;
902 use_win2k_gsstsig = ISC_TRUE;
903 break;
904 case 't':
905 result = isc_parse_uint32(&timeout,
906 isc_commandline_argument, 10);
907 if (result != ISC_R_SUCCESS) {
908 fprintf(stderr, "bad timeout '%s'\n", isc_commandline_argument);
909 exit(1);
911 if (timeout == 0)
912 timeout = UINT_MAX;
913 break;
914 case 'u':
915 result = isc_parse_uint32(&udp_timeout,
916 isc_commandline_argument, 10);
917 if (result != ISC_R_SUCCESS) {
918 fprintf(stderr, "bad udp timeout '%s'\n", isc_commandline_argument);
919 exit(1);
921 if (udp_timeout == 0)
922 udp_timeout = UINT_MAX;
923 break;
924 case 'r':
925 result = isc_parse_uint32(&udp_retries,
926 isc_commandline_argument, 10);
927 if (result != ISC_R_SUCCESS) {
928 fprintf(stderr, "bad udp retries '%s'\n", isc_commandline_argument);
929 exit(1);
931 break;
933 case 'R':
934 setup_entropy(mctx, isc_commandline_argument, ectx);
935 break;
937 default:
938 fprintf(stderr, "%s: unhandled option: %c\n",
939 argv[0], isc_commandline_option);
940 exit(1);
943 if (keyfile != NULL && keystr != NULL) {
944 fprintf(stderr, "%s: cannot specify both -k and -y\n",
945 argv[0]);
946 exit(1);
949 #ifdef GSSAPI
950 if (usegsstsig && (keyfile != NULL || keystr != NULL)) {
951 fprintf(stderr, "%s: cannot specify -g with -k or -y\n",
952 argv[0]);
953 exit(1);
955 #else
956 if (usegsstsig) {
957 fprintf(stderr, "%s: cannot specify -g or -o, " \
958 "program not linked with GSS API Library\n",
959 argv[0]);
960 exit(1);
962 #endif
964 if (argv[isc_commandline_index] != NULL) {
965 if (strcmp(argv[isc_commandline_index], "-") == 0) {
966 input = stdin;
967 } else {
968 result = isc_stdio_open(argv[isc_commandline_index],
969 "r", &input);
970 if (result != ISC_R_SUCCESS) {
971 fprintf(stderr, "could not open '%s': %s\n",
972 argv[isc_commandline_index],
973 isc_result_totext(result));
974 exit(1);
977 interactive = ISC_FALSE;
981 static isc_uint16_t
982 parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) {
983 isc_result_t result;
984 char *word;
985 isc_buffer_t *namebuf = NULL;
986 isc_buffer_t source;
988 word = nsu_strsep(cmdlinep, " \t\r\n");
989 if (*word == 0) {
990 fprintf(stderr, "could not read owner name\n");
991 return (STATUS_SYNTAX);
994 result = dns_message_gettempname(msg, namep);
995 check_result(result, "dns_message_gettempname");
996 result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
997 check_result(result, "isc_buffer_allocate");
998 dns_name_init(*namep, NULL);
999 dns_name_setbuffer(*namep, namebuf);
1000 dns_message_takebuffer(msg, &namebuf);
1001 isc_buffer_init(&source, word, strlen(word));
1002 isc_buffer_add(&source, strlen(word));
1003 result = dns_name_fromtext(*namep, &source, dns_rootname,
1004 ISC_FALSE, NULL);
1005 check_result(result, "dns_name_fromtext");
1006 isc_buffer_invalidate(&source);
1007 return (STATUS_MORE);
1010 static isc_uint16_t
1011 parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass,
1012 dns_rdatatype_t rdatatype, dns_message_t *msg,
1013 dns_rdata_t *rdata)
1015 char *cmdline = *cmdlinep;
1016 isc_buffer_t source, *buf = NULL, *newbuf = NULL;
1017 isc_region_t r;
1018 isc_lex_t *lex = NULL;
1019 dns_rdatacallbacks_t callbacks;
1020 isc_result_t result;
1022 while (*cmdline != 0 && isspace((unsigned char)*cmdline))
1023 cmdline++;
1025 if (*cmdline != 0) {
1026 dns_rdatacallbacks_init(&callbacks);
1027 result = isc_lex_create(mctx, strlen(cmdline), &lex);
1028 check_result(result, "isc_lex_create");
1029 isc_buffer_init(&source, cmdline, strlen(cmdline));
1030 isc_buffer_add(&source, strlen(cmdline));
1031 result = isc_lex_openbuffer(lex, &source);
1032 check_result(result, "isc_lex_openbuffer");
1033 result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
1034 check_result(result, "isc_buffer_allocate");
1035 result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex,
1036 dns_rootname, 0, mctx, buf,
1037 &callbacks);
1038 isc_lex_destroy(&lex);
1039 if (result == ISC_R_SUCCESS) {
1040 isc_buffer_usedregion(buf, &r);
1041 result = isc_buffer_allocate(mctx, &newbuf, r.length);
1042 check_result(result, "isc_buffer_allocate");
1043 isc_buffer_putmem(newbuf, r.base, r.length);
1044 isc_buffer_usedregion(newbuf, &r);
1045 dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r);
1046 isc_buffer_free(&buf);
1047 dns_message_takebuffer(msg, &newbuf);
1048 } else {
1049 fprintf(stderr, "invalid rdata format: %s\n",
1050 isc_result_totext(result));
1051 isc_buffer_free(&buf);
1052 return (STATUS_SYNTAX);
1054 } else {
1055 rdata->flags = DNS_RDATA_UPDATE;
1057 *cmdlinep = cmdline;
1058 return (STATUS_MORE);
1061 static isc_uint16_t
1062 make_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) {
1063 isc_result_t result;
1064 char *word;
1065 dns_name_t *name = NULL;
1066 isc_textregion_t region;
1067 dns_rdataset_t *rdataset = NULL;
1068 dns_rdatalist_t *rdatalist = NULL;
1069 dns_rdataclass_t rdataclass;
1070 dns_rdatatype_t rdatatype;
1071 dns_rdata_t *rdata = NULL;
1072 isc_uint16_t retval;
1074 ddebug("make_prereq()");
1077 * Read the owner name
1079 retval = parse_name(&cmdline, updatemsg, &name);
1080 if (retval != STATUS_MORE)
1081 return (retval);
1084 * If this is an rrset prereq, read the class or type.
1086 if (isrrset) {
1087 word = nsu_strsep(&cmdline, " \t\r\n");
1088 if (*word == 0) {
1089 fprintf(stderr, "could not read class or type\n");
1090 goto failure;
1092 region.base = word;
1093 region.length = strlen(word);
1094 result = dns_rdataclass_fromtext(&rdataclass, &region);
1095 if (result == ISC_R_SUCCESS) {
1096 if (!setzoneclass(rdataclass)) {
1097 fprintf(stderr, "class mismatch: %s\n", word);
1098 goto failure;
1101 * Now read the type.
1103 word = nsu_strsep(&cmdline, " \t\r\n");
1104 if (*word == 0) {
1105 fprintf(stderr, "could not read type\n");
1106 goto failure;
1108 region.base = word;
1109 region.length = strlen(word);
1110 result = dns_rdatatype_fromtext(&rdatatype, &region);
1111 if (result != ISC_R_SUCCESS) {
1112 fprintf(stderr, "invalid type: %s\n", word);
1113 goto failure;
1115 } else {
1116 rdataclass = getzoneclass();
1117 result = dns_rdatatype_fromtext(&rdatatype, &region);
1118 if (result != ISC_R_SUCCESS) {
1119 fprintf(stderr, "invalid type: %s\n", word);
1120 goto failure;
1123 } else
1124 rdatatype = dns_rdatatype_any;
1126 result = dns_message_gettemprdata(updatemsg, &rdata);
1127 check_result(result, "dns_message_gettemprdata");
1129 rdata->data = NULL;
1130 rdata->length = 0;
1132 if (isrrset && ispositive) {
1133 retval = parse_rdata(&cmdline, rdataclass, rdatatype,
1134 updatemsg, rdata);
1135 if (retval != STATUS_MORE)
1136 goto failure;
1137 } else
1138 rdata->flags = DNS_RDATA_UPDATE;
1140 result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
1141 check_result(result, "dns_message_gettemprdatalist");
1142 result = dns_message_gettemprdataset(updatemsg, &rdataset);
1143 check_result(result, "dns_message_gettemprdataset");
1144 dns_rdatalist_init(rdatalist);
1145 rdatalist->type = rdatatype;
1146 if (ispositive) {
1147 if (isrrset && rdata->data != NULL)
1148 rdatalist->rdclass = rdataclass;
1149 else
1150 rdatalist->rdclass = dns_rdataclass_any;
1151 } else
1152 rdatalist->rdclass = dns_rdataclass_none;
1153 rdatalist->covers = 0;
1154 rdatalist->ttl = 0;
1155 rdata->rdclass = rdatalist->rdclass;
1156 rdata->type = rdatatype;
1157 ISC_LIST_INIT(rdatalist->rdata);
1158 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1159 dns_rdataset_init(rdataset);
1160 dns_rdatalist_tordataset(rdatalist, rdataset);
1161 ISC_LIST_INIT(name->list);
1162 ISC_LIST_APPEND(name->list, rdataset, link);
1163 dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE);
1164 return (STATUS_MORE);
1166 failure:
1167 if (name != NULL)
1168 dns_message_puttempname(updatemsg, &name);
1169 return (STATUS_SYNTAX);
1172 static isc_uint16_t
1173 evaluate_prereq(char *cmdline) {
1174 char *word;
1175 isc_boolean_t ispositive, isrrset;
1177 ddebug("evaluate_prereq()");
1178 word = nsu_strsep(&cmdline, " \t\r\n");
1179 if (*word == 0) {
1180 fprintf(stderr, "could not read operation code\n");
1181 return (STATUS_SYNTAX);
1183 if (strcasecmp(word, "nxdomain") == 0) {
1184 ispositive = ISC_FALSE;
1185 isrrset = ISC_FALSE;
1186 } else if (strcasecmp(word, "yxdomain") == 0) {
1187 ispositive = ISC_TRUE;
1188 isrrset = ISC_FALSE;
1189 } else if (strcasecmp(word, "nxrrset") == 0) {
1190 ispositive = ISC_FALSE;
1191 isrrset = ISC_TRUE;
1192 } else if (strcasecmp(word, "yxrrset") == 0) {
1193 ispositive = ISC_TRUE;
1194 isrrset = ISC_TRUE;
1195 } else {
1196 fprintf(stderr, "incorrect operation code: %s\n", word);
1197 return (STATUS_SYNTAX);
1199 return (make_prereq(cmdline, ispositive, isrrset));
1202 static isc_uint16_t
1203 evaluate_server(char *cmdline) {
1204 char *word, *server;
1205 long port;
1207 word = nsu_strsep(&cmdline, " \t\r\n");
1208 if (*word == 0) {
1209 fprintf(stderr, "could not read server name\n");
1210 return (STATUS_SYNTAX);
1212 server = word;
1214 word = nsu_strsep(&cmdline, " \t\r\n");
1215 if (*word == 0)
1216 port = DNSDEFAULTPORT;
1217 else {
1218 char *endp;
1219 port = strtol(word, &endp, 10);
1220 if (*endp != 0) {
1221 fprintf(stderr, "port '%s' is not numeric\n", word);
1222 return (STATUS_SYNTAX);
1223 } else if (port < 1 || port > 65535) {
1224 fprintf(stderr, "port '%s' is out of range "
1225 "(1 to 65535)\n", word);
1226 return (STATUS_SYNTAX);
1230 if (userserver == NULL) {
1231 userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
1232 if (userserver == NULL)
1233 fatal("out of memory");
1236 get_address(server, (in_port_t)port, userserver);
1238 return (STATUS_MORE);
1241 static isc_uint16_t
1242 evaluate_local(char *cmdline) {
1243 char *word, *local;
1244 long port;
1245 struct in_addr in4;
1246 struct in6_addr in6;
1248 word = nsu_strsep(&cmdline, " \t\r\n");
1249 if (*word == 0) {
1250 fprintf(stderr, "could not read server name\n");
1251 return (STATUS_SYNTAX);
1253 local = word;
1255 word = nsu_strsep(&cmdline, " \t\r\n");
1256 if (*word == 0)
1257 port = 0;
1258 else {
1259 char *endp;
1260 port = strtol(word, &endp, 10);
1261 if (*endp != 0) {
1262 fprintf(stderr, "port '%s' is not numeric\n", word);
1263 return (STATUS_SYNTAX);
1264 } else if (port < 1 || port > 65535) {
1265 fprintf(stderr, "port '%s' is out of range "
1266 "(1 to 65535)\n", word);
1267 return (STATUS_SYNTAX);
1271 if (localaddr == NULL) {
1272 localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
1273 if (localaddr == NULL)
1274 fatal("out of memory");
1277 if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1)
1278 isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port);
1279 else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1)
1280 isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port);
1281 else {
1282 fprintf(stderr, "invalid address %s", local);
1283 return (STATUS_SYNTAX);
1286 return (STATUS_MORE);
1289 static isc_uint16_t
1290 evaluate_key(char *cmdline) {
1291 char *namestr;
1292 char *secretstr;
1293 isc_buffer_t b;
1294 isc_result_t result;
1295 dns_fixedname_t fkeyname;
1296 dns_name_t *keyname;
1297 int secretlen;
1298 unsigned char *secret = NULL;
1299 isc_buffer_t secretbuf;
1300 dns_name_t *hmacname = NULL;
1301 isc_uint16_t digestbits = 0;
1302 char *n;
1304 namestr = nsu_strsep(&cmdline, " \t\r\n");
1305 if (*namestr == 0) {
1306 fprintf(stderr, "could not read key name\n");
1307 return (STATUS_SYNTAX);
1310 dns_fixedname_init(&fkeyname);
1311 keyname = dns_fixedname_name(&fkeyname);
1313 n = strchr(namestr, ':');
1314 if (n != NULL) {
1315 digestbits = parse_hmac(&hmacname, namestr, n - namestr);
1316 namestr = n + 1;
1317 } else
1318 hmacname = DNS_TSIG_HMACMD5_NAME;
1320 isc_buffer_init(&b, namestr, strlen(namestr));
1321 isc_buffer_add(&b, strlen(namestr));
1322 result = dns_name_fromtext(keyname, &b, dns_rootname, ISC_FALSE, NULL);
1323 if (result != ISC_R_SUCCESS) {
1324 fprintf(stderr, "could not parse key name\n");
1325 return (STATUS_SYNTAX);
1328 secretstr = nsu_strsep(&cmdline, "\r\n");
1329 if (*secretstr == 0) {
1330 fprintf(stderr, "could not read key secret\n");
1331 return (STATUS_SYNTAX);
1333 secretlen = strlen(secretstr) * 3 / 4;
1334 secret = isc_mem_allocate(mctx, secretlen);
1335 if (secret == NULL)
1336 fatal("out of memory");
1338 isc_buffer_init(&secretbuf, secret, secretlen);
1339 result = isc_base64_decodestring(secretstr, &secretbuf);
1340 if (result != ISC_R_SUCCESS) {
1341 fprintf(stderr, "could not create key from %s: %s\n",
1342 secretstr, isc_result_totext(result));
1343 isc_mem_free(mctx, secret);
1344 return (STATUS_SYNTAX);
1346 secretlen = isc_buffer_usedlength(&secretbuf);
1348 if (tsigkey != NULL)
1349 dns_tsigkey_detach(&tsigkey);
1350 result = dns_tsigkey_create(keyname, hmacname, secret, secretlen,
1351 ISC_TRUE, NULL, 0, 0, mctx, NULL,
1352 &tsigkey);
1353 isc_mem_free(mctx, secret);
1354 if (result != ISC_R_SUCCESS) {
1355 fprintf(stderr, "could not create key from %s %s: %s\n",
1356 namestr, secretstr, dns_result_totext(result));
1357 return (STATUS_SYNTAX);
1359 dst_key_setbits(tsigkey->key, digestbits);
1360 return (STATUS_MORE);
1363 static isc_uint16_t
1364 evaluate_zone(char *cmdline) {
1365 char *word;
1366 isc_buffer_t b;
1367 isc_result_t result;
1369 word = nsu_strsep(&cmdline, " \t\r\n");
1370 if (*word == 0) {
1371 fprintf(stderr, "could not read zone name\n");
1372 return (STATUS_SYNTAX);
1375 dns_fixedname_init(&fuserzone);
1376 userzone = dns_fixedname_name(&fuserzone);
1377 isc_buffer_init(&b, word, strlen(word));
1378 isc_buffer_add(&b, strlen(word));
1379 result = dns_name_fromtext(userzone, &b, dns_rootname, ISC_FALSE,
1380 NULL);
1381 if (result != ISC_R_SUCCESS) {
1382 userzone = NULL; /* Lest it point to an invalid name */
1383 fprintf(stderr, "could not parse zone name\n");
1384 return (STATUS_SYNTAX);
1387 return (STATUS_MORE);
1390 static isc_uint16_t
1391 evaluate_class(char *cmdline) {
1392 char *word;
1393 isc_textregion_t r;
1394 isc_result_t result;
1395 dns_rdataclass_t rdclass;
1397 word = nsu_strsep(&cmdline, " \t\r\n");
1398 if (*word == 0) {
1399 fprintf(stderr, "could not read class name\n");
1400 return (STATUS_SYNTAX);
1403 r.base = word;
1404 r.length = strlen(word);
1405 result = dns_rdataclass_fromtext(&rdclass, &r);
1406 if (result != ISC_R_SUCCESS) {
1407 fprintf(stderr, "could not parse class name: %s\n", word);
1408 return (STATUS_SYNTAX);
1410 switch (rdclass) {
1411 case dns_rdataclass_none:
1412 case dns_rdataclass_any:
1413 case dns_rdataclass_reserved0:
1414 fprintf(stderr, "bad default class: %s\n", word);
1415 return (STATUS_SYNTAX);
1416 default:
1417 defaultclass = rdclass;
1420 return (STATUS_MORE);
1423 static isc_uint16_t
1424 update_addordelete(char *cmdline, isc_boolean_t isdelete) {
1425 isc_result_t result;
1426 dns_name_t *name = NULL;
1427 isc_uint32_t ttl;
1428 char *word;
1429 dns_rdataclass_t rdataclass;
1430 dns_rdatatype_t rdatatype;
1431 dns_rdata_t *rdata = NULL;
1432 dns_rdatalist_t *rdatalist = NULL;
1433 dns_rdataset_t *rdataset = NULL;
1434 isc_textregion_t region;
1435 isc_uint16_t retval;
1437 ddebug("update_addordelete()");
1440 * Read the owner name.
1442 retval = parse_name(&cmdline, updatemsg, &name);
1443 if (retval != STATUS_MORE)
1444 return (retval);
1446 result = dns_message_gettemprdata(updatemsg, &rdata);
1447 check_result(result, "dns_message_gettemprdata");
1449 rdata->rdclass = 0;
1450 rdata->type = 0;
1451 rdata->data = NULL;
1452 rdata->length = 0;
1455 * If this is an add, read the TTL and verify that it's in range.
1456 * If it's a delete, ignore a TTL if present (for compatibility).
1458 word = nsu_strsep(&cmdline, " \t\r\n");
1459 if (*word == 0) {
1460 if (!isdelete) {
1461 fprintf(stderr, "could not read owner ttl\n");
1462 goto failure;
1464 else {
1465 ttl = 0;
1466 rdataclass = dns_rdataclass_any;
1467 rdatatype = dns_rdatatype_any;
1468 rdata->flags = DNS_RDATA_UPDATE;
1469 goto doneparsing;
1472 result = isc_parse_uint32(&ttl, word, 10);
1473 if (result != ISC_R_SUCCESS) {
1474 if (isdelete) {
1475 ttl = 0;
1476 goto parseclass;
1477 } else {
1478 fprintf(stderr, "ttl '%s': %s\n", word,
1479 isc_result_totext(result));
1480 goto failure;
1484 if (isdelete)
1485 ttl = 0;
1486 else if (ttl > TTL_MAX) {
1487 fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n",
1488 word, TTL_MAX);
1489 goto failure;
1493 * Read the class or type.
1495 word = nsu_strsep(&cmdline, " \t\r\n");
1496 parseclass:
1497 if (*word == 0) {
1498 if (isdelete) {
1499 rdataclass = dns_rdataclass_any;
1500 rdatatype = dns_rdatatype_any;
1501 rdata->flags = DNS_RDATA_UPDATE;
1502 goto doneparsing;
1503 } else {
1504 fprintf(stderr, "could not read class or type\n");
1505 goto failure;
1508 region.base = word;
1509 region.length = strlen(word);
1510 rdataclass = dns_rdataclass_any;
1511 result = dns_rdataclass_fromtext(&rdataclass, &region);
1512 if (result == ISC_R_SUCCESS && rdataclass != dns_rdataclass_any) {
1513 if (!setzoneclass(rdataclass)) {
1514 fprintf(stderr, "class mismatch: %s\n", word);
1515 goto failure;
1518 * Now read the type.
1520 word = nsu_strsep(&cmdline, " \t\r\n");
1521 if (*word == 0) {
1522 if (isdelete) {
1523 rdataclass = dns_rdataclass_any;
1524 rdatatype = dns_rdatatype_any;
1525 rdata->flags = DNS_RDATA_UPDATE;
1526 goto doneparsing;
1527 } else {
1528 fprintf(stderr, "could not read type\n");
1529 goto failure;
1532 region.base = word;
1533 region.length = strlen(word);
1534 result = dns_rdatatype_fromtext(&rdatatype, &region);
1535 if (result != ISC_R_SUCCESS) {
1536 fprintf(stderr, "'%s' is not a valid type: %s\n",
1537 word, isc_result_totext(result));
1538 goto failure;
1540 } else {
1541 rdataclass = getzoneclass();
1542 result = dns_rdatatype_fromtext(&rdatatype, &region);
1543 if (result != ISC_R_SUCCESS) {
1544 fprintf(stderr, "'%s' is not a valid class or type: "
1545 "%s\n", word, isc_result_totext(result));
1546 goto failure;
1550 retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg,
1551 rdata);
1552 if (retval != STATUS_MORE)
1553 goto failure;
1555 if (isdelete) {
1556 if ((rdata->flags & DNS_RDATA_UPDATE) != 0)
1557 rdataclass = dns_rdataclass_any;
1558 else
1559 rdataclass = dns_rdataclass_none;
1560 } else {
1561 if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
1562 fprintf(stderr, "could not read rdata\n");
1563 goto failure;
1567 doneparsing:
1569 result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
1570 check_result(result, "dns_message_gettemprdatalist");
1571 result = dns_message_gettemprdataset(updatemsg, &rdataset);
1572 check_result(result, "dns_message_gettemprdataset");
1573 dns_rdatalist_init(rdatalist);
1574 rdatalist->type = rdatatype;
1575 rdatalist->rdclass = rdataclass;
1576 rdatalist->covers = rdatatype;
1577 rdatalist->ttl = (dns_ttl_t)ttl;
1578 ISC_LIST_INIT(rdatalist->rdata);
1579 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1580 dns_rdataset_init(rdataset);
1581 dns_rdatalist_tordataset(rdatalist, rdataset);
1582 ISC_LIST_INIT(name->list);
1583 ISC_LIST_APPEND(name->list, rdataset, link);
1584 dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE);
1585 return (STATUS_MORE);
1587 failure:
1588 if (name != NULL)
1589 dns_message_puttempname(updatemsg, &name);
1590 dns_message_puttemprdata(updatemsg, &rdata);
1591 return (STATUS_SYNTAX);
1594 static isc_uint16_t
1595 evaluate_update(char *cmdline) {
1596 char *word;
1597 isc_boolean_t isdelete;
1599 ddebug("evaluate_update()");
1600 word = nsu_strsep(&cmdline, " \t\r\n");
1601 if (*word == 0) {
1602 fprintf(stderr, "could not read operation code\n");
1603 return (STATUS_SYNTAX);
1605 if (strcasecmp(word, "delete") == 0)
1606 isdelete = ISC_TRUE;
1607 else if (strcasecmp(word, "add") == 0)
1608 isdelete = ISC_FALSE;
1609 else {
1610 fprintf(stderr, "incorrect operation code: %s\n", word);
1611 return (STATUS_SYNTAX);
1613 return (update_addordelete(cmdline, isdelete));
1616 static void
1617 setzone(dns_name_t *zonename) {
1618 isc_result_t result;
1619 dns_name_t *name = NULL;
1620 dns_rdataset_t *rdataset = NULL;
1622 result = dns_message_firstname(updatemsg, DNS_SECTION_ZONE);
1623 if (result == ISC_R_SUCCESS) {
1624 dns_message_currentname(updatemsg, DNS_SECTION_ZONE, &name);
1625 dns_message_removename(updatemsg, name, DNS_SECTION_ZONE);
1626 for (rdataset = ISC_LIST_HEAD(name->list);
1627 rdataset != NULL;
1628 rdataset = ISC_LIST_HEAD(name->list)) {
1629 ISC_LIST_UNLINK(name->list, rdataset, link);
1630 dns_rdataset_disassociate(rdataset);
1631 dns_message_puttemprdataset(updatemsg, &rdataset);
1633 dns_message_puttempname(updatemsg, &name);
1636 if (zonename != NULL) {
1637 result = dns_message_gettempname(updatemsg, &name);
1638 check_result(result, "dns_message_gettempname");
1639 dns_name_init(name, NULL);
1640 dns_name_clone(zonename, name);
1641 result = dns_message_gettemprdataset(updatemsg, &rdataset);
1642 check_result(result, "dns_message_gettemprdataset");
1643 dns_rdataset_makequestion(rdataset, getzoneclass(),
1644 dns_rdatatype_soa);
1645 ISC_LIST_INIT(name->list);
1646 ISC_LIST_APPEND(name->list, rdataset, link);
1647 dns_message_addname(updatemsg, name, DNS_SECTION_ZONE);
1651 static void
1652 show_message(FILE *stream, dns_message_t *msg, const char *description) {
1653 isc_result_t result;
1654 isc_buffer_t *buf = NULL;
1655 int bufsz;
1657 ddebug("show_message()");
1659 setzone(userzone);
1661 bufsz = INITTEXT;
1662 do {
1663 if (bufsz > MAXTEXT) {
1664 fprintf(stderr, "could not allocate large enough "
1665 "buffer to display message\n");
1666 exit(1);
1668 if (buf != NULL)
1669 isc_buffer_free(&buf);
1670 result = isc_buffer_allocate(mctx, &buf, bufsz);
1671 check_result(result, "isc_buffer_allocate");
1672 result = dns_message_totext(msg, style, 0, buf);
1673 bufsz *= 2;
1674 } while (result == ISC_R_NOSPACE);
1675 if (result != ISC_R_SUCCESS) {
1676 fprintf(stderr, "could not convert message to text format.\n");
1677 isc_buffer_free(&buf);
1678 return;
1680 fprintf(stream, "%s\n%.*s", description,
1681 (int)isc_buffer_usedlength(buf), (char*)isc_buffer_base(buf));
1682 isc_buffer_free(&buf);
1686 static isc_uint16_t
1687 get_next_command(void) {
1688 char cmdlinebuf[MAXCMD];
1689 char *cmdline;
1690 char *word;
1692 ddebug("get_next_command()");
1693 if (interactive) {
1694 fprintf(stdout, "> ");
1695 fflush(stdout);
1697 isc_app_block();
1698 cmdline = fgets(cmdlinebuf, MAXCMD, input);
1699 isc_app_unblock();
1700 if (cmdline == NULL)
1701 return (STATUS_QUIT);
1702 word = nsu_strsep(&cmdline, " \t\r\n");
1704 if (feof(input))
1705 return (STATUS_QUIT);
1706 if (*word == 0)
1707 return (STATUS_SEND);
1708 if (word[0] == ';')
1709 return (STATUS_MORE);
1710 if (strcasecmp(word, "quit") == 0)
1711 return (STATUS_QUIT);
1712 if (strcasecmp(word, "prereq") == 0)
1713 return (evaluate_prereq(cmdline));
1714 if (strcasecmp(word, "update") == 0)
1715 return (evaluate_update(cmdline));
1716 if (strcasecmp(word, "server") == 0)
1717 return (evaluate_server(cmdline));
1718 if (strcasecmp(word, "local") == 0)
1719 return (evaluate_local(cmdline));
1720 if (strcasecmp(word, "zone") == 0)
1721 return (evaluate_zone(cmdline));
1722 if (strcasecmp(word, "class") == 0)
1723 return (evaluate_class(cmdline));
1724 if (strcasecmp(word, "send") == 0)
1725 return (STATUS_SEND);
1726 if (strcasecmp(word, "show") == 0) {
1727 show_message(stdout, updatemsg, "Outgoing update query:");
1728 return (STATUS_MORE);
1730 if (strcasecmp(word, "answer") == 0) {
1731 if (answer != NULL)
1732 show_message(stdout, answer, "Answer:");
1733 return (STATUS_MORE);
1735 if (strcasecmp(word, "key") == 0) {
1736 usegsstsig = ISC_FALSE;
1737 return (evaluate_key(cmdline));
1739 if (strcasecmp(word, "gsstsig") == 0) {
1740 #ifdef GSSAPI
1741 usegsstsig = ISC_TRUE;
1742 use_win2k_gsstsig = ISC_FALSE;
1743 #else
1744 fprintf(stderr, "gsstsig not supported\n");
1745 #endif
1746 return (STATUS_MORE);
1748 if (strcasecmp(word, "oldgsstsig") == 0) {
1749 #ifdef GSSAPI
1750 usegsstsig = ISC_TRUE;
1751 use_win2k_gsstsig = ISC_TRUE;
1752 #else
1753 fprintf(stderr, "gsstsig not supported\n");
1754 #endif
1755 return (STATUS_MORE);
1757 if (strcasecmp(word, "help") == 0) {
1758 fprintf(stdout,
1759 "local address [port] (set local resolver)\n"
1760 "server address [port] (set master server for zone)\n"
1761 "send (send the update request)\n"
1762 "show (show the update request)\n"
1763 "answer (show the answer to the last request)\n"
1764 "quit (quit, any pending update is not sent\n"
1765 "help (display this message_\n"
1766 "key [hmac:]keyname secret (use TSIG to sign the request)\n"
1767 "gsstsig (use GSS_TSIG to sign the request)\n"
1768 "oldgsstsig (use Microsoft's GSS_TSIG to sign the request)\n"
1769 "zone name (set the zone to be updated)\n"
1770 "class CLASS (set the zone's DNS class, e.g. IN (default), CH)\n"
1771 "prereq nxdomain name (does this name not exist)\n"
1772 "prereq yxdomain name (does this name exist)\n"
1773 "prereq nxrrset .... (does this RRset exist)\n"
1774 "prereq yxrrset .... (does this RRset not exist)\n"
1775 "update add .... (add the given record to the zone)\n"
1776 "update delete .... (remove the given record(s) from the zone)\n");
1777 return (STATUS_MORE);
1779 fprintf(stderr, "incorrect section name: %s\n", word);
1780 return (STATUS_SYNTAX);
1783 static isc_boolean_t
1784 user_interaction(void) {
1785 isc_uint16_t result = STATUS_MORE;
1787 ddebug("user_interaction()");
1788 while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) {
1789 result = get_next_command();
1790 if (!interactive && result == STATUS_SYNTAX)
1791 fatal("syntax error");
1793 if (result == STATUS_SEND)
1794 return (ISC_TRUE);
1795 return (ISC_FALSE);
1799 static void
1800 done_update(void) {
1801 isc_event_t *event = global_event;
1802 ddebug("done_update()");
1803 isc_task_send(global_task, &event);
1806 static void
1807 check_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) {
1808 isc_result_t result;
1809 dns_rdata_t rdata = DNS_RDATA_INIT;
1810 dns_rdata_any_tsig_t tsig;
1812 result = dns_rdataset_first(rdataset);
1813 check_result(result, "dns_rdataset_first");
1814 dns_rdataset_current(rdataset, &rdata);
1815 result = dns_rdata_tostruct(&rdata, &tsig, NULL);
1816 check_result(result, "dns_rdata_tostruct");
1817 if (tsig.error != 0) {
1818 if (isc_buffer_remaininglength(b) < 1)
1819 check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
1820 isc__buffer_putstr(b, "(" /*)*/);
1821 result = dns_tsigrcode_totext(tsig.error, b);
1822 check_result(result, "dns_tsigrcode_totext");
1823 if (isc_buffer_remaininglength(b) < 1)
1824 check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
1825 isc__buffer_putstr(b, /*(*/ ")");
1829 static void
1830 update_completed(isc_task_t *task, isc_event_t *event) {
1831 dns_requestevent_t *reqev = NULL;
1832 isc_result_t result;
1833 dns_request_t *request;
1835 UNUSED(task);
1837 ddebug("update_completed()");
1839 requests--;
1841 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1842 reqev = (dns_requestevent_t *)event;
1843 request = reqev->request;
1845 if (shuttingdown) {
1846 dns_request_destroy(&request);
1847 isc_event_free(&event);
1848 maybeshutdown();
1849 return;
1852 if (reqev->result != ISC_R_SUCCESS) {
1853 fprintf(stderr, "; Communication with server failed: %s\n",
1854 isc_result_totext(reqev->result));
1855 seenerror = ISC_TRUE;
1856 goto done;
1859 result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer);
1860 check_result(result, "dns_message_create");
1861 result = dns_request_getresponse(request, answer,
1862 DNS_MESSAGEPARSE_PRESERVEORDER);
1863 switch (result) {
1864 case ISC_R_SUCCESS:
1865 if (answer->verify_attempted)
1866 ddebug("tsig verification successful");
1867 break;
1868 case DNS_R_CLOCKSKEW:
1869 case DNS_R_EXPECTEDTSIG:
1870 case DNS_R_TSIGERRORSET:
1871 case DNS_R_TSIGVERIFYFAILURE:
1872 case DNS_R_UNEXPECTEDTSIG:
1873 case ISC_R_FAILURE:
1874 #if 0
1875 if (usegsstsig && answer->rcode == dns_rcode_noerror) {
1877 * For MS DNS that violates RFC 2845, section 4.2
1879 break;
1881 #endif
1882 fprintf(stderr, "; TSIG error with server: %s\n",
1883 isc_result_totext(result));
1884 seenerror = ISC_TRUE;
1885 break;
1886 default:
1887 check_result(result, "dns_request_getresponse");
1890 if (answer->rcode != dns_rcode_noerror) {
1891 seenerror = ISC_TRUE;
1892 if (!debugging) {
1893 char buf[64];
1894 isc_buffer_t b;
1895 dns_rdataset_t *rds;
1897 isc_buffer_init(&b, buf, sizeof(buf) - 1);
1898 result = dns_rcode_totext(answer->rcode, &b);
1899 check_result(result, "dns_rcode_totext");
1900 rds = dns_message_gettsig(answer, NULL);
1901 if (rds != NULL)
1902 check_tsig_error(rds, &b);
1903 fprintf(stderr, "update failed: %.*s\n",
1904 (int)isc_buffer_usedlength(&b), buf);
1907 if (debugging)
1908 show_message(stderr, answer, "\nReply from update query:");
1910 done:
1911 dns_request_destroy(&request);
1912 if (usegsstsig) {
1913 dns_name_free(&tmpzonename, mctx);
1914 dns_name_free(&restart_master, mctx);
1916 isc_event_free(&event);
1917 done_update();
1920 static void
1921 send_update(dns_name_t *zonename, isc_sockaddr_t *master,
1922 isc_sockaddr_t *srcaddr)
1924 isc_result_t result;
1925 dns_request_t *request = NULL;
1926 unsigned int options = 0;
1928 ddebug("send_update()");
1930 setzone(zonename);
1932 if (usevc)
1933 options |= DNS_REQUESTOPT_TCP;
1934 if (tsigkey == NULL && sig0key != NULL) {
1935 result = dns_message_setsig0key(updatemsg, sig0key);
1936 check_result(result, "dns_message_setsig0key");
1938 if (debugging) {
1939 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
1941 isc_sockaddr_format(master, addrbuf, sizeof(addrbuf));
1942 fprintf(stderr, "Sending update to %s\n", addrbuf);
1945 result = dns_request_createvia3(requestmgr, updatemsg, srcaddr,
1946 master, options, tsigkey, timeout,
1947 udp_timeout, udp_retries, global_task,
1948 update_completed, NULL, &request);
1949 check_result(result, "dns_request_createvia3");
1951 if (debugging)
1952 show_message(stdout, updatemsg, "Outgoing update query:");
1954 requests++;
1957 static void
1958 recvsoa(isc_task_t *task, isc_event_t *event) {
1959 dns_requestevent_t *reqev = NULL;
1960 dns_request_t *request = NULL;
1961 isc_result_t result, eresult;
1962 dns_message_t *rcvmsg = NULL;
1963 dns_section_t section;
1964 dns_name_t *name = NULL;
1965 dns_rdataset_t *soaset = NULL;
1966 dns_rdata_soa_t soa;
1967 dns_rdata_t soarr = DNS_RDATA_INIT;
1968 int pass = 0;
1969 dns_name_t master;
1970 nsu_requestinfo_t *reqinfo;
1971 dns_message_t *soaquery = NULL;
1972 isc_sockaddr_t *addr;
1973 isc_boolean_t seencname = ISC_FALSE;
1974 dns_name_t tname;
1975 unsigned int nlabels;
1977 UNUSED(task);
1979 ddebug("recvsoa()");
1981 requests--;
1983 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1984 reqev = (dns_requestevent_t *)event;
1985 request = reqev->request;
1986 eresult = reqev->result;
1987 reqinfo = reqev->ev_arg;
1988 soaquery = reqinfo->msg;
1989 addr = reqinfo->addr;
1991 if (shuttingdown) {
1992 dns_request_destroy(&request);
1993 dns_message_destroy(&soaquery);
1994 isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
1995 isc_event_free(&event);
1996 maybeshutdown();
1997 return;
2000 if (eresult != ISC_R_SUCCESS) {
2001 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
2003 isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
2004 fprintf(stderr, "; Communication with %s failed: %s\n",
2005 addrbuf, isc_result_totext(eresult));
2006 if (userserver != NULL)
2007 fatal("could not talk to specified name server");
2008 else if (++ns_inuse >= lwconf->nsnext)
2009 fatal("could not talk to any default name server");
2010 ddebug("Destroying request [%p]", request);
2011 dns_request_destroy(&request);
2012 dns_message_renderreset(soaquery);
2013 dns_message_settsigkey(soaquery, NULL);
2014 sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
2015 isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
2016 isc_event_free(&event);
2017 setzoneclass(dns_rdataclass_none);
2018 return;
2021 isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
2022 reqinfo = NULL;
2023 isc_event_free(&event);
2024 reqev = NULL;
2026 ddebug("About to create rcvmsg");
2027 result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
2028 check_result(result, "dns_message_create");
2029 result = dns_request_getresponse(request, rcvmsg,
2030 DNS_MESSAGEPARSE_PRESERVEORDER);
2031 if (result == DNS_R_TSIGERRORSET && userserver != NULL) {
2032 dns_message_destroy(&rcvmsg);
2033 ddebug("Destroying request [%p]", request);
2034 dns_request_destroy(&request);
2035 reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t));
2036 if (reqinfo == NULL)
2037 fatal("out of memory");
2038 reqinfo->msg = soaquery;
2039 reqinfo->addr = addr;
2040 dns_message_renderreset(soaquery);
2041 ddebug("retrying soa request without TSIG");
2042 result = dns_request_createvia3(requestmgr, soaquery,
2043 localaddr, addr, 0, NULL,
2044 FIND_TIMEOUT * 20,
2045 FIND_TIMEOUT, 3,
2046 global_task, recvsoa, reqinfo,
2047 &request);
2048 check_result(result, "dns_request_createvia");
2049 requests++;
2050 return;
2052 check_result(result, "dns_request_getresponse");
2053 section = DNS_SECTION_ANSWER;
2054 if (debugging)
2055 show_message(stderr, rcvmsg, "Reply from SOA query:");
2057 if (rcvmsg->rcode != dns_rcode_noerror &&
2058 rcvmsg->rcode != dns_rcode_nxdomain)
2059 fatal("response to SOA query was unsuccessful");
2061 if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) {
2062 char namebuf[DNS_NAME_FORMATSIZE];
2063 dns_name_format(userzone, namebuf, sizeof(namebuf));
2064 error("specified zone '%s' does not exist (NXDOMAIN)",
2065 namebuf);
2066 dns_message_destroy(&rcvmsg);
2067 dns_request_destroy(&request);
2068 dns_message_destroy(&soaquery);
2069 ddebug("Out of recvsoa");
2070 done_update();
2071 return;
2074 lookforsoa:
2075 if (pass == 0)
2076 section = DNS_SECTION_ANSWER;
2077 else if (pass == 1)
2078 section = DNS_SECTION_AUTHORITY;
2079 else
2080 goto droplabel;
2082 result = dns_message_firstname(rcvmsg, section);
2083 if (result != ISC_R_SUCCESS) {
2084 pass++;
2085 goto lookforsoa;
2087 while (result == ISC_R_SUCCESS) {
2088 name = NULL;
2089 dns_message_currentname(rcvmsg, section, &name);
2090 soaset = NULL;
2091 result = dns_message_findtype(name, dns_rdatatype_soa, 0,
2092 &soaset);
2093 if (result == ISC_R_SUCCESS)
2094 break;
2095 if (section == DNS_SECTION_ANSWER) {
2096 dns_rdataset_t *tset = NULL;
2097 if (dns_message_findtype(name, dns_rdatatype_cname, 0,
2098 &tset) == ISC_R_SUCCESS ||
2099 dns_message_findtype(name, dns_rdatatype_dname, 0,
2100 &tset) == ISC_R_SUCCESS ) {
2101 seencname = ISC_TRUE;
2102 break;
2106 result = dns_message_nextname(rcvmsg, section);
2109 if (soaset == NULL && !seencname) {
2110 pass++;
2111 goto lookforsoa;
2114 if (seencname)
2115 goto droplabel;
2117 if (debugging) {
2118 char namestr[DNS_NAME_FORMATSIZE];
2119 dns_name_format(name, namestr, sizeof(namestr));
2120 fprintf(stderr, "Found zone name: %s\n", namestr);
2123 result = dns_rdataset_first(soaset);
2124 check_result(result, "dns_rdataset_first");
2126 dns_rdata_init(&soarr);
2127 dns_rdataset_current(soaset, &soarr);
2128 result = dns_rdata_tostruct(&soarr, &soa, NULL);
2129 check_result(result, "dns_rdata_tostruct");
2131 dns_name_init(&master, NULL);
2132 dns_name_clone(&soa.origin, &master);
2134 if (userzone != NULL)
2135 zonename = userzone;
2136 else
2137 zonename = name;
2139 if (debugging) {
2140 char namestr[DNS_NAME_FORMATSIZE];
2141 dns_name_format(&master, namestr, sizeof(namestr));
2142 fprintf(stderr, "The master is: %s\n", namestr);
2145 if (userserver != NULL)
2146 serveraddr = userserver;
2147 else {
2148 char serverstr[DNS_NAME_MAXTEXT+1];
2149 isc_buffer_t buf;
2151 isc_buffer_init(&buf, serverstr, sizeof(serverstr));
2152 result = dns_name_totext(&master, ISC_TRUE, &buf);
2153 check_result(result, "dns_name_totext");
2154 serverstr[isc_buffer_usedlength(&buf)] = 0;
2155 get_address(serverstr, DNSDEFAULTPORT, &tempaddr);
2156 serveraddr = &tempaddr;
2158 dns_rdata_freestruct(&soa);
2160 #ifdef GSSAPI
2161 if (usegsstsig) {
2162 dns_name_init(&tmpzonename, NULL);
2163 dns_name_dup(zonename, mctx, &tmpzonename);
2164 dns_name_init(&restart_master, NULL);
2165 dns_name_dup(&master, mctx, &restart_master);
2166 start_gssrequest(&master);
2167 } else {
2168 send_update(zonename, serveraddr, localaddr);
2169 setzoneclass(dns_rdataclass_none);
2171 #else
2172 send_update(zonename, serveraddr, localaddr);
2173 setzoneclass(dns_rdataclass_none);
2174 #endif
2176 dns_message_destroy(&soaquery);
2177 dns_request_destroy(&request);
2179 out:
2180 dns_message_destroy(&rcvmsg);
2181 ddebug("Out of recvsoa");
2182 return;
2184 droplabel:
2185 result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
2186 INSIST(result == ISC_R_SUCCESS);
2187 name = NULL;
2188 dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
2189 nlabels = dns_name_countlabels(name);
2190 if (nlabels == 1)
2191 fatal("could not find enclosing zone");
2192 dns_name_init(&tname, NULL);
2193 dns_name_getlabelsequence(name, 1, nlabels - 1, &tname);
2194 dns_name_clone(&tname, name);
2195 dns_request_destroy(&request);
2196 dns_message_renderreset(soaquery);
2197 dns_message_settsigkey(soaquery, NULL);
2198 if (userserver != NULL)
2199 sendrequest(localaddr, userserver, soaquery, &request);
2200 else
2201 sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
2202 goto out;
2205 static void
2206 sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
2207 dns_message_t *msg, dns_request_t **request)
2209 isc_result_t result;
2210 nsu_requestinfo_t *reqinfo;
2212 reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t));
2213 if (reqinfo == NULL)
2214 fatal("out of memory");
2215 reqinfo->msg = msg;
2216 reqinfo->addr = destaddr;
2217 result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0,
2218 (userserver != NULL) ? tsigkey : NULL,
2219 FIND_TIMEOUT * 20, FIND_TIMEOUT, 3,
2220 global_task, recvsoa, reqinfo, request);
2221 check_result(result, "dns_request_createvia");
2222 requests++;
2225 #ifdef GSSAPI
2226 static void
2227 start_gssrequest(dns_name_t *master)
2229 gss_ctx_id_t context;
2230 isc_buffer_t buf;
2231 isc_result_t result;
2232 isc_uint32_t val = 0;
2233 dns_message_t *rmsg;
2234 dns_request_t *request = NULL;
2235 dns_name_t *servname;
2236 dns_fixedname_t fname;
2237 char namestr[DNS_NAME_FORMATSIZE];
2238 char keystr[DNS_NAME_FORMATSIZE];
2240 debug("start_gssrequest");
2241 usevc = ISC_TRUE;
2243 if (gssring != NULL)
2244 dns_tsigkeyring_destroy(&gssring);
2245 gssring = NULL;
2246 result = dns_tsigkeyring_create(mctx, &gssring);
2248 if (result != ISC_R_SUCCESS)
2249 fatal("dns_tsigkeyring_create failed: %s",
2250 isc_result_totext(result));
2252 dns_name_format(master, namestr, sizeof(namestr));
2253 if (kserver == NULL) {
2254 kserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
2255 if (kserver == NULL)
2256 fatal("out of memory");
2258 if (userserver == NULL)
2259 get_address(namestr, DNSDEFAULTPORT, kserver);
2260 else
2261 (void)memcpy(kserver, userserver, sizeof(isc_sockaddr_t));
2263 dns_fixedname_init(&fname);
2264 servname = dns_fixedname_name(&fname);
2266 result = isc_string_printf(servicename, sizeof(servicename),
2267 "DNS/%s", namestr);
2268 if (result != ISC_R_SUCCESS)
2269 fatal("isc_string_printf(servicename) failed: %s",
2270 isc_result_totext(result));
2271 isc_buffer_init(&buf, servicename, strlen(servicename));
2272 isc_buffer_add(&buf, strlen(servicename));
2273 result = dns_name_fromtext(servname, &buf, dns_rootname,
2274 ISC_FALSE, NULL);
2275 if (result != ISC_R_SUCCESS)
2276 fatal("dns_name_fromtext(servname) failed: %s",
2277 isc_result_totext(result));
2279 dns_fixedname_init(&fkname);
2280 keyname = dns_fixedname_name(&fkname);
2282 isc_random_get(&val);
2283 result = isc_string_printf(keystr, sizeof(keystr), "%u.sig-%s",
2284 val, namestr);
2285 if (result != ISC_R_SUCCESS)
2286 fatal("isc_string_printf(keystr) failed: %s",
2287 isc_result_totext(result));
2288 isc_buffer_init(&buf, keystr, strlen(keystr));
2289 isc_buffer_add(&buf, strlen(keystr));
2291 result = dns_name_fromtext(keyname, &buf, dns_rootname,
2292 ISC_FALSE, NULL);
2293 if (result != ISC_R_SUCCESS)
2294 fatal("dns_name_fromtext(keyname) failed: %s",
2295 isc_result_totext(result));
2297 /* Windows doesn't recognize name compression in the key name. */
2298 keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
2300 rmsg = NULL;
2301 result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &rmsg);
2302 if (result != ISC_R_SUCCESS)
2303 fatal("dns_message_create failed: %s",
2304 isc_result_totext(result));
2306 /* Build first request. */
2308 context = GSS_C_NO_CONTEXT;
2309 result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0,
2310 &context, use_win2k_gsstsig);
2311 if (result == ISC_R_FAILURE)
2312 fatal("Check your Kerberos ticket, it may have expired.");
2313 if (result != ISC_R_SUCCESS)
2314 fatal("dns_tkey_buildgssquery failed: %s",
2315 isc_result_totext(result));
2317 send_gssrequest(localaddr, kserver, rmsg, &request, context);
2320 static void
2321 send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
2322 dns_message_t *msg, dns_request_t **request,
2323 gss_ctx_id_t context)
2325 isc_result_t result;
2326 nsu_gssinfo_t *reqinfo;
2327 unsigned int options = 0;
2329 debug("send_gssrequest");
2330 reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t));
2331 if (reqinfo == NULL)
2332 fatal("out of memory");
2333 reqinfo->msg = msg;
2334 reqinfo->addr = destaddr;
2335 reqinfo->context = context;
2337 options |= DNS_REQUESTOPT_TCP;
2338 result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr,
2339 options, tsigkey, FIND_TIMEOUT * 20,
2340 FIND_TIMEOUT, 3, global_task, recvgss,
2341 reqinfo, request);
2342 check_result(result, "dns_request_createvia3");
2343 if (debugging)
2344 show_message(stdout, msg, "Outgoing update query:");
2345 requests++;
2348 static void
2349 recvgss(isc_task_t *task, isc_event_t *event) {
2350 dns_requestevent_t *reqev = NULL;
2351 dns_request_t *request = NULL;
2352 isc_result_t result, eresult;
2353 dns_message_t *rcvmsg = NULL;
2354 nsu_gssinfo_t *reqinfo;
2355 dns_message_t *tsigquery = NULL;
2356 isc_sockaddr_t *addr;
2357 gss_ctx_id_t context;
2358 isc_buffer_t buf;
2359 dns_name_t *servname;
2360 dns_fixedname_t fname;
2362 UNUSED(task);
2364 ddebug("recvgss()");
2366 requests--;
2368 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2369 reqev = (dns_requestevent_t *)event;
2370 request = reqev->request;
2371 eresult = reqev->result;
2372 reqinfo = reqev->ev_arg;
2373 tsigquery = reqinfo->msg;
2374 context = reqinfo->context;
2375 addr = reqinfo->addr;
2377 if (shuttingdown) {
2378 dns_request_destroy(&request);
2379 dns_message_destroy(&tsigquery);
2380 isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
2381 isc_event_free(&event);
2382 maybeshutdown();
2383 return;
2386 if (eresult != ISC_R_SUCCESS) {
2387 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
2389 isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
2390 fprintf(stderr, "; Communication with %s failed: %s\n",
2391 addrbuf, isc_result_totext(eresult));
2392 if (userserver != NULL)
2393 fatal("could not talk to specified name server");
2394 else if (++ns_inuse >= lwconf->nsnext)
2395 fatal("could not talk to any default name server");
2396 ddebug("Destroying request [%p]", request);
2397 dns_request_destroy(&request);
2398 dns_message_renderreset(tsigquery);
2399 sendrequest(localaddr, &servers[ns_inuse], tsigquery,
2400 &request);
2401 isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
2402 isc_event_free(&event);
2403 return;
2405 isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
2407 isc_event_free(&event);
2408 reqev = NULL;
2410 ddebug("recvgss creating rcvmsg");
2411 result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
2412 check_result(result, "dns_message_create");
2414 result = dns_request_getresponse(request, rcvmsg,
2415 DNS_MESSAGEPARSE_PRESERVEORDER);
2416 check_result(result, "dns_request_getresponse");
2418 if (debugging)
2419 show_message(stderr, rcvmsg,
2420 "recvmsg reply from GSS-TSIG query");
2422 if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) {
2423 ddebug("recvgss trying %s GSS-TSIG",
2424 use_win2k_gsstsig ? "Standard" : "Win2k");
2425 if (use_win2k_gsstsig)
2426 use_win2k_gsstsig = ISC_FALSE;
2427 else
2428 use_win2k_gsstsig = ISC_TRUE;
2429 tried_other_gsstsig = ISC_TRUE;
2430 start_gssrequest(&restart_master);
2431 goto done;
2434 if (rcvmsg->rcode != dns_rcode_noerror &&
2435 rcvmsg->rcode != dns_rcode_nxdomain)
2436 fatal("response to GSS-TSIG query was unsuccessful");
2439 dns_fixedname_init(&fname);
2440 servname = dns_fixedname_name(&fname);
2441 isc_buffer_init(&buf, servicename, strlen(servicename));
2442 isc_buffer_add(&buf, strlen(servicename));
2443 result = dns_name_fromtext(servname, &buf, dns_rootname,
2444 ISC_FALSE, NULL);
2445 check_result(result, "dns_name_fromtext");
2447 tsigkey = NULL;
2448 result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname,
2449 &context, &tsigkey, gssring,
2450 use_win2k_gsstsig);
2451 switch (result) {
2453 case DNS_R_CONTINUE:
2454 send_gssrequest(localaddr, kserver, tsigquery, &request,
2455 context);
2456 break;
2458 case ISC_R_SUCCESS:
2460 * XXXSRA Waaay too much fun here. There's no good
2461 * reason why we need a TSIG here (the people who put
2462 * it into the spec admitted at the time that it was
2463 * not a security issue), and Windows clients don't
2464 * seem to work if named complies with the spec and
2465 * includes the gratuitous TSIG. So we're in the
2466 * bizarre situation of having to choose between
2467 * complying with a useless requirement in the spec
2468 * and interoperating. This is nuts. If we can
2469 * confirm this behavior, we should ask the WG to
2470 * consider removing the requirement for the
2471 * gratuitous TSIG here. For the moment, we ignore
2472 * the TSIG -- this too is a spec violation, but it's
2473 * the least insane thing to do.
2475 #if 0
2477 * Verify the signature.
2479 rcvmsg->state = DNS_SECTION_ANY;
2480 dns_message_setquerytsig(rcvmsg, NULL);
2481 result = dns_message_settsigkey(rcvmsg, tsigkey);
2482 check_result(result, "dns_message_settsigkey");
2483 result = dns_message_checksig(rcvmsg, NULL);
2484 ddebug("tsig verification: %s", dns_result_totext(result));
2485 check_result(result, "dns_message_checksig");
2486 #endif /* 0 */
2488 send_update(&tmpzonename, serveraddr, localaddr);
2489 setzoneclass(dns_rdataclass_none);
2490 break;
2492 default:
2493 fatal("dns_tkey_negotiategss: %s", isc_result_totext(result));
2496 done:
2497 dns_request_destroy(&request);
2498 dns_message_destroy(&tsigquery);
2500 dns_message_destroy(&rcvmsg);
2501 ddebug("Out of recvgss");
2503 #endif
2505 static void
2506 start_update(void) {
2507 isc_result_t result;
2508 dns_rdataset_t *rdataset = NULL;
2509 dns_name_t *name = NULL;
2510 dns_request_t *request = NULL;
2511 dns_message_t *soaquery = NULL;
2512 dns_name_t *firstname;
2513 dns_section_t section = DNS_SECTION_UPDATE;
2515 ddebug("start_update()");
2517 if (answer != NULL)
2518 dns_message_destroy(&answer);
2520 if (userzone != NULL && userserver != NULL && ! usegsstsig) {
2521 send_update(userzone, userserver, localaddr);
2522 setzoneclass(dns_rdataclass_none);
2523 return;
2526 result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
2527 &soaquery);
2528 check_result(result, "dns_message_create");
2530 if (userserver == NULL)
2531 soaquery->flags |= DNS_MESSAGEFLAG_RD;
2533 result = dns_message_gettempname(soaquery, &name);
2534 check_result(result, "dns_message_gettempname");
2536 result = dns_message_gettemprdataset(soaquery, &rdataset);
2537 check_result(result, "dns_message_gettemprdataset");
2539 dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa);
2541 if (userzone != NULL) {
2542 dns_name_init(name, NULL);
2543 dns_name_clone(userzone, name);
2544 } else {
2545 result = dns_message_firstname(updatemsg, section);
2546 if (result == ISC_R_NOMORE) {
2547 section = DNS_SECTION_PREREQUISITE;
2548 result = dns_message_firstname(updatemsg, section);
2550 if (result != ISC_R_SUCCESS) {
2551 dns_message_puttempname(soaquery, &name);
2552 dns_rdataset_disassociate(rdataset);
2553 dns_message_puttemprdataset(soaquery, &rdataset);
2554 dns_message_destroy(&soaquery);
2555 done_update();
2556 return;
2558 firstname = NULL;
2559 dns_message_currentname(updatemsg, section, &firstname);
2560 dns_name_init(name, NULL);
2561 dns_name_clone(firstname, name);
2564 ISC_LIST_INIT(name->list);
2565 ISC_LIST_APPEND(name->list, rdataset, link);
2566 dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
2568 if (userserver != NULL)
2569 sendrequest(localaddr, userserver, soaquery, &request);
2570 else {
2571 ns_inuse = 0;
2572 sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
2576 static void
2577 cleanup(void) {
2578 ddebug("cleanup()");
2580 if (answer != NULL)
2581 dns_message_destroy(&answer);
2583 #ifdef GSSAPI
2584 if (tsigkey != NULL) {
2585 ddebug("detach tsigkey x%p", tsigkey);
2586 dns_tsigkey_detach(&tsigkey);
2588 if (gssring != NULL) {
2589 ddebug("Destroying GSS-TSIG keyring");
2590 dns_tsigkeyring_destroy(&gssring);
2592 if (kserver != NULL) {
2593 isc_mem_put(mctx, kserver, sizeof(isc_sockaddr_t));
2594 kserver = NULL;
2596 #endif
2598 ddebug("Shutting down task manager");
2599 isc_taskmgr_destroy(&taskmgr);
2601 ddebug("Destroying event");
2602 isc_event_free(&global_event);
2604 ddebug("Shutting down socket manager");
2605 isc_socketmgr_destroy(&socketmgr);
2607 ddebug("Shutting down timer manager");
2608 isc_timermgr_destroy(&timermgr);
2610 ddebug("Destroying hash context");
2611 isc_hash_destroy();
2613 ddebug("Destroying name state");
2614 dns_name_destroy();
2616 ddebug("Removing log context");
2617 isc_log_destroy(&lctx);
2619 ddebug("Destroying memory context");
2620 if (memdebugging)
2621 isc_mem_stats(mctx, stderr);
2622 isc_mem_destroy(&mctx);
2625 static void
2626 getinput(isc_task_t *task, isc_event_t *event) {
2627 isc_boolean_t more;
2629 UNUSED(task);
2631 if (shuttingdown) {
2632 maybeshutdown();
2633 return;
2636 if (global_event == NULL)
2637 global_event = event;
2639 reset_system();
2640 more = user_interaction();
2641 if (!more) {
2642 isc_app_shutdown();
2643 return;
2645 start_update();
2646 return;
2650 main(int argc, char **argv) {
2651 isc_result_t result;
2652 style = &dns_master_style_debug;
2654 input = stdin;
2656 interactive = ISC_TF(isatty(0));
2658 isc_app_start();
2660 pre_parse_args(argc, argv);
2662 result = isc_mem_create(0, 0, &mctx);
2663 check_result(result, "isc_mem_create");
2665 parse_args(argc, argv, mctx, &entropy);
2667 setup_system();
2669 result = isc_app_onrun(mctx, global_task, getinput, NULL);
2670 check_result(result, "isc_app_onrun");
2672 (void)isc_app_run();
2674 cleanup();
2676 isc_app_finish();
2678 if (seenerror)
2679 return (2);
2680 else
2681 return (0);