From b2318b35c1f191f2500b69e547cddb05fe9b5ba4 Mon Sep 17 00:00:00 2001 From: manuel Date: Fri, 3 Jul 2015 16:20:57 +0200 Subject: convert dns handling to getdns --- dns.c | 645 ++++++++++++++++++++++++++++++++---------------------------------- 1 file changed, 312 insertions(+), 333 deletions(-) diff --git a/dns.c b/dns.c index bed2bd2..5f8ba77 100644 --- a/dns.c +++ b/dns.c @@ -5,8 +5,8 @@ #include #include #include -extern int res_query(); -extern int res_search(); +#include +#include #include "ip.h" #include "ipalloc.h" #include "fmt.h" @@ -16,405 +16,384 @@ extern int res_search(); #include "dns.h" #include "case.h" -static unsigned short getshort(c) unsigned char *c; -{ unsigned short u; u = c[0]; return (u << 8) + c[1]; } +static getdns_context *context = NULL; +static stralloc glue = {0}; -static struct { unsigned char *buf; } response; -static int responsebuflen = 0; -static int responselen; -static unsigned char *responseend; -static unsigned char *responsepos; -static u_long saveresoptions; +static int getdns_resolve_query(const char *name, uint16_t type, + getdns_dict **response) +{ + if (getdns_general_sync(context, name, type, NULL, response) + != GETDNS_RETURN_GOOD) + return DNS_HARD; -static int numanswers; -static char name[MAXDNAME]; -static struct ip_address ip; -unsigned short pref; + uint32_t error; + getdns_dict_get_int(*response, "status", &error); + if (error != GETDNS_RESPSTATUS_GOOD) + return DNS_HARD; -static stralloc glue = {0}; - -static int (*lookup)() = res_query; + return 0; +} -static int resolve(domain,type) -stralloc *domain; -int type; +static int getdns_resolve_loop(getdns_dict *response, uint16_t type, + int (*cb_rr)(getdns_dict *response, getdns_dict *rdata, void *userarg), + void *userarg) { - int n; - int i; - - errno = 0; - if (!stralloc_copy(&glue,domain)) return DNS_MEM; - if (!stralloc_0(&glue)) return DNS_MEM; - if (!responsebuflen) - if (response.buf = (unsigned char *)alloc(PACKETSZ+1)) - responsebuflen = PACKETSZ+1; - else return DNS_MEM; - - responselen = lookup(glue.s,C_IN,type,response.buf,responsebuflen); - if ((responselen >= responsebuflen) || - (responselen > 0 && (((HEADER *)response.buf)->tc))) - { - if (responsebuflen < 65536) - if (alloc_re(&response.buf, responsebuflen, 65536)) - responsebuflen = 65536; - else return DNS_MEM; - saveresoptions = _res.options; - _res.options |= RES_USEVC; - responselen = lookup(glue.s,C_IN,type,response.buf,responsebuflen); - _res.options = saveresoptions; - } - if (responselen <= 0) - { - if (errno == ECONNREFUSED) return DNS_SOFT; - if (h_errno == TRY_AGAIN) return DNS_SOFT; - return DNS_HARD; - } - responseend = response.buf + responselen; - responsepos = response.buf + sizeof(HEADER); - n = ntohs(((HEADER *)response.buf)->qdcount); - while (n-- > 0) - { - i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); - if (i < 0) return DNS_SOFT; - responsepos += i; - i = responseend - responsepos; - if (i < QFIXEDSZ) return DNS_SOFT; - responsepos += QFIXEDSZ; + getdns_list *answers; + if (getdns_dict_get_list(response, "replies_tree", &answers) + != GETDNS_RETURN_GOOD) + return DNS_HARD; + + size_t num_answers, rec_ix, num_cb = 0; + getdns_list_get_length(answers, &num_answers); + for (rec_ix = 0; rec_ix < num_answers; ++rec_ix) { + getdns_dict *record; + getdns_list_get_dict(answers, rec_ix, &record); + + getdns_list *answer; + getdns_dict_get_list(record, "answer", &answer); + + size_t num_rr, rr_ix; + getdns_list_get_length(answer, &num_rr); + for (rr_ix = 0; rr_ix < num_rr; ++rr_ix) { + getdns_dict *rr, *rr_rdata; + uint32_t rr_type; + + getdns_list_get_dict(answer, rr_ix, &rr); + getdns_dict_get_int(rr, "type", &rr_type); + if (rr_type != type) + continue; + + if (cb_rr != NULL) + { + getdns_dict_get_dict(rr, "rdata", &rr_rdata); + int cb = cb_rr(response, rr_rdata, userarg); + if (cb != 0) + return cb; + } + ++num_cb; + } } - numanswers = ntohs(((HEADER *)response.buf)->ancount); - return 0; + + return num_cb; } -static int findname(wanttype) -int wanttype; +static int getdns_resolve(const char *name, uint16_t type, + int (*cb_rr)(getdns_dict *response, getdns_dict *rdata, void *userarg), + void *userarg) { - unsigned short rrtype; - unsigned short rrdlen; - int i; - - if (numanswers <= 0) return 2; - --numanswers; - if (responsepos == responseend) return DNS_SOFT; - - i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); - if (i < 0) return DNS_SOFT; - responsepos += i; - - i = responseend - responsepos; - if (i < 4 + 3 * 2) return DNS_SOFT; - - rrtype = getshort(responsepos); - rrdlen = getshort(responsepos + 8); - responsepos += 10; - - if (rrtype == wanttype) - { - if (dn_expand(response.buf,responseend,responsepos,name,MAXDNAME) < 0) - return DNS_SOFT; - responsepos += rrdlen; - return 1; - } - - responsepos += rrdlen; - return 0; + getdns_dict *response = NULL; + int r = getdns_resolve_query(name, type, &response); + r |= getdns_resolve_loop(response, type, cb_rr, userarg); + getdns_dict_destroy(response); + return r; } -static int findip(wanttype) -int wanttype; +static int getdns_resolve_num(getdns_dict *response, uint16_t type, size_t *num) { - unsigned short rrtype; - unsigned short rrdlen; - int i; - - if (numanswers <= 0) return 2; - --numanswers; - if (responsepos == responseend) return DNS_SOFT; - - i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); - if (i < 0) return DNS_SOFT; - responsepos += i; - - i = responseend - responsepos; - if (i < 4 + 3 * 2) return DNS_SOFT; - - rrtype = getshort(responsepos); - rrdlen = getshort(responsepos + 8); - responsepos += 10; - - if (rrtype == wanttype) - { - if (rrdlen < 4) - return DNS_SOFT; - ip.d[0] = responsepos[0]; - ip.d[1] = responsepos[1]; - ip.d[2] = responsepos[2]; - ip.d[3] = responsepos[3]; - responsepos += rrdlen; - return 1; - } - - responsepos += rrdlen; - return 0; + int r = getdns_resolve_loop(response, type, NULL, NULL); + if (r < 0) + return r; + *num = r; + return 0; } -static int findmx(wanttype) -int wanttype; +void dns_init(int flagsearch) { - unsigned short rrtype; - unsigned short rrdlen; - int i; - - if (numanswers <= 0) return 2; - --numanswers; - if (responsepos == responseend) return DNS_SOFT; - - i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); - if (i < 0) return DNS_SOFT; - responsepos += i; - - i = responseend - responsepos; - if (i < 4 + 3 * 2) return DNS_SOFT; - - rrtype = getshort(responsepos); - rrdlen = getshort(responsepos + 8); - responsepos += 10; - - if (rrtype == wanttype) - { - if (rrdlen < 3) - return DNS_SOFT; - pref = (responsepos[0] << 8) + responsepos[1]; - if (dn_expand(response.buf,responseend,responsepos + 2,name,MAXDNAME) < 0) - return DNS_SOFT; - responsepos += rrdlen; - return 1; - } - - responsepos += rrdlen; - return 0; + getdns_context_create(&context, 1); + getdns_context_set_resolution_type(context, GETDNS_RESOLUTION_STUB); + if (!flagsearch) + getdns_context_set_append_name(context, GETDNS_APPEND_NAME_NEVER); + else + fprintf(stderr, "not supported!\n"); //FIXME } -void dns_init(flagsearch) -int flagsearch; +static int dns_cname_cb(getdns_dict *response, getdns_dict *rdata, + void *userarg) { - res_init(); - if (flagsearch) lookup = res_search; + stralloc *sa = userarg; + + getdns_bindata *bindata = NULL; + if (getdns_dict_get_bindata(rdata, "cname", &bindata) + != GETDNS_RETURN_GOOD) + return DNS_SOFT; + + char *dname; + getdns_convert_dns_name_to_fqdn(bindata, &dname); + dname[strlen(dname) - 1] = '\0'; + if (!stralloc_copys(sa, dname)) { + free(dname); + return DNS_MEM; + } + free(dname); + return 0; } -int dns_cname(sa) -stralloc *sa; +int dns_cname(stralloc *sa) { - int r; - int loop; - for (loop = 0;loop < 10;++loop) + int loop; + for (loop = 0; loop < 10; ++loop) { - if (!sa->len) return loop; - if (sa->s[sa->len - 1] == ']') return loop; - if (sa->s[sa->len - 1] == '.') { --sa->len; continue; } - switch(resolve(sa,T_CNAME)) + if (!sa->len) + return loop; + if (sa->s[sa->len - 1] == ']') + return loop; + if (sa->s[sa->len - 1] == '.') { + --sa->len; + continue; + } + + if (!stralloc_0(sa)) + return DNS_MEM; + switch(getdns_resolve(sa->s, GETDNS_RRTYPE_CNAME, dns_cname_cb, sa)) { - case DNS_MEM: return DNS_MEM; - case DNS_SOFT: return DNS_SOFT; - case DNS_HARD: return loop; - default: - while ((r = findname(T_CNAME)) != 2) - { - if (r == DNS_SOFT) return DNS_SOFT; - if (r == 1) - { - if (!stralloc_copys(sa,name)) return DNS_MEM; - break; - } - } - if (r == 2) return loop; + case DNS_MEM: + return DNS_MEM; + case DNS_SOFT: + return DNS_SOFT; + case DNS_HARD: + case 0: + return loop; } } - return DNS_HARD; /* alias loop */ + return DNS_HARD; /* alias loop */ } -#define FMT_IAA 40 - -static int iaafmt(s,ip) -char *s; -struct ip_address *ip; +static int iaafmt(char *s, struct ip_address *ip) { - unsigned int i; - unsigned int len; - len = 0; - i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i; - i = fmt_str(s,"."); len += i; if (s) s += i; - i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i; - i = fmt_str(s,"."); len += i; if (s) s += i; - i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i; - i = fmt_str(s,"."); len += i; if (s) s += i; - i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i; - i = fmt_str(s,".in-addr.arpa."); len += i; if (s) s += i; - return len; + unsigned int i, len = 0; + i = fmt_ulong(s, (unsigned long) ip->d[3]); len += i; if (s) s += i; + i = fmt_str(s, "."); len += i; if (s) s += i; + i = fmt_ulong(s, (unsigned long) ip->d[2]); len += i; if (s) s += i; + i = fmt_str(s, "."); len += i; if (s) s += i; + i = fmt_ulong(s, (unsigned long) ip->d[1]); len += i; if (s) s += i; + i = fmt_str(s, "."); len += i; if (s) s += i; + i = fmt_ulong(s, (unsigned long) ip->d[0]); len += i; if (s) s += i; + i = fmt_str(s, ".in-addr.arpa."); len += i; if (s) s += i; + return len; } -int dns_ptr(sa,ip) -stralloc *sa; -struct ip_address *ip; +static int dns_ptr_cb(getdns_dict *response, getdns_dict *rdata, + void *userarg) { - int r; - - if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM; - sa->len = iaafmt(sa->s,ip); - switch(resolve(sa,T_PTR)) - { - case DNS_MEM: return DNS_MEM; - case DNS_SOFT: return DNS_SOFT; - case DNS_HARD: return DNS_HARD; - } - while ((r = findname(T_PTR)) != 2) - { - if (r == DNS_SOFT) return DNS_SOFT; - if (r == 1) - { - if (!stralloc_copys(sa,name)) return DNS_MEM; - return 0; - } + stralloc *sa = userarg; + + getdns_bindata *bindata = NULL; + if (getdns_dict_get_bindata(rdata, "rdata_raw", &bindata) + != GETDNS_RETURN_GOOD) + return DNS_SOFT; + + char *dname; + getdns_convert_dns_name_to_fqdn(bindata, &dname); + dname[strlen(dname) - 1] = '\0'; + if (!stralloc_copys(sa, dname)) { + free(dname); + return DNS_MEM; } - return DNS_HARD; + free(dname); + return 0; +} + +int dns_ptr(stralloc *sa, struct ip_address *ip) +{ + if (!stralloc_ready(sa, iaafmt((char *)0, ip))) + return DNS_MEM; + sa->len = iaafmt(sa->s, ip); + if (!stralloc_0(sa)) + return DNS_MEM; + + int num = getdns_resolve(sa->s, GETDNS_RRTYPE_PTR, dns_ptr_cb, sa); + return (num < 0) ? num : 0; } -static int dns_ipplus(ia,sa,pref) -ipalloc *ia; -stralloc *sa; -int pref; +struct dns_ipplus_user { + ipalloc *ia; +#ifdef IX_FQDN + char *fqdn; +#endif + int pref; +}; + +static int dns_ipplus_cb(getdns_dict *response, getdns_dict *rdata, + void *userarg) { - int r; - struct ip_mx ix = {0}; + struct dns_ipplus_user *u = userarg; + struct ip_mx ix = {0}; + + getdns_bindata *bindata = NULL; + if (getdns_dict_get_bindata(rdata, "ipv4_address", &bindata) + != GETDNS_RETURN_GOOD) + return DNS_SOFT; + + memcpy(ix.ip.d, bindata->data, 4); + ix.pref = u->pref; +#ifdef IX_FQDN + ix.fqdn = u->fqdn; +#endif + if (!ipalloc_append(u->ia, &ix)) + return DNS_MEM; + + return 0; +} - if (!stralloc_copy(&glue,sa)) return DNS_MEM; - if (!stralloc_0(&glue)) return DNS_MEM; - if (glue.s[0]) { - if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) +static int dns_ipplus(ipalloc *ia, stralloc *sa, int pref) +{ + struct ip_mx ix = {0}; + + if (!stralloc_copy(&glue, sa)) + return DNS_MEM; + if (!stralloc_0(&glue)) + return DNS_MEM; + if (glue.s[0]) { + if (!glue.s[ip_scan(glue.s, &ix.ip)] || !glue.s[ip_scanbracket(glue.s, &ix.ip)]) { - if (!ipalloc_append(ia,&ix)) return DNS_MEM; - return 0; + if (!ipalloc_append(ia,&ix)) + return DNS_MEM; + return 0; } - } - - switch(resolve(sa,T_A)) - { - case DNS_MEM: return DNS_MEM; - case DNS_SOFT: return DNS_SOFT; - case DNS_HARD: return DNS_HARD; } - while ((r = findip(T_A)) != 2) - { - ix.ip = ip; - ix.pref = pref; - if (r == DNS_SOFT) return DNS_SOFT; - if (r == 1) { + + struct dns_ipplus_user u = { + .ia = ia, #ifdef IX_FQDN - ix.fqdn = glue.s; + .fqdn = glue.s, #endif - if (!ipalloc_append(ia,&ix)) return DNS_MEM; - } - } + .pref = pref, + }; + int num = getdns_resolve(glue.s, GETDNS_RRTYPE_A, dns_ipplus_cb, &u); #ifdef IX_FQDN - glue.s = 0; + glue.s = 0; #endif - return 0; + if (num == 0) + num = DNS_HARD; + return (num < 0) ? num : 0; } -int dns_ip(ia,sa) -ipalloc *ia; -stralloc *sa; +int dns_ip(ipalloc *ia, stralloc *sa) { - if (!ipalloc_readyplus(ia,0)) return DNS_MEM; - ia->len = 0; - return dns_ipplus(ia,sa,0); + if (!ipalloc_readyplus(ia, 0)) + return DNS_MEM; + ia->len = 0; + return dns_ipplus(ia, sa, 0); } -int dns_mxip(ia,sa,random) -ipalloc *ia; -stralloc *sa; -unsigned long random; +struct dns_mxip_user { + unsigned num; + struct mx_user { + stralloc sa; + unsigned short p; + } *mx; +}; + +static int dns_mxip_cb(getdns_dict *response, getdns_dict *rdata, + void *userarg) { - int r; - struct mx { stralloc sa; unsigned short p; } *mx; - struct ip_mx ix = {0}; - int nummx; - int i; - int j; - int flagsoft; - - if (!ipalloc_readyplus(ia,0)) return DNS_MEM; - ia->len = 0; - - if (!stralloc_copy(&glue,sa)) return DNS_MEM; - if (!stralloc_0(&glue)) return DNS_MEM; - if (glue.s[0]) { - if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) - { - if (!ipalloc_append(ia,&ix)) return DNS_MEM; - return 0; - } - } + struct dns_mxip_user *mx = userarg; - switch(resolve(sa,T_MX)) - { - case DNS_MEM: return DNS_MEM; - case DNS_SOFT: return DNS_SOFT; - case DNS_HARD: return dns_ip(ia,sa); - } + getdns_bindata *bindata = NULL; + if (getdns_dict_get_bindata(rdata, "exchange", &bindata) + != GETDNS_RETURN_GOOD) + return DNS_SOFT; - mx = (struct mx *) alloc(numanswers * sizeof(struct mx)); - if (!mx) return DNS_MEM; - nummx = 0; + char *dname; + getdns_convert_dns_name_to_fqdn(bindata, &dname); + dname[strlen(dname) - 1] = '\0'; - while ((r = findmx(T_MX)) != 2) + uint32_t pref; + getdns_dict_get_int(rdata, "preference", &pref); + + mx->mx[mx->num].p = pref; + mx->mx[mx->num].sa.s = 0; + if (!stralloc_copys(&mx->mx[mx->num].sa, dname)) { - if (r == DNS_SOFT) { alloc_free(mx); return DNS_SOFT; } - if (r == 1) + free(dname); + return DNS_MEM; + } + mx->num++; + free(dname); + return 0; +} + +int dns_mxip(ipalloc *ia, stralloc *sa, unsigned long random) +{ + struct ip_mx ix = {0}; + + if (!ipalloc_readyplus(ia, 0)) + return DNS_MEM; + ia->len = 0; + + if (!stralloc_copy(&glue, sa)) + return DNS_MEM; + if (!stralloc_0(&glue)) + return DNS_MEM; + if (glue.s[0]) { + if (!glue.s[ip_scan(glue.s, &ix.ip)] || !glue.s[ip_scanbracket(glue.s, &ix.ip)]) { - mx[nummx].p = pref; - mx[nummx].sa.s = 0; - if (!stralloc_copys(&mx[nummx].sa,name)) - { - while (nummx > 0) alloc_free(mx[--nummx].sa.s); - alloc_free(mx); return DNS_MEM; - } - ++nummx; + if (!ipalloc_append(ia,&ix)) + return DNS_MEM; + return 0; } } - if (!nummx) return dns_ip(ia,sa); /* e.g., CNAME -> A */ + getdns_dict *response = NULL; + size_t num_rr = 0; + int ret = getdns_resolve_query(glue.s, GETDNS_RRTYPE_MX, &response); + ret |= getdns_resolve_num(response, GETDNS_RRTYPE_MX, &num_rr); + if (ret != 0 || num_rr == 0) { + getdns_dict_destroy(response); + return (ret != 0) ? ret : dns_ip(ia, sa); /* e.g., CNAME -> A */ + } + + struct dns_mxip_user mx = { + .num = 0, + .mx = (struct mx_user*)alloc(num_rr * sizeof(struct mx_user)), + }; + if (!mx.mx) + return DNS_MEM; + ret = getdns_resolve_loop(response, GETDNS_RRTYPE_MX, dns_mxip_cb, &mx); + if (ret < 0) + { + while (mx.num > 0) + alloc_free(mx.mx[--mx.num].sa.s); + alloc_free(mx.mx); + getdns_dict_destroy(response); + return ret; + } + getdns_dict_destroy(response); - flagsoft = 0; - while (nummx > 0) + int flagsoft = 0; + while (mx.num > 0) { - unsigned long numsame; + int i, j; + unsigned long numsame = 1; - i = 0; - numsame = 1; - for (j = 1;j < nummx;++j) - if (mx[j].p < mx[i].p) + i = 0; + for (j = 1; j < mx.num; ++j) { + if (mx.mx[j].p < mx.mx[i].p) { - i = j; - numsame = 1; + i = j; + numsame = 1; } - else if (mx[j].p == mx[i].p) + else if (mx.mx[j].p == mx.mx[i].p) { - ++numsame; - random = random * 69069 + 1; - if ((random / 2) < (2147483647 / numsame)) - i = j; + ++numsame; + random = random * 69069 + 1; + if ((random / 2) < (2147483647 / numsame)) + i = j; } + } - switch(dns_ipplus(ia,&mx[i].sa,mx[i].p)) + switch(dns_ipplus(ia, &mx.mx[i].sa, mx.mx[i].p)) { - case DNS_MEM: case DNS_SOFT: - flagsoft = 1; break; + case DNS_MEM: + case DNS_SOFT: + flagsoft = 1; + break; } - alloc_free(mx[i].sa.s); - mx[i] = mx[--nummx]; + alloc_free(mx.mx[i].sa.s); + mx.mx[i] = mx.mx[--mx.num]; } - alloc_free(mx); - return flagsoft; + alloc_free(mx.mx); + return flagsoft; } -- cgit v1.2.3