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