chiark / gitweb /
Include TTL (well, actually, expiry time) in answers.
authorian <ian>
Sun, 11 Apr 1999 17:21:15 +0000 (17:21 +0000)
committerian <ian>
Sun, 11 Apr 1999 17:21:15 +0000 (17:21 +0000)
12 files changed:
client/adnstest.c
regress/Makefile.in
regress/case-manya.out
regress/case-norm.out
regress/case-timeout.out
regress/case-trunc.out
src/adns.h
src/internal.h
src/parse.c
src/query.c
src/reply.c
src/types.c

index ea9ed2a..98caf2f 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include <stdio.h>
+#include <sys/time.h>
 #include <unistd.h>
 #include <assert.h>
 #include <stdlib.h>
@@ -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; i<ans->nrrs; i++) {
index a356ccf..2055f08 100644 (file)
@@ -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
index f21068c..6a352a0 100644 (file)
@@ -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
index 70648e5..9be2769 100644 (file)
@@ -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
index 1b71759..ccbbd39 100644 (file)
@@ -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
index dbd0c4a..7943119 100644 (file)
@@ -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
index 82f29d4..a234cda 100644 (file)
@@ -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);
 
index f0f9147..5e59a12 100644 (file)
@@ -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
index 22d9d96..842556a 100644 (file)
@@ -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);
   }
index 545feec..666fdd7 100644 (file)
@@ -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; rrn<ans->nrrs; 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.);
index c37bb40..452c5f6 100644 (file)
@@ -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; rri<ancount; rri++) {
     rrstart= cbyte;
     st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
-                    &rrtype,&rrclass,&rdlength,&rdstart,
+                    &rrtype,&rrclass,&ttl, &rdlength,&rdstart,
                     &ownermatched);
     if (st) { adns__query_fail(qu,st); return; }
     if (rrtype == -1) goto x_truncated;
@@ -177,6 +178,7 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
 
        memcpy(qu->answer->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; rri<nscount; rri++) {
       rrstart= cbyte;
       st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
-                      &rrtype,&rrclass,&rdlength,&rdstart, 0);
+                      &rrtype,&rrclass,&ttl, &rdlength,&rdstart, 0);
       if (st) { adns__query_fail(qu,st); return; }
       if (rrtype==-1) goto x_truncated;
       if (rrclass != DNS_CLASS_IN) {
@@ -223,12 +220,20 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
                   rrclass,DNS_CLASS_IN);
        continue;
       }
-      if (rrtype == adns_r_soa_raw) { foundsoa= 1; break; }
+      if (rrtype == adns_r_soa_raw) { foundsoa= 1; soattl= ttl; break; }
       else if (rrtype == adns_r_ns_raw) { foundns= 1; }
     }
+    
+    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);
+      return;
+    }
 
     if (foundsoa || !foundns) {
       /* Aha !  A NODATA response, good. */
+      adns__update_expires(qu,soattl,now);
       adns__query_fail(qu,adns_s_nodata);
       return;
     }
@@ -275,13 +280,14 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
 
   for (rri=0, nrrs=0; rri<ancount; rri++) {
     st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
-                    &rrtype,&rrclass,&rdlength,&rdstart,
+                    &rrtype,&rrclass,&ttl, &rdlength,&rdstart,
                     &ownermatched);
     assert(!st); assert(rrtype != -1);
     if (rrclass != DNS_CLASS_IN ||
        rrtype != (qu->typei->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;
index bd87450..deac6c4 100644 (file)
@@ -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; rri<count; rri++) {
     st= adns__findrr_anychk(pai->qu, 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;