From 494e45482a5bd6c9b53d0b5ba591e11a97af8a1e Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 12 Dec 2006 03:48:46 +0000 Subject: [PATCH] r11536@Kushana: nickm | 2006-12-11 22:48:21 -0500 Add ipv6 functionality to evdns. svn:r9089 --- ChangeLog | 3 +- configure.in | 4 +++ doc/TODO | 2 +- src/or/eventdns.c | 88 ++++++++++++++++++++++++++++++++++++++++++----- src/or/eventdns.h | 4 +++ 5 files changed, 90 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 60b3badcc1..b11c40dfaf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,7 +6,8 @@ Changes in version 0.1.2.5-xxxx - 200?-??-?? - Try to batch changes to the state so that we do as few disk writes as possible while still storing important things in a timely fashion. - - Ongoing work on eventdns infrastructure + - Ongoing work on eventdns infrastructure: add dns server and ipv6 + support. o Major bugfixes: - Fix a longstanding bug in eventdns that prevented the count of diff --git a/configure.in b/configure.in index 5bae75d6c3..8bb63a484b 100644 --- a/configure.in +++ b/configure.in @@ -554,6 +554,10 @@ AC_CHECK_SIZEOF(size_t) AC_CHECK_TYPES([uint, u_char]) +AC_CHECK_TYPES([struct in6_addr, struct sockaddr_storage], , , +[#include +#include ]) + if test -z "$CROSS_COMPILE"; then AC_CACHE_CHECK([whether time_t is signed], tor_cv_time_t_signed, [ AC_TRY_RUN([ diff --git a/doc/TODO b/doc/TODO index 248724624c..5d6ec2a0d6 100644 --- a/doc/TODO +++ b/doc/TODO @@ -92,7 +92,7 @@ N - DNS improvements . Asynchronous DNS o Document and rename SearchDomains, ResolvConf options D Make API closer to getaddrinfo() - - Teach evdns about ipv6. + o Teach evdns about ipv6. - Make evdns use windows strerror equivalents. - Teach evdns to be able to listen for requests to be processed. o Design interface. diff --git a/src/or/eventdns.c b/src/or/eventdns.c index d449fadd82..8c596e8831 100644 --- a/src/or/eventdns.c +++ b/src/or/eventdns.c @@ -349,6 +349,12 @@ struct request { char transmit_me; // needs to be transmitted }; +#ifndef HAVE_STRUCT_IN6_ADDR +struct in6_addr { + u8 s6_addr[16]; +}; +#endif + struct reply { unsigned int type; unsigned int have_answer; @@ -357,6 +363,10 @@ struct reply { u32 addrcount; u32 addresses[MAX_ADDRS]; } a; + struct { + u32 addrcount; + struct in6_addr addresses[MAX_ADDRS]; + } aaaa; struct { char name[HOST_NAME_MAX]; } ptr; @@ -811,7 +821,7 @@ reply_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply) if (reply) req->user_callback(DNS_ERR_NONE, DNS_IPv4_A, reply->data.a.addrcount, ttl, - reply->data.a.addresses, + reply->data.a.addresses, req->user_pointer); else req->user_callback(err, 0, 0, 0, NULL, req->user_pointer); @@ -826,6 +836,14 @@ reply_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply) req->user_pointer); } return; + case TYPE_AAAA: + if (reply) + req->user_callback(DNS_ERR_NONE, DNS_IPv4_AAAA, + reply->data.aaaa.addrcount, ttl, + reply->data.aaaa.addresses, + req->user_pointer); + else + req->user_callback(err, 0, 0, 0, NULL, req->user_pointer); } assert(0); } @@ -1015,11 +1033,11 @@ reply_parse(u8 *packet, int length) if (type == TYPE_A && class == CLASS_INET) { int addrcount, addrtocopy; - if (req->request_type != TYPE_A) { + if (req->request_type != type) { j += datalength; continue; } - // XXXX do something sane with malformed A answers. - addrcount = datalength >> 2; // each IP address is 4 bytes + // XXXX do something sane with malformed answers. + addrcount = datalength >> 2; // each address is 4 bytes long addrtocopy = MIN(MAX_ADDRS - reply.data.a.addrcount, (unsigned)addrcount); ttl_r = MIN(ttl_r, ttl); @@ -1027,8 +1045,8 @@ reply_parse(u8 *packet, int length) if (j + 4*addrtocopy > length) return -1; memcpy(&reply.data.a.addresses[reply.data.a.addrcount], packet + j, 4*addrtocopy); - j += 4*addrtocopy; reply.data.a.addrcount += addrtocopy; + j += 4*addrtocopy; reply.have_answer = 1; if (reply.data.a.addrcount == MAX_ADDRS) break; } else if (type == TYPE_PTR && class == CLASS_INET) { @@ -1040,12 +1058,24 @@ reply_parse(u8 *packet, int length) return -1; reply.have_answer = 1; break; - } else if (type == TYPE_AAAA && class == CLASS_INET) { - if (req->request_type != TYPE_AAAA) { + } else if (type == TYPE_AAAA && class == CLASS_INET) { + int addrcount, addrtocopy; + if (req->request_type != type) { j += datalength; continue; } - // XXXX Implement me. -NM - j += datalength; + // XXXX do something sane with malformed answers. + addrcount = datalength >> 4; // each address is 16 bytes long + addrtocopy = MIN(MAX_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount); + ttl_r = MIN(ttl_r, ttl); + + // we only bother with the first four addresses. + if (j + 16*addrtocopy > length) return -1; + memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount], + packet + j, 16*addrtocopy); + reply.data.aaaa.addrcount += addrtocopy; + j += 16*addrtocopy; + reply.have_answer = 1; + if (reply.data.a.addrcount == MAX_ADDRS) break; } else { // skip over any other type of resource j += datalength; @@ -2309,6 +2339,22 @@ int evdns_resolve_ipv4(const char *name, int flags, } } +// exported function +int evdns_resolve_ipv6(const char *name, int flags, + evdns_callback_type callback, void *ptr) { + log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); + if (flags & DNS_QUERY_NO_SEARCH) { + struct request *const req = + request_new(TYPE_AAAA, name, flags, callback, ptr); + if (req == NULL) + return 1; + request_submit(req); + return 0; + } else { + return search_request_new(TYPE_AAAA, name, flags, callback, ptr); + } +} + int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) { char buf[32]; struct request *req; @@ -2327,6 +2373,30 @@ int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type cal return 0; } +int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) { + char buf[64]; + char *cp; + struct request *req; + int i; + assert(in); + + cp = buf; + for (i=0; i < 16; ++i) { + u8 byte = in->s6_addr[i]; + *cp++ = "0123456789abcdef"[byte >> 4]; + *cp++ = '.'; + *cp++ = "0123456789abcdef"[byte & 0x0f]; + *cp++ = '.'; + } + assert(cp + strlen(".ip6.arpa") < buf+sizeof(buf)); + strcpy(cp, ".ip6.arpa"); + log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); + req = request_new(TYPE_PTR, buf, flags, callback, ptr); + if (!req) return 1; + request_submit(req); + return 0; +} + ///////////////////////////////////////////////////////////////////// // Search support // diff --git a/src/or/eventdns.h b/src/or/eventdns.h index 19a924e2b2..439f7787be 100644 --- a/src/or/eventdns.h +++ b/src/or/eventdns.h @@ -41,6 +41,7 @@ #define DNS_IPv4_A 1 #define DNS_PTR 2 +#define DNS_IPv4_AAAA 3 #define DNS_QUERY_NO_SEARCH 1 @@ -60,8 +61,11 @@ int evdns_clear_nameservers_and_suspend(void); int evdns_resume(void); int evdns_nameserver_ip_add(const char *ip_as_string); int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr); +int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr); struct in_addr; +struct in6_addr; int evdns_resolve_reverse(struct in_addr *addr, int flags, evdns_callback_type callback, void *ptr); +int evdns_resolve_reverse_ipv6(struct in6_addr *addr, int flags, evdns_callback_type callback, void *ptr); int evdns_resolv_conf_parse(int flags, const char *); #ifdef MS_WINDOWS int evdns_config_windows_nameservers(void);