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); |
