Halfway through IPv6 stuff. Most of the _rr_addr handling is left abandon.1999-04-11.ipv6
authorian <ian>
Sun, 11 Apr 1999 15:50:18 +0000 (15:50 +0000)
committerian <ian>
Sun, 11 Apr 1999 15:50:18 +0000 (15:50 +0000)
undone, but I think the interfaces are there now.  This is going on a
branch because glibc has no IPv6 yet ...

client/adnstest.c
src/adns.h
src/internal.h
src/query.c
src/transmit.c
src/types.c

index ea9ed2a..55b957c 100644 (file)
@@ -48,6 +48,7 @@ static const adns_rrtype defaulttypes[]= {
   adns_r_mx_raw,
   adns_r_txt,
   adns_r_rp_raw,
+  adns_r_aaaa,
   
   adns_r_addr,
   adns_r_ns,
index ce12fc2..5c347f9 100644 (file)
@@ -36,29 +36,70 @@ typedef struct adns__state *adns_state;
 typedef struct adns__query *adns_query;
 
 typedef enum {
-  adns_if_noenv=        0x0001, /* do not look at environment */
-  adns_if_noerrprint=   0x0002, /* never print output to stderr (_debug overrides) */
-  adns_if_noserverwarn= 0x0004, /* do not warn to stderr about duff nameservers etc */
-  adns_if_debug=        0x0008, /* enable all output to stderr plus debug msgs */
-  adns_if_noautosys=    0x0010, /* do not make syscalls at every opportunity */
-  adns_if_eintr=        0x0020, /* allow _wait and _synchronous to return EINTR */
+  adns_if_noenv=           0x0001, /* do not look at environment */
+  adns_if_noerrprint=      0x0002, /* never print output to stderr (_debug overrides) */
+  adns_if_noserverwarn=    0x0004, /* do not warn to stderr about duff nameservers etc */
+  adns_if_debug=           0x0008, /* enable all output to stderr plus debug msgs */
+  adns_if_noautosys=       0x0010, /* do not make syscalls at every opportunity */
+  adns_if_eintr=           0x0020, /* allow _wait and _synchronous to return EINTR */
+
+  /* Flags for address formatting, in both init and query.  Do not use directly. */
+  adns__iqaf_keepv4=      0x01000, /* If clear, any IPv4s will be mapped to AF_INET6 */
+  adns__iqaf_weakv6=      0x02000, /* `Prefer IPv6 less' - depends on other flags */
+  adns__iqaf_only=        0x04000, /* Return only one kind of address */
+  adns__iqaf_override=    0x08000, /* In query flags, means to ignore init flags */
+  adns__iqaf_mask=        0x07000, /* Mask of flags that _override overrides */
+
+  /* Actual address formatting options.  These set the default.  Do not combine them.
+   * Meanings are:
+   * _v6first:    Query for AAAA; if no AAAA then query for A.  Return all as AF_INET6.
+   * _v6first:    Same, but return IPv6 as AF_INET6 and IPv4 as AF_INET.
+   * _both:       Query for both A and AAAA, return all addresses as AF_INET6.
+   * _bothraw:    Same, but return IPv6 as AF_INET6 and IPv4 as AF_INET.
+   * _v4only:     Query only for A, and return as AF_INET.
+   * _v6only:     Query only for AAAA, and return as AF_INET6.
+   * If none is specified, the default is _v6first.
+   */
+  adns_if_addr_v6first=      0,
+  adns_if_addr_v6firstraw=                                     adns__iqaf_keepv4,
+  adns_if_addr_both=                         adns__iqaf_weakv6,
+  adns_if_addr_bothraw=                      adns__iqaf_weakv6|adns__iqaf_keepv4,
+  adns_if_addr_v4only=       adns__iqaf_only|adns__iqaf_weakv6|adns__iqaf_keepv4,
+  adns_if_addr_v6only=       adns__iqaf_only,
+
+  adns__if_internalmask=   0x7fff0000
 } adns_initflags;
 
 typedef enum {
-  adns_qf_search=          0x000001, /* use the searchlist */
-  adns_qf_usevc=           0x000002, /* use a virtual circuit (TCP connection) */
-  adns_qf_quoteok_query=   0x000010, /* allow quote-requiring chars in query domain */
-  adns_qf_quoteok_cname=   0x000020, /* allow ... in CNAME we go via */
-  adns_qf_quoteok_anshost= 0x000040, /* allow ... in answers expected to be hostnames */
-  adns_qf_cname_loose=     0x000100, /* allow refs to CNAMEs - without, get _s_cname */
-  adns_qf_cname_forbid=    0x000200, /* don't follow CNAMEs, instead give _s_cname */
-  adns__qf_internalmask=   0x0ff000
+  adns_qf_search=          0x0000001, /* use the searchlist */
+  adns_qf_usevc=           0x0000002, /* use a virtual circuit (TCP connection) */
+  adns_qf_quoteok_query=   0x0000010, /* allow quote-requiring chars in query domain */
+  adns_qf_quoteok_cname=   0x0000020, /* allow ... in CNAME we go via */
+  adns_qf_quoteok_anshost= 0x0000040, /* allow ... in answers expected to be hostnames */
+  adns_qf_cname_loose=     0x0000100, /* allow refs to CNAMEs - without, get _s_cname */
+  adns_qf_cname_forbid=    0x0000200, /* don't follow CNAMEs, instead give _s_cname */
+
+  /* Address formatting options.  They have the same meaning as the corresponding
+   * adns_if_... options.  Do not combine with other _if_addr/_qf_addr options.
+   * If a _qf_addr is specified then the _if_addr are irrelevant, otherwise the
+   * _if_addr are used.
+   */
+  adns_qf_addr_both=       adns__iqaf_override|adns_if_addr_both,
+  adns_qf_addr_bothraw=    adns__iqaf_override|adns_if_addr_bothraw,
+  adns_qf_addr_v6first=    adns__iqaf_override|adns_if_addr_v6first,
+  adns_qf_addr_v6firstraw= adns__iqaf_override|adns_if_addr_v6firstraw,
+  adns_qf_addr_v4only=     adns__iqaf_override|adns_if_addr_v4only,
+  adns_qf_addr_v6only=     adns__iqaf_override|adns_if_addr_v6only,
+  
+  adns__qf_internalmask=   0x7fff0000
 } adns_queryflags;
 
 typedef enum {
-  adns__rrt_typemask=  0x0ffff,
-  adns__qtf_deref=     0x10000, /* dereference domains and perhaps produce extra data */
-  adns__qtf_mail822=   0x20000, /* make mailboxes be in RFC822 rcpt field format */
+  adns__rrt_typemask=   0x0ffff,
+  adns__qtf_deref=      0x10000, /* dereference domains and perhaps produce extra data */
+  adns__qtf_mail822=    0x20000, /* make mailboxes be in RFC822 rcpt field format */
+  adns__qtf_nostdquery= 0x40000, /* do not make normal initial query */
+  adns__qtf_mask=   0x07fff0000,
   
   adns_r_none=               0,
   
@@ -85,7 +126,9 @@ typedef enum {
   adns_r_rp_raw=            17,
   adns_r_rp=                    adns_r_rp_raw|adns__qtf_mail822,
 
-  adns_r_addr=                  adns_r_a|adns__qtf_deref
+  adns_r_aaaa=              28,
+  
+  adns_r_addr=                  adns_r_a|adns__qtf_nostdquery
   
 } adns_rrtype;
 
@@ -152,7 +195,8 @@ typedef struct {
   int len;
   union {
     struct sockaddr sa;
-    struct sockaddr_in inet;
+    struct sockaddr_in inet; /* port field will be zero */
+    struct sockaddr_in6 inet6; /* port field will be zero */
   } addr;
 } adns_rr_addr;
 
@@ -203,6 +247,7 @@ typedef struct {
     adns_rr_intstr *(*manyistr);      /* txt (list of strings ends with i=-1, str=0) */
     adns_rr_addr *addr;               /* addr */
     struct in_addr *inaddr;           /* a */
+    struct in_addr6 *inaddr6;         /* aaaa */
     adns_rr_hostaddr *hostaddr;       /* ns */
     adns_rr_intstrpair *intstrpair;   /* hinfo */
     adns_rr_strpair *strpair;         /* rp, rp_raw */
@@ -269,7 +314,6 @@ int adns_wait(adns_state ads,
              adns_answer **answer_r,
              void **context_r);
 /* fixme: include TTL in answer somehow */
-/* fixme: multithreading/locking */
 /* fixme: easy way to get lists of fd's */
 /* fixme: IPv6 */
 
index f0f9147..59bfeb7 100644 (file)
@@ -120,6 +120,24 @@ typedef struct {
   /* Returns !0 if RR a should be strictly after RR b in the sort order,
    * 0 otherwise.  Must not fail.
    */
+
+  /* Now come a number of hooks which are usually zero.  They are used by
+   * query types which need special processing, like adns_rr_addr.
+   */
+
+  int (*initqtype)(adns_state ads, adns_queryflags flags);
+  /* Returns the typecode (DNS, not adns_rr_type) for the initial
+   * query.  The general code will always construct a query datagram
+   * for the owner domain specified in _submit.
+   * If !initqtype then (typeinfo->type & adns__rrt_typemask) is used.
+   */
+  
+  adns_status (*begin)(adns_state ads, adns_query qu, struct timeval now);
+  /* Alternative `query start' function.  If !begin then the general code
+   * will try to send the initial query datagram by UDP to a nameserver.
+   * If it returns an error then the original _submit will too; it may
+   * also choose to fail the query.
+   */
 } typeinfo;
 
 typedef struct allocnode {
@@ -247,11 +265,9 @@ struct adns__state {
   int nservers, nsortlist, tcpserver;
   enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate;
   struct timeval tcptimeout;
-  struct server {
-    struct in_addr addr;
-  } servers[MAXSERVERS];
+  adns_rr_addr servers[MAXSERVERS]; /* port fields will be 53 here */
   struct sortlist {
-    struct in_addr base, mask;
+    struct in_addr6 base, mask;
   } sortlist[MAXSORTLIST];
 };
 
@@ -315,6 +331,15 @@ adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r,
  * That domain must be correct and untruncated.
  */
 
+adns_status adns__subquery(adns_state ads, adns_query parent, vbuf *vb,
+                          const byte *qd_dgram, int qd_dglen, int qd_begin,
+                          adns_rrtype type, adns_queryflags flags,
+                          struct timeval now, const qcontext *ctx);
+/* Constructs a query datagram using _mkquery_frdgram, as above, and then
+ * makes the query an internal one with parent qu and sends it off.
+ * vbuf is used as a buffer to construct the query, and will be overwritten.
+ */
+  
 void adns__query_tcp(adns_query qu, struct timeval now);
 /* Query must be in state tcpwait/timew; it will be moved to a new state
  * if possible and no further processing can be done on it for now.
@@ -323,7 +348,7 @@ void adns__query_tcp(adns_query qu, struct timeval now);
  *
  * adns__tcp_tryconnect should already have been called - _tcp
  * will only use an existing connection (if there is one), which it
- * may break.  If the conn list lost then the caller is responsible for any
+ * may break.  If the conn is lost then the caller is responsible for any
  * reestablishment and retry.
  */
 
index 545feec..ffe346d 100644 (file)
@@ -87,12 +87,16 @@ int adns__internal_submit(adns_state ads, adns_query *query_r,
   }
   qu->vb= *qumsg_vb;
   adns__vbuf_init(qumsg_vb);
+
+  if (failstat) goto x_failure;
   
-  if (failstat) {
-    adns__query_fail(qu,failstat);
-    return adns_s_ok;
+  if (qu->typei->begin) {
+    failstat= qu->typei->begin(ads,qu,now);
+    if (failstat) goto x_failure;
+  } else {
+    adns__query_udp(qu,now);
   }
-  adns__query_udp(qu,now);
+
   adns__autosys(ads,now);
 
   return adns_s_ok;
@@ -102,6 +106,33 @@ int adns__internal_submit(adns_state ads, adns_query *query_r,
  x_nomemory:
   adns__vbuf_free(qumsg_vb);
   return adns_s_nomemory;
+
+ x_failure:
+  adns__query_fail(qu,failstat);
+  return adns_s_ok;
+}
+
+adns_status adns__subquery(adns_state ads, adns_query parent, vbuf *vb,
+                          const byte *qd_dgram, int qd_dglen, int qd_begin,
+                          adns_rrtype type, adns_queryflags flags,
+                          struct timeval now, const qcontext *ctx) {
+  adns_status st;
+  int id;
+  adns_query nqu;
+  
+  st= adns__mkquery_frdgram(ads, vb, &id,
+                           qd_dgram, qd_dglen, qd_begin,
+                           type, flags);
+  if (st) return st;
+  
+  st= adns__internal_submit(ads, &nqu, adns__findtype(type),
+                           vb, id, flags, now, 0, ctx);
+  if (st) return st;
+
+  nqu->parent= parent;
+  LIST_LINK_TAIL_PART(parent->children,nqu,siblings.);
+
+  return adns_s_ok;
 }
 
 int adns_submit(adns_state ads,
@@ -127,6 +158,11 @@ int adns_submit(adns_state ads,
   r= gettimeofday(&now,0); if (r) return errno;
   id= 0;
 
+  if (!(flags & adns__iqaf_override)) {
+    flags &= ~adns__iqaf_mask;
+    flags |= ads->iflags & adns__iqaf_mask;
+  }
+
   adns__vbuf_init(&vb);
 
   ol= strlen(owner);
@@ -134,7 +170,9 @@ int adns_submit(adns_state ads,
                                 
   if (owner[ol-1]=='.' && owner[ol-2]!='\\') { flags &= ~adns_qf_search; ol--; }
 
-  stat= adns__mkquery(ads,&vb,&id, owner,ol, typei,flags);
+
+                    typei->initialtype ? typei->initialtype(ads,flags) : typei->type
+                      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);       
index d3978c3..4f7d680 100644 (file)
@@ -71,7 +71,8 @@ static adns_status mkquery_footer(vbuf *vb, adns_rrtype type) {
 
 adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
                          const char *owner, int ol,
-                         const typeinfo *typei, adns_queryflags flags) {
+                         const typeinfo *typei, adns_rr_type typecode,
+                         adns_queryflags flags) {
   int ll, c, nlabs;
   byte label[255], *rqp;
   const char *p, *pe;
@@ -118,8 +119,8 @@ adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
   MKQUERY_ADDB(0);
 
   MKQUERY_STOP(vb);
-  
-  st= mkquery_footer(vb,typei->type);
+
+  st= mkquery_footer(vb,typecode);
   
   return adns_s_ok;
 }
index bd87450..5f15c6d 100644 (file)
@@ -281,7 +281,37 @@ static adns_status cs_inaddr(vbuf *vb, const void *datap) {
 }
 
 /*
- * _addr   (pa,di,csp,cs)
+ * _inaddr6   (pa,dip,di)
+ */
+
+static adns_status pa_inaddr6(const parseinfo *pai, int cbyte, int max, void *datap) {
+  struct in_addr6 *storeto= datap;
+  
+  if (max-cbyte != 16) return adns_s_invaliddata;
+  memcpy(storeto, pai->dgram + cbyte, 16);
+  return adns_s_ok;
+}
+
+static int dip_inaddr6(adns_state ads, struct in_addr a, struct in_addr b) {
+  return 0;
+}
+
+static int di_inaddr6(adns_state ads, const void *datap_a, const void *datap_b) {
+  const struct in_addr6 *ap= datap_a, *bp= datap_b;
+
+  return dip_inaddr6(ads,*ap,*bp);
+}
+
+static adns_status cs_inaddr6(vbuf *vb, const void *datap) {
+  char buf[INET6_ADDRSTRLEN], *ia;
+
+  ia= inet_ntop(AF_INET6,datap,buf,sizeof(buf); assert(ia);
+  CSP_ADDSTR(ia);
+  return adns_s_ok;
+}
+
+/*
+ * _addr   (pa,di,csp,cs, iq,bg)
  */
 
 static adns_status pa_addr(const parseinfo *pai, int cbyte, int max, void *datap) {
@@ -299,8 +329,25 @@ static adns_status pa_addr(const parseinfo *pai, int cbyte, int max, void *datap
 static int di_addr(adns_state ads, const void *datap_a, const void *datap_b) {
   const adns_rr_addr *ap= datap_a, *bp= datap_b;
 
-  assert(ap->addr.sa.sa_family == AF_INET);
-  return dip_inaddr(ads, ap->addr.inet.sin_addr, bp->addr.inet.sin_addr);
+  switch (ap->addr.sa.sa_family) {
+  case AF_INET6:
+    switch (bp->addr.sa.sa_family) {
+    case AF_INET6:
+      return dip_inaddr6(ads, ap->addr.inet6.sin_addr, bp->addr.inet6.sin_addr);
+    case AF_INET:
+      return 0;
+    }
+    break;
+  case AF_INET:
+    switch (bp->addr.sa.sa_family) {
+    case AF_INET:
+      return dip_inaddr(ads, ap->addr.inet.sin_addr, bp->addr.inet.sin_addr);
+    case AF_INET6:
+      return 1;
+    }
+    break;
+  }
+  abort();
 }
 
 static int div_addr(void *context, const void *datap_a, const void *datap_b) {
@@ -311,12 +358,25 @@ static int div_addr(void *context, const void *datap_a, const void *datap_b) {
 
 static adns_status csp_addr(vbuf *vb, const adns_rr_addr *rrp) {
   const char *ia;
-  static char buf[30];
+  static char buf[INET6_ADDRSTRLEN];
 
   switch (rrp->addr.inet.sin_family) {
   case AF_INET:
     CSP_ADDSTR("AF_INET ");
-    ia= inet_ntoa(rrp->addr.inet.sin_addr); assert(ia);
+    ia= inet_ntoa(rrp->addr.inet.sin_addr);
+    assert(ia);
+    CSP_ADDSTR(ia);
+    break;
+  case AF_INET6:
+    if (IN6_IS_ADDR_V4MAPPED(&rrp->addr.inet6.sin6_addr)) {
+      CSP_ADDSTR("IPv6-mapped-IPv4 ");
+      ia= inet_ntoa(*(struct in_addr*)(rrp->addr.inet6.sin6_addr.s6_addr+12));
+      assert(ia);
+    } else {
+      CSP_ADDSTR("AF_INET6 ");
+      ia= inet_ntop(AF_INET6,&rrp->addr.inet.sin6_addr,buf,sizeof(buf));
+      assert(ia);
+    }
     CSP_ADDSTR(ia);
     break;
   default:
@@ -333,6 +393,31 @@ static adns_status cs_addr(vbuf *vb, const void *datap) {
   return csp_addr(vb,rrp);
 }
 
+static int iq_addr(adns_state ads, adns_queryflags flags) {
+  if (~flags & (adns__iqaf_only|adns__iqaf_weakv6)) {
+    return adns_rr_aaaa;
+  } else {
+    return adns_rr_a;
+  }
+}
+
+static adns_status bg_addr(adns_state ads, adns_query qu, struct timeval now) {
+  qcontext ctx;
+    
+  if (!((flags^adns__iqaf_weakv6) & (adns__iqaf_weakv6|adns__iqaf_only))) {
+    ctx.ext= 0;
+    ctx.callback= icb_addr4;
+
+    st= adns__subquery(ads, qu, qu->vb,
+                      qu->query_dgram, query_dglen, DNS_HDRSIZE,
+                      adns_rr_a, qu->flags, now, &ctx);
+    if (!st) return st;
+  }
+  adns__query_udp(qu,now);
+  
+  return adns_s_ok;
+}
+
 /*
  * _domain  (pap)
  */
@@ -429,10 +514,8 @@ static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io,
                                int max, adns_rr_hostaddr *rrp) {
   adns_status st;
   int dmstart, cbyte;
-  qcontext ctx;
-  int id;
-  adns_query nqu;
   adns_queryflags nflags;
+  qcontext ctx;
 
   dmstart= cbyte= *cbyte_io;
   st= pap_domain(pai, &cbyte, max, &rrp->host,
@@ -453,25 +536,18 @@ static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io,
   st= pap_findaddrs(pai, rrp, &cbyte, pai->arcount, dmstart);
   if (st) return st;
   if (rrp->naddrs != -1) return adns_s_ok;
-
-  st= adns__mkquery_frdgram(pai->ads, &pai->qu->vb, &id,
-                           pai->dgram, pai->dglen, dmstart,
-                           adns_r_addr, adns_qf_quoteok_query);
-  if (st) return st;
+  
+  nflags= adns_qf_quoteok_query;
+  if (!(pai->qu->flags & adns_qf_cname_loose)) nflags |= adns_qf_cname_forbid;
 
   ctx.ext= 0;
   ctx.callback= icb_hostaddr;
   ctx.info.hostaddr= rrp;
-  
-  nflags= adns_qf_quoteok_query;
-  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);
-  if (st) return st;
 
-  nqu->parent= pai->qu;
-  LIST_LINK_TAIL_PART(pai->qu->children,nqu,siblings.);
+  st= adns__subquery(pai->ads, pai->qu, pai->qu->vb,
+                    pai->dgram, pai->dglen, dmstart,
+                    adns_r_addr, nflags, now, &ctx);
+  if (st) return st;
 
   return adns_s_ok;
 }
@@ -875,35 +951,42 @@ static void mf_flat(adns_query qu, void *data) { }
 
 #define TYPESZ_M(member)           (sizeof(*((adns_answer*)0)->rrs.member))
 
-#define DEEP_MEMB(memb) TYPESZ_M(memb), mf_##memb, cs_##memb
-#define FLAT_MEMB(memb) TYPESZ_M(memb), mf_flat, cs_##memb
+#define ANY_TYPE(code,rrt,fmt,memb,makefinal,parser,comparer, initqcode,begin) \
+ { adns_r_##code, rrt, fmt, TYPESZ_M(memb), makefinal, cs_##memb, parser, comparer, \
+   initqcode, begin }
 
 #define DEEP_TYPE(code,rrt,fmt,memb,parser,comparer) \
- { adns_r_##code, rrt, fmt, TYPESZ_M(memb), mf_##memb, cs_##memb, parser, comparer }
+ ANY_TYPE(code,rrt,fmt,memb, mf_##memb,parser,comparer, 0,0)
 #define FLAT_TYPE(code,rrt,fmt,memb,parser,comparer) \
- { adns_r_##code, rrt, fmt, TYPESZ_M(memb), mf_flat, cs_##memb, parser, comparer }
+ ANY_TYPE(code,rrt,fmt,memb, mf_flat,parser,comparer, 0,0)
+
+#define DEEP_SPEC(code,rrt,fmt,memb,parser,comparer) \
+ ANY_TYPE(code,rrt,fmt,memb, mf_##memb,parser,comparer, iq_##memb,bg_##memb)
+#define FLAT_SPEC(code,rrt,fmt,memb,parser,comparer) \
+ ANY_TYPE(code,rrt,fmt,memb, mf_flat,parser,comparer, iq_##memb,bg_##memb)
 
 static const typeinfo typeinfos[] = {
-/* Must be in ascending order of rrtype ! */
-/* mem-mgmt code     rrt     fmt      member       parser        comparer    */
-                                                            
-  FLAT_TYPE(a,       "A",     0,      inaddr,      pa_inaddr,    di_inaddr   ),
-  DEEP_TYPE(ns_raw,  "NS",   "raw",   str,         pa_host_raw,  0           ),
-  DEEP_TYPE(cname,   "CNAME", 0,      str,         pa_host_raw,  0           ),
-  DEEP_TYPE(soa_raw, "SOA",  "raw",   soa,         pa_soa,       0           ),
-  DEEP_TYPE(ptr_raw, "PTR",  "raw",   str,         pa_host_raw,  0           ),
-  DEEP_TYPE(hinfo,   "HINFO", 0,      intstrpair,  pa_hinfo,     0           ),
-  DEEP_TYPE(mx_raw,  "MX",   "raw",   intstr,      pa_mx_raw,    di_mx_raw   ),
-  DEEP_TYPE(txt,     "TXT",   0,      manyistr,    pa_txt,       0           ),
-  DEEP_TYPE(rp_raw,  "RP",   "raw",   strpair,     pa_rp,        0           ),
-                                                                                    
-  FLAT_TYPE(addr,    "A",  "addr",    addr,        pa_addr,      di_addr     ),
-  DEEP_TYPE(ns,      "NS", "+addr",   hostaddr,    pa_hostaddr,  di_hostaddr ),
-  DEEP_TYPE(ptr,     "PTR","checked", str,         pa_ptr,       0           ),
-  DEEP_TYPE(mx,      "MX", "+addr",   inthostaddr, pa_mx,        di_mx       ),
-                                                                          
-  DEEP_TYPE(soa,     "SOA","822",     soa,         pa_soa,       0           ),
-  DEEP_TYPE(rp,      "RP", "822",     strpair,     pa_rp,        0           ),
+/* Must be in ascending order of code ! */
+/* mem-mgmt code     rrt     fmt        member       parser       comparer    */
+                                                                 
+  FLAT_TYPE(a,       "A",     0,        inaddr,      pa_inaddr,   di_inaddr   ),
+  DEEP_TYPE(ns_raw,  "NS",   "raw",     str,         pa_host_raw, 0           ),
+  DEEP_TYPE(cname,   "CNAME", 0,        str,         pa_host_raw, 0           ),
+  DEEP_TYPE(soa_raw, "SOA",  "raw",     soa,         pa_soa,      0           ),
+  DEEP_TYPE(ptr_raw, "PTR",  "raw",     str,         pa_host_raw, 0           ),
+  DEEP_TYPE(hinfo,   "HINFO", 0,        intstrpair,  pa_hinfo,    0           ),
+  DEEP_TYPE(mx_raw,  "MX",   "raw",     intstr,      pa_mx_raw,   di_mx_raw   ),
+  DEEP_TYPE(txt,     "TXT",   0,        manyistr,    pa_txt,      0           ),
+  DEEP_TYPE(rp_raw,  "RP",   "raw",     strpair,     pa_rp,       0           ),
+  FLAT_TYPE(aaaa,    "AAAA",  0,        inaddr6,     pa_inaddr6,  di_inaddr6  ),
+                                                                              
+  FLAT_SPEC(addr,    "addr",  0,        addr,        pa_addr,     di_addr     ),
+  DEEP_TYPE(ns,      "NS",   "+addr",   hostaddr,    pa_hostaddr, di_hostaddr ),
+  DEEP_TYPE(ptr,     "PTR",  "checked", str,         pa_ptr,      0           ),
+  DEEP_TYPE(mx,      "MX",   "+addr",   inthostaddr, pa_mx,       di_mx       ),
+                                                                              
+  DEEP_TYPE(soa,     "SOA",  "822",     soa,         pa_soa,      0           ),
+  DEEP_TYPE(rp,      "RP",   "822",     strpair,     pa_rp,       0           ),
 };
 
 const typeinfo *adns__findtype(adns_rrtype type) {