summaryrefslogtreecommitdiffstats
path: root/rfc1035
diff options
context:
space:
mode:
authorSam Varshavchik2020-05-07 22:49:32 -0400
committerSam Varshavchik2020-05-07 22:49:32 -0400
commitc9982ab6a25c0cd95bfc0867dc8cab991786ddb5 (patch)
treeef5010016d5c2a6afbcd54a583c8d0c045f87006 /rfc1035
parent531c5ca6c1290dfc036f6149199cb9c19ba23ab1 (diff)
downloadcourier-libs-c9982ab6a25c0cd95bfc0867dc8cab991786ddb5.tar.bz2
More simultaneous DNS query support.
Diffstat (limited to 'rfc1035')
-rw-r--r--rfc1035/rfc1035.h16
-rw-r--r--rfc1035/rfc1035reply.c9
-rw-r--r--rfc1035/rfc1035search.c144
-rw-r--r--rfc1035/testlookup.c115
4 files changed, 266 insertions, 18 deletions
diff --git a/rfc1035/rfc1035.h b/rfc1035/rfc1035.h
index ee85101..9a92c1b 100644
--- a/rfc1035/rfc1035.h
+++ b/rfc1035/rfc1035.h
@@ -228,6 +228,22 @@ int rfc1035_resolve_cname(
#define RFC1035_X_RANDOMIZE 1 /* Randomize query results */
+/*
+** rfc1035_resolve_cname_multiple is a version of rfc1035_resolve_cname
+** that accepts an array of qtypes, and issues a query for each qtype.
+**
+** qtypes points to a 0-terminated list of RRs.
+*/
+int rfc1035_resolve_cname_multiple(struct rfc1035_res *res,
+ char *namebuf,
+ /* RFC1035_MAXNAMESIZE buffer with
+ ** the name to query */
+ unsigned char *qtypes,
+ unsigned qclass,
+ struct rfc1035_reply **ptr,
+ int x_flags);
+
+
/*
** Always call replyfree when done.
*/
diff --git a/rfc1035/rfc1035reply.c b/rfc1035/rfc1035reply.c
index ac1e87e..ab43dfb 100644
--- a/rfc1035/rfc1035reply.c
+++ b/rfc1035/rfc1035reply.c
@@ -489,7 +489,10 @@ void rfc1035_rr_rand_ar(struct rfc1035_reply *rr)
void rfc1035_rr_rand(struct rfc1035_reply *rr)
{
- rfc1035_rr_rand_an(rr);
- rfc1035_rr_rand_ns(rr);
- rfc1035_rr_rand_ar(rr);
+ if (rr->ancount > 1)
+ rfc1035_rr_rand_an(rr);
+ if (rr->nscount > 1)
+ rfc1035_rr_rand_ns(rr);
+ if (rr->arcount > 1)
+ rfc1035_rr_rand_ar(rr);
}
diff --git a/rfc1035/rfc1035search.c b/rfc1035/rfc1035search.c
index 019f521..526e7a0 100644
--- a/rfc1035/rfc1035search.c
+++ b/rfc1035/rfc1035search.c
@@ -141,7 +141,8 @@ int rfc1035_replysearch_all(const struct rfc1035_res *res,
return (-1);
}
-int rfc1035_resolve_cname(struct rfc1035_res *res, char *namebuf,
+int rfc1035_resolve_cname(struct rfc1035_res *res,
+ char *namebuf,
unsigned qtype,
unsigned qclass,
struct rfc1035_reply **ptr,
@@ -212,3 +213,144 @@ int recursion_count=10;
return (-1);
}
}
+
+int rfc1035_resolve_cname_multiple(struct rfc1035_res *res,
+ char *namebuf,
+ unsigned char *qtypes,
+ unsigned qclass,
+ struct rfc1035_reply **ptr,
+ int x_flags)
+{
+ int n, query_again;
+ int retry_count=10;
+ unsigned nqueries=strlen((char*)qtypes), u, good, cname;
+ struct rfc1035_query qu[nqueries];
+ struct rfc1035_reply *p;
+
+ char cmpname1[RFC1035_MAXNAMESIZE+1],
+ cmpname2[RFC1035_MAXNAMESIZE+1];
+
+ static const char forbidden[] =
+ {
+ RFC1035_TYPE_CNAME,
+ RFC1035_TYPE_AXFR,
+ RFC1035_TYPE_ANY,
+ 0
+ };
+
+ if (nqueries == 0)
+ return -1;
+
+ for (u=0; u<nqueries; ++u)
+ {
+ qu[u].name=namebuf;
+ qu[u].qclass=qclass;
+ qu[u].qtype=qtypes[u];
+
+ if (strchr(forbidden, qtypes[u]))
+ {
+ if (nqueries == 1)
+ {
+ return rfc1035_resolve_cname(res, namebuf,
+ qtypes[0],
+ qclass,
+ ptr,
+ x_flags);
+ }
+ return -1;
+ }
+ }
+
+ *ptr=NULL;
+
+ do // query loop
+ {
+ if (*ptr)
+ rfc1035_replyfree( *ptr );
+
+ if ( (*ptr=rfc1035_resolve_multiple(res, RFC1035_OPCODE_QUERY,
+ qu, nqueries)) == 0)
+ return (-1);
+
+ query_again=0;
+
+ for (;;) // change name loop
+ {
+ int fatal = 0;
+
+ good = cname = 0;
+ for (u=0, p=*ptr; p; ++u, p=p->next)
+ {
+ if (p->rcode != RFC1035_RCODE_NOERROR ||
+ (n=rfc1035_replysearch_all(res,
+ p, namebuf,
+ qu[u].qtype,
+ qclass, 0))
+ < 0)
+ continue;
+ else if (p->allrrs[n]->rrtype == qu[u].qtype)
+ {
+ ++good;
+ }
+ else // CNAME (not the queried type).
+ {
+ if (rfc1035_replyhostname(p, p->anptr[n].rr.domainname,
+ cname? cmpname1: cmpname2) == 0)
+ fatal=-1;
+
+ else if (cname && strcmp(cmpname1, cmpname2))
+ query_again=1; // different aliases: try again
+
+ ++cname;
+ }
+ }
+
+ if (good == 0 && cname == 0)
+ {
+ rfc1035_replyfree( *ptr );
+ *ptr=0;
+ return (-1);
+ }
+
+ if (good > 0 && cname > 0)
+ query_again=1; // have both cnames and non-cnames
+
+ if (query_again)
+ {
+ if (--retry_count > 0)
+ break;
+
+ fatal=RFC1035_ERR_CNAME_RECURSIVE;
+ }
+
+ if (fatal)
+ {
+ rfc1035_replyfree( *ptr );
+ *ptr=0;
+ return fatal;
+ }
+
+ if (good)
+ break;
+
+ /* CNAME found. Return alias to caller, and restart from there */
+
+ strcpy(namebuf, cmpname1);
+ }
+
+ } while (query_again);
+
+ if (x_flags & RFC1035_X_RANDOMIZE)
+ for (p=*ptr; p; p=p->next)
+ if (p->rcode == RFC1035_RCODE_NOERROR)
+ rfc1035_rr_rand(p);
+
+/*
+* Collecting allrrs shall be a further proposal.
+ if ((x_flags & RFC1035_X_COLLECT) &&
+ (*ptr)->rcode == RFC1035_RCODE_NOERROR)
+ rfc1035_collect_allrrs(*ptr);
+*/
+
+ return (0);
+}
diff --git a/rfc1035/testlookup.c b/rfc1035/testlookup.c
index cd99c81..75c701f 100644
--- a/rfc1035/testlookup.c
+++ b/rfc1035/testlookup.c
@@ -74,13 +74,65 @@ static void spflookup(const char *current_domain)
}
}
+static int get_q_type_pass(const char *p,
+ void (*cb)(unsigned char, void *),
+ void *ptr)
+{
+ char qbuf[strlen(p)+1];
+ char *q;
+
+ strcpy(qbuf, p);
+
+ for (q=qbuf; (q=strtok(q, ", \t\r\n")); q=0)
+ {
+ int n=rfc1035_type_strtoi(q);
+
+ if (n < 0)
+ return -1;
+
+ (*cb)(n, ptr);
+ }
+
+ return 0;
+}
+
+static void get_q_type_count(unsigned char c, void *ptr)
+{
+ ++*(size_t *)ptr;
+}
+
+static void get_q_type_save(unsigned char c, void *ptr)
+{
+ *(*(unsigned char **)ptr)++=c;
+}
+
+static unsigned char *get_q_type(const char *p)
+{
+ size_t n=0;
+ unsigned char *buf, *q;
+
+ errno=EINVAL;
+ if (get_q_type_pass(p, &get_q_type_count, &n) < 0)
+ return 0;
+
+ if ((buf=(unsigned char *)malloc(n+1)) == 0)
+ return 0;
+
+ q=buf;
+ get_q_type_pass(p, &get_q_type_save, &q);
+
+ *q=0;
+
+ return buf;
+}
+
int main(int argc, char **argv)
{
struct rfc1035_res res;
struct rfc1035_reply *replyp;
int argn;
const char *q_name;
-int q_type;
+unsigned char *q_type;
int q_class;
int q_xflag=0;
int q_rflag=0;
@@ -229,18 +281,26 @@ char ptrbuf[RFC1035_MAXNAMESIZE+1];
exit(1);
}
- q_type= -1;
+ q_type=0;
if (argn < argc)
{
if (strcmp(argv[argn], "spf") == 0)
- q_type= -2;
- else
- q_type=rfc1035_type_strtoi(argv[argn++]);
+ {
+ spflookup(q_name);
+ exit(0);
+ }
+ q_type=get_q_type(argv[argn]);
+ if (!q_type)
+ {
+ perror(argv[argn]);
+ exit(1);
+ }
+ argn++;
}
- if (q_type == -1)
- q_type=q_xflag ? RFC1035_TYPE_PTR:RFC1035_TYPE_ANY;
+ if (q_type == 0)
+ q_type=get_q_type(q_xflag ? "PTR":"ANY");
q_class= -1;
if (argn < argc)
@@ -248,22 +308,49 @@ char ptrbuf[RFC1035_MAXNAMESIZE+1];
if (q_class < 0)
q_class=RFC1035_CLASS_IN;
- if (q_type == -2)
+ if (q_type[0] && q_type[1])
{
- spflookup(q_name);
- exit(0);
- }
+ char namebuf[RFC1035_MAXNAMESIZE+1];
- replyp=rfc1035_resolve(&res, RFC1035_OPCODE_QUERY,
- q_name, q_type, q_class);
+ namebuf[0]=0;
+ strncat(namebuf, q_name, RFC1035_MAXNAMESIZE);
+ if (rfc1035_resolve_cname_multiple(&res, namebuf,
+ q_type, q_class,
+ &replyp,
+ RFC1035_X_RANDOMIZE)
+ < 0)
+ replyp=0;
+ }
+ else
+ {
+ replyp=rfc1035_resolve(&res, RFC1035_OPCODE_QUERY,
+ q_name, q_type[0], q_class);
+ }
+ free(q_type);
if (!replyp)
{
perror(argv[0]);
exit(1);
}
- rfc1035_dump(replyp, stdout);
+ if (q_type[0] && q_type[1])
+ {
+ struct rfc1035_reply *q;
+
+ for (q=replyp; q; q=q->next)
+ {
+ struct rfc1035_reply *s=q->next;
+
+ q->next=0;
+ rfc1035_dump(q, stdout);
+ q->next=s;
+ }
+ }
+ else
+ {
+ rfc1035_dump(replyp, stdout);
+ }
rfc1035_replyfree(replyp);
rfc1035_destroy_resolv(&res);
return (0);