diff -u -w -p -r1.1.1.1 -r1.2 --- client/adh-main.c 22 Sep 2003 12:34:27 -0000 1.1.1.1 +++ client/adh-main.c 23 Apr 2003 19:18:56 -0000 1.2 @@ -99,6 +99,7 @@ void of_type(const struct optioninfo *oi /* raw versions */ { adns_r_a, "a" }, + { adns_r_aaaa, "aaaa" }, { adns_r_ns_raw, "ns-" }, { adns_r_soa_raw, "soa-" }, { adns_r_ptr_raw, "ptr-" }, diff -u -w -p -r1.1.1.1 -r1.3 --- client/adh-opts.c 22 Sep 2003 12:34:27 -0000 1.1.1.1 +++ client/adh-opts.c 26 Oct 2003 15:54:04 -0000 1.3 @@ -33,6 +33,8 @@ int ov_verbose= 0; adns_rrtype ov_type= adns_r_none; int ov_search=0, ov_qc_query=0, ov_qc_anshost=0, ov_qc_cname=1; int ov_tcp=0, ov_cname=0, ov_format=fmt_default; +int ov_ipflags=0; +int ov_ip6mapped=0; char *ov_id= 0; struct perqueryflags_remember ov_pqfr = { 1,1,1, tm_none }; @@ -114,6 +116,16 @@ static const struct optioninfo perquery_ "Cl", "cname-loose", &ov_cname, adns_qf_cname_loose }, { ot_value, "CNAME ok for query domain, but not in RRs (default)", "Cs", "cname-ok", &ov_cname, 0 }, + + { ot_desconly, "per-query IPv6 mode:" }, + { ot_value, "Ask only for IPv6 addresses", + "I6", "ip6-only", &ov_ipflags, adns_qf_ip6 }, + { ot_value, "Ask only for IPv4 addresses", + "I4", "ip4-only", &ov_ipflags, adns_qf_ip4 }, + { ot_value, "Ask for both IPv4 and IPv6 addresses (default)", + "IX", "ipv6-mixed", &ov_ipflags, adns_qf_ip4|adns_qf_ip6 }, + { ot_value, "Ask for both IPv4 and IPv6 addresses, using IPv4-mapped IPv6 addresses", + "IM", "ipv6-mapped", &ov_ip6mapped, adns_qf_ip6mapped }, { ot_desconly, "asynchronous/pipe mode options:" }, { ot_funcarg, "Set , default is decimal sequence starting 0", diff -u -w -p -r1.1.1.1 -r1.3 --- client/adh-query.c 22 Sep 2003 12:34:27 -0000 1.1.1.1 +++ client/adh-query.c 26 Oct 2003 15:54:04 -0000 1.3 @@ -79,6 +79,7 @@ static void prep_query(struct query_node (ov_qc_query ? adns_qf_quoteok_query : 0) | (ov_qc_anshost ? adns_qf_quoteok_anshost : 0) | (ov_qc_cname ? 0 : adns_qf_quoteok_cname) | + ov_ipflags | ov_ip6mapped | ov_cname, *qun_r= qun; diff -u -w -p -r1.1.1.1 -r1.3 --- client/adnshost.h 22 Sep 2003 12:34:27 -0000 1.1.1.1 +++ client/adnshost.h 26 Oct 2003 15:54:04 -0000 1.3 @@ -82,6 +82,8 @@ extern int ov_verbose; extern adns_rrtype ov_type; extern int ov_search, ov_qc_query, ov_qc_anshost, ov_qc_cname; extern int ov_tcp, ov_cname, ov_format; +extern int ov_ipflags; +extern int ov_ip6mapped; extern char *ov_id; extern struct perqueryflags_remember ov_pqfr; diff -u -w -p -r1.1.1.1 -r1.13 --- src/adns.h 22 Sep 2003 12:34:29 -0000 1.1.1.1 +++ src/adns.h 26 Oct 2003 21:32:12 -0000 1.13 @@ -84,7 +88,10 @@ typedef enum { adns_if_eintr= 0x0020,/* allow _wait and _synchronous to return EINTR */ adns_if_nosigpipe= 0x0040,/* applic has SIGPIPE ignored, do not protect */ adns_if_checkc_entex=0x0100,/* consistency checks on entry/exit to adns fns */ - adns_if_checkc_freq= 0x0300 /* consistency checks very frequently (slow!) */ + adns_if_checkc_freq= 0x0300,/* consistency checks very frequently (slow!) */ + adns_if_ip4only= 0x1000,/* make default be adns_qf_ip4 */ + adns_if_ip6only= 0x2000,/* make default be adns_qf_ip6 */ + adns_if_ip6mapped= 0x4000,/* make default be adns_qf_ip4|adns_qf_ip6|adns_qf_ip6mapped */ } adns_initflags; typedef enum { @@ -97,13 +104,59 @@ typedef enum { adns_qf_quotefail_cname=0x00000080,/* refuse if quote-req chars in CNAME we go via */ adns_qf_cname_loose= 0x00000100,/* allow refs to CNAMEs - without, get _s_cname */ adns_qf_cname_forbid= 0x00000200,/* don't follow CNAMEs, instead give _s_cname */ + + /* Affects addr queries only (FIXME: And additional section processing?) */ + adns_qf_ip4= 0x00001000, /* Ask for A records */ + adns_qf_ip6= 0x00002000, /* Ask for AAAA records */ + adns_qf_ip6mapped= 0x00004000, /* Return any IPv4 addresses as IPv6 mapped addresses */ + + adns__qf_ip_mask= 0x00003000, adns__qf_internalmask= 0x0ff00000 } adns_queryflags; +/* IPv6 support: + * + * The _qf_ip4 and _qf_ip6 says which kinds of address records (A and + * AAAA) we should ask for. _qf_ip6mapped says how we return ipv6 + * addresses to the caller. Four modes of operation, corresponding to + * the _if_ip* flags: + * + * Record type: A AAAA + * flags: + * + * Default => AF_INET => AF_INET6 + * + * _if_ip4only => AF_INET not used + * + * _if_ip6only not used => AF_INET6 + * + * _if_ipv6mapped => AF_INET6 => AF_INET6 + * + * _if_ip4only => AF_INET6 not used + * | _if_ipv6mapped + * + * Furthermore, there are configuration options which can prevent the + * use of either AAAA or A records for _r_addr; so it is safe to use + * _qf_ip6_mapped and _r_addr without checking explicitly whether the host + * has IPv6 connectivity. + * + * The corresponding _qf_ip* flags are constructed from the _if_ip* + * flags and the query flags submitted to functions like adns_submit. + * If none of _qf_ip4 and _qf_ip6 are set explicitly in the query + * flags, the default behaviour is used. If the flags are set, the + * default configuration is overridden. + * + * Applications which do not support IPv4 should set none of these + * flags. Applications which have been `naively' converted to use + * AF_INET6 throughout should set adns_if_ip6. Applications which + * know what they are doing should know which flags to set :-). + */ + typedef enum { 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__qtf_special= 0x40000, /* no simple correspondence to a single rr type */ adns_r_none= 0, @@ -130,8 +183,11 @@ 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, /* RFC 1886 */ + adns_r_srv_raw= 33, /* RFC 2782 */ + adns_r_srv= adns_r_srv_raw|adns__qtf_deref, + adns_r_addr= 1 | adns__qtf_special, } adns_rrtype; /* @@ -256,9 +312,13 @@ typedef enum { typedef struct { int len; +#if 0 + int order; /* Cache index on sortlist? */ +#endif union { struct sockaddr sa; struct sockaddr_in inet; + struct sockaddr_in6 inet6; } addr; } adns_rr_addr; @@ -299,6 +359,20 @@ typedef struct { } adns_rr_soa; typedef struct { + unsigned short priority; + unsigned short weight; + unsigned short port; + adns_rr_hostaddr ha; +} adns_rr_srv; + +typedef struct { + unsigned short priority; + unsigned short weight; + unsigned short port; + char *target; +} adns_rr_srvraw; + +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 */ @@ -312,12 +386,15 @@ typedef struct { adns_rr_intstr *(*manyistr); /* txt (list strs ends with i=-1, str=0)*/ adns_rr_addr *addr; /* addr */ struct in_addr *inaddr; /* a */ + struct in6_addr *in6addr; /* aaaa */ adns_rr_hostaddr *hostaddr; /* ns */ adns_rr_intstrpair *intstrpair; /* hinfo */ adns_rr_strpair *strpair; /* rp, rp_raw */ adns_rr_inthostaddr *inthostaddr;/* mx */ adns_rr_intstr *intstr; /* mx_raw */ adns_rr_soa *soa; /* soa, soa_raw */ + adns_rr_srv *srv; /* srv */ + adns_rr_srvraw *srvraw; /* srv_raw */ } rrs; } adns_answer; @@ -434,6 +511,13 @@ int adns_init_strcfg(adns_state *newstat * setting of adns_if_check_entex, adns_if_check_freq, or neither, * in the flags passed to adns_init. * + * in6only + * in4only + * Return only IPv6, respectively only IPv4 addresses, in + * _rr_addr's. This may result in an adns_s_nodata error, if the + * application only supports, or the remote host only has, the wrong + * kind of address. + * * There are a number of environment variables which can modify the * behaviour of adns. They take effect only if adns_init is used, and * the caller of adns_init can disable them using adns_if_noenv. In @@ -517,7 +601,32 @@ int adns_submit_reverse(adns_state ads, void *context, adns_query *query_r); /* type must be _r_ptr or _r_ptr_raw. _qf_search is ignored. - * addr->sa_family must be AF_INET or you get ENOSYS. + * addr->sa_family must be AF_INET or AF_INET6 you get ENOSYS. + */ + +int adns_getaddrinfo(adns_state ads, + const char *name, /* Eg, "www.example.coom" */ + const char *service, /* Eg, "http" */ + const char *protocol, /* Eg, "tcp" */ + unsigned short defaultport, /* Eg, 80 */ + adns_queryflags flags, + adns_answer **answer_r, int *invented_r); +/* Does an SRV lookup (RFC2052). If this fails, tries an AAAA or A + * lookup instead, and if found uses getservbyname to find the port + * number (or failing that, uses defaultport). In the `fallback' + * case, will invent an SRV record with have priority and weight == 0 + * and set *invented_r to 1; if real SRV records were found, will set + * *invented_r to 0. invented_r may be null but answer_r may not be. + * If _getaddrinfo returns nonzero, *answer_r and/or *invented_r may + * or may not have been overwritten and should not be used. + * + * NB, like adns_synchronous, can fail either by returning an errno + * value, or by returning an adns_answer with ->nrrs==0 and + * ->status!=0. + * + * You have to write two loops when using the returned value, an outer + * one to loop over the returned SRV's, and an inner one to loop over + * the addresses for each one. */ int adns_submit_reverse_any(adns_state ads, diff -u -w -p -r1.1.1.1 -r1.6 --- src/check.c 22 Sep 2003 12:34:29 -0000 1.1.1.1 +++ src/check.c 26 Oct 2003 21:23:24 -0000 1.6 @@ -79,10 +81,10 @@ static void checkc_global(adns_state ads int i; assert(ads->udpsocket >= 0); - +#if 0 for (i=0; insortlist; i++) assert(!(ads->sortlist[i].base.s_addr & ~ads->sortlist[i].mask.s_addr)); - +#endif assert(ads->tcpserver >= 0 && ads->tcpserver < ads->nservers); switch (ads->tcpstate) { diff -u -w -p -r1.1.1.1 -r1.15 --- src/internal.h 22 Sep 2003 12:34:29 -0000 1.1.1.1 +++ src/internal.h 26 Oct 2003 21:24:01 -0000 1.15 @@ -130,6 +130,16 @@ typedef struct { * and will not be null-terminated by convstring. */ + void (*submithook)(adns_query qu, + /* FIXME: Do we need to pass flags? Isn't qu->flags enough? */ + adns_queryflags flags, + struct timeval now); + /* If NULL, submitting a query means to format it and send it over + * the wire. If non-NULL, the labels are written to qu->vb, and then + * this function is called. It's the hook's responsibility to submit + * the query, or submit some other queries and put the original on + * the child queue. */ + adns_status (*parse)(const parseinfo *pai, int cbyte, int max, void *store_r); /* Parse one RR, in dgram of length dglen, starting at cbyte and @@ -151,6 +161,8 @@ typedef struct { typedef struct allocnode { struct allocnode *next, *back; + size_t size; + /* Needed for realloc */ } allocnode; union maxalign { @@ -217,7 +229,10 @@ struct adns__query { * the vbuf is initialised but empty and everything else is zero. */ - int id, flags, retries; + int id; + /* -2 at allocation, -1 when done, >= 0 while the query is pending. */ + + int flags, retries; int udpnextserver; unsigned long udpsent; /* bitmap indexed by server */ struct timeval timeout; @@ -245,34 +260,34 @@ struct adns__query { * * +------------------------+ * START -----> | tosend/NONE | - * +------------------------+ - * / |\ \ - * too big for UDP / UDP timeout \ \ send via UDP - * send via TCP / more retries \ \ - * when conn'd / desired \ \ - * | | | - * v | v - * +-----------+ +-------------+ - * | tcpw/tcpw | ________ | tosend/udpw | - * +-----------+ \ +-------------+ - * | | | UDP timeout | | - * | | | no more | | - * | | | retries | | - * \ | TCP died | desired | | - * \ \ no more | | | - * \ \ servers | TCP / | - * \ \ to try | timeout / | - * got \ \ v |_ | got - * reply \ _| +------------------+ / reply - * \ | done/output FAIL | / - * \ +------------------+ / - * \ / - * _| |_ - * (..... got reply ....) - * / \ + * _____+------------------------+ + * consists of __----- / |\ \ + * child- / / UDP timeout \ \ send via UDP + * queries / too big for UDP/ more retries \ \ + * only / send via TCP / desired \ \ + * / when conn'd / | | + * / |_ | v + * | +-----------+ +-------------+ + * | | tcpw/tcpw | ________ | tosend/udpw | + * | +-----------+ \ +-------------+ + * | | | | UDP timeout | | + * | | | | no more | | + * | | | | retries | | + * | \ | TCP died | desired | | + * | \ \ no more | | | + * | \ \ servers | TCP / | + * | \ \ to try | timeout / | + * | got \ \ v |_ | got + * | reply \ _| +------------------+ / reply + * \ \ | done/output FAIL | / + * \ \ +------------------+ / + * \ \ / + * \ _| |_ + * \ (..... got reply ....) + * \ / \ * need child query/ies / \ no child query - * / \ - * |_ _| + * \ / \ + * _| |_ _| * +---------------+ +----------------+ * | childw/childw | ----------------> | done/output OK | * +---------------+ children done +----------------+ @@ -307,7 +322,12 @@ struct adns__state { struct in_addr addr; } servers[MAXSERVERS]; struct sortlist { - struct in_addr base, mask; + sa_family_t family; + unsigned prefix; + union { + struct in_addr inet; + struct in6_addr inet6; + } base; } sortlist[MAXSORTLIST]; char **searchlist; }; @@ -370,12 +390,26 @@ void adns__sigpipe_unprotect(adns_state) /* From transmit.c: */ +adns_status adns__mkquery_labels(vbuf *vb, + const char *owner, int ol, + adns_queryflags flags); +/* Assembles the owner part of a query packet in vb. */ + +adns_status adns__mkquery_labels_frdgram(adns_state ads, vbuf *vb, + const byte *qd_dgram, int qd_dglen, + int qd_begin); + adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r, const char *owner, int ol, const typeinfo *typei, adns_queryflags flags); /* Assembles a query packet in vb. A new id is allocated and returned. */ +adns_status adns__mkquery_frlabels(adns_state ads, vbuf *vb, int *id_r, + char *l, int llen, + adns_rrtype type, adns_queryflags flags); +/* Same as adns__mkquery, but with the labels preformatted. */ + adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r, const byte *qd_dgram, int qd_dglen, int qd_begin, @@ -415,6 +449,9 @@ adns_status adns__internal_submit(adns_s * the memory for it is _taken over_ by this routine whether it * succeeds or fails (if it succeeds, the vbuf is reused for qu->vb). * + * For query types with a submithook (i.e. adns_r_addr), + * vbuf should contain just the label, not a complete query. + * * *ctx is copied byte-for-byte into the query. * * When the child query is done, ctx->callback will be called. The @@ -442,6 +479,7 @@ void adns__search_next(adns_state ads, a */ void *adns__alloc_interim(adns_query qu, size_t sz); +void *adns__realloc_interim(adns_query qu, void *p, size_t sz); void *adns__alloc_preserved(adns_query qu, size_t sz); /* Allocates some memory, and records which query it came from * and how much there was. diff -u -w -p -r1.1.1.1 -r1.8 --- src/query.c 22 Sep 2003 12:34:29 -0000 1.1.1.1 +++ src/query.c 26 Oct 2003 17:40:04 -0000 1.8 @@ -120,7 +124,18 @@ adns_status adns__internal_submit(adns_s *query_r= qu; memcpy(&qu->ctx,ctx,sizeof(qu->ctx)); - query_submit(ads,qu, typei,qumsg_vb,id,flags,now); + + if (typei->submithook) { + qu->vb = *qumsg_vb; + adns__vbuf_init(qumsg_vb); + + typei->submithook(qu, flags, now); + if (qu->children.head) { + qu->state= query_childw; + LIST_LINK_TAIL(ads->childw,qu); + } + } + else query_submit(ads,qu, typei,qumsg_vb,id,flags,now); return adns_s_ok; } @@ -133,20 +148,31 @@ static void query_simple(adns_state ads, int id; adns_status stat; - stat= adns__mkquery(ads,&qu->vb,&id, owner,ol, typei,flags); - if (stat) { - if (stat == adns_s_querydomaintoolong && (flags & adns_qf_search)) { - adns__search_next(ads,qu,now); - return; - } else { - adns__query_fail(qu,stat); - return; + if (typei->submithook) { + stat= adns__mkquery_labels(&qu->vb, owner, ol, flags); + if (stat) goto fail; + + typei->submithook(qu, flags, now); + if (qu->children.head) { + qu->state= query_childw; + LIST_LINK_TAIL(ads->childw,qu); } + return; } + else { + stat= adns__mkquery(ads,&qu->vb,&id, owner,ol, typei,flags); + if (stat) goto fail; vb_new= qu->vb; adns__vbuf_init(&qu->vb); query_submit(ads,qu, typei,&vb_new,id, flags,now); + return; + } + fail: + if (stat == adns_s_querydomaintoolong && (flags & adns_qf_search)) + adns__search_next(ads,qu,now); + else + adns__query_fail(qu,stat); } void adns__search_next(adns_state ads, adns_query qu, struct timeval now) { @@ -221,6 +247,16 @@ int adns_submit(adns_state ads, adns__consistency(ads,0,cc_entex); + if (!(flags & adns__qf_ip_mask)) { + /* Select default mode */ + if (!(ads->iflags & adns_if_ip4only)) + flags |= adns_qf_ip4; + if (!(ads->iflags & adns_if_ip6only)) + flags |= adns_qf_ip6; + if (ads->iflags & adns_if_ip6mapped) + flags |= adns_qf_ip6mapped; + } + typei= adns__findtype(type); if (!typei) return ENOSYS; @@ -343,7 +379,34 @@ static void *alloc_common(adns_query qu, an= malloc(MEM_ROUND(MEM_ROUND(sizeof(*an)) + sz)); if (!an) return 0; LIST_LINK_TAIL(qu->allocations,an); + an->size = sz; return (byte*)an + MEM_ROUND(sizeof(*an)); +} + +void *adns__realloc_interim(adns_query qu, void *p, size_t sz) { + allocnode *an; + allocnode *nan; + + sz = MEM_ROUND(sz); + assert(sz); /* Freeing via realloc not supported */ + assert(!qu->final_allocspace); + + an = (allocnode *) ((byte *) p - MEM_ROUND(sizeof(*an))); + assert(an->size <= qu->interim_allocd); + + nan = realloc(an, MEM_ROUND(MEM_ROUND(sizeof(*an)) + sz)); + if (!nan) return 0; + + qu->interim_allocd -= nan->size; + qu->interim_allocd += sz; + nan->size = sz; + + if (nan->next) nan->next->back = nan; + else qu->allocations.tail = nan; + if (nan->back) nan->back->next = nan; + else qu->allocations.head = nan; + + return (byte*)nan + MEM_ROUND(sizeof(*nan)); } void *adns__alloc_interim(adns_query qu, size_t sz) { diff -u -w -p -r1.1.1.1 -r1.6 --- src/setup.c 22 Sep 2003 12:34:29 -0000 1.1.1.1 +++ src/setup.c 26 Oct 2003 21:24:50 -0000 1.6 @@ -151,6 +151,7 @@ static void ccf_search(adns_state ads, c static void ccf_sortlist(adns_state ads, const char *fn, int lno, const char *buf) { + /* FIXME: Handle IPv6 addresses */ const char *word; char tbuf[200], *slash, *ep; struct in_addr base, mask; @@ -192,6 +193,21 @@ static void ccf_sortlist(adns_state ads, " overlaps address `%s'",slash,tbuf); continue; } + { + /* Convert bitmask to prefix length */ + unsigned long bits; + + for(bits=ntohl(mask.s_addr), initial = 0; + bits & 0x80000000UL; + bits <<= 1) + initial++; + + if (bits & 0xffffffff) { + configparseerr(ads,fn,lno, + "mask `%s' in sortlist is non-continuous",slash); + continue; + } + } } else { initial= strtoul(slash,&ep,10); if (*ep || initial>32) { @@ -203,11 +219,11 @@ static void ccf_sortlist(adns_state ads, } else { baselocal= ntohl(base.s_addr); if (!baselocal & 0x080000000UL) /* class A */ - mask.s_addr= htonl(0x0ff000000UL); + initial = 8; else if ((baselocal & 0x0c0000000UL) == 0x080000000UL) - mask.s_addr= htonl(0x0ffff0000UL); /* class B */ + initial= 16; /* class B */ else if ((baselocal & 0x0f0000000UL) == 0x0e0000000UL) - mask.s_addr= htonl(0x0ff000000UL); /* class C */ + initial= 24; /* class C */ else { configparseerr(ads,fn,lno, "network address `%s'" " in sortlist is not in classed ranges," @@ -216,8 +232,10 @@ static void ccf_sortlist(adns_state ads, } } - ads->sortlist[ads->nsortlist].base= base; - ads->sortlist[ads->nsortlist].mask= mask; + ads->sortlist[ads->nsortlist].family= AF_INET; + ads->sortlist[ads->nsortlist].base.inet= base; + ads->sortlist[ads->nsortlist].prefix= initial; + ads->nsortlist++; } } diff -u -w -p -r1.1.1.1 -r1.9 --- src/transmit.c 22 Sep 2003 12:34:29 -0000 1.1.1.1 +++ src/transmit.c 26 Oct 2003 17:41:22 -0000 1.9 @@ -63,6 +63,8 @@ static adns_status mkquery_header(adns_s return adns_s_ok; } +/* FIXME: Return value is always adns_s_ok, and never used. But I + * don't understand why we can assert that we have space in the vbuf. */ static adns_status mkquery_footer(vbuf *vb, adns_rrtype type) { byte *rqp; @@ -75,15 +77,15 @@ static adns_status mkquery_footer(vbuf * return adns_s_ok; } -adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r, + +adns_status adns__mkquery_labels(vbuf *vb, const char *owner, int ol, - const typeinfo *typei, adns_queryflags flags) { + adns_queryflags flags) { int ll, c, nbytes; byte label[255], *rqp; const char *p, *pe; - adns_status st; - st= mkquery_header(ads,vb,id_r,ol+2); if (st) return st; + if (!adns__vbuf_ensure(vb,ol+2)) return adns_s_nomemory; MKQUERY_START(vb); @@ -127,22 +129,30 @@ adns_status adns__mkquery(adns_state ads MKQUERY_ADDB(0); MKQUERY_STOP(vb); + return adns_s_ok; +} + +adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r, + const char *owner, int ol, + const typeinfo *typei, adns_queryflags flags) { + adns_status st; + st= mkquery_header(ads,vb,id_r,ol+2); if (st) return st; + st= adns__mkquery_labels(vb, owner, ol, flags); if (st) return st; st= mkquery_footer(vb,typei->type); return adns_s_ok; } -adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r, +adns_status adns__mkquery_labels_frdgram(adns_state ads, vbuf *vb, const byte *qd_dgram, int qd_dglen, - int qd_begin, - adns_rrtype type, adns_queryflags flags) { + int qd_begin) { + adns_status st; byte *rqp; findlabel_state fls; int lablen, labstart; - adns_status st; - st= mkquery_header(ads,vb,id_r,qd_dglen); if (st) return st; + if (!adns__vbuf_ensure(vb,qd_dglen)) return adns_s_nomemory; MKQUERY_START(vb); @@ -159,6 +169,31 @@ adns_status adns__mkquery_frdgram(adns_s MKQUERY_STOP(vb); + return adns_s_ok; +} + +adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r, + const byte *qd_dgram, int qd_dglen, + int qd_begin, + adns_rrtype type, adns_queryflags flags) { + adns_status st; + + st= mkquery_header(ads,vb,id_r,qd_dglen); if (st) return st; + st= adns__mkquery_labels_frdgram(ads, vb, + qd_dgram, qd_dglen, qd_begin); + if (st) return st; + st= mkquery_footer(vb,type); + + return adns_s_ok; +} + +adns_status adns__mkquery_frlabels(adns_state ads, vbuf *vb, int *id_r, + char *l, int llen, + adns_rrtype type, adns_queryflags flags) { + adns_status st; + + st= mkquery_header(ads,vb,id_r,llen); if (st) return st; + if (!adns__vbuf_append(vb, l, llen)) return adns_s_nomemory; st= mkquery_footer(vb,type); return adns_s_ok; diff -u -w -p -r1.1.1.1 -r1.13 --- src/types.c 22 Sep 2003 12:34:29 -0000 1.1.1.1 +++ src/types.c 26 Oct 2003 21:26:56 -0000 1.13 @@ -49,7 +49,8 @@ * _manyistr (mf,cs) * _txt (pa) * _inaddr (pa,dip,di) - * _addr (pa,di,csp,cs) + * _in6addr (pa,cs) + * _addr (sh,di,csp,cs) * _domain (pap) * _host_raw (pa) * _hostaddr (pap,pa,dip,di,mfp,mf,csp,cs +pap_findaddrs) @@ -247,14 +248,20 @@ static adns_status pa_inaddr(const parse return adns_s_ok; } -static int search_sortlist(adns_state ads, struct in_addr ad) { +static int search_sortlist_in(adns_state ads, struct in_addr ad) { const struct sortlist *slp; int i; for (i=0, slp=ads->sortlist; - insortlist && - !((ad.s_addr & slp->mask.s_addr) == slp->base.s_addr); - i++, slp++); + insortlist; + i++, slp++) { + if (slp->family == AF_INET) { + struct in_addr mask; + mask.s_addr = htonl(-1 << slp->prefix); + if ( (ad.s_addr & mask.s_addr ) == slp->base.inet.s_addr) + break; + } + } return i; } @@ -263,8 +270,8 @@ static int dip_inaddr(adns_state ads, st if (!ads->nsortlist) return 0; - ai= search_sortlist(ads,a); - bi= search_sortlist(ads,b); + ai= search_sortlist_in(ads,a); + bi= search_sortlist_in(ads,b); return bidgram + cbyte, 16); + return adns_s_ok; +} + +static int search_sortlist_in6(adns_state ads, const struct in6_addr *ad) { + const struct sortlist *slp; + int i; + + for (i=0, slp=ads->sortlist; + insortlist; + i++, slp++) { + if (slp->family == AF_INET6) { + int pb = slp->prefix / 8; + int mask = 0xff & (-1 << (slp->prefix % 8)); + if (memcmp(ad->s6_addr, slp->base.inet6.s6_addr, pb) == 0 + && (!mask + || (ad->s6_addr[pb] & mask) == slp->base.inet6.s6_addr[pb])) + break; + } + } + return i; +} + +static int dip_in6addr(adns_state ads, + const struct in6_addr *a, const struct in6_addr *b) { + int ai, bi; + + if (!ads->nsortlist) return 0; + + ai= search_sortlist_in6(ads,a); + bi= search_sortlist_in6(ads,b); + return bisin6_family = AF_INET6; + sa->sin6_addr.s6_addr16[5] = 0xffff; + sa->sin6_addr.s6_addr32[3] = in->s_addr; +} + +static void icb_addr(adns_query parent, adns_query child) { + /* Copy A record to result */ + adns_answer *cans= child->answer; + adns_answer *pans= parent->answer; + adns_state ads= parent->ads; + adns_rr_addr *addr; + + int i; + + if (cans->status == adns_s_nodata && parent->children.head) { + /* We may get records from the remaining queries */ + LIST_LINK_TAIL(ads->childw,parent); + return; + } + else if (cans->status) { + adns__query_fail(parent,cans->status); + return; + } + + assert(cans->nrrs); + + /* Copy CNAME. CNAME must be consistent for both queries. */ + if (cans->cname && pans->cname) { + if (strcmp(cans->cname, pans->cname)) { + adns__query_fail(parent, adns_s_inconsistent); + return; + } + } + else if (pans->cname) { + adns__query_fail(parent, adns_s_inconsistent); + return; + } + else if (cans->cname) { + size_t len; + if (pans->nrrs) { + adns__query_fail(parent, adns_s_inconsistent); + return; + } + len = strlen(cans->cname) + 1; + pans->cname = adns__alloc_preserved(parent, len); + if (!pans->cname) { + adns__query_fail(parent, adns_s_nomemory); + return; + } + memcpy(pans->cname, cans->cname, len); + } + if (pans->nrrs) + { + void *p = adns__realloc_interim(parent,pans->rrs.untyped, + sizeof(adns_rr_addr) * (cans->nrrs + pans->nrrs)); + if (!p) { + adns__query_fail(parent, adns_s_nomemory); + return; + } + pans->rrs.untyped = p; + addr = pans->rrs.addr + pans->nrrs; + pans->nrrs += cans->nrrs; + } + else { + pans->rrs.untyped = adns__alloc_interim(parent,sizeof(adns_rr_addr) * cans->nrrs); + if (!pans->rrs.untyped) { + adns__query_fail(parent,adns_s_nomemory); + return; + } + pans->nrrs = cans->nrrs; + addr = pans->rrs.addr; + } + if (parent->expires > child->expires) parent->expires = child->expires; + switch (cans->type) { + default: abort(); + case adns_r_a: + if (parent->flags & adns_qf_ip6mapped) + for (i = 0; inrrs; i++) { + addr[i].len = sizeof(struct sockaddr_in6); + mk_mapped_ipv6(&addr[i].addr.inet6, &cans->rrs.inaddr[i]); + } + else + for (i = 0; inrrs; i++) { + addr[i].len = sizeof(struct sockaddr_in); + memset(&addr[i].addr.inet, 0, sizeof(addr[i].addr.inet)); + addr[i].addr.inet.sin_family = AF_INET; + addr[i].addr.inet.sin_addr = cans->rrs.inaddr[i]; + } + break; + case adns_r_aaaa: + for (i = 0; inrrs; i++) { + addr[i].len = sizeof(struct sockaddr_in6); + memset(&addr[i].addr.inet6, 0, sizeof(addr[i].addr.inet6)); + addr[i].addr.inet6.sin6_family = AF_INET6; + addr[i].addr.inet6.sin6_addr = cans->rrs.in6addr[i]; + } + break; + } + + if (!parent->children.head) { + adns__query_done(parent); + return; + } else { + LIST_LINK_TAIL(ads->childw,parent); + return; + } +} + +static void sh_addr(adns_query qu, + adns_queryflags flags, struct timeval now) +{ + adns_status st; + int id; + qcontext ctx; + adns_query nqu; + vbuf vb; + + /* Must have a non-negative id, or else adns__internal_check will think that we + * are on the output queue. */ + qu->id = 0; + + ctx.ext= 0; + ctx.callback= icb_addr; + /* What to store in ctx.info? */ + + adns__vbuf_init(&vb); + + if (flags & adns_qf_ip4) { /* A query */ + st= adns__mkquery_frlabels(qu->ads, &vb, &id, + qu->vb.buf, qu->vb.used, adns_r_a, flags); + if (st) { adns__query_fail(qu, st); return; } + + st= adns__internal_submit(qu->ads, &nqu, adns__findtype(adns_r_a), + &vb, id, flags, now, &ctx); + if (st) { adns__query_fail(qu, st); return; } + + nqu->parent = qu; + LIST_LINK_TAIL_PART(qu->children,nqu,siblings.); + } + + if (flags & adns_qf_ip6) { /* AAAA query */ + st= adns__mkquery_frlabels(qu->ads, &vb, &id, + qu->vb.buf, qu->vb.used, adns_r_aaaa, flags); + if (st) { adns__query_fail(qu, st); return; } + + st= adns__internal_submit(qu->ads, &nqu, adns__findtype(adns_r_aaaa), + &vb, id, flags, now, &ctx); + if (st) { adns__query_fail(qu, st); return; } + + nqu->parent = qu; + LIST_LINK_TAIL_PART(qu->children,nqu,siblings.); + } + assert(qu->children.head); +} + +static adns_status pap_addr(const parseinfo *pai, adns_rrtype type, int cbyte, + int max, adns_rr_addr *rr) { + const byte *dgram= pai->dgram; + adns_queryflags flags = pai->qu->flags; + + switch (type) + { + default: abort(); + case adns_r_a: + assert(flags & adns_qf_ip4); if (max-cbyte != 4) return adns_s_invaliddata; - storeto->len= sizeof(storeto->addr.inet); - memset(&storeto->addr,0,sizeof(storeto->addr.inet)); - storeto->addr.inet.sin_family= AF_INET; - memcpy(&storeto->addr.inet.sin_addr,dgram+cbyte,4); + + if (flags & adns_qf_ip6mapped) { + rr->len = sizeof(struct sockaddr_in6); + mk_mapped_ipv6(&rr->addr.inet6, (const struct in_addr *) (dgram+cbyte)); + } + else { + rr->len= sizeof(rr->addr.inet); + memset(&rr->addr.inet,0,sizeof(rr->addr.inet)); + rr->addr.inet.sin_family= AF_INET; + memcpy(&rr->addr.inet.sin_addr,dgram+cbyte,4); + } + break; + case adns_r_aaaa: + assert(flags & adns_qf_ip6); + + if (max-cbyte != 16) return adns_s_invaliddata; + + rr->len= sizeof(rr->addr.inet6); + memset(&rr->addr,0,sizeof(rr->addr.inet6)); + rr->addr.inet6.sin6_family= AF_INET6; + memcpy(&rr->addr.inet6.sin6_addr,dgram+cbyte,16); + + break; + } + return adns_s_ok; } +static int search_sortlist_addr(adns_state ads, const adns_rr_addr *ad) { + switch(ad->addr.sa.sa_family) { + default: abort(); + case AF_INET: return search_sortlist_in(ads, ad->addr.inet.sin_addr); + case AF_INET6: return search_sortlist_in6(ads, &ad->addr.inet6.sin6_addr); + } +} + 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; + int ai, bi; + + if (!ads->nsortlist) return 0; - assert(ap->addr.sa.sa_family == AF_INET); - return dip_inaddr(ads, ap->addr.inet.sin_addr, bp->addr.inet.sin_addr); + ai = search_sortlist_addr(ads, ap); + bi = search_sortlist_addr(ads, bp); + return biaddr.inet.sin_family) { case AF_INET: @@ -324,6 +588,12 @@ static adns_status csp_addr(vbuf *vb, co ia= inet_ntoa(rrp->addr.inet.sin_addr); assert(ia); CSP_ADDSTR(ia); break; + case AF_INET6: + CSP_ADDSTR("INET6 "); + ia= inet_ntop(AF_INET6, &rrp->addr.inet6.sin6_addr, + buf, sizeof(buf)); assert(ia); + CSP_ADDSTR(ia); + break; default: sprintf(buf,"AF=%u",rrp->addr.sa.sa_family); CSP_ADDSTR(buf); @@ -420,17 +690,22 @@ static adns_status pap_findaddrs(const p &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) { + if (!ownermatched || class != DNS_CLASS_IN) { + if (naddrs>0) break; else continue; + } + if (! ((type == adns_r_a && (pai->qu->flags & adns_qf_ip4)) + || (type == adns_r_aaaa && (pai->qu->flags & adns_qf_ip6)))) { if (naddrs>0) break; else continue; } + if (naddrs == -1) { 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)); + st= pap_addr(pai, type, rdstart,rdstart+rdlen, + (adns_rr_addr *) pai->qu->vb.buf + naddrs); if (st) return st; naddrs++; } @@ -472,7 +747,6 @@ static adns_status pap_hostaddr(const pa adns_status st; int dmstart, cbyte; qcontext ctx; - int id; adns_query nqu; adns_queryflags nflags; @@ -496,9 +770,8 @@ static adns_status pap_hostaddr(const pa 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); + st= adns__mkquery_labels_frdgram(pai->ads, &pai->qu->vb, + pai->dgram, pai->dglen, dmstart); if (st) return st; ctx.ext= 0; @@ -509,7 +782,7 @@ static adns_status pap_hostaddr(const pa 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, &ctx); + &pai->qu->vb, 0, nflags, pai->now, &ctx); if (st) return st; nqu->parent= pai->qu; @@ -741,7 +1014,7 @@ static adns_status pa_ptr(const parseinf char *ep; byte ipv[4]; char labbuf[4]; - int cbyte, i, lablen, labstart, l, id; + int cbyte, i, lablen, labstart, l; adns_query nqu; qcontext ctx; @@ -783,16 +1056,15 @@ static adns_status pa_ptr(const parseinf htonl((ipv[0]<<24) | (ipv[1]<<16) | (ipv[2]<<8) | (ipv[3])); } - st= adns__mkquery_frdgram(pai->ads, &pai->qu->vb, &id, - pai->dgram, pai->dglen, dmstart, - adns_r_addr, adns_qf_quoteok_query); + st= adns__mkquery_labels_frdgram(pai->ads, &pai->qu->vb, + pai->dgram, pai->dglen, dmstart); if (st) return st; ctx.ext= 0; ctx.callback= icb_ptr; memset(&ctx.info,0,sizeof(ctx.info)); st= adns__internal_submit(pai->ads, &nqu, adns__findtype(adns_r_addr), - &pai->qu->vb, id, + &pai->qu->vb, 0, adns_qf_quoteok_query, pai->now, &ctx); if (st) return st; @@ -1016,9 +1288,11 @@ static void mf_flat(adns_query qu, void #define FLAT_MEMB(memb) TYPESZ_M(memb), mf_flat, cs_##memb #define DEEP_TYPE(code,rrt,fmt,memb,parser,comparer,printer) \ - { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_##memb, printer,parser,comparer } + { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_##memb, printer,NULL,parser,comparer } #define FLAT_TYPE(code,rrt,fmt,memb,parser,comparer,printer) \ - { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_flat, printer,parser,comparer } + { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_flat, printer,NULL,parser,comparer } +#define SPECIAL_TYPE(code,rrt,fmt,memb,submit,comparer,printer) \ + { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_flat, printer,submit,NULL,comparer } static const typeinfo typeinfos[] = { /* Must be in ascending order of rrtype ! */ @@ -1033,14 +1307,19 @@ DEEP_TYPE(hinfo, "HINFO", 0, intstrpair DEEP_TYPE(mx_raw, "MX", "raw",intstr, pa_mx_raw, di_mx_raw,cs_inthost ), DEEP_TYPE(txt, "TXT", 0, manyistr,pa_txt, 0, cs_txt ), DEEP_TYPE(rp_raw, "RP", "raw",strpair, pa_rp, 0, cs_rp ), +FLAT_TYPE(aaaa, "AAAA", 0, in6addr, pa_in6addr, di_in6addr, cs_in6addr ), -FLAT_TYPE(addr, "A", "addr", addr, pa_addr, di_addr, cs_addr ), +/* adns__qtf_deref set */ DEEP_TYPE(ns, "NS", "+addr",hostaddr,pa_hostaddr,di_hostaddr,cs_hostaddr ), DEEP_TYPE(ptr, "PTR","checked",str, pa_ptr, 0, cs_domain ), DEEP_TYPE(mx, "MX", "+addr",inthostaddr,pa_mx, di_mx, cs_inthostaddr), +/* adns__qtf_mail822 set */ DEEP_TYPE(soa, "SOA","822", soa, pa_soa, 0, cs_soa ), DEEP_TYPE(rp, "RP", "822", strpair, pa_rp, 0, cs_rp ), + +/* adns__qtf_special set */ +SPECIAL_TYPE(addr,"A", "addr", addr, sh_addr,0 /*di_addr*/, cs_addr ), }; const typeinfo *adns__findtype(adns_rrtype type) {