chiark / gitweb /
unknown rr types seem to work
authorian <ian>
Fri, 7 Apr 2006 00:25:14 +0000 (00:25 +0000)
committerian <ian>
Fri, 7 Apr 2006 00:25:14 +0000 (00:25 +0000)
13 files changed:
TODO
changelog
client/adh-main.c
client/adh-opts.c
client/adh-query.c
client/adnshost.h
client/adnstest.c
src/adns.h
src/internal.h
src/query.c
src/reply.c
src/transmit.c
src/types.c

diff --git a/TODO b/TODO
index 7d1b81f..596ce28 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,5 +1,4 @@
 WISHLIST:
 WISHLIST:
-* Support for as-yet-unrecognised query types.
 * Make timeouts configurable.
 * `fake' reverse queries (give nnn.nnn.nnn.nnn either always or on error)
 * `fake' forward queries (allow nnn.nnn.nnn.nnn -> A)
 * Make timeouts configurable.
 * `fake' reverse queries (give nnn.nnn.nnn.nnn either always or on error)
 * `fake' forward queries (allow nnn.nnn.nnn.nnn -> A)
index 8c245b1..e1fff88 100644 (file)
--- a/changelog
+++ b/changelog
@@ -18,7 +18,8 @@ adns (1.1.999.0.2); urgency=medium
   * Provide adns_if_none and adns_qf_none (which will help with compilers
     which complain about plain `0' being passed where an enum is wanted).
 
   * Provide adns_if_none and adns_qf_none (which will help with compilers
     which complain about plain `0' being passed where an enum is wanted).
 
- * Support for SRV RRs.
+  * Support for SRV RRs.
+  * Support for unknown RR types (according to RFC3597).
 
  --
 
 
  --
 
index 7065d58..49df6f5 100644 (file)
@@ -111,6 +111,14 @@ void of_type(const struct optioninfo *oi, const char *arg, const char *arg2) {
   };
 
   const struct typename *tnp;
   };
 
   const struct typename *tnp;
+  unsigned long unknowntype;
+  char *ep;
+
+  if (strlen(arg) > 4 && !memcmp(arg,"type",4) &&
+      (unknowntype= strtoul(arg+4, &ep, 10), !*ep) && unknowntype < 65536) {
+    ov_type= unknowntype | adns_r_unknown;
+    return;
+  }
 
   for (tnp=typenames;
        tnp->type && strcmp(arg,tnp->desc);
 
   for (tnp=typenames;
        tnp->type && strcmp(arg,tnp->desc);
index a649037..1a46bae 100644 (file)
@@ -266,6 +266,7 @@ static void printusage(void) {
        "  ns  soa  ptr  mx  rp  srv  addr       - enhanced versions\n"
        "  cname  hinfo  txt                     - types with only one version\n"
        "  a  ns-  soa-  ptr-  mx-  rp-  srv-    - _raw versions\n"
        "  ns  soa  ptr  mx  rp  srv  addr       - enhanced versions\n"
        "  cname  hinfo  txt                     - types with only one version\n"
        "  a  ns-  soa-  ptr-  mx-  rp-  srv-    - _raw versions\n"
+       "  type<number>                          - `unknown' type, RFC3597\n"
        "Default is addr, or ptr for -i/--ptr queries\n",
        stdout);
   if (ferror(stdout)) sysfail("write usage message",errno);
        "Default is addr, or ptr for -i/--ptr queries\n",
        stdout);
   if (ferror(stdout)) sysfail("write usage message",errno);
index d17beab..b366697 100644 (file)
@@ -55,6 +55,20 @@ void ensure_adns_init(void) {
     ov_format= ov_asynch ? fmt_asynch : fmt_simple;
 }
 
     ov_format= ov_asynch ? fmt_asynch : fmt_simple;
 }
 
