X-Git-Url: https://git.distorted.org.uk/~mdw/adns/blobdiff_plain/ab898cf443c0302e801234d8df345e7eb8e8c06f..37883323b39ceb0f98d0960c33c57f1d9cdf4ce9:/src/query.c diff --git a/src/query.c b/src/query.c index b9e6d4d..8944b2f 100644 --- a/src/query.c +++ b/src/query.c @@ -5,12 +5,11 @@ * - query submission and cancellation (user-visible and internal) */ /* - * This file is - * Copyright (C) 1997-1999 Ian Jackson - * - * It is part of adns, which is - * Copyright (C) 1997-1999 Ian Jackson - * Copyright (C) 1999 Tony Finch + * This file is part of adns, which is + * Copyright (C) 1997-2000,2003,2006 Ian Jackson + * Copyright (C) 1999-2000,2003,2006 Tony Finch + * Copyright (C) 1991 Massachusetts Institute of Technology + * (See the file INSTALL for full details.) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,13 +36,15 @@ #include "internal.h" -static adns_query query_alloc(adns_state ads, const typeinfo *typei, +static adns_query query_alloc(adns_state ads, + const typeinfo *typei, adns_rrtype type, adns_queryflags flags, struct timeval now) { /* Allocate a virgin query and return it. */ adns_query qu; qu= malloc(sizeof(*qu)); if (!qu) return 0; - qu->answer= malloc(sizeof(*qu->answer)); if (!qu->answer) { free(qu); return 0; } + qu->answer= malloc(sizeof(*qu->answer)); + if (!qu->answer) { free(qu); return 0; } qu->ads= ads; qu->state= query_tosend; @@ -66,11 +67,11 @@ static adns_query query_alloc(adns_state ads, const typeinfo *typei, adns__vbuf_init(&qu->search_vb); qu->search_origlen= qu->search_pos= qu->search_doneabs= 0; - qu->id= 0; + qu->id= -2; /* will be overwritten with real id before we leave adns */ qu->flags= flags; - qu->udpretries= 0; + qu->retries= 0; qu->udpnextserver= 0; - qu->udpsent= qu->tcpfailed= 0; + qu->udpsent= 0; timerclear(&qu->timeout); qu->expires= now.tv_sec + MAXTTLBELIEVE; @@ -78,7 +79,7 @@ static adns_query query_alloc(adns_state ads, const typeinfo *typei, qu->answer->status= adns_s_ok; qu->answer->cname= qu->answer->owner= 0; - qu->answer->type= typei->type; + qu->answer->type= type; qu->answer->expires= -1; qu->answer->nrrs= 0; qu->answer->rrs.untyped= 0; @@ -91,7 +92,7 @@ static void query_submit(adns_state ads, adns_query qu, const typeinfo *typei, vbuf *qumsg_vb, int id, adns_queryflags flags, struct timeval now) { /* Fills in the query message in for a previously-allocated query, - * and submits it. Cannot fail. + * and submits it. Cannot fail. Takes over the memory for qumsg_vb. */ qu->vb= *qumsg_vb; @@ -103,17 +104,23 @@ static void query_submit(adns_state ads, adns_query qu, qu->id= id; qu->query_dglen= qu->vb.used; memcpy(qu->query_dgram,qu->vb.buf,qu->vb.used); - - adns__query_send(qu,now); + + if (flags & adns__qf_nosend) + ; + else if (typei->query_send && !(flags & adns__qf_senddirect)) + typei->query_send(qu,now); + else + adns__query_send(qu, now); } adns_status adns__internal_submit(adns_state ads, adns_query *query_r, - const typeinfo *typei, vbuf *qumsg_vb, int id, + const typeinfo *typei, adns_rrtype type, + vbuf *qumsg_vb, int id, adns_queryflags flags, struct timeval now, const qcontext *ctx) { adns_query qu; - qu= query_alloc(ads,typei,flags,now); + qu= query_alloc(ads,typei,type,flags & ~adns__qf_nosend,now); if (!qu) { adns__vbuf_free(qumsg_vb); return adns_s_nomemory; } *query_r= qu; @@ -127,16 +134,25 @@ static void query_simple(adns_state ads, adns_query qu, const char *owner, int ol, const typeinfo *typei, adns_queryflags flags, struct timeval now) { - vbuf vb; + vbuf vb_new; int id; adns_status stat; - adns__vbuf_init(&vb); - - stat= adns__mkquery(ads,&vb,&id, owner,ol, typei,flags); - if (stat) { adns__query_fail(qu,stat); return; } + stat= adns__mkquery(ads,&qu->vb,&id, owner,ol, + typei,qu->answer->type, flags); + if (stat) { + if (stat == adns_s_querydomaintoolong && (flags & adns_qf_search)) { + adns__search_next(ads,qu,now); + return; + } else { + adns__query_fail(qu,stat); + return; + } + } - query_submit(ads,qu, typei,&vb,id, flags,now); + vb_new= qu->vb; + adns__vbuf_init(&qu->vb); + query_submit(ads,qu, typei,&vb_new,id, flags,now); } void adns__search_next(adns_state ads, adns_query qu, struct timeval now) { @@ -149,8 +165,8 @@ void adns__search_next(adns_state ads, adns_query qu, struct timeval now) { } else { if (qu->search_pos >= ads->nsearchlist) { if (qu->search_doneabs) { + qu->search_vb.used= qu->search_origlen; stat= adns_s_nxdomain; goto x_fail; - return; } else { nextentry= 0; qu->search_doneabs= 1; @@ -163,17 +179,19 @@ void adns__search_next(adns_state ads, adns_query qu, struct timeval now) { qu->search_vb.used= qu->search_origlen; if (nextentry) { if (!adns__vbuf_append(&qu->search_vb,".",1) || - !adns__vbuf_appendstr(&qu->search_vb,nextentry)) { - stat= adns_s_nomemory; goto x_fail; - } + !adns__vbuf_appendstr(&qu->search_vb,nextentry)) + goto x_nomemory; } free(qu->query_dgram); qu->query_dgram= 0; qu->query_dglen= 0; - query_simple(ads,qu, qu->search_vb.buf, qu->search_vb.used, qu->typei, qu->flags, now); + query_simple(ads,qu, qu->search_vb.buf, qu->search_vb.used, + qu->typei, qu->flags, now); return; - + +x_nomemory: + stat= adns_s_nomemory; x_fail: adns__query_fail(qu,stat); } @@ -182,6 +200,8 @@ static int save_owner(adns_query qu, const char *owner, int ol) { /* Returns 1 if OK, otherwise there was no memory. */ adns_answer *ans; + if (!(qu->flags & adns_qf_owner)) return 1; + ans= qu->answer; assert(!ans->owner); @@ -207,11 +227,14 @@ int adns_submit(adns_state ads, adns__consistency(ads,0,cc_entex); + if (!(type & adns__qtf_bigaddr) || !(type & adns__qtf_manyaf)) + flags = (flags & ~adns__qf_afmask) | adns_qf_ipv4_only; + typei= adns__findtype(type); if (!typei) return ENOSYS; r= gettimeofday(&now,0); if (r) goto x_errno; - qu= query_alloc(ads,typei,flags,now); if (!qu) goto x_errno; + qu= query_alloc(ads,typei,type,flags,now); if (!qu) goto x_errno; qu->ctx.ext= context; qu->ctx.callback= 0; @@ -225,6 +248,7 @@ int adns_submit(adns_state ads, if (ol>=1 && owner[ol-1]=='.' && (ol<2 || owner[ol-2]!='\\')) { flags &= ~adns_qf_search; + qu->flags= flags; ol--; } @@ -258,6 +282,65 @@ int adns_submit(adns_state ads, return r; } +static const char *default_zone = ""; + +int adns_submit_reverse_any(adns_state ads, + const struct sockaddr *addr, + const char *zone, + adns_rrtype type, + adns_queryflags flags, + void *context, + adns_query *query_r) { + char *buf, *buf_free, *p; + char shortbuf[100]; + const afinfo *ai; + int r, lreq; + + flags &= ~adns_qf_search; + + switch (addr->sa_family) { + case AF_INET: + ai = &adns__inet_afinfo; + if (zone == default_zone) zone = "in-addr.arpa"; + break; + case AF_INET6: + ai = &adns__inet6_afinfo; + if (zone == default_zone) zone = "ip6.arpa"; + break; + default: + return ENOSYS; + } + + lreq= strlen(zone) + ai->nrevcomp*(ai->revcompwd + 1) + 1; + if (lreq > sizeof(shortbuf)) { + buf= malloc(lreq); + if (!buf) return errno; + buf_free= buf; + } else { + buf= shortbuf; + buf_free= 0; + } + + p = ai->rev_mkname(addr, buf); + *p++ = '.'; + strcpy(p, zone); + + r= adns_submit(ads,buf,type,flags,context,query_r); + free(buf_free); + return r; +} + +int adns_submit_reverse(adns_state ads, + const struct sockaddr *addr, + adns_rrtype type, + adns_queryflags flags, + void *context, + adns_query *query_r) { + if (type != adns_r_ptr && type != adns_r_ptr_raw) return EINVAL; + return adns_submit_reverse_any(ads,addr,default_zone, + type,flags,context,query_r); +} + int adns_synchronous(adns_state ads, const char *owner, adns_rrtype type, @@ -283,6 +366,7 @@ static void *alloc_common(adns_query qu, size_t sz) { an= malloc(MEM_ROUND(MEM_ROUND(sizeof(*an)) + sz)); if (!an) return 0; LIST_LINK_TAIL(qu->allocations,an); + an->sz = sz; return (byte*)an + MEM_ROUND(sizeof(*an)); } @@ -306,15 +390,36 @@ void *adns__alloc_preserved(adns_query qu, size_t sz) { return rv; } +static allocnode *alloc_info(adns_query qu, void *p, size_t *sz_r) +{ + allocnode *an; + + if (!p || p == qu) { *sz_r = 0; return 0; } + an = (allocnode *)((byte *)p - MEM_ROUND(sizeof(allocnode))); + *sz_r = MEM_ROUND(an->sz); + return an; +} + +void adns__free_interim(adns_query qu, void *p) { + size_t sz; + allocnode *an = alloc_info(qu, p, &sz); + + if (!an) return; + assert(!qu->final_allocspace); + LIST_UNLINK(qu->allocations, an); + free(an); + qu->interim_allocd -= sz; +} + void *adns__alloc_mine(adns_query qu, size_t sz) { return alloc_common(qu,MEM_ROUND(sz)); } -void adns__transfer_interim(adns_query from, adns_query to, void *block, size_t sz) { - allocnode *an; +void adns__transfer_interim(adns_query from, adns_query to, void *block) { + size_t sz; + allocnode *an = alloc_info(from, block, &sz); - if (!block) return; - an= (void*)((byte*)block - MEM_ROUND(sizeof(*an))); + if (!an) return; assert(!to->final_allocspace); assert(!from->final_allocspace); @@ -344,7 +449,7 @@ void *adns__alloc_final(adns_query qu, size_t sz) { return rp; } -static void cancel_children(adns_query qu) { +void adns__cancel_children(adns_query qu) { adns_query cqu, ncqu; for (cqu= qu->children.head; cqu; cqu= ncqu) { @@ -355,7 +460,7 @@ static void cancel_children(adns_query qu) { void adns__reset_preserved(adns_query qu) { assert(!qu->final_allocspace); - cancel_children(qu); + adns__cancel_children(qu); qu->answer->nrrs= 0; qu->answer->rrs.untyped= 0; qu->interim_allocd= qu->preserved_allocd; @@ -364,10 +469,13 @@ void adns__reset_preserved(adns_query qu) { static void free_query_allocs(adns_query qu) { allocnode *an, *ann; - cancel_children(qu); + adns__cancel_children(qu); for (an= qu->allocations.head; an; an= ann) { ann= an->next; free(an); } LIST_INIT(qu->allocations); adns__vbuf_free(&qu->vb); + adns__vbuf_free(&qu->search_vb); + free(qu->query_dgram); + qu->query_dgram= 0; } void adns_cancel(adns_query qu) { @@ -377,10 +485,13 @@ void adns_cancel(adns_query qu) { adns__consistency(ads,qu,cc_entex); if (qu->parent) LIST_UNLINK_PART(qu->parent->children,qu,siblings.); switch (qu->state) { - case query_tosend: case query_tcpwait: case query_tcpsent: - LIST_UNLINK(ads->timew,qu); + case query_tosend: + LIST_UNLINK(ads->udpw,qu); break; - case query_child: + case query_tcpw: + LIST_UNLINK(ads->tcpw,qu); + break; + case query_childw: LIST_UNLINK(ads->childw,qu); break; case query_done: @@ -395,7 +506,8 @@ void adns_cancel(adns_query qu) { adns__consistency(ads,0,cc_entex); } -void adns__update_expires(adns_query qu, unsigned long ttl, struct timeval now) { +void adns__update_expires(adns_query qu, unsigned long ttl, + struct timeval now) { time_t max; assert(ttl <= MAXTTLBELIEVE); @@ -411,7 +523,8 @@ static void makefinal_query(adns_query qu) { ans= qu->answer; if (qu->interim_allocd) { - ans= realloc(qu->answer, MEM_ROUND(MEM_ROUND(sizeof(*ans)) + qu->interim_allocd)); + ans= realloc(qu->answer, + MEM_ROUND(MEM_ROUND(sizeof(*ans)) + qu->interim_allocd)); if (!ans) goto x_nomem; qu->answer= ans; } @@ -444,13 +557,12 @@ void adns__query_done(adns_query qu) { adns_answer *ans; adns_query parent; - cancel_children(qu); + adns__cancel_children(qu); qu->id= -1; ans= qu->answer; - if (qu->flags & adns_qf_owner && qu->flags & adns_qf_search && - ans->status != adns_s_nomemory) { + if (qu->flags & adns_qf_search && ans->status != adns_s_nomemory) { if (!save_owner(qu, qu->search_vb.buf, qu->search_vb.used)) { adns__query_fail(qu,adns_s_nomemory); return; @@ -458,15 +570,19 @@ void adns__query_done(adns_query qu) { } if (ans->nrrs && qu->typei->diff_needswap) { - if (!adns__vbuf_ensure(&qu->vb,qu->typei->rrsz)) { + if (!adns__vbuf_ensure(&qu->vb,ans->rrsz)) { adns__query_fail(qu,adns_s_nomemory); return; } adns__isort(ans->rrs.bytes, ans->nrrs, ans->rrsz, qu->vb.buf, - (int(*)(void*, const void*, const void*))qu->typei->diff_needswap, + (int(*)(void*, const void*, const void*)) + qu->typei->diff_needswap, qu->ads); } + if (ans->nrrs && qu->typei->postsort) { + qu->typei->postsort(qu->ads, ans->rrs.bytes, ans->nrrs, qu->typei); + } ans->expires= qu->expires; parent= qu->parent; @@ -475,6 +591,7 @@ void adns__query_done(adns_query qu) { LIST_UNLINK(qu->ads->childw,parent); qu->ctx.callback(parent,qu); free_query_allocs(qu); + free(qu->answer); free(qu); } else { makefinal_query(qu);