diff options
| author | Sam Varshavchik | 2020-05-07 22:49:32 -0400 |
|---|---|---|
| committer | Sam Varshavchik | 2020-05-07 22:49:32 -0400 |
| commit | c9982ab6a25c0cd95bfc0867dc8cab991786ddb5 (patch) | |
| tree | ef5010016d5c2a6afbcd54a583c8d0c045f87006 /rfc1035 | |
| parent | 531c5ca6c1290dfc036f6149199cb9c19ba23ab1 (diff) | |
| download | courier-libs-c9982ab6a25c0cd95bfc0867dc8cab991786ddb5.tar.bz2 | |
More simultaneous DNS query support.
Diffstat (limited to 'rfc1035')
| -rw-r--r-- | rfc1035/rfc1035.h | 16 | ||||
| -rw-r--r-- | rfc1035/rfc1035reply.c | 9 | ||||
| -rw-r--r-- | rfc1035/rfc1035search.c | 144 | ||||
| -rw-r--r-- | rfc1035/testlookup.c | 115 |
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); |
