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