diff --git a/Makefile b/Makefile index 5ba3e19..a87bc87 100644 --- a/Makefile +++ b/Makefile @@ -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/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 , 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/regress/case-connfail.sys b/regress/case-connfail.sys index b62923b..2064368 100644 --- a/regress/case-connfail.sys +++ b/regress/case-connfail.sys @@ -3,76 +3,88 @@ start 1056289303.784817 socket type=SOCK_DGRAM socket=6 + +0.000066 + socket type=SOCK_DGRAM + socket=7 +0.000031 fcntl fd=6 cmd=F_GETFL fcntl=~O_NONBLOCK&... +0.000010 fcntl fd=6 cmd=F_SETFL O_NONBLOCK|... fcntl=OK + +0.000264 + fcntl fd=7 cmd=F_GETFL + fcntl=~O_NONBLOCK&... + +0.000087 + fcntl fd=7 cmd=F_SETFL O_NONBLOCK|... + fcntl=OK +0.000007 socket type=SOCK_STREAM - socket=7 + socket=8 +0.000059 - fcntl fd=7 cmd=F_GETFL + fcntl fd=8 cmd=F_GETFL fcntl=~O_NONBLOCK&... +0.000007 - fcntl fd=7 cmd=F_SETFL O_NONBLOCK|... + fcntl fd=8 cmd=F_SETFL O_NONBLOCK|... fcntl=OK +0.000006 - connect fd=7 addr=172.18.45.36:53 + connect fd=8 addr=172.18.45.36:53 connect=ENOTSOCK +0.000013 - close fd=7 + close fd=8 close=OK +0.000031 socket type=SOCK_STREAM - socket=7 + socket=8 +0.000035 - fcntl fd=7 cmd=F_GETFL + fcntl fd=8 cmd=F_GETFL fcntl=~O_NONBLOCK&... +0.000006 - fcntl fd=7 cmd=F_SETFL O_NONBLOCK|... + fcntl fd=8 cmd=F_SETFL O_NONBLOCK|... fcntl=OK +0.000007 - connect fd=7 addr=172.18.45.6:53 + connect fd=8 addr=172.18.45.6:53 connect=ENOTSOCK +0.000008 - close fd=7 + close fd=8 close=OK +0.000013 - select max=7 rfds=[6] wfds=[] efds=[] to=0.000000 + select max=8 rfds=[6,7] wfds=[] efds=[] to=0.000000 select=0 rfds=[] wfds=[] efds=[] +0.000036 socket type=SOCK_STREAM - socket=7 + socket=8 +0.000036 - fcntl fd=7 cmd=F_GETFL + fcntl fd=8 cmd=F_GETFL fcntl=~O_NONBLOCK&... +0.000007 - fcntl fd=7 cmd=F_SETFL O_NONBLOCK|... + fcntl fd=8 cmd=F_SETFL O_NONBLOCK|... fcntl=OK +0.000006 - connect fd=7 addr=172.18.45.36:53 + connect fd=8 addr=172.18.45.36:53 connect=ENOTSOCK +0.000008 - close fd=7 + close fd=8 close=OK +0.000013 socket type=SOCK_STREAM - socket=7 + socket=8 +0.000036 - fcntl fd=7 cmd=F_GETFL + fcntl fd=8 cmd=F_GETFL fcntl=~O_NONBLOCK&... +0.000007 - fcntl fd=7 cmd=F_SETFL O_NONBLOCK|... + fcntl fd=8 cmd=F_SETFL O_NONBLOCK|... fcntl=OK +0.000006 - connect fd=7 addr=172.18.45.6:53 + connect fd=8 addr=172.18.45.6:53 connect=ENOTSOCK +0.000008 - close fd=7 + close fd=8 close=OK +0.000012 close fd=6 close=OK + +0.000067 + close fd=7 + close=OK +0.000023 diff --git a/regress/case-flags10.sys b/regress/case-flags10.sys index fe0b341..99f1f8b 100644 --- a/regress/case-flags10.sys +++ b/regress/case-flags10.sys @@ -3,13 +3,25 @@ adnstest default start 929580072.670441 socket type=SOCK_DGRAM socket=4 + +0.000066 + socket type=SOCK_DGRAM + socket=7 +0.000191 fcntl fd=4 cmd=F_GETFL fcntl=~O_NONBLOCK&... +0.000084 fcntl fd=4 cmd=F_SETFL O_NONBLOCK|... fcntl=OK + +0.000264 + fcntl fd=7 cmd=F_GETFL + fcntl=~O_NONBLOCK&... + +0.000087 + fcntl fd=7 cmd=F_SETFL O_NONBLOCK|... + fcntl=OK +0.000061 close fd=4 close=OK + +0.000067 + close fd=7 + close=OK +0.000001 diff --git a/regress/case-longdom1.sys b/regress/case-longdom1.sys index a54e14d..6920322 100644 --- a/regress/case-longdom1.sys +++ b/regress/case-longdom1.sys @@ -3,13 +3,25 @@ adnstest default start 951955690.505811 socket type=SOCK_DGRAM socket=4 + +0.000066 + socket type=SOCK_DGRAM + socket=7 +0.000126 fcntl fd=4 cmd=F_GETFL fcntl=~O_NONBLOCK&... +0.000058 fcntl fd=4 cmd=F_SETFL O_NONBLOCK|... fcntl=OK + +0.000264 + fcntl fd=7 cmd=F_GETFL + fcntl=~O_NONBLOCK&... + +0.000087 + fcntl fd=7 cmd=F_SETFL O_NONBLOCK|... + fcntl=OK +0.000035 close fd=4 close=OK + +0.000067 + close fd=7 + close=OK +0.000269 diff --git a/regress/case-longdomsrch0.sys b/regress/case-longdomsrch0.sys index 298bec8..94be025 100644 --- a/regress/case-longdomsrch0.sys +++ b/regress/case-longdomsrch0.sys @@ -3,13 +3,25 @@ adnstest ndots100 start 951956073.321566 socket type=SOCK_DGRAM socket=4 + +0.000066 + socket type=SOCK_DGRAM + socket=7 +0.000131 fcntl fd=4 cmd=F_GETFL fcntl=~O_NONBLOCK&... +0.000056 fcntl fd=4 cmd=F_SETFL O_NONBLOCK|... fcntl=OK + +0.000264 + fcntl fd=7 cmd=F_GETFL + fcntl=~O_NONBLOCK&... + +0.000087 + fcntl fd=7 cmd=F_SETFL O_NONBLOCK|... + fcntl=OK +0.000034 close fd=4 close=OK + +0.000067 + close fd=7 + close=OK +0.000340 diff --git a/regress/case-longlab1.sys b/regress/case-longlab1.sys index 5b0e46a..d832c9d 100644 --- a/regress/case-longlab1.sys +++ b/regress/case-longlab1.sys @@ -3,13 +3,25 @@ adnstest default start 951955261.286712 socket type=SOCK_DGRAM socket=4 + +0.000066 + socket type=SOCK_DGRAM + socket=7 +0.000128 fcntl fd=4 cmd=F_GETFL fcntl=~O_NONBLOCK&... +0.000053 fcntl fd=4 cmd=F_SETFL O_NONBLOCK|... fcntl=OK + +0.000264 + fcntl fd=7 cmd=F_GETFL + fcntl=~O_NONBLOCK&... + +0.000087 + fcntl fd=7 cmd=F_SETFL O_NONBLOCK|... + fcntl=OK +0.000033 close fd=4 close=OK + +0.000067 + close fd=7 + close=OK +0.000238 diff --git a/regress/case-tcpmultipart.sys b/regress/case-tcpmultipart.sys index d26ded2..00e2488 100644 --- a/regress/case-tcpmultipart.sys +++ b/regress/case-tcpmultipart.sys @@ -3,12 +3,21 @@ adnstest tunnel start 938365454.994875 socket type=SOCK_DGRAM socket=4 + +0.000066 + socket type=SOCK_DGRAM + socket=7 +0.000164 fcntl fd=4 cmd=F_GETFL fcntl=~O_NONBLOCK&... +0.000055 fcntl fd=4 cmd=F_SETFL O_NONBLOCK|... fcntl=OK + +0.000264 + fcntl fd=7 cmd=F_GETFL + fcntl=~O_NONBLOCK&... + +0.000087 + fcntl fd=7 cmd=F_SETFL O_NONBLOCK|... + fcntl=OK +0.000043 socket type=SOCK_STREAM socket=5 @@ -22,7 +31,7 @@ adnstest tunnel connect fd=5 addr=172.31.80.9:53 connect=EINPROGRESS +0.000414 - select max=6 rfds=[4] wfds=[5] efds=[] to=13.998324 + select max=8 rfds=[4,7] wfds=[5] efds=[] to=13.998324 select=1 rfds=[] wfds=[5] efds=[] +1.-647444 read fd=5 buflen=1 @@ -43,7 +52,7 @@ adnstest tunnel 2d616464 72046172 70610000 0c0001. write=47 +0.000273 - select max=6 rfds=[4,5] wfds=[] efds=[5] to=29.644233 + select max=8 rfds=[4,5,7] wfds=[] efds=[5] to=29.644233 select=1 rfds=[5] wfds=[] efds=[] +0.538651 read fd=5 buflen=2 @@ -66,7 +75,7 @@ adnstest tunnel read fd=5 buflen=297 read=EAGAIN +0.000476 - select max=6 rfds=[4,5] wfds=[] efds=[5] to=29.105246 + select max=8 rfds=[4,5,7] wfds=[] efds=[5] to=29.105246 select=1 rfds=[5] wfds=[] efds=[] +1.-401146 read fd=5 buflen=297 @@ -109,7 +118,7 @@ adnstest tunnel read fd=5 buflen=2572 read=EAGAIN +0.000101 - select max=6 rfds=[4,5] wfds=[] efds=[5] to=28.502804 + select max=8 rfds=[4,5,7] wfds=[] efds=[5] to=28.502804 select=1 rfds=[5] wfds=[] efds=[] +0.336462 read fd=5 buflen=2572 @@ -148,7 +157,7 @@ adnstest tunnel read fd=5 buflen=1624 read=EAGAIN +0.000124 - select max=6 rfds=[4,5] wfds=[] efds=[5] to=28.162903 + select max=8 rfds=[4,5,7] wfds=[] efds=[5] to=28.162903 select=1 rfds=[5] wfds=[] efds=[] +1.-683589 read fd=5 buflen=1624 @@ -187,7 +196,7 @@ adnstest tunnel read fd=5 buflen=676 read=EAGAIN +0.000114 - select max=6 rfds=[4,5] wfds=[] efds=[5] to=27.843177 + select max=8 rfds=[4,5,7] wfds=[] efds=[5] to=27.843177 select=1 rfds=[5] wfds=[] efds=[] +0.376863 read fd=5 buflen=676 @@ -230,7 +239,7 @@ adnstest tunnel read fd=5 buflen=3248 read=EAGAIN +0.000066 - select max=6 rfds=[4,5] wfds=[] efds=[5] to=27.454446 + select max=8 rfds=[4,5,7] wfds=[] efds=[5] to=27.454446 select=1 rfds=[5] wfds=[] efds=[] +0.316770 read fd=5 buflen=3248 @@ -242,6 +251,9 @@ adnstest tunnel +0.000429 close fd=4 close=OK + +0.000067 + close fd=7 + close=OK +0.000375 close fd=5 close=OK diff --git a/regress/case-timeout.sys b/regress/case-timeout.sys index f810c3b..756becc 100644 --- a/regress/case-timeout.sys +++ b/regress/case-timeout.sys @@ -3,19 +3,28 @@ adnstest noserver start 912889153.349504 socket type=SOCK_DGRAM socket=4 + +0.000066 + socket type=SOCK_DGRAM + socket=7 +0.000193 fcntl fd=4 cmd=F_GETFL fcntl=~O_NONBLOCK&... +0.000088 fcntl fd=4 cmd=F_SETFL O_NONBLOCK|... fcntl=OK + +0.000264 + fcntl fd=7 cmd=F_GETFL + fcntl=~O_NONBLOCK&... + +0.000087 + fcntl fd=7 cmd=F_SETFL O_NONBLOCK|... + fcntl=OK +0.000072 sendto fd=4 addr=172.18.45.36:53 311f0100 00010000 00000000 06636869 61726b08 67726565 6e656e64 036f7267 02756b00 00010001. sendto=40 +0.000617 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999383 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999383 select=0 rfds=[] wfds=[] efds=[] +2.008683 sendto fd=4 addr=172.18.45.36:53 @@ -23,7 +32,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000406 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999594 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999594 select=0 rfds=[] wfds=[] efds=[] +2.009544 sendto fd=4 addr=172.18.45.36:53 @@ -31,7 +40,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000428 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999572 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999572 select=0 rfds=[] wfds=[] efds=[] +2.009567 sendto fd=4 addr=172.18.45.36:53 @@ -39,7 +48,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000449 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999551 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999551 select=0 rfds=[] wfds=[] efds=[] +2.009551 sendto fd=4 addr=172.18.45.36:53 @@ -47,7 +56,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000381 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999619 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999619 select=0 rfds=[] wfds=[] efds=[] +2.009614 sendto fd=4 addr=172.18.45.36:53 @@ -55,7 +64,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000383 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999617 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999617 select=0 rfds=[] wfds=[] efds=[] +2.009622 sendto fd=4 addr=172.18.45.36:53 @@ -63,7 +72,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000387 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999613 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999613 select=0 rfds=[] wfds=[] efds=[] +2.009603 sendto fd=4 addr=172.18.45.36:53 @@ -71,7 +80,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000404 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999596 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999596 select=0 rfds=[] wfds=[] efds=[] +2.009607 sendto fd=4 addr=172.18.45.36:53 @@ -79,7 +88,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000468 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999532 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999532 select=0 rfds=[] wfds=[] efds=[] +2.009526 sendto fd=4 addr=172.18.45.36:53 @@ -87,7 +96,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000431 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999569 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999569 select=0 rfds=[] wfds=[] efds=[] +2.009564 sendto fd=4 addr=172.18.45.36:53 @@ -95,7 +104,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000429 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999571 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999571 select=0 rfds=[] wfds=[] efds=[] +2.009586 sendto fd=4 addr=172.18.45.36:53 @@ -103,7 +112,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000479 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999521 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999521 select=0 rfds=[] wfds=[] efds=[] +2.009511 sendto fd=4 addr=172.18.45.36:53 @@ -111,7 +120,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000430 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999570 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999570 select=0 rfds=[] wfds=[] efds=[] +2.009571 sendto fd=4 addr=172.18.45.36:53 @@ -119,7 +128,7 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000440 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999560 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999560 select=0 rfds=[] wfds=[] efds=[] +2.009564 sendto fd=4 addr=172.18.45.36:53 @@ -127,9 +136,12 @@ adnstest noserver 02756b00 00010001. sendto=40 +0.000439 - select max=5 rfds=[4] wfds=[] efds=[] to=1.999561 + select max=8 rfds=[4,7] wfds=[] efds=[] to=1.999561 select=0 rfds=[] wfds=[] efds=[] +2.009554 close fd=4 close=OK + +0.000067 + close fd=7 + close=OK +0.000267 diff --git a/regress/case-unknownq.sys b/regress/case-unknownq.sys index 736210d..052c028 100644 --- a/regress/case-unknownq.sys +++ b/regress/case-unknownq.sys @@ -3,13 +3,25 @@ adnstest default start 933811310.565828 socket type=SOCK_DGRAM socket=4 + +0.000066 + socket type=SOCK_DGRAM + socket=7 +0.000264 fcntl fd=4 cmd=F_GETFL fcntl=~O_NONBLOCK&... +0.000087 fcntl fd=4 cmd=F_SETFL O_NONBLOCK|... fcntl=OK + +0.000264 + fcntl fd=7 cmd=F_GETFL + fcntl=~O_NONBLOCK&... + +0.000087 + fcntl fd=7 cmd=F_SETFL O_NONBLOCK|... + fcntl=OK +0.000067 close fd=4 close=OK + +0.000067 + close fd=7 + close=OK +0.000307 diff --git a/regress/hcommon.c b/regress/hcommon.c index 0324e58..60cd7cc 100644 --- a/regress/hcommon.c +++ b/regress/hcommon.c @@ -144,10 +144,18 @@ void Qwrite( int fd , const void *buf , size_t len ) { Q_vb(); } void Tvbaddr(const struct sockaddr *addr, int len) { - const struct sockaddr_in *ai= (const struct sockaddr_in*)addr; - assert(len==sizeof(struct sockaddr_in)); - assert(ai->sin_family==AF_INET); - Tvbf("%s:%u",inet_ntoa(ai->sin_addr),htons(ai->sin_port)); + if(addr->sa_family==AF_INET) { + const struct sockaddr_in *ai= (const struct sockaddr_in*)addr; + assert(len==sizeof(struct sockaddr_in)); + assert(ai->sin_family==AF_INET); + Tvbf("%s:%u",inet_ntoa(ai->sin_addr),htons(ai->sin_port)); + } else { + char buf[INET6_ADDRSTRLEN]; + const struct sockaddr_in6 *ai6= (const struct sockaddr_in6*)addr; + assert(len==sizeof(struct sockaddr_in6)); + assert(ai6->sin6_family==AF_INET6); + Tvbf("%s:%u",inet_ntop(AF_INET6, &(ai6->sin6_addr), buf, sizeof(buf)),htons(ai6->sin6_port)); + } } void Tvbbytes(const void *buf, int len) { const byte *bp; diff --git a/regress/hcommon.c.m4 b/regress/hcommon.c.m4 index 0f205fe..5de19d4 100644 --- a/regress/hcommon.c.m4 +++ b/regress/hcommon.c.m4 @@ -129,11 +129,18 @@ m4_define(`hm_specsyscall', `') m4_include(`hsyscalls.i4') void Tvbaddr(const struct sockaddr *addr, int len) { - const struct sockaddr_in *ai= (const struct sockaddr_in*)addr; - - assert(len==sizeof(struct sockaddr_in)); - assert(ai->sin_family==AF_INET); - Tvbf("%s:%u",inet_ntoa(ai->sin_addr),htons(ai->sin_port)); + if(addr->sa_family==AF_INET) { + const struct sockaddr_in *ai= (const struct sockaddr_in*)addr; + assert(len==sizeof(struct sockaddr_in)); + assert(ai->sin_family==AF_INET); + Tvbf("%s:%u",inet_ntoa(ai->sin_addr),htons(ai->sin_port)); + } else { + char buf[INET6_ADDRSTRLEN]; + const struct sockaddr_in6 *ai6= (const struct sockaddr_in6*)addr; + assert(len==sizeof(struct sockaddr_in6)); + assert(ai6->sin6_family==AF_INET6); + Tvbf("%s:%u",inet_ntop(AF_INET6, &(ai6->sin6_addr), buf, sizeof(buf)),htons(ai6->sin6_port)); + } } void Tvbbytes(const void *buf, int len) { diff --git a/regress/hplayback.c b/regress/hplayback.c index 594f7e6..e0e2246 100644 --- a/regress/hplayback.c +++ b/regress/hplayback.c @@ -153,22 +153,42 @@ static void Ppollfds(struct pollfd *fds, int nfds) { } #endif static void Paddr(struct sockaddr *addr, int *lenr) { + struct sockaddr_in6 *sa6= (struct sockaddr_in6*)addr; struct sockaddr_in *sa= (struct sockaddr_in*)addr; char *p, *ep; long ul; assert(*lenr >= sizeof(*sa)); - p= strchr(vb2.buf+vb2.used,':'); - if (!p) Psyntax("no port on address"); - *p++= 0; memset(sa,0,sizeof(*sa)); - sa->sin_family= AF_INET; - if (!inet_aton(vb2.buf+vb2.used,&sa->sin_addr)) Psyntax("invalid address"); - ul= strtoul(p,&ep,10); - if (*ep && *ep != ' ') Psyntax("invalid port (bad syntax)"); - if (ul >= 65536) Psyntax("port too large"); - sa->sin_port= htons(ul); - *lenr= sizeof(*sa); - vb2.used= ep - (char*)vb2.buf; + if (!inet_aton(vb2.buf+vb2.used,&sa->sin_addr)){ + p= strchr(vb2.buf+vb2.used,':'); + if (!p) Psyntax("no port on address"); + *p++= 0; + sa->sin_family= AF_INET; + ul= strtoul(p,&ep,10); + if (*ep && *ep != ' ') Psyntax("invalid port (bad syntax)"); + if (ul >= 65536) Psyntax("port too large"); + sa->sin_port= htons(ul); + *lenr= sizeof(*sa); + vb2.used= ep - (char*)vb2.buf; + return; + } else { + assert(*lenr >= sizeof(*sa6)); + memset(sa6,0,sizeof(*sa6)); + if (!inet_pton(AF_INET6, vb2.buf+vb2.used, &sa6->sin6_addr)) { + p= strrchr(vb2.buf+vb2.used,':'); + if (!p) Psyntax("no port on address"); + *p++= 0; + sa6->sin6_family= AF_INET6; + ul= strtoul(p,&ep,10); + if (*ep && *ep != ' ') Psyntax("invalid port (bad syntax)"); + if (ul >= 65536) Psyntax("port too large"); + sa6->sin6_port= htons(ul); + *lenr= sizeof(*sa6); + vb2.used= ep - (char*)vb2.buf; + return; + } + } + Psyntax("invalid address"); } static int Pbytes(byte *buf, int maxlen) { static const char hexdigits[]= "0123456789abcdef"; @@ -283,7 +303,6 @@ int Hpoll( struct pollfd *fds , int nfds , int timeout ) { int Hsocket( int domain , int type , int protocol ) { int r, amtread; char *ep; - Tmust("socket","domain",domain==AF_INET); Tmust("socket","type",type==SOCK_STREAM || type==SOCK_DGRAM); Qsocket( type ); if (!adns__vbuf_ensure(&vb2,1000)) Tnomem(); diff --git a/regress/hplayback.c.m4 b/regress/hplayback.c.m4 index 868aa52..d023b7c 100644 --- a/regress/hplayback.c.m4 +++ b/regress/hplayback.c.m4 @@ -210,24 +210,42 @@ static void Ppollfds(struct pollfd *fds, int nfds) { #endif static void Paddr(struct sockaddr *addr, int *lenr) { + struct sockaddr_in6 *sa6= (struct sockaddr_in6*)addr; struct sockaddr_in *sa= (struct sockaddr_in*)addr; char *p, *ep; long ul; - assert(*lenr >= sizeof(*sa)); - p= strchr(vb2.buf+vb2.used,':'); - if (!p) Psyntax("no port on address"); - *p++= 0; memset(sa,0,sizeof(*sa)); - sa->sin_family= AF_INET; - if (!inet_aton(vb2.buf+vb2.used,&sa->sin_addr)) Psyntax("invalid address"); - ul= strtoul(p,&ep,10); - if (*ep && *ep != hm_squote hm_squote) Psyntax("invalid port (bad syntax)"); - if (ul >= 65536) Psyntax("port too large"); - sa->sin_port= htons(ul); - *lenr= sizeof(*sa); - - vb2.used= ep - (char*)vb2.buf; + if (!inet_aton(vb2.buf+vb2.used,&sa->sin_addr)){ + p= strchr(vb2.buf+vb2.used,':'); + if (!p) Psyntax("no port on address"); + *p++= 0; + sa->sin_family= AF_INET; + ul= strtoul(p,&ep,10); + if (*ep && *ep != ' ') Psyntax("invalid port (bad syntax)"); + if (ul >= 65536) Psyntax("port too large"); + sa->sin_port= htons(ul); + *lenr= sizeof(*sa); + vb2.used= ep - (char*)vb2.buf; + return; + } else { + assert(*lenr >= sizeof(*sa6)); + memset(sa6,0,sizeof(*sa6)); + if (!inet_pton(AF_INET6, vb2.buf+vb2.used, &sa6->sin6_addr)) { + p= strrchr(vb2.buf+vb2.used,':'); + if (!p) Psyntax("no port on address"); + *p++= 0; + sa6->sin6_family= AF_INET6; + ul= strtoul(p,&ep,10); + if (*ep && *ep != ' ') Psyntax("invalid port (bad syntax)"); + if (ul >= 65536) Psyntax("port too large"); + sa6->sin6_port= htons(ul); + *lenr= sizeof(*sa6); + vb2.used= ep - (char*)vb2.buf; + return; + } + } + Psyntax("invalid address"); } static int Pbytes(byte *buf, int maxlen) { diff --git a/regress/hrecord.c b/regress/hrecord.c index 88e24a4..67dff6f 100644 --- a/regress/hrecord.c +++ b/regress/hrecord.c @@ -81,7 +81,6 @@ int Hpoll( struct pollfd *fds , int nfds , int timeout ) { #endif int Hsocket( int domain , int type , int protocol ) { int r, e; - Tmust("socket","domain",domain==AF_INET); Tmust("socket","type",type==SOCK_STREAM || type==SOCK_DGRAM); Qsocket( type ); r= socket( domain , type , protocol ); diff --git a/regress/hsyscalls.i4 b/regress/hsyscalls.i4 index ad90104..b5dfc56 100644 --- a/regress/hsyscalls.i4 +++ b/regress/hsyscalls.i4 @@ -70,7 +70,7 @@ hm_syscall( hm_syscall( socket, `hm_rv_fd', ` - hm_arg_must(int,domain,AF_INET) hm_na + hm_arg_ign(int,domain) hm_na hm_arg_socktype(type) hm_na hm_arg_ign(int,protocol) hm_na ') diff --git a/src/adns.h b/src/adns.h index 34f9f49..aad05fd 100644 --- a/src/adns.h +++ b/src/adns.h @@ -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 * . * 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); @@ -830,7 +924,7 @@ int adns_beforepoll(adns_state ads, struct pollfd *fds, * In any case this call won't block. */ -#define ADNS_POLLFDS_RECOMMENDED 2 +#define ADNS_POLLFDS_RECOMMENDED 3 /* If you allocate an fds buf with at least RECOMMENDED entries then * you are unlikely to need to enlarge it. You are recommended to do * so if it's convenient. However, you must be prepared for adns to diff --git a/src/check.c b/src/check.c index 41cdde5..704a15e 100644 --- a/src/check.c +++ b/src/check.c @@ -4,6 +4,7 @@ */ /* * This file is part of adns, which is + * Copyright (C) 2009 Luca Bruno * Copyright (C) 1997-2000,2003,2006 Ian Jackson * Copyright (C) 1999-2000,2003,2006 Tony Finch * Copyright (C) 1991 Massachusetts Institute of Technology @@ -24,6 +25,8 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include + #include "internal.h" void adns_checkconsistency(adns_state ads, adns_query qu) { @@ -77,11 +80,11 @@ static void checkc_notcpbuf(adns_state ads) { static void checkc_global(adns_state ads) { int i; - assert(ads->udpsocket >= 0); - + assert((ads->udpsocket >= 0) || (ads->udpsocket6 >= 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 --git a/src/event.c b/src/event.c index ad5861e..3fb95a1 100644 --- a/src/event.c +++ b/src/event.c @@ -6,6 +6,7 @@ */ /* * This file is part of adns, which is + * Copyright (C) 2009 Luca Bruno * Copyright (C) 1997-2000,2003,2006 Ian Jackson * Copyright (C) 1999-2000,2003,2006 Tony Finch * Copyright (C) 1991 Massachusetts Institute of Technology @@ -100,6 +101,7 @@ static void tcp_broken_events(adns_state ads) { void adns__tcp_tryconnect(adns_state ads, struct timeval now) { int r, fd, tries; struct sockaddr_in addr; + struct sockaddr_in6 addr6; struct protoent *proto; for (tries=0; triesnservers; tries++) { @@ -123,7 +125,7 @@ void adns__tcp_tryconnect(adns_state ads, struct timeval now) { adns__diag(ads,-1,0,"unable to find protocol no. for TCP !"); return; } - fd= socket(AF_INET,SOCK_STREAM,proto->p_proto); + fd= socket(ads->servers[ads->tcpserver].sin_family,SOCK_STREAM,proto->p_proto); if (fd<0) { adns__diag(ads,-1,0,"cannot create TCP socket: %s",strerror(errno)); return; @@ -135,11 +137,19 @@ void adns__tcp_tryconnect(adns_state ads, struct timeval now) { close(fd); return; } - memset(&addr,0,sizeof(addr)); - addr.sin_family= AF_INET; - addr.sin_port= htons(DNS_PORT); - addr.sin_addr= ads->servers[ads->tcpserver].addr; - r= connect(fd,(const struct sockaddr*)&addr,sizeof(addr)); + if(ads->servers[ads->tcpserver].sin_family==AF_INET) { + memset(&addr,0,sizeof(addr)); + addr.sin_family= AF_INET; + addr.sin_port= htons(DNS_PORT); + addr.sin_addr= ads->servers[ads->tcpserver].addr; + r= connect(fd,(const struct sockaddr*)&addr,sizeof(addr)); + } else { + memset(&addr6,0,sizeof(addr6)); + addr6.sin6_family= AF_INET6; + addr6.sin6_port= htons(DNS_PORT); + addr6.sin6_addr= ads->servers[ads->tcpserver].addr6; + r= connect(fd,(const struct sockaddr*)&addr6,sizeof(addr6)); + } ads->tcpsocket= fd; ads->tcpstate= server_connecting; if (r==0) { tcp_connected(ads,now); return; } @@ -311,34 +321,41 @@ void adns_processtimeouts(adns_state ads, const struct timeval *now) { int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]) { /* Returns the number of entries filled in. Always zeroes revents. */ - assert(MAX_POLLFDS==2); - - pollfds_buf[0].fd= ads->udpsocket; - pollfds_buf[0].events= POLLIN; - pollfds_buf[0].revents= 0; + assert(MAX_POLLFDS==3); + if (ads->udpsocket >= 0) { + pollfds_buf[0].fd= ads->udpsocket; + pollfds_buf[0].events= POLLIN; + pollfds_buf[0].revents= 0; + } + if(ads->udpsocket6 >= 0) { + pollfds_buf[1].fd= ads->udpsocket6; + pollfds_buf[1].events= POLLIN; + pollfds_buf[1].revents= 0; + } switch (ads->tcpstate) { case server_disconnected: case server_broken: - return 1; + return 2; case server_connecting: - pollfds_buf[1].events= POLLOUT; + pollfds_buf[2].events= POLLOUT; break; case server_ok: - pollfds_buf[1].events= + pollfds_buf[2].events= ads->tcpsend.used ? POLLIN|POLLOUT|POLLPRI : POLLIN|POLLPRI; break; default: abort(); } - pollfds_buf[1].fd= ads->tcpsocket; - return 2; + pollfds_buf[2].fd= ads->tcpsocket; + return 3; } int adns_processreadable(adns_state ads, int fd, const struct timeval *now) { int want, dgramlen, r, udpaddrlen, serv, old_skip; byte udpbuf[DNS_MAXUDP]; struct sockaddr_in udpaddr; + struct sockaddr_in6 udpaddr6; adns__consistency(ads,0,cc_entex); @@ -431,6 +448,48 @@ int adns_processreadable(adns_state ads, int fd, const struct timeval *now) { adns__procdgram(ads,udpbuf,r,serv,0,*now); } } + else if (fd == ads->udpsocket6) { + for (;;) { + udpaddrlen= sizeof(udpaddr6); + r= recvfrom(ads->udpsocket6,udpbuf,sizeof(udpbuf),0, + (struct sockaddr*)&udpaddr6,&udpaddrlen); + if (r<0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { r= 0; goto xit; } + if (errno == EINTR) continue; + if (errno_resources(errno)) { r= errno; goto xit; } + adns__warn(ads,-1,0,"datagram receive error: %s",strerror(errno)); + r= 0; goto xit; + } + if (udpaddrlen != sizeof(udpaddr6)) { + adns__diag(ads,-1,0,"datagram received with wrong address length %d" + " (expected %lu)", udpaddrlen, + (unsigned long)sizeof(udpaddr6)); + continue; + } + if (udpaddr6.sin6_family != AF_INET6) { + adns__diag(ads,-1,0,"datagram received with wrong protocol family" + " %u (expected %u)",udpaddr6.sin6_family,AF_INET6); + continue; + } + if (ntohs(udpaddr6.sin6_port) != DNS_PORT) { + adns__diag(ads,-1,0,"datagram received from wrong port" + " %u (expected %u)", ntohs(udpaddr6.sin6_port),DNS_PORT); + continue; + } + for (serv= 0; + serv < ads->nservers && + (memcmp(&(ads->servers[serv].addr6.s6_addr), &(udpaddr6.sin6_addr.s6_addr), sizeof(struct in6_addr))); + serv++); + if (serv >= ads->nservers) { + char buf_dst[INET6_ADDRSTRLEN]; + adns__warn(ads,-1,0,"datagram received from unknown nameserver %s", + inet_ntop(AF_INET6, &(udpaddr6.sin6_addr), buf_dst, INET6_ADDRSTRLEN*sizeof(char))); + continue; + } + adns__procdgram(ads,udpbuf,r,serv,0,*now); + } + } + r= 0; xit: adns__consistency(ads,0,cc_entex); diff --git a/src/internal.h b/src/internal.h index 58cd15d..e4e56c9 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 +----------------+ @@ -313,7 +336,7 @@ struct adns__state { int configerrno; struct query_queue udpw, tcpw, childw, output; adns_query forallnext; - int nextid, udpsocket, tcpsocket; + int nextid, udpsocket, udpsocket6, tcpsocket; vbuf tcpsend, tcprecv; int nservers, nsortlist, nsearchlist, searchndots, tcpserver, tcprecv_skip; enum adns__tcpstate { @@ -330,10 +353,17 @@ struct adns__state { sigset_t stdsigmask; struct pollfd pollfds_buf[MAX_POLLFDS]; struct server { + sa_family_t sin_family; struct in_addr addr; + struct in6_addr addr6; } 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 +431,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 +447,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 +491,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 +521,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 +#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..07b1f13 100644 --- a/src/setup.c +++ b/src/setup.c @@ -5,6 +5,7 @@ */ /* * This file is part of adns, which is + * Copyright (C) 2009 Luca Bruno * Copyright (C) 1997-2000,2003,2006 Ian Jackson * Copyright (C) 1999-2000,2003,2006 Tony Finch * Copyright (C) 1991 Massachusetts Institute of Technology @@ -41,12 +42,12 @@ static void readconfig(adns_state ads, const char *filename, int warnmissing); -static void addserver(adns_state ads, struct in_addr addr) { +static void addserverv4(adns_state ads, struct in_addr addr) { int i; struct server *ss; for (i=0; inservers; i++) { - if (ads->servers[i].addr.s_addr == addr.s_addr) { + if ((ads->servers[i].sin_family == AF_INET) && (ads->servers[i].addr.s_addr == addr.s_addr)) { adns__debug(ads,-1,0,"duplicate nameserver %s ignored",inet_ntoa(addr)); return; } @@ -58,10 +59,35 @@ static void addserver(adns_state ads, struct in_addr addr) { } ss= ads->servers+ads->nservers; + ss->sin_family= AF_INET; ss->addr= addr; ads->nservers++; } +static void addserverv6(adns_state ads, struct in6_addr addr) { + int i; + struct server *ss; + char buf[INET6_ADDRSTRLEN]; + + for (i=0; inservers; i++) { + if ((ads->servers[i].sin_family == AF_INET6) && !(memcmp(&(ads->servers[i].addr6.s6_addr), &(addr.s6_addr), sizeof(struct in6_addr)))) { + adns__debug(ads,-1,0,"duplicate nameserver %s ignored", inet_ntop(AF_INET6, &addr, buf, INET6_ADDRSTRLEN*sizeof(char))); + return; + } + } + + if (ads->nservers>=MAXSERVERS) { + adns__diag(ads,-1,0,"too many nameservers, ignoring %s", inet_ntop(AF_INET6, &addr, buf, INET6_ADDRSTRLEN*sizeof(char))); + return; + } + + ss= ads->servers+ads->nservers; + ss->sin_family= AF_INET6; + ss->addr6= addr; + ads->nservers++; +} + + static void freesearchlist(adns_state ads) { if (ads->nsearchlist) free(*ads->searchlist); free(ads->searchlist); @@ -105,16 +131,28 @@ static int nextword(const char **bufp_io, const char **word_r, int *l_r) { static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char *buf) { - struct in_addr ia; - - if (!inet_aton(buf,&ia)) { - configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf); - return; + struct in_addr ia4; + struct in6_addr ia6; + char ns_name[INET6_ADDRSTRLEN]; + + if (!inet_aton(buf,&ia4)) { + if (!inet_pton(AF_INET6, buf,&ia6)) { + configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf); + return; + } + else { + adns__debug(ads,-1,0,"using nameserver %s", inet_ntop(AF_INET6, &ia6, ns_name, INET6_ADDRSTRLEN*sizeof(char))); + addserverv6(ads,ia6); + + } + } + else { + adns__debug(ads,-1,0,"using nameserver %s",inet_ntoa(ia4)); + addserverv4(ads,ia4); } - adns__debug(ads,-1,0,"using nameserver %s",inet_ntoa(ia)); - addserver(ads,ia); } + static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) { const char *bufp, *word; @@ -150,6 +188,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 +230,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 +256,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 +269,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++; } } @@ -522,7 +578,7 @@ static int init_begin(adns_state *ads_r, adns_initflags flags, LIST_INIT(ads->output); ads->forallnext= 0; ads->nextid= 0x311f; - ads->udpsocket= ads->tcpsocket= -1; + ads->udpsocket= ads->udpsocket6= ads->tcpsocket= -1; adns__vbuf_init(&ads->tcpsend); adns__vbuf_init(&ads->tcprecv); ads->tcprecv_skip= 0; @@ -550,16 +606,22 @@ static int init_finish(adns_state ads) { if (ads->logfn && ads->iflags & adns_if_debug) adns__lprintf(ads,"adns: no nameservers, using localhost\n"); ia.s_addr= htonl(INADDR_LOOPBACK); - addserver(ads,ia); + addserverv4(ads,ia); } proto= getprotobyname("udp"); if (!proto) { r= ENOPROTOOPT; goto x_free; } ads->udpsocket= socket(AF_INET,SOCK_DGRAM,proto->p_proto); if (ads->udpsocket<0) { r= errno; goto x_free; } + ads->udpsocket6= socket(AF_INET6,SOCK_DGRAM,proto->p_proto); + if (ads->udpsocket6<0) { r= errno; goto x_free6; } + r= adns__setnonblock(ads,ads->udpsocket); if (r) { r= errno; goto x_closeudp; } + r= adns__setnonblock(ads,ads->udpsocket6); + if (r) { r= errno; goto x_closeudp6; } + return 0; x_closeudp: @@ -567,6 +629,12 @@ static int init_finish(adns_state ads) { x_free: free(ads); return r; + + x_closeudp6: + close(ads->udpsocket6); + x_free6: + free(ads); + return r; } static void init_abort(adns_state ads) { @@ -678,7 +746,10 @@ void adns_finish(adns_state ads) { else if (ads->output.head) adns_cancel(ads->output.head); else break; } - close(ads->udpsocket); + if (ads->udpsocket >= 0) + close(ads->udpsocket); + if (ads->udpsocket6 >= 0) + close(ads->udpsocket6); if (ads->tcpsocket >= 0) close(ads->tcpsocket); adns__vbuf_free(&ads->tcpsend); adns__vbuf_free(&ads->tcprecv); diff --git a/src/transmit.c b/src/transmit.c index 7afb90f..fb733fc 100644 --- a/src/transmit.c +++ b/src/transmit.c @@ -5,6 +5,7 @@ */ /* * This file is part of adns, which is + * Copyright (C) 2009 Luca Bruno * Copyright (C) 1997-2000,2003,2006 Ian Jackson * Copyright (C) 1999-2000,2003,2006 Tony Finch * Copyright (C) 1991 Massachusetts Institute of Technology @@ -62,6 +63,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 +121,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 +150,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 +191,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; @@ -251,6 +285,7 @@ static void query_usetcp(adns_query qu, struct timeval now) { void adns__query_send(adns_query qu, struct timeval now) { struct sockaddr_in servaddr; + struct sockaddr_in6 servaddr6; int serv, r; adns_state ads; @@ -266,15 +301,25 @@ void adns__query_send(adns_query qu, struct timeval now) { } serv= qu->udpnextserver; - memset(&servaddr,0,sizeof(servaddr)); - ads= qu->ads; - servaddr.sin_family= AF_INET; - servaddr.sin_addr= ads->servers[serv].addr; - servaddr.sin_port= htons(DNS_PORT); + + if(ads->servers[serv].sin_family == AF_INET) { + memset(&servaddr,0,sizeof(servaddr)); + servaddr.sin_family= ads->servers[serv].sin_family; + servaddr.sin_addr= ads->servers[serv].addr; + servaddr.sin_port= htons(DNS_PORT); + r= sendto(ads->udpsocket,qu->query_dgram,qu->query_dglen,0, + (const struct sockaddr*)&servaddr,sizeof(servaddr)); + } else { + memset(&servaddr6,0,sizeof(servaddr6)); + servaddr6.sin6_family= ads->servers[serv].sin_family; + servaddr6.sin6_addr= ads->servers[serv].addr6; + servaddr6.sin6_port= htons(DNS_PORT); + r= sendto(ads->udpsocket6,qu->query_dgram,qu->query_dglen,0, + (const struct sockaddr*)&servaddr6,sizeof(servaddr6)); + } + - r= sendto(ads->udpsocket,qu->query_dgram,qu->query_dglen,0, - (const struct sockaddr*)&servaddr,sizeof(servaddr)); if (r<0 && errno == EMSGSIZE) { qu->retries= 0; query_usetcp(qu,now); diff --git a/src/types.c b/src/types.c index 36ff879..712ae69 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; - 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; } @@ -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 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) { + 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; 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; + + 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 biaddr.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; inrrs; i++, found++) { if (queried->len == found->len && !memcmp(&queried->addr,&found->addr,queried->len)) { @@ -734,18 +1018,12 @@ 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 +1033,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; iqu->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 +1500,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 +1524,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 +1537,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,"", "addr",addr,sh_addr, di_addr, cs_addr ), }; static const typeinfo typeinfo_unknown=