+void type_info(adns_rrtype type, const char **typename_r,
+              const void *datap, char **data_r) {
+  static char buf[12];
+  adns_status st;
+  
+  st= adns_rr_info(type, typename_r, 0,0, datap,data_r);
+  if (st == adns_s_nomemory) sysfail("adns_rr_info failed",ENOMEM);
+  assert(!st);
+  if (typename_r && !*typename_r) {
+    sprintf(buf,"TYPE%d", (int)(type & adns_rrt_typemask));
+    *typename_r= buf;
+  }
+}
+
 static void prep_query(struct query_node **qun_r, int *quflags_r) {
   struct query_node *qun;
   char idbuf[20];
 static void prep_query(struct query_node **qun_r, int *quflags_r) {
   struct query_node *qun;
   char idbuf[20];
@@ -221,7 +235,6 @@ static void print_status(adns_status st, struct query_node *qun, adns_answer *an
 static void print_dnsfail(adns_status st, struct query_node *qun, adns_answer *answer) {
   int r;
   const char *typename, *statusstring;
 static void print_dnsfail(adns_status st, struct query_node *qun, adns_answer *answer) {
   int r;
   const char *typename, *statusstring;
-  adns_status ist;
   
   if (ov_format == fmt_inline) {
     if (fputs("; failed ",stdout) == EOF) outerr();
   
   if (ov_format == fmt_inline) {
     if (fputs("; failed ",stdout) == EOF) outerr();
@@ -232,7 +245,7 @@ static void print_dnsfail(adns_status st, struct query_node *qun, adns_answer *a
   if (st == adns_s_nxdomain) {
     r= fprintf(stderr,"%s does not exist\n", owner_show(qun,answer));
   } else {
   if (st == adns_s_nxdomain) {
     r= fprintf(stderr,"%s does not exist\n", owner_show(qun,answer));
   } else {
-    ist= adns_rr_info(answer->type, &typename, 0,0,0,0);
+    type_info(answer->type, &typename, 0,0);
     if (st == adns_s_nodata) {
       r= fprintf(stderr,"%s has no %s record\n", owner_show(qun,answer), typename);
     } else {
     if (st == adns_s_nodata) {
       r= fprintf(stderr,"%s has no %s record\n", owner_show(qun,answer), typename);
     } else {
@@ -245,7 +258,7 @@ static void print_dnsfail(adns_status st, struct query_node *qun, adns_answer *a
 }
     
 void query_done(struct query_node *qun, adns_answer *answer) {
 }
     
 void query_done(struct query_node *qun, adns_answer *answer) {
-  adns_status st, ist;
+  adns_status st;
   int rrn, nrrs;
   const char *rrp, *realowner, *typename;
   char *datastr;
   int rrn, nrrs;
   const char *rrp, *realowner, *typename;
   char *datastr;
@@ -279,9 +292,7 @@ void query_done(struct query_node *qun, adns_answer *answer) {
         rrn++, rrp += answer->rrsz) {
       if (realowner) print_withspace(realowner);
       print_ttl(qun,answer);
         rrn++, rrp += answer->rrsz) {
       if (realowner) print_withspace(realowner);
       print_ttl(qun,answer);
-      ist= adns_rr_info(answer->type, &typename, 0, 0, rrp, &datastr);
-      if (ist == adns_s_nomemory) sysfail("adns_rr_info failed",ENOMEM);
-      assert(!ist);
+      type_info(answer->type,&typename, rrp,&datastr);
       if (qun->pqfr.show_type) print_withspace(typename);
       if (printf("%s\n",datastr) == EOF) outerr();
       free(datastr);
       if (qun->pqfr.show_type) print_withspace(typename);
       if (printf("%s\n",datastr) == EOF) outerr();
       free(datastr);
index a8da4ff..30dd481 100644 (file)
@@ -108,6 +108,12 @@ void ensure_adns_init(void);
 void query_do(const char *domain);
 void query_done(struct query_node *qun, adns_answer *answer);
 
 void query_do(const char *domain);
 void query_done(struct query_node *qun, adns_answer *answer);
 
+void type_info(adns_rrtype type, const char **typename_r,
+              const void *datap, char **data_r);
+  /* wrapper for adns_rr_info which uses a static buffer to provide
+   * *typename_r for adns_r_unknown */
+
+
 /* declarations related to main program and useful utility functions */
 
 void sysfail(const char *what, int errnoval) NONRETURNING;
 /* declarations related to main program and useful utility functions */
 
 void sysfail(const char *what, int errnoval) NONRETURNING;
index 36d7ffe..cbc87bb 100644 (file)
@@ -136,7 +136,7 @@ static const adns_rrtype defaulttypes[]= {
 
 static void dumptype(adns_status ri, const char *rrtn, const char *fmtn) {
   fprintf(stdout, "%s(%s)%s%s",
 
 static void dumptype(adns_status ri, const char *rrtn, const char *fmtn) {
   fprintf(stdout, "%s(%s)%s%s",
-         ri ? "?" : rrtn, ri ? "?" : fmtn ? fmtn : "-",
+         rrtn ? "?" : rrtn, ri ? "?" : fmtn ? fmtn : "-",
          ri ? " " : "", ri ? adns_strerror(ri) : "");
 }
 
          ri ? " " : "", ri ? adns_strerror(ri) : "");
 }
 
index 65edbd8..a29b568 100644 (file)
@@ -104,25 +104,28 @@ typedef enum { /* In general, or together the desired flags: */
 } adns_queryflags;
 
 typedef enum {
 } adns_queryflags;
 
 typedef enum {
- adns__rrt_typemask=0x0ffff,
+ adns_rrt_typemask=  0x0ffff,
  adns__qtf_deref=    0x10000,/* dereference domains; perhaps get extra data */
  adns__qtf_mail822=  0x20000,/* return mailboxes in RFC822 rcpt field fmt   */
 
  adns_r_unknown=     0x40000,
    /* To use this, ask for records of type   <rr-type-code>|adns_r_unknown.
  adns__qtf_deref=    0x10000,/* dereference domains; perhaps get extra data */
  adns__qtf_mail822=  0x20000,/* return mailboxes in RFC822 rcpt field fmt   */
 
  adns_r_unknown=     0x40000,
    /* To use this, ask for records of type   <rr-type-code>|adns_r_unknown.
-    * adns will not process the RDATA at all - you'll get intstr's, where
-    * the int is the length and the char* points to the data.  String
-    * representation of the RR data is as in RFC3597.  adns_rr_info
-    * will not return the type name in *rrtname_r (due to memory management
-    * problems); *fmtname_r will be set to "unknown".
+    * adns will not process the RDATA - you'll get adns_rr_byteblocks,
+    * where the int is the length and the unsigned char* points to the
+    * data.  String representation of the RR data (by adns_rrinfo) is as in
+    * RFC3597.  adns_rr_info will not return the type name in *rrtname_r
+    * (due to memory management problems); *fmtname_r will be set to
+    * "unknown".
     *
     * Do not specify adns_r_unknown along with a known RR type which
     *
     * Do not specify adns_r_unknown along with a known RR type which
-    * requires domain name uncompression.  Domain names will not be
-    * uncompressed and the resulting data will be useless.  Asking for
-    * meta-RR types via adns_r_unknown will not work properly either
-    * and may make adns complain about server misbehaviour.
-    */
-                    
+    * requires domain name uncompression (see RFC3597 s4); domain names
+    * will not be uncompressed and the resulting data would be useless.
+    * Asking for meta-RR types via adns_r_unknown will not work properly
+    * either and may make adns complain about server misbehaviour, so don't
+    * do that.
+    *
+    * Don't forget adns_qf_quoteok if that's what you want. */
+
  adns_r_none=             0,
                     
  adns_r_a=                1,
  adns_r_none=             0,
                     
  adns_r_a=                1,
@@ -333,6 +336,11 @@ typedef struct {
 } adns_rr_srvha;
 
 typedef struct {
 } adns_rr_srvha;
 
 typedef struct {
+  int len;
+  unsigned char *data;
+} adns_rr_byteblock;
+
+typedef struct {
   adns_status status;
   char *cname; /* always NULL if query was for CNAME records */
   char *owner; /* only set if req'd in query flags; maybe 0 on error anyway */
   adns_status status;
   char *cname; /* always NULL if query was for CNAME records */
   char *owner; /* only set if req'd in query flags; maybe 0 on error anyway */
@@ -350,10 +358,11 @@ typedef struct {
     adns_rr_intstrpair *intstrpair;  /* hinfo */
     adns_rr_strpair *strpair;        /* rp, rp_raw */
     adns_rr_inthostaddr *inthostaddr;/* mx */
     adns_rr_intstrpair *intstrpair;  /* hinfo */
     adns_rr_strpair *strpair;        /* rp, rp_raw */
     adns_rr_inthostaddr *inthostaddr;/* mx */
-    adns_rr_intstr *intstr;          /* mx_raw, ...|unknown */
+    adns_rr_intstr *intstr;          /* mx_raw */
     adns_rr_soa *soa;                /* soa, soa_raw */
     adns_rr_srvraw *srvraw;          /* srv_raw */
     adns_rr_srvha *srvha;/* srv */
     adns_rr_soa *soa;                /* soa, soa_raw */
     adns_rr_srvraw *srvraw;          /* srv_raw */
     adns_rr_srvha *srvha;/* srv */
+    adns_rr_byteblock *byteblock;    /* ...|unknown */
   } rrs;
 } adns_answer;
 
   } rrs;
 } adns_answer;
 
index e4ec09e..eebf2a0 100644 (file)
@@ -114,7 +114,7 @@ typedef struct {
 } parseinfo;
 
 typedef struct typeinfo {
 } parseinfo;
 
 typedef struct typeinfo {
-  adns_rrtype type;
+  adns_rrtype typekey;
   const char *rrtname;
   const char *fmtname;
   int rrsz;
   const char *rrtname;
   const char *fmtname;
   int rrsz;
@@ -404,7 +404,8 @@ void adns__sigpipe_unprotect(adns_state);
 
 adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
                          const char *owner, int ol,
 
 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_rrtype type,
+                         adns_queryflags flags);
 /* Assembles a query packet in vb.  A new id is allocated and returned.
  */
 
 /* Assembles a query packet in vb.  A new id is allocated and returned.
  */
 
index 0b62ff6..4b24a30 100644 (file)
@@ -37,7 +37,8 @@
 
 #include "internal.h"
 
 
 #include "internal.h"
 
-static adns_query query_alloc(adns_state ads, const typeinfo *typei,
+static adns_query query_alloc(adns_state ads,
+                             const typeinfo *typei, adns_rrtype type,
                              adns_queryflags flags, struct timeval now) {
   /* Allocate a virgin query and return it. */
   adns_query qu;
                              adns_queryflags flags, struct timeval now) {
   /* Allocate a virgin query and return it. */
   adns_query qu;
@@ -79,7 +80,7 @@ static adns_query query_alloc(adns_state ads, const typeinfo *typei,
 
   qu->answer->status= adns_s_ok;
   qu->answer->cname= qu->answer->owner= 0;
 
   qu->answer->status= adns_s_ok;
   qu->answer->cname= qu->answer->owner= 0;
-  qu->answer->type= typei->type;
+  qu->answer->type= type;
   qu->answer->expires= -1;
   qu->answer->nrrs= 0;
   qu->answer->rrs.untyped= 0;
   qu->answer->expires= -1;
   qu->answer->nrrs= 0;
   qu->answer->rrs.untyped= 0;
@@ -115,7 +116,7 @@ adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
                                  const qcontext *ctx) {
   adns_query qu;
 
                                  const qcontext *ctx) {
   adns_query qu;
 
-  qu= query_alloc(ads,typei,flags,now);
+  qu= query_alloc(ads,typei,typei->typekey,flags,now);
   if (!qu) { adns__vbuf_free(qumsg_vb); return adns_s_nomemory; }
   *query_r= qu;
 
   if (!qu) { adns__vbuf_free(qumsg_vb); return adns_s_nomemory; }
   *query_r= qu;
 
@@ -133,7 +134,8 @@ static void query_simple(adns_state ads, adns_query qu,
   int id;
   adns_status stat;
 
   int id;
   adns_status stat;
 
-  stat= adns__mkquery(ads,&qu->vb,&id, owner,ol, typei,flags);
+  stat= adns__mkquery(ads,&qu->vb,&id, owner,ol,
+                     typei,qu->answer->type, flags);
   if (stat) {
     if (stat == adns_s_querydomaintoolong && (flags & adns_qf_search)) {
       adns__search_next(ads,qu,now);
   if (stat) {
     if (stat == adns_s_querydomaintoolong && (flags & adns_qf_search)) {
       adns__search_next(ads,qu,now);
@@ -225,7 +227,7 @@ int adns_submit(adns_state ads,
   if (!typei) return ENOSYS;
 
   r= gettimeofday(&now,0); if (r) goto x_errno;
   if (!typei) return ENOSYS;
 
   r= gettimeofday(&now,0); if (r) goto x_errno;
-  qu= query_alloc(ads,typei,flags,now); if (!qu) goto x_errno;
+  qu= query_alloc(ads,typei,type,flags,now); if (!qu) goto x_errno;
   
   qu->ctx.ext= context;
   qu->ctx.callback= 0;
   
   qu->ctx.ext= context;
   qu->ctx.callback= 0;
index 4e7f8f7..199746c 100644 (file)
@@ -187,7 +187,7 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
       continue;
     }
     if (rrtype == adns_r_cname &&
       continue;
     }
     if (rrtype == adns_r_cname &&
-       (qu->typei->type & adns__rrt_typemask) != adns_r_cname) {
+       (qu->answer->type & adns_rrt_typemask) != adns_r_cname) {
       if (qu->flags & adns_qf_cname_forbid) {
        adns__query_fail(qu,adns_s_prohibitedcname);
        return;
       if (qu->flags & adns_qf_cname_forbid) {
        adns__query_fail(qu,adns_s_prohibitedcname);
        return;
@@ -230,7 +230,7 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
         * it contains the relevant info.
         */
       }
         * it contains the relevant info.
         */
       }
-    } else if (rrtype == (qu->typei->type & adns__rrt_typemask)) {
+    } else if (rrtype == (qu->answer->type & adns_rrt_typemask)) {
       wantedrrs++;
     } else {
       adns__debug(ads,serv,qu,"ignoring answer RR"
       wantedrrs++;
     } else {
       adns__debug(ads,serv,qu,"ignoring answer RR"
@@ -339,7 +339,7 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
                     &ownermatched);
     assert(!st); assert(rrtype != -1);
     if (rrclass != DNS_CLASS_IN ||
                     &ownermatched);
     assert(!st); assert(rrtype != -1);
     if (rrclass != DNS_CLASS_IN ||
-       rrtype != (qu->typei->type & adns__rrt_typemask) ||
+       rrtype != (qu->answer->type & adns_rrt_typemask) ||
        !ownermatched)
       continue;
     adns__update_expires(qu,ttl,now);
        !ownermatched)
       continue;
     adns__update_expires(qu,ttl,now);
@@ -373,7 +373,7 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
   if (qu->cname_dgram) {
     st= adns__mkquery_frdgram(qu->ads,&qu->vb,&qu->id,
                              qu->cname_dgram,qu->cname_dglen,qu->cname_begin,
   if (qu->cname_dgram) {
     st= adns__mkquery_frdgram(qu->ads,&qu->vb,&qu->id,
                              qu->cname_dgram,qu->cname_dglen,qu->cname_begin,
-                             qu->typei->type, qu->flags);
+                             qu->answer->type, qu->flags);
     if (st) { adns__query_fail(qu,st); return; }
     
     newquery= realloc(qu->query_dgram,qu->vb.used);
     if (st) { adns__query_fail(qu,st); return; }
     
     newquery= realloc(qu->query_dgram,qu->vb.used);
index 6136bf9..c7dcdb4 100644 (file)
@@ -67,7 +67,7 @@ static adns_status mkquery_footer(vbuf *vb, adns_rrtype type) {
   byte *rqp;
 
   MKQUERY_START(vb);
   byte *rqp;
 
   MKQUERY_START(vb);
-  MKQUERY_ADDW(type & adns__rrt_typemask); /* QTYPE */
+  MKQUERY_ADDW(type & adns_rrt_typemask); /* QTYPE */
   MKQUERY_ADDW(DNS_CLASS_IN); /* QCLASS=IN */
   MKQUERY_STOP(vb);
   assert(vb->used <= vb->avail);
   MKQUERY_ADDW(DNS_CLASS_IN); /* QCLASS=IN */
   MKQUERY_STOP(vb);
   assert(vb->used <= vb->avail);
@@ -121,7 +121,8 @@ adns_status adns__qdpl_normal(adns_state ads,
 
 adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
                          const char *owner, int ol,
 
 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_rrtype type,
+                         adns_queryflags flags) {
   int labelnum, ll, nbytes;
   byte label[255];
   byte *rqp;
   int labelnum, ll, nbytes;
   byte label[255];
   byte *rqp;
@@ -150,7 +151,7 @@ adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
 
   MKQUERY_STOP(vb);
   
 
   MKQUERY_STOP(vb);
   
-  st= mkquery_footer(vb,typei->type);
+  st= mkquery_footer(vb,type);
   
   return adns_s_ok;
 }
   
   return adns_s_ok;
 }
index 14afc90..e0b9698 100644 (file)
@@ -64,6 +64,8 @@
  * _rp                        (pa)
  * _soa                       (pa,mf,cs)
  * _srv*                      (qdpl,(pap),pa,mf,di,(csp),cs,postsort)
  * _rp                        (pa)
  * _soa                       (pa,mf,cs)
  * _srv*                      (qdpl,(pap),pa,mf,di,(csp),cs,postsort)
+ * _byteblock                 (mf)
+ * _opaque                    (pa,cs)
  * _flat                      (mf)
  *
  * within each section:
  * _flat                      (mf)
  *
  * within each section:
@@ -908,7 +910,7 @@ static adns_status pap_mailbox822(const parseinfo *pai,
 
 static adns_status pap_mailbox(const parseinfo *pai, int *cbyte_io, int max,
                               char **mb_r) {
 
 static adns_status pap_mailbox(const parseinfo *pai, int *cbyte_io, int max,
                               char **mb_r) {
-  if (pai->qu->typei->type & adns__qtf_mail822) {
+  if (pai->qu->typei->typekey & adns__qtf_mail822) {
     return pap_mailbox822(pai, cbyte_io, max, mb_r);
   } else {
     return pap_domain(pai, cbyte_io, max, mb_r, pdf_quoteok);
     return pap_mailbox822(pai, cbyte_io, max, mb_r);
   } else {
     return pap_domain(pai, cbyte_io, max, mb_r, pdf_quoteok);
@@ -1183,6 +1185,56 @@ static void postsort_srv(adns_state ads, void *array, int nrrs,
 }
 
 /*
 }
 
 /*
+ * _byteblock   (mf)
+ */
+
+static void mf_byteblock(adns_query qu, void *datap) {
+  adns_rr_byteblock *rrp= datap;
+  void *bytes= rrp->data;
+  adns__makefinal_block(qu,&bytes,rrp->len);
+  rrp->data= bytes;
+}
+
+/*
+ * _opaque   (pa,cs)
+ */
+
+static adns_status pa_opaque(const parseinfo *pai, int cbyte,
+                            int max, void *datap) {
+  adns_rr_byteblock *rrp= datap;
+
+  rrp->len= max - cbyte;
+  rrp->data= adns__alloc_interim(pai->qu, rrp->len);
+  if (!rrp->data) R_NOMEM;
+  memcpy(rrp->data, pai->dgram + cbyte, rrp->len);
+  return adns_s_ok;
+}
+
+static adns_status cs_opaque(vbuf *vb, const void *datap) {
+  const adns_rr_byteblock *rrp= datap;
+  char buf[10];
+  int l;
+  unsigned char *p;
+
+  sprintf(buf,"\\# %d",rrp->len);
+  CSP_ADDSTR(buf);
+  
+  for (l= rrp->len, p= rrp->data;
+       l>=4;
+       l -= 4, p += 4) {
+    sprintf(buf," %02x%02x%02x%02x",p[0],p[1],p[2],p[3]);
+    CSP_ADDSTR(buf);
+  }
+  for (;
+       l>0;
+       l--, p++) {
+    sprintf(buf," %02x",*p);
+    CSP_ADDSTR(buf);
+  }
+  return adns_s_ok;
+}
+  
+/*
  * _flat   (mf)
  */
 
  * _flat   (mf)
  */
 
@@ -1234,15 +1286,20 @@ DEEP_TYPE(soa,    "SOA","822",  soa,     pa_soa,     0,        cs_soa        ),
 DEEP_TYPE(rp,     "RP", "822",  strpair, pa_rp,      0,        cs_rp         ),
 };
 
 DEEP_TYPE(rp,     "RP", "822",  strpair, pa_rp,      0,        cs_rp         ),
 };
 
+static const typeinfo typeinfo_unknown=
+DEEP_TYPE(unknown,0, "unknown",byteblock,pa_opaque,  0,        cs_opaque     );
+
 const typeinfo *adns__findtype(adns_rrtype type) {
   const typeinfo *begin, *end, *mid;
 
 const typeinfo *adns__findtype(adns_rrtype type) {
   const typeinfo *begin, *end, *mid;
 
+  if (type & adns_r_unknown) return &typeinfo_unknown;
+
   begin= typeinfos;  end= typeinfos+(sizeof(typeinfos)/sizeof(typeinfo));
 
   while (begin < end) {
     mid= begin + ((end-begin)>>1);
   begin= typeinfos;  end= typeinfos+(sizeof(typeinfos)/sizeof(typeinfo));
 
   while (begin < end) {
     mid= begin + ((end-begin)>>1);
-    if (mid->type == type) return mid;
-    if (type > mid->type) begin= mid+1;
+    if (mid->typekey == type) return mid;
+    if (type > mid->typekey) begin= mid+1;
     else end= mid;
   }
   return 0;
     else end= mid;
   }
   return 0;