aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-04-14 22:53:39 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2018-04-14 22:53:39 +0200
commit71e016d806f0f2c9168e9096546c15996e6a8e20 (patch)
treed13bafa4d0c1719e6e0143afa81866b98646224e
parentdb93b21ec9c7923dc2c419c81650b070b9ca751a (diff)
downloadbusybox-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.c241
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
264struct query { 264struct 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
272static const struct { 272static const struct {
@@ -288,23 +288,22 @@ static const struct {
288}; 288};
289 289
290static const char *const rcodes[] = { 290static 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 */
522static int send_queries(struct ns *ns, struct query *queries, int n_queries) 522static 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