diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-04-15 10:46:44 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-04-15 10:46:44 +0200 |
commit | 2cf75b3c8113c59db0bf9290bd0fdfc77cd2237b (patch) | |
tree | 1ece0fdd95fbf15f5a259ecff9a2923388ca0fc6 | |
parent | 4e73c0f659738f141583bbf92b3df5346d5fb3c0 (diff) | |
download | busybox-w32-2cf75b3c8113c59db0bf9290bd0fdfc77cd2237b.tar.gz busybox-w32-2cf75b3c8113c59db0bf9290bd0fdfc77cd2237b.tar.bz2 busybox-w32-2cf75b3c8113c59db0bf9290bd0fdfc77cd2237b.zip |
nslookup: process replies immediately, do not store them
function old new delta
nslookup_main 1837 2708 +871
parse_reply 852 - -852
------------------------------------------------------------------------------
(add/remove: 0/1 grow/shrink: 1/0 up/down: 871/-852) Total: 19 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/nslookup.c | 196 |
1 files changed, 110 insertions, 86 deletions
diff --git a/networking/nslookup.c b/networking/nslookup.c index 92e07e8b1..d31801e96 100644 --- a/networking/nslookup.c +++ b/networking/nslookup.c | |||
@@ -264,9 +264,10 @@ struct ns { | |||
264 | struct query { | 264 | struct query { |
265 | const char *name; | 265 | const char *name; |
266 | unsigned qlen, rlen; | 266 | unsigned qlen, rlen; |
267 | unsigned latency; | 267 | // unsigned latency; |
268 | uint8_t rcode; | 268 | // uint8_t rcode; |
269 | unsigned char query[512], reply[512]; | 269 | unsigned char query[512]; |
270 | // unsigned char reply[512]; | ||
270 | }; | 271 | }; |
271 | 272 | ||
272 | static const struct { | 273 | static const struct { |
@@ -325,9 +326,14 @@ struct globals { | |||
325 | G.default_timeout = 5; \ | 326 | G.default_timeout = 5; \ |
326 | } while (0) | 327 | } while (0) |
327 | 328 | ||
328 | static int | 329 | enum { |
329 | parse_reply(const unsigned char *msg, size_t len) | 330 | OPT_stats = (1 << 4), |
331 | }; | ||
332 | |||
333 | static int parse_reply(const unsigned char *msg, size_t len) | ||
330 | { | 334 | { |
335 | HEADER *header; | ||
336 | |||
331 | ns_msg handle; | 337 | ns_msg handle; |
332 | ns_rr rr; | 338 | ns_rr rr; |
333 | int i, n, rdlen; | 339 | int i, n, rdlen; |
@@ -335,14 +341,18 @@ parse_reply(const unsigned char *msg, size_t len) | |||
335 | char astr[INET6_ADDRSTRLEN], dname[MAXDNAME]; | 341 | char astr[INET6_ADDRSTRLEN], dname[MAXDNAME]; |
336 | const unsigned char *cp; | 342 | const unsigned char *cp; |
337 | 343 | ||
344 | header = (HEADER *)msg; | ||
345 | if (!header->aa) | ||
346 | printf("Non-authoritative answer:\n"); | ||
347 | |||
338 | if (ns_initparse(msg, len, &handle) != 0) { | 348 | if (ns_initparse(msg, len, &handle) != 0) { |
339 | //fprintf(stderr, "Unable to parse reply: %s\n", strerror(errno)); | 349 | //printf("Unable to parse reply: %s\n", strerror(errno)); |
340 | return -1; | 350 | return -1; |
341 | } | 351 | } |
342 | 352 | ||
343 | for (i = 0; i < ns_msg_count(handle, ns_s_an); i++) { | 353 | for (i = 0; i < ns_msg_count(handle, ns_s_an); i++) { |
344 | if (ns_parserr(&handle, ns_s_an, i, &rr) != 0) { | 354 | if (ns_parserr(&handle, ns_s_an, i, &rr) != 0) { |
345 | //fprintf(stderr, "Unable to parse resource record: %s\n", strerror(errno)); | 355 | //printf("Unable to parse resource record: %s\n", strerror(errno)); |
346 | return -1; | 356 | return -1; |
347 | } | 357 | } |
348 | 358 | ||
@@ -387,7 +397,7 @@ parse_reply(const unsigned char *msg, size_t len) | |||
387 | if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), | 397 | if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), |
388 | ns_rr_rdata(rr), dname, sizeof(dname)) < 0 | 398 | ns_rr_rdata(rr), dname, sizeof(dname)) < 0 |
389 | ) { | 399 | ) { |
390 | //fprintf(stderr, "Unable to uncompress domain: %s\n", strerror(errno)); | 400 | //printf("Unable to uncompress domain: %s\n", strerror(errno)); |
391 | return -1; | 401 | return -1; |
392 | } | 402 | } |
393 | printf(format, ns_rr_name(rr), dname); | 403 | printf(format, ns_rr_name(rr), dname); |
@@ -395,14 +405,14 @@ parse_reply(const unsigned char *msg, size_t len) | |||
395 | 405 | ||
396 | case ns_t_mx: | 406 | case ns_t_mx: |
397 | if (rdlen < 2) { | 407 | if (rdlen < 2) { |
398 | fprintf(stderr, "MX record too short\n"); | 408 | printf("MX record too short\n"); |
399 | return -1; | 409 | return -1; |
400 | } | 410 | } |
401 | n = ns_get16(ns_rr_rdata(rr)); | 411 | n = ns_get16(ns_rr_rdata(rr)); |
402 | if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), | 412 | if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), |
403 | ns_rr_rdata(rr) + 2, dname, sizeof(dname)) < 0 | 413 | ns_rr_rdata(rr) + 2, dname, sizeof(dname)) < 0 |
404 | ) { | 414 | ) { |
405 | //fprintf(stderr, "Cannot uncompress MX domain: %s\n", strerror(errno)); | 415 | //printf("Cannot uncompress MX domain: %s\n", strerror(errno)); |
406 | return -1; | 416 | return -1; |
407 | } | 417 | } |
408 | printf("%s\tmail exchanger = %d %s\n", ns_rr_name(rr), n, dname); | 418 | printf("%s\tmail exchanger = %d %s\n", ns_rr_name(rr), n, dname); |
@@ -410,7 +420,7 @@ parse_reply(const unsigned char *msg, size_t len) | |||
410 | 420 | ||
411 | case ns_t_txt: | 421 | case ns_t_txt: |
412 | if (rdlen < 1) { | 422 | if (rdlen < 1) { |
413 | //fprintf(stderr, "TXT record too short\n"); | 423 | //printf("TXT record too short\n"); |
414 | return -1; | 424 | return -1; |
415 | } | 425 | } |
416 | n = *(unsigned char *)ns_rr_rdata(rr); | 426 | n = *(unsigned char *)ns_rr_rdata(rr); |
@@ -433,7 +443,7 @@ parse_reply(const unsigned char *msg, size_t len) | |||
433 | n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), | 443 | n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), |
434 | cp, dname, sizeof(dname)); | 444 | cp, dname, sizeof(dname)); |
435 | if (n < 0) { | 445 | if (n < 0) { |
436 | //fprintf(stderr, "Unable to uncompress domain: %s\n", strerror(errno)); | 446 | //printf("Unable to uncompress domain: %s\n", strerror(errno)); |
437 | return -1; | 447 | return -1; |
438 | } | 448 | } |
439 | 449 | ||
@@ -443,7 +453,7 @@ parse_reply(const unsigned char *msg, size_t len) | |||
443 | n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), | 453 | n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), |
444 | cp, dname, sizeof(dname)); | 454 | cp, dname, sizeof(dname)); |
445 | if (n < 0) { | 455 | if (n < 0) { |
446 | //fprintf(stderr, "Unable to uncompress domain: %s\n", strerror(errno)); | 456 | //printf("Unable to uncompress domain: %s\n", strerror(errno)); |
447 | return -1; | 457 | return -1; |
448 | } | 458 | } |
449 | 459 | ||
@@ -513,11 +523,13 @@ static char *make_ptr(char resbuf[80], const char *addrstr) | |||
513 | */ | 523 | */ |
514 | static int send_queries(struct ns *ns, struct query *query, int n_queries) | 524 | static int send_queries(struct ns *ns, struct query *query, int n_queries) |
515 | { | 525 | { |
526 | unsigned char reply[512]; | ||
527 | uint8_t rcode; | ||
516 | len_and_sockaddr *local_lsa; | 528 | len_and_sockaddr *local_lsa; |
517 | struct pollfd pfd; | 529 | struct pollfd pfd; |
518 | int servfail_retry = 0; | 530 | int servfail_retry = 0; |
519 | int n_replies = 0; | 531 | int n_replies = 0; |
520 | int save_idx = 0; | 532 | // int save_idx = 0; |
521 | unsigned retry_interval; | 533 | unsigned retry_interval; |
522 | unsigned timeout = G.default_timeout * 1000; | 534 | unsigned timeout = G.default_timeout * 1000; |
523 | unsigned tstart, tsent, tcur; | 535 | unsigned tstart, tsent, tcur; |
@@ -564,18 +576,34 @@ static int send_queries(struct ns *ns, struct query *query, int n_queries) | |||
564 | if (poll(&pfd, 1, retry_interval - (tcur - tsent)) <= 0) | 576 | if (poll(&pfd, 1, retry_interval - (tcur - tsent)) <= 0) |
565 | goto next; | 577 | goto next; |
566 | 578 | ||
567 | recvlen = read(pfd.fd, query[save_idx].reply, sizeof(query[0].reply)); | 579 | recvlen = read(pfd.fd, reply, sizeof(reply)); |
580 | if (recvlen < 0) { | ||
581 | bb_perror_msg("read"); | ||
582 | next: | ||
583 | tcur = monotonic_ms(); | ||
584 | continue; | ||
585 | } | ||
568 | 586 | ||
569 | /* Error/non-identifiable packet */ | 587 | if (ns->replies++ == 0) { |
588 | printf("Server:\t\t%s\n", ns->name); | ||
589 | printf("Address:\t%s\n\n", | ||
590 | auto_string(xmalloc_sockaddr2dotted(&ns->lsa->u.sa)) | ||
591 | ); | ||
592 | /* In "Address", bind-utils-9.11.3 show port after a hash: "1.2.3.4#53" */ | ||
593 | /* Should we do the same? */ | ||
594 | } | ||
595 | |||
596 | /* Non-identifiable packet */ | ||
570 | if (recvlen < 4) { | 597 | if (recvlen < 4) { |
571 | dbg("read is too short:%d\n", recvlen); | 598 | dbg("read is too short:%d\n", recvlen); |
572 | goto next; | 599 | goto next; |
573 | } | 600 | } |
574 | 601 | ||
575 | /* Find which query this answer goes with, if any */ | 602 | /* Find which query this answer goes with, if any */ |
576 | qn = save_idx; | 603 | // qn = save_idx; |
604 | qn = 0; | ||
577 | for (;;) { | 605 | for (;;) { |
578 | if (memcmp(query[save_idx].reply, query[qn].query, 2) == 0) { | 606 | if (memcmp(reply, query[qn].query, 2) == 0) { |
579 | dbg("response matches query %u\n", qn); | 607 | dbg("response matches query %u\n", qn); |
580 | break; | 608 | break; |
581 | } | 609 | } |
@@ -590,38 +618,42 @@ static int send_queries(struct ns *ns, struct query *query, int n_queries) | |||
590 | goto next; | 618 | goto next; |
591 | } | 619 | } |
592 | 620 | ||
593 | ns->replies++; | 621 | rcode = reply[3] & 0x0f; |
594 | 622 | dbg("query %u rcode:%s\n", qn, rcodes[rcode]); | |
595 | query[qn].rcode = query[save_idx].reply[3] & 15; | ||
596 | dbg("query %u rcode:%s\n", qn, rcodes[query[qn].rcode]); | ||
597 | 623 | ||
598 | /* Only accept positive or negative responses; | 624 | /* Retry immediately on SERVFAIL */ |
599 | * retry immediately on server failure, and ignore | 625 | if (rcode == 2) { |
600 | * all other codes such as refusal. | 626 | ns->failures++; |
601 | */ | ||
602 | switch (query[qn].rcode) { | ||
603 | case 0: | ||
604 | case 3: | ||
605 | break; | ||
606 | case 2: | ||
607 | if (servfail_retry) { | 627 | if (servfail_retry) { |
608 | servfail_retry--; | 628 | servfail_retry--; |
609 | ns->failures++; | ||
610 | write(pfd.fd, query[qn].query, query[qn].qlen); | 629 | write(pfd.fd, query[qn].query, query[qn].qlen); |
611 | dbg("query %u resent\n", qn); | 630 | dbg("query %u resent\n", qn); |
631 | goto next; | ||
612 | } | 632 | } |
613 | /* fall through */ | ||
614 | default: | ||
615 | next: | ||
616 | tcur = monotonic_ms(); | ||
617 | continue; | ||
618 | } | 633 | } |
619 | 634 | ||
620 | /* Store answer */ | 635 | /* Process reply */ |
621 | n_replies++; | ||
622 | query[qn].rlen = recvlen; | 636 | query[qn].rlen = recvlen; |
623 | tcur = monotonic_ms(); | 637 | tcur = monotonic_ms(); |
638 | #if 1 | ||
639 | if (option_mask32 & OPT_stats) { | ||
640 | printf("Query #%d completed in %ums:\n", qn, tcur - tstart); | ||
641 | } | ||
642 | if (rcode != 0) { | ||
643 | printf("** server can't find %s: %s\n", | ||
644 | query[qn].name, rcodes[rcode]); | ||
645 | } else { | ||
646 | if (parse_reply(reply, recvlen) < 0) | ||
647 | printf("*** Can't find %s: Parse error\n", query[qn].name); | ||
648 | } | ||
649 | bb_putchar('\n'); | ||
650 | n_replies++; | ||
651 | if (n_replies >= n_queries) | ||
652 | goto ret; | ||
653 | #else | ||
654 | //used to store replies and process them later | ||
624 | query[qn].latency = tcur - tstart; | 655 | query[qn].latency = tcur - tstart; |
656 | n_replies++; | ||
625 | if (qn != save_idx) { | 657 | if (qn != save_idx) { |
626 | /* "wrong" receive buffer, move to correct one */ | 658 | /* "wrong" receive buffer, move to correct one */ |
627 | memcpy(query[qn].reply, query[save_idx].reply, recvlen); | 659 | memcpy(query[qn].reply, query[save_idx].reply, recvlen); |
@@ -635,6 +667,7 @@ static int send_queries(struct ns *ns, struct query *query, int n_queries) | |||
635 | if (!query[save_idx].rlen) | 667 | if (!query[save_idx].rlen) |
636 | break; /* this one is empty */ | 668 | break; /* this one is empty */ |
637 | } | 669 | } |
670 | #endif | ||
638 | } /* while() */ | 671 | } /* while() */ |
639 | 672 | ||
640 | ret: | 673 | ret: |
@@ -718,11 +751,9 @@ int nslookup_main(int argc UNUSED_PARAM, char **argv) | |||
718 | llist_t *type_strings; | 751 | llist_t *type_strings; |
719 | int n_queries; | 752 | int n_queries; |
720 | unsigned types; | 753 | unsigned types; |
721 | int rc; | ||
722 | int opts; | 754 | int opts; |
723 | enum { | 755 | int rc; |
724 | OPT_stats = (1 << 4), | 756 | int err; |
725 | }; | ||
726 | 757 | ||
727 | INIT_G(); | 758 | INIT_G(); |
728 | 759 | ||
@@ -827,61 +858,54 @@ int nslookup_main(int argc UNUSED_PARAM, char **argv) | |||
827 | add_ns("127.0.0.1"); | 858 | add_ns("127.0.0.1"); |
828 | } | 859 | } |
829 | 860 | ||
830 | for (rc = 0; rc < G.serv_count; rc++) { | 861 | for (rc = 0; rc < G.serv_count;) { |
831 | int c = send_queries(&G.server[rc], queries, n_queries); | 862 | int c; |
832 | if (c > 0) | 863 | |
864 | c = send_queries(&G.server[rc], queries, n_queries); | ||
865 | if (c > 0) { | ||
866 | /* more than zero replies received */ | ||
867 | if (opts & OPT_stats) { | ||
868 | printf("Replies:\t%d\n", G.server[rc].replies); | ||
869 | printf("Failures:\t%d\n\n", G.server[rc].failures); | ||
870 | } | ||
833 | break; | 871 | break; |
872 | //FIXME: we "break" even though some queries may still be not answered, and other servers may know them? | ||
873 | } | ||
834 | /* c = 0: timed out waiting for replies */ | 874 | /* c = 0: timed out waiting for replies */ |
835 | /* c < 0: error (message already printed) */ | 875 | /* c < 0: error (message already printed) */ |
836 | rc++; | 876 | rc++; |
837 | if (rc >= G.serv_count) { | 877 | if (rc >= G.serv_count) { |
838 | fprintf(stderr, | 878 | // |
839 | ";; connection timed out; no servers could be reached\n\n"); | 879 | // NB: bind-utils-9.11.3 behavior (all to stdout, not stderr): |
880 | // | ||
881 | // $ nslookup gmail.com 8.8.8.8 | ||
882 | // ;; connection timed out; no servers could be reached | ||
883 | // | ||
884 | // $ nslookup -s gmail.com 8.8.8.8; echo EXITCODE:$? | ||
885 | // <~10 sec> | ||
886 | // ;; Connection to 8.8.8.8#53(8.8.8.8) for gmail.com failed: timed out. | ||
887 | // <~10 sec> | ||
888 | // ;; Connection to 8.8.8.8#53(8.8.8.8) for gmail.com failed: timed out. | ||
889 | // <~10 sec> | ||
890 | // ;; connection timed out; no servers could be reached | ||
891 | // ;; Connection to 8.8.8.8#53(8.8.8.8) for gmail.com failed: timed out. | ||
892 | // <empty line> | ||
893 | // EXITCODE:1 | ||
894 | // $ _ | ||
895 | printf(";; connection timed out; no servers could be reached\n\n"); | ||
840 | return EXIT_FAILURE; | 896 | return EXIT_FAILURE; |
841 | } | 897 | } |
842 | } | 898 | } |
843 | 899 | ||
844 | printf("Server:\t\t%s\n", G.server[rc].name); | 900 | err = 0; |
845 | printf("Address:\t%s\n", xmalloc_sockaddr2dotted(&G.server[rc].lsa->u.sa)); | ||
846 | /* In "Address", bind-utils-9.11.3 show port after a hash: "1.2.3.4#53" */ | ||
847 | /* Should we do the same? */ | ||
848 | |||
849 | if (opts & OPT_stats) { | ||
850 | printf("Replies:\t%d\n", G.server[rc].replies); | ||
851 | printf("Failures:\t%d\n", G.server[rc].failures); | ||
852 | } | ||
853 | printf("\n"); | ||
854 | |||
855 | for (rc = 0; rc < n_queries; rc++) { | 901 | for (rc = 0; rc < n_queries; rc++) { |
856 | int c; | 902 | if (queries[rc].rlen == 0) { |
857 | |||
858 | if (opts & OPT_stats) { | ||
859 | printf("Query #%d completed in %ums:\n", rc, queries[rc].latency); | ||
860 | } | ||
861 | |||
862 | if (queries[rc].rcode != 0) { | ||
863 | printf("** server can't find %s: %s\n", queries[rc].name, | ||
864 | rcodes[queries[rc].rcode]); | ||
865 | continue; | ||
866 | } | ||
867 | |||
868 | c = 0; | ||
869 | if (queries[rc].rlen) { | ||
870 | HEADER *header; | ||
871 | |||
872 | header = (HEADER *)queries[rc].reply; | ||
873 | if (!header->aa) | ||
874 | printf("Non-authoritative answer:\n"); | ||
875 | c = parse_reply(queries[rc].reply, queries[rc].rlen); | ||
876 | } | ||
877 | |||
878 | if (c == 0) | ||
879 | printf("*** Can't find %s: No answer\n", queries[rc].name); | 903 | printf("*** Can't find %s: No answer\n", queries[rc].name); |
880 | else if (c < 0) | 904 | err = 1; |
881 | printf("*** Can't find %s: Parse error\n", queries[rc].name); | 905 | } |
882 | |||
883 | bb_putchar('\n'); | ||
884 | } | 906 | } |
907 | if (err) | ||
908 | bb_putchar('\n'); /* should this affect exicode too? */ | ||
885 | 909 | ||
886 | if (ENABLE_FEATURE_CLEAN_UP) { | 910 | if (ENABLE_FEATURE_CLEAN_UP) { |
887 | free(ns); | 911 | free(ns); |