1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 #include <config.h>
13 
14 #ifndef WIN32
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 
18 #include <netinet/in.h>
19 
20 #include <arpa/inet.h>
21 
22 #include <netdb.h>
23 #include <unistd.h>
24 #endif
25 
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include <isc/base64.h>
32 #include <isc/buffer.h>
33 #include <isc/commandline.h>
34 #include <isc/lib.h>
35 #include <isc/mem.h>
36 #include <isc/print.h>
37 #include <isc/sockaddr.h>
38 #include <isc/util.h>
39 #include <isc/app.h>
40 #include <isc/task.h>
41 #include <isc/socket.h>
42 #include <isc/timer.h>
43 
44 #include <irs/resconf.h>
45 #include <irs/netdb.h>
46 
47 #include <dns/client.h>
48 #include <dns/fixedname.h>
49 #include <dns/keyvalues.h>
50 #include <dns/lib.h>
51 #include <dns/name.h>
52 #include <dns/rdata.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 
59 #include <dst/dst.h>
60 
61 static char *algname;
62 
63 static isc_result_t
printdata(dns_rdataset_t * rdataset,dns_name_t * owner)64 printdata(dns_rdataset_t *rdataset, dns_name_t *owner) {
65 	isc_buffer_t target;
66 	isc_result_t result;
67 	isc_region_t r;
68 	char t[4096];
69 
70 	if (!dns_rdataset_isassociated(rdataset)) {
71 		printf("[WARN: empty]\n");
72 		return (ISC_R_SUCCESS);
73 	}
74 
75 	isc_buffer_init(&target, t, sizeof(t));
76 
77 	result = dns_rdataset_totext(rdataset, owner, false, false,
78 				     &target);
79 	if (result != ISC_R_SUCCESS)
80 		return (result);
81 	isc_buffer_usedregion(&target, &r);
82 	printf("%.*s", (int)r.length, (char *)r.base);
83 
84 	return (ISC_R_SUCCESS);
85 }
86 
87 ISC_PLATFORM_NORETURN_PRE static void
88 usage(void) ISC_PLATFORM_NORETURN_POST;
89 
90 static void
usage(void)91 usage(void) {
92 	fprintf(stderr, "resolve [-t RRtype] "
93 		"[[-a algorithm] [-e] -k keyname -K keystring] "
94 		"[-S domain:serveraddr_for_domain ] [-s server_address]"
95 		"[-b address[#port]] hostname\n");
96 
97 	exit(1);
98 }
99 
100 static void
set_key(dns_client_t * client,char * keynamestr,char * keystr,bool is_sep,isc_mem_t ** mctxp)101 set_key(dns_client_t *client, char *keynamestr, char *keystr,
102 	bool is_sep, isc_mem_t **mctxp)
103 {
104 	isc_result_t result;
105 	dns_fixedname_t fkeyname;
106 	unsigned int namelen;
107 	dns_name_t *keyname;
108 	dns_rdata_dnskey_t keystruct;
109 	unsigned char keydata[4096];
110 	isc_buffer_t keydatabuf;
111 	unsigned char rrdata[4096];
112 	isc_buffer_t rrdatabuf;
113 	isc_buffer_t b;
114 	isc_textregion_t tr;
115 	isc_region_t r;
116 	dns_secalg_t alg;
117 
118 	result = isc_mem_create(0, 0, mctxp);
119 	if (result != ISC_R_SUCCESS) {
120 		fprintf(stderr, "failed to create mctx\n");
121 		exit(1);
122 	}
123 
124 	if (algname != NULL) {
125 		tr.base = algname;
126 		tr.length = strlen(algname);
127 		result = dns_secalg_fromtext(&alg, &tr);
128 		if (result != ISC_R_SUCCESS) {
129 			fprintf(stderr, "failed to identify the algorithm\n");
130 			exit(1);
131 		}
132 	} else
133 		alg = DNS_KEYALG_RSASHA1;
134 
135 	keystruct.common.rdclass = dns_rdataclass_in;
136 	keystruct.common.rdtype = dns_rdatatype_dnskey;
137 	keystruct.flags = DNS_KEYOWNER_ZONE; /* fixed */
138 	if (is_sep)
139 		keystruct.flags |= DNS_KEYFLAG_KSK;
140 	keystruct.protocol = DNS_KEYPROTO_DNSSEC; /* fixed */
141 	keystruct.algorithm = alg;
142 
143 	isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
144 	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
145 	result = isc_base64_decodestring(keystr, &keydatabuf);
146 	if (result != ISC_R_SUCCESS) {
147 		fprintf(stderr, "base64 decode failed\n");
148 		exit(1);
149 	}
150 	isc_buffer_usedregion(&keydatabuf, &r);
151 	keystruct.datalen = r.length;
152 	keystruct.data = r.base;
153 
154 	result = dns_rdata_fromstruct(NULL, keystruct.common.rdclass,
155 				      keystruct.common.rdtype,
156 				      &keystruct, &rrdatabuf);
157 	if (result != ISC_R_SUCCESS) {
158 		fprintf(stderr, "failed to construct key rdata\n");
159 		exit(1);
160 	}
161 	namelen = strlen(keynamestr);
162 	isc_buffer_init(&b, keynamestr, namelen);
163 	isc_buffer_add(&b, namelen);
164 	keyname = dns_fixedname_initname(&fkeyname);
165 	result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
166 	if (result != ISC_R_SUCCESS) {
167 		fprintf(stderr, "failed to construct key name\n");
168 		exit(1);
169 	}
170 	result = dns_client_addtrustedkey(client, dns_rdataclass_in,
171 					  keyname, &rrdatabuf);
172 	if (result != ISC_R_SUCCESS) {
173 		fprintf(stderr, "failed to add key for %s\n",
174 			keynamestr);
175 		exit(1);
176 	}
177 }
178 
179 static void
addserver(dns_client_t * client,const char * addrstr,const char * port,const char * name_space)180 addserver(dns_client_t *client, const char *addrstr, const char *port,
181 	  const char *name_space)
182 {
183 	struct addrinfo hints, *res;
184 	int gaierror;
185 	isc_sockaddr_t sa;
186 	isc_sockaddrlist_t servers;
187 	isc_result_t result;
188 	unsigned int namelen;
189 	isc_buffer_t b;
190 	dns_fixedname_t fname;
191 	dns_name_t *name = NULL;
192 
193 	memset(&hints, 0, sizeof(hints));
194 	hints.ai_family = AF_UNSPEC;
195 	hints.ai_socktype = SOCK_DGRAM;
196 	hints.ai_protocol = IPPROTO_UDP;
197 	hints.ai_flags = AI_NUMERICHOST;
198 	gaierror = getaddrinfo(addrstr, port, &hints, &res);
199 	if (gaierror != 0) {
200 		fprintf(stderr, "getaddrinfo failed: %s\n",
201 			gai_strerror(gaierror));
202 		exit(1);
203 	}
204 	INSIST(res->ai_addrlen <= sizeof(sa.type));
205 	memmove(&sa.type, res->ai_addr, res->ai_addrlen);
206 	sa.length = (unsigned int)res->ai_addrlen;
207 	freeaddrinfo(res);
208 	ISC_LINK_INIT(&sa, link);
209 	ISC_LIST_INIT(servers);
210 	ISC_LIST_APPEND(servers, &sa, link);
211 
212 	if (name_space != NULL) {
213 		namelen = strlen(name_space);
214 		isc_buffer_constinit(&b, name_space, namelen);
215 		isc_buffer_add(&b, namelen);
216 		name = dns_fixedname_initname(&fname);
217 		result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
218 		if (result != ISC_R_SUCCESS) {
219 			fprintf(stderr, "failed to convert qname: %u\n",
220 				result);
221 			exit(1);
222 		}
223 	}
224 
225 	result = dns_client_setservers(client, dns_rdataclass_in, name,
226 				       &servers);
227 	if (result != ISC_R_SUCCESS) {
228 		fprintf(stderr, "set server failed: %u\n", result);
229 		exit(1);
230 	}
231 }
232 
233 int
main(int argc,char * argv[])234 main(int argc, char *argv[]) {
235 	int ch;
236 	isc_textregion_t tr;
237 	char *server = NULL;
238 	char *altserver = NULL;
239 	char *altserveraddr = NULL;
240 	char *altservername = NULL;
241 	dns_client_t *client = NULL;
242 	char *keynamestr = NULL;
243 	char *keystr = NULL;
244 	isc_result_t result;
245 	isc_buffer_t b;
246 	dns_fixedname_t qname0;
247 	unsigned int namelen;
248 	dns_name_t *qname, *name;
249 	dns_rdatatype_t type = dns_rdatatype_a;
250 	dns_rdataset_t *rdataset;
251 	dns_namelist_t namelist;
252 	isc_mem_t *keymctx = NULL;
253 	unsigned int clientopt, resopt;
254 	bool is_sep = false;
255 	const char *port = "53";
256 	isc_mem_t *mctx = NULL;
257 	isc_appctx_t *actx = NULL;
258 	isc_taskmgr_t *taskmgr = NULL;
259 	isc_socketmgr_t *socketmgr = NULL;
260 	isc_timermgr_t *timermgr = NULL;
261 	struct in_addr in4;
262 	struct in6_addr in6;
263 	isc_sockaddr_t a4, a6;
264 	isc_sockaddr_t *addr4 = NULL, *addr6 = NULL;
265 
266 	while ((ch = isc_commandline_parse(argc, argv,
267 					   "a:b:es:t:k:K:p:S:")) != -1) {
268 		switch (ch) {
269 		case 't':
270 			tr.base = isc_commandline_argument;
271 			tr.length = strlen(isc_commandline_argument);
272 			result = dns_rdatatype_fromtext(&type, &tr);
273 			if (result != ISC_R_SUCCESS) {
274 				fprintf(stderr,
275 					"invalid RRtype: %s\n",
276 					isc_commandline_argument);
277 				exit(1);
278 			}
279 			break;
280 		case 'a':
281 			algname = isc_commandline_argument;
282 			break;
283 		case 'b':
284 			if (inet_pton(AF_INET,
285 				      isc_commandline_argument, &in4) == 1) {
286 				if (addr4 != NULL) {
287 					fprintf(stderr, "only one local "
288 							"address per family "
289 							"can be specified\n");
290 					exit(1);
291 				}
292 				isc_sockaddr_fromin(&a4, &in4, 0);
293 				addr4 = &a4;
294 			} else if (inet_pton(AF_INET6,
295 					     isc_commandline_argument,
296 					     &in6) == 1) {
297 				if (addr6 != NULL) {
298 					fprintf(stderr, "only one local "
299 							"address per family "
300 							"can be specified\n");
301 					exit(1);
302 				}
303 				isc_sockaddr_fromin6(&a6, &in6, 0);
304 				addr6 = &a6;
305 			} else {
306 				fprintf(stderr, "invalid address %s\n",
307 					isc_commandline_argument);
308 				exit(1);
309 			}
310 			break;
311 		case 'e':
312 			is_sep = true;
313 			break;
314 		case 'S':
315 			if (altserver != NULL) {
316 				fprintf(stderr, "alternate server "
317 					"already defined: %s\n",
318 					altserver);
319 				exit(1);
320 			}
321 			altserver = isc_commandline_argument;
322 			break;
323 		case 's':
324 			if (server != NULL) {
325 				fprintf(stderr, "server "
326 					"already defined: %s\n",
327 					server);
328 				exit(1);
329 			}
330 			server = isc_commandline_argument;
331 			break;
332 		case 'k':
333 			keynamestr = isc_commandline_argument;
334 			break;
335 		case 'K':
336 			keystr = isc_commandline_argument;
337 			break;
338 		case 'p':
339 			port = isc_commandline_argument;
340 			break;
341 		default:
342 			usage();
343 		}
344 	}
345 
346 	argc -= isc_commandline_index;
347 	argv += isc_commandline_index;
348 	if (argc < 1)
349 		usage();
350 
351 	if (altserver != NULL) {
352 		char *cp;
353 
354 		cp = strchr(altserver, ':');
355 		if (cp == NULL) {
356 			fprintf(stderr, "invalid alternate server: %s\n",
357 				altserver);
358 			exit(1);
359 		}
360 		*cp = '\0';
361 		altservername = altserver;
362 		altserveraddr = cp + 1;
363 	}
364 
365 	isc_lib_register();
366 	result = dns_lib_init();
367 	if (result != ISC_R_SUCCESS) {
368 		fprintf(stderr, "dns_lib_init failed: %u\n", result);
369 		exit(1);
370 	}
371 
372 	result = isc_mem_create(0, 0, &mctx);
373 	if (result != ISC_R_SUCCESS) {
374 		fprintf(stderr, "failed to crate mctx\n");
375 		exit(1);
376 	}
377 
378 	result = isc_appctx_create(mctx, &actx);
379 	if (result != ISC_R_SUCCESS)
380 		goto cleanup;
381 	result = isc_app_ctxstart(actx);
382 	if (result != ISC_R_SUCCESS)
383 		goto cleanup;
384 	result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr);
385 	if (result != ISC_R_SUCCESS)
386 		goto cleanup;
387 	result = isc_socketmgr_createinctx(mctx, actx, &socketmgr);
388 	if (result != ISC_R_SUCCESS)
389 		goto cleanup;
390 	result = isc_timermgr_createinctx(mctx, actx, &timermgr);
391 	if (result != ISC_R_SUCCESS)
392 		goto cleanup;
393 
394 	clientopt = 0;
395 	result = dns_client_createx2(mctx, actx, taskmgr, socketmgr, timermgr,
396 				    clientopt, &client, addr4, addr6);
397 	if (result != ISC_R_SUCCESS) {
398 		fprintf(stderr, "dns_client_create failed: %u, %s\n", result,
399 			isc_result_totext(result));
400 		exit(1);
401 	}
402 
403 	/* Set the nameserver */
404 	if (server == NULL) {
405 		irs_resconf_t *resconf = NULL;
406 		isc_sockaddrlist_t *nameservers;
407 
408 		result = irs_resconf_load(mctx, "/etc/resolv.conf", &resconf);
409 		if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
410 			fprintf(stderr, "irs_resconf_load failed: %u\n",
411 				result);
412 			exit(1);
413 		}
414 		nameservers = irs_resconf_getnameservers(resconf);
415 		result = dns_client_setservers(client, dns_rdataclass_in,
416 					       NULL, nameservers);
417 		if (result != ISC_R_SUCCESS) {
418 			irs_resconf_destroy(&resconf);
419 			fprintf(stderr, "dns_client_setservers failed: %u\n",
420 				result);
421 			exit(1);
422 		}
423 		irs_resconf_destroy(&resconf);
424 	} else {
425 		addserver(client, server, port, NULL);
426 	}
427 
428 	/* Set the alternate nameserver (when specified) */
429 	if (altserver != NULL)
430 		addserver(client, altserveraddr, port, altservername);
431 
432 	/* Install DNSSEC key (if given) */
433 	if (keynamestr != NULL) {
434 		if (keystr == NULL) {
435 			fprintf(stderr,
436 				"key string is missing "
437 				"while key name is provided\n");
438 			exit(1);
439 		}
440 		set_key(client, keynamestr, keystr, is_sep, &keymctx);
441 	}
442 
443 	/* Construct qname */
444 	namelen = strlen(argv[0]);
445 	isc_buffer_init(&b, argv[0], namelen);
446 	isc_buffer_add(&b, namelen);
447 	qname = dns_fixedname_initname(&qname0);
448 	result = dns_name_fromtext(qname, &b, dns_rootname, 0, NULL);
449 	if (result != ISC_R_SUCCESS)
450 		fprintf(stderr, "failed to convert qname: %u\n", result);
451 
452 	/* Perform resolution */
453 	resopt = DNS_CLIENTRESOPT_ALLOWRUN;
454 	if (keynamestr == NULL)
455 		resopt |= DNS_CLIENTRESOPT_NODNSSEC;
456 	ISC_LIST_INIT(namelist);
457 	result = dns_client_resolve(client, qname, dns_rdataclass_in, type,
458 				    resopt, &namelist);
459 	if (result != ISC_R_SUCCESS) {
460 		fprintf(stderr,
461 			"resolution failed: %s\n", dns_result_totext(result));
462 	}
463 	for (name = ISC_LIST_HEAD(namelist); name != NULL;
464 	     name = ISC_LIST_NEXT(name, link)) {
465 		for (rdataset = ISC_LIST_HEAD(name->list);
466 		     rdataset != NULL;
467 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
468 			if (printdata(rdataset, name) != ISC_R_SUCCESS)
469 				fprintf(stderr, "print data failed\n");
470 		}
471 	}
472 
473 	dns_client_freeresanswer(client, &namelist);
474 
475 	/* Cleanup */
476 cleanup:
477 	dns_client_destroy(&client);
478 
479 	if (taskmgr != NULL)
480 		isc_taskmgr_destroy(&taskmgr);
481 	if (timermgr != NULL)
482 		isc_timermgr_destroy(&timermgr);
483 	if (socketmgr != NULL)
484 		isc_socketmgr_destroy(&socketmgr);
485 	if (actx != NULL)
486 		isc_appctx_destroy(&actx);
487 	isc_mem_detach(&mctx);
488 
489 	if (keynamestr != NULL)
490 		isc_mem_destroy(&keymctx);
491 	dns_lib_shutdown();
492 
493 	return (0);
494 }
495