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>
This commit is contained in:
parent
4e73c0f659
commit
2cf75b3c81
@ -264,9 +264,10 @@ struct ns {
|
|||||||
struct query {
|
struct query {
|
||||||
const char *name;
|
const char *name;
|
||||||
unsigned qlen, rlen;
|
unsigned qlen, rlen;
|
||||||
unsigned latency;
|
// unsigned latency;
|
||||||
uint8_t rcode;
|
// uint8_t rcode;
|
||||||
unsigned char query[512], reply[512];
|
unsigned char query[512];
|
||||||
|
// unsigned char reply[512];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
@ -325,9 +326,14 @@ struct globals {
|
|||||||
G.default_timeout = 5; \
|
G.default_timeout = 5; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static int
|
enum {
|
||||||
parse_reply(const unsigned char *msg, size_t len)
|
OPT_stats = (1 << 4),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int parse_reply(const unsigned char *msg, size_t len)
|
||||||
{
|
{
|
||||||
|
HEADER *header;
|
||||||
|
|
||||||
ns_msg handle;
|
ns_msg handle;
|
||||||
ns_rr rr;
|
ns_rr rr;
|
||||||
int i, n, rdlen;
|
int i, n, rdlen;
|
||||||
@ -335,14 +341,18 @@ parse_reply(const unsigned char *msg, size_t len)
|
|||||||
char astr[INET6_ADDRSTRLEN], dname[MAXDNAME];
|
char astr[INET6_ADDRSTRLEN], dname[MAXDNAME];
|
||||||
const unsigned char *cp;
|
const unsigned char *cp;
|
||||||
|
|
||||||
|
header = (HEADER *)msg;
|
||||||
|
if (!header->aa)
|
||||||
|
printf("Non-authoritative answer:\n");
|
||||||
|
|
||||||
if (ns_initparse(msg, len, &handle) != 0) {
|
if (ns_initparse(msg, len, &handle) != 0) {
|
||||||
//fprintf(stderr, "Unable to parse reply: %s\n", strerror(errno));
|
//printf("Unable to parse reply: %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ns_msg_count(handle, ns_s_an); i++) {
|
for (i = 0; i < ns_msg_count(handle, ns_s_an); i++) {
|
||||||
if (ns_parserr(&handle, ns_s_an, i, &rr) != 0) {
|
if (ns_parserr(&handle, ns_s_an, i, &rr) != 0) {
|
||||||
//fprintf(stderr, "Unable to parse resource record: %s\n", strerror(errno));
|
//printf("Unable to parse resource record: %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,7 +397,7 @@ parse_reply(const unsigned char *msg, size_t len)
|
|||||||
if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
|
if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
|
||||||
ns_rr_rdata(rr), dname, sizeof(dname)) < 0
|
ns_rr_rdata(rr), dname, sizeof(dname)) < 0
|
||||||
) {
|
) {
|
||||||
//fprintf(stderr, "Unable to uncompress domain: %s\n", strerror(errno));
|
//printf("Unable to uncompress domain: %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
printf(format, ns_rr_name(rr), dname);
|
printf(format, ns_rr_name(rr), dname);
|
||||||
@ -395,14 +405,14 @@ parse_reply(const unsigned char *msg, size_t len)
|
|||||||
|
|
||||||
case ns_t_mx:
|
case ns_t_mx:
|
||||||
if (rdlen < 2) {
|
if (rdlen < 2) {
|
||||||
fprintf(stderr, "MX record too short\n");
|
printf("MX record too short\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
n = ns_get16(ns_rr_rdata(rr));
|
n = ns_get16(ns_rr_rdata(rr));
|
||||||
if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
|
if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
|
||||||
ns_rr_rdata(rr) + 2, dname, sizeof(dname)) < 0
|
ns_rr_rdata(rr) + 2, dname, sizeof(dname)) < 0
|
||||||
) {
|
) {
|
||||||
//fprintf(stderr, "Cannot uncompress MX domain: %s\n", strerror(errno));
|
//printf("Cannot uncompress MX domain: %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
printf("%s\tmail exchanger = %d %s\n", ns_rr_name(rr), n, dname);
|
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)
|
|||||||
|
|
||||||
case ns_t_txt:
|
case ns_t_txt:
|
||||||
if (rdlen < 1) {
|
if (rdlen < 1) {
|
||||||
//fprintf(stderr, "TXT record too short\n");
|
//printf("TXT record too short\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
n = *(unsigned char *)ns_rr_rdata(rr);
|
n = *(unsigned char *)ns_rr_rdata(rr);
|
||||||
@ -433,7 +443,7 @@ parse_reply(const unsigned char *msg, size_t len)
|
|||||||
n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
|
n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
|
||||||
cp, dname, sizeof(dname));
|
cp, dname, sizeof(dname));
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
//fprintf(stderr, "Unable to uncompress domain: %s\n", strerror(errno));
|
//printf("Unable to uncompress domain: %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,7 +453,7 @@ parse_reply(const unsigned char *msg, size_t len)
|
|||||||
n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
|
n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
|
||||||
cp, dname, sizeof(dname));
|
cp, dname, sizeof(dname));
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
//fprintf(stderr, "Unable to uncompress domain: %s\n", strerror(errno));
|
//printf("Unable to uncompress domain: %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,11 +523,13 @@ static char *make_ptr(char resbuf[80], const char *addrstr)
|
|||||||
*/
|
*/
|
||||||
static int send_queries(struct ns *ns, struct query *query, int n_queries)
|
static int send_queries(struct ns *ns, struct query *query, int n_queries)
|
||||||
{
|
{
|
||||||
|
unsigned char reply[512];
|
||||||
|
uint8_t rcode;
|
||||||
len_and_sockaddr *local_lsa;
|
len_and_sockaddr *local_lsa;
|
||||||
struct pollfd pfd;
|
struct pollfd pfd;
|
||||||
int servfail_retry = 0;
|
int servfail_retry = 0;
|
||||||
int n_replies = 0;
|
int n_replies = 0;
|
||||||
int save_idx = 0;
|
// int save_idx = 0;
|
||||||
unsigned retry_interval;
|
unsigned retry_interval;
|
||||||
unsigned timeout = G.default_timeout * 1000;
|
unsigned timeout = G.default_timeout * 1000;
|
||||||
unsigned tstart, tsent, tcur;
|
unsigned tstart, tsent, tcur;
|
||||||
@ -564,18 +576,34 @@ static int send_queries(struct ns *ns, struct query *query, int n_queries)
|
|||||||
if (poll(&pfd, 1, retry_interval - (tcur - tsent)) <= 0)
|
if (poll(&pfd, 1, retry_interval - (tcur - tsent)) <= 0)
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
recvlen = read(pfd.fd, query[save_idx].reply, sizeof(query[0].reply));
|
recvlen = read(pfd.fd, reply, sizeof(reply));
|
||||||
|
if (recvlen < 0) {
|
||||||
|
bb_perror_msg("read");
|
||||||
|
next:
|
||||||
|
tcur = monotonic_ms();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Error/non-identifiable packet */
|
if (ns->replies++ == 0) {
|
||||||
|
printf("Server:\t\t%s\n", ns->name);
|
||||||
|
printf("Address:\t%s\n\n",
|
||||||
|
auto_string(xmalloc_sockaddr2dotted(&ns->lsa->u.sa))
|
||||||
|
);
|
||||||
|
/* In "Address", bind-utils-9.11.3 show port after a hash: "1.2.3.4#53" */
|
||||||
|
/* Should we do the same? */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Non-identifiable packet */
|
||||||
if (recvlen < 4) {
|
if (recvlen < 4) {
|
||||||
dbg("read is too short:%d\n", recvlen);
|
dbg("read is too short:%d\n", recvlen);
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find which query this answer goes with, if any */
|
/* Find which query this answer goes with, if any */
|
||||||
qn = save_idx;
|
// qn = save_idx;
|
||||||
|
qn = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (memcmp(query[save_idx].reply, query[qn].query, 2) == 0) {
|
if (memcmp(reply, query[qn].query, 2) == 0) {
|
||||||
dbg("response matches query %u\n", qn);
|
dbg("response matches query %u\n", qn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -590,38 +618,42 @@ static int send_queries(struct ns *ns, struct query *query, int n_queries)
|
|||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
ns->replies++;
|
rcode = reply[3] & 0x0f;
|
||||||
|
dbg("query %u rcode:%s\n", qn, rcodes[rcode]);
|
||||||
|
|
||||||
query[qn].rcode = query[save_idx].reply[3] & 15;
|
/* Retry immediately on SERVFAIL */
|
||||||
dbg("query %u rcode:%s\n", qn, rcodes[query[qn].rcode]);
|
if (rcode == 2) {
|
||||||
|
ns->failures++;
|
||||||
/* Only accept positive or negative responses;
|
|
||||||
* retry immediately on server failure, and ignore
|
|
||||||
* all other codes such as refusal.
|
|
||||||
*/
|
|
||||||
switch (query[qn].rcode) {
|
|
||||||
case 0:
|
|
||||||
case 3:
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (servfail_retry) {
|
if (servfail_retry) {
|
||||||
servfail_retry--;
|
servfail_retry--;
|
||||||
ns->failures++;
|
|
||||||
write(pfd.fd, query[qn].query, query[qn].qlen);
|
write(pfd.fd, query[qn].query, query[qn].qlen);
|
||||||
dbg("query %u resent\n", qn);
|
dbg("query %u resent\n", qn);
|
||||||
|
goto next;
|
||||||
}
|
}
|
||||||
/* fall through */
|
|
||||||
default:
|
|
||||||
next:
|
|
||||||
tcur = monotonic_ms();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store answer */
|
/* Process reply */
|
||||||
n_replies++;
|
|
||||||
query[qn].rlen = recvlen;
|
query[qn].rlen = recvlen;
|
||||||
tcur = monotonic_ms();
|
tcur = monotonic_ms();
|
||||||
|
#if 1
|
||||||
|
if (option_mask32 & OPT_stats) {
|
||||||
|
printf("Query #%d completed in %ums:\n", qn, tcur - tstart);
|
||||||
|
}
|
||||||
|
if (rcode != 0) {
|
||||||
|
printf("** server can't find %s: %s\n",
|
||||||
|
query[qn].name, rcodes[rcode]);
|
||||||
|
} else {
|
||||||
|
if (parse_reply(reply, recvlen) < 0)
|
||||||
|
printf("*** Can't find %s: Parse error\n", query[qn].name);
|
||||||
|
}
|
||||||
|
bb_putchar('\n');
|
||||||
|
n_replies++;
|
||||||
|
if (n_replies >= n_queries)
|
||||||
|
goto ret;
|
||||||
|
#else
|
||||||
|
//used to store replies and process them later
|
||||||
query[qn].latency = tcur - tstart;
|
query[qn].latency = tcur - tstart;
|
||||||
|
n_replies++;
|
||||||
if (qn != save_idx) {
|
if (qn != save_idx) {
|
||||||
/* "wrong" receive buffer, move to correct one */
|
/* "wrong" receive buffer, move to correct one */
|
||||||
memcpy(query[qn].reply, query[save_idx].reply, recvlen);
|
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)
|
|||||||
if (!query[save_idx].rlen)
|
if (!query[save_idx].rlen)
|
||||||
break; /* this one is empty */
|
break; /* this one is empty */
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
} /* while() */
|
} /* while() */
|
||||||
|
|
||||||
ret:
|
ret:
|
||||||
@ -718,11 +751,9 @@ int nslookup_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
llist_t *type_strings;
|
llist_t *type_strings;
|
||||||
int n_queries;
|
int n_queries;
|
||||||
unsigned types;
|
unsigned types;
|
||||||
int rc;
|
|
||||||
int opts;
|
int opts;
|
||||||
enum {
|
int rc;
|
||||||
OPT_stats = (1 << 4),
|
int err;
|
||||||
};
|
|
||||||
|
|
||||||
INIT_G();
|
INIT_G();
|
||||||
|
|
||||||
@ -827,61 +858,54 @@ int nslookup_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
add_ns("127.0.0.1");
|
add_ns("127.0.0.1");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (rc = 0; rc < G.serv_count; rc++) {
|
for (rc = 0; rc < G.serv_count;) {
|
||||||
int c = send_queries(&G.server[rc], queries, n_queries);
|
int c;
|
||||||
if (c > 0)
|
|
||||||
|
c = send_queries(&G.server[rc], queries, n_queries);
|
||||||
|
if (c > 0) {
|
||||||
|
/* more than zero replies received */
|
||||||
|
if (opts & OPT_stats) {
|
||||||
|
printf("Replies:\t%d\n", G.server[rc].replies);
|
||||||
|
printf("Failures:\t%d\n\n", G.server[rc].failures);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
//FIXME: we "break" even though some queries may still be not answered, and other servers may know them?
|
||||||
|
}
|
||||||
/* c = 0: timed out waiting for replies */
|
/* c = 0: timed out waiting for replies */
|
||||||
/* c < 0: error (message already printed) */
|
/* c < 0: error (message already printed) */
|
||||||
rc++;
|
rc++;
|
||||||
if (rc >= G.serv_count) {
|
if (rc >= G.serv_count) {
|
||||||
fprintf(stderr,
|
//
|
||||||
";; connection timed out; no servers could be reached\n\n");
|
// NB: bind-utils-9.11.3 behavior (all to stdout, not stderr):
|
||||||
|
//
|
||||||
|
// $ nslookup gmail.com 8.8.8.8
|
||||||
|
// ;; connection timed out; no servers could be reached
|
||||||
|
//
|
||||||
|
// $ nslookup -s gmail.com 8.8.8.8; echo EXITCODE:$?
|
||||||
|
// <~10 sec>
|
||||||
|
// ;; Connection to 8.8.8.8#53(8.8.8.8) for gmail.com failed: timed out.
|
||||||
|
// <~10 sec>
|
||||||
|
// ;; Connection to 8.8.8.8#53(8.8.8.8) for gmail.com failed: timed out.
|
||||||
|
// <~10 sec>
|
||||||
|
// ;; connection timed out; no servers could be reached
|
||||||
|
// ;; Connection to 8.8.8.8#53(8.8.8.8) for gmail.com failed: timed out.
|
||||||
|
// <empty line>
|
||||||
|
// EXITCODE:1
|
||||||
|
// $ _
|
||||||
|
printf(";; connection timed out; no servers could be reached\n\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Server:\t\t%s\n", G.server[rc].name);
|
err = 0;
|
||||||
printf("Address:\t%s\n", xmalloc_sockaddr2dotted(&G.server[rc].lsa->u.sa));
|
|
||||||
/* In "Address", bind-utils-9.11.3 show port after a hash: "1.2.3.4#53" */
|
|
||||||
/* Should we do the same? */
|
|
||||||
|
|
||||||
if (opts & OPT_stats) {
|
|
||||||
printf("Replies:\t%d\n", G.server[rc].replies);
|
|
||||||
printf("Failures:\t%d\n", G.server[rc].failures);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
for (rc = 0; rc < n_queries; rc++) {
|
for (rc = 0; rc < n_queries; rc++) {
|
||||||
int c;
|
if (queries[rc].rlen == 0) {
|
||||||
|
|
||||||
if (opts & OPT_stats) {
|
|
||||||
printf("Query #%d completed in %ums:\n", rc, queries[rc].latency);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queries[rc].rcode != 0) {
|
|
||||||
printf("** server can't find %s: %s\n", queries[rc].name,
|
|
||||||
rcodes[queries[rc].rcode]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
c = 0;
|
|
||||||
if (queries[rc].rlen) {
|
|
||||||
HEADER *header;
|
|
||||||
|
|
||||||
header = (HEADER *)queries[rc].reply;
|
|
||||||
if (!header->aa)
|
|
||||||
printf("Non-authoritative answer:\n");
|
|
||||||
c = parse_reply(queries[rc].reply, queries[rc].rlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == 0)
|
|
||||||
printf("*** Can't find %s: No answer\n", queries[rc].name);
|
printf("*** Can't find %s: No answer\n", queries[rc].name);
|
||||||
else if (c < 0)
|
err = 1;
|
||||||
printf("*** Can't find %s: Parse error\n", queries[rc].name);
|
}
|
||||||
|
|
||||||
bb_putchar('\n');
|
|
||||||
}
|
}
|
||||||
|
if (err)
|
||||||
|
bb_putchar('\n'); /* should this affect exicode too? */
|
||||||
|
|
||||||
if (ENABLE_FEATURE_CLEAN_UP) {
|
if (ENABLE_FEATURE_CLEAN_UP) {
|
||||||
free(ns);
|
free(ns);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user