summaryrefslogtreecommitdiff
path: root/src/types.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/types.c')
-rw-r--r--src/types.c413
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=