From 5ed1b7e755b26a55f35d512cfedd384776baf483 Mon Sep 17 00:00:00 2001 From: ian Date: Sun, 11 Apr 1999 15:50:18 +0000 Subject: [PATCH] Halfway through IPv6 stuff. Most of the _rr_addr handling is left undone, but I think the interfaces are there now. This is going on a branch because glibc has no IPv6 yet ... --- client/adnstest.c | 1 + src/adns.h | 84 +++++++++++++++++++------- src/internal.h | 35 +++++++++-- src/query.c | 48 +++++++++++++-- src/transmit.c | 7 ++- src/types.c | 175 ++++++++++++++++++++++++++++++++++++++++-------------- 6 files changed, 271 insertions(+), 79 deletions(-) diff --git a/client/adnstest.c b/client/adnstest.c index ea9ed2a..55b957c 100644 --- a/client/adnstest.c +++ b/client/adnstest.c @@ -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, diff --git a/src/adns.h b/src/adns.h index ce12fc2..5c347f9 100644 --- a/src/adns.h +++ b/src/adns.h @@ -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 */ diff --git a/src/internal.h b/src/internal.h index f0f9147..59bfeb7 100644 --- a/src/internal.h +++ b/src/internal.h @@ -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. */ diff --git a/src/query.c b/src/query.c index 545feec..ffe346d 100644 --- a/src/query.c +++ b/src/query.c @@ -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); diff --git a/src/transmit.c b/src/transmit.c index d3978c3..4f7d680 100644 --- a/src/transmit.c +++ b/src/transmit.c @@ -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; } diff --git a/src/types.c b/src/types.c index bd87450..5f15c6d 100644 --- a/src/types.c +++ b/src/types.c @@ -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) { -- 2.11.0