chiark / gitweb /
adnshost: adh-opts.c: Whitespace adjustments to option table
[adns.git] / src / types.c
index aa34c0ab9945ab43b6256437fa25bded7df8b0b6..59e9502e2f60f7072d4281479f8c69a14df1c576 100644 (file)
@@ -4,14 +4,15 @@
  */
 /*
  *  This file is part of adns, which is
- *    Copyright (C) 1997-2000,2003,2006  Ian Jackson
+ *    Copyright (C) 1997-2000,2003,2006,2014-2016,2020  Ian Jackson
+ *    Copyright (C) 2014  Mark Wooding
  *    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
- *  the Free Software Foundation; either version 2, or (at your option)
+ *  the Free Software Foundation; either version 3, or (at your option)
  *  any later version.
  *  
  *  This program is distributed in the hope that it will be useful,
@@ -20,8 +21,7 @@
  *  GNU General Public License for more details.
  *  
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software Foundation,
- *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
+ *  along with this program; if not, write to the Free Software Foundation.
  */
 
 #include <stddef.h>
@@ -221,7 +221,7 @@ static adns_status pa_txt(const parseinfo *pai, int cbyte,
   return adns_s_ok;
 }
 
-static adns_status cs_txt(vbuf *vb, const void *datap) {
+static adns_status cs_txt(vbuf *vb, adns_rrtype rrt, const void *datap) {
   const adns_rr_intstr *const *rrp= datap;
   const adns_rr_intstr *current;
   adns_status st;
@@ -238,7 +238,7 @@ static adns_status cs_txt(vbuf *vb, const void *datap) {
  * _hinfo   (cs)
  */
 
-static adns_status cs_hinfo(vbuf *vb, const void *datap) {
+static adns_status cs_hinfo(vbuf *vb, adns_rrtype rrt, const void *datap) {
   const adns_rr_intstrpair *rrp= datap;
   adns_status st;
 
@@ -316,7 +316,7 @@ static adns_status csp_genaddr(vbuf *vb, int af, const void *p) {
   return adns_s_ok;
 }
 
-static adns_status cs_inaddr(vbuf *vb, const void *datap) {
+static adns_status cs_inaddr(vbuf *vb, adns_rrtype rrt, const void *datap) {
   return csp_genaddr(vb, AF_INET,datap);
 }
 
@@ -338,7 +338,7 @@ static int di_in6addr(adns_state ads,
   return dip_genaddr(ads,AF_INET6,datap_a,datap_b);
 }
 
-static adns_status cs_in6addr(vbuf *vb, const void *datap) {
+static adns_status cs_in6addr(vbuf *vb, adns_rrtype rrt, const void *datap) {
   return csp_genaddr(vb,AF_INET6,datap);
 }
 
@@ -400,50 +400,46 @@ static unsigned addr_rrtypeflag(adns_rrtype type) {
  * adns__qf_addr_cname set so that we know that we're in the fixup state.
  */
 
-static adns_status pap_addr(const parseinfo *pai, int rrty, size_t rrsz,
-                           int *cbyte_io, int max, adns_rr_addr *storeto) {
-  const byte *dgram= pai->dgram;
-  int af, addrlen, salen;
+static adns_status pap_addr(const parseinfo *pai, int in_rrty, size_t out_rrsz,
+                           int *cbyte_io, int cbyte_max, adns_rr_addr *out) {
+  int in_addrlen;
+  int out_af, out_salen;
   struct in6_addr v6map;
-  const void *oaddr= dgram + *cbyte_io;
-  int avail= max - *cbyte_io;
-  int step= -1;
-  void *addrp= 0;
-
-  switch (rrty) {
-  case adns_r_a:
-    if ((pai->qu->flags & adns_qf_ipv6_mapv4) &&
-       (pai->qu->answer->type & adns__qtf_bigaddr)) {
-      if (avail < 4) return adns_s_invaliddata;
-      memset(v6map.s6_addr +  0, 0x00, 10);
-      memset(v6map.s6_addr + 10, 0xff,  2);
-      memcpy(v6map.s6_addr + 12, oaddr, 4);
-      oaddr= v6map.s6_addr; avail= sizeof(v6map.s6_addr);
-      if (step < 0) step= 4;
-      goto aaaa;
-    }
-    af= AF_INET; addrlen= 4;
-    addrp= &storeto->addr.inet.sin_addr;
-    salen= sizeof(storeto->addr.inet);
-    break;
-  case adns_r_aaaa:
-  aaaa:
-    af= AF_INET6; addrlen= 16;
-    addrp= storeto->addr.inet6.sin6_addr.s6_addr;
-    salen= sizeof(storeto->addr.inet6);
-    break;
+
+  const void *use_addr= pai->dgram + *cbyte_io;
+
+  switch (in_rrty) {
+  case adns_r_a:    in_addrlen= 4;  out_af= AF_INET;  break;
+  case adns_r_aaaa: in_addrlen= 16; out_af= AF_INET6; break;
+  default: abort();
   }
-  assert(addrp);
 
-  assert(offsetof(adns_rr_addr, addr) + salen <= rrsz);
-  if (addrlen < avail) return adns_s_invaliddata;
-  if (step < 0) step= addrlen;
-  *cbyte_io += step;
-  memset(&storeto->addr, 0, salen);
-  storeto->len= salen;
-  storeto->addr.sa.sa_family= af;
-  memcpy(addrp, oaddr, addrlen);
+  if ((*cbyte_io + in_addrlen) != cbyte_max) return adns_s_invaliddata;
 
+  if (out_af==AF_INET &&
+      (pai->qu->flags & adns_qf_ipv6_mapv4) &&
+      (pai->qu->answer->type & adns__qtf_bigaddr)) {
+    memset(v6map.s6_addr +  0, 0x00,    10);
+    memset(v6map.s6_addr + 10, 0xff,     2);
+    memcpy(v6map.s6_addr + 12, use_addr, 4);
+    use_addr= v6map.s6_addr;
+    out_af= AF_INET6;
+  }
+
+  switch (out_af) {
+  case AF_INET:  out_salen= sizeof(out->addr.inet);  break;
+  case AF_INET6: out_salen= sizeof(out->addr.inet6); break;
+  default: abort();
+  }
+
+  assert(offsetof(adns_rr_addr, addr) + out_salen <= out_rrsz);
+
+  memset(&out->addr, 0, out_salen);
+  out->len= out_salen;
+  out->addr.sa.sa_family= out_af;
+  adns__addr_inject(use_addr, &out->addr);
+
+  *cbyte_io += in_addrlen;
   return adns_s_ok;
 }
 
@@ -503,7 +499,7 @@ static adns_status csp_addr(vbuf *vb, const adns_rr_addr *rrp) {
   return adns_s_ok;
 }
 
-static adns_status cs_addr(vbuf *vb, const void *datap) {
+static adns_status cs_addr(vbuf *vb, adns_rrtype rrt, const void *datap) {
   const adns_rr_addr *rrp= datap;
 
   return csp_addr(vb,rrp);
@@ -583,11 +579,11 @@ static adns_status addr_submit(adns_query parent, adns_query *query_r,
    * available record types.  The memory management and callback rules are
    * the same as for adns__internal_submit.
    *
-   * Some differences: the query is linked onto the parent's children list
-   * before exit (though the parent's state is not changed, and it is not
-   * linked into the childw list queue); and we fiddle with the `tinfo'
-   * portion of the context structure (yes, modifying *ctx), since this is,
-   * in fact, the main purpose of this function.
+   * Some differences: the query is linked onto the parent's children
+   * list before exit (though the parent's state is not changed, and
+   * it is not linked into the childw list queue); and we set the
+   * `tinfo' portion of the context structure (yes, modifying *ctx),
+   * since this is, in fact, the main purpose of this function.
    */
 
   adns_state ads= parent->ads;
@@ -789,7 +785,7 @@ static adns_status csp_domain(vbuf *vb, const char *domain) {
   return adns_s_ok;
 }
 
-static adns_status cs_domain(vbuf *vb, const void *datap) {
+static adns_status cs_domain(vbuf *vb, adns_rrtype rrt, const void *datap) {
   const char *const *domainp= datap;
   return csp_domain(vb,*domainp);
 }
@@ -842,6 +838,7 @@ 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 (type==-1) continue;
     if (!ownermatched || class != DNS_CLASS_IN) continue;
     typef= addr_rrtypeflag(type);
     if (!(want & typef)) continue;
@@ -896,6 +893,7 @@ static void icb_hostaddr(adns_query parent, adns_query child) {
 done:
   if (st) {
     adns__free_interim(parent, rrp->addrs);
+    rrp->addrs = 0;
     rrp->naddrs= (st>0 && st<=adns_s_max_tempfail) ? -1 : 0;
   }
 
@@ -1003,11 +1001,13 @@ static void mf_hostaddr(adns_query qu, void *datap) {
   mfp_hostaddr(qu,rrp);
 }
 
-static adns_status csp_hostaddr(vbuf *vb, const adns_rr_hostaddr *rrp) {
+static adns_status csp_hostaddr(vbuf *vb, adns_rrtype rrt,
+                               const adns_rr_hostaddr *rrp) {
   const char *errstr;
   adns_status st;
   char buf[20];
   int i;
+  size_t addrsz= gsz_addr(0, rrt);
 
   st= csp_domain(vb,rrp->host);  if (st) return st;
 
@@ -1027,7 +1027,7 @@ static adns_status csp_hostaddr(vbuf *vb, const adns_rr_hostaddr *rrp) {
     CSP_ADDSTR(" (");
     for (i=0; i<rrp->naddrs; i++) {
       CSP_ADDSTR(" ");
-      st= csp_addr(vb,&rrp->addrs[i]);
+      st= csp_addr(vb, (const void*)((const char*)rrp->addrs + addrsz*i));
     }
     CSP_ADDSTR(" )");
   } else {
@@ -1036,10 +1036,10 @@ static adns_status csp_hostaddr(vbuf *vb, const adns_rr_hostaddr *rrp) {
   return adns_s_ok;
 }
 
-static adns_status cs_hostaddr(vbuf *vb, const void *datap) {
+static adns_status cs_hostaddr(vbuf *vb, adns_rrtype rrt, const void *datap) {
   const adns_rr_hostaddr *rrp= datap;
 
-  return csp_hostaddr(vb,rrp);
+  return csp_hostaddr(vb,rrt,rrp);
 }
 
 /*
@@ -1111,26 +1111,35 @@ static void mf_inthostaddr(adns_query qu, void *datap) {
   mfp_hostaddr(qu,&rrp->ha);
 }
 
-static adns_status cs_inthostaddr(vbuf *vb, const void *datap) {
-  const adns_rr_inthostaddr *rrp= datap;
+static adns_status csp_intofinthost(vbuf *vb, int i) {
   char buf[10];
 
-  sprintf(buf,"%u ",rrp->i);
+  if (i < 0 || i > 0xffff)
+    /* currently only used for MX whose priorities are 16-bit */
+    return adns_s_invaliddata;
+  
+  sprintf(buf,"%u ",i);
   CSP_ADDSTR(buf);
+  return adns_s_ok;
+}
 
-  return csp_hostaddr(vb,&rrp->ha);
+static adns_status cs_inthostaddr(vbuf *vb, adns_rrtype rrt, const void *datap) {
+  const adns_rr_inthostaddr *rrp= datap;
+  adns_status st;
+
+  st = csp_intofinthost(vb,rrp->i);  if (st) return st;
+  return csp_hostaddr(vb,rrt,&rrp->ha);
 }
 
 /*
  * _inthost  (cs)
  */
 
-static adns_status cs_inthost(vbuf *vb, const void *datap) {
+static adns_status cs_inthost(vbuf *vb, adns_rrtype rrt, const void *datap) {
   const adns_rr_intstr *rrp= datap;
-  char buf[10];
+  adns_status st;
 
-  sprintf(buf,"%u ",rrp->i);
-  CSP_ADDSTR(buf);
+  st = csp_intofinthost(vb,rrp->i);  if (st) return st;
   return csp_domain(vb,rrp->str);
 }
 
@@ -1281,6 +1290,7 @@ static adns_status pap_mailbox822(const parseinfo *pai,
                        pai->dgram, pai->dglen, max,
                        *cbyte_io, cbyte_io);
   st= adns__findlabel_next(&fls,&lablen,&labstart);
+  if (st) return st;
   if (!lablen) {
     adns__vbuf_appendstr(vb,".");
     goto x_ok;
@@ -1353,7 +1363,7 @@ static adns_status pa_rp(const parseinfo *pai, int cbyte,
   return adns_s_ok;
 }
 
-static adns_status cs_rp(vbuf *vb, const void *datap) {
+static adns_status cs_rp(vbuf *vb, adns_rrtype rrt, const void *datap) {
   const adns_rr_strpair *rrp= datap;
   adns_status st;
 
@@ -1373,7 +1383,7 @@ static adns_status pa_soa(const parseinfo *pai, int cbyte,
   adns_rr_soa *rrp= datap;
   const byte *dgram= pai->dgram;
   adns_status st;
-  int msw, lsw, i;
+  int i;
 
   st= pap_domain(pai, &cbyte, max, &rrp->mname,
                 pai->qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0);
@@ -1385,9 +1395,8 @@ static adns_status pa_soa(const parseinfo *pai, int cbyte,
   if (cbyte+20 != max) return adns_s_invaliddata;
   
   for (i=0; i<5; i++) {
-    GET_W(cbyte,msw);
-    GET_W(cbyte,lsw);
-    (&rrp->serial)[i]= (msw<<16) | lsw;
+    unsigned long v;
+    (&rrp->serial)[i]= GET_L(cbyte, v);
   }
 
   return adns_s_ok;
@@ -1400,7 +1409,7 @@ static void mf_soa(adns_query qu, void *datap) {
   adns__makefinal_str(qu,&rrp->rname);
 }
 
-static adns_status cs_soa(vbuf *vb, const void *datap) {
+static adns_status cs_soa(vbuf *vb, adns_rrtype rrt, const void *datap) {
   const adns_rr_soa *rrp= datap;
   char buf[20];
   int i;
@@ -1411,6 +1420,8 @@ static adns_status cs_soa(vbuf *vb, const void *datap) {
   st= csp_mailbox(vb,rrp->rname);  if (st) return st;
 
   for (i=0; i<5; i++) {
+    if (rrp->serial > 0xffffffffUL)
+      return adns_s_invaliddata;
     sprintf(buf," %lu",(&rrp->serial)[i]);
     CSP_ADDSTR(buf);
   }
@@ -1499,12 +1510,16 @@ static int di_srv(adns_state ads, const void *datap_a, const void *datap_b) {
 static adns_status csp_srv_begin(vbuf *vb, const adns_rr_srvha *rrp
                                   /* might be adns_rr_srvraw* */) {
   char buf[30];
+  if (rrp->priority < 0 || rrp->priority > 0xffff ||
+      rrp->weight   < 0 || rrp->weight   > 0xffff ||
+      rrp->port     < 0 || rrp->port     > 0xffff)
+    return adns_s_invaliddata;
   sprintf(buf,"%u %u %u ", rrp->priority, rrp->weight, rrp->port);
   CSP_ADDSTR(buf);
   return adns_s_ok;
 }
 
-static adns_status cs_srvraw(vbuf *vb, const void *datap) {
+static adns_status cs_srvraw(vbuf *vb, adns_rrtype rrt, const void *datap) {
   const adns_rr_srvraw *rrp= datap;
   adns_status st;
   
@@ -1512,12 +1527,12 @@ static adns_status cs_srvraw(vbuf *vb, const void *datap) {
   return csp_domain(vb,rrp->host);
 }
 
-static adns_status cs_srvha(vbuf *vb, const void *datap) {
+static adns_status cs_srvha(vbuf *vb, adns_rrtype rrt, const void *datap) {
   const adns_rr_srvha *rrp= datap;
   adns_status st;
 
   st= csp_srv_begin(vb,(const void*)datap);  if (st) return st;
-  return csp_hostaddr(vb,&rrp->ha);
+  return csp_hostaddr(vb,rrt,&rrp->ha);
 }
 
 static void postsort_srv(adns_state ads, void *array, int nrrs,int rrsz,
@@ -1608,12 +1623,15 @@ static adns_status pa_opaque(const parseinfo *pai, int cbyte,
   return adns_s_ok;
 }
 
-static adns_status cs_opaque(vbuf *vb, const void *datap) {
+static adns_status cs_opaque(vbuf *vb, adns_rrtype rrt, const void *datap) {
   const adns_rr_byteblock *rrp= datap;
   char buf[10];
   int l;
   unsigned char *p;
 
+  if (rrp->len < 0 || rrp->len > 0xffff)
+    return adns_s_invaliddata;
+
   sprintf(buf,"\\# %d",rrp->len);
   CSP_ADDSTR(buf);
   
@@ -1697,6 +1715,10 @@ DEEP_TYPE(unknown,0, "unknown",byteblock,opaque,  0,     opaque            );
 const typeinfo *adns__findtype(adns_rrtype type) {
   const typeinfo *begin, *end, *mid;
 
+  if (type & ~(adns_rrtype)0x63ffffff)
+    /* 0x60000000 is reserved for `harmless' future expansion */
+    return 0;
+
   if (type & adns_r_unknown) return &typeinfo_unknown;
   type &= adns_rrt_reprmask;