From: ian Date: Sun, 11 Apr 1999 17:21:15 +0000 (+0000) Subject: Include TTL (well, actually, expiry time) in answers. X-Git-Tag: rel-adns-0-1~21 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=commitdiff_plain;h=73dba56e1981d7fe721acf17d0cd91a4fed04850 Include TTL (well, actually, expiry time) in answers. --- diff --git a/client/adnstest.c b/client/adnstest.c index ea9ed2a..98caf2f 100644 --- a/client/adnstest.c +++ b/client/adnstest.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -76,6 +77,7 @@ int main(int argc, char *const *argv) { int len, i, qc, qi, tc, ti, ch; adns_status r, ri; const adns_rrtype *types; + struct timeval now; adns_rrtype *types_a; if (argv[0] && argv[1] && argv[1][0] == '/') { @@ -146,12 +148,15 @@ int main(int argc, char *const *argv) { r= adns_wait(ads,&qu,&ans,0); if (r) failure("wait",r); + if (gettimeofday(&now,0)) { perror("gettimeofday"); exit(3); } + ri= adns_rr_info(ans->type, &rrtn,&fmtn,&len, 0,0); fprintf(stdout, "%s type ", domlist[qi]); dumptype(ri,rrtn,fmtn); - fprintf(stdout, ": %s; nrrs=%d; cname=%s\n", + fprintf(stdout, ": %s; nrrs=%d; cname=%s; ttl=%ld\n", adns_strerror(ans->status), - ans->nrrs, ans->cname ? ans->cname : "$"); + ans->nrrs, ans->cname ? ans->cname : "$", + (long)ans->expires - (long)now.tv_sec); if (ans->nrrs) { assert(!ri); for (i=0; inrrs; i++) { diff --git a/regress/Makefile.in b/regress/Makefile.in index a356ccf..2055f08 100644 --- a/regress/Makefile.in +++ b/regress/Makefile.in @@ -40,12 +40,15 @@ ALLOBJS= $(HARNLOBJS) dtest.o hrecord.o hplayback.o hcommon.o check: $(TARGETS) ./checkall -hrecord: $(srcdir)/../client/adnstest.o hrecord.o hcommon.o $(HARNLOBJS) -hplayback: $(srcdir)/../client/adnstest.o hplayback.o hcommon.o $(HARNLOBJS) +hrecord: adnstest_c.o hrecord.o hcommon.o $(HARNLOBJS) +hplayback: adnstest_c.o hplayback.o hcommon.o $(HARNLOBJS) %_d.o: $(srcdir)/../src/%.c $(CC) $(HCPPFLAGS) -c -g -o $@ $< +%_c.o: $(srcdir)/../client/%.c + $(CC) $(HCPPFLAGS) -I $(srcdir)/../src -c -g -o $@ $< + $(ALLOBJS): $(srcdir)/../src/adns.h $(srcdir)/../src/internal.h harness.h %:: %.m4 hmacros.i4 hsyscalls.i4 diff --git a/regress/case-manya.out b/regress/case-manya.out index f21068c..6a352a0 100644 --- a/regress/case-manya.out +++ b/regress/case-manya.out @@ -1,6 +1,6 @@ adns debug: using nameserver 172.18.45.6 manyaddrs.test.iwj.relativity.greenend.org.uk type 1 A(-) submitted -manyaddrs.test.iwj.relativity.greenend.org.uk type A(-): OK; nrrs=4; cname=$ +manyaddrs.test.iwj.relativity.greenend.org.uk type A(-): OK; nrrs=4; cname=$; ttl=60 127.0.0.1 172.18.45.6 172.18.45.1 diff --git a/regress/case-norm.out b/regress/case-norm.out index 70648e5..9be2769 100644 --- a/regress/case-norm.out +++ b/regress/case-norm.out @@ -1,4 +1,4 @@ adns debug: using nameserver 172.18.45.6 chiark.greenend.org.uk type 1 A(-) submitted -chiark.greenend.org.uk type A(-): OK; nrrs=1; cname=$ +chiark.greenend.org.uk type A(-): OK; nrrs=1; cname=$; ttl=86400 195.224.76.132 diff --git a/regress/case-timeout.out b/regress/case-timeout.out index 1b71759..ccbbd39 100644 --- a/regress/case-timeout.out +++ b/regress/case-timeout.out @@ -1,3 +1,3 @@ adns debug: using nameserver 172.18.45.36 chiark.greenend.org.uk type 1 A(-) submitted -chiark.greenend.org.uk type A(-): DNS query timed out; nrrs=0; cname=$ +chiark.greenend.org.uk type A(-): DNS query timed out; nrrs=0; cname=$; ttl=604770 diff --git a/regress/case-trunc.out b/regress/case-trunc.out index dbd0c4a..7943119 100644 --- a/regress/case-trunc.out +++ b/regress/case-trunc.out @@ -1,3 +1,3 @@ adns debug: using nameserver 172.18.45.6 trunc.test.iwj.relativity.greenend.org.uk type 1 A(-) submitted -trunc.test.iwj.relativity.greenend.org.uk type A(-): No such data; nrrs=0; cname=$ +trunc.test.iwj.relativity.greenend.org.uk type A(-): No such data; nrrs=0; cname=$; ttl=60 diff --git a/src/adns.h b/src/adns.h index 82f29d4..a234cda 100644 --- a/src/adns.h +++ b/src/adns.h @@ -195,6 +195,7 @@ typedef struct { adns_status status; char *cname; /* always NULL if query was for CNAME records */ adns_rrtype type; /* guaranteed to be same as in query */ + time_t expires; /* expiry time, defined only if _s_ok, nxdomain or nodata. NOT TTL! */ int nrrs, rrsz; union { void *untyped; @@ -268,8 +269,8 @@ int adns_wait(adns_state ads, adns_query *query_io, adns_answer **answer_r, void **context_r); -/* fixme: include TTL in answer somehow */ /* fixme: easy way to get lists of fd's */ +/* fixme: minor cache */ void adns_cancel(adns_query query); diff --git a/src/internal.h b/src/internal.h index f0f9147..5e59a12 100644 --- a/src/internal.h +++ b/src/internal.h @@ -44,6 +44,7 @@ typedef unsigned char byte; #define UDPRETRYMS 2000 #define TCPMS 30000 #define LOCALRESOURCEMS 20 +#define MAXTTLBELIEVE (7*86400) /* any TTL > 7 days is capped */ #define DNS_PORT 53 #define DNS_MAXUDP 512 @@ -181,6 +182,7 @@ struct adns__query { int udpnextserver; unsigned long udpsent, tcpfailed; /* bitmap indexed by server */ struct timeval timeout; + time_t expires; /* Earliest expiry time of any record we used. */ qcontext ctx; @@ -379,6 +381,10 @@ void adns__transfer_interim(adns_query from, adns_query to, void *block, size_t * * It is legal to call adns__transfer_interim with a null pointer; this * has no effect. + * + * _transfer_interim also ensures that the expiry time of the `to' query + * is no later than that of the `from' query, so that child queries' + * TTLs get inherited by their parents. */ void *adns__alloc_mine(adns_query qu, size_t sz); @@ -478,16 +484,17 @@ adns_status adns__parse_domain(adns_state ads, int serv, adns_query qu, adns_status adns__findrr(adns_query qu, int serv, const byte *dgram, int dglen, int *cbyte_io, - int *type_r, int *class_r, int *rdlen_r, int *rdstart_r, + int *type_r, int *class_r, unsigned long *ttl_r, + int *rdlen_r, int *rdstart_r, int *ownermatchedquery_r); /* Finds the extent and some of the contents of an RR in a datagram * and does some checks. The datagram is *dgram, length dglen, and * the RR starts at *cbyte_io (which is updated afterwards to point * to the end of the RR). * - * The type, class and RRdata length and start are returned iff - * the corresponding pointer variables are not null. type_r and - * class_r may not be null. + * The type, class, TTL and RRdata length and start are returned iff + * the corresponding pointer variables are not null. type_r, class_r + * and ttl_r may not be null. The TTL will be capped. * * If ownermatchedquery_r != 0 then the owner domain of this * RR will be compared with that in the query (or, if the query @@ -506,7 +513,8 @@ adns_status adns__findrr(adns_query qu, int serv, adns_status adns__findrr_anychk(adns_query qu, int serv, const byte *dgram, int dglen, int *cbyte_io, - int *type_r, int *class_r, int *rdlen_r, int *rdstart_r, + int *type_r, int *class_r, unsigned long *ttl_r, + int *rdlen_r, int *rdstart_r, const byte *eo_dgram, int eo_dglen, int eo_cbyte, int *eo_matched_r); /* Like adns__findrr_checked, except that the datagram and @@ -523,6 +531,11 @@ adns_status adns__findrr_anychk(adns_query qu, int serv, * untruncated. */ +void adns__update_expires(adns_query qu, unsigned long ttl, struct timeval now); +/* Updates the `expires' field in the query, so that it doesn't exceed + * now + ttl. + */ + int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len); /* From event.c: */ @@ -581,5 +594,11 @@ static inline int ctype_alpha(int c) { #define GETIL_B(cb) (((dgram)[(cb)++]) & 0x0ff) #define GET_B(cb,tv) ((tv)= GETIL_B((cb))) #define GET_W(cb,tv) ((tv)=0, (tv)|=(GETIL_B((cb))<<8), (tv)|=GETIL_B(cb), (tv)) +#define GET_L(cb,tv) ( (tv)=0, \ + (tv)|=(GETIL_B((cb))<<24), \ + (tv)|=(GETIL_B((cb))<<16), \ + (tv)|=(GETIL_B((cb))<<8), \ + (tv)|=GETIL_B(cb), \ + (tv) ) #endif diff --git a/src/parse.c b/src/parse.c index 22d9d96..842556a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -150,13 +150,15 @@ adns_status adns__parse_domain(adns_state ads, int serv, adns_query qu, adns_status adns__findrr_anychk(adns_query qu, int serv, const byte *dgram, int dglen, int *cbyte_io, - int *type_r, int *class_r, int *rdlen_r, int *rdstart_r, + int *type_r, int *class_r, unsigned long *ttl_r, + int *rdlen_r, int *rdstart_r, const byte *eo_dgram, int eo_dglen, int eo_cbyte, int *eo_matched_r) { findlabel_state fls, eo_fls; int cbyte; int tmp, rdlen, mismatch; + unsigned long ttl; int lablen, labstart, ch; int eo_lablen, eo_labstart, eo_ch; adns_status st; @@ -193,7 +195,11 @@ adns_status adns__findrr_anychk(adns_query qu, int serv, if (cbyte+10>dglen) goto x_truncated; GET_W(cbyte,tmp); *type_r= tmp; GET_W(cbyte,tmp); *class_r= tmp; - cbyte+= 4; /* we skip the TTL */ + + GET_L(cbyte,ttl); + if (ttl > MAXTTLBELIEVE) ttl= MAXTTLBELIEVE; + *ttl_r= ttl; + GET_W(cbyte,rdlen); if (rdlen_r) *rdlen_r= rdlen; if (rdstart_r) *rdstart_r= cbyte; cbyte+= rdlen; @@ -208,23 +214,24 @@ adns_status adns__findrr_anychk(adns_query qu, int serv, adns_status adns__findrr(adns_query qu, int serv, const byte *dgram, int dglen, int *cbyte_io, - int *type_r, int *class_r, int *rdlen_r, int *rdstart_r, + int *type_r, int *class_r, unsigned long *ttl_r, + int *rdlen_r, int *rdstart_r, int *ownermatchedquery_r) { if (!ownermatchedquery_r) { return adns__findrr_anychk(qu,serv, dgram,dglen,cbyte_io, - type_r,class_r,rdlen_r,rdstart_r, + type_r,class_r,ttl_r,rdlen_r,rdstart_r, 0,0,0, 0); } else if (!qu->cname_dgram) { return adns__findrr_anychk(qu,serv, dgram,dglen,cbyte_io, - type_r,class_r,rdlen_r,rdstart_r, + type_r,class_r,ttl_r,rdlen_r,rdstart_r, qu->query_dgram,qu->query_dglen,DNS_HDRSIZE, ownermatchedquery_r); } else { return adns__findrr_anychk(qu,serv, dgram,dglen,cbyte_io, - type_r,class_r,rdlen_r,rdstart_r, + type_r,class_r,ttl_r,rdlen_r,rdstart_r, qu->cname_dgram,qu->cname_dglen,qu->cname_begin, ownermatchedquery_r); } diff --git a/src/query.c b/src/query.c index 545feec..666fdd7 100644 --- a/src/query.c +++ b/src/query.c @@ -64,6 +64,7 @@ int adns__internal_submit(adns_state ads, adns_query *query_r, qu->udpsent= qu->tcpfailed= 0; timerclear(&qu->timeout); memcpy(&qu->ctx,ctx,sizeof(qu->ctx)); + qu->expires= now.tv_sec + MAXTTLBELIEVE; qu->answer->status= adns_s_ok; qu->answer->cname= 0; @@ -192,6 +193,8 @@ void adns__transfer_interim(adns_query from, adns_query to, void *block, size_t from->interim_allocd -= sz; to->interim_allocd += sz; + + if (to->expires > from->expires) to->expires= from->expires; } void *adns__alloc_final(adns_query qu, size_t sz) { @@ -255,6 +258,15 @@ void adns_cancel(adns_query qu) { free(qu); } +void adns__update_expires(adns_query qu, unsigned long ttl, struct timeval now) { + time_t max; + + assert(ttl <= MAXTTLBELIEVE); + max= now.tv_sec + ttl; + if (qu->expires < max) return; + qu->expires= max; +} + static void makefinal_query(adns_query qu) { adns_answer *ans; int rrn; @@ -276,7 +288,7 @@ static void makefinal_query(adns_query qu) { for (rrn=0; rrnnrrs; rrn++) qu->typei->makefinal(qu, ans->rrs.bytes + rrn*ans->rrsz); } - + free_query_allocs(qu); return; @@ -305,6 +317,7 @@ void adns__query_done(adns_query qu) { qu->ads); } + ans->expires= qu->expires; parent= qu->parent; if (parent) { LIST_UNLINK_PART(parent->children,qu,siblings.); diff --git a/src/reply.c b/src/reply.c index c37bb40..452c5f6 100644 --- a/src/reply.c +++ b/src/reply.c @@ -33,6 +33,7 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, int rrtype, rrclass, rdlength, rdstart; int anstart, nsstart, arstart; int ownermatched, l, nrrs; + unsigned long ttl, soattl; const typeinfo *typei; adns_query qu, nqu; dns_rcode rcode; @@ -138,7 +139,7 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, for (rri= 0; rrianswer->cname,qu->vb.buf,l); cname_here= 1; + adns__update_expires(qu,ttl,now); /* If we find the answer section truncated after this point we restart * the query at the CNAME; if beforehand then we obviously have to use * TCP. If there is no truncation we can use the whole answer if @@ -203,18 +205,13 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, if (!wantedrrs) { /* Oops, NODATA or NXDOMAIN or perhaps a referral (which would be a problem) */ - - if (rcode == rcode_nxdomain) { - adns__query_fail(qu,adns_s_nxdomain); - return; - } /* RFC2308: NODATA has _either_ a SOA _or_ _no_ NS records in authority section */ - foundsoa= 0; foundns= 0; + foundsoa= 0; soattl= 0; foundns= 0; for (rri= 0; rritypei->type & adns__rrt_typemask) || !ownermatched) continue; + adns__update_expires(qu,ttl,now); st= typei->parse(&pai, rdstart,rdstart+rdlength, rrsdata+nrrs*typei->rrsz); if (st) { adns__query_fail(qu,st); return; } if (rdstart==-1) goto x_truncated; diff --git a/src/types.c b/src/types.c index bd87450..deac6c4 100644 --- a/src/types.c +++ b/src/types.c @@ -381,11 +381,12 @@ static adns_status pap_findaddrs(const parseinfo *pai, adns_rr_hostaddr *ha, int *cbyte_io, int count, int dmstart) { int rri, naddrs; int type, class, rdlen, rdstart, ownermatched; + unsigned long ttl; adns_status st; for (rri=0, naddrs=-1; rriqu, pai->serv, pai->dgram, pai->dglen, cbyte_io, - &type, &class, &rdlen, &rdstart, + &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) { @@ -395,6 +396,7 @@ static adns_status pap_findaddrs(const parseinfo *pai, adns_rr_hostaddr *ha, 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)); if (st) return st;