summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2012-11-07 09:28:16 -0800
committerAnas Nashif <anas.nashif@intel.com>2012-11-07 09:28:16 -0800
commit0fdbfaf8c645a78328f00d2bc589d49900439342 (patch)
treef6cc38126676ef35e51395c479efaedf6365015a
parent392a34daa6f724cf96834620a3875f2138742aa3 (diff)
downloadadns-0fdbfaf8c645a78328f00d2bc589d49900439342.tar.gz
adns-0fdbfaf8c645a78328f00d2bc589d49900439342.tar.bz2
adns-0fdbfaf8c645a78328f00d2bc589d49900439342.zip
adns-1.4-ipv6
-rw-r--r--Makefile.in4
-rw-r--r--client/adh-main.c2
-rw-r--r--client/adh-opts.c12
-rw-r--r--client/adh-query.c34
-rw-r--r--client/adnshost.h2
-rw-r--r--client/adnstest.c3
-rw-r--r--src/adns.h104
-rw-r--r--src/check.c6
-rw-r--r--src/internal.h106
-rw-r--r--src/query.c159
-rw-r--r--src/setup.c28
-rw-r--r--src/transmit.c55
-rw-r--r--src/types.c413
13 files changed, 767 insertions, 161 deletions
diff --git a/Makefile.in b/Makefile.in
index 6e2e449..0babf0e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -56,9 +56,9 @@ dist_tmp=dist_tmp/adns-$(DISTVERSION)
dist: distprep
rm -rf dist_tmp*
mkdir dist_tmp $(dist_tmp)
- find \( -name CVS -o -name dist_tmp* \) -prune -o -type d -print | \
+ find . \( -name CVS -o -name dist_tmp* \) -prune -o -type d -print | \
sed -e 's#.*#mkdir -p $(dist_tmp)/&#' | sh
- find \( -name CVS -o -name dist_tmp* \) -prune -o -type f -print | \
+ find . \( -name CVS -o -name dist_tmp* \) -prune -o -type f -print | \
sed -e 's#.*#ln & $(dist_tmp)/&#' | sh
$(MAKE) -C dist_tmp/adns-$(DISTVERSION) distclean
cd dist_tmp && tar cf ../$(dist_tmp).tar `basename $(dist_tmp)`
diff --git a/client/adh-main.c b/client/adh-main.c
index b6f3bd4..f2032ec 100644
--- a/client/adh-main.c
+++ b/client/adh-main.c
@@ -91,6 +91,7 @@ void of_type(const struct optioninfo *oi, const char *arg, const char *arg2) {
{ adns_r_rp, "rp" },
{ adns_r_srv, "srv" },
{ adns_r_addr, "addr" },
+ { adns_r_srv, "srv" },
/* types with only one version */
{ adns_r_cname, "cname" },
@@ -99,6 +100,7 @@ void of_type(const struct optioninfo *oi, const char *arg, const char *arg2) {
/* 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 --git a/client/adh-opts.c b/client/adh-opts.c
index 08310e0..7b17c89 100644
--- a/client/adh-opts.c
+++ b/client/adh-opts.c
@@ -32,6 +32,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_options[]= {
{ 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 <id>, default is decimal sequence starting 0",
0, "asynch-id", 0,0, &of_asynch_id, "id" },
diff --git a/client/adh-query.c b/client/adh-query.c
index 125bb33..2186004 100644
--- a/client/adh-query.c
+++ b/client/adh-query.c
@@ -92,24 +92,37 @@ static void prep_query(struct query_node **qun_r, int *quflags_r) {
(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;
}
+static int a2addr(adns_rr_addr *rr, const char *addr) {
+ char *p;
+ if (strchr(addr, ':')) {
+ memset(&rr->addr.inet6, 0, sizeof(rr->addr.inet6));
+ rr->addr.sa.sa_family = AF_INET6;
+ p = (char *) &rr->addr.inet6.sin6_addr;
+ }
+ else {
+ memset(&rr->addr.inet, 0, sizeof(rr->addr.inet));
+ rr->addr.sa.sa_family = AF_INET;
+ p = (char *) &rr->addr.inet.sin_addr;
+ }
+ return inet_pton(rr->addr.sa.sa_family, addr, p) > 0;
+}
+
void of_ptr(const struct optioninfo *oi, const char *arg, const char *arg2) {
struct query_node *qun;
int quflags, r;
- struct sockaddr_in sa;
-
- memset(&sa,0,sizeof(sa));
- sa.sin_family= AF_INET;
- if (!inet_aton(arg,&sa.sin_addr)) usageerr("invalid IP address %s",arg);
+ adns_rr_addr rr;
+ if (!a2addr(&rr, arg)) usageerr("invalid IP address %s",arg);
prep_query(&qun,&quflags);
qun->owner= xstrsave(arg);
r= adns_submit_reverse(ads,
- (struct sockaddr*)&sa,
+ &rr.addr.sa,
ov_type == adns_r_none ? adns_r_ptr : ov_type,
quflags,
qun,
@@ -122,17 +135,14 @@ void of_ptr(const struct optioninfo *oi, const char *arg, const char *arg2) {
void of_reverse(const struct optioninfo *oi, const char *arg, const char *arg2) {
struct query_node *qun;
int quflags, r;
- struct sockaddr_in sa;
-
- memset(&sa,0,sizeof(sa));
- sa.sin_family= AF_INET;
- if (!inet_aton(arg,&sa.sin_addr)) usageerr("invalid IP address %s",arg);
+ adns_rr_addr rr;
+ if (!a2addr(&rr, arg)) usageerr("invalid IP address %s",arg);
prep_query(&qun,&quflags);
qun->owner= xmalloc(strlen(arg) + strlen(arg2) + 2);
sprintf(qun->owner, "%s %s", arg,arg2);
r= adns_submit_reverse_any(ads,
- (struct sockaddr*)&sa, arg2,
+ &rr.addr.sa, arg2,
ov_type == adns_r_none ? adns_r_txt : ov_type,
quflags,
qun,
diff --git a/client/adnshost.h b/client/adnshost.h
index fcc96a3..7e2341a 100644
--- a/client/adnshost.h
+++ b/client/adnshost.h
@@ -81,6 +81,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 --git a/client/adnstest.c b/client/adnstest.c
index 550cf27..ae70285 100644
--- a/client/adnstest.c
+++ b/client/adnstest.c
@@ -119,13 +119,16 @@ static const adns_rrtype defaulttypes[]= {
adns_r_ptr_raw,
adns_r_hinfo,
adns_r_mx_raw,
+ adns_r_srv_raw,
adns_r_txt,
adns_r_rp_raw,
+ adns_r_aaaa, /* Does the order matter? */
adns_r_addr,
adns_r_ns,
adns_r_ptr,
adns_r_mx,
+ adns_r_srv,
adns_r_soa,
adns_r_rp,
diff --git a/src/adns.h b/src/adns.h
index 34f9f49..34350ca 100644
--- a/src/adns.h
+++ b/src/adns.h
@@ -52,7 +52,7 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
- * $Id: adns.h,v 1.96 2006/08/09 11:16:59 ian Exp $
+ * $Id: adns.h,v 1.19 2007/10/03 20:01:05 nisse Exp $
*/
#ifndef ADNS_H_INCLUDED
@@ -71,6 +71,10 @@
extern "C" { /* I really dislike this - iwj. */
#endif
+#ifndef AF_INET6
+#include "adns-in6fake.h"
+#endif
+
/* All struct in_addr anywhere in adns are in NETWORK byte order. */
typedef struct adns__state *adns_state;
@@ -87,7 +91,10 @@ typedef enum { /* In general, or together the desired flags: */
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 { /* In general, or together the desired flags: */
@@ -101,9 +108,54 @@ typedef enum { /* In general, or together the desired flags: */
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 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 */
@@ -127,6 +179,8 @@ typedef enum {
*
* Don't forget adns_qf_quoteok if that's what you want. */
+ adns__qtf_special= 0x80000,/* no simple correspondence to a single rr type */
+
adns_r_none= 0,
adns_r_a= 1,
@@ -151,6 +205,7 @@ typedef enum {
adns_r_rp_raw= 17,
adns_r_rp= adns_r_rp_raw|adns__qtf_mail822,
+ adns_r_aaaa= 28, /* RFC 1886 */
/* For SRV records, query domain without _qf_quoteok_query must look
* as expected from SRV RFC with hostname-like Name. _With_
@@ -158,7 +213,8 @@ typedef enum {
adns_r_srv_raw= 33,
adns_r_srv= adns_r_srv_raw|adns__qtf_deref,
- adns_r_addr= adns_r_a|adns__qtf_deref
+ /* FIXME: Maybe add adns__qtf_deref too? */
+ adns_r_addr= 1 | adns__qtf_special,
} adns_rrtype;
@@ -284,9 +340,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;
@@ -355,6 +415,7 @@ 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 */
@@ -506,6 +567,13 @@ int adns_init_logfn(adns_state *newstate_r, adns_initflags flags,
* 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
@@ -589,7 +657,33 @@ 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 or 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. The defaultport is in
+ * hot byte order). In the `fallback' case, will invent an SRV record
+ * which 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,
@@ -602,7 +696,7 @@ int adns_submit_reverse_any(adns_state ads,
/* For RBL-style reverse `zone's; look up
* <reversed-address>.<zone>
* Any type is allowed. _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 or you get ENOSYS.
*/
void adns_finish(adns_state ads);
diff --git a/src/check.c b/src/check.c
index 41cdde5..8925ecb 100644
--- a/src/check.c
+++ b/src/check.c
@@ -24,6 +24,8 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <stdlib.h>
+
#include "internal.h"
void adns_checkconsistency(adns_state ads, adns_query qu) {
@@ -78,10 +80,10 @@ static void checkc_global(adns_state ads) {
int i;
assert(ads->udpsocket >= 0);
-
+#if 0
for (i=0; i<ads->nsortlist; 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 --git a/src/internal.h b/src/internal.h
index 58cd15d..1eb166d 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -129,6 +129,16 @@ typedef struct typeinfo {
* 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
@@ -176,6 +186,8 @@ adns_status adns__qdpl_normal(adns_state ads,
typedef struct allocnode {
struct allocnode *next, *back;
+ size_t size;
+ /* Needed for realloc */
} allocnode;
union maxalign {
@@ -191,11 +203,16 @@ typedef struct {
void *ext;
void (*callback)(adns_query parent, adns_query child);
union {
- adns_rr_addr ptr_parent_addr;
adns_rr_hostaddr *hostaddr;
} info;
} qcontext;
+typedef struct {
+ union {
+ adns_rr_addr ptr_addr;
+ } info;
+} qextra;
+
struct adns__query {
adns_state ads;
enum { query_tosend, query_tcpw, query_childw, query_done } state;
@@ -242,13 +259,19 @@ 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;
time_t expires; /* Earliest expiry time of any record we used. */
qcontext ctx;
+ /* Information related to the parent of the query */
+ qextra extra;
+ /* Extra information about this query. */
/* Possible states:
*
@@ -270,34 +293,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 +----------------+
@@ -333,7 +356,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;
unsigned short rand48xsubi[3];
@@ -401,6 +429,15 @@ void adns__sigpipe_unprotect(adns_state);
/* From transmit.c: */
+adns_status adns__mkquery_labels(adns_state ads, vbuf *vb,
+ const char *owner, int ol,
+ const typeinfo *typei, 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_rrtype type,
@@ -408,6 +445,11 @@ adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
/* 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,
@@ -447,6 +489,9 @@ adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
* 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
@@ -474,6 +519,7 @@ void adns__search_next(adns_state ads, adns_query qu, struct timeval now);
*/
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 --git a/src/query.c b/src/query.c
index d09702e..2894e4d 100644
--- a/src/query.c
+++ b/src/query.c
@@ -36,6 +36,10 @@
#include "internal.h"
+#if DMALLOC
+# include <dmalloc.h>
+#endif
+
static adns_query query_alloc(adns_state ads,
const typeinfo *typei, adns_rrtype type,
adns_queryflags flags, struct timeval now) {
@@ -76,6 +80,7 @@ static adns_query query_alloc(adns_state ads,
qu->expires= now.tv_sec + MAXTTLBELIEVE;
memset(&qu->ctx,0,sizeof(qu->ctx));
+ memset(&qu->extra,0,sizeof(qu->extra));
qu->answer->status= adns_s_ok;
qu->answer->cname= qu->answer->owner= 0;
@@ -88,6 +93,20 @@ static adns_query query_alloc(adns_state ads,
return qu;
}
+static adns_queryflags default_ip6_flags(adns_state ads)
+{
+ adns_queryflags flags = 0;
+
+ 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;
+
+ return flags;
+}
+
static void query_submit(adns_state ads, adns_query qu,
const typeinfo *typei, vbuf *qumsg_vb, int id,
adns_queryflags flags, struct timeval now) {
@@ -108,6 +127,7 @@ static void query_submit(adns_state ads, adns_query qu,
adns__query_send(qu,now);
}
+/* FIXME: Take a adns_rrtype type artument? */
adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
const typeinfo *typei, vbuf *qumsg_vb,
int id,
@@ -115,12 +135,26 @@ adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
const qcontext *ctx) {
adns_query qu;
+ if (!(flags & adns__qf_ip_mask))
+ flags |= default_ip6_flags(ads);
+
qu= query_alloc(ads,typei,typei->typekey,flags,now);
if (!qu) { adns__vbuf_free(qumsg_vb); return adns_s_nomemory; }
*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,21 +167,32 @@ static void query_simple(adns_state ads, adns_query qu,
int id;
adns_status stat;
- 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);
- return;
- } else {
- adns__query_fail(qu,stat);
- return;
+ if (typei->submithook) {
+ stat= adns__mkquery_labels(ads, &qu->vb, owner, ol, typei, 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,qu->answer->type,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) {
@@ -222,6 +267,9 @@ int adns_submit(adns_state ads,
adns__consistency(ads,0,cc_entex);
+ if (!(flags & adns__qf_ip_mask))
+ flags |= default_ip6_flags(ads);
+
typei= adns__findtype(type);
if (!typei) return ENOSYS;
@@ -288,13 +336,13 @@ int adns_submit_reverse_any(adns_state ads,
flags &= ~adns_qf_search;
- if (addr->sa_family != AF_INET) return ENOSYS;
- iaddr= (const unsigned char*)
- &(((const struct sockaddr_in*)addr) -> sin_addr);
-
+ switch (addr->sa_family) {
+ default: return ENOSYS;
+ case AF_INET:
+ iaddr= (const unsigned char*) &((const struct sockaddr_in*)addr)->sin_addr;
lreq= strlen(zone) + 4*4 + 1;
if (lreq > sizeof(shortbuf)) {
- buf= malloc(strlen(zone) + 4*4 + 1);
+ buf= malloc(lreq);
if (!buf) return errno;
buf_free= buf;
} else {
@@ -302,7 +350,32 @@ int adns_submit_reverse_any(adns_state ads,
buf_free= 0;
}
sprintf(buf, "%d.%d.%d.%d.%s", iaddr[3], iaddr[2], iaddr[1], iaddr[0], zone);
-
+ break;
+ case AF_INET6:
+ iaddr= (const unsigned char*) &((const struct sockaddr_in6*)addr)->sin6_addr;
+ lreq = strlen(zone) + 2*32 + 1;
+ if (lreq > sizeof(shortbuf)) {
+ buf= malloc(lreq);
+ if (!buf) return errno;
+ buf_free= buf;
+ }
+ else {
+ buf= shortbuf;
+ buf_free= 0;
+ }
+ strcpy(buf + 2*32, zone);
+ {
+ int i;
+ const unsigned char *p;
+ static const unsigned char hex[16] = "0123456789abcdef";
+ for (i = 0, p = iaddr + 15; i < 2*32; p--) {
+ buf[i++] = hex[*p & 0xf];
+ buf[i++] = '.';
+ buf[i++] = hex[*p / 0x10];
+ buf[i++] = '.';
+ }
+ }
+ }
r= adns_submit(ads,buf,type,flags,context,query_r);
free(buf_free);
return r;
@@ -314,9 +387,34 @@ int adns_submit_reverse(adns_state ads,
adns_queryflags flags,
void *context,
adns_query *query_r) {
+ int r;
+ /* Address record used for forward lookup and consistency check */
+ adns_rr_addr rr;
+ const char *zone;
+
if (type != adns_r_ptr && type != adns_r_ptr_raw) return EINVAL;
- return adns_submit_reverse_any(ads,addr,"in-addr.arpa",
+ memset(&rr, 0, sizeof(rr));
+ rr.addr.sa.sa_family = addr->sa_family;
+
+ switch (addr->sa_family) {
+ default: return ENOSYS;
+ case AF_INET:
+ zone = "in-addr.arpa";
+ rr.len = sizeof(rr.addr.inet);
+ rr.addr.inet.sin_addr = ((const struct sockaddr_in *)addr)->sin_addr;
+ break;
+ case AF_INET6:
+ zone = "ip6.arpa";
+ rr.len = sizeof(rr.addr.inet6);
+ rr.addr.inet6.sin6_addr = ((const struct sockaddr_in6 *)addr)->sin6_addr;
+ break;
+ }
+
+ r= adns_submit_reverse_any(ads,addr,zone,
type,flags,context,query_r);
+ if (r) return r;
+ (*query_r)->extra.info.ptr_addr = rr;
+ return 0;
}
int adns_synchronous(adns_state ads,
@@ -344,9 +442,36 @@ static void *alloc_common(adns_query qu, size_t sz) {
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) {
void *rv;
diff --git a/src/setup.c b/src/setup.c
index 44c3cee..57037cc 100644
--- a/src/setup.c
+++ b/src/setup.c
@@ -150,6 +150,7 @@ static void ccf_search(adns_state ads, const char *fn,
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;
@@ -191,6 +192,21 @@ static void ccf_sortlist(adns_state ads, const char *fn,
" 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) {
@@ -202,11 +218,11 @@ static void ccf_sortlist(adns_state ads, const char *fn,
} 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,"
@@ -215,8 +231,10 @@ static void ccf_sortlist(adns_state ads, const char *fn,
}
}
- 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 --git a/src/transmit.c b/src/transmit.c
index 7afb90f..73ecd91 100644
--- a/src/transmit.c
+++ b/src/transmit.c
@@ -62,6 +62,8 @@ static adns_status mkquery_header(adns_state ads, vbuf *vb,
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;
@@ -118,17 +120,15 @@ adns_status adns__qdpl_normal(adns_state ads,
return adns_s_ok;
}
-adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
+adns_status adns__mkquery_labels(adns_state ads, vbuf *vb,
const char *owner, int ol,
- const typeinfo *typei, adns_rrtype type,
- adns_queryflags flags) {
+ const typeinfo *typei, adns_queryflags flags) {
int labelnum, ll, nbytes;
- byte label[255];
- byte *rqp;
+ 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);
@@ -149,22 +149,31 @@ adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
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_rrtype type,
+ adns_queryflags flags) {
+ adns_status st;
+ st= mkquery_header(ads,vb,id_r,ol+2); if (st) return st;
+ st= adns__mkquery_labels(ads, vb, owner, ol, typei, flags); if (st) return st;
st= mkquery_footer(vb,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);
@@ -181,6 +190,30 @@ adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r,
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 --git a/src/types.c b/src/types.c
index 36ff879..bed890a 100644
--- a/src/types.c
+++ b/src/types.c
@@ -48,12 +48,15 @@
* _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)
* _mx_raw (pa,di)
* _mx (pa,di)
+ * _srv_raw (pa,di,mf,cs)
+ * _srv (pa,di,mf,cs)
* _inthostaddr (mf,cs)
* _ptr (pa)
* _strpair (mf,cs)
@@ -251,14 +254,20 @@ static adns_status pa_inaddr(const parseinfo *pai, int cbyte,
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;
- i<ads->nsortlist &&
- !((ad.s_addr & slp->mask.s_addr) == slp->base.s_addr);
- i++, slp++);
+ i<ads->nsortlist;
+ 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;
}
@@ -267,8 +276,8 @@ static int dip_inaddr(adns_state ads, struct in_addr a, struct in_addr b) {
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 bi<ai;
}
@@ -289,27 +298,297 @@ static adns_status cs_inaddr(vbuf *vb, const void *datap) {
}
/*
- * _addr (pa,di,csp,cs)
+ * _in6addr (pa,dip,di)
*/
-static adns_status pa_addr(const parseinfo *pai, int cbyte,
+static adns_status pa_in6addr(const parseinfo *pai, int cbyte,
int max, void *datap) {
- adns_rr_addr *storeto= datap;
+ struct in_addr *storeto= datap;
+
+ if (max-cbyte != 16) return adns_s_invaliddata;
+ memcpy(storeto, pai->dgram + 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;
+ i<ads->nsortlist;
+ 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 bi<ai;
+}
+
+static int di_in6addr(adns_state ads,
+ const void *datap_a, const void *datap_b) {
+ const struct in6_addr *ap= datap_a, *bp= datap_b;
+
+ return dip_in6addr(ads,ap,bp);
+}
+
+
+static adns_status cs_in6addr(vbuf *vb, const void *datap) {
+ char buf[INET6_ADDRSTRLEN];
+ const char *ia;
+
+ ia= inet_ntop(AF_INET6, datap, buf, sizeof(buf)); assert(ia);
+ CSP_ADDSTR(ia);
+ return adns_s_ok;
+}
+
+/*
+ * _addr (sh,pa,di,csp,cs)
+ */
+
+static void mk_mapped_ipv6(struct sockaddr_in6 *sa, const struct in_addr *in) {
+ memset(sa, 0, sizeof(*sa));
+ sa->sin6_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) {
+ adns_answer *cans= child->answer;
+ adns_answer *pans= parent->answer;
+ adns_state ads= parent->ads;
+ adns_rr_addr *addr;
+
+ int i;
+
+ if (parent->expires > child->expires) parent->expires = child->expires;
+
+ if (cans->status == adns_s_nxdomain) {
+ adns__query_fail(parent,cans->status);
+ return;
+ }
+ if (cans->status == adns_s_nodata && parent->children.head) {
+ /* We may get records from the remaining queries */
+ LIST_LINK_TAIL(ads->childw,parent);
+ return;
+ }
+ if (cans->status) {
+ if (pans->nrrs)
+ adns__query_done(parent);
+ else
+ 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;
+ }
+
+ switch (cans->type) {
+ default: abort();
+ case adns_r_a:
+ if (parent->flags & adns_qf_ip6mapped)
+ for (i = 0; i<cans->nrrs; i++) {
+ addr[i].len = sizeof(struct sockaddr_in6);
+ mk_mapped_ipv6(&addr[i].addr.inet6, &cans->rrs.inaddr[i]);
+ }
+ else
+ for (i = 0; i<cans->nrrs; 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; i<cans->nrrs; 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;
+
+ assert(flags & adns__qf_ip_mask);
+
+ /* 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 dip_addr(adns_state ads,
+ const adns_rr_addr *a, const adns_rr_addr *b) {
+ int ai, bi;
+ ai = search_sortlist_addr(ads, a);
+ bi = search_sortlist_addr(ads, b);
+ return bi<ai;
+}
+
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);
+ return dip_addr(ads, ap, bp);
}
static int div_addr(void *context, const void *datap_a, const void *datap_b) {
@@ -320,7 +599,7 @@ 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;
- char buf[30];
+ char buf[INET6_ADDRSTRLEN];
switch (rrp->addr.inet.sin_family) {
case AF_INET:
@@ -328,6 +607,12 @@ static adns_status csp_addr(vbuf *vb, const adns_rr_addr *rrp) {
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);
@@ -424,17 +709,22 @@ static adns_status pap_findaddrs(const parseinfo *pai, adns_rr_hostaddr *ha,
&type, &class, &ttl, &rdlen, &rdstart,
pai->dgram, pai->dglen, dmstart, &ownermatched);
if (st) return st;
- if (!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++;
}
@@ -476,7 +766,6 @@ static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io,
adns_status st;
int dmstart, cbyte;
qcontext ctx;
- int id;
adns_query nqu;
adns_queryflags nflags;
@@ -500,9 +789,8 @@ static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io,
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;
@@ -513,7 +801,7 @@ static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io,
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;
@@ -539,11 +827,7 @@ static int dip_hostaddr(adns_state ads,
if (ap->astatus != bp->astatus) return ap->astatus;
if (ap->astatus) return 0;
- assert(ap->addrs[0].addr.sa.sa_family == AF_INET);
- assert(bp->addrs[0].addr.sa.sa_family == AF_INET);
- return dip_inaddr(ads,
- ap->addrs[0].addr.inet.sin_addr,
- bp->addrs[0].addr.inet.sin_addr);
+ return dip_addr(ads, &ap->addrs[0], &bp->addrs[0]);
}
static int di_hostaddr(adns_state ads,
@@ -717,7 +1001,7 @@ static void icb_ptr(adns_query parent, adns_query child) {
return;
}
- queried= &parent->ctx.info.ptr_parent_addr;
+ queried= &parent->extra.info.ptr_addr;
for (i=0, found=cans->rrs.addr; i<cans->nrrs; i++, found++) {
if (queried->len == found->len &&
!memcmp(&queried->addr,&found->addr,queried->len)) {
@@ -734,18 +1018,14 @@ static void icb_ptr(adns_query parent, adns_query child) {
adns__query_fail(parent,adns_s_inconsistent);
}
+/* FIXME: Completely different in adns-1.4. */
static adns_status pa_ptr(const parseinfo *pai, int dmstart,
int max, void *datap) {
static const char *const (expectdomain[])= { DNS_INADDR_ARPA };
char **rrp= datap;
adns_status st;
- adns_rr_addr *ap;
- findlabel_state fls;
- char *ep;
- byte ipv[4];
- char labbuf[4];
- int cbyte, i, lablen, labstart, l, id;
+ int cbyte;
adns_query nqu;
qcontext ctx;
@@ -755,48 +1035,20 @@ static adns_status pa_ptr(const parseinfo *pai, int dmstart,
if (st) return st;
if (cbyte != max) return adns_s_invaliddata;
- ap= &pai->qu->ctx.info.ptr_parent_addr;
- if (!ap->len) {
- adns__findlabel_start(&fls, pai->ads, -1, pai->qu,
- pai->qu->query_dgram, pai->qu->query_dglen,
- pai->qu->query_dglen, DNS_HDRSIZE, 0);
- for (i=0; i<4; i++) {
- st= adns__findlabel_next(&fls,&lablen,&labstart); assert(!st);
- if (lablen<=0 || lablen>3) return adns_s_querydomainwrong;
- memcpy(labbuf, pai->qu->query_dgram + labstart, lablen);
- labbuf[lablen]= 0;
- ipv[3-i]= strtoul(labbuf,&ep,10);
- if (*ep) return adns_s_querydomainwrong;
- if (lablen>1 && pai->qu->query_dgram[labstart]=='0')
- return adns_s_querydomainwrong;
- }
- for (i=0; i<sizeof(expectdomain)/sizeof(*expectdomain); i++) {
- st= adns__findlabel_next(&fls,&lablen,&labstart); assert(!st);
- l= strlen(expectdomain[i]);
- if (lablen != l ||
- memcmp(pai->qu->query_dgram + labstart, expectdomain[i], l))
- return adns_s_querydomainwrong;
- }
- st= adns__findlabel_next(&fls,&lablen,0); assert(!st);
- if (lablen) return adns_s_querydomainwrong;
-
- ap->len= sizeof(struct sockaddr_in);
- memset(&ap->addr,0,sizeof(ap->addr.inet));
- ap->addr.inet.sin_family= AF_INET;
- ap->addr.inet.sin_addr.s_addr=
- htonl((ipv[0]<<24) | (ipv[1]<<16) | (ipv[2]<<8) | (ipv[3]));
- }
+ /* Should be initialized by adns_submit_reverse. If it's not, we
+ * can't do any consistency checking. */
+ if (!pai->qu->extra.info.ptr_addr.len) 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);
+ pai->qu->vb.used = 0;
+ 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;
@@ -1250,13 +1502,16 @@ static void mf_flat(adns_query qu, void *data) { }
#define DEEP_TYPE(code,rrt,fmt,memb,parser,comparer,printer) \
{ adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_##memb, \
- printer,parser,comparer, adns__qdpl_normal,0 }
+ printer,0,parser,comparer, adns__qdpl_normal,0 }
#define FLAT_TYPE(code,rrt,fmt,memb,parser,comparer,printer) \
{ adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_flat, \
- printer,parser,comparer, adns__qdpl_normal,0 }
+ printer,0,parser,comparer, adns__qdpl_normal,0 }
#define XTRA_TYPE(code,rrt,fmt,memb,parser,comparer,printer,qdpl,postsort) \
{ adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_##memb, \
- printer,parser,comparer,qdpl,postsort }
+ printer,0,parser,comparer,qdpl,postsort }
+#define SPECIAL_TYPE(code,rrt,fmt,memb,submit,comparer,printer) \
+ { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_flat, \
+ printer,submit,0,comparer, adns__qdpl_normal,0 }
static const typeinfo typeinfos[] = {
/* Must be in ascending order of rrtype ! */
@@ -1271,10 +1526,11 @@ DEEP_TYPE(hinfo, "HINFO", 0, intstrpair,pa_hinfo, 0, cs_hinfo ),
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 ),
XTRA_TYPE(srv_raw,"SRV", "raw",srvraw , pa_srvraw, di_srv, cs_srvraw,
qdpl_srv, postsort_srv),
-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),
@@ -1283,6 +1539,9 @@ XTRA_TYPE(srv, "SRV","+addr",srvha, pa_srvha, di_srv, cs_srvha,
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+AAAA>", "addr",addr,sh_addr, di_addr, cs_addr ),
};
static const typeinfo typeinfo_unknown=