aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-04-15 10:46:44 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2018-04-15 10:46:44 +0200
commit2cf75b3c8113c59db0bf9290bd0fdfc77cd2237b (patch)
tree1ece0fdd95fbf15f5a259ecff9a2923388ca0fc6
parent4e73c0f659738f141583bbf92b3df5346d5fb3c0 (diff)
downloadbusybox-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.c196
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 {
264struct query { 264struct 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
272static const struct { 273static 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
328static int 329enum {
329parse_reply(const unsigned char *msg, size_t len) 330 OPT_stats = (1 << 4),
331};
332
333static 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 */
514static int send_queries(struct ns *ns, struct query *query, int n_queries) 524static 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);