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