From: ian Date: Sat, 17 Apr 1999 13:45:47 +0000 (+0000) Subject: Search list implementation compiles, but not tested. X-Git-Tag: rel-adns-0-1~13 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=commitdiff_plain;h=660d7d3b4af029c3e86fdfe1ac078815c41ed79e Search list implementation compiles, but not tested. --- diff --git a/src/internal.h b/src/internal.h index a71d9dc..4ec3c3e 100644 --- a/src/internal.h +++ b/src/internal.h @@ -51,6 +51,7 @@ typedef unsigned char byte; #define DNS_MAXUDP 512 #define DNS_MAXDOMAIN 255 #define DNS_HDRSIZE 12 +#define DNS_IDOFFSET 0 #define DNS_CLASS_IN 1 #define DNS_INADDR_ARPA "in-addr", "arpa" @@ -185,7 +186,8 @@ struct adns__query { * is copied into the vbuf, and _origlen set to its length. Then * we walk the searchlist, if we want to. _pos says where we are * (next entry to try), and _doneabs says whether we've done the - * absolute query yet. If flags doesn't have adns_qf_search then + * absolute query yet (0=not yet, 1=done, -1=must do straight away, + * but not done yet). If flags doesn't have adns_qf_search then * the vbuf is initialised but empty and everything else is zero. * * fixme: actually implement this! @@ -259,7 +261,7 @@ struct adns__state { struct { adns_query head, tail; } timew, childw, output; int nextid, udpsocket, tcpsocket; vbuf tcpsend, tcprecv; - int nservers, nsortlist, nsearchlist, tcpserver; + int nservers, nsortlist, nsearchlist, searchndots, tcpserver; enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate; struct timeval tcptimeout; struct sigaction stdsigpipe; @@ -332,7 +334,8 @@ void adns__sigpipe_unprotect(adns_state); adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r, const char *owner, int ol, const typeinfo *typei, adns_queryflags flags); -/* Assembles a query packet in vb, and returns id at *id_r. */ +/* Assembles a query packet in vb. A new id is allocated and returned. + */ adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r, const byte *qd_dgram, int qd_dglen, int qd_begin, @@ -362,10 +365,10 @@ void adns__query_udp(adns_query qu, struct timeval now); /* From query.c: */ -int adns__internal_submit(adns_state ads, adns_query *query_r, - const typeinfo *typei, vbuf *qumsg_vb, int id, - adns_queryflags flags, struct timeval now, - adns_status failstat, const qcontext *ctx); +adns_status adns__internal_submit(adns_state ads, adns_query *query_r, + const typeinfo *typei, vbuf *qumsg_vb, int id, + adns_queryflags flags, struct timeval now, + const qcontext *ctx); /* Submits a query (for internal use, called during external submits). * * The new query is returned in *query_r, or we return adns_s_nomemory. @@ -374,12 +377,19 @@ int adns__internal_submit(adns_state ads, adns_query *query_r, * the memory for it is _taken over_ by this routine whether it * succeeds or fails (if it succeeds, the vbuf is reused for qu->vb). * - * If failstat is nonzero then if we are successful in creating the query - * it is immediately failed with code failstat (but _submit still succeds). - * * *ctx is copied byte-for-byte into the query. */ +void adns__search_next(adns_state ads, adns_query qu, struct timeval now); +/* Walks down the searchlist for a query with adns_qf_search. + * The query should have just had a negative response, or not had + * any queries sent yet, and should not be on any queue. + * The query_dgram if any will be freed and forgotten and a new + * one constructed from the search_* members of the query. + * + * Cannot fail (in case of error, calls adns__query_fail). + */ + void *adns__alloc_interim(adns_query qu, size_t sz); /* Allocates some memory, and records which query it came from * and how much there was. @@ -604,6 +614,7 @@ static inline int ctype_alpha(int c) { * sizeof(union maxalign) ) #define LIST_INIT(list) ((list).head= (list).tail= 0) +#define LINK_INIT(link) ((link).next= (link).back= 0) #define LIST_UNLINK_PART(list,node,part) \ do { \ diff --git a/src/query.c b/src/query.c index f710d3e..81c04cb 100644 --- a/src/query.c +++ b/src/query.c @@ -33,76 +33,146 @@ #include "internal.h" -int adns__internal_submit(adns_state ads, adns_query *query_r, - const typeinfo *typei, vbuf *qumsg_vb, int id, - adns_queryflags flags, struct timeval now, - adns_status failstat, const qcontext *ctx) { +static adns_query query_alloc(adns_state ads, const typeinfo *typei, + adns_queryflags flags, struct timeval now) { + /* Allocate a virgin query and return it. */ adns_query qu; - - qu= malloc(sizeof(*qu)); if (!qu) goto x_nomemory; - qu->answer= malloc(sizeof(*qu->answer)); if (!qu->answer) goto x_freequ_nomemory; - + + qu= malloc(sizeof(*qu)); if (!qu) return 0; + qu->answer= malloc(sizeof(*qu->answer)); if (!qu->answer) { free(qu); return 0; } + qu->ads= ads; qu->state= query_udp; qu->back= qu->next= qu->parent= 0; LIST_INIT(qu->children); - qu->siblings.next= qu->siblings.back= 0; + LINK_INIT(qu->siblings); LIST_INIT(qu->allocations); qu->interim_allocd= 0; qu->final_allocspace= 0; qu->typei= typei; + qu->query_dgram= 0; + qu->query_dglen= 0; adns__vbuf_init(&qu->vb); qu->cname_dgram= 0; qu->cname_dglen= qu->cname_begin= 0; - - qu->id= id; + + adns__vbuf_init(&qu->search_vb); + qu->search_origlen= qu->search_pos= qu->search_doneabs= 0; + + qu->id= 0; qu->flags= flags; qu->udpretries= 0; qu->udpnextserver= 0; qu->udpsent= qu->tcpfailed= 0; timerclear(&qu->timeout); - memcpy(&qu->ctx,ctx,sizeof(qu->ctx)); qu->expires= now.tv_sec + MAXTTLBELIEVE; + memset(&qu->ctx,0,sizeof(qu->ctx)); + qu->answer->status= adns_s_ok; qu->answer->cname= 0; qu->answer->type= typei->type; + qu->answer->expires= -1; qu->answer->nrrs= 0; qu->answer->rrs= 0; qu->answer->rrsz= typei->rrsz; - - *query_r= qu; - qu->query_dglen= qumsg_vb->used; - if (qumsg_vb->used) { - qu->query_dgram= malloc(qumsg_vb->used); - if (!qu->query_dgram) { - adns__query_fail(qu,adns_s_nomemory); - return adns_s_ok; - } - memcpy(qu->query_dgram,qumsg_vb->buf,qumsg_vb->used); - } else { - qu->query_dgram= 0; - } + return qu; +} + +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. + */ + qu->vb= *qumsg_vb; adns__vbuf_init(qumsg_vb); + + qu->query_dgram= malloc(qu->vb.used); + if (!qu->query_dgram) { adns__query_fail(qu,adns_s_nomemory); return; } + + qu->id= id; + qu->query_dglen= qu->vb.used; + memcpy(qu->query_dgram,qu->vb.buf,qu->vb.used); - if (failstat) { - adns__query_fail(qu,failstat); - return adns_s_ok; - } adns__query_udp(qu,now); adns__autosys(ads,now); +} +adns_status adns__internal_submit(adns_state ads, adns_query *query_r, + const typeinfo *typei, vbuf *qumsg_vb, int id, + adns_queryflags flags, struct timeval now, + const qcontext *ctx) { + adns_query qu; + + qu= query_alloc(ads,typei,flags,now); + if (!qu) { adns__vbuf_free(qumsg_vb); return adns_s_nomemory; } + *query_r= qu; + + memcpy(&qu->ctx,ctx,sizeof(qu->ctx)); + query_submit(ads,qu, typei,qumsg_vb,id,flags,now); + return adns_s_ok; +} - x_freequ_nomemory: - free(qu); - x_nomemory: - adns__vbuf_free(qumsg_vb); - return adns_s_nomemory; +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; + 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; } + + query_submit(ads,qu, typei,&vb,id, flags,now); +} + +void adns__search_next(adns_state ads, adns_query qu, struct timeval now) { + const char *nextentry; + adns_status stat; + + if (qu->search_doneabs<0) { + nextentry= 0; + qu->search_doneabs= 1; + } else { + if (qu->search_pos >= ads->nsearchlist) { + if (qu->search_doneabs) { + stat= adns_s_nxdomain; goto x_fail; + return; + } else { + nextentry= 0; + qu->search_doneabs= 1; + } + } else { + nextentry= ads->searchlist[qu->search_pos++]; + } + } + + if (nextentry) { + if (!adns__vbuf_append(&qu->search_vb,".",1) || + !adns__vbuf_appendstr(&qu->search_vb,nextentry)) { + stat= adns_s_nomemory; goto x_fail; + } else { + qu->search_vb.used= qu->search_origlen; + } + } + + 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); + return; + +x_fail: + adns__query_fail(qu,stat); } int adns_submit(adns_state ads, @@ -111,34 +181,53 @@ int adns_submit(adns_state ads, adns_queryflags flags, void *context, adns_query *query_r) { - qcontext ctx; - int id, r, ol; - vbuf vb, search_vb; + int r, ol, ndots; adns_status stat; const typeinfo *typei; struct timeval now; + adns_query qu; + const char *p; typei= adns__findtype(type); if (!typei) return adns_s_unknownrrtype; - - ctx.ext= context; - ctx.callback= 0; - memset(&ctx.info,0,sizeof(ctx.info)); - - r= gettimeofday(&now,0); if (r) return errno; - id= 0; - adns__vbuf_init(&vb); + r= gettimeofday(&now,0); if (r) goto x_errno; + qu= query_alloc(ads,typei,flags,now); if (!qu) goto x_errno; + + qu->ctx.ext= context; + qu->ctx.callback= 0; + memset(&qu->ctx.info,0,sizeof(qu->ctx.info)); ol= strlen(owner); - if (ol>DNS_MAXDOMAIN+1) { stat= adns_s_querydomaintoolong; goto xit; } + if (!ol) { stat= adns_s_querydomaininvalid; goto x_adnsfail; } + if (ol>DNS_MAXDOMAIN+1) { stat= adns_s_querydomaintoolong; goto x_adnsfail; } if (ol>=2 && owner[ol-1]=='.' && owner[ol-2]!='\\') { flags &= ~adns_qf_search; ol--; } - stat= adns__mkquery(ads,&vb,&id, owner,ol, typei,flags); - - xit: - return adns__internal_submit(ads,query_r, typei,&vb,id, flags,now, stat,&ctx); + if (flags & adns_qf_search) { + r= adns__vbuf_append(&qu->search_vb,owner,ol); + if (!r) { stat= adns_s_nomemory; goto x_adnsfail; } + + for (ndots=0, p=owner; (p= strchr(p,'.')); p++, ndots++); + qu->search_doneabs= (ndots >= ads->searchndots) ? -1 : 0; + + qu->search_origlen= ol; + + adns__search_next(ads,qu,now); + return 0; + } + + query_simple(ads,qu, owner,ol, typei,flags, now); + return 0; + + x_adnsfail: + adns__query_fail(qu,stat); + return 0; + + x_errno: + r= errno; + assert(r); + return r; } int adns_synchronous(adns_state ads, diff --git a/src/reply.c b/src/reply.c index c1ad342..ab7c8ff 100644 --- a/src/reply.c +++ b/src/reply.c @@ -227,7 +227,12 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, if (rcode == rcode_nxdomain) { /* We still wanted to look for the SOA so we could find the TTL. */ adns__update_expires(qu,soattl,now); - adns__query_fail(qu,adns_s_nxdomain); + + if (qu->flags & adns_qf_search) { + adns__search_next(ads,qu,now); + } else { + adns__query_fail(qu,adns_s_nxdomain); + } return; } diff --git a/src/setup.c b/src/setup.c index 26a5cff..1b81da1 100644 --- a/src/setup.c +++ b/src/setup.c @@ -428,6 +428,7 @@ static int init_begin(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { ads->nservers= ads->nsortlist= ads->nsearchlist= ads->tcpserver= 0; ads->tcpstate= server_disconnected; ads->searchlist= 0; + ads->searchndots= 1; timerclear(&ads->tcptimeout); *ads_r= ads; diff --git a/src/transmit.c b/src/transmit.c index d0b9d95..11d774b 100644 --- a/src/transmit.c +++ b/src/transmit.c @@ -39,11 +39,10 @@ static adns_status mkquery_header(adns_state ads, vbuf *vb, int *id_r, int qdlen if (!adns__vbuf_ensure(vb,DNS_HDRSIZE+qdlen+4)) return adns_s_nomemory; - *id_r= id= (ads->nextid++) & 0x0ffff; - vb->used= 0; MKQUERY_START(vb); + *id_r= id= (ads->nextid++) & 0x0ffff; MKQUERY_ADDW(id); MKQUERY_ADDB(0x01); /* QR=Q(0), OPCODE=QUERY(0000), !AA, !TC, RD */ MKQUERY_ADDB(0x00); /* !RA, Z=000, RCODE=NOERROR(0000) */ diff --git a/src/types.c b/src/types.c index e4e56f6..50fb1e8 100644 --- a/src/types.c +++ b/src/types.c @@ -469,7 +469,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, 0, &ctx); + &pai->qu->vb, id, nflags, pai->now, &ctx); if (st) return st; nqu->parent= pai->qu; @@ -712,7 +712,7 @@ static adns_status pa_ptr(const parseinfo *pai, int dmstart, int max, void *data memset(&ctx.info,0,sizeof(ctx.info)); st= adns__internal_submit(pai->ads, &nqu, adns__findtype(adns_r_addr), &pai->qu->vb, id, - adns_qf_quoteok_query, pai->now, 0, &ctx); + adns_qf_quoteok_query, pai->now, &ctx); if (st) return st; nqu->parent= pai->qu;