From db2370a12f9ac78cedb448439969079b6dc568f3 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 10 Mar 2005 23:30:34 +0000 Subject: [PATCH] Dominick Meglio added ares_parse_aaaa_reply.c and did various adjustments. The first little steps towards IPv6 support! --- ares/CHANGES | 5 + ares/Makefile.inc | 5 +- ares/acinclude.m4 | 49 ++++++++++ ares/ares.h | 3 +- ares/ares_parse_aaaa_reply.c | 173 +++++++++++++++++++++++++++++++++++ ares/configure.ac | 28 ++++++ ares/setup.h | 26 +++++- 7 files changed, 283 insertions(+), 6 deletions(-) create mode 100644 ares/ares_parse_aaaa_reply.c diff --git a/ares/CHANGES b/ares/CHANGES index 7f5be2701..49f4a324d 100644 --- a/ares/CHANGES +++ b/ares/CHANGES @@ -1,5 +1,10 @@ Changelog for the c-ares project +* March 11, 2005 + +- Dominick Meglio added ares_parse_aaaa_reply.c and did various + adjustments. The first little steps towards IPv6 support! + * November 7 - Fixed the VC project and makefile to use ares_cancel and ares_version diff --git a/ares/Makefile.inc b/ares/Makefile.inc index 9c95e61b7..d8b1e0608 100644 --- a/ares/Makefile.inc +++ b/ares/Makefile.inc @@ -3,7 +3,8 @@ ares__close_sockets.c ares_free_string.c ares_search.c ares__get_hostent.c \ ares_gethostbyaddr.c ares_send.c ares__read_line.c ares_gethostbyname.c \ ares_strerror.c ares_cancel.c ares_init.c ares_timeout.c ares_destroy.c \ ares_mkquery.c ares_version.c ares_expand_name.c ares_parse_a_reply.c \ -windows_port.c ares_expand_string.c ares_parse_ptr_reply.c +windows_port.c ares_expand_string.c ares_parse_ptr_reply.c \ +ares_parse_aaaa_reply.c HHEADERS = ares.h ares_private.h setup.h ares_dns.h ares_version.h nameser.h @@ -12,4 +13,4 @@ MANPAGES= ares_destroy.3 ares_expand_name.3 ares_expand_string.3 ares_fds.3 \ ares_gethostbyname.3 ares_init.3 ares_init_options.3 ares_mkquery.3 \ ares_parse_a_reply.3 ares_parse_ptr_reply.3 ares_process.3 \ ares_query.3 ares_search.3 ares_send.3 ares_strerror.3 ares_timeout.3 \ - ares_version.3 ares_cancel.3 \ No newline at end of file + ares_version.3 ares_cancel.3 diff --git a/ares/acinclude.m4 b/ares/acinclude.m4 index 32a35036c..31972aa36 100644 --- a/ares/acinclude.m4 +++ b/ares/acinclude.m4 @@ -99,3 +99,52 @@ AC_DEFUN([CURL_CC_DEBUG_OPTS], ]) dnl end of AC_DEFUN() + +dnl This macro determines if the specified struct exists in the specified file +dnl Syntax: +dnl CARES_CHECK_STRUCT(headers, struct name, if found, [if not found]) + +AC_DEFUN([CARES_CHECK_STRUCT], [ + AC_MSG_CHECKING([for struct $2]) + AC_TRY_COMPILE([$1], + [ + struct $2 struct_instance; + ], ac_struct="yes", ac_found="no") + if test "$ac_struct" = "yes" ; then + AC_MSG_RESULT(yes) + $3 + else + AC_MSG_RESULT(no) + $4 + fi +]) + +dnl This macro determines if the specified constant exists in the specified file +dnl Syntax: +dnl CARES_CHECK_CONSTANT(headers, constant name, if found, [if not found]) + +AC_DEFUN([CARES_CHECK_CONSTANT], [ + AC_MSG_CHECKING([for $2]) + AC_TRY_RUN( + [ + $1 + + int main() + { + #ifdef $2 + return 0; + #else + return 1; + #endif + } + ], ac_constant="yes", ac_constant="no") + if test "$ac_constant" = "yes" ; then + AC_MSG_RESULT(yes) + $3 + else + AC_MSG_RESULT(no) + $4 + fi +]) + + diff --git a/ares/ares.h b/ares/ares.h index 162e7241a..d032de434 100644 --- a/ares/ares.h +++ b/ares/ares.h @@ -137,12 +137,13 @@ int ares_expand_string(const unsigned char *encoded, const unsigned char *abuf, int alen, unsigned char **s, long *enclen); int ares_parse_a_reply(const unsigned char *abuf, int alen, struct hostent **host); +int ares_parse_aaaa_reply(const unsigned char *abuf, int alen, + struct hostent **host); int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr, int addrlen, int family, struct hostent **host); void ares_free_string(void *str); void ares_free_hostent(struct hostent *host); const char *ares_strerror(int code); -void ares_free_errmem(char *mem); #ifdef __cplusplus } diff --git a/ares/ares_parse_aaaa_reply.c b/ares/ares_parse_aaaa_reply.c new file mode 100644 index 000000000..575591ae5 --- /dev/null +++ b/ares/ares_parse_aaaa_reply.c @@ -0,0 +1,173 @@ +/* Copyright 2005 Dominick Meglio + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "setup.h" +#include + +#if defined(WIN32) && !defined(WATT32) +#include "nameser.h" +#else +#include +#include +#include +#include +#include +#endif + +#include +#include +#include "ares.h" +#include "ares_dns.h" +#include "ares_private.h" + +int ares_parse_aaaa_reply(const unsigned char *abuf, int alen, + struct hostent **host) +{ + unsigned int qdcount, ancount; + int status, i, rr_type, rr_class, rr_len, naddrs; + int naliases; + long len; + const unsigned char *aptr; + char *hostname, *rr_name, *rr_data, **aliases; + struct in6_addr *addrs; + struct hostent *hostent; + + /* Set *host to NULL for all failure cases. */ + *host = NULL; + + /* Give up if abuf doesn't have room for a header. */ + if (alen < HFIXEDSZ) + return ARES_EBADRESP; + + /* Fetch the question and answer count from the header. */ + qdcount = DNS_HEADER_QDCOUNT(abuf); + ancount = DNS_HEADER_ANCOUNT(abuf); + if (qdcount != 1) + return ARES_EBADRESP; + + /* Expand the name from the question, and skip past the question. */ + aptr = abuf + HFIXEDSZ; + status = ares_expand_name(aptr, abuf, alen, &hostname, &len); + if (status != ARES_SUCCESS) + return status; + if (aptr + len + QFIXEDSZ > abuf + alen) + { + free(hostname); + return ARES_EBADRESP; + } + aptr += len + QFIXEDSZ; + + /* Allocate addresses and aliases; ancount gives an upper bound for both. */ + addrs = malloc(ancount * sizeof(struct in6_addr)); + if (!addrs) + { + free(hostname); + return ARES_ENOMEM; + } + aliases = malloc((ancount + 1) * sizeof(char *)); + if (!aliases) + { + free(hostname); + free(addrs); + return ARES_ENOMEM; + } + naddrs = 0; + naliases = 0; + + /* Examine each answer resource record (RR) in turn. */ + for (i = 0; i < (int)ancount; i++) + { + /* Decode the RR up to the data field. */ + status = ares_expand_name(aptr, abuf, alen, &rr_name, &len); + if (status != ARES_SUCCESS) + break; + aptr += len; + if (aptr + RRFIXEDSZ > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + rr_type = DNS_RR_TYPE(aptr); + rr_class = DNS_RR_CLASS(aptr); + rr_len = DNS_RR_LEN(aptr); + aptr += RRFIXEDSZ; + + if (rr_class == C_IN && rr_type == T_AAAA + && rr_len == sizeof(struct in6_addr) + && strcasecmp(rr_name, hostname) == 0) + { + memcpy(&addrs[naddrs], aptr, sizeof(struct in6_addr)); + naddrs++; + status = ARES_SUCCESS; + } + + if (rr_class == C_IN && rr_type == T_CNAME) + { + /* Record the RR name as an alias. */ + aliases[naliases] = rr_name; + naliases++; + + /* Decode the RR data and replace the hostname with it. */ + status = ares_expand_name(aptr, abuf, alen, &rr_data, &len); + if (status != ARES_SUCCESS) + break; + free(hostname); + hostname = rr_data; + } + else + free(rr_name); + + aptr += rr_len; + if (aptr > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + } + + if (status == ARES_SUCCESS && naddrs == 0) + status = ARES_ENODATA; + if (status == ARES_SUCCESS) + { + /* We got our answer. Allocate memory to build the host entry. */ + aliases[naliases] = NULL; + hostent = malloc(sizeof(struct hostent)); + if (hostent) + { + hostent->h_addr_list = malloc((naddrs + 1) * sizeof(char *)); + if (hostent->h_addr_list) + { + /* Fill in the hostent and return successfully. */ + hostent->h_name = hostname; + hostent->h_aliases = aliases; + hostent->h_addrtype = AF_INET6; + hostent->h_length = sizeof(struct in6_addr); + for (i = 0; i < naddrs; i++) + hostent->h_addr_list[i] = (char *) &addrs[i]; + hostent->h_addr_list[naddrs] = NULL; + *host = hostent; + return ARES_SUCCESS; + } + free(hostent); + } + status = ARES_ENOMEM; + } + for (i = 0; i < naliases; i++) + free(aliases[i]); + free(aliases); + free(addrs); + free(hostname); + return status; +} diff --git a/ares/configure.ac b/ares/configure.ac index 64c76c9f9..f4ed76f4f 100644 --- a/ares/configure.ac +++ b/ares/configure.ac @@ -63,4 +63,32 @@ AC_CHECK_HEADERS( sys/socket.h \ ) +dnl check for AF_INET6 +CARES_CHECK_CONSTANT( + [ + #include + #include + ], [PF_INET6], + AC_DEFINE_UNQUOTED(HAVE_PF_INET6,1,[Define to 1 if you have PF_INET6.]) +) + +dnl check for PF_INET6 +CARES_CHECK_CONSTANT( + [ + #include + #include + ], [AF_INET6], + AC_DEFINE_UNQUOTED(HAVE_AF_INET6,1,[Define to 1 if you have AF_INET6.]) +) + + +dnl check for the in6_addr structure +CARES_CHECK_STRUCT( + [ + #include + #include + ], [in6_addr], + AC_DEFINE_UNQUOTED(HAVE_STRUCT_IN6_ADDR,1,[Define to 1 if you have struct in6_addr.]) +) + AC_OUTPUT(Makefile) diff --git a/ares/setup.h b/ares/setup.h index 696f7c58d..b7b99b5e3 100644 --- a/ares/setup.h +++ b/ares/setup.h @@ -1,7 +1,7 @@ #ifndef ARES_SETUP_H #define ARES_SETUP_H -/* Copyright (C) 2004 by Daniel Stenberg et al +/* Copyright (C) 2004 - 2005 by Daniel Stenberg et al * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided @@ -45,11 +45,11 @@ typedef int ares_socket_t; /* Assume a few thing unless they're set by configure */ #if !defined(HAVE_SYS_TIME_H) && !defined(_MSC_VER) -#define HAVE_SYS_TIME_H +#define HAVE_SYS_TIME_H #endif #if !defined(HAVE_UNISTD_H) && !defined(_MSC_VER) -#define HAVE_UNISTD_H +#define HAVE_UNISTD_H #endif #if !defined(HAVE_SYS_UIO_H) && !defined(WIN32) && !defined(MSDOS) @@ -69,4 +69,24 @@ int ares_strcasecmp(const char *s1, const char *s2); #define strcasecmp(a,b) ares_strcasecmp(a,b) #endif +/* IPv6 compatibility */ +#if !defined(HAVE_AF_INET6) +#if defined(HAVE_PF_INET6) +#define AF_INET6 PF_INET6 +#else +#define AF_INET6 AF_MAX+1 +#endif +#endif + +#ifndef HAVE_PF_INET6 +#define PF_INET6 AF_INET6 +#endif + +#ifndef HAVE_STRUCT_IN6_ADDR +struct in6_addr +{ + unsigned char s6_addr[16]; +}; +#endif + #endif /* ARES_SETUP_H */