aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-04-14 17:54:24 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2018-04-14 17:55:54 +0200
commit55bc8e8826df8cf5c342f57e513d10ee6c632838 (patch)
treedc798c0b7e8ce967d0c713c9b76dc0ca6ef7be0f
parent75568354f6e2ab08302085bbcb32c3368c49b86f (diff)
downloadbusybox-w32-55bc8e8826df8cf5c342f57e513d10ee6c632838.tar.gz
busybox-w32-55bc8e8826df8cf5c342f57e513d10ee6c632838.tar.bz2
busybox-w32-55bc8e8826df8cf5c342f57e513d10ee6c632838.zip
nslookup: usee bbox network functions instead of opne-coded mess
function old new delta nslookup_main 2363 2091 -272 add_ns 663 65 -598 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-870) Total: -870 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--networking/nslookup.c310
1 files changed, 70 insertions, 240 deletions
diff --git a/networking/nslookup.c b/networking/nslookup.c
index 6f8f02fc1..50d91abbc 100644
--- a/networking/nslookup.c
+++ b/networking/nslookup.c
@@ -256,7 +256,7 @@ int nslookup_main(int argc, char **argv)
256 256
257struct ns { 257struct ns {
258 const char *name; 258 const char *name;
259 len_and_sockaddr addr; 259 len_and_sockaddr *lsa;
260 int failures; 260 int failures;
261 int replies; 261 int replies;
262}; 262};
@@ -266,7 +266,7 @@ struct query {
266 size_t qlen, rlen; 266 size_t qlen, rlen;
267 unsigned char query[512], reply[512]; 267 unsigned char query[512], reply[512];
268 unsigned long latency; 268 unsigned long latency;
269 int rcode, n_ns; 269 int rcode;
270}; 270};
271 271
272static const struct { 272static const struct {
@@ -315,6 +315,8 @@ struct globals {
315 unsigned default_port; 315 unsigned default_port;
316 unsigned default_retry; 316 unsigned default_retry;
317 unsigned default_timeout; 317 unsigned default_timeout;
318 unsigned serv_count;
319 struct ns *server;
318} FIX_ALIASING; 320} FIX_ALIASING;
319#define G (*(struct globals*)bb_common_bufsiz1) 321#define G (*(struct globals*)bb_common_bufsiz1)
320#define INIT_G() do { \ 322#define INIT_G() do { \
@@ -480,69 +482,6 @@ parse_reply(const unsigned char *msg, size_t len, int *bb_style_counter)
480 return i; 482 return i;
481} 483}
482 484
483static int parse_nsaddr(const char *addrstr, len_and_sockaddr *lsa)
484{
485 char *hash;
486 unsigned port = G.default_port;
487 IF_FEATURE_IPV6(unsigned scope;)
488
489 dbg("%s: addrstr:'%s'\n", __func__, addrstr);
490
491 hash = strchr(addrstr, '#');
492
493 if (hash) {
494 *hash++ = '\0';
495 port = bb_strtou(hash, NULL, 10);
496 if (errno || port > 65535) {
497 errno = EINVAL;
498 return -1;
499 }
500 }
501
502#if ENABLE_FEATURE_IPV6
503 scope = 0;
504 hash = strchr(addrstr, '%');
505 if (hash) {
506 char ifname[IFNAMSIZ];
507 int i;
508
509 hash++;
510 for (i = 0; hash[i] != '\0' && hash[i] != '#'; i++) {
511 if (i >= IFNAMSIZ) {
512 errno = ENODEV;
513 return -1;
514 }
515 ifname[i] = hash[i];
516 }
517 ifname[i] = '\0';
518
519 scope = if_nametoindex(ifname);
520 if (scope == 0) {
521 errno = ENODEV;
522 return -1;
523 }
524 }
525
526 if (inet_pton(AF_INET6, addrstr, &lsa->u.sin6.sin6_addr)) {
527 lsa->u.sin6.sin6_family = AF_INET6;
528 lsa->u.sin6.sin6_port = htons(port);
529 lsa->u.sin6.sin6_scope_id = scope;
530 lsa->len = sizeof(lsa->u.sin6);
531 return 0;
532 }
533#endif
534
535 if (inet_pton(AF_INET, addrstr, &lsa->u.sin.sin_addr)) {
536 lsa->u.sin.sin_family = AF_INET;
537 lsa->u.sin.sin_port = htons(port);
538 lsa->len = sizeof(lsa->u.sin);
539 return 0;
540 }
541
542 errno = EINVAL;
543 return -1;
544}
545
546static char *make_ptr(char resbuf[80], const char *addrstr) 485static char *make_ptr(char resbuf[80], const char *addrstr)
547{ 486{
548 unsigned char addr[16]; 487 unsigned char addr[16];
@@ -577,104 +516,65 @@ static char *make_ptr(char resbuf[80], const char *addrstr)
577 return NULL; 516 return NULL;
578} 517}
579 518
580#if ENABLE_FEATURE_IPV6
581static void to_v4_mapped(len_and_sockaddr *a)
582{
583 if (a->u.sa.sa_family != AF_INET)
584 return;
585
586 /* Order is important */
587//FIXME: port?
588 memcpy(a->u.sin6.sin6_addr.s6_addr + 12, &a->u.sin.sin_addr, 4);
589 memcpy(a->u.sin6.sin6_addr.s6_addr, v4_mapped, 12);
590
591 a->u.sin6.sin6_family = AF_INET6;
592 a->u.sin6.sin6_flowinfo = 0;
593 a->u.sin6.sin6_scope_id = 0;
594 a->len = sizeof(a->u.sin6);
595}
596#endif
597
598/* 519/*
599 * Function logic borrowed & modified from musl libc, res_msend.c 520 * Function logic borrowed & modified from musl libc, res_msend.c
600 */ 521 */
601static int send_queries(struct ns *ns, int n_ns, struct query *queries, int n_queries) 522static int send_queries(struct ns *ns, struct query *queries, int n_queries)
602{ 523{
603 int fd;
604 int timeout = G.default_timeout * 1000, retry_interval, servfail_retry = 0;
605 len_and_sockaddr from = { };
606 int recvlen = 0;
607 int n_replies = 0;
608 struct pollfd pfd; 524 struct pollfd pfd;
609 unsigned long t0, t1, t2; 525 int servfail_retry = 0;
610 int nn, qn, next_query = 0; 526 int n_replies = 0;
611 527 int next_query = 0;
612 from.u.sa.sa_family = AF_INET; 528 unsigned retry_interval;
613 from.len = sizeof(from.u.sin); 529 unsigned timeout = G.default_timeout * 1000;
614#if ENABLE_FEATURE_IPV6 530 unsigned t0, t1, t2;
615 for (nn = 0; nn < n_ns; nn++) {
616 if (ns[nn].addr.u.sa.sa_family == AF_INET6) {
617 from.u.sa.sa_family = AF_INET6;
618 from.len = sizeof(from.u.sin6);
619 break;
620 }
621 }
622#endif
623
624 /* Get local address and open/bind a socket */
625#if ENABLE_FEATURE_IPV6
626 fd = socket(from.u.sa.sa_family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
627 /* Handle case where system lacks IPv6 support */
628 if (fd < 0) {
629 if (from.u.sa.sa_family != AF_INET6 || errno != EAFNOSUPPORT)
630 bb_perror_msg_and_die("socket");
631 fd = xsocket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
632 from.u.sa.sa_family = AF_INET;
633 }
634#else
635 fd = xsocket(from.u.sa.sa_family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
636#endif
637 xbind(fd, &from.u.sa, from.len);
638
639#if ENABLE_FEATURE_IPV6
640 /* Convert any IPv4 addresses in a mixed environment to v4-mapped */
641 if (from.u.sa.sa_family == AF_INET6) {
642 setsockopt_1(fd, IPPROTO_IPV6, IPV6_V6ONLY);
643 for (nn = 0; nn < n_ns; nn++)
644 to_v4_mapped(&ns[nn].addr);
645 }
646#endif
647 531
648 pfd.fd = fd; 532 pfd.fd = -1;
649 pfd.events = POLLIN; 533 pfd.events = POLLIN;
534
650 retry_interval = timeout / G.default_retry; 535 retry_interval = timeout / G.default_retry;
651 t0 = t2 = monotonic_ms(); 536 t0 = t2 = monotonic_ms();
652 t1 = t2 - retry_interval; 537 t1 = t2 - retry_interval;
653 538
654 for (; t2 - t0 < timeout; t2 = monotonic_ms()) { 539 for (; t2 - t0 < timeout; t2 = monotonic_ms()) {
655 if (t2 - t1 >= retry_interval) { 540 if (t2 - t1 >= retry_interval) {
541 int qn;
656 for (qn = 0; qn < n_queries; qn++) { 542 for (qn = 0; qn < n_queries; qn++) {
657 if (queries[qn].rlen) 543 if (queries[qn].rlen)
658 continue; 544 continue;
659 545 if (pfd.fd < 0) {
660 for (nn = 0; nn < n_ns; nn++) { 546 len_and_sockaddr *local_lsa;
661 sendto(fd, queries[qn].query, queries[qn].qlen, 547 pfd.fd = xsocket_type(&local_lsa, ns->lsa->u.sa.sa_family, SOCK_DGRAM);
662 MSG_NOSIGNAL, &ns[nn].addr.u.sa, ns[nn].addr.len); 548 /*
549 * local_lsa has "null" address and port 0 now.
550 * bind() ensures we have a *particular port* selected by kernel
551 * and remembered in fd, thus later recv(fd)
552 * receives only packets sent to this port.
553 */
554 xbind(pfd.fd, &local_lsa->u.sa, local_lsa->len);
555 free(local_lsa);
556 /* Make read/writes know the destination */
557 xconnect(pfd.fd, &ns->lsa->u.sa, ns->lsa->len);
558 ndelay_on(pfd.fd);
663 } 559 }
560 write(pfd.fd, queries[qn].query, queries[qn].qlen);
664 } 561 }
665 562
666 t1 = t2; 563 t1 = t2;
667 servfail_retry = 2 * n_queries; 564 servfail_retry = 2 * n_queries;
668 } 565 }
669 566 poll_more:
670 /* Wait for a response, or until time to retry */ 567 /* Wait for a response, or until time to retry */
671 if (poll(&pfd, 1, t1 + retry_interval - t2) <= 0) 568 if (poll(&pfd, 1, t1 + retry_interval - t2) <= 0)
672 continue; 569 continue;
673 570
674 while (1) { 571 while (1) {
675 recvlen = recvfrom(fd, queries[next_query].reply, 572 int qn;
676 sizeof(queries[next_query].reply), 0, 573 int recvlen;
677 &from.u.sa, &from.len 574
575 recvlen = read(pfd.fd,
576 queries[next_query].reply,
577 sizeof(queries[next_query].reply)
678 ); 578 );
679 579
680 /* read error */ 580 /* read error */
@@ -683,15 +583,7 @@ static int send_queries(struct ns *ns, int n_ns, struct query *queries, int n_qu
683 583
684 /* Ignore non-identifiable packets */ 584 /* Ignore non-identifiable packets */
685 if (recvlen < 4) 585 if (recvlen < 4)
686 continue; 586 goto poll_more;
687
688 /* Ignore replies from addresses we didn't send to */
689 for (nn = 0; nn < n_ns; nn++)
690 if (memcmp(&from.u.sa, &ns[nn].addr.u.sa, from.len) == 0)
691 break;
692
693 if (nn >= n_ns)
694 continue;
695 587
696 /* Find which query this answer goes with, if any */ 588 /* Find which query this answer goes with, if any */
697 for (qn = next_query; qn < n_queries; qn++) 589 for (qn = next_query; qn < n_queries; qn++)
@@ -699,13 +591,12 @@ static int send_queries(struct ns *ns, int n_ns, struct query *queries, int n_qu
699 break; 591 break;
700 592
701 if (qn >= n_queries || queries[qn].rlen) 593 if (qn >= n_queries || queries[qn].rlen)
702 continue; 594 goto poll_more;
703 595
704 queries[qn].rcode = queries[next_query].reply[3] & 15; 596 queries[qn].rcode = queries[next_query].reply[3] & 15;
705 queries[qn].latency = monotonic_ms() - t0; 597 queries[qn].latency = monotonic_ms() - t0;
706 queries[qn].n_ns = nn;
707 598
708 ns[nn].replies++; 599 ns->replies++;
709 600
710 /* Only accept positive or negative responses; 601 /* Only accept positive or negative responses;
711 * retry immediately on server failure, and ignore 602 * retry immediately on server failure, and ignore
@@ -717,9 +608,8 @@ static int send_queries(struct ns *ns, int n_ns, struct query *queries, int n_qu
717 608
718 case 2: 609 case 2:
719 if (servfail_retry && servfail_retry--) { 610 if (servfail_retry && servfail_retry--) {
720 ns[nn].failures++; 611 ns->failures++;
721 sendto(fd, queries[qn].query, queries[qn].qlen, 612 write(pfd.fd, queries[qn].query, queries[qn].qlen);
722 MSG_NOSIGNAL, &ns[nn].addr.u.sa, ns[nn].addr.len);
723 } 613 }
724 /* fall through */ 614 /* fall through */
725 615
@@ -736,94 +626,42 @@ static int send_queries(struct ns *ns, int n_ns, struct query *queries, int n_qu
736 while (next_query < n_queries) { 626 while (next_query < n_queries) {
737 if (!queries[next_query].rlen) 627 if (!queries[next_query].rlen)
738 break; 628 break;
739
740 next_query++; 629 next_query++;
741 } 630 }
742 } 631 } else {
743 else {
744 memcpy(queries[qn].reply, queries[next_query].reply, recvlen); 632 memcpy(queries[qn].reply, queries[next_query].reply, recvlen);
745 } 633 }
746 634
747 if (next_query >= n_queries) 635 if (next_query >= n_queries)
748 return n_replies; 636 goto ret;
749 } 637 }
750 } 638 }
639 ret:
640 if (pfd.fd >= 0)
641 close(pfd.fd);
751 642
752 return n_replies; 643 return n_replies;
753} 644}
754 645
755///FIXME: use standard lsa = xhost2sockaddr(host, port) instead 646static void add_ns(const char *addr)
756
757static struct ns *add_ns(struct ns **ns, int *n_ns, const char *addr)
758{ 647{
759 char portstr[sizeof("65535")], *p; 648 struct ns *ns;
760 len_and_sockaddr a = { }; 649 unsigned count;
761 struct ns *tmp;
762 struct addrinfo *ai, *aip, hints = {
763 .ai_flags = AI_NUMERICSERV,
764 .ai_socktype = SOCK_DGRAM
765 };
766 650
767 dbg("%s: addr:'%s'\n", __func__, addr); 651 dbg("%s: addr:'%s'\n", __func__, addr);
768 652
769 if (parse_nsaddr(addr, &a)) { 653 count = G.serv_count++;
770 /* Maybe we got a domain name, attempt to resolve it using the standard
771 * resolver routines */
772
773 p = strchr(addr, '#');
774 snprintf(portstr, sizeof(portstr), "%hu",
775 (unsigned short)(p ? strtoul(p, NULL, 10) : G.default_port));
776 654
777 if (!getaddrinfo(addr, portstr, &hints, &ai)) { 655 G.server = xrealloc_vector(G.server, /*8=2^3:*/ 3, count);
778 for (aip = ai; aip; aip = aip->ai_next) { 656 ns = &G.server[count];
779 if (aip->ai_addr->sa_family != AF_INET && 657 ns->name = addr;
780 aip->ai_addr->sa_family != AF_INET6) 658 ns->lsa = xhost2sockaddr(addr, 53);
781 continue; 659 /*ns->replies = 0; - already is */
782 660 /*ns->failures = 0; - already is */
783#if ! ENABLE_FEATURE_IPV6
784 if (aip->ai_addr->sa_family != AF_INET)
785 continue;
786#endif
787
788 tmp = realloc(*ns, sizeof(**ns) * (*n_ns + 1));
789
790 if (!tmp)
791 return NULL;
792
793 *ns = tmp;
794
795 (*ns)[*n_ns].name = addr;
796 (*ns)[*n_ns].replies = 0;
797 (*ns)[*n_ns].failures = 0;
798 (*ns)[*n_ns].addr.len = aip->ai_addrlen;
799
800 memcpy(&(*ns)[*n_ns].addr.u.sa, aip->ai_addr, aip->ai_addrlen);
801
802 (*n_ns)++;
803 }
804
805 freeaddrinfo(ai);
806
807 return &(*ns)[*n_ns];
808 }
809
810 return NULL;
811 }
812
813 tmp = xrealloc(*ns, sizeof(**ns) * (*n_ns + 1));
814 *ns = tmp;
815
816 (*ns)[*n_ns].addr = a;
817 (*ns)[*n_ns].name = addr;
818 (*ns)[*n_ns].replies = 0;
819 (*ns)[*n_ns].failures = 0;
820
821 return &(*ns)[(*n_ns)++];
822} 661}
823 662
824static int parse_resolvconf(struct ns **ns, int *n_ns) 663static void parse_resolvconf(void)
825{ 664{
826 int prev_n_ns = *n_ns;
827 FILE *resolv; 665 FILE *resolv;
828 666
829 resolv = fopen("/etc/resolv.conf", "r"); 667 resolv = fopen("/etc/resolv.conf", "r");
@@ -841,16 +679,11 @@ static int parse_resolvconf(struct ns **ns, int *n_ns)
841 if (!p) 679 if (!p)
842 continue; 680 continue;
843 681
844 if (!add_ns(ns, n_ns, xstrdup(p))) { 682 add_ns(xstrdup(p));
845 free(p);
846 break;
847 }
848 } 683 }
849 684
850 fclose(resolv); 685 fclose(resolv);
851 } 686 }
852
853 return *n_ns - prev_n_ns;
854} 687}
855 688
856static struct query *add_query(struct query **queries, int *n_queries, 689static struct query *add_query(struct query **queries, int *n_queries,
@@ -913,7 +746,7 @@ int nslookup_main(int argc UNUSED_PARAM, char **argv)
913 struct ns *ns; 746 struct ns *ns;
914 struct query *queries; 747 struct query *queries;
915 llist_t *type_strings; 748 llist_t *type_strings;
916 int n_ns, n_queries; 749 int n_queries;
917 int bb_style_counter = 0; 750 int bb_style_counter = 0;
918 unsigned types; 751 unsigned types;
919 int rc; 752 int rc;
@@ -1018,40 +851,37 @@ int nslookup_main(int argc UNUSED_PARAM, char **argv)
1018 } while (argv[0] && argv[1]); 851 } while (argv[0] && argv[1]);
1019 852
1020 /* Use given DNS server if present */ 853 /* Use given DNS server if present */
1021 n_ns = 0;
1022 ns = NULL;
1023 if (argv[0]) { 854 if (argv[0]) {
1024 if (!add_ns(&ns, &n_ns, argv[0])) 855 add_ns(argv[0]);
1025 bb_error_msg_and_die("invalid NS server address \"%s\"", argv[0]);
1026 } else { 856 } else {
1027 parse_resolvconf(&ns, &n_ns); 857 parse_resolvconf();
1028 /* Fall back to localhost if we could not find NS in resolv.conf */ 858 /* Fall back to localhost if we could not find NS in resolv.conf */
1029 if (n_ns == 0) 859 if (G.serv_count == 0)
1030 add_ns(&ns, &n_ns, "127.0.0.1"); 860 add_ns("127.0.0.1");
1031 } 861 }
1032 862
1033 for (rc = 0; rc < n_ns; rc++) { 863 for (rc = 0; rc < G.serv_count; rc++) {
1034 int c = send_queries(&ns[rc], 1, queries, n_queries); 864 int c = send_queries(&G.server[rc], queries, n_queries);
1035 if (c < 0) 865 if (c < 0)
1036 bb_perror_msg_and_die("can't send queries"); 866 bb_perror_msg_and_die("can't send queries");
1037 if (c > 0) 867 if (c > 0)
1038 break; 868 break;
1039 rc++; 869 rc++;
1040 if (rc >= n_ns) { 870 if (rc >= G.serv_count) {
1041 fprintf(stderr, 871 fprintf(stderr,
1042 ";; connection timed out; no servers could be reached\n\n"); 872 ";; connection timed out; no servers could be reached\n\n");
1043 return EXIT_FAILURE; 873 return EXIT_FAILURE;
1044 } 874 }
1045 } 875 }
1046 876
1047 printf("Server:\t\t%s\n", ns[rc].name); 877 printf("Server:\t\t%s\n", G.server[rc].name);
1048 { 878 {
1049 char buf[SIZEOF_SAL2STR_BUF]; 879 char buf[SIZEOF_SAL2STR_BUF];
1050 printf("Address:\t%s\n", sal2str(buf, &ns[rc].addr)); 880 printf("Address:\t%s\n", sal2str(buf, G.server[rc].lsa));
1051 } 881 }
1052 if (opts & OPT_stats) { 882 if (opts & OPT_stats) {
1053 printf("Replies:\t%d\n", ns[rc].replies); 883 printf("Replies:\t%d\n", G.server[rc].replies);
1054 printf("Failures:\t%d\n", ns[rc].failures); 884 printf("Failures:\t%d\n", G.server[rc].failures);
1055 } 885 }
1056 printf("\n"); 886 printf("\n");
1057 887