From 6318fca29e9d3ebe9300a229d0b84e16ec5e5626 Mon Sep 17 00:00:00 2001 From: Niels Provos Date: Sat, 27 Jan 2007 04:22:36 +0000 Subject: [PATCH] AAAA support for DNS; from Nick Mathewson. unfortunately, no regression test svn:r315 --- configure.in | 13 ++++++++- evdns.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ evdns.h | 6 +++- 3 files changed, 96 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 947f5e74..6ada6d7d 100644 --- a/configure.in +++ b/configure.in @@ -39,7 +39,7 @@ AC_CHECK_LIB(socket, socket) dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/ioctl.h sys/devpoll.h port.h) +AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/ioctl.h sys/devpoll.h port.h netinet/in6.h) if test "x$ac_cv_header_sys_queue_h" = "xyes"; then AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h) AC_EGREP_CPP(yes, @@ -340,6 +340,17 @@ AC_CHECK_TYPE(u_int64_t, unsigned long long) AC_CHECK_TYPE(u_int32_t, unsigned int) AC_CHECK_TYPE(u_int16_t, unsigned short) AC_CHECK_TYPE(u_int8_t, unsigned char) +AC_CHECK_TYPES([struct in6_addr], , , +[#ifdef WIN32 +#include +#else +#include +#include +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif]) AC_MSG_CHECKING([for socklen_t]) AC_TRY_COMPILE([ diff --git a/evdns.c b/evdns.c index 5db2a86e..d092b0e4 100644 --- a/evdns.c +++ b/evdns.c @@ -105,6 +105,10 @@ #include #endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif + #define EVDNS_LOG_DEBUG 0 #define EVDNS_LOG_WARN 1 @@ -167,6 +171,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; @@ -175,6 +185,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; @@ -574,6 +588,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_IPv6_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); } @@ -783,6 +805,24 @@ reply_parse(u8 *packet, int length) { return -1; reply.have_answer = 1; break; + } else if (type == TYPE_AAAA && class == CLASS_INET) { + int addrcount, addrtocopy; + if (req->request_type != TYPE_AAAA) { + j += datalength; continue; + } + // XXXX do something sane with malformed AAAA 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.aaaa.addrcount == MAX_ADDRS) break; } else { // skip over any other type of resource j += datalength; @@ -1449,6 +1489,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; @@ -1467,6 +1523,29 @@ 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=15; i >= 0; --i) { + u8 byte = in->s6_addr[i]; + *cp++ = "0123456789abcdef"[byte & 0x0f]; + *cp++ = '.'; + *cp++ = "0123456789abcdef"[byte >> 4]; + *cp++ = '.'; + } + assert(cp + strlen(".ip6.arpa") < buf+sizeof(buf)); + memcpy(cp, ".ip6.arpa", strlen(".ip6.arpa")+1); + 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/evdns.h b/evdns.h index d502564d..4b4f5a93 100644 --- a/evdns.h +++ b/evdns.h @@ -266,6 +266,7 @@ extern "C" { #define DNS_IPv4_A 1 #define DNS_PTR 2 +#define DNS_IPv6_AAAA 3 #define DNS_QUERY_NO_SEARCH 1 @@ -276,7 +277,7 @@ extern "C" { /* * The callback that contains the results from a lookup. - * - type is either DNS_IPv4_A or DNS_PTR + * - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA * - count contains the number of addresses of form type * - ttl is the number of seconds the resolution may be cached for. * - addresses needs to be cast according to type @@ -292,8 +293,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 *in, int flags, evdns_callback_type callback, void *ptr); +int evdns_resolve_reverse_ipv6(struct in6_addr *in, 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); -- 2.40.0