]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/contrib/bind9/bin/nsupdate/nsupdate.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / 6 / contrib / bind9 / bin / nsupdate / nsupdate.c
1 /*
2  * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000-2003  Internet Software Consortium.
4  *
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.
8  *
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.
16  */
17
18 /* $Id: nsupdate.c,v 1.103.2.15.2.30 2008/01/17 23:45:27 tbox Exp $ */
19
20 #include <config.h>
21
22 #include <ctype.h>
23 #include <errno.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27
28 #include <isc/app.h>
29 #include <isc/base64.h>
30 #include <isc/buffer.h>
31 #include <isc/commandline.h>
32 #include <isc/entropy.h>
33 #include <isc/event.h>
34 #include <isc/hash.h>
35 #include <isc/lex.h>
36 #include <isc/mem.h>
37 #include <isc/parseint.h>
38 #include <isc/region.h>
39 #include <isc/sockaddr.h>
40 #include <isc/socket.h>
41 #include <isc/stdio.h>
42 #include <isc/string.h>
43 #include <isc/task.h>
44 #include <isc/timer.h>
45 #include <isc/types.h>
46 #include <isc/util.h>
47
48 #include <dns/callbacks.h>
49 #include <dns/dispatch.h>
50 #include <dns/dnssec.h>
51 #include <dns/events.h>
52 #include <dns/fixedname.h>
53 #include <dns/masterdump.h>
54 #include <dns/message.h>
55 #include <dns/name.h>
56 #include <dns/rcode.h>
57 #include <dns/rdata.h>
58 #include <dns/rdataclass.h>
59 #include <dns/rdatalist.h>
60 #include <dns/rdataset.h>
61 #include <dns/rdatastruct.h>
62 #include <dns/rdatatype.h>
63 #include <dns/request.h>
64 #include <dns/result.h>
65 #include <dns/tsig.h>
66
67 #include <dst/dst.h>
68
69 #include <lwres/lwres.h>
70 #include <lwres/net.h>
71
72 #include <bind9/getaddresses.h>
73
74 #ifdef HAVE_ADDRINFO
75 #ifdef HAVE_GETADDRINFO
76 #ifdef HAVE_GAISTRERROR
77 #define USE_GETADDRINFO
78 #endif
79 #endif
80 #endif
81
82 #ifndef USE_GETADDRINFO
83 #ifndef ISC_PLATFORM_NONSTDHERRNO
84 extern int h_errno;
85 #endif
86 #endif
87
88 #define MAXCMD (4 * 1024)
89 #define MAXWIRE (64 * 1024)
90 #define PACKETSIZE ((64 * 1024) - 1)
91 #define INITTEXT (2 * 1024)
92 #define MAXTEXT (128 * 1024)
93 #define FIND_TIMEOUT 5
94 #define TTL_MAX 2147483647U     /* Maximum signed 32 bit integer. */
95
96 #define DNSDEFAULTPORT 53
97
98 #ifndef RESOLV_CONF
99 #define RESOLV_CONF "/etc/resolv.conf"
100 #endif
101
102 static isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE;
103 static isc_boolean_t memdebugging = ISC_FALSE;
104 static isc_boolean_t have_ipv4 = ISC_FALSE;
105 static isc_boolean_t have_ipv6 = ISC_FALSE;
106 static isc_boolean_t is_dst_up = ISC_FALSE;
107 static isc_boolean_t usevc = ISC_FALSE;
108 static isc_taskmgr_t *taskmgr = NULL;
109 static isc_task_t *global_task = NULL;
110 static isc_event_t *global_event = NULL;
111 static isc_mem_t *mctx = NULL;
112 static dns_dispatchmgr_t *dispatchmgr = NULL;
113 static dns_requestmgr_t *requestmgr = NULL;
114 static isc_socketmgr_t *socketmgr = NULL;
115 static isc_timermgr_t *timermgr = NULL;
116 static dns_dispatch_t *dispatchv4 = NULL;
117 static dns_dispatch_t *dispatchv6 = NULL;
118 static dns_message_t *updatemsg = NULL;
119 static dns_fixedname_t fuserzone;
120 static dns_name_t *userzone = NULL;
121 static dns_tsigkey_t *tsigkey = NULL;
122 static dst_key_t *sig0key;
123 static lwres_context_t *lwctx = NULL;
124 static lwres_conf_t *lwconf;
125 static isc_sockaddr_t *servers;
126 static int ns_inuse = 0;
127 static int ns_total = 0;
128 static isc_sockaddr_t *userserver = NULL;
129 static isc_sockaddr_t *localaddr = NULL;
130 static char *keystr = NULL, *keyfile = NULL;
131 static isc_entropy_t *entp = NULL;
132 static isc_boolean_t shuttingdown = ISC_FALSE;
133 static FILE *input;
134 static isc_boolean_t interactive = ISC_TRUE;
135 static isc_boolean_t seenerror = ISC_FALSE;
136 static const dns_master_style_t *style;
137 static int requests = 0;
138 static unsigned int timeout = 300;
139 static unsigned int udp_timeout = 3;
140 static unsigned int udp_retries = 3;
141 static dns_rdataclass_t defaultclass = dns_rdataclass_in;
142 static dns_rdataclass_t zoneclass = dns_rdataclass_none;
143 static dns_message_t *answer = NULL;
144
145 typedef struct nsu_requestinfo {
146         dns_message_t *msg;
147         isc_sockaddr_t *addr;
148 } nsu_requestinfo_t;
149
150 static void
151 sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
152             dns_message_t *msg, dns_request_t **request);
153 static void
154 fatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
155
156 static void
157 debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
158
159 static void
160 ddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
161
162 static void
163 error(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
164
165 #define STATUS_MORE     (isc_uint16_t)0
166 #define STATUS_SEND     (isc_uint16_t)1
167 #define STATUS_QUIT     (isc_uint16_t)2
168 #define STATUS_SYNTAX   (isc_uint16_t)3
169
170 static dns_rdataclass_t
171 getzoneclass(void) {
172         if (zoneclass == dns_rdataclass_none)
173                 zoneclass = defaultclass;
174         return (zoneclass);
175 }
176
177 static isc_boolean_t
178 setzoneclass(dns_rdataclass_t rdclass) {
179         if (zoneclass == dns_rdataclass_none ||
180             rdclass == dns_rdataclass_none)
181                 zoneclass = rdclass;
182         if (zoneclass != rdclass)
183                 return (ISC_FALSE);
184         return (ISC_TRUE);
185 }
186
187 static void
188 fatal(const char *format, ...) {
189         va_list args;
190
191         va_start(args, format);
192         vfprintf(stderr, format, args);
193         va_end(args);
194         fprintf(stderr, "\n");
195         exit(1);
196 }
197
198 static void
199 error(const char *format, ...) {
200         va_list args;
201
202         va_start(args, format);
203         vfprintf(stderr, format, args);
204         va_end(args);
205         fprintf(stderr, "\n");
206 }
207
208 static void
209 debug(const char *format, ...) {
210         va_list args;
211
212         if (debugging) {
213                 va_start(args, format);
214                 vfprintf(stderr, format, args);
215                 va_end(args);
216                 fprintf(stderr, "\n");
217         }
218 }
219
220 static void
221 ddebug(const char *format, ...) {
222         va_list args;
223
224         if (ddebugging) {
225                 va_start(args, format);
226                 vfprintf(stderr, format, args);
227                 va_end(args);
228                 fprintf(stderr, "\n");
229         }
230 }
231
232 static inline void
233 check_result(isc_result_t result, const char *msg) {
234         if (result != ISC_R_SUCCESS)
235                 fatal("%s: %s", msg, isc_result_totext(result));
236 }
237
238 static void *
239 mem_alloc(void *arg, size_t size) {
240         return (isc_mem_get(arg, size));
241 }
242
243 static void
244 mem_free(void *arg, void *mem, size_t size) {
245         isc_mem_put(arg, mem, size);
246 }
247
248 static char *
249 nsu_strsep(char **stringp, const char *delim) {
250         char *string = *stringp;
251         char *s;
252         const char *d;
253         char sc, dc;
254
255         if (string == NULL)
256                 return (NULL);
257
258         for (; *string != '\0'; string++) {
259                 sc = *string;
260                 for (d = delim; (dc = *d) != '\0'; d++) {
261                         if (sc == dc)
262                                 break;
263                 }
264                 if (dc == 0)
265                         break;
266         }
267
268         for (s = string; *s != '\0'; s++) {
269                 sc = *s;
270                 for (d = delim; (dc = *d) != '\0'; d++) {
271                         if (sc == dc) {
272                                 *s++ = '\0';
273                                 *stringp = s;
274                                 return (string);
275                         }
276                 }
277         }
278         *stringp = NULL;
279         return (string);
280 }
281
282 static void
283 reset_system(void) {
284         isc_result_t result;
285
286         ddebug("reset_system()");
287         /* If the update message is still around, destroy it */
288         if (updatemsg != NULL)
289                 dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER);
290         else {
291                 result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
292                                             &updatemsg);
293                 check_result(result, "dns_message_create");
294         }
295         updatemsg->opcode = dns_opcode_update;
296 }
297
298 static void
299 setup_keystr(void) {
300         unsigned char *secret = NULL;
301         int secretlen;
302         isc_buffer_t secretbuf;
303         isc_result_t result;
304         isc_buffer_t keynamesrc;
305         char *secretstr;
306         char *s;
307         dns_fixedname_t fkeyname;
308         dns_name_t *keyname;
309
310         dns_fixedname_init(&fkeyname);
311         keyname = dns_fixedname_name(&fkeyname);
312
313         debug("Creating key...");
314
315         s = strchr(keystr, ':');
316         if (s == NULL || s == keystr || *s == 0)
317                 fatal("key option must specify keyname:secret");
318         secretstr = s + 1;
319
320         isc_buffer_init(&keynamesrc, keystr, s - keystr);
321         isc_buffer_add(&keynamesrc, s - keystr);
322
323         debug("namefromtext");
324         result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname,
325                                    ISC_FALSE, NULL);
326         check_result(result, "dns_name_fromtext");
327
328         secretlen = strlen(secretstr) * 3 / 4;
329         secret = isc_mem_allocate(mctx, secretlen);
330         if (secret == NULL)
331                 fatal("out of memory");
332
333         isc_buffer_init(&secretbuf, secret, secretlen);
334         result = isc_base64_decodestring(secretstr, &secretbuf);
335         if (result != ISC_R_SUCCESS) {
336                 fprintf(stderr, "could not create key from %s: %s\n",
337                         keystr, isc_result_totext(result));
338                 goto failure;
339         }
340
341         secretlen = isc_buffer_usedlength(&secretbuf);
342
343         debug("keycreate");
344         result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name,
345                                     secret, secretlen, ISC_TRUE, NULL,
346                                     0, 0, mctx, NULL, &tsigkey);
347         if (result != ISC_R_SUCCESS)
348                 fprintf(stderr, "could not create key from %s: %s\n",
349                         keystr, dns_result_totext(result));
350  failure:
351         if (secret != NULL)
352                 isc_mem_free(mctx, secret);
353 }
354
355 static void
356 setup_keyfile(void) {
357         dst_key_t *dstkey = NULL;
358         isc_result_t result;
359
360         debug("Creating key...");
361
362         result = dst_key_fromnamedfile(keyfile,
363                                        DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
364                                        &dstkey);
365         if (result != ISC_R_SUCCESS) {
366                 fprintf(stderr, "could not read key from %s: %s\n",
367                         keyfile, isc_result_totext(result));
368                 return;
369         }
370         if (dst_key_alg(dstkey) == DST_ALG_HMACMD5) {
371                 result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
372                                                    dns_tsig_hmacmd5_name,
373                                                    dstkey, ISC_FALSE, NULL,
374                                                    0, 0, mctx, NULL, &tsigkey);
375                 if (result != ISC_R_SUCCESS) {
376                         fprintf(stderr, "could not create key from %s: %s\n",
377                                 keyfile, isc_result_totext(result));
378                         dst_key_free(&dstkey);
379                         return;
380                 }
381         } else
382                 sig0key = dstkey;
383 }
384
385 static void
386 doshutdown(void) {
387         isc_task_detach(&global_task);
388
389         if (userserver != NULL)
390                 isc_mem_put(mctx, userserver, sizeof(isc_sockaddr_t));
391
392         if (localaddr != NULL)
393                 isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t));
394
395         if (tsigkey != NULL) {
396                 ddebug("Freeing TSIG key");
397                 dns_tsigkey_detach(&tsigkey);
398         }
399
400         if (sig0key != NULL) {
401                 ddebug("Freeing SIG(0) key");
402                 dst_key_free(&sig0key);
403         }
404
405         if (updatemsg != NULL)
406                 dns_message_destroy(&updatemsg);
407
408         if (is_dst_up) {
409                 ddebug("Destroy DST lib");
410                 dst_lib_destroy();
411                 is_dst_up = ISC_FALSE;
412         }
413
414         if (entp != NULL) {
415                 ddebug("Detach from entropy");
416                 isc_entropy_detach(&entp);
417         }
418
419         lwres_conf_clear(lwctx);
420         lwres_context_destroy(&lwctx);
421
422         isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t));
423
424         ddebug("Destroying request manager");
425         dns_requestmgr_detach(&requestmgr);
426
427         ddebug("Freeing the dispatchers");
428         if (have_ipv4)
429                 dns_dispatch_detach(&dispatchv4);
430         if (have_ipv6)
431                 dns_dispatch_detach(&dispatchv6);
432
433         ddebug("Shutting down dispatch manager");
434         dns_dispatchmgr_destroy(&dispatchmgr);
435
436 }
437
438 static void
439 maybeshutdown(void) {
440         ddebug("Shutting down request manager");
441         dns_requestmgr_shutdown(requestmgr);
442
443         if (requests != 0)
444                 return;
445
446         doshutdown();
447 }
448
449 static void
450 shutdown_program(isc_task_t *task, isc_event_t *event) {
451         REQUIRE(task == global_task);
452         UNUSED(task);
453
454         ddebug("shutdown_program()");
455         isc_event_free(&event);
456
457         shuttingdown = ISC_TRUE;
458         maybeshutdown();
459 }
460
461 static void
462 setup_system(void) {
463         isc_result_t result;
464         isc_sockaddr_t bind_any, bind_any6;
465         lwres_result_t lwresult;
466         unsigned int attrs, attrmask;
467         int i;
468
469         ddebug("setup_system()");
470
471         dns_result_register();
472
473         result = isc_net_probeipv4();
474         if (result == ISC_R_SUCCESS)
475                 have_ipv4 = ISC_TRUE;
476
477         result = isc_net_probeipv6();
478         if (result == ISC_R_SUCCESS)
479                 have_ipv6 = ISC_TRUE;
480
481         if (!have_ipv4 && !have_ipv6)
482                 fatal("could not find either IPv4 or IPv6");
483
484         result = isc_mem_create(0, 0, &mctx);
485         check_result(result, "isc_mem_create");
486
487         lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1);
488         if (lwresult != LWRES_R_SUCCESS)
489                 fatal("lwres_context_create failed");
490
491         (void)lwres_conf_parse(lwctx, RESOLV_CONF);
492         lwconf = lwres_conf_get(lwctx);
493
494         ns_total = lwconf->nsnext;
495         if (ns_total <= 0) {
496                 /* No name servers in resolv.conf; default to loopback. */
497                 struct in_addr localhost;
498                 ns_total = 1;
499                 servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
500                 if (servers == NULL)
501                         fatal("out of memory");
502                 localhost.s_addr = htonl(INADDR_LOOPBACK);
503                 isc_sockaddr_fromin(&servers[0], &localhost, DNSDEFAULTPORT);
504         } else {
505                 servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
506                 if (servers == NULL)
507                         fatal("out of memory");
508                 for (i = 0; i < ns_total; i++) {
509                         if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4) {
510                                 struct in_addr in4;
511                                 memcpy(&in4, lwconf->nameservers[i].address, 4);
512                                 isc_sockaddr_fromin(&servers[i], &in4, DNSDEFAULTPORT);
513                         } else {
514                                 struct in6_addr in6;
515                                 memcpy(&in6, lwconf->nameservers[i].address, 16);
516                                 isc_sockaddr_fromin6(&servers[i], &in6,
517                                                      DNSDEFAULTPORT);
518                         }
519                 }
520         }
521
522         result = isc_entropy_create(mctx, &entp);
523         check_result(result, "isc_entropy_create");
524
525         result = isc_hash_create(mctx, entp, DNS_NAME_MAXWIRE);
526         check_result(result, "isc_hash_create");
527         isc_hash_init();
528
529         result = dns_dispatchmgr_create(mctx, entp, &dispatchmgr);
530         check_result(result, "dns_dispatchmgr_create");
531
532         result = isc_socketmgr_create(mctx, &socketmgr);
533         check_result(result, "dns_socketmgr_create");
534
535         result = isc_timermgr_create(mctx, &timermgr);
536         check_result(result, "dns_timermgr_create");
537
538         result = isc_taskmgr_create(mctx, 1, 0, &taskmgr);
539         check_result(result, "isc_taskmgr_create");
540
541         result = isc_task_create(taskmgr, 0, &global_task);
542         check_result(result, "isc_task_create");
543
544         result = isc_task_onshutdown(global_task, shutdown_program, NULL);
545         check_result(result, "isc_task_onshutdown");
546
547         result = dst_lib_init(mctx, entp, 0);
548         check_result(result, "dst_lib_init");
549         is_dst_up = ISC_TRUE;
550
551         attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
552         attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
553
554         if (have_ipv6) {
555                 attrs = DNS_DISPATCHATTR_UDP;
556                 attrs |= DNS_DISPATCHATTR_MAKEQUERY;
557                 attrs |= DNS_DISPATCHATTR_IPV6;
558                 isc_sockaddr_any6(&bind_any6);
559                 result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
560                                              &bind_any6, PACKETSIZE,
561                                              4, 2, 3, 5,
562                                              attrs, attrmask, &dispatchv6);
563                 check_result(result, "dns_dispatch_getudp (v6)");
564         }
565
566         if (have_ipv4) {
567                 attrs = DNS_DISPATCHATTR_UDP;
568                 attrs |= DNS_DISPATCHATTR_MAKEQUERY;
569                 attrs |= DNS_DISPATCHATTR_IPV4;
570                 isc_sockaddr_any(&bind_any);
571                 result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
572                                              &bind_any, PACKETSIZE,
573                                              4, 2, 3, 5,
574                                              attrs, attrmask, &dispatchv4);
575                 check_result(result, "dns_dispatch_getudp (v4)");
576         }
577
578         result = dns_requestmgr_create(mctx, timermgr,
579                                        socketmgr, taskmgr, dispatchmgr,
580                                        dispatchv4, dispatchv6, &requestmgr);
581         check_result(result, "dns_requestmgr_create");
582
583         if (keystr != NULL)
584                 setup_keystr();
585         else if (keyfile != NULL)
586                 setup_keyfile();
587 }
588
589 static void
590 get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
591         int count;
592         isc_result_t result;
593
594         isc_app_block();
595         result = bind9_getaddresses(host, port, sockaddr, 1, &count);
596         isc_app_unblock();
597         if (result != ISC_R_SUCCESS)
598                 fatal("couldn't get address for '%s': %s",
599                       host, isc_result_totext(result));
600         INSIST(count == 1);
601 }
602
603 static void
604 parse_args(int argc, char **argv) {
605         int ch;
606         isc_result_t result;
607
608         debug("parse_args");
609         while ((ch = isc_commandline_parse(argc, argv, "dDMy:vk:r:t:u:")) != -1)
610         {
611                 switch (ch) {
612                 case 'd':
613                         debugging = ISC_TRUE;
614                         break;
615                 case 'D': /* was -dd */
616                         debugging = ISC_TRUE;
617                         ddebugging = ISC_TRUE;
618                         break;
619                 case 'M': /* was -dm */
620                         debugging = ISC_TRUE;
621                         ddebugging = ISC_TRUE;
622                         memdebugging = ISC_TRUE;
623                         isc_mem_debugging = ISC_MEM_DEBUGTRACE |
624                                             ISC_MEM_DEBUGRECORD;
625                         break;
626                 case 'y':
627                         keystr = isc_commandline_argument;
628                         break;
629                 case 'v':
630                         usevc = ISC_TRUE;
631                         break;
632                 case 'k':
633                         keyfile = isc_commandline_argument;
634                         break;
635                 case 't':
636                         result = isc_parse_uint32(&timeout,
637                                                   isc_commandline_argument, 10);
638                         if (result != ISC_R_SUCCESS) {
639                                 fprintf(stderr, "bad timeout '%s'\n",                                           isc_commandline_argument);
640                                 exit(1);
641                         }
642                         if (timeout == 0)
643                                 timeout = UINT_MAX;
644                         break;
645                 case 'u':
646                         result = isc_parse_uint32(&udp_timeout,
647                                                   isc_commandline_argument, 10);
648                         if (result != ISC_R_SUCCESS) {
649                                 fprintf(stderr, "bad udp timeout '%s'\n",                                               isc_commandline_argument);
650                                 exit(1);
651                         }
652                         if (udp_timeout == 0)
653                                 udp_timeout = UINT_MAX;
654                         break;
655                 case 'r':
656                         result = isc_parse_uint32(&udp_retries,
657                                                   isc_commandline_argument, 10);
658                         if (result != ISC_R_SUCCESS) {
659                                 fprintf(stderr, "bad udp retries '%s'\n",                                               isc_commandline_argument);
660                                 exit(1);
661                         }
662                         break;
663                 default:
664                         fprintf(stderr, "%s: invalid argument -%c\n",
665                                 argv[0], ch);
666                         fprintf(stderr, "usage: nsupdate [-d] "
667                                 "[-y keyname:secret | -k keyfile] [-v] "
668                                 "[filename]\n");
669                         exit(1);
670                 }
671         }
672         if (keyfile != NULL && keystr != NULL) {
673                 fprintf(stderr, "%s: cannot specify both -k and -y\n",
674                         argv[0]);
675                 exit(1);
676         }
677
678         if (argv[isc_commandline_index] != NULL) {
679                 if (strcmp(argv[isc_commandline_index], "-") == 0) {
680                         input = stdin;
681                 } else {
682                         result = isc_stdio_open(argv[isc_commandline_index],
683                                                 "r", &input);
684                         if (result != ISC_R_SUCCESS) {
685                                 fprintf(stderr, "could not open '%s': %s\n",
686                                         argv[isc_commandline_index],
687                                         isc_result_totext(result));
688                                 exit(1);
689                         }
690                 }
691                 interactive = ISC_FALSE;
692         }
693 }
694
695 static isc_uint16_t
696 parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) {
697         isc_result_t result;
698         char *word;
699         isc_buffer_t *namebuf = NULL;
700         isc_buffer_t source;
701
702         word = nsu_strsep(cmdlinep, " \t\r\n");
703         if (*word == 0) {
704                 fprintf(stderr, "could not read owner name\n");
705                 return (STATUS_SYNTAX);
706         }
707
708         result = dns_message_gettempname(msg, namep);
709         check_result(result, "dns_message_gettempname");
710         result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
711         check_result(result, "isc_buffer_allocate");
712         dns_name_init(*namep, NULL);
713         dns_name_setbuffer(*namep, namebuf);
714         dns_message_takebuffer(msg, &namebuf);
715         isc_buffer_init(&source, word, strlen(word));
716         isc_buffer_add(&source, strlen(word));
717         result = dns_name_fromtext(*namep, &source, dns_rootname,
718                                    ISC_FALSE, NULL);
719         check_result(result, "dns_name_fromtext");
720         isc_buffer_invalidate(&source);
721         return (STATUS_MORE);
722 }
723
724 static isc_uint16_t
725 parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass,
726             dns_rdatatype_t rdatatype, dns_message_t *msg,
727             dns_rdata_t *rdata)
728 {
729         char *cmdline = *cmdlinep;
730         isc_buffer_t source, *buf = NULL, *newbuf = NULL;
731         isc_region_t r;
732         isc_lex_t *lex = NULL;
733         dns_rdatacallbacks_t callbacks;
734         isc_result_t result;
735
736         while (*cmdline != 0 && isspace((unsigned char)*cmdline))
737                 cmdline++;
738
739         if (*cmdline != 0) {
740                 dns_rdatacallbacks_init(&callbacks);
741                 result = isc_lex_create(mctx, strlen(cmdline), &lex);
742                 check_result(result, "isc_lex_create");
743                 isc_buffer_init(&source, cmdline, strlen(cmdline));
744                 isc_buffer_add(&source, strlen(cmdline));
745                 result = isc_lex_openbuffer(lex, &source);
746                 check_result(result, "isc_lex_openbuffer");
747                 result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
748                 check_result(result, "isc_buffer_allocate");
749                 result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex,
750                                             dns_rootname, 0, mctx, buf,
751                                             &callbacks);
752                 isc_lex_destroy(&lex);
753                 if (result == ISC_R_SUCCESS) {
754                         isc_buffer_usedregion(buf, &r);
755                         result = isc_buffer_allocate(mctx, &newbuf, r.length);
756                         check_result(result, "isc_buffer_allocate");
757                         isc_buffer_putmem(newbuf, r.base, r.length);
758                         isc_buffer_usedregion(newbuf, &r);
759                         dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r);
760                         isc_buffer_free(&buf);
761                         dns_message_takebuffer(msg, &newbuf);
762                 } else {
763                         fprintf(stderr, "invalid rdata format: %s\n",
764                                 isc_result_totext(result));
765                         isc_buffer_free(&buf);
766                         return (STATUS_SYNTAX);
767                 }
768         } else {
769                 rdata->flags = DNS_RDATA_UPDATE;
770         }
771         *cmdlinep = cmdline;
772         return (STATUS_MORE);
773 }
774
775 static isc_uint16_t
776 make_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) {
777         isc_result_t result;
778         char *word;
779         dns_name_t *name = NULL;
780         isc_textregion_t region;
781         dns_rdataset_t *rdataset = NULL;
782         dns_rdatalist_t *rdatalist = NULL;
783         dns_rdataclass_t rdataclass;
784         dns_rdatatype_t rdatatype;
785         dns_rdata_t *rdata = NULL;
786         isc_uint16_t retval;
787
788         ddebug("make_prereq()");
789
790         /*
791          * Read the owner name
792          */
793         retval = parse_name(&cmdline, updatemsg, &name);
794         if (retval != STATUS_MORE)
795                 return (retval);
796
797         /*
798          * If this is an rrset prereq, read the class or type.
799          */
800         if (isrrset) {
801                 word = nsu_strsep(&cmdline, " \t\r\n");
802                 if (*word == 0) {
803                         fprintf(stderr, "could not read class or type\n");
804                         goto failure;
805                 }
806                 region.base = word;
807                 region.length = strlen(word);
808                 result = dns_rdataclass_fromtext(&rdataclass, &region);
809                 if (result == ISC_R_SUCCESS) {
810                         if (!setzoneclass(rdataclass)) {
811                                 fprintf(stderr, "class mismatch: %s\n", word);
812                                 goto failure;
813                         }
814                         /*
815                          * Now read the type.
816                          */
817                         word = nsu_strsep(&cmdline, " \t\r\n");
818                         if (*word == 0) {
819                                 fprintf(stderr, "could not read type\n");
820                                 goto failure;
821                         }
822                         region.base = word;
823                         region.length = strlen(word);
824                         result = dns_rdatatype_fromtext(&rdatatype, &region);
825                         if (result != ISC_R_SUCCESS) {
826                                 fprintf(stderr, "invalid type: %s\n", word);
827                                 goto failure;
828                         }
829                 } else {
830                         rdataclass = getzoneclass();
831                         result = dns_rdatatype_fromtext(&rdatatype, &region);
832                         if (result != ISC_R_SUCCESS) {
833                                 fprintf(stderr, "invalid type: %s\n", word);
834                                 goto failure;
835                         }
836                 }
837         } else
838                 rdatatype = dns_rdatatype_any;
839
840         result = dns_message_gettemprdata(updatemsg, &rdata);
841         check_result(result, "dns_message_gettemprdata");
842
843         rdata->data = NULL;
844         rdata->length = 0;
845
846         if (isrrset && ispositive) {
847                 retval = parse_rdata(&cmdline, rdataclass, rdatatype,
848                                      updatemsg, rdata);
849                 if (retval != STATUS_MORE)
850                         goto failure;
851         } else
852                 rdata->flags = DNS_RDATA_UPDATE;
853
854         result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
855         check_result(result, "dns_message_gettemprdatalist");
856         result = dns_message_gettemprdataset(updatemsg, &rdataset);
857         check_result(result, "dns_message_gettemprdataset");
858         dns_rdatalist_init(rdatalist);
859         rdatalist->type = rdatatype;
860         if (ispositive) {
861                 if (isrrset && rdata->data != NULL)
862                         rdatalist->rdclass = rdataclass;
863                 else
864                         rdatalist->rdclass = dns_rdataclass_any;
865         } else
866                 rdatalist->rdclass = dns_rdataclass_none;
867         rdatalist->covers = 0;
868         rdatalist->ttl = 0;
869         rdata->rdclass = rdatalist->rdclass;
870         rdata->type = rdatatype;
871         ISC_LIST_INIT(rdatalist->rdata);
872         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
873         dns_rdataset_init(rdataset);
874         dns_rdatalist_tordataset(rdatalist, rdataset);
875         ISC_LIST_INIT(name->list);
876         ISC_LIST_APPEND(name->list, rdataset, link);
877         dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE);
878         return (STATUS_MORE);
879
880  failure:
881         if (name != NULL)
882                 dns_message_puttempname(updatemsg, &name);
883         return (STATUS_SYNTAX);
884 }
885
886 static isc_uint16_t
887 evaluate_prereq(char *cmdline) {
888         char *word;
889         isc_boolean_t ispositive, isrrset;
890
891         ddebug("evaluate_prereq()");
892         word = nsu_strsep(&cmdline, " \t\r\n");
893         if (*word == 0) {
894                 fprintf(stderr, "could not read operation code\n");
895                 return (STATUS_SYNTAX);
896         }
897         if (strcasecmp(word, "nxdomain") == 0) {
898                 ispositive = ISC_FALSE;
899                 isrrset = ISC_FALSE;
900         } else if (strcasecmp(word, "yxdomain") == 0) {
901                 ispositive = ISC_TRUE;
902                 isrrset = ISC_FALSE;
903         } else if (strcasecmp(word, "nxrrset") == 0) {
904                 ispositive = ISC_FALSE;
905                 isrrset = ISC_TRUE;
906         } else if (strcasecmp(word, "yxrrset") == 0) {
907                 ispositive = ISC_TRUE;
908                 isrrset = ISC_TRUE;
909         } else {
910                 fprintf(stderr, "incorrect operation code: %s\n", word);
911                 return (STATUS_SYNTAX);
912         }
913         return (make_prereq(cmdline, ispositive, isrrset));
914 }
915
916 static isc_uint16_t
917 evaluate_server(char *cmdline) {
918         char *word, *server;
919         long port;
920
921         word = nsu_strsep(&cmdline, " \t\r\n");
922         if (*word == 0) {
923                 fprintf(stderr, "could not read server name\n");
924                 return (STATUS_SYNTAX);
925         }
926         server = word;
927
928         word = nsu_strsep(&cmdline, " \t\r\n");
929         if (*word == 0)
930                 port = DNSDEFAULTPORT;
931         else {
932                 char *endp;
933                 port = strtol(word, &endp, 10);
934                 if (*endp != 0) {
935                         fprintf(stderr, "port '%s' is not numeric\n", word);
936                         return (STATUS_SYNTAX);
937                 } else if (port < 1 || port > 65535) {
938                         fprintf(stderr, "port '%s' is out of range "
939                                 "(1 to 65535)\n", word);
940                         return (STATUS_SYNTAX);
941                 }
942         }
943
944         if (userserver == NULL) {
945                 userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
946                 if (userserver == NULL)
947                         fatal("out of memory");
948         }
949
950         get_address(server, (in_port_t)port, userserver);
951
952         return (STATUS_MORE);
953 }
954
955 static isc_uint16_t
956 evaluate_local(char *cmdline) {
957         char *word, *local;
958         long port;
959         struct in_addr in4;
960         struct in6_addr in6;
961
962         word = nsu_strsep(&cmdline, " \t\r\n");
963         if (*word == 0) {
964                 fprintf(stderr, "could not read server name\n");
965                 return (STATUS_SYNTAX);
966         }
967         local = word;
968
969         word = nsu_strsep(&cmdline, " \t\r\n");
970         if (*word == 0)
971                 port = 0;
972         else {
973                 char *endp;
974                 port = strtol(word, &endp, 10);
975                 if (*endp != 0) {
976                         fprintf(stderr, "port '%s' is not numeric\n", word);
977                         return (STATUS_SYNTAX);
978                 } else if (port < 1 || port > 65535) {
979                         fprintf(stderr, "port '%s' is out of range "
980                                 "(1 to 65535)\n", word);
981                         return (STATUS_SYNTAX);
982                 }
983         }
984
985         if (localaddr == NULL) {
986                 localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
987                 if (localaddr == NULL)
988                         fatal("out of memory");
989         }
990
991         if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1)
992                 isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port);
993         else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1)
994                 isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port);
995         else {
996                 fprintf(stderr, "invalid address %s", local);
997                 return (STATUS_SYNTAX);
998         }
999
1000         return (STATUS_MORE);
1001 }
1002
1003 static isc_uint16_t
1004 evaluate_key(char *cmdline) {
1005         char *namestr;
1006         char *secretstr;
1007         isc_buffer_t b;
1008         isc_result_t result;
1009         dns_fixedname_t fkeyname;
1010         dns_name_t *keyname;
1011         int secretlen;
1012         unsigned char *secret = NULL;
1013         isc_buffer_t secretbuf;
1014
1015         namestr = nsu_strsep(&cmdline, " \t\r\n");
1016         if (*namestr == 0) {
1017                 fprintf(stderr, "could not read key name\n");
1018                 return (STATUS_SYNTAX);
1019         }
1020
1021         dns_fixedname_init(&fkeyname);
1022         keyname = dns_fixedname_name(&fkeyname);
1023
1024         isc_buffer_init(&b, namestr, strlen(namestr));
1025         isc_buffer_add(&b, strlen(namestr));
1026         result = dns_name_fromtext(keyname, &b, dns_rootname, ISC_FALSE, NULL);
1027         if (result != ISC_R_SUCCESS) {
1028                 fprintf(stderr, "could not parse key name\n");
1029                 return (STATUS_SYNTAX);
1030         }
1031
1032         secretstr = nsu_strsep(&cmdline, "\r\n");
1033         if (*secretstr == 0) {
1034                 fprintf(stderr, "could not read key secret\n");
1035                 return (STATUS_SYNTAX);
1036         }
1037         secretlen = strlen(secretstr) * 3 / 4;
1038         secret = isc_mem_allocate(mctx, secretlen);
1039         if (secret == NULL)
1040                 fatal("out of memory");
1041
1042         isc_buffer_init(&secretbuf, secret, secretlen);
1043         result = isc_base64_decodestring(secretstr, &secretbuf);
1044         if (result != ISC_R_SUCCESS) {
1045                 fprintf(stderr, "could not create key from %s: %s\n",
1046                         secretstr, isc_result_totext(result));
1047                 isc_mem_free(mctx, secret);
1048                 return (STATUS_SYNTAX);
1049         }
1050         secretlen = isc_buffer_usedlength(&secretbuf);
1051
1052         if (tsigkey != NULL)
1053                 dns_tsigkey_detach(&tsigkey);
1054         result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name,
1055                                     secret, secretlen, ISC_TRUE, NULL, 0, 0,
1056                                     mctx, NULL, &tsigkey);
1057         isc_mem_free(mctx, secret);
1058         if (result != ISC_R_SUCCESS) {
1059                 fprintf(stderr, "could not create key from %s %s: %s\n",
1060                         namestr, secretstr, dns_result_totext(result));
1061                 return (STATUS_SYNTAX);
1062         }
1063         return (STATUS_MORE);
1064 }
1065
1066 static isc_uint16_t
1067 evaluate_zone(char *cmdline) {
1068         char *word;
1069         isc_buffer_t b;
1070         isc_result_t result;
1071
1072         word = nsu_strsep(&cmdline, " \t\r\n");
1073         if (*word == 0) {
1074                 fprintf(stderr, "could not read zone name\n");
1075                 return (STATUS_SYNTAX);
1076         }
1077
1078         dns_fixedname_init(&fuserzone);
1079         userzone = dns_fixedname_name(&fuserzone);
1080         isc_buffer_init(&b, word, strlen(word));
1081         isc_buffer_add(&b, strlen(word));
1082         result = dns_name_fromtext(userzone, &b, dns_rootname, ISC_FALSE,
1083                                    NULL);
1084         if (result != ISC_R_SUCCESS) {
1085                 userzone = NULL; /* Lest it point to an invalid name */
1086                 fprintf(stderr, "could not parse zone name\n");
1087                 return (STATUS_SYNTAX);
1088         }
1089
1090         return (STATUS_MORE);
1091 }
1092
1093 static isc_uint16_t
1094 evaluate_class(char *cmdline) {
1095         char *word;
1096         isc_textregion_t r;
1097         isc_result_t result;
1098         dns_rdataclass_t rdclass;
1099
1100         word = nsu_strsep(&cmdline, " \t\r\n");
1101         if (*word == 0) {
1102                 fprintf(stderr, "could not read class name\n");
1103                 return (STATUS_SYNTAX);
1104         }
1105
1106         r.base = word;
1107         r.length = strlen(word);
1108         result = dns_rdataclass_fromtext(&rdclass, &r);
1109         if (result != ISC_R_SUCCESS) {
1110                 fprintf(stderr, "could not parse class name: %s\n", word);
1111                 return (STATUS_SYNTAX);
1112         }
1113         switch (rdclass) {
1114         case dns_rdataclass_none:
1115         case dns_rdataclass_any:
1116         case dns_rdataclass_reserved0:
1117                 fprintf(stderr, "bad default class: %s\n", word);
1118                 return (STATUS_SYNTAX);
1119         default:
1120                 defaultclass = rdclass;
1121         }
1122
1123         return (STATUS_MORE);
1124 }
1125
1126 static isc_uint16_t
1127 update_addordelete(char *cmdline, isc_boolean_t isdelete) {
1128         isc_result_t result;
1129         dns_name_t *name = NULL;
1130         isc_uint32_t ttl;
1131         char *word;
1132         dns_rdataclass_t rdataclass;
1133         dns_rdatatype_t rdatatype;
1134         dns_rdata_t *rdata = NULL;
1135         dns_rdatalist_t *rdatalist = NULL;
1136         dns_rdataset_t *rdataset = NULL;
1137         isc_textregion_t region;
1138         isc_uint16_t retval;
1139
1140         ddebug("update_addordelete()");
1141
1142         /*
1143          * Read the owner name.
1144          */
1145         retval = parse_name(&cmdline, updatemsg, &name);
1146         if (retval != STATUS_MORE)
1147                 return (retval);
1148
1149         result = dns_message_gettemprdata(updatemsg, &rdata);
1150         check_result(result, "dns_message_gettemprdata");
1151
1152         rdata->rdclass = 0;
1153         rdata->type = 0;
1154         rdata->data = NULL;
1155         rdata->length = 0;
1156
1157         /*
1158          * If this is an add, read the TTL and verify that it's in range.
1159          * If it's a delete, ignore a TTL if present (for compatibility).
1160          */
1161         word = nsu_strsep(&cmdline, " \t\r\n");
1162         if (*word == 0) {
1163                 if (!isdelete) {
1164                         fprintf(stderr, "could not read owner ttl\n");
1165                         goto failure;
1166                 }
1167                 else {
1168                         ttl = 0;
1169                         rdataclass = dns_rdataclass_any;
1170                         rdatatype = dns_rdatatype_any;
1171                         rdata->flags = DNS_RDATA_UPDATE;
1172                         goto doneparsing;
1173                 }
1174         }
1175         result = isc_parse_uint32(&ttl, word, 10);
1176         if (result != ISC_R_SUCCESS) {
1177                 if (isdelete) {
1178                         ttl = 0;
1179                         goto parseclass;
1180                 } else {
1181                         fprintf(stderr, "ttl '%s': %s\n", word,
1182                                 isc_result_totext(result));
1183                         goto failure;
1184                 }
1185         }
1186
1187         if (isdelete)
1188                 ttl = 0;
1189         else if (ttl > TTL_MAX) {
1190                 fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n",
1191                         word, TTL_MAX);
1192                 goto failure;
1193         }
1194
1195         /*
1196          * Read the class or type.
1197          */
1198         word = nsu_strsep(&cmdline, " \t\r\n");
1199  parseclass:
1200         if (*word == 0) {
1201                 if (isdelete) {
1202                         rdataclass = dns_rdataclass_any;
1203                         rdatatype = dns_rdatatype_any;
1204                         rdata->flags = DNS_RDATA_UPDATE;
1205                         goto doneparsing;
1206                 } else {
1207                         fprintf(stderr, "could not read class or type\n");
1208                         goto failure;
1209                 }
1210         }
1211         region.base = word;
1212         region.length = strlen(word);
1213         result = dns_rdataclass_fromtext(&rdataclass, &region);
1214         if (result == ISC_R_SUCCESS) {
1215                 if (!setzoneclass(rdataclass)) {
1216                         fprintf(stderr, "class mismatch: %s\n", word);
1217                         goto failure;
1218                 }
1219                 /*
1220                  * Now read the type.
1221                  */
1222                 word = nsu_strsep(&cmdline, " \t\r\n");
1223                 if (*word == 0) {
1224                         if (isdelete) {
1225                                 rdataclass = dns_rdataclass_any;
1226                                 rdatatype = dns_rdatatype_any;
1227                                 rdata->flags = DNS_RDATA_UPDATE;
1228                                 goto doneparsing;
1229                         } else {
1230                                 fprintf(stderr, "could not read type\n");
1231                                 goto failure;
1232                         }
1233                 }
1234                 region.base = word;
1235                 region.length = strlen(word);
1236                 result = dns_rdatatype_fromtext(&rdatatype, &region);
1237                 if (result != ISC_R_SUCCESS) {
1238                         fprintf(stderr, "'%s' is not a valid type: %s\n",
1239                                 word, isc_result_totext(result));
1240                         goto failure;
1241                 }
1242         } else {
1243                 rdataclass = getzoneclass();
1244                 result = dns_rdatatype_fromtext(&rdatatype, &region);
1245                 if (result != ISC_R_SUCCESS) {
1246                         fprintf(stderr, "'%s' is not a valid class or type: "
1247                                 "%s\n", word, isc_result_totext(result));
1248                         goto failure;
1249                 }
1250         }
1251
1252         retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg,
1253                              rdata);
1254         if (retval != STATUS_MORE)
1255                 goto failure;
1256
1257         if (isdelete) {
1258                 if ((rdata->flags & DNS_RDATA_UPDATE) != 0)
1259                         rdataclass = dns_rdataclass_any;
1260                 else
1261                         rdataclass = dns_rdataclass_none;
1262         } else {
1263                 if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
1264                         fprintf(stderr, "could not read rdata\n");
1265                         goto failure;
1266                 }
1267         }
1268
1269  doneparsing:
1270
1271         result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
1272         check_result(result, "dns_message_gettemprdatalist");
1273         result = dns_message_gettemprdataset(updatemsg, &rdataset);
1274         check_result(result, "dns_message_gettemprdataset");
1275         dns_rdatalist_init(rdatalist);
1276         rdatalist->type = rdatatype;
1277         rdatalist->rdclass = rdataclass;
1278         rdatalist->covers = rdatatype;
1279         rdatalist->ttl = (dns_ttl_t)ttl;
1280         ISC_LIST_INIT(rdatalist->rdata);
1281         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1282         dns_rdataset_init(rdataset);
1283         dns_rdatalist_tordataset(rdatalist, rdataset);
1284         ISC_LIST_INIT(name->list);
1285         ISC_LIST_APPEND(name->list, rdataset, link);
1286         dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE);
1287         return (STATUS_MORE);
1288
1289  failure:
1290         if (name != NULL)
1291                 dns_message_puttempname(updatemsg, &name);
1292         dns_message_puttemprdata(updatemsg, &rdata);
1293         return (STATUS_SYNTAX);
1294 }
1295
1296 static isc_uint16_t
1297 evaluate_update(char *cmdline) {
1298         char *word;
1299         isc_boolean_t isdelete;
1300
1301         ddebug("evaluate_update()");
1302         word = nsu_strsep(&cmdline, " \t\r\n");
1303         if (*word == 0) {
1304                 fprintf(stderr, "could not read operation code\n");
1305                 return (STATUS_SYNTAX);
1306         }
1307         if (strcasecmp(word, "delete") == 0)
1308                 isdelete = ISC_TRUE;
1309         else if (strcasecmp(word, "add") == 0)
1310                 isdelete = ISC_FALSE;
1311         else {
1312                 fprintf(stderr, "incorrect operation code: %s\n", word);
1313                 return (STATUS_SYNTAX);
1314         }
1315         return (update_addordelete(cmdline, isdelete));
1316 }
1317
1318 static void
1319 show_message(dns_message_t *msg) {
1320         isc_result_t result;
1321         isc_buffer_t *buf = NULL;
1322         int bufsz;
1323
1324         ddebug("show_message()");
1325         bufsz = INITTEXT;
1326         do {
1327                 if (bufsz > MAXTEXT) {
1328                         fprintf(stderr, "could not allocate large enough "
1329                                 "buffer to display message\n");
1330                         exit(1);
1331                 }
1332                 if (buf != NULL)
1333                         isc_buffer_free(&buf);
1334                 result = isc_buffer_allocate(mctx, &buf, bufsz);
1335                 check_result(result, "isc_buffer_allocate");
1336                 result = dns_message_totext(msg, style, 0, buf);
1337                 bufsz *= 2;
1338         } while (result == ISC_R_NOSPACE);
1339         if (result != ISC_R_SUCCESS) {
1340                 fprintf(stderr, "could not convert message to text format.\n");
1341                 isc_buffer_free(&buf);
1342                 return;
1343         }
1344         printf("Outgoing update query:\n%.*s",
1345                (int)isc_buffer_usedlength(buf),
1346                (char*)isc_buffer_base(buf));
1347         isc_buffer_free(&buf);
1348 }
1349
1350
1351 static isc_uint16_t
1352 get_next_command(void) {
1353         char cmdlinebuf[MAXCMD];
1354         char *cmdline;
1355         char *word;
1356
1357         ddebug("get_next_command()");
1358         if (interactive) {
1359                 fprintf(stdout, "> ");
1360                 fflush(stdout);
1361         }
1362         isc_app_block();
1363         cmdline = fgets(cmdlinebuf, MAXCMD, input);
1364         isc_app_unblock();
1365         if (cmdline == NULL)
1366                 return (STATUS_QUIT);
1367         word = nsu_strsep(&cmdline, " \t\r\n");
1368
1369         if (feof(input))
1370                 return (STATUS_QUIT);
1371         if (*word == 0)
1372                 return (STATUS_SEND);
1373         if (word[0] == ';')
1374                 return (STATUS_MORE);
1375         if (strcasecmp(word, "quit") == 0)
1376                 return (STATUS_QUIT);
1377         if (strcasecmp(word, "prereq") == 0)
1378                 return (evaluate_prereq(cmdline));
1379         if (strcasecmp(word, "update") == 0)
1380                 return (evaluate_update(cmdline));
1381         if (strcasecmp(word, "server") == 0)
1382                 return (evaluate_server(cmdline));
1383         if (strcasecmp(word, "local") == 0)
1384                 return (evaluate_local(cmdline));
1385         if (strcasecmp(word, "zone") == 0)
1386                 return (evaluate_zone(cmdline));
1387         if (strcasecmp(word, "class") == 0)
1388                 return (evaluate_class(cmdline));
1389         if (strcasecmp(word, "send") == 0)
1390                 return (STATUS_SEND);
1391         if (strcasecmp(word, "show") == 0) {
1392                 show_message(updatemsg);
1393                 return (STATUS_MORE);
1394         }
1395         if (strcasecmp(word, "answer") == 0) {
1396                 if (answer != NULL)
1397                         show_message(answer);
1398                 return (STATUS_MORE);
1399         }
1400         if (strcasecmp(word, "key") == 0)
1401                 return (evaluate_key(cmdline));
1402         fprintf(stderr, "incorrect section name: %s\n", word);
1403         return (STATUS_SYNTAX);
1404 }
1405
1406 static isc_boolean_t
1407 user_interaction(void) {
1408         isc_uint16_t result = STATUS_MORE;
1409
1410         ddebug("user_interaction()");
1411         while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) {
1412                 result = get_next_command();
1413                 if (!interactive && result == STATUS_SYNTAX)
1414                         fatal("syntax error");
1415         }
1416         if (result == STATUS_SEND)
1417                 return (ISC_TRUE);
1418         return (ISC_FALSE);
1419
1420 }
1421
1422 static void
1423 done_update(void) {
1424         isc_event_t *event = global_event;
1425         ddebug("done_update()");
1426         isc_task_send(global_task, &event);
1427 }
1428
1429 static void
1430 check_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) {
1431         isc_result_t result;
1432         dns_rdata_t rdata = DNS_RDATA_INIT;
1433         dns_rdata_any_tsig_t tsig;
1434
1435         result = dns_rdataset_first(rdataset);
1436         check_result(result, "dns_rdataset_first");
1437         dns_rdataset_current(rdataset, &rdata);
1438         result = dns_rdata_tostruct(&rdata, &tsig, NULL);
1439         check_result(result, "dns_rdata_tostruct");
1440         if (tsig.error != 0) {
1441                 if (isc_buffer_remaininglength(b) < 1)
1442                       check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
1443                 isc__buffer_putstr(b, "(" /*)*/);
1444                 result = dns_tsigrcode_totext(tsig.error, b);
1445                 check_result(result, "dns_tsigrcode_totext");
1446                 if (isc_buffer_remaininglength(b) < 1)
1447                       check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
1448                 isc__buffer_putstr(b,  /*(*/ ")");
1449         }
1450 }
1451
1452 static void
1453 update_completed(isc_task_t *task, isc_event_t *event) {
1454         dns_requestevent_t *reqev = NULL;
1455         isc_result_t result;
1456         dns_request_t *request;
1457
1458         UNUSED(task);
1459
1460         ddebug("update_completed()");
1461
1462         requests--;
1463
1464         REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1465         reqev = (dns_requestevent_t *)event;
1466         request = reqev->request;
1467
1468         if (shuttingdown) {
1469                 dns_request_destroy(&request);
1470                 isc_event_free(&event);
1471                 maybeshutdown();
1472                 return;
1473         }
1474
1475         if (reqev->result != ISC_R_SUCCESS) {
1476                 fprintf(stderr, "; Communication with server failed: %s\n",
1477                         isc_result_totext(reqev->result));
1478                 seenerror = ISC_TRUE;
1479                 goto done;
1480         }
1481
1482         result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer);
1483         check_result(result, "dns_message_create");
1484         result = dns_request_getresponse(request, answer,
1485                                          DNS_MESSAGEPARSE_PRESERVEORDER);
1486         switch (result) {
1487         case ISC_R_SUCCESS:
1488                 break;
1489         case DNS_R_CLOCKSKEW:
1490         case DNS_R_EXPECTEDTSIG:
1491         case DNS_R_TSIGERRORSET:
1492         case DNS_R_TSIGVERIFYFAILURE:
1493         case DNS_R_UNEXPECTEDTSIG:
1494                 fprintf(stderr, "; TSIG error with server: %s\n",
1495                         isc_result_totext(result));
1496                 seenerror = ISC_TRUE;
1497                 break;
1498         default:
1499                 check_result(result, "dns_request_getresponse");
1500         }
1501
1502         if (answer->rcode != dns_rcode_noerror) {
1503                 seenerror = ISC_TRUE;
1504                 if (!debugging) {
1505                         char buf[64];
1506                         isc_buffer_t b;
1507                         dns_rdataset_t *rds;
1508
1509                         isc_buffer_init(&b, buf, sizeof(buf) - 1);
1510                         result = dns_rcode_totext(answer->rcode, &b);
1511                         check_result(result, "dns_rcode_totext");
1512                         rds = dns_message_gettsig(answer, NULL);
1513                         if (rds != NULL)
1514                                 check_tsig_error(rds, &b);
1515                         fprintf(stderr, "update failed: %.*s\n",
1516                                 (int)isc_buffer_usedlength(&b), buf);
1517                 }
1518         }
1519         if (debugging) {
1520                 isc_buffer_t *buf = NULL;
1521                 int bufsz;
1522
1523                 bufsz = INITTEXT;
1524                 do {
1525                         if (bufsz > MAXTEXT) {
1526                                 fprintf(stderr, "could not allocate large "
1527                                         "enough buffer to display message\n");
1528                                 exit(1);
1529                         }
1530                         if (buf != NULL)
1531                                 isc_buffer_free(&buf);
1532                         result = isc_buffer_allocate(mctx, &buf, bufsz);
1533                         check_result(result, "isc_buffer_allocate");
1534                         result = dns_message_totext(answer, style, 0, buf);
1535                         bufsz *= 2;
1536                 } while (result == ISC_R_NOSPACE);
1537                 check_result(result, "dns_message_totext");
1538                 fprintf(stderr, "\nReply from update query:\n%.*s\n",
1539                         (int)isc_buffer_usedlength(buf),
1540                         (char*)isc_buffer_base(buf));
1541                 isc_buffer_free(&buf);
1542         }
1543  done:
1544         dns_request_destroy(&request);
1545         isc_event_free(&event);
1546         done_update();
1547 }
1548
1549 static void
1550 send_update(dns_name_t *zonename, isc_sockaddr_t *master,
1551             isc_sockaddr_t *srcaddr)
1552 {
1553         isc_result_t result;
1554         dns_request_t *request = NULL;
1555         dns_name_t *name = NULL;
1556         dns_rdataset_t *rdataset = NULL;
1557         unsigned int options = 0;
1558
1559         ddebug("send_update()");
1560
1561         result = dns_message_gettempname(updatemsg, &name);
1562         check_result(result, "dns_message_gettempname");
1563         dns_name_init(name, NULL);
1564         dns_name_clone(zonename, name);
1565         result = dns_message_gettemprdataset(updatemsg, &rdataset);
1566         check_result(result, "dns_message_gettemprdataset");
1567         dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa);
1568         ISC_LIST_INIT(name->list);
1569         ISC_LIST_APPEND(name->list, rdataset, link);
1570         dns_message_addname(updatemsg, name, DNS_SECTION_ZONE);
1571
1572         if (usevc)
1573                 options |= DNS_REQUESTOPT_TCP;
1574         if (tsigkey == NULL && sig0key != NULL) {
1575                 result = dns_message_setsig0key(updatemsg, sig0key);
1576                 check_result(result, "dns_message_setsig0key");
1577         }
1578         if (debugging) {
1579                 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
1580
1581                 isc_sockaddr_format(master, addrbuf, sizeof(addrbuf));
1582                 fprintf(stderr, "Sending update to %s\n", addrbuf);
1583         }
1584         result = dns_request_createvia3(requestmgr, updatemsg, srcaddr,
1585                                         master, options, tsigkey, timeout,
1586                                         udp_timeout, udp_retries, global_task,
1587                                         update_completed, NULL, &request);
1588         check_result(result, "dns_request_createvia3");
1589
1590         if (debugging)
1591                 show_message(updatemsg);
1592
1593         requests++;
1594 }
1595
1596 static void
1597 recvsoa(isc_task_t *task, isc_event_t *event) {
1598         dns_requestevent_t *reqev = NULL;
1599         dns_request_t *request = NULL;
1600         isc_result_t result, eresult;
1601         dns_message_t *rcvmsg = NULL;
1602         dns_section_t section;
1603         dns_name_t *name = NULL;
1604         dns_rdataset_t *soaset = NULL;
1605         dns_rdata_soa_t soa;
1606         dns_rdata_t soarr = DNS_RDATA_INIT;
1607         int pass = 0;
1608         dns_name_t master;
1609         isc_sockaddr_t *serveraddr, tempaddr;
1610         dns_name_t *zonename;
1611         nsu_requestinfo_t *reqinfo;
1612         dns_message_t *soaquery = NULL;
1613         isc_sockaddr_t *addr;
1614         isc_boolean_t seencname = ISC_FALSE;
1615         dns_name_t tname;
1616         unsigned int nlabels;
1617
1618         UNUSED(task);
1619
1620         ddebug("recvsoa()");
1621
1622         requests--;
1623
1624         REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1625         reqev = (dns_requestevent_t *)event;
1626         request = reqev->request;
1627         eresult = reqev->result;
1628         reqinfo = reqev->ev_arg;
1629         soaquery = reqinfo->msg;
1630         addr = reqinfo->addr;
1631
1632         if (shuttingdown) {
1633                 dns_request_destroy(&request);
1634                 dns_message_destroy(&soaquery);
1635                 isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
1636                 isc_event_free(&event);
1637                 maybeshutdown();
1638                 return;
1639         }
1640
1641         if (eresult != ISC_R_SUCCESS) {
1642                 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
1643
1644                 isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
1645                 fprintf(stderr, "; Communication with %s failed: %s\n",
1646                        addrbuf, isc_result_totext(eresult));
1647                 if (userserver != NULL)
1648                         fatal("could not talk to specified name server");
1649                 else if (++ns_inuse >= lwconf->nsnext)
1650                         fatal("could not talk to any default name server");
1651                 ddebug("Destroying request [%p]", request);
1652                 dns_request_destroy(&request);
1653                 dns_message_renderreset(soaquery);
1654                 dns_message_settsigkey(soaquery, NULL);
1655                 sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
1656                 isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
1657                 isc_event_free(&event);
1658                 setzoneclass(dns_rdataclass_none);
1659                 return;
1660         }
1661
1662         isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
1663         reqinfo = NULL;
1664         isc_event_free(&event);
1665         reqev = NULL;
1666
1667         ddebug("About to create rcvmsg");
1668         result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
1669         check_result(result, "dns_message_create");
1670         result = dns_request_getresponse(request, rcvmsg,
1671                                          DNS_MESSAGEPARSE_PRESERVEORDER);
1672         if (result == DNS_R_TSIGERRORSET && userserver != NULL) {
1673                 dns_message_destroy(&rcvmsg);
1674                 ddebug("Destroying request [%p]", request);
1675                 dns_request_destroy(&request);
1676                 reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t));
1677                 if (reqinfo == NULL)
1678                         fatal("out of memory");
1679                 reqinfo->msg = soaquery;
1680                 reqinfo->addr = addr;
1681                 dns_message_renderreset(soaquery);
1682                 ddebug("retrying soa request without TSIG");
1683                 result = dns_request_createvia3(requestmgr, soaquery,
1684                                                 localaddr, addr, 0, NULL,
1685                                                 FIND_TIMEOUT * 20,
1686                                                 FIND_TIMEOUT, 3,
1687                                                 global_task, recvsoa, reqinfo,
1688                                                 &request);
1689                 check_result(result, "dns_request_createvia");
1690                 requests++;
1691                 return;
1692         }
1693         check_result(result, "dns_request_getresponse");
1694         section = DNS_SECTION_ANSWER;
1695         if (debugging) {
1696                 isc_buffer_t *buf = NULL;
1697                 int bufsz;
1698                 bufsz = INITTEXT;
1699                 do {
1700                         if (buf != NULL)
1701                                 isc_buffer_free(&buf);
1702                         if (bufsz > MAXTEXT) {
1703                                 fprintf(stderr, "could not allocate enough "
1704                                          "space for debugging message\n");
1705                                 exit(1);
1706                         }
1707                         result = isc_buffer_allocate(mctx, &buf, bufsz);
1708                         check_result(result, "isc_buffer_allocate");
1709                         result = dns_message_totext(rcvmsg, style, 0, buf);
1710                 } while (result == ISC_R_NOSPACE);
1711                 check_result(result, "dns_message_totext");
1712                 fprintf(stderr, "Reply from SOA query:\n%.*s\n",
1713                         (int)isc_buffer_usedlength(buf),
1714                         (char*)isc_buffer_base(buf));
1715                 isc_buffer_free(&buf);
1716         }
1717
1718         if (rcvmsg->rcode != dns_rcode_noerror &&
1719             rcvmsg->rcode != dns_rcode_nxdomain)
1720                 fatal("response to SOA query was unsuccessful");
1721
1722         if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) {
1723                 char namebuf[DNS_NAME_FORMATSIZE];
1724                 dns_name_format(userzone, namebuf, sizeof(namebuf));
1725                 error("specified zone '%s' does not exist (NXDOMAIN)",
1726                       namebuf);
1727                 dns_message_destroy(&rcvmsg);
1728                 dns_request_destroy(&request);
1729                 dns_message_destroy(&soaquery);
1730                 ddebug("Out of recvsoa");
1731                 done_update();
1732                 return;
1733         }
1734
1735  lookforsoa:
1736         if (pass == 0)
1737                 section = DNS_SECTION_ANSWER;
1738         else if (pass == 1)
1739                 section = DNS_SECTION_AUTHORITY;
1740         else
1741                 goto droplabel;
1742
1743         result = dns_message_firstname(rcvmsg, section);
1744         if (result != ISC_R_SUCCESS) {
1745                 pass++;
1746                 goto lookforsoa;
1747         }
1748         while (result == ISC_R_SUCCESS) {
1749                 name = NULL;
1750                 dns_message_currentname(rcvmsg, section, &name);
1751                 soaset = NULL;
1752                 result = dns_message_findtype(name, dns_rdatatype_soa, 0,
1753                                               &soaset);
1754                 if (result == ISC_R_SUCCESS)
1755                         break;
1756                 if (section == DNS_SECTION_ANSWER) {
1757                         dns_rdataset_t *tset = NULL;
1758                         if (dns_message_findtype(name, dns_rdatatype_cname, 0,
1759                                                  &tset) == ISC_R_SUCCESS
1760                             ||
1761                             dns_message_findtype(name, dns_rdatatype_dname, 0,
1762                                                  &tset) == ISC_R_SUCCESS
1763                             )
1764                         {
1765                                 seencname = ISC_TRUE;
1766                                 break;
1767                         }
1768                 }
1769
1770                 result = dns_message_nextname(rcvmsg, section);
1771         }
1772
1773         if (soaset == NULL && !seencname) {
1774                 pass++;
1775                 goto lookforsoa;
1776         }
1777
1778         if (seencname)
1779                 goto droplabel;
1780
1781         if (debugging) {
1782                 char namestr[DNS_NAME_FORMATSIZE];
1783                 dns_name_format(name, namestr, sizeof(namestr));
1784                 fprintf(stderr, "Found zone name: %s\n", namestr);
1785         }
1786
1787         result = dns_rdataset_first(soaset);
1788         check_result(result, "dns_rdataset_first");
1789
1790         dns_rdata_init(&soarr);
1791         dns_rdataset_current(soaset, &soarr);
1792         result = dns_rdata_tostruct(&soarr, &soa, NULL);
1793         check_result(result, "dns_rdata_tostruct");
1794
1795         dns_name_init(&master, NULL);
1796         dns_name_clone(&soa.origin, &master);
1797
1798         if (userzone != NULL)
1799                 zonename = userzone;
1800         else
1801                 zonename = name;
1802
1803         if (debugging) {
1804                 char namestr[DNS_NAME_FORMATSIZE];
1805                 dns_name_format(&master, namestr, sizeof(namestr));
1806                 fprintf(stderr, "The master is: %s\n", namestr);
1807         }
1808
1809         if (userserver != NULL)
1810                 serveraddr = userserver;
1811         else {
1812                 char serverstr[DNS_NAME_MAXTEXT+1];
1813                 isc_buffer_t buf;
1814
1815                 isc_buffer_init(&buf, serverstr, sizeof(serverstr));
1816                 result = dns_name_totext(&master, ISC_TRUE, &buf);
1817                 check_result(result, "dns_name_totext");
1818                 serverstr[isc_buffer_usedlength(&buf)] = 0;
1819                 get_address(serverstr, DNSDEFAULTPORT, &tempaddr);
1820                 serveraddr = &tempaddr;
1821         }
1822         dns_rdata_freestruct(&soa);
1823
1824         send_update(zonename, serveraddr, localaddr);
1825         setzoneclass(dns_rdataclass_none);
1826
1827         dns_message_destroy(&soaquery);
1828         dns_request_destroy(&request);
1829
1830  out:
1831         dns_message_destroy(&rcvmsg);
1832         ddebug("Out of recvsoa");
1833         return;
1834
1835  droplabel:
1836         result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
1837         INSIST(result == ISC_R_SUCCESS);
1838         name = NULL;
1839         dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
1840         nlabels = dns_name_countlabels(name);
1841         if (nlabels == 1)
1842                 fatal("could not find enclosing zone");
1843         dns_name_init(&tname, NULL);
1844         dns_name_getlabelsequence(name, 1, nlabels - 1, &tname);
1845         dns_name_clone(&tname, name);
1846         dns_request_destroy(&request);
1847         dns_message_renderreset(soaquery);
1848         dns_message_settsigkey(soaquery, NULL);
1849         if (userserver != NULL)
1850                 sendrequest(localaddr, userserver, soaquery, &request);
1851         else
1852                 sendrequest(localaddr, &servers[ns_inuse], soaquery,
1853                             &request);
1854         goto out;
1855 }
1856
1857 static void
1858 sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
1859             dns_message_t *msg, dns_request_t **request)
1860 {
1861         isc_result_t result;
1862         nsu_requestinfo_t *reqinfo;
1863
1864         reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t));
1865         if (reqinfo == NULL)
1866                 fatal("out of memory");
1867         reqinfo->msg = msg;
1868         reqinfo->addr = destaddr;
1869         result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0,
1870                                         (userserver != NULL) ? tsigkey : NULL,
1871                                         FIND_TIMEOUT * 20, FIND_TIMEOUT, 3,
1872                                         global_task, recvsoa, reqinfo, request);
1873         check_result(result, "dns_request_createvia");
1874         requests++;
1875 }
1876
1877 static void
1878 start_update(void) {
1879         isc_result_t result;
1880         dns_rdataset_t *rdataset = NULL;
1881         dns_name_t *name = NULL;
1882         dns_request_t *request = NULL;
1883         dns_message_t *soaquery = NULL;
1884         dns_name_t *firstname;
1885         dns_section_t section = DNS_SECTION_UPDATE;
1886
1887         ddebug("start_update()");
1888
1889         if (answer != NULL)
1890                 dns_message_destroy(&answer);
1891
1892         if (userzone != NULL && userserver != NULL) {
1893                 send_update(userzone, userserver, localaddr);
1894                 setzoneclass(dns_rdataclass_none);
1895                 return;
1896         }
1897
1898         result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
1899                                     &soaquery);
1900         check_result(result, "dns_message_create");
1901
1902         if (userserver == NULL)
1903                 soaquery->flags |= DNS_MESSAGEFLAG_RD;
1904
1905         result = dns_message_gettempname(soaquery, &name);
1906         check_result(result, "dns_message_gettempname");
1907
1908         result = dns_message_gettemprdataset(soaquery, &rdataset);
1909         check_result(result, "dns_message_gettemprdataset");
1910
1911         dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa);
1912
1913         if (userzone != NULL) {
1914                 dns_name_init(name, NULL);
1915                 dns_name_clone(userzone, name);
1916         } else {
1917                 result = dns_message_firstname(updatemsg, section);
1918                 if (result == ISC_R_NOMORE) {
1919                         section = DNS_SECTION_PREREQUISITE;
1920                         result = dns_message_firstname(updatemsg, section);
1921                 }
1922                 if (result != ISC_R_SUCCESS) {
1923                         done_update();
1924                         return;
1925                 }
1926                 firstname = NULL;
1927                 dns_message_currentname(updatemsg, section, &firstname);
1928                 dns_name_init(name, NULL);
1929                 dns_name_clone(firstname, name);
1930         }
1931
1932         ISC_LIST_INIT(name->list);
1933         ISC_LIST_APPEND(name->list, rdataset, link);
1934         dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
1935
1936         if (userserver != NULL)
1937                 sendrequest(localaddr, userserver, soaquery, &request);
1938         else {
1939                 ns_inuse = 0;
1940                 sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
1941         }
1942 }
1943
1944 static void
1945 cleanup(void) {
1946         ddebug("cleanup()");
1947
1948         if (answer != NULL)
1949                 dns_message_destroy(&answer);
1950         ddebug("Shutting down task manager");
1951         isc_taskmgr_destroy(&taskmgr);
1952
1953         ddebug("Destroying event");
1954         isc_event_free(&global_event);
1955
1956         ddebug("Shutting down socket manager");
1957         isc_socketmgr_destroy(&socketmgr);
1958
1959         ddebug("Shutting down timer manager");
1960         isc_timermgr_destroy(&timermgr);
1961
1962         ddebug("Destroying hash context");
1963         isc_hash_destroy();
1964
1965         ddebug("Destroying memory context");
1966         if (memdebugging)
1967                 isc_mem_stats(mctx, stderr);
1968         isc_mem_destroy(&mctx);
1969 }
1970
1971 static void
1972 getinput(isc_task_t *task, isc_event_t *event) {
1973         isc_boolean_t more;
1974
1975         UNUSED(task);
1976
1977         if (shuttingdown) {
1978                 maybeshutdown();
1979                 return;
1980         }
1981
1982         if (global_event == NULL)
1983                 global_event = event;
1984
1985         reset_system();
1986         more = user_interaction();
1987         if (!more) {
1988                 isc_app_shutdown();
1989                 return;
1990         }
1991         start_update();
1992         return;
1993 }
1994
1995 int
1996 main(int argc, char **argv) {
1997         isc_result_t result;
1998         style = &dns_master_style_debug;
1999
2000         input = stdin;
2001
2002         interactive = ISC_TF(isatty(0));
2003
2004         isc_app_start();
2005
2006         parse_args(argc, argv);
2007
2008         setup_system();
2009
2010         result = isc_app_onrun(mctx, global_task, getinput, NULL);
2011         check_result(result, "isc_app_onrun");
2012
2013         (void)isc_app_run();
2014
2015         cleanup();
2016
2017         isc_app_finish();
2018
2019         if (seenerror)
2020                 return (2);
2021         else
2022                 return (0);
2023 }