]> granicus.if.org Git - libevent/commitdiff
AAAA support for DNS; from Nick Mathewson.
authorNiels Provos <provos@gmail.com>
Sat, 27 Jan 2007 04:22:36 +0000 (04:22 +0000)
committerNiels Provos <provos@gmail.com>
Sat, 27 Jan 2007 04:22:36 +0000 (04:22 +0000)
unfortunately, no regression test

svn:r315

configure.in
evdns.c
evdns.h

index 947f5e74fdae0e92a32d7770fff8689fc44a7206..6ada6d7d98f0e50d294f32cca3e57714fb5ada77 100644 (file)
@@ -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 <winsock2.h>
+#else
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif])
 
 AC_MSG_CHECKING([for socklen_t])
 AC_TRY_COMPILE([
diff --git a/evdns.c b/evdns.c
index 5db2a86e8f135aadf475979dcea888e00cd6f0c5..d092b0e4943c28663153fe8d1abde317dc05725f 100644 (file)
--- a/evdns.c
+++ b/evdns.c
 #include <arpa/inet.h>
 #endif
 
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#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 d502564dfeed09ea0c967aa974090b477f875e13..4b4f5a931662662b3932caf3b005637d0613f8aa 100644 (file)
--- 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);