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>
This commit is contained in:
parent
db93b21ec9
commit
71e016d806
@ -263,10 +263,10 @@ struct ns {
|
|||||||
|
|
||||||
struct query {
|
struct query {
|
||||||
const char *name;
|
const char *name;
|
||||||
size_t qlen, rlen;
|
unsigned qlen, rlen;
|
||||||
|
unsigned latency;
|
||||||
|
uint8_t rcode;
|
||||||
unsigned char query[512], reply[512];
|
unsigned char query[512], reply[512];
|
||||||
unsigned long latency;
|
|
||||||
int rcode;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
@ -288,23 +288,22 @@ static const struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const char *const rcodes[] = {
|
static const char *const rcodes[] = {
|
||||||
"NOERROR",
|
"NOERROR", // 0
|
||||||
"FORMERR",
|
"FORMERR", // 1
|
||||||
"SERVFAIL",
|
"SERVFAIL", // 2
|
||||||
"NXDOMAIN",
|
"NXDOMAIN", // 3
|
||||||
"NOTIMP",
|
"NOTIMP", // 4
|
||||||
"REFUSED",
|
"REFUSED", // 5
|
||||||
"YXDOMAIN",
|
"YXDOMAIN", // 6
|
||||||
"YXRRSET",
|
"YXRRSET", // 7
|
||||||
"NXRRSET",
|
"NXRRSET", // 8
|
||||||
"NOTAUTH",
|
"NOTAUTH", // 9
|
||||||
"NOTZONE",
|
"NOTZONE", // 10
|
||||||
"RESERVED11",
|
"11", // 11 not assigned
|
||||||
"RESERVED12",
|
"12", // 12 not assigned
|
||||||
"RESERVED13",
|
"13", // 13 not assigned
|
||||||
"RESERVED14",
|
"14", // 14 not assigned
|
||||||
"RESERVED15",
|
"15", // 15 not assigned
|
||||||
"BADVERS"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if ENABLE_FEATURE_IPV6
|
#if ENABLE_FEATURE_IPV6
|
||||||
@ -518,131 +517,136 @@ static char *make_ptr(char resbuf[80], const char *addrstr)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Function logic borrowed & modified from musl libc, res_msend.c
|
* Function logic borrowed & modified from musl libc, res_msend.c
|
||||||
|
* n_queries is always > 0.
|
||||||
*/
|
*/
|
||||||
static int send_queries(struct ns *ns, struct query *queries, int n_queries)
|
static int send_queries(struct ns *ns, struct query *query, int n_queries)
|
||||||
{
|
{
|
||||||
|
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 next_query = 0;
|
int save_idx = 0;
|
||||||
unsigned retry_interval;
|
unsigned retry_interval;
|
||||||
unsigned timeout = G.default_timeout * 1000;
|
unsigned timeout = G.default_timeout * 1000;
|
||||||
unsigned t0, t1, t2;
|
unsigned tstart, tsent, tcur;
|
||||||
|
|
||||||
pfd.fd = -1;
|
|
||||||
pfd.events = POLLIN;
|
pfd.events = POLLIN;
|
||||||
|
pfd.fd = xsocket_type(&local_lsa, ns->lsa->u.sa.sa_family, SOCK_DGRAM);
|
||||||
|
/*
|
||||||
|
* local_lsa has "null" address and port 0 now.
|
||||||
|
* bind() ensures we have a *particular port* selected by kernel
|
||||||
|
* and remembered in fd, thus later recv(fd)
|
||||||
|
* receives only packets sent to this port.
|
||||||
|
*/
|
||||||
|
xbind(pfd.fd, &local_lsa->u.sa, local_lsa->len);
|
||||||
|
free(local_lsa);
|
||||||
|
/* Make read/writes know the destination */
|
||||||
|
xconnect(pfd.fd, &ns->lsa->u.sa, ns->lsa->len);
|
||||||
|
ndelay_on(pfd.fd);
|
||||||
|
|
||||||
retry_interval = timeout / G.default_retry;
|
retry_interval = timeout / G.default_retry;
|
||||||
t0 = t2 = monotonic_ms();
|
tstart = tcur = monotonic_ms();
|
||||||
t1 = t2 - retry_interval;
|
goto send;
|
||||||
|
|
||||||
for (; t2 - t0 < timeout; t2 = monotonic_ms()) {
|
while (tcur - tstart < timeout) {
|
||||||
if (t2 - t1 >= retry_interval) {
|
int qn;
|
||||||
int qn;
|
int recvlen;
|
||||||
|
|
||||||
|
if (tcur - tsent >= retry_interval) {
|
||||||
|
send:
|
||||||
for (qn = 0; qn < n_queries; qn++) {
|
for (qn = 0; qn < n_queries; qn++) {
|
||||||
if (queries[qn].rlen)
|
if (query[qn].rlen)
|
||||||
continue;
|
continue;
|
||||||
if (pfd.fd < 0) {
|
if (write(pfd.fd, query[qn].query, query[qn].qlen) < 0) {
|
||||||
len_and_sockaddr *local_lsa;
|
|
||||||
pfd.fd = xsocket_type(&local_lsa, ns->lsa->u.sa.sa_family, SOCK_DGRAM);
|
|
||||||
/*
|
|
||||||
* local_lsa has "null" address and port 0 now.
|
|
||||||
* bind() ensures we have a *particular port* selected by kernel
|
|
||||||
* and remembered in fd, thus later recv(fd)
|
|
||||||
* receives only packets sent to this port.
|
|
||||||
*/
|
|
||||||
xbind(pfd.fd, &local_lsa->u.sa, local_lsa->len);
|
|
||||||
free(local_lsa);
|
|
||||||
/* Make read/writes know the destination */
|
|
||||||
xconnect(pfd.fd, &ns->lsa->u.sa, ns->lsa->len);
|
|
||||||
ndelay_on(pfd.fd);
|
|
||||||
}
|
|
||||||
if (write(pfd.fd, queries[qn].query, queries[qn].qlen) < 0) {
|
|
||||||
bb_perror_msg("write to '%s'", ns->name);
|
bb_perror_msg("write to '%s'", ns->name);
|
||||||
close(pfd.fd);
|
n_replies = -1; /* "no go, try next server" */
|
||||||
return -1; /* "no go, try next server" */
|
goto ret;
|
||||||
}
|
}
|
||||||
|
dbg("query %u sent\n", qn);
|
||||||
}
|
}
|
||||||
|
tsent = tcur;
|
||||||
t1 = t2;
|
|
||||||
servfail_retry = 2 * n_queries;
|
servfail_retry = 2 * n_queries;
|
||||||
}
|
}
|
||||||
poll_more:
|
|
||||||
/* Wait for a response, or until time to retry */
|
/* Wait for a response, or until time to retry */
|
||||||
if (poll(&pfd, 1, t1 + retry_interval - t2) <= 0)
|
if (poll(&pfd, 1, retry_interval - (tcur - tsent)) <= 0)
|
||||||
continue;
|
goto next;
|
||||||
|
|
||||||
while (1) {
|
recvlen = read(pfd.fd, query[save_idx].reply, sizeof(query[0].reply));
|
||||||
int qn;
|
|
||||||
int recvlen;
|
|
||||||
|
|
||||||
recvlen = read(pfd.fd,
|
/* Error/non-identifiable packet */
|
||||||
queries[next_query].reply,
|
if (recvlen < 4) {
|
||||||
sizeof(queries[next_query].reply)
|
dbg("read is too short:%d\n", recvlen);
|
||||||
);
|
goto next;
|
||||||
|
|
||||||
/* read error */
|
|
||||||
if (recvlen < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Ignore non-identifiable packets */
|
|
||||||
if (recvlen < 4)
|
|
||||||
goto poll_more;
|
|
||||||
|
|
||||||
/* Find which query this answer goes with, if any */
|
|
||||||
for (qn = next_query; qn < n_queries; qn++)
|
|
||||||
if (memcmp(queries[next_query].reply, queries[qn].query, 2) == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (qn >= n_queries || queries[qn].rlen)
|
|
||||||
goto poll_more;
|
|
||||||
|
|
||||||
queries[qn].rcode = queries[next_query].reply[3] & 15;
|
|
||||||
queries[qn].latency = monotonic_ms() - t0;
|
|
||||||
|
|
||||||
ns->replies++;
|
|
||||||
|
|
||||||
/* Only accept positive or negative responses;
|
|
||||||
* retry immediately on server failure, and ignore
|
|
||||||
* all other codes such as refusal. */
|
|
||||||
switch (queries[qn].rcode) {
|
|
||||||
case 0:
|
|
||||||
case 3:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
if (servfail_retry && servfail_retry--) {
|
|
||||||
ns->failures++;
|
|
||||||
write(pfd.fd, queries[qn].query, queries[qn].qlen);
|
|
||||||
}
|
|
||||||
/* fall through */
|
|
||||||
|
|
||||||
default:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store answer */
|
|
||||||
n_replies++;
|
|
||||||
|
|
||||||
queries[qn].rlen = recvlen;
|
|
||||||
|
|
||||||
if (qn == next_query) {
|
|
||||||
while (next_query < n_queries) {
|
|
||||||
if (!queries[next_query].rlen)
|
|
||||||
break;
|
|
||||||
next_query++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
memcpy(queries[qn].reply, queries[next_query].reply, recvlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next_query >= n_queries)
|
|
||||||
goto ret;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/* Find which query this answer goes with, if any */
|
||||||
|
qn = save_idx;
|
||||||
|
for (;;) {
|
||||||
|
if (memcmp(query[save_idx].reply, query[qn].query, 2) == 0) {
|
||||||
|
dbg("response matches query %u\n", qn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (++qn >= n_queries) {
|
||||||
|
dbg("response does not match any query\n");
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query[qn].rlen) {
|
||||||
|
dbg("dropped duplicate response to query %u\n", qn);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
ns->replies++;
|
||||||
|
|
||||||
|
query[qn].rcode = query[save_idx].reply[3] & 15;
|
||||||
|
dbg("query %u rcode:%s\n", qn, rcodes[query[qn].rcode]);
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
servfail_retry--;
|
||||||
|
ns->failures++;
|
||||||
|
write(pfd.fd, query[qn].query, query[qn].qlen);
|
||||||
|
dbg("query %u resent\n", qn);
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
|
next:
|
||||||
|
tcur = monotonic_ms();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store answer */
|
||||||
|
n_replies++;
|
||||||
|
query[qn].rlen = recvlen;
|
||||||
|
tcur = monotonic_ms();
|
||||||
|
query[qn].latency = tcur - tstart;
|
||||||
|
if (qn != save_idx) {
|
||||||
|
/* "wrong" receive buffer, move to correct one */
|
||||||
|
memcpy(query[qn].reply, query[save_idx].reply, recvlen);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* query[0..save_idx] have replies, move to next one, if exists */
|
||||||
|
for (;;) {
|
||||||
|
save_idx++;
|
||||||
|
if (save_idx >= n_queries)
|
||||||
|
goto ret; /* all are full: we have all results */
|
||||||
|
if (!query[save_idx].rlen)
|
||||||
|
break; /* this one is empty */
|
||||||
|
}
|
||||||
|
} /* while() */
|
||||||
|
|
||||||
ret:
|
ret:
|
||||||
if (pfd.fd >= 0)
|
close(pfd.fd);
|
||||||
close(pfd.fd);
|
|
||||||
|
|
||||||
return n_replies;
|
return n_replies;
|
||||||
}
|
}
|
||||||
@ -791,12 +795,13 @@ int nslookup_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
n_queries = 0;
|
n_queries = 0;
|
||||||
queries = NULL;
|
queries = NULL;
|
||||||
do {
|
do {
|
||||||
/* No explicit type given, guess query type.
|
|
||||||
* If we can convert the domain argument into a ptr (means that
|
|
||||||
* inet_pton() could read it) we assume a PTR request, else
|
|
||||||
* we issue A+AAAA queries and switch to an output format
|
|
||||||
* mimicking the one of the traditional nslookup applet. */
|
|
||||||
if (types == 0) {
|
if (types == 0) {
|
||||||
|
/* No explicit type given, guess query type.
|
||||||
|
* If we can convert the domain argument into a ptr (means that
|
||||||
|
* inet_pton() could read it) we assume a PTR request, else
|
||||||
|
* we issue A+AAAA queries and switch to an output format
|
||||||
|
* mimicking the one of the traditional nslookup applet.
|
||||||
|
*/
|
||||||
char *ptr;
|
char *ptr;
|
||||||
char buf80[80];
|
char buf80[80];
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user