AAAA support for DNS; from Nick Mathewson.

unfortunately, no regression test



svn:r315
This commit is contained in:
Niels Provos 2007-01-27 04:22:36 +00:00
parent 22e53c7a84
commit 6318fca29e
3 changed files with 96 additions and 2 deletions

View File

@ -39,7 +39,7 @@ AC_CHECK_LIB(socket, socket)
dnl Checks for header files. dnl Checks for header files.
AC_HEADER_STDC 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 if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h) AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
AC_EGREP_CPP(yes, 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_int32_t, unsigned int)
AC_CHECK_TYPE(u_int16_t, unsigned short) AC_CHECK_TYPE(u_int16_t, unsigned short)
AC_CHECK_TYPE(u_int8_t, unsigned char) 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_MSG_CHECKING([for socklen_t])
AC_TRY_COMPILE([ AC_TRY_COMPILE([

79
evdns.c
View File

@ -105,6 +105,10 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
#ifdef HAVE_NETINET_IN6_H
#include <netinet/in6.h>
#endif
#define EVDNS_LOG_DEBUG 0 #define EVDNS_LOG_DEBUG 0
#define EVDNS_LOG_WARN 1 #define EVDNS_LOG_WARN 1
@ -167,6 +171,12 @@ struct request {
char transmit_me; // needs to be transmitted char transmit_me; // needs to be transmitted
}; };
#ifndef HAVE_STRUCT_IN6_ADDR
struct in6_addr {
u8 s6_addr[16];
};
#endif
struct reply { struct reply {
unsigned int type; unsigned int type;
unsigned int have_answer; unsigned int have_answer;
@ -175,6 +185,10 @@ struct reply {
u32 addrcount; u32 addrcount;
u32 addresses[MAX_ADDRS]; u32 addresses[MAX_ADDRS];
} a; } a;
struct {
u32 addrcount;
struct in6_addr addresses[MAX_ADDRS];
} aaaa;
struct { struct {
char name[HOST_NAME_MAX]; char name[HOST_NAME_MAX];
} ptr; } ptr;
@ -574,6 +588,14 @@ reply_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply)
req->user_pointer); req->user_pointer);
} }
return; 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); assert(0);
} }
@ -783,6 +805,24 @@ reply_parse(u8 *packet, int length) {
return -1; return -1;
reply.have_answer = 1; reply.have_answer = 1;
break; 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 { } else {
// skip over any other type of resource // skip over any other type of resource
j += datalength; 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) { int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
char buf[32]; char buf[32];
struct request *req; struct request *req;
@ -1467,6 +1523,29 @@ int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type cal
return 0; 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 // Search support
// //

View File

@ -266,6 +266,7 @@ extern "C" {
#define DNS_IPv4_A 1 #define DNS_IPv4_A 1
#define DNS_PTR 2 #define DNS_PTR 2
#define DNS_IPv6_AAAA 3
#define DNS_QUERY_NO_SEARCH 1 #define DNS_QUERY_NO_SEARCH 1
@ -276,7 +277,7 @@ extern "C" {
/* /*
* The callback that contains the results from a lookup. * 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 * - count contains the number of addresses of form type
* - ttl is the number of seconds the resolution may be cached for. * - ttl is the number of seconds the resolution may be cached for.
* - addresses needs to be cast according to type * - 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_resume(void);
int evdns_nameserver_ip_add(const char *ip_as_string); 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_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 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(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 *); int evdns_resolv_conf_parse(int flags, const char *);
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
int evdns_config_windows_nameservers(void); int evdns_config_windows_nameservers(void);