diff options
Diffstat (limited to 'src/types.c')
-rw-r--r-- | src/types.c | 413 |
1 files changed, 336 insertions, 77 deletions
diff --git a/src/types.c b/src/types.c index 36ff879..bed890a 100644 --- a/src/types.c +++ b/src/types.c @@ -48,12 +48,15 @@ * _manyistr (mf,cs) * _txt (pa) * _inaddr (pa,dip,di) - * _addr (pa,di,csp,cs) + * _in6addr (pa,cs) + * _addr (sh,di,csp,cs) * _domain (pap) * _host_raw (pa) * _hostaddr (pap,pa,dip,di,mfp,mf,csp,cs +pap_findaddrs) * _mx_raw (pa,di) * _mx (pa,di) + * _srv_raw (pa,di,mf,cs) + * _srv (pa,di,mf,cs) * _inthostaddr (mf,cs) * _ptr (pa) * _strpair (mf,cs) @@ -251,14 +254,20 @@ static adns_status pa_inaddr(const parseinfo *pai, int cbyte, return adns_s_ok; } -static int search_sortlist(adns_state ads, struct in_addr ad) { +static int search_sortlist_in(adns_state ads, struct in_addr ad) { const struct sortlist *slp; int i; for (i=0, slp=ads->sortlist; - i<ads->nsortlist && - !((ad.s_addr & slp->mask.s_addr) == slp->base.s_addr); - i++, slp++); + i<ads->nsortlist; + i++, slp++) { + if (slp->family == AF_INET) { + struct in_addr mask; + mask.s_addr = htonl(-1 << slp->prefix); + if ( (ad.s_addr & mask.s_addr ) == slp->base.inet.s_addr) + break; + } + } return i; } @@ -267,8 +276,8 @@ static int dip_inaddr(adns_state ads, struct in_addr a, struct in_addr b) { if (!ads->nsortlist) return 0; - ai= search_sortlist(ads,a); - bi= search_sortlist(ads,b); + ai= search_sortlist_in(ads,a); + bi= search_sortlist_in(ads,b); return bi<ai; } @@ -289,27 +298,297 @@ static adns_status cs_inaddr(vbuf *vb, const void *datap) { } /* - * _addr (pa,di,csp,cs) + * _in6addr (pa,dip,di) */ -static adns_status pa_addr(const parseinfo *pai, int cbyte, +static adns_status pa_in6addr(const parseinfo *pai, int cbyte, int max, void *datap) { - adns_rr_addr *storeto= datap; + struct in_addr *storeto= datap; + + if (max-cbyte != 16) return adns_s_invaliddata; + memcpy(storeto, pai->dgram + cbyte, 16); + return adns_s_ok; +} + +static int search_sortlist_in6(adns_state ads, const struct in6_addr *ad) { + const struct sortlist *slp; + int i; + + for (i=0, slp=ads->sortlist; + i<ads->nsortlist; + i++, slp++) { + if (slp->family == AF_INET6) { + int pb = slp->prefix / 8; + int mask = 0xff & (-1 << (slp->prefix % 8)); + if (memcmp(ad->s6_addr, slp->base.inet6.s6_addr, pb) == 0 + && (!mask + || (ad->s6_addr[pb] & mask) == slp->base.inet6.s6_addr[pb])) + break; + } + } + return i; +} + +static int dip_in6addr(adns_state ads, + const struct in6_addr *a, const struct in6_addr *b) { + int ai, bi; + + if (!ads->nsortlist) return 0; + + ai= search_sortlist_in6(ads,a); + bi= search_sortlist_in6(ads,b); + return bi<ai; +} + +static int di_in6addr(adns_state ads, + const void *datap_a, const void *datap_b) { + const struct in6_addr *ap= datap_a, *bp= datap_b; + + return dip_in6addr(ads,ap,bp); +} + + +static adns_status cs_in6addr(vbuf *vb, const void *datap) { + char buf[INET6_ADDRSTRLEN]; + const char *ia; + + ia= inet_ntop(AF_INET6, datap, buf, sizeof(buf)); assert(ia); + CSP_ADDSTR(ia); + return adns_s_ok; +} + +/* + * _addr (sh,pa,di,csp,cs) + */ + +static void mk_mapped_ipv6(struct sockaddr_in6 *sa, const struct in_addr *in) { + memset(sa, 0, sizeof(*sa)); + sa->sin6_family = AF_INET6; + sa->sin6_addr.s6_addr16[5] = 0xffff; + sa->sin6_addr.s6_addr32[3] = in->s_addr; +} + +static void icb_addr(adns_query parent, adns_query child) { + adns_answer *cans= child->answer; + adns_answer *pans= parent->answer; + adns_state ads= parent->ads; + adns_rr_addr *addr; + + int i; + + if (parent->expires > child->expires) parent->expires = child->expires; + + if (cans->status == adns_s_nxdomain) { + adns__query_fail(parent,cans->status); + return; + } + if (cans->status == adns_s_nodata && parent->children.head) { + /* We may get records from the remaining queries */ + LIST_LINK_TAIL(ads->childw,parent); + return; + } + if (cans->status) { + if (pans->nrrs) + adns__query_done(parent); + else + adns__query_fail(parent,cans->status); + return; + } + + assert(cans->nrrs); + + /* Copy CNAME. CNAME must be consistent for both queries. */ + if (cans->cname && pans->cname) { + if (strcmp(cans->cname, pans->cname)) { + adns__query_fail(parent, adns_s_inconsistent); + return; + } + } + else if (pans->cname) { + adns__query_fail(parent, adns_s_inconsistent); + return; + } + else if (cans->cname) { + size_t len; + if (pans->nrrs) { + adns__query_fail(parent, adns_s_inconsistent); + return; + } + len = strlen(cans->cname) + 1; + pans->cname = adns__alloc_preserved(parent, len); + if (!pans->cname) { + adns__query_fail(parent, adns_s_nomemory); + return; + } + memcpy(pans->cname, cans->cname, len); + } + if (pans->nrrs) + { + void *p = adns__realloc_interim(parent,pans->rrs.untyped, + sizeof(adns_rr_addr) * (cans->nrrs + pans->nrrs)); + if (!p) { + adns__query_fail(parent, adns_s_nomemory); + return; + } + pans->rrs.untyped = p; + addr = pans->rrs.addr + pans->nrrs; + pans->nrrs += cans->nrrs; + } + else { + pans->rrs.untyped + = adns__alloc_interim(parent,sizeof(adns_rr_addr) * cans->nrrs); + if (!pans->rrs.untyped) { + adns__query_fail(parent,adns_s_nomemory); + return; + } + pans->nrrs = cans->nrrs; + addr = pans->rrs.addr; + } + + switch (cans->type) { + default: abort(); + case adns_r_a: + if (parent->flags & adns_qf_ip6mapped) + for (i = 0; i<cans->nrrs; i++) { + addr[i].len = sizeof(struct sockaddr_in6); + mk_mapped_ipv6(&addr[i].addr.inet6, &cans->rrs.inaddr[i]); + } + else + for (i = 0; i<cans->nrrs; i++) { + addr[i].len = sizeof(struct sockaddr_in); + memset(&addr[i].addr.inet, 0, sizeof(addr[i].addr.inet)); + addr[i].addr.inet.sin_family = AF_INET; + addr[i].addr.inet.sin_addr = cans->rrs.inaddr[i]; + } + break; + case adns_r_aaaa: + for (i = 0; i<cans->nrrs; i++) { + addr[i].len = sizeof(struct sockaddr_in6); + memset(&addr[i].addr.inet6, 0, sizeof(addr[i].addr.inet6)); + addr[i].addr.inet6.sin6_family = AF_INET6; + addr[i].addr.inet6.sin6_addr = cans->rrs.in6addr[i]; + } + break; + } + + if (!parent->children.head) { + adns__query_done(parent); + return; + } else { + LIST_LINK_TAIL(ads->childw,parent); + return; + } +} + +static void sh_addr(adns_query qu, + adns_queryflags flags, struct timeval now) +{ + adns_status st; + int id; + qcontext ctx; + adns_query nqu; + vbuf vb; + + assert(flags & adns__qf_ip_mask); + + /* Must have a non-negative id, or else adns__internal_check will + * think that we are on the output queue. */ + qu->id = 0; + + ctx.ext= 0; + ctx.callback= icb_addr; + /* What to store in ctx.info? */ + + adns__vbuf_init(&vb); + + if (flags & adns_qf_ip4) { /* A query */ + st= adns__mkquery_frlabels(qu->ads, &vb, &id, + qu->vb.buf, qu->vb.used, adns_r_a, flags); + if (st) { adns__query_fail(qu, st); return; } + + st= adns__internal_submit(qu->ads, &nqu, adns__findtype(adns_r_a), + &vb, id, flags, now, &ctx); + if (st) { adns__query_fail(qu, st); return; } + + nqu->parent = qu; + LIST_LINK_TAIL_PART(qu->children,nqu,siblings.); + } + + if (flags & adns_qf_ip6) { /* AAAA query */ + st= adns__mkquery_frlabels(qu->ads, &vb, &id, + qu->vb.buf, qu->vb.used, adns_r_aaaa, flags); + if (st) { adns__query_fail(qu, st); return; } + + st= adns__internal_submit(qu->ads, &nqu, adns__findtype(adns_r_aaaa), + &vb, id, flags, now, &ctx); + if (st) { adns__query_fail(qu, st); return; } + + nqu->parent = qu; + LIST_LINK_TAIL_PART(qu->children,nqu,siblings.); + } + assert(qu->children.head); +} + +static adns_status pap_addr(const parseinfo *pai, adns_rrtype type, int cbyte, + int max, adns_rr_addr *rr) { + const byte *dgram= pai->dgram; + adns_queryflags flags = pai->qu->flags; + + switch (type) + { + default: abort(); + case adns_r_a: + assert(flags & adns_qf_ip4); if (max-cbyte != 4) return adns_s_invaliddata; - storeto->len= sizeof(storeto->addr.inet); - memset(&storeto->addr,0,sizeof(storeto->addr.inet)); - storeto->addr.inet.sin_family= AF_INET; - memcpy(&storeto->addr.inet.sin_addr,dgram+cbyte,4); + + if (flags & adns_qf_ip6mapped) { + rr->len = sizeof(struct sockaddr_in6); + mk_mapped_ipv6(&rr->addr.inet6, (const struct in_addr *) (dgram+cbyte)); + } + else { + rr->len= sizeof(rr->addr.inet); + memset(&rr->addr.inet,0,sizeof(rr->addr.inet)); + rr->addr.inet.sin_family= AF_INET; + memcpy(&rr->addr.inet.sin_addr,dgram+cbyte,4); + } + break; + case adns_r_aaaa: + assert(flags & adns_qf_ip6); + + if (max-cbyte != 16) return adns_s_invaliddata; + + rr->len= sizeof(rr->addr.inet6); + memset(&rr->addr,0,sizeof(rr->addr.inet6)); + rr->addr.inet6.sin6_family= AF_INET6; + memcpy(&rr->addr.inet6.sin6_addr,dgram+cbyte,16); + + break; + } + return adns_s_ok; } +static int search_sortlist_addr(adns_state ads, const adns_rr_addr *ad) { + switch(ad->addr.sa.sa_family) { + default: abort(); + case AF_INET: return search_sortlist_in(ads, ad->addr.inet.sin_addr); + case AF_INET6: return search_sortlist_in6(ads, &ad->addr.inet6.sin6_addr); + } +} + +static int dip_addr(adns_state ads, + const adns_rr_addr *a, const adns_rr_addr *b) { + int ai, bi; + ai = search_sortlist_addr(ads, a); + bi = search_sortlist_addr(ads, b); + return bi<ai; +} + static int di_addr(adns_state ads, const void *datap_a, const void *datap_b) { const adns_rr_addr *ap= datap_a, *bp= datap_b; - - assert(ap->addr.sa.sa_family == AF_INET); - return dip_inaddr(ads, ap->addr.inet.sin_addr, bp->addr.inet.sin_addr); + return dip_addr(ads, ap, bp); } static int div_addr(void *context, const void *datap_a, const void *datap_b) { @@ -320,7 +599,7 @@ static int div_addr(void *context, const void *datap_a, const void *datap_b) { static adns_status csp_addr(vbuf *vb, const adns_rr_addr *rrp) { const char *ia; - char buf[30]; + char buf[INET6_ADDRSTRLEN]; switch (rrp->addr.inet.sin_family) { case AF_INET: @@ -328,6 +607,12 @@ static adns_status csp_addr(vbuf *vb, const adns_rr_addr *rrp) { ia= inet_ntoa(rrp->addr.inet.sin_addr); assert(ia); CSP_ADDSTR(ia); break; + case AF_INET6: + CSP_ADDSTR("INET6 "); + ia= inet_ntop(AF_INET6, &rrp->addr.inet6.sin6_addr, + buf, sizeof(buf)); assert(ia); + CSP_ADDSTR(ia); + break; default: sprintf(buf,"AF=%u",rrp->addr.sa.sa_family); CSP_ADDSTR(buf); @@ -424,17 +709,22 @@ static adns_status pap_findaddrs(const parseinfo *pai, adns_rr_hostaddr *ha, &type, &class, &ttl, &rdlen, &rdstart, pai->dgram, pai->dglen, dmstart, &ownermatched); if (st) return st; - if (!ownermatched || class != DNS_CLASS_IN || type != adns_r_a) { + if (!ownermatched || class != DNS_CLASS_IN) { + if (naddrs>0) break; else continue; + } + if (! ((type == adns_r_a && (pai->qu->flags & adns_qf_ip4)) + || (type == adns_r_aaaa && (pai->qu->flags & adns_qf_ip6)))) { if (naddrs>0) break; else continue; } + if (naddrs == -1) { naddrs= 0; } if (!adns__vbuf_ensure(&pai->qu->vb, (naddrs+1)*sizeof(adns_rr_addr))) R_NOMEM; adns__update_expires(pai->qu,ttl,pai->now); - st= pa_addr(pai, rdstart,rdstart+rdlen, - pai->qu->vb.buf + naddrs*sizeof(adns_rr_addr)); + st= pap_addr(pai, type, rdstart,rdstart+rdlen, + (adns_rr_addr *) pai->qu->vb.buf + naddrs); if (st) return st; naddrs++; } @@ -476,7 +766,6 @@ static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io, adns_status st; int dmstart, cbyte; qcontext ctx; - int id; adns_query nqu; adns_queryflags nflags; @@ -500,9 +789,8 @@ static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io, if (st) return st; if (rrp->naddrs != -1) return adns_s_ok; - st= adns__mkquery_frdgram(pai->ads, &pai->qu->vb, &id, - pai->dgram, pai->dglen, dmstart, - adns_r_addr, adns_qf_quoteok_query); + st= adns__mkquery_labels_frdgram(pai->ads, &pai->qu->vb, + pai->dgram, pai->dglen, dmstart); if (st) return st; ctx.ext= 0; @@ -513,7 +801,7 @@ static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io, if (!(pai->qu->flags & adns_qf_cname_loose)) nflags |= adns_qf_cname_forbid; st= adns__internal_submit(pai->ads, &nqu, adns__findtype(adns_r_addr), - &pai->qu->vb, id, nflags, pai->now, &ctx); + &pai->qu->vb, 0, nflags, pai->now, &ctx); if (st) return st; nqu->parent= pai->qu; @@ -539,11 +827,7 @@ static int dip_hostaddr(adns_state ads, if (ap->astatus != bp->astatus) return ap->astatus; if (ap->astatus) return 0; - assert(ap->addrs[0].addr.sa.sa_family == AF_INET); - assert(bp->addrs[0].addr.sa.sa_family == AF_INET); - return dip_inaddr(ads, - ap->addrs[0].addr.inet.sin_addr, - bp->addrs[0].addr.inet.sin_addr); + return dip_addr(ads, &ap->addrs[0], &bp->addrs[0]); } static int di_hostaddr(adns_state ads, @@ -717,7 +1001,7 @@ static void icb_ptr(adns_query parent, adns_query child) { return; } - queried= &parent->ctx.info.ptr_parent_addr; + queried= &parent->extra.info.ptr_addr; for (i=0, found=cans->rrs.addr; i<cans->nrrs; i++, found++) { if (queried->len == found->len && !memcmp(&queried->addr,&found->addr,queried->len)) { @@ -734,18 +1018,14 @@ static void icb_ptr(adns_query parent, adns_query child) { adns__query_fail(parent,adns_s_inconsistent); } +/* FIXME: Completely different in adns-1.4. */ static adns_status pa_ptr(const parseinfo *pai, int dmstart, int max, void *datap) { static const char *const (expectdomain[])= { DNS_INADDR_ARPA }; char **rrp= datap; adns_status st; - adns_rr_addr *ap; - findlabel_state fls; - char *ep; - byte ipv[4]; - char labbuf[4]; - int cbyte, i, lablen, labstart, l, id; + int cbyte; adns_query nqu; qcontext ctx; @@ -755,48 +1035,20 @@ static adns_status pa_ptr(const parseinfo *pai, int dmstart, if (st) return st; if (cbyte != max) return adns_s_invaliddata; - ap= &pai->qu->ctx.info.ptr_parent_addr; - if (!ap->len) { - adns__findlabel_start(&fls, pai->ads, -1, pai->qu, - pai->qu->query_dgram, pai->qu->query_dglen, - pai->qu->query_dglen, DNS_HDRSIZE, 0); - for (i=0; i<4; i++) { - st= adns__findlabel_next(&fls,&lablen,&labstart); assert(!st); - if (lablen<=0 || lablen>3) return adns_s_querydomainwrong; - memcpy(labbuf, pai->qu->query_dgram + labstart, lablen); - labbuf[lablen]= 0; - ipv[3-i]= strtoul(labbuf,&ep,10); - if (*ep) return adns_s_querydomainwrong; - if (lablen>1 && pai->qu->query_dgram[labstart]=='0') - return adns_s_querydomainwrong; - } - for (i=0; i<sizeof(expectdomain)/sizeof(*expectdomain); i++) { - st= adns__findlabel_next(&fls,&lablen,&labstart); assert(!st); - l= strlen(expectdomain[i]); - if (lablen != l || - memcmp(pai->qu->query_dgram + labstart, expectdomain[i], l)) - return adns_s_querydomainwrong; - } - st= adns__findlabel_next(&fls,&lablen,0); assert(!st); - if (lablen) return adns_s_querydomainwrong; - - ap->len= sizeof(struct sockaddr_in); - memset(&ap->addr,0,sizeof(ap->addr.inet)); - ap->addr.inet.sin_family= AF_INET; - ap->addr.inet.sin_addr.s_addr= - htonl((ipv[0]<<24) | (ipv[1]<<16) | (ipv[2]<<8) | (ipv[3])); - } + /* Should be initialized by adns_submit_reverse. If it's not, we + * can't do any consistency checking. */ + if (!pai->qu->extra.info.ptr_addr.len) return adns_s_ok; - st= adns__mkquery_frdgram(pai->ads, &pai->qu->vb, &id, - pai->dgram, pai->dglen, dmstart, - adns_r_addr, adns_qf_quoteok_query); + pai->qu->vb.used = 0; + st= adns__mkquery_labels_frdgram(pai->ads, &pai->qu->vb, + pai->dgram, pai->dglen, dmstart); if (st) return st; ctx.ext= 0; ctx.callback= icb_ptr; memset(&ctx.info,0,sizeof(ctx.info)); st= adns__internal_submit(pai->ads, &nqu, adns__findtype(adns_r_addr), - &pai->qu->vb, id, + &pai->qu->vb, 0, adns_qf_quoteok_query, pai->now, &ctx); if (st) return st; @@ -1250,13 +1502,16 @@ static void mf_flat(adns_query qu, void *data) { } #define DEEP_TYPE(code,rrt,fmt,memb,parser,comparer,printer) \ { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_##memb, \ - printer,parser,comparer, adns__qdpl_normal,0 } + printer,0,parser,comparer, adns__qdpl_normal,0 } #define FLAT_TYPE(code,rrt,fmt,memb,parser,comparer,printer) \ { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_flat, \ - printer,parser,comparer, adns__qdpl_normal,0 } + printer,0,parser,comparer, adns__qdpl_normal,0 } #define XTRA_TYPE(code,rrt,fmt,memb,parser,comparer,printer,qdpl,postsort) \ { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_##memb, \ - printer,parser,comparer,qdpl,postsort } + printer,0,parser,comparer,qdpl,postsort } +#define SPECIAL_TYPE(code,rrt,fmt,memb,submit,comparer,printer) \ + { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_flat, \ + printer,submit,0,comparer, adns__qdpl_normal,0 } static const typeinfo typeinfos[] = { /* Must be in ascending order of rrtype ! */ @@ -1271,10 +1526,11 @@ DEEP_TYPE(hinfo, "HINFO", 0, intstrpair,pa_hinfo, 0, cs_hinfo ), DEEP_TYPE(mx_raw, "MX", "raw",intstr, pa_mx_raw, di_mx_raw,cs_inthost ), DEEP_TYPE(txt, "TXT", 0, manyistr,pa_txt, 0, cs_txt ), DEEP_TYPE(rp_raw, "RP", "raw",strpair, pa_rp, 0, cs_rp ), +FLAT_TYPE(aaaa, "AAAA", 0, in6addr, pa_in6addr, di_in6addr, cs_in6addr ), XTRA_TYPE(srv_raw,"SRV", "raw",srvraw , pa_srvraw, di_srv, cs_srvraw, qdpl_srv, postsort_srv), -FLAT_TYPE(addr, "A", "addr", addr, pa_addr, di_addr, cs_addr ), +/* adns__qtf_deref set */ DEEP_TYPE(ns, "NS", "+addr",hostaddr,pa_hostaddr,di_hostaddr,cs_hostaddr ), DEEP_TYPE(ptr, "PTR","checked",str, pa_ptr, 0, cs_domain ), DEEP_TYPE(mx, "MX", "+addr",inthostaddr,pa_mx, di_mx, cs_inthostaddr), @@ -1283,6 +1539,9 @@ XTRA_TYPE(srv, "SRV","+addr",srvha, pa_srvha, di_srv, cs_srvha, DEEP_TYPE(soa, "SOA","822", soa, pa_soa, 0, cs_soa ), DEEP_TYPE(rp, "RP", "822", strpair, pa_rp, 0, cs_rp ), + +/* adns__qtf_special set */ +SPECIAL_TYPE(addr,"<A+AAAA>", "addr",addr,sh_addr, di_addr, cs_addr ), }; static const typeinfo typeinfo_unknown= |