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