diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-04-14 22:53:39 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-04-14 22:53:39 +0200 |
commit | 71e016d806f0f2c9168e9096546c15996e6a8e20 (patch) | |
tree | d13bafa4d0c1719e6e0143afa81866b98646224e | |
parent | db93b21ec9c7923dc2c419c81650b070b9ca751a (diff) | |
download | busybox-w32-71e016d806f0f2c9168e9096546c15996e6a8e20.tar.gz busybox-w32-71e016d806f0f2c9168e9096546c15996e6a8e20.tar.bz2 busybox-w32-71e016d806f0f2c9168e9096546c15996e6a8e20.zip |
nslookup: shrink send_queries()
function old new delta
rcodes 68 64 -4
nslookup_main 2007 1880 -127
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-131) Total: -131 bytes
text data bss dec hex filename
926735 555 5740 933030 e3ca6 busybox_old
926525 555 5740 932820 e3bd4 busybox_unstripped
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/nslookup.c | 241 |
1 files changed, 123 insertions, 118 deletions
diff --git a/networking/nslookup.c b/networking/nslookup.c index 2e6569497..23ab97585 100644 --- a/networking/nslookup.c +++ b/networking/nslookup.c | |||
@@ -263,10 +263,10 @@ struct ns { | |||
263 | 263 | ||
264 | struct query { | 264 | struct query { |
265 | const char *name; | 265 | const char *name; |
266 | size_t qlen, rlen; | 266 | unsigned qlen, rlen; |
267 | unsigned latency; | ||
268 | uint8_t rcode; | ||
267 | unsigned char query[512], reply[512]; | 269 | unsigned char query[512], reply[512]; |
268 | unsigned long latency; | ||
269 | int rcode; | ||
270 | }; | 270 | }; |
271 | 271 | ||
272 | static const struct { | 272 | static const struct { |
@@ -288,23 +288,22 @@ static const struct { | |||
288 | }; | 288 | }; |
289 | 289 | ||
290 | static const char *const rcodes[] = { | 290 | static const char *const rcodes[] = { |
291 | "NOERROR", | 291 | "NOERROR", // 0 |
292 | "FORMERR", | 292 | "FORMERR", // 1 |
293 | "SERVFAIL", | 293 | "SERVFAIL", // 2 |
294 | "NXDOMAIN", | 294 | "NXDOMAIN", // 3 |
295 | "NOTIMP", | 295 | "NOTIMP", // 4 |
296 | "REFUSED", | 296 | "REFUSED", // 5 |
297 | "YXDOMAIN", | 297 | "YXDOMAIN", // 6 |
298 | "YXRRSET", | 298 | "YXRRSET", // 7 |
299 | "NXRRSET", | 299 | "NXRRSET", // 8 |
300 | "NOTAUTH", | 300 | "NOTAUTH", // 9 |
301 | "NOTZONE", | 301 | "NOTZONE", // 10 |
302 | "RESERVED11", | 302 | "11", // 11 not assigned |
303 | "RESERVED12", | 303 | "12", // 12 not assigned |
304 | "RESERVED13", | 304 | "13", // 13 not assigned |
305 | "RESERVED14", | 305 | "14", // 14 not assigned |
306 | "RESERVED15", | 306 | "15", // 15 not assigned |
307 | "BADVERS" | ||
308 | }; | 307 | }; |
309 | 308 | ||
310 | #if ENABLE_FEATURE_IPV6 | 309 | #if ENABLE_FEATURE_IPV6 |
@@ -518,131 +517,136 @@ static char *make_ptr(char resbuf[80], const char *addrstr) | |||
518 | 517 | ||
519 | /* | 518 | /* |
520 | * Function logic borrowed & modified from musl libc, res_msend.c | 519 | * Function logic borrowed & modified from musl libc, res_msend.c |
520 | * n_queries is always > 0. | ||
521 | */ | 521 | */ |
522 | static int send_queries(struct ns *ns, struct query *queries, int n_queries) | 522 | static int send_queries(struct ns *ns, struct query *query, int n_queries) |
523 | { | 523 | { |
524 | len_and_sockaddr *local_lsa; | ||
524 | struct pollfd pfd; | 525 | struct pollfd pfd; |
525 | int servfail_retry = 0; | 526 | int servfail_retry = 0; |
526 | int n_replies = 0; | 527 | int n_replies = 0; |
527 | int next_query = 0; | 528 | int save_idx = 0; |
528 | unsigned retry_interval; | 529 | unsigned retry_interval; |
529 | unsigned timeout = G.default_timeout * 1000; | 530 | unsigned timeout = G.default_timeout * 1000; |
530 | unsigned t0, t1, t2; | 531 | unsigned tstart, tsent, tcur; |
531 | 532 | ||
532 | pfd.fd = -1; | ||
533 | pfd.events = POLLIN; | 533 | pfd.events = POLLIN; |
534 | pfd.fd = xsocket_type(&local_lsa, ns->lsa->u.sa.sa_family, SOCK_DGRAM); | ||
535 | /* | ||
536 | * local_lsa has "null" address and port 0 now. | ||
537 | * bind() ensures we have a *particular port* selected by kernel | ||
538 | * and remembered in fd, thus later recv(fd) | ||
539 | * receives only packets sent to this port. | ||
540 | */ | ||
541 | xbind(pfd.fd, &local_lsa->u.sa, local_lsa->len); | ||
542 | free(local_lsa); | ||
543 | /* Make read/writes know the destination */ | ||
544 | xconnect(pfd.fd, &ns->lsa->u.sa, ns->lsa->len); | ||
545 | ndelay_on(pfd.fd); | ||
534 | 546 | ||
535 | retry_interval = timeout / G.default_retry; | 547 | retry_interval = timeout / G.default_retry; |
536 | t0 = t2 = monotonic_ms(); | 548 | tstart = tcur = monotonic_ms(); |
537 | t1 = t2 - retry_interval; | 549 | goto send; |
550 | |||
551 | while (tcur - tstart < timeout) { | ||
552 | int qn; | ||
553 | int recvlen; | ||
538 | 554 | ||
539 | for (; t2 - t0 < timeout; t2 = monotonic_ms()) { | 555 | if (tcur - tsent >= retry_interval) { |
540 | if (t2 - t1 >= retry_interval) { | 556 | send: |
541 | int qn; | ||
542 | for (qn = 0; qn < n_queries; qn++) { | 557 | for (qn = 0; qn < n_queries; qn++) { |
543 | if (queries[qn].rlen) | 558 | if (query[qn].rlen) |
544 | continue; | 559 | continue; |
545 | if (pfd.fd < 0) { | 560 | if (write(pfd.fd, query[qn].query, query[qn].qlen) < 0) { |
546 | len_and_sockaddr *local_lsa; | ||
547 | pfd.fd = xsocket_type(&local_lsa, ns->lsa->u.sa.sa_family, SOCK_DGRAM); | ||
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); | ||
559 | } | ||
560 | if (write(pfd.fd, queries[qn].query, queries[qn].qlen) < 0) { | ||
561 | bb_perror_msg("write to '%s'", ns->name); | 561 | bb_perror_msg("write to '%s'", ns->name); |
562 | close(pfd.fd); | 562 | n_replies = -1; /* "no go, try next server" */ |
563 | return -1; /* "no go, try next server" */ | 563 | goto ret; |
564 | } | 564 | } |
565 | dbg("query %u sent\n", qn); | ||
565 | } | 566 | } |
566 | 567 | tsent = tcur; | |
567 | t1 = t2; | ||
568 | servfail_retry = 2 * n_queries; | 568 | servfail_retry = 2 * n_queries; |
569 | } | 569 | } |
570 | poll_more: | ||
571 | /* Wait for a response, or until time to retry */ | ||
572 | if (poll(&pfd, 1, t1 + retry_interval - t2) <= 0) | ||
573 | continue; | ||
574 | |||
575 | while (1) { | ||
576 | int qn; | ||
577 | int recvlen; | ||
578 | |||
579 | recvlen = read(pfd.fd, | ||
580 | queries[next_query].reply, | ||
581 | sizeof(queries[next_query].reply) | ||
582 | ); | ||
583 | 570 | ||
584 | /* read error */ | 571 | /* Wait for a response, or until time to retry */ |
585 | if (recvlen < 0) | 572 | if (poll(&pfd, 1, retry_interval - (tcur - tsent)) <= 0) |
586 | break; | 573 | goto next; |
587 | |||
588 | /* Ignore non-identifiable packets */ | ||
589 | if (recvlen < 4) | ||
590 | goto poll_more; | ||
591 | |||
592 | /* Find which query this answer goes with, if any */ | ||
593 | for (qn = next_query; qn < n_queries; qn++) | ||
594 | if (memcmp(queries[next_query].reply, queries[qn].query, 2) == 0) | ||
595 | break; | ||
596 | |||
597 | if (qn >= n_queries || queries[qn].rlen) | ||
598 | goto poll_more; | ||
599 | 574 | ||
600 | queries[qn].rcode = queries[next_query].reply[3] & 15; | 575 | recvlen = read(pfd.fd, query[save_idx].reply, sizeof(query[0].reply)); |
601 | queries[qn].latency = monotonic_ms() - t0; | ||
602 | 576 | ||
603 | ns->replies++; | 577 | /* Error/non-identifiable packet */ |
578 | if (recvlen < 4) { | ||
579 | dbg("read is too short:%d\n", recvlen); | ||
580 | goto next; | ||
581 | } | ||
604 | 582 | ||
605 | /* Only accept positive or negative responses; | 583 | /* Find which query this answer goes with, if any */ |
606 | * retry immediately on server failure, and ignore | 584 | qn = save_idx; |
607 | * all other codes such as refusal. */ | 585 | for (;;) { |
608 | switch (queries[qn].rcode) { | 586 | if (memcmp(query[save_idx].reply, query[qn].query, 2) == 0) { |
609 | case 0: | 587 | dbg("response matches query %u\n", qn); |
610 | case 3: | ||
611 | break; | 588 | break; |
612 | |||
613 | case 2: | ||
614 | if (servfail_retry && servfail_retry--) { | ||
615 | ns->failures++; | ||
616 | write(pfd.fd, queries[qn].query, queries[qn].qlen); | ||
617 | } | ||
618 | /* fall through */ | ||
619 | |||
620 | default: | ||
621 | continue; | ||
622 | } | 589 | } |
590 | if (++qn >= n_queries) { | ||
591 | dbg("response does not match any query\n"); | ||
592 | goto next; | ||
593 | } | ||
594 | } | ||
623 | 595 | ||
624 | /* Store answer */ | 596 | if (query[qn].rlen) { |
625 | n_replies++; | 597 | dbg("dropped duplicate response to query %u\n", qn); |
598 | goto next; | ||
599 | } | ||
626 | 600 | ||
627 | queries[qn].rlen = recvlen; | 601 | ns->replies++; |
628 | 602 | ||
629 | if (qn == next_query) { | 603 | query[qn].rcode = query[save_idx].reply[3] & 15; |
630 | while (next_query < n_queries) { | 604 | dbg("query %u rcode:%s\n", qn, rcodes[query[qn].rcode]); |
631 | if (!queries[next_query].rlen) | 605 | |
632 | break; | 606 | /* Only accept positive or negative responses; |
633 | next_query++; | 607 | * retry immediately on server failure, and ignore |
634 | } | 608 | * all other codes such as refusal. |
635 | } else { | 609 | */ |
636 | memcpy(queries[qn].reply, queries[next_query].reply, recvlen); | 610 | switch (query[qn].rcode) { |
611 | case 0: | ||
612 | case 3: | ||
613 | break; | ||
614 | case 2: | ||
615 | if (servfail_retry) { | ||
616 | servfail_retry--; | ||
617 | ns->failures++; | ||
618 | write(pfd.fd, query[qn].query, query[qn].qlen); | ||
619 | dbg("query %u resent\n", qn); | ||
637 | } | 620 | } |
621 | /* fall through */ | ||
622 | default: | ||
623 | next: | ||
624 | tcur = monotonic_ms(); | ||
625 | continue; | ||
626 | } | ||
638 | 627 | ||
639 | if (next_query >= n_queries) | 628 | /* Store answer */ |
640 | goto ret; | 629 | n_replies++; |
630 | query[qn].rlen = recvlen; | ||
631 | tcur = monotonic_ms(); | ||
632 | query[qn].latency = tcur - tstart; | ||
633 | if (qn != save_idx) { | ||
634 | /* "wrong" receive buffer, move to correct one */ | ||
635 | memcpy(query[qn].reply, query[save_idx].reply, recvlen); | ||
636 | continue; | ||
641 | } | 637 | } |
642 | } | 638 | /* query[0..save_idx] have replies, move to next one, if exists */ |
639 | for (;;) { | ||
640 | save_idx++; | ||
641 | if (save_idx >= n_queries) | ||
642 | goto ret; /* all are full: we have all results */ | ||
643 | if (!query[save_idx].rlen) | ||
644 | break; /* this one is empty */ | ||
645 | } | ||
646 | } /* while() */ | ||
647 | |||
643 | ret: | 648 | ret: |
644 | if (pfd.fd >= 0) | 649 | close(pfd.fd); |
645 | close(pfd.fd); | ||
646 | 650 | ||
647 | return n_replies; | 651 | return n_replies; |
648 | } | 652 | } |
@@ -791,12 +795,13 @@ int nslookup_main(int argc UNUSED_PARAM, char **argv) | |||
791 | n_queries = 0; | 795 | n_queries = 0; |
792 | queries = NULL; | 796 | queries = NULL; |
793 | do { | 797 | do { |
794 | /* No explicit type given, guess query type. | ||
795 | * If we can convert the domain argument into a ptr (means that | ||
796 | * inet_pton() could read it) we assume a PTR request, else | ||
797 | * we issue A+AAAA queries and switch to an output format | ||
798 | * mimicking the one of the traditional nslookup applet. */ | ||
799 | if (types == 0) { | 798 | if (types == 0) { |
799 | /* No explicit type given, guess query type. | ||
800 | * If we can convert the domain argument into a ptr (means that | ||
801 | * inet_pton() could read it) we assume a PTR request, else | ||
802 | * we issue A+AAAA queries and switch to an output format | ||
803 | * mimicking the one of the traditional nslookup applet. | ||
804 | */ | ||
800 | char *ptr; | 805 | char *ptr; |
801 | char buf80[80]; | 806 | char buf80[80]; |
802 | 807 | ||