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, &region);
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, &region);
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, &region);
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, &region);
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, &region);
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, &region);
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