]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/export/samples/sample-update.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / export / samples / sample-update.c
1 /*
2  * Copyright (C) 2009, 2010  Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 /* $Id: sample-update.c,v 1.10 2010/12/09 00:54:34 marka Exp $ */
18
19 #include <config.h>
20
21 #include <sys/types.h>
22 #include <sys/socket.h>
23
24 #include <netinet/in.h>
25
26 #include <arpa/inet.h>
27
28 #include <unistd.h>
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <netdb.h>
34
35 #include <isc/buffer.h>
36 #include <isc/lex.h>
37 #include <isc/lib.h>
38 #include <isc/mem.h>
39 #include <isc/parseint.h>
40 #include <isc/sockaddr.h>
41 #include <isc/util.h>
42
43 #include <dns/callbacks.h>
44 #include <dns/client.h>
45 #include <dns/fixedname.h>
46 #include <dns/lib.h>
47 #include <dns/name.h>
48 #include <dns/rdata.h>
49 #include <dns/rdataclass.h>
50 #include <dns/rdatalist.h>
51 #include <dns/rdataset.h>
52 #include <dns/rdatastruct.h>
53 #include <dns/rdatatype.h>
54 #include <dns/result.h>
55 #include <dns/secalg.h>
56 #include <dns/tsec.h>
57
58 #include <dst/dst.h>
59
60 static dns_tsec_t *tsec = NULL;
61 static const dns_rdataclass_t default_rdataclass = dns_rdataclass_in;
62 static isc_bufferlist_t usedbuffers;
63 static ISC_LIST(dns_rdatalist_t) usedrdatalists;
64
65 static void setup_tsec(char *keyfile, isc_mem_t *mctx);
66 static void update_addordelete(isc_mem_t *mctx, char *cmdline,
67                                isc_boolean_t isdelete, dns_name_t *name);
68 static void evaluate_prereq(isc_mem_t *mctx, char *cmdline, dns_name_t *name);
69
70 ISC_PLATFORM_NORETURN_PRE static void
71 usage(void) ISC_PLATFORM_NORETURN_POST;
72
73 static void
74 usage(void) {
75         fprintf(stderr, "sample-update "
76                 "[-a auth_server] "
77                 "[-k keyfile] "
78                 "[-p prerequisite] "
79                 "[-r recursive_server] "
80                 "[-z zonename] "
81                 "(add|delete) \"name TTL RRtype RDATA\"\n");
82         exit(1);
83 }
84
85 int
86 main(int argc, char *argv[]) {
87         int ch;
88         struct addrinfo hints, *res;
89         int gai_error;
90         dns_client_t *client = NULL;
91         char *zonenamestr = NULL;
92         char *keyfilename = NULL;
93         char *prereqstr = NULL;
94         isc_sockaddrlist_t auth_servers;
95         char *auth_server = NULL;
96         char *recursive_server = NULL;
97         isc_sockaddr_t sa_auth, sa_recursive;
98         isc_sockaddrlist_t rec_servers;
99         isc_result_t result;
100         isc_boolean_t isdelete;
101         isc_buffer_t b, *buf;
102         dns_fixedname_t zname0, pname0, uname0;
103         size_t namelen;
104         dns_name_t *zname = NULL, *uname, *pname;
105         dns_rdataset_t *rdataset;
106         dns_rdatalist_t *rdatalist;
107         dns_rdata_t *rdata;
108         dns_namelist_t updatelist, prereqlist, *prereqlistp = NULL;
109         isc_mem_t *umctx = NULL;
110
111         while ((ch = getopt(argc, argv, "a:k:p:r:z:")) != -1) {
112                 switch (ch) {
113                 case 'k':
114                         keyfilename = optarg;
115                         break;
116                 case 'a':
117                         auth_server = optarg;
118                         break;
119                 case 'p':
120                         prereqstr = optarg;
121                         break;
122                 case 'r':
123                         recursive_server = optarg;
124                         break;
125                 case 'z':
126                         zonenamestr = optarg;
127                         break;
128                 default:
129                         usage();
130                 }
131         }
132
133         argc -= optind;
134         argv += optind;
135         if (argc < 2)
136                 usage();
137
138         /* command line argument validation */
139         if (strcmp(argv[0], "delete") == 0)
140                 isdelete = ISC_TRUE;
141         else if (strcmp(argv[0], "add") == 0)
142                 isdelete = ISC_FALSE;
143         else {
144                 fprintf(stderr, "invalid update command: %s\n", argv[0]);
145                 exit(1);
146         }
147
148         if (auth_server == NULL && recursive_server == NULL) {
149                 fprintf(stderr, "authoritative or recursive server "
150                         "must be specified\n");
151                 usage();
152         }
153
154         /* Initialization */
155         ISC_LIST_INIT(usedbuffers);
156         ISC_LIST_INIT(usedrdatalists);
157         ISC_LIST_INIT(prereqlist);
158         ISC_LIST_INIT(auth_servers);
159         isc_lib_register();
160         result = dns_lib_init();
161         if (result != ISC_R_SUCCESS) {
162                 fprintf(stderr, "dns_lib_init failed: %d\n", result);
163                 exit(1);
164         }
165         result = isc_mem_create(0, 0, &umctx);
166         if (result != ISC_R_SUCCESS) {
167                 fprintf(stderr, "failed to crate mctx\n");
168                 exit(1);
169         }
170
171         result = dns_client_create(&client, 0);
172         if (result != ISC_R_SUCCESS) {
173                 fprintf(stderr, "dns_client_create failed: %d\n", result);
174                 exit(1);
175         }
176
177         /* Set the authoritative server */
178         if (auth_server != NULL) {
179                 memset(&hints, 0, sizeof(hints));
180                 hints.ai_family = AF_UNSPEC;
181                 hints.ai_socktype = SOCK_DGRAM;
182                 hints.ai_protocol = IPPROTO_UDP;
183                 hints.ai_flags = AI_NUMERICHOST;
184                 gai_error = getaddrinfo(auth_server, "53", &hints, &res);
185                 if (gai_error != 0) {
186                         fprintf(stderr, "getaddrinfo failed: %s\n",
187                                 gai_strerror(gai_error));
188                         exit(1);
189                 }
190                 INSIST(res->ai_addrlen <= sizeof(sa_auth.type));
191                 memcpy(&sa_auth.type, res->ai_addr, res->ai_addrlen);
192                 freeaddrinfo(res);
193                 sa_auth.length = res->ai_addrlen;
194                 ISC_LINK_INIT(&sa_auth, link);
195
196                 ISC_LIST_APPEND(auth_servers, &sa_auth, link);
197         }
198
199         /* Set the recursive server */
200         if (recursive_server != NULL) {
201                 memset(&hints, 0, sizeof(hints));
202                 hints.ai_family = AF_UNSPEC;
203                 hints.ai_socktype = SOCK_DGRAM;
204                 hints.ai_protocol = IPPROTO_UDP;
205                 hints.ai_flags = AI_NUMERICHOST;
206                 gai_error = getaddrinfo(recursive_server, "53", &hints, &res);
207                 if (gai_error != 0) {
208                         fprintf(stderr, "getaddrinfo failed: %s\n",
209                                 gai_strerror(gai_error));
210                         exit(1);
211                 }
212                 INSIST(res->ai_addrlen <= sizeof(sa_recursive.type));
213                 memcpy(&sa_recursive.type, res->ai_addr, res->ai_addrlen);
214                 freeaddrinfo(res);
215                 sa_recursive.length = res->ai_addrlen;
216                 ISC_LINK_INIT(&sa_recursive, link);
217                 ISC_LIST_INIT(rec_servers);
218                 ISC_LIST_APPEND(rec_servers, &sa_recursive, link);
219                 result = dns_client_setservers(client, dns_rdataclass_in,
220                                                NULL, &rec_servers);
221                 if (result != ISC_R_SUCCESS) {
222                         fprintf(stderr, "set server failed: %d\n", result);
223                         exit(1);
224                 }
225         }
226
227         /* Construct zone name */
228         zname = NULL;
229         if (zonenamestr != NULL) {
230                 namelen = strlen(zonenamestr);
231                 isc_buffer_init(&b, zonenamestr, namelen);
232                 isc_buffer_add(&b, namelen);
233                 dns_fixedname_init(&zname0);
234                 zname = dns_fixedname_name(&zname0);
235                 result = dns_name_fromtext(zname, &b, dns_rootname, 0, NULL);
236                 if (result != ISC_R_SUCCESS)
237                         fprintf(stderr, "failed to convert zone name: %d\n",
238                                 result);
239         }
240
241         /* Construct prerequisite name (if given) */
242         if (prereqstr != NULL) {
243                 dns_fixedname_init(&pname0);
244                 pname = dns_fixedname_name(&pname0);
245                 evaluate_prereq(umctx, prereqstr, pname);
246                 ISC_LIST_APPEND(prereqlist, pname, link);
247                 prereqlistp = &prereqlist;
248         }
249
250         /* Construct update name */
251         ISC_LIST_INIT(updatelist);
252         dns_fixedname_init(&uname0);
253         uname = dns_fixedname_name(&uname0);
254         update_addordelete(umctx, argv[1], isdelete, uname);
255         ISC_LIST_APPEND(updatelist, uname, link);
256
257         /* Set up TSIG/SIG(0) key (if given) */
258         if (keyfilename != NULL)
259                 setup_tsec(keyfilename, umctx);
260
261         /* Perform update */
262         result = dns_client_update(client,
263                                    default_rdataclass, /* XXX: fixed */
264                                    zname, prereqlistp, &updatelist,
265                                    (auth_server == NULL) ? NULL :
266                                    &auth_servers, tsec, 0);
267         if (result != ISC_R_SUCCESS) {
268                 fprintf(stderr,
269                         "update failed: %s\n", dns_result_totext(result));
270         } else
271                 fprintf(stderr, "update succeeded\n");
272
273         /* Cleanup */
274         while ((pname = ISC_LIST_HEAD(prereqlist)) != NULL) {
275                 while ((rdataset = ISC_LIST_HEAD(pname->list)) != NULL) {
276                         ISC_LIST_UNLINK(pname->list, rdataset, link);
277                         dns_rdataset_disassociate(rdataset);
278                         isc_mem_put(umctx, rdataset, sizeof(*rdataset));
279                 }
280                 ISC_LIST_UNLINK(prereqlist, pname, link);
281         }
282         while ((uname = ISC_LIST_HEAD(updatelist)) != NULL) {
283                 while ((rdataset = ISC_LIST_HEAD(uname->list)) != NULL) {
284                         ISC_LIST_UNLINK(uname->list, rdataset, link);
285                         dns_rdataset_disassociate(rdataset);
286                         isc_mem_put(umctx, rdataset, sizeof(*rdataset));
287                 }
288                 ISC_LIST_UNLINK(updatelist, uname, link);
289         }
290         while ((rdatalist = ISC_LIST_HEAD(usedrdatalists)) != NULL) {
291                 while ((rdata = ISC_LIST_HEAD(rdatalist->rdata)) != NULL) {
292                         ISC_LIST_UNLINK(rdatalist->rdata, rdata, link);
293                         isc_mem_put(umctx, rdata, sizeof(*rdata));
294                 }
295                 ISC_LIST_UNLINK(usedrdatalists, rdatalist, link);
296                 isc_mem_put(umctx, rdatalist, sizeof(*rdatalist));
297         }
298         while ((buf = ISC_LIST_HEAD(usedbuffers)) != NULL) {
299                 ISC_LIST_UNLINK(usedbuffers, buf, link);
300                 isc_buffer_free(&buf);
301         }
302         if (tsec != NULL)
303                 dns_tsec_destroy(&tsec);
304         isc_mem_destroy(&umctx);
305         dns_client_destroy(&client);
306         dns_lib_shutdown();
307
308         exit(0);
309 }
310
311 /*
312  *  Subroutines borrowed from nsupdate.c
313  */
314 #define MAXWIRE (64 * 1024)
315 #define TTL_MAX 2147483647U     /* Maximum signed 32 bit integer. */
316
317 static char *
318 nsu_strsep(char **stringp, const char *delim) {
319         char *string = *stringp;
320         char *s;
321         const char *d;
322         char sc, dc;
323
324         if (string == NULL)
325                 return (NULL);
326
327         for (; *string != '\0'; string++) {
328                 sc = *string;
329                 for (d = delim; (dc = *d) != '\0'; d++) {
330                         if (sc == dc)
331                                 break;
332                 }
333                 if (dc == 0)
334                         break;
335         }
336
337         for (s = string; *s != '\0'; s++) {
338                 sc = *s;
339                 for (d = delim; (dc = *d) != '\0'; d++) {
340                         if (sc == dc) {
341                                 *s++ = '\0';
342                                 *stringp = s;
343                                 return (string);
344                         }
345                 }
346         }
347         *stringp = NULL;
348         return (string);
349 }
350
351 static void
352 fatal(const char *format, ...) {
353         va_list args;
354
355         va_start(args, format);
356         vfprintf(stderr, format, args);
357         va_end(args);
358         fprintf(stderr, "\n");
359         exit(1);
360 }
361
362 static inline void
363 check_result(isc_result_t result, const char *msg) {
364         if (result != ISC_R_SUCCESS)
365                 fatal("%s: %s", msg, isc_result_totext(result));
366 }
367
368 static void
369 parse_name(char **cmdlinep, dns_name_t *name) {
370         isc_result_t result;
371         char *word;
372         isc_buffer_t source;
373
374         word = nsu_strsep(cmdlinep, " \t\r\n");
375         if (*word == 0) {
376                 fprintf(stderr, "could not read owner name\n");
377                 exit(1);
378         }
379
380         isc_buffer_init(&source, word, strlen(word));
381         isc_buffer_add(&source, strlen(word));
382         result = dns_name_fromtext(name, &source, dns_rootname, 0, NULL);
383         check_result(result, "dns_name_fromtext");
384         isc_buffer_invalidate(&source);
385 }
386
387 static void
388 parse_rdata(isc_mem_t *mctx, char **cmdlinep, dns_rdataclass_t rdataclass,
389             dns_rdatatype_t rdatatype, dns_rdata_t *rdata)
390 {
391         char *cmdline = *cmdlinep;
392         isc_buffer_t source, *buf = NULL, *newbuf = NULL;
393         isc_region_t r;
394         isc_lex_t *lex = NULL;
395         dns_rdatacallbacks_t callbacks;
396         isc_result_t result;
397
398         while (cmdline != NULL && *cmdline != 0 &&
399                isspace((unsigned char)*cmdline))
400                 cmdline++;
401
402         if (cmdline != NULL && *cmdline != 0) {
403                 dns_rdatacallbacks_init(&callbacks);
404                 result = isc_lex_create(mctx, strlen(cmdline), &lex);
405                 check_result(result, "isc_lex_create");
406                 isc_buffer_init(&source, cmdline, strlen(cmdline));
407                 isc_buffer_add(&source, strlen(cmdline));
408                 result = isc_lex_openbuffer(lex, &source);
409                 check_result(result, "isc_lex_openbuffer");
410                 result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
411                 check_result(result, "isc_buffer_allocate");
412                 result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex,
413                                             dns_rootname, 0, mctx, buf,
414                                             &callbacks);
415                 isc_lex_destroy(&lex);
416                 if (result == ISC_R_SUCCESS) {
417                         isc_buffer_usedregion(buf, &r);
418                         result = isc_buffer_allocate(mctx, &newbuf, r.length);
419                         check_result(result, "isc_buffer_allocate");
420                         isc_buffer_putmem(newbuf, r.base, r.length);
421                         isc_buffer_usedregion(newbuf, &r);
422                         dns_rdata_reset(rdata);
423                         dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r);
424                         isc_buffer_free(&buf);
425                         ISC_LIST_APPEND(usedbuffers, newbuf, link);
426                 } else {
427                         fprintf(stderr, "invalid rdata format: %s\n",
428                                 isc_result_totext(result));
429                         isc_buffer_free(&buf);
430                         exit(1);
431                 }
432         } else {
433                 rdata->flags = DNS_RDATA_UPDATE;
434         }
435         *cmdlinep = cmdline;
436 }
437
438 static void
439 update_addordelete(isc_mem_t *mctx, char *cmdline, isc_boolean_t isdelete,
440                    dns_name_t *name)
441 {
442         isc_result_t result;
443         isc_uint32_t ttl;
444         char *word;
445         dns_rdataclass_t rdataclass;
446         dns_rdatatype_t rdatatype;
447         dns_rdata_t *rdata = NULL;
448         dns_rdatalist_t *rdatalist = NULL;
449         dns_rdataset_t *rdataset = NULL;
450         isc_textregion_t region;
451
452         /*
453          * Read the owner name.
454          */
455         parse_name(&cmdline, name);
456
457         rdata = isc_mem_get(mctx, sizeof(*rdata));
458         if (rdata == NULL) {
459                 fprintf(stderr, "memory allocation for rdata failed\n");
460                 exit(1);
461         }
462         dns_rdata_init(rdata);
463
464         /*
465          * If this is an add, read the TTL and verify that it's in range.
466          * If it's a delete, ignore a TTL if present (for compatibility).
467          */
468         word = nsu_strsep(&cmdline, " \t\r\n");
469         if (word == NULL || *word == 0) {
470                 if (!isdelete) {
471                         fprintf(stderr, "could not read owner ttl\n");
472                         exit(1);
473                 }
474                 else {
475                         ttl = 0;
476                         rdataclass = dns_rdataclass_any;
477                         rdatatype = dns_rdatatype_any;
478                         rdata->flags = DNS_RDATA_UPDATE;
479                         goto doneparsing;
480                 }
481         }
482         result = isc_parse_uint32(&ttl, word, 10);
483         if (result != ISC_R_SUCCESS) {
484                 if (isdelete) {
485                         ttl = 0;
486                         goto parseclass;
487                 } else {
488                         fprintf(stderr, "ttl '%s': %s\n", word,
489                                 isc_result_totext(result));
490                         exit(1);
491                 }
492         }
493
494         if (isdelete)
495                 ttl = 0;
496         else if (ttl > TTL_MAX) {
497                 fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n",
498                         word, TTL_MAX);
499                 exit(1);
500         }
501
502         /*
503          * Read the class or type.
504          */
505         word = nsu_strsep(&cmdline, " \t\r\n");
506  parseclass:
507         if (word == NULL || *word == 0) {
508                 if (isdelete) {
509                         rdataclass = dns_rdataclass_any;
510                         rdatatype = dns_rdatatype_any;
511                         rdata->flags = DNS_RDATA_UPDATE;
512                 goto doneparsing;
513                 } else {
514                         fprintf(stderr, "could not read class or type\n");
515                         exit(1);
516                 }
517         }
518         region.base = word;
519         region.length = strlen(word);
520         result = dns_rdataclass_fromtext(&rdataclass, &region);
521         if (result == ISC_R_SUCCESS) {
522                 /*
523                  * Now read the type.
524                  */
525                 word = nsu_strsep(&cmdline, " \t\r\n");
526                 if (word == NULL || *word == 0) {
527                         if (isdelete) {
528                                 rdataclass = dns_rdataclass_any;
529                                 rdatatype = dns_rdatatype_any;
530                                 rdata->flags = DNS_RDATA_UPDATE;
531                                 goto doneparsing;
532                         } else {
533                                 fprintf(stderr, "could not read type\n");
534                                 exit(1);
535                         }
536                 }
537                 region.base = word;
538                 region.length = strlen(word);
539                 result = dns_rdatatype_fromtext(&rdatatype, &region);
540                 if (result != ISC_R_SUCCESS) {
541                         fprintf(stderr, "'%s' is not a valid type: %s\n",
542                                 word, isc_result_totext(result));
543                         exit(1);
544                 }
545         } else {
546                 rdataclass = default_rdataclass;
547                 result = dns_rdatatype_fromtext(&rdatatype, &region);
548                 if (result != ISC_R_SUCCESS) {
549                         fprintf(stderr, "'%s' is not a valid class or type: "
550                                 "%s\n", word, isc_result_totext(result));
551                         exit(1);
552                 }
553         }
554
555         parse_rdata(mctx, &cmdline, rdataclass, rdatatype, rdata);
556
557         if (isdelete) {
558                 if ((rdata->flags & DNS_RDATA_UPDATE) != 0)
559                         rdataclass = dns_rdataclass_any;
560                 else
561                         rdataclass = dns_rdataclass_none;
562         } else {
563                 if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
564                         fprintf(stderr, "could not read rdata\n");
565                         exit(1);
566                 }
567         }
568
569  doneparsing:
570
571         rdatalist = isc_mem_get(mctx, sizeof(*rdatalist));
572         if (rdatalist == NULL) {
573                 fprintf(stderr, "memory allocation for rdatalist failed\n");
574                 exit(1);
575         }
576         dns_rdatalist_init(rdatalist);
577         rdatalist->type = rdatatype;
578         rdatalist->rdclass = rdataclass;
579         rdatalist->covers = rdatatype;
580         rdatalist->ttl = (dns_ttl_t)ttl;
581         ISC_LIST_INIT(rdatalist->rdata);
582         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
583         ISC_LIST_APPEND(usedrdatalists, rdatalist, link);
584
585         rdataset = isc_mem_get(mctx, sizeof(*rdataset));
586         if (rdataset == NULL) {
587                 fprintf(stderr, "memory allocation for rdataset failed\n");
588                 exit(1);
589         }
590         dns_rdataset_init(rdataset);
591         dns_rdatalist_tordataset(rdatalist, rdataset);
592         ISC_LIST_INIT(name->list);
593         ISC_LIST_APPEND(name->list, rdataset, link);
594 }
595
596 static void
597 make_prereq(isc_mem_t *mctx, char *cmdline, isc_boolean_t ispositive,
598             isc_boolean_t isrrset, dns_name_t *name)
599 {
600         isc_result_t result;
601         char *word;
602         isc_textregion_t region;
603         dns_rdataset_t *rdataset = NULL;
604         dns_rdatalist_t *rdatalist = NULL;
605         dns_rdataclass_t rdataclass;
606         dns_rdatatype_t rdatatype;
607         dns_rdata_t *rdata = NULL;
608
609         /*
610          * Read the owner name
611          */
612         parse_name(&cmdline, name);
613
614         /*
615          * If this is an rrset prereq, read the class or type.
616          */
617         if (isrrset) {
618                 word = nsu_strsep(&cmdline, " \t\r\n");
619                 if (word == NULL || *word == 0) {
620                         fprintf(stderr, "could not read class or type\n");
621                         exit(1);
622                 }
623                 region.base = word;
624                 region.length = strlen(word);
625                 result = dns_rdataclass_fromtext(&rdataclass, &region);
626                 if (result == ISC_R_SUCCESS) {
627                         /*
628                          * Now read the type.
629                          */
630                         word = nsu_strsep(&cmdline, " \t\r\n");
631                         if (word == NULL || *word == 0) {
632                                 fprintf(stderr, "could not read type\n");
633                                 exit(1);
634                         }
635                         region.base = word;
636                         region.length = strlen(word);
637                         result = dns_rdatatype_fromtext(&rdatatype, &region);
638                         if (result != ISC_R_SUCCESS) {
639                                 fprintf(stderr, "invalid type: %s\n", word);
640                                 exit(1);
641                         }
642                 } else {
643                         rdataclass = default_rdataclass;
644                         result = dns_rdatatype_fromtext(&rdatatype, &region);
645                         if (result != ISC_R_SUCCESS) {
646                                 fprintf(stderr, "invalid type: %s\n", word);
647                                 exit(1);
648                         }
649                 }
650         } else
651                 rdatatype = dns_rdatatype_any;
652
653         rdata = isc_mem_get(mctx, sizeof(*rdata));
654         if (rdata == NULL) {
655                 fprintf(stderr, "memory allocation for rdata failed\n");
656                 exit(1);
657         }
658         dns_rdata_init(rdata);
659
660         if (isrrset && ispositive)
661                 parse_rdata(mctx, &cmdline, rdataclass, rdatatype, rdata);
662         else
663                 rdata->flags = DNS_RDATA_UPDATE;
664
665         rdatalist = isc_mem_get(mctx, sizeof(*rdatalist));
666         if (rdatalist == NULL) {
667                 fprintf(stderr, "memory allocation for rdatalist failed\n");
668                 exit(1);
669         }
670         dns_rdatalist_init(rdatalist);
671         rdatalist->type = rdatatype;
672         if (ispositive) {
673                 if (isrrset && rdata->data != NULL)
674                         rdatalist->rdclass = rdataclass;
675                 else
676                         rdatalist->rdclass = dns_rdataclass_any;
677         } else
678                 rdatalist->rdclass = dns_rdataclass_none;
679         rdatalist->covers = 0;
680         rdatalist->ttl = 0;
681         rdata->rdclass = rdatalist->rdclass;
682         rdata->type = rdatatype;
683         ISC_LIST_INIT(rdatalist->rdata);
684         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
685         ISC_LIST_APPEND(usedrdatalists, rdatalist, link);
686
687         rdataset = isc_mem_get(mctx, sizeof(*rdataset));
688         if (rdataset == NULL) {
689                 fprintf(stderr, "memory allocation for rdataset failed\n");
690                 exit(1);
691         }
692         dns_rdataset_init(rdataset);
693         dns_rdatalist_tordataset(rdatalist, rdataset);
694         ISC_LIST_INIT(name->list);
695         ISC_LIST_APPEND(name->list, rdataset, link);
696 }
697
698 static void
699 evaluate_prereq(isc_mem_t *mctx, char *cmdline, dns_name_t *name) {
700         char *word;
701         isc_boolean_t ispositive, isrrset;
702
703         word = nsu_strsep(&cmdline, " \t\r\n");
704         if (word == NULL || *word == 0) {
705                 fprintf(stderr, "could not read operation code\n");
706                 exit(1);
707         }
708         if (strcasecmp(word, "nxdomain") == 0) {
709                 ispositive = ISC_FALSE;
710                 isrrset = ISC_FALSE;
711         } else if (strcasecmp(word, "yxdomain") == 0) {
712                 ispositive = ISC_TRUE;
713                 isrrset = ISC_FALSE;
714         } else if (strcasecmp(word, "nxrrset") == 0) {
715                 ispositive = ISC_FALSE;
716                 isrrset = ISC_TRUE;
717         } else if (strcasecmp(word, "yxrrset") == 0) {
718                 ispositive = ISC_TRUE;
719                 isrrset = ISC_TRUE;
720         } else {
721                 fprintf(stderr, "incorrect operation code: %s\n", word);
722                 exit(1);
723         }
724
725         make_prereq(mctx, cmdline, ispositive, isrrset, name);
726 }
727
728 static void
729 setup_tsec(char *keyfile, isc_mem_t *mctx) {
730         dst_key_t *dstkey = NULL;
731         isc_result_t result;
732         dns_tsectype_t tsectype;
733
734         result = dst_key_fromnamedfile(keyfile, NULL,
735                                        DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
736                                        &dstkey);
737         if (result != ISC_R_SUCCESS) {
738                 fprintf(stderr, "could not read key from %s: %s\n",
739                         keyfile, isc_result_totext(result));
740                 exit(1);
741         }
742
743         if (dst_key_alg(dstkey) == DST_ALG_HMACMD5)
744                 tsectype = dns_tsectype_tsig;
745         else
746                 tsectype = dns_tsectype_sig0;
747
748         result = dns_tsec_create(mctx, tsectype, dstkey, &tsec);
749         dst_key_free(&dstkey);
750         if (result != ISC_R_SUCCESS) {
751                 fprintf(stderr, "could not create tsec: %s\n",
752                         isc_result_totext(result));
753                 exit(1);
754         }
755 }