1 /* 2 * nslookup_lede - musl compatible replacement for busybox nslookup 3 * 4 * Copyright (C) 2017 Jo-Philipp Wich <jo@mein.io> 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 THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <stdio.h> 20 #include <resolv.h> 21 #include <string.h> 22 #include <errno.h> 23 #include <time.h> 24 #include <poll.h> 25 #include <unistd.h> 26 #include <stdlib.h> 27 #include <sys/socket.h> 28 #include <arpa/inet.h> 29 #include <net/if.h> 30 #include <netdb.h> 31 #include <fcntl.h> 32 33 #include "ucode/module.h" 34 35 #define for_each_item(arr, item) \ 36 for (uc_value_t *_idx = NULL, *item = (ucv_type(arr) == UC_ARRAY) ? ucv_array_get(arr, 0) : arr; \ 37 (uintptr_t)_idx < (ucv_type(arr) == UC_ARRAY ? ucv_array_length(arr) : (arr != NULL)); \ 38 _idx = (void *)((uintptr_t)_idx + 1), item = ucv_array_get(arr, (uintptr_t)_idx)) 39 40 #define err_return(code, ...) do { set_error(code, __VA_ARGS__); return NULL; } while(0) 41 42 static struct { 43 int code; 44 char *msg; 45 } last_error; 46 47 __attribute__((format(printf, 2, 3))) static void 48 set_error(int errcode, const char *fmt, ...) { 49 va_list ap; 50 51 free(last_error.msg); 52 53 last_error.code = errcode; 54 last_error.msg = NULL; 55 56 if (fmt) { 57 va_start(ap, fmt); 58 xvasprintf(&last_error.msg, fmt, ap); 59 va_end(ap); 60 } 61 } 62 63 typedef struct { 64 socklen_t len; 65 union { 66 struct sockaddr sa; 67 struct sockaddr_in sin; 68 struct sockaddr_in6 sin6; 69 } u; 70 } addr_t; 71 72 typedef struct { 73 const char *name; 74 addr_t addr; 75 } ns_t; 76 77 typedef struct { 78 char *name; 79 size_t qlen, rlen; 80 unsigned char query[512]; 81 int rcode; 82 } query_t; 83 84 typedef struct __attribute__((packed)) { 85 uint8_t root_domain; 86 uint16_t type; 87 uint16_t edns_maxsize; 88 uint8_t extended_rcode; 89 uint8_t edns_version; 90 uint16_t z; 91 uint16_t data_length; 92 } opt_rr_t; 93 94 typedef struct { 95 uint32_t qtypes; 96 size_t n_ns; 97 ns_t *ns; 98 size_t n_queries; 99 query_t *queries; 100 uint32_t retries; 101 uint32_t timeout; 102 uint16_t edns_maxsize; 103 } resolve_ctx_t; 104 105 106 static struct { 107 int type; 108 const char *name; 109 } qtypes[] = { 110 { ns_t_soa, "SOA" }, 111 { ns_t_ns, "NS" }, 112 { ns_t_a, "A" }, 113 { ns_t_aaaa, "AAAA" }, 114 { ns_t_cname, "CNAME" }, 115 { ns_t_mx, "MX" }, 116 { ns_t_txt, "TXT" }, 117 { ns_t_srv, "SRV" }, 118 { ns_t_ptr, "PTR" }, 119 { ns_t_any, "ANY" }, 120 { } 121 }; 122 123 static const char *rcodes[] = { 124 "NOERROR", 125 "FORMERR", 126 "SERVFAIL", 127 "NXDOMAIN", 128 "NOTIMP", 129 "REFUSED", 130 "YXDOMAIN", 131 "YXRRSET", 132 "NXRRSET", 133 "NOTAUTH", 134 "NOTZONE", 135 "RESERVED11", 136 "RESERVED12", 137 "RESERVED13", 138 "RESERVED14", 139 "RESERVED15", 140 "BADVERS" 141 }; 142 143 static unsigned int default_port = 53; 144 145 146 static uc_value_t * 147 init_obj(uc_vm_t *vm, uc_value_t *obj, const char *key, uc_type_t type) 148 { 149 uc_value_t *existing; 150 151 existing = ucv_object_get(obj, key, NULL); 152 153 if (existing == NULL) { 154 switch (type) { 155 case UC_ARRAY: 156 existing = ucv_array_new(vm); 157 break; 158 159 case UC_OBJECT: 160 existing = ucv_object_new(vm); 161 break; 162 163 default: 164 return NULL; 165 } 166 167 ucv_object_add(obj, key, existing); 168 } 169 170 return existing; 171 } 172 173 static int 174 parse_reply(uc_vm_t *vm, uc_value_t *res_obj, const unsigned char *msg, size_t len) 175 { 176 ns_msg handle; 177 ns_rr rr; 178 int i, n, rdlen; 179 const char *key = NULL; 180 char astr[INET6_ADDRSTRLEN], dname[MAXDNAME]; 181 const unsigned char *cp; 182 uc_value_t *name_obj, *type_arr, *item; 183 184 if (ns_initparse(msg, len, &handle) != 0) { 185 set_error(errno, "Unable to parse reply packet"); 186 187 return -1; 188 } 189 190 for (i = 0; i < ns_msg_count(handle, ns_s_an); i++) { 191 if (ns_parserr(&handle, ns_s_an, i, &rr) != 0) { 192 set_error(errno, "Unable to parse resource record"); 193 194 return -1; 195 } 196 197 name_obj = init_obj(vm, res_obj, ns_rr_name(rr), UC_OBJECT); 198 199 rdlen = ns_rr_rdlen(rr); 200 201 switch (ns_rr_type(rr)) 202 { 203 case ns_t_a: 204 if (rdlen != 4) { 205 set_error(EBADMSG, "Invalid A record length"); 206 207 return -1; 208 } 209 210 type_arr = init_obj(vm, name_obj, "A", UC_ARRAY); 211 212 inet_ntop(AF_INET, ns_rr_rdata(rr), astr, sizeof(astr)); 213 ucv_array_push(type_arr, ucv_string_new(astr)); 214 break; 215 216 case ns_t_aaaa: 217 if (rdlen != 16) { 218 set_error(EBADMSG, "Invalid AAAA record length"); 219 220 return -1; 221 } 222 223 type_arr = init_obj(vm, name_obj, "AAAA", UC_ARRAY); 224 225 inet_ntop(AF_INET6, ns_rr_rdata(rr), astr, sizeof(astr)); 226 ucv_array_push(type_arr, ucv_string_new(astr)); 227 break; 228 229 case ns_t_ns: 230 if (!key) 231 key = "NS"; 232 /* fall through */ 233 234 case ns_t_cname: 235 if (!key) 236 key = "CNAME"; 237 /* fall through */ 238 239 case ns_t_ptr: 240 if (!key) 241 key = "PTR"; 242 243 if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), 244 ns_rr_rdata(rr), dname, sizeof(dname)) < 0) { 245 set_error(errno, "Unable to uncompress domain name"); 246 247 return -1; 248 } 249 250 type_arr = init_obj(vm, name_obj, key, UC_ARRAY); 251 n = ucv_array_length(type_arr); 252 item = n ? ucv_array_get(type_arr, n - 1) : NULL; 253 254 if (!n || strcmp(ucv_string_get(item), dname)) 255 ucv_array_push(type_arr, ucv_string_new(dname)); 256 257 break; 258 259 case ns_t_mx: 260 if (rdlen < 2) { 261 set_error(EBADMSG, "MX record too short"); 262 263 return -1; 264 } 265 266 n = ns_get16(ns_rr_rdata(rr)); 267 268 if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), 269 ns_rr_rdata(rr) + 2, dname, sizeof(dname)) < 0) { 270 set_error(errno, "Unable to uncompress MX domain"); 271 272 return -1; 273 } 274 275 type_arr = init_obj(vm, name_obj, "MX", UC_ARRAY); 276 item = ucv_array_new_length(vm, 2); 277 ucv_array_push(item, ucv_int64_new(n)); 278 ucv_array_push(item, ucv_string_new(dname)); 279 ucv_array_push(type_arr, item); 280 break; 281 282 case ns_t_txt: 283 if (rdlen < 1) { 284 set_error(EBADMSG, "TXT record too short"); 285 286 return -1; 287 } 288 289 n = *(unsigned char *)ns_rr_rdata(rr); 290 291 if (n > 0) { 292 memset(dname, 0, sizeof(dname)); 293 memcpy(dname, ns_rr_rdata(rr) + 1, n); 294 295 type_arr = init_obj(vm, name_obj, "TXT", UC_ARRAY); 296 ucv_array_push(type_arr, ucv_string_new(dname)); 297 } 298 break; 299 300 case ns_t_srv: 301 if (rdlen < 6) { 302 set_error(EBADMSG, "SRV record too short"); 303 304 return -1; 305 } 306 307 cp = ns_rr_rdata(rr); 308 n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), 309 cp + 6, dname, sizeof(dname)); 310 311 if (n < 0) { 312 set_error(errno, "Unable to uncompress domain name"); 313 314 return -1; 315 } 316 317 type_arr = init_obj(vm, name_obj, "SRV", UC_ARRAY); 318 item = ucv_array_new_length(vm, 4); 319 ucv_array_push(item, ucv_int64_new(ns_get16(cp))); 320 ucv_array_push(item, ucv_int64_new(ns_get16(cp + 2))); 321 ucv_array_push(item, ucv_int64_new(ns_get16(cp + 4))); 322 ucv_array_push(item, ucv_string_new(dname)); 323 ucv_array_push(type_arr, item); 324 break; 325 326 case ns_t_soa: 327 if (rdlen < 20) { 328 set_error(EBADMSG, "SOA record too short"); 329 330 return -1; 331 } 332 333 type_arr = init_obj(vm, name_obj, "SOA", UC_ARRAY); 334 item = ucv_array_new_length(vm, 7); 335 336 cp = ns_rr_rdata(rr); 337 n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), 338 cp, dname, sizeof(dname)); 339 340 if (n < 0) { 341 set_error(errno, "Unable to uncompress domain name"); 342 ucv_put(item); 343 344 return -1; 345 } 346 347 ucv_array_push(item, ucv_string_new(dname)); /* origin */ 348 cp += n; 349 350 n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), 351 cp, dname, sizeof(dname)); 352 353 if (n < 0) { 354 set_error(errno, "Unable to uncompress domain name"); 355 ucv_put(item); 356 357 return -1; 358 } 359 360 ucv_array_push(item, ucv_string_new(dname)); /* mail addr */ 361 cp += n; 362 363 ucv_array_push(item, ucv_int64_new(ns_get32(cp))); /* serial */ 364 cp += 4; 365 366 ucv_array_push(item, ucv_int64_new(ns_get32(cp))); /* refresh */ 367 cp += 4; 368 369 ucv_array_push(item, ucv_int64_new(ns_get32(cp))); /* retry */ 370 cp += 4; 371 372 ucv_array_push(item, ucv_int64_new(ns_get32(cp))); /* expire */ 373 cp += 4; 374 375 ucv_array_push(item, ucv_int64_new(ns_get32(cp))); /* minimum */ 376 377 ucv_array_push(type_arr, item); 378 break; 379 380 default: 381 break; 382 } 383 } 384 385 return i; 386 } 387 388 static int 389 parse_nsaddr(const char *addrstr, addr_t *lsa) 390 { 391 char *eptr, *hash, ifname[IFNAMSIZ]; 392 unsigned int port = default_port; 393 unsigned int scope = 0; 394 395 hash = strchr(addrstr, '#'); 396 397 if (hash) { 398 *hash++ = '\0'; 399 port = strtoul(hash, &eptr, 10); 400 401 if (eptr == hash || *eptr != '\0' || port > 65535) { 402 errno = EINVAL; 403 return -1; 404 } 405 } 406 407 hash = strchr(addrstr, '%'); 408 409 if (hash) { 410 for (eptr = ++hash; *eptr != '\0' && *eptr != '#'; eptr++) { 411 if ((eptr - hash) >= IFNAMSIZ) { 412 errno = ENODEV; 413 return -1; 414 } 415 416 ifname[eptr - hash] = *eptr; 417 } 418 419 ifname[eptr - hash] = '\0'; 420 scope = if_nametoindex(ifname); 421 422 if (scope == 0) { 423 errno = ENODEV; 424 return -1; 425 } 426 } 427 428 if (inet_pton(AF_INET6, addrstr, &lsa->u.sin6.sin6_addr)) { 429 lsa->u.sin6.sin6_family = AF_INET6; 430 lsa->u.sin6.sin6_port = htons(port); 431 lsa->u.sin6.sin6_scope_id = scope; 432 lsa->len = sizeof(lsa->u.sin6); 433 return 0; 434 } 435 436 if (!scope && inet_pton(AF_INET, addrstr, &lsa->u.sin.sin_addr)) { 437 lsa->u.sin.sin_family = AF_INET; 438 lsa->u.sin.sin_port = htons(port); 439 lsa->len = sizeof(lsa->u.sin); 440 return 0; 441 } 442 443 errno = EINVAL; 444 return -1; 445 } 446 447 static char * 448 make_ptr(const char *addrstr) 449 { 450 const char *hexdigit = "0123456789abcdef"; 451 static char ptrstr[73]; 452 unsigned char addr[16]; 453 char *ptr = ptrstr; 454 int i; 455 456 if (inet_pton(AF_INET6, addrstr, addr)) { 457 if (memcmp(addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12) != 0) { 458 for (i = 0; i < 16; i++) { 459 *ptr++ = hexdigit[(unsigned char)addr[15 - i] & 0xf]; 460 *ptr++ = '.'; 461 *ptr++ = hexdigit[(unsigned char)addr[15 - i] >> 4]; 462 *ptr++ = '.'; 463 } 464 strcpy(ptr, "ip6.arpa"); 465 } 466 else { 467 sprintf(ptr, "%u.%u.%u.%u.in-addr.arpa", 468 addr[15], addr[14], addr[13], addr[12]); 469 } 470 471 return ptrstr; 472 } 473 474 if (inet_pton(AF_INET, addrstr, addr)) { 475 sprintf(ptr, "%u.%u.%u.%u.in-addr.arpa", 476 addr[3], addr[2], addr[1], addr[0]); 477 return ptrstr; 478 } 479 480 return NULL; 481 } 482 483 static unsigned long 484 mtime(void) 485 { 486 struct timespec ts; 487 clock_gettime(CLOCK_REALTIME, &ts); 488 489 return (unsigned long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; 490 } 491 492 static void 493 to_v4_mapped(addr_t *a) 494 { 495 if (a->u.sa.sa_family != AF_INET) 496 return; 497 498 memcpy(a->u.sin6.sin6_addr.s6_addr + 12, 499 &a->u.sin.sin_addr, 4); 500 501 memcpy(a->u.sin6.sin6_addr.s6_addr, 502 "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); 503 504 a->u.sin6.sin6_family = AF_INET6; 505 a->u.sin6.sin6_flowinfo = 0; 506 a->u.sin6.sin6_scope_id = 0; 507 a->len = sizeof(a->u.sin6); 508 } 509 510 static void 511 add_status(uc_vm_t *vm, uc_value_t *res_obj, const char *name, const char *rcode) 512 { 513 uc_value_t *name_obj = init_obj(vm, res_obj, name, UC_OBJECT); 514 515 ucv_object_add(name_obj, "rcode", ucv_string_new(rcode)); 516 } 517 518 /* 519 * Function logic borrowed & modified from musl libc, res_msend.c 520 */ 521 522 static int 523 send_queries(resolve_ctx_t *ctx, uc_vm_t *vm, uc_value_t *res_obj) 524 { 525 int fd, flags; 526 int servfail_retry = 0; 527 addr_t from = { }; 528 int one = 1; 529 int recvlen = 0; 530 int n_replies = 0; 531 struct pollfd pfd; 532 unsigned long t0, t1, t2, timeout = ctx->timeout, retry_interval; 533 unsigned int nn, qn, next_query = 0; 534 struct { unsigned char *buf; size_t len; } reply_buf = { 0 }; 535 536 from.u.sa.sa_family = AF_INET; 537 from.len = sizeof(from.u.sin); 538 539 for (nn = 0; nn < ctx->n_ns; nn++) { 540 if (ctx->ns[nn].addr.u.sa.sa_family == AF_INET6) { 541 from.u.sa.sa_family = AF_INET6; 542 from.len = sizeof(from.u.sin6); 543 break; 544 } 545 } 546 547 #ifdef __APPLE__ 548 flags = SOCK_DGRAM; 549 #else 550 flags = SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK; 551 #endif 552 553 /* Get local address and open/bind a socket */ 554 fd = socket(from.u.sa.sa_family, flags, 0); 555 556 /* Handle case where system lacks IPv6 support */ 557 if (fd < 0 && from.u.sa.sa_family == AF_INET6 && errno == EAFNOSUPPORT) { 558 fd = socket(AF_INET, flags, 0); 559 from.u.sa.sa_family = AF_INET; 560 } 561 562 if (fd < 0) { 563 set_error(errno, "Unable to open UDP socket"); 564 565 return -1; 566 } 567 568 #ifdef __APPLE__ 569 flags = fcntl(fd, F_GETFD); 570 571 if (flags < 0) { 572 set_error(errno, "Unable to acquire socket descriptor flags"); 573 close(fd); 574 575 return -1; 576 } 577 578 if (fcntl(fd, F_SETFD, flags|O_CLOEXEC|O_NONBLOCK) < 0) { 579 set_error(errno, "Unable to set socket descriptor flags"); 580 close(fd); 581 582 return -1; 583 } 584 #endif 585 586 if (bind(fd, &from.u.sa, from.len) < 0) { 587 set_error(errno, "Unable to bind UDP socket"); 588 close(fd); 589 590 return -1; 591 } 592 593 /* Convert any IPv4 addresses in a mixed environment to v4-mapped */ 594 if (from.u.sa.sa_family == AF_INET6) { 595 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); 596 597 for (nn = 0; nn < ctx->n_ns; nn++) 598 to_v4_mapped(&ctx->ns[nn].addr); 599 } 600 601 pfd.fd = fd; 602 pfd.events = POLLIN; 603 retry_interval = timeout / ctx->retries; 604 t0 = t2 = mtime(); 605 t1 = t2 - retry_interval; 606 607 for (; t2 - t0 < timeout; t2 = mtime()) { 608 if (t2 - t1 >= retry_interval) { 609 for (qn = 0; qn < ctx->n_queries; qn++) { 610 if (ctx->queries[qn].rcode == 0 || ctx->queries[qn].rcode == 3) 611 continue; 612 613 for (nn = 0; nn < ctx->n_ns; nn++) { 614 sendto(fd, ctx->queries[qn].query, ctx->queries[qn].qlen, 615 MSG_NOSIGNAL, &ctx->ns[nn].addr.u.sa, ctx->ns[nn].addr.len); 616 } 617 } 618 619 t1 = t2; 620 servfail_retry = 2 * ctx->n_queries; 621 } 622 623 /* Wait for a response, or until time to retry */ 624 switch (poll(&pfd, 1, t1+retry_interval-t2)) { 625 case 0: 626 /* timeout */ 627 for (qn = 0; qn < ctx->n_queries; qn++) { 628 if (ctx->queries[qn].rcode != -1) 629 continue; 630 631 for (nn = 0; nn < ctx->n_ns; nn++) 632 add_status(vm, res_obj, ctx->queries[qn].name, "TIMEOUT"); 633 } 634 635 continue; 636 637 case -1: 638 /* error */ 639 continue; 640 } 641 642 while (1) { 643 recvlen = recvfrom(fd, NULL, 0, MSG_PEEK|MSG_TRUNC, &from.u.sa, &from.len); 644 645 /* read error */ 646 if (recvlen < 0) 647 break; 648 649 if ((size_t)recvlen > reply_buf.len) { 650 reply_buf.buf = xrealloc(reply_buf.buf, recvlen); 651 reply_buf.len = recvlen; 652 } 653 654 recvlen = recvfrom(fd, reply_buf.buf, recvlen, 0, &from.u.sa, &from.len); 655 656 /* Ignore non-identifiable packets */ 657 if (recvlen < 4) 658 continue; 659 660 /* Ignore replies from addresses we didn't send to */ 661 for (nn = 0; nn < ctx->n_ns; nn++) 662 if (memcmp(&from.u.sa, &ctx->ns[nn].addr.u.sa, from.len) == 0) 663 break; 664 665 if (nn >= ctx->n_ns) 666 continue; 667 668 /* Find which query this answer goes with, if any */ 669 for (qn = next_query; qn < ctx->n_queries; qn++) 670 if (!memcmp(reply_buf.buf, ctx->queries[qn].query, 2)) 671 break; 672 673 /* Do not overwrite previous replies from other servers 674 * but allow overwriting preexisting NXDOMAIN reply */ 675 if (qn >= ctx->n_queries || 676 ctx->queries[qn].rcode == 0 || 677 (ctx->queries[qn].rcode == 3 && (reply_buf.buf[3] & 15) != 0)) 678 continue; 679 680 ctx->queries[qn].rcode = reply_buf.buf[3] & 15; 681 682 switch (ctx->queries[qn].rcode) { 683 case 0: 684 ucv_object_delete( 685 ucv_object_get(res_obj, ctx->queries[qn].name, NULL), 686 "rcodes"); 687 688 break; 689 690 case 2: 691 /* Retry immediately on server failure. */ 692 if (servfail_retry && servfail_retry--) 693 sendto(fd, ctx->queries[qn].query, ctx->queries[qn].qlen, 694 MSG_NOSIGNAL, &ctx->ns[nn].addr.u.sa, ctx->ns[nn].addr.len); 695 696 /* fall through */ 697 698 default: 699 add_status(vm, res_obj, ctx->queries[qn].name, 700 rcodes[ctx->queries[qn].rcode]); 701 } 702 703 /* Store answer */ 704 n_replies++; 705 706 ctx->queries[qn].rlen = recvlen; 707 708 parse_reply(vm, res_obj, reply_buf.buf, recvlen); 709 710 if (qn == next_query) { 711 while (next_query < ctx->n_queries) { 712 if (ctx->queries[next_query].rcode == -1) 713 break; 714 715 next_query++; 716 } 717 } 718 719 if (next_query >= ctx->n_queries) 720 goto out; 721 } 722 } 723 724 out: 725 free(reply_buf.buf); 726 727 return n_replies; 728 } 729 730 static ns_t * 731 add_ns(resolve_ctx_t *ctx, const char *addr) 732 { 733 char portstr[sizeof("65535")], *p; 734 addr_t a = { }; 735 struct addrinfo *ai, *aip, hints = { 736 .ai_flags = AI_NUMERICSERV, 737 .ai_socktype = SOCK_DGRAM 738 }; 739 740 if (parse_nsaddr(addr, &a)) { 741 /* Maybe we got a domain name, attempt to resolve it using the standard 742 * resolver routines */ 743 744 p = strchr(addr, '#'); 745 snprintf(portstr, sizeof(portstr), "%hu", 746 (unsigned short)(p ? strtoul(p, NULL, 10) : default_port)); 747 748 if (!getaddrinfo(addr, portstr, &hints, &ai)) { 749 for (aip = ai; aip; aip = aip->ai_next) { 750 if (aip->ai_addr->sa_family != AF_INET && 751 aip->ai_addr->sa_family != AF_INET6) 752 continue; 753 754 ctx->ns = xrealloc(ctx->ns, sizeof(*ctx->ns) * (ctx->n_ns + 1)); 755 ctx->ns[ctx->n_ns].name = addr; 756 ctx->ns[ctx->n_ns].addr.len = aip->ai_addrlen; 757 758 memcpy(&ctx->ns[ctx->n_ns].addr.u.sa, aip->ai_addr, aip->ai_addrlen); 759 760 ctx->n_ns++; 761 } 762 763 freeaddrinfo(ai); 764 765 return &ctx->ns[ctx->n_ns]; 766 } 767 768 return NULL; 769 } 770 771 ctx->ns = xrealloc(ctx->ns, sizeof(*ctx->ns) * (ctx->n_ns + 1)); 772 ctx->ns[ctx->n_ns].addr = a; 773 ctx->ns[ctx->n_ns].name = addr; 774 775 return &ctx->ns[ctx->n_ns++]; 776 } 777 778 static int 779 parse_resolvconf(resolve_ctx_t *ctx) 780 { 781 int prev_n_ns = ctx->n_ns; 782 char line[128], *p; 783 FILE *resolv; 784 bool ok; 785 786 if ((resolv = fopen("/etc/resolv.conf", "r")) != NULL) { 787 while (fgets(line, sizeof(line), resolv)) { 788 p = strtok(line, " \t\n"); 789 790 if (!p || strcmp(p, "nameserver")) 791 continue; 792 793 p = strtok(NULL, " \t\n"); 794 795 if (!p) 796 continue; 797 798 p = xstrdup(p); 799 ok = add_ns(ctx, p); 800 801 free(p); 802 803 if (!ok) 804 break; 805 } 806 807 fclose(resolv); 808 } 809 810 return ctx->n_ns - prev_n_ns; 811 } 812 813 static query_t * 814 add_query(resolve_ctx_t *ctx, int type, const char *dname) 815 { 816 opt_rr_t *opt; 817 ssize_t qlen; 818 819 ctx->queries = xrealloc(ctx->queries, sizeof(*ctx->queries) * (ctx->n_queries + 1)); 820 821 memset(&ctx->queries[ctx->n_queries], 0, sizeof(*ctx->queries)); 822 823 qlen = res_mkquery(QUERY, dname, C_IN, type, NULL, 0, NULL, 824 ctx->queries[ctx->n_queries].query, 825 sizeof(ctx->queries[ctx->n_queries].query)); 826 827 /* add OPT record */ 828 if (ctx->edns_maxsize != 0 && qlen + sizeof(opt_rr_t) <= sizeof(ctx->queries[ctx->n_queries].query)) { 829 ctx->queries[ctx->n_queries].query[11] = 1; 830 831 opt = (opt_rr_t *)&ctx->queries[ctx->n_queries].query[qlen]; 832 opt->root_domain = 0; 833 opt->type = htons(41); 834 opt->edns_maxsize = htons(ctx->edns_maxsize); 835 opt->extended_rcode = 0; 836 opt->edns_version = 0; 837 opt->z = htons(0); 838 opt->data_length = htons(0); 839 840 qlen += sizeof(opt_rr_t); 841 } 842 843 ctx->queries[ctx->n_queries].qlen = qlen; 844 ctx->queries[ctx->n_queries].name = xstrdup(dname); 845 ctx->queries[ctx->n_queries].rcode = -1; 846 847 return &ctx->queries[ctx->n_queries++]; 848 } 849 850 static bool 851 check_types(uc_value_t *typenames, uint32_t *types) 852 { 853 size_t i; 854 855 *types = 0; 856 857 for_each_item(typenames, typename) { 858 if (ucv_type(typename) != UC_STRING) 859 err_return(EINVAL, "Query type value not a string"); 860 861 for (i = 0; qtypes[i].name; i++) { 862 if (!strcasecmp(ucv_string_get(typename), qtypes[i].name)) { 863 *types |= (1 << i); 864 break; 865 } 866 } 867 868 if (!qtypes[i].name) 869 err_return(EINVAL, "Unrecognized query type '%s'", 870 ucv_string_get(typename)); 871 } 872 873 return true; 874 } 875 876 static void 877 add_queries(resolve_ctx_t *ctx, uc_value_t *name) 878 { 879 char *s = ucv_string_get(name); 880 char *ptr; 881 size_t i; 882 883 if (ctx->qtypes == 0) { 884 ptr = make_ptr(s); 885 886 if (ptr) { 887 add_query(ctx, ns_t_ptr, ptr); 888 } 889 else { 890 add_query(ctx, ns_t_a, s); 891 add_query(ctx, ns_t_aaaa, s); 892 } 893 } 894 else { 895 for (i = 0; qtypes[i].name; i++) { 896 if (ctx->qtypes & (1 << i)) { 897 if (qtypes[i].type == ns_t_ptr) { 898 ptr = make_ptr(s); 899 add_query(ctx, ns_t_ptr, ptr ? ptr : s); 900 } 901 else { 902 add_query(ctx, qtypes[i].type, s); 903 } 904 } 905 } 906 } 907 } 908 909 static bool 910 parse_options(resolve_ctx_t *ctx, uc_value_t *opts) 911 { 912 uc_value_t *v; 913 914 if (!check_types(ucv_object_get(opts, "type", NULL), &ctx->qtypes)) 915 return false; 916 917 for_each_item(ucv_object_get(opts, "nameserver", NULL), server) { 918 if (ucv_type(server) != UC_STRING) 919 err_return(EINVAL, "Nameserver value not a string"); 920 921 if (!add_ns(ctx, ucv_string_get(server))) 922 err_return(EINVAL, "Unable to resolve nameserver address '%s'", 923 ucv_string_get(server)); 924 } 925 926 /* Find NS servers in resolv.conf if none provided */ 927 if (ctx->n_ns == 0) 928 parse_resolvconf(ctx); 929 930 /* Fall back to localhost if we could not find NS in resolv.conf */ 931 if (ctx->n_ns == 0) 932 add_ns(ctx, "127.0.0.1"); 933 934 v = ucv_object_get(opts, "retries", NULL); 935 936 if (ucv_type(v) == UC_INTEGER) 937 ctx->retries = ucv_uint64_get(v); 938 else if (v) 939 err_return(EINVAL, "Retries value not an integer"); 940 941 v = ucv_object_get(opts, "timeout", NULL); 942 943 if (ucv_type(v) == UC_INTEGER) 944 ctx->timeout = ucv_uint64_get(v); 945 else if (v) 946 err_return(EINVAL, "Timeout value not an integer"); 947 948 v = ucv_object_get(opts, "edns_maxsize", NULL); 949 950 if (ucv_type(v) == UC_INTEGER) 951 ctx->edns_maxsize = ucv_uint64_get(v); 952 else if (v) 953 err_return(EINVAL, "EDNS max size not an integer"); 954 955 return true; 956 } 957 958 static uc_value_t * 959 uc_resolv_query(uc_vm_t *vm, size_t nargs) 960 { 961 resolve_ctx_t ctx = { .retries = 2, .timeout = 5000, .edns_maxsize = 4096 }; 962 uc_value_t *names = uc_fn_arg(0); 963 uc_value_t *opts = uc_fn_arg(1); 964 uc_value_t *res_obj = NULL; 965 966 if (!parse_options(&ctx, opts)) 967 goto err; 968 969 for_each_item(names, name) { 970 if (ucv_type(name) != UC_STRING) { 971 set_error(EINVAL, "Domain name value not a string"); 972 goto err; 973 } 974 975 add_queries(&ctx, name); 976 } 977 978 res_obj = ucv_object_new(vm); 979 980 if (send_queries(&ctx, vm, res_obj) == 0) 981 set_error(ETIMEDOUT, "Server did not respond"); 982 983 err: 984 while (ctx.n_queries) 985 free(ctx.queries[--ctx.n_queries].name); 986 987 free(ctx.queries); 988 free(ctx.ns); 989 990 return res_obj; 991 } 992 993 static uc_value_t * 994 uc_resolv_error(uc_vm_t *vm, size_t nargs) 995 { 996 uc_stringbuf_t *buf; 997 const char *s; 998 999 if (last_error.code == 0) 1000 return NULL; 1001 1002 buf = ucv_stringbuf_new(); 1003 1004 s = strerror(last_error.code); 1005 1006 ucv_stringbuf_addstr(buf, s, strlen(s)); 1007 1008 if (last_error.msg) 1009 ucv_stringbuf_printf(buf, ": %s", last_error.msg); 1010 1011 set_error(0, NULL); 1012 1013 return ucv_stringbuf_finish(buf); 1014 } 1015 1016 1017 static const uc_function_list_t resolv_fns[] = { 1018 { "query", uc_resolv_query }, 1019 { "error", uc_resolv_error }, 1020 }; 1021 1022 void uc_module_init(uc_vm_t *vm, uc_value_t *scope) 1023 { 1024 uc_function_list_register(scope, resolv_fns); 1025 } 1026
This page was automatically generated by LXR 0.3.1. • OpenWrt