summaryrefslogtreecommitdiffstats
path: root/rfc1035/rfc1035resolve.c
diff options
context:
space:
mode:
Diffstat (limited to 'rfc1035/rfc1035resolve.c')
-rw-r--r--rfc1035/rfc1035resolve.c368
1 files changed, 248 insertions, 120 deletions
diff --git a/rfc1035/rfc1035resolve.c b/rfc1035/rfc1035resolve.c
index b8bb91f..57b4139 100644
--- a/rfc1035/rfc1035resolve.c
+++ b/rfc1035/rfc1035resolve.c
@@ -15,11 +15,6 @@
#include <string.h>
#include <idna.h>
-struct querybuf {
- char qbuf[512];
- unsigned qbuflen;
- } ;
-
static void putqbuf(const char *p, unsigned l, void *q)
{
struct querybuf *qp=(struct querybuf *)q;
@@ -88,19 +83,41 @@ struct rfc1035_reply
}
static struct rfc1035_reply
+*rfc1035_resolve_multiple_attempt(struct rfc1035_res *res,
+ struct rfc1035_udp_query_responses *resps,
+ int udpfd,
+ int af,
+ const RFC1035_ADDR *sin,
+ unsigned current_timeout);
+
+static struct rfc1035_reply
+*rfc1035_resolve_multiple_attempt_tcp(struct rfc1035_res *res,
+ char const*query,
+ unsigned querylen,
+ int af,
+ const RFC1035_ADDR *sin,
+ int isaxfr,
+ unsigned current_timeout);
+
+static struct rfc1035_reply
*rfc1035_resolve_multiple_idna(struct rfc1035_res *res,
int opcode,
const struct rfc1035_query *queries,
unsigned nqueries)
{
- struct querybuf qbuf;
+ struct querybuf qbuf[nqueries];
int udpfd;
- int attempt;
+ unsigned attempt;
const RFC1035_ADDR *ns;
unsigned nscount;
unsigned current_timeout, timeout_backoff;
unsigned nbackoff, backoff_num;
int af;
+ unsigned i;
+ int isaxfr=0;
+ struct rfc1035_udp_query_responses *resps=0;
+
+ struct rfc1035_reply *rfcreply=0;
static const char fakereply[]={0, 0, 0, RFC1035_RCODE_SERVFAIL,
0, 0,
0, 0,
@@ -113,18 +130,34 @@ static struct rfc1035_reply
if (res->rfc1035_good_ns >= nscount)
res->rfc1035_good_ns=0;
- qbuf.qbuflen=0;
- if ( rfc1035_mkquery(res,
- opcode, queries, nqueries, &putqbuf, &qbuf))
+ for (i=0; i<nqueries; i++)
{
- errno=EINVAL;
- return (0);
+ qbuf[i].qbuflen=0;
+ if ( rfc1035_mkquery(res,
+ opcode, &queries[i], 1, &putqbuf, &qbuf[i]))
+ {
+ errno=EINVAL;
+ return (0);
+ }
+ if (queries[i].qtype == RFC1035_TYPE_AXFR)
+ {
+ isaxfr=1;
+ break;
+ }
}
+ if (isaxfr && nqueries > 1)
+ return rfc1035_replyparse(fakereply, sizeof(fakereply));
+
/* Prepare the UDP socket */
if ((udpfd=rfc1035_open_udp(&af)) < 0) return (0);
+ /* Prepare responses array for multple queries */
+
+ if (!isaxfr)
+ resps=rfc1035_udp_query_response_alloc_bis(qbuf, nqueries);
+
/* Keep trying until we get an answer from a nameserver */
current_timeout=res->rfc1035_timeout_initial;
@@ -133,148 +166,243 @@ static struct rfc1035_reply
if (!nbackoff) nbackoff=RFC1035_DEFAULT_MAXIMUM_BACKOFF;
timeout_backoff=current_timeout;
- for (backoff_num=0; backoff_num < nbackoff; backoff_num++,
- current_timeout *= timeout_backoff)
-
- for ( attempt=0; attempt < nscount; ++attempt)
+ for (backoff_num=0; backoff_num < nbackoff; backoff_num++,
+ current_timeout *= timeout_backoff)
{
- int nbytes;
- char *reply;
- struct rfc1035_reply *rfcreply=0;
-
- const RFC1035_ADDR *sin=&ns[(res->rfc1035_good_ns+attempt) % nscount];
- int sin_len=sizeof(*sin);
-
- int dotcp=0, isaxfr=0;
- unsigned i;
-
- for (i=0; i<nqueries; i++)
- if (queries[i].qtype == RFC1035_TYPE_AXFR)
+ for ( attempt=0; attempt < nscount; ++attempt)
+ {
+ const RFC1035_ADDR *sin=
+ &ns[(res->rfc1035_good_ns+attempt) % nscount];
+
+ rfcreply=isaxfr ?
+ rfc1035_resolve_multiple_attempt_tcp
+ (res,
+ qbuf[0].qbuf,
+ qbuf[0].qbuflen,
+ af,
+ sin,
+ 1,
+ current_timeout)
+ : rfc1035_resolve_multiple_attempt
+ (res,
+ resps,
+ udpfd,
+ af,
+ sin,
+ current_timeout);
+
+ if (rfcreply)
{
- dotcp=1;
- isaxfr=1;
+ res->rfc1035_good_ns=
+ (res->rfc1035_good_ns + attempt) %
+ nscount;
break;
}
+ }
- if (isaxfr && nqueries > 1)
- return (rfc1035_replyparse(fakereply,
- sizeof(fakereply)));
+ if (rfcreply)
+ break;
+ }
- if (!dotcp)
- {
+ sox_close(udpfd);
+
+ if (resps)
+ rfc1035_udp_query_response_free(resps);
+
+ if (!rfcreply)
+ rfcreply=rfc1035_replyparse(fakereply, sizeof(fakereply));
+
+ return (rfcreply);
+}
+
+static struct rfc1035_reply
+*rfc1035_resolve_multiple_attempt(struct rfc1035_res *res,
+ struct rfc1035_udp_query_responses *resps,
+ int udpfd,
+ int af,
+ const RFC1035_ADDR *sin,
+ unsigned current_timeout)
+{
+ struct rfc1035_reply *rfcreply=0, **rfcpp=&rfcreply;
+ int sin_len=sizeof(*sin);
+ int dotcp=0;
+ unsigned n, nqueries=resps->n_queries;
+
+ if (!resps)
+ return NULL;
+
+ if (!dotcp)
+ {
/* Send the query via UDP */
RFC1035_NETADDR addrbuf;
const struct sockaddr *addrptr;
int addrptrlen;
- if (rfc1035_mkaddress(af, &addrbuf,
- sin, htons(53),
- &addrptr, &addrptrlen))
- continue;
+ if (rfc1035_mkaddress(af, &addrbuf,
+ sin, htons(53),
+ &addrptr, &addrptrlen))
+ return NULL;
- if ((reply=rfc1035_query_udp(res, udpfd, addrptr,
- addrptrlen, qbuf.qbuf, qbuf.qbuflen, &nbytes,
- current_timeout)) == 0)
- continue;
+ if (rfc1035_udp_query_multi(res, udpfd, addrptr,
+ addrptrlen, resps, current_timeout) == 0)
+ return NULL;
- res->rfc1035_good_ns= (res->rfc1035_good_ns + attempt) %
- nscount;
+ /* Parse the replies */
- /* Parse the reply */
+ for (n = 0; n < nqueries; ++n)
+ {
+ struct rfc1035_udp_query_response *reply=&resps->queries[n];
+ if (!reply->response)
+ break; // How come? rfc1035_udp_query_multi succeeded...
- rfcreply=rfc1035_replyparse(reply, nbytes);
- if (!rfcreply)
+ *rfcpp=rfc1035_replyparse(reply->response, reply->resplen);
+ if (!*rfcpp)
{
- free(reply);
- if (errno == ENOMEM) break;
- continue;
- /* Bad response from the server, try the next one. */
+ free(reply->response); // possibly unparseable
+ reply->response=0;
+ break;
}
- rfcreply->mallocedbuf=reply;
- /*
- ** If the reply came back with the truncated bit set,
- ** retry the query via TCP.
- */
- if (rfcreply->tc)
- {
+ if ((*rfcpp)->tc)
dotcp=1;
- rfc1035_replyfree(rfcreply);
- }
+ (*rfcpp)->mallocedbuf=reply->response;
+ reply->response=0;
+ rfcpp=&(*rfcpp)->next;
}
- if (dotcp)
+ if (n < nqueries)
{
- int tcpfd;
- struct rfc1035_reply *firstreply=0, *lastreply=0;
-
- if ((tcpfd=rfc1035_open_tcp(res, sin)) < 0)
- continue; /*
- ** Can't connect via TCP,
- ** try the next server.
- */
-
- reply=rfc1035_query_tcp(res, tcpfd, qbuf.qbuf,
- qbuf.qbuflen, &nbytes, current_timeout);
+ if (rfcreply)
+ rfc1035_replyfree(rfcreply);
+ return NULL;
+ }
+ }
- if (!reply)
+ if (dotcp)
+ {
+ n = 0;
+ for (rfcpp=&rfcreply; *rfcpp; rfcpp=&(*rfcpp)->next, ++n)
+ {
+ /*
+ * UDP replies are all in, some were truncated.
+ */
+ if ((*rfcpp)->tc)
{
- sox_close(tcpfd);
- continue;
- }
-
- res->rfc1035_good_ns= (res->rfc1035_good_ns
- + attempt) % nscount;
+ struct rfc1035_reply *next=(*rfcpp)->next, *newrfc;
+ struct rfc1035_udp_query_response *reply=&resps->queries[n];
- rfcreply=rfc1035_replyparse(reply, nbytes);
- if (!rfcreply)
- {
- free(reply);
- sox_close(tcpfd);
- continue;
- }
- rfcreply->mallocedbuf=reply;
- firstreply=lastreply=rfcreply;
- while (isaxfr && rfcreply->rcode == 0)
- {
- if ((reply=rfc1035_recv_tcp(res,
- tcpfd, &nbytes, current_timeout))==0)
+ newrfc=rfc1035_resolve_multiple_attempt_tcp(res,
+ reply->query, reply->querylen,
+ af, sin, 0, current_timeout);
+ if (!newrfc)
break;
- rfcreply=rfc1035_replyparse(reply, nbytes);
- if (!rfcreply)
- {
- free(reply);
- rfc1035_replyfree(firstreply);
- firstreply=0;
- break;
- }
- rfcreply->mallocedbuf=reply;
- lastreply->next=rfcreply;
- lastreply=rfcreply;
-
- if ( rfcreply->ancount &&
- rfcreply->anptr[0].rrtype ==
- RFC1035_TYPE_SOA)
- break;
+ /*
+ * Replace the truncated reply in the linked list
+ */
+ (*rfcpp)->next=0; // only free this
+ rfc1035_replyfree(*rfcpp);
+ *rfcpp=newrfc;
+ (*rfcpp)->next=next;
}
- sox_close(tcpfd);
- if (!firstreply)
- return (0);
- rfcreply=firstreply;
}
- memcpy(&rfcreply->server_addr, sin, sin_len);
- sox_close(udpfd);
- return (rfcreply);
+
+ if (n < nqueries && rfcreply)
+ {
+ rfc1035_replyfree(rfcreply);
+ rfcreply=0;
+ }
}
+ if (rfcreply)
+ memcpy(&rfcreply->server_addr, sin, sin_len);
+
+ return (rfcreply);
+}
+
+static struct rfc1035_reply
+*rfc1035_resolve_multiple_attempt_tcp(struct rfc1035_res *res,
+ char const*query,
+ unsigned querylen,
+ int af,
+ const RFC1035_ADDR *sin,
+ int isaxfr,
+ unsigned current_timeout)
+{
+ int nbytes;
+ char *reply;
+ struct rfc1035_reply *rfcreply;
+ unsigned i;
+
/*
- ** Return a fake server failure reply, when we couldn't contact
- ** any name server.
+ ** First record in axfr will be an SOA. Start searching for the
+ ** trailing SOA starting with record 1. In case of multiple responses
+ ** we'll start looking with element 0, again.
*/
- sox_close(udpfd);
- return (rfc1035_replyparse(fakereply, sizeof(fakereply)));
+ unsigned check_soa=1;
+
+ int tcpfd;
+ struct rfc1035_reply *firstreply=0, *lastreply=0;
+
+ if ((tcpfd=rfc1035_open_tcp(res, sin)) < 0)
+ return NULL; /*
+ ** Can't connect via TCP,
+ ** try the next server.
+ */
+
+ reply=rfc1035_query_tcp(res, tcpfd, query,
+ querylen, &nbytes, current_timeout);
+
+ if (!reply)
+ {
+ sox_close(tcpfd);
+ return NULL;
+ }
+
+ rfcreply=rfc1035_replyparse(reply, nbytes);
+ if (!rfcreply)
+ {
+ free(reply);
+ sox_close(tcpfd);
+ return NULL;
+ }
+ rfcreply->mallocedbuf=reply;
+ firstreply=lastreply=rfcreply;
+ while (isaxfr && rfcreply->rcode == 0)
+ {
+ for (i=check_soa; i<rfcreply->ancount; ++i)
+ {
+ if (rfcreply->anptr[i].rrtype ==
+ RFC1035_TYPE_SOA)
+ break;
+ }
+
+ if (i < rfcreply->ancount)
+ break; /* Found trailing SOA */
+
+ check_soa=0;
+
+ if ((reply=rfc1035_recv_tcp(res,
+ tcpfd, &nbytes,
+ current_timeout))==0)
+ break;
+
+ rfcreply=rfc1035_replyparse(reply, nbytes);
+ if (!rfcreply)
+ {
+ free(reply);
+ rfc1035_replyfree(firstreply);
+ firstreply=0;
+ break;
+ }
+ rfcreply->mallocedbuf=reply;
+ lastreply->next=rfcreply;
+ lastreply=rfcreply;
+ }
+ sox_close(tcpfd);
+
+ return firstreply;
}
struct rfc1035_reply *rfc1035_resolve(