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