diff options
Diffstat (limited to 'third_party/libevent/test/regress_dns.c')
-rw-r--r-- | third_party/libevent/test/regress_dns.c | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/third_party/libevent/test/regress_dns.c b/third_party/libevent/test/regress_dns.c new file mode 100644 index 0000000..8191192 --- /dev/null +++ b/third_party/libevent/test/regress_dns.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef WIN32 +#include <winsock2.h> +#include <windows.h> +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#include <sys/queue.h> +#ifndef WIN32 +#include <sys/socket.h> +#include <sys/signal.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> +#endif +#ifdef HAVE_NETINET_IN6_H +#include <netinet/in6.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "event.h" +#include "evdns.h" +#include "log.h" + +static int dns_ok = 0; +static int dns_err = 0; + +void dns_suite(void); + +static void +dns_gethostbyname_cb(int result, char type, int count, int ttl, + void *addresses, void *arg) +{ + dns_ok = dns_err = 0; + + if (result == DNS_ERR_TIMEOUT) { + fprintf(stdout, "[Timed out] "); + dns_err = result; + goto out; + } + + if (result != DNS_ERR_NONE) { + fprintf(stdout, "[Error code %d] ", result); + goto out; + } + + fprintf(stderr, "type: %d, count: %d, ttl: %d: ", type, count, ttl); + + switch (type) { + case DNS_IPv6_AAAA: { +#if defined(HAVE_STRUCT_IN6_ADDR) && defined(HAVE_INET_NTOP) + struct in6_addr *in6_addrs = addresses; + char buf[INET6_ADDRSTRLEN+1]; + int i; + /* a resolution that's not valid does not help */ + if (ttl < 0) + goto out; + for (i = 0; i < count; ++i) { + const char *b = inet_ntop(AF_INET6, &in6_addrs[i], buf,sizeof(buf)); + if (b) + fprintf(stderr, "%s ", b); + else + fprintf(stderr, "%s ", strerror(errno)); + } +#endif + break; + } + case DNS_IPv4_A: { + struct in_addr *in_addrs = addresses; + int i; + /* a resolution that's not valid does not help */ + if (ttl < 0) + goto out; + for (i = 0; i < count; ++i) + fprintf(stderr, "%s ", inet_ntoa(in_addrs[i])); + break; + } + case DNS_PTR: + /* may get at most one PTR */ + if (count != 1) + goto out; + + fprintf(stderr, "%s ", *(char **)addresses); + break; + default: + goto out; + } + + dns_ok = type; + +out: + event_loopexit(NULL); +} + +static void +dns_gethostbyname(void) +{ + fprintf(stdout, "Simple DNS resolve: "); + dns_ok = 0; + evdns_resolve_ipv4("www.monkey.org", 0, dns_gethostbyname_cb, NULL); + event_dispatch(); + + if (dns_ok == DNS_IPv4_A) { + fprintf(stdout, "OK\n"); + } else { + fprintf(stdout, "FAILED\n"); + exit(1); + } +} + +static void +dns_gethostbyname6(void) +{ + fprintf(stdout, "IPv6 DNS resolve: "); + dns_ok = 0; + evdns_resolve_ipv6("www.ietf.org", 0, dns_gethostbyname_cb, NULL); + event_dispatch(); + + if (dns_ok == DNS_IPv6_AAAA) { + fprintf(stdout, "OK\n"); + } else if (!dns_ok && dns_err == DNS_ERR_TIMEOUT) { + fprintf(stdout, "SKIPPED\n"); + } else { + fprintf(stdout, "FAILED (%d)\n", dns_ok); + exit(1); + } +} + +static void +dns_gethostbyaddr(void) +{ + struct in_addr in; + in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */ + fprintf(stdout, "Simple reverse DNS resolve: "); + dns_ok = 0; + evdns_resolve_reverse(&in, 0, dns_gethostbyname_cb, NULL); + event_dispatch(); + + if (dns_ok == DNS_PTR) { + fprintf(stdout, "OK\n"); + } else { + fprintf(stdout, "FAILED\n"); + exit(1); + } +} + +static int n_server_responses = 0; + +static void +dns_server_request_cb(struct evdns_server_request *req, void *data) +{ + int i, r; + const char TEST_ARPA[] = "11.11.168.192.in-addr.arpa"; + for (i = 0; i < req->nquestions; ++i) { + struct in_addr ans; + ans.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */ + if (req->questions[i]->type == EVDNS_TYPE_A && + req->questions[i]->dns_question_class == EVDNS_CLASS_INET && + !strcmp(req->questions[i]->name, "zz.example.com")) { + r = evdns_server_request_add_a_reply(req, "zz.example.com", + 1, &ans.s_addr, 12345); + if (r<0) + dns_ok = 0; + } else if (req->questions[i]->type == EVDNS_TYPE_AAAA && + req->questions[i]->dns_question_class == EVDNS_CLASS_INET && + !strcmp(req->questions[i]->name, "zz.example.com")) { + char addr6[17] = "abcdefghijklmnop"; + r = evdns_server_request_add_aaaa_reply(req, "zz.example.com", + 1, addr6, 123); + if (r<0) + dns_ok = 0; + } else if (req->questions[i]->type == EVDNS_TYPE_PTR && + req->questions[i]->dns_question_class == EVDNS_CLASS_INET && + !strcmp(req->questions[i]->name, TEST_ARPA)) { + r = evdns_server_request_add_ptr_reply(req, NULL, TEST_ARPA, + "ZZ.EXAMPLE.COM", 54321); + if (r<0) + dns_ok = 0; + } else { + fprintf(stdout, "Unexpected question %d %d \"%s\" ", + req->questions[i]->type, + req->questions[i]->dns_question_class, + req->questions[i]->name); + dns_ok = 0; + } + } + r = evdns_server_request_respond(req, 0); + if (r<0) { + fprintf(stdout, "Couldn't send reply. "); + dns_ok = 0; + } +} + +static void +dns_server_gethostbyname_cb(int result, char type, int count, int ttl, + void *addresses, void *arg) +{ + if (result != DNS_ERR_NONE) { + fprintf(stdout, "Unexpected result %d. ", result); + dns_ok = 0; + goto out; + } + if (count != 1) { + fprintf(stdout, "Unexpected answer count %d. ", count); + dns_ok = 0; + goto out; + } + switch (type) { + case DNS_IPv4_A: { + struct in_addr *in_addrs = addresses; + if (in_addrs[0].s_addr != htonl(0xc0a80b0bUL) || ttl != 12345) { + fprintf(stdout, "Bad IPv4 response \"%s\" %d. ", + inet_ntoa(in_addrs[0]), ttl); + dns_ok = 0; + goto out; + } + break; + } + case DNS_IPv6_AAAA: { +#if defined (HAVE_STRUCT_IN6_ADDR) && defined(HAVE_INET_NTOP) + struct in6_addr *in6_addrs = addresses; + char buf[INET6_ADDRSTRLEN+1]; + if (memcmp(&in6_addrs[0].s6_addr, "abcdefghijklmnop", 16) + || ttl != 123) { + const char *b = inet_ntop(AF_INET6, &in6_addrs[0],buf,sizeof(buf)); + fprintf(stdout, "Bad IPv6 response \"%s\" %d. ", b, ttl); + dns_ok = 0; + goto out; + } +#endif + break; + } + case DNS_PTR: { + char **addrs = addresses; + if (strcmp(addrs[0], "ZZ.EXAMPLE.COM") || ttl != 54321) { + fprintf(stdout, "Bad PTR response \"%s\" %d. ", + addrs[0], ttl); + dns_ok = 0; + goto out; + } + break; + } + default: + fprintf(stdout, "Bad response type %d. ", type); + dns_ok = 0; + } + + out: + if (++n_server_responses == 3) { + event_loopexit(NULL); + } +} + +static void +dns_server(void) +{ + int sock; + struct sockaddr_in my_addr; + struct evdns_server_port *port; + struct in_addr resolve_addr; + + dns_ok = 1; + fprintf(stdout, "DNS server support: "); + + /* Add ourself as the only nameserver, and make sure we really are + * the only nameserver. */ + evdns_nameserver_ip_add("127.0.0.1:35353"); + if (evdns_count_nameservers() != 1) { + fprintf(stdout, "Couldn't set up.\n"); + exit(1); + } + + /* Now configure a nameserver port. */ + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + perror("socket"); + exit(1); + } +#ifdef WIN32 + { + u_long nonblocking = 1; + ioctlsocket(sock, FIONBIO, &nonblocking); + } +#else + fcntl(sock, F_SETFL, O_NONBLOCK); +#endif + memset(&my_addr, 0, sizeof(my_addr)); + my_addr.sin_family = AF_INET; + my_addr.sin_port = htons(35353); + my_addr.sin_addr.s_addr = htonl(0x7f000001UL); + if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) { + perror("bind"); + exit (1); + } + port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL); + + /* Send two queries. */ + evdns_resolve_ipv4("zz.example.com", DNS_QUERY_NO_SEARCH, + dns_server_gethostbyname_cb, NULL); + evdns_resolve_ipv6("zz.example.com", DNS_QUERY_NO_SEARCH, + dns_server_gethostbyname_cb, NULL); + resolve_addr.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */ + evdns_resolve_reverse(&resolve_addr, 0, + dns_server_gethostbyname_cb, NULL); + + event_dispatch(); + + if (dns_ok) { + fprintf(stdout, "OK\n"); + } else { + fprintf(stdout, "FAILED\n"); + exit(1); + } + + evdns_close_server_port(port); + evdns_shutdown(0); /* remove ourself as nameserver. */ +#ifdef WIN32 + closesocket(sock); +#else + close(sock); +#endif +} + +void +dns_suite(void) +{ + dns_server(); /* Do this before we call evdns_init. */ + + evdns_init(); + dns_gethostbyname(); + dns_gethostbyname6(); + dns_gethostbyaddr(); + + evdns_shutdown(0); +} |