1275970Scy/* 2275970Scy * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson 3275970Scy * 4275970Scy * Redistribution and use in source and binary forms, with or without 5275970Scy * modification, are permitted provided that the following conditions 6275970Scy * are met: 7275970Scy * 1. Redistributions of source code must retain the above copyright 8275970Scy * notice, this list of conditions and the following disclaimer. 9275970Scy * 2. Redistributions in binary form must reproduce the above copyright 10275970Scy * notice, this list of conditions and the following disclaimer in the 11275970Scy * documentation and/or other materials provided with the distribution. 12275970Scy * 3. The name of the author may not be used to endorse or promote products 13275970Scy * derived from this software without specific prior written permission. 14275970Scy * 15275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25275970Scy */ 26275970Scy#include "../util-internal.h" 27275970Scy 28275970Scy#ifdef _WIN32 29275970Scy#include <winsock2.h> 30275970Scy#include <windows.h> 31275970Scy#include <ws2tcpip.h> 32275970Scy#endif 33275970Scy 34275970Scy#include "event2/event-config.h" 35275970Scy 36275970Scy#include <sys/types.h> 37275970Scy#include <sys/stat.h> 38275970Scy#ifdef EVENT__HAVE_SYS_TIME_H 39275970Scy#include <sys/time.h> 40275970Scy#endif 41275970Scy#include <sys/queue.h> 42275970Scy#ifndef _WIN32 43275970Scy#include <sys/socket.h> 44275970Scy#include <signal.h> 45275970Scy#include <netinet/in.h> 46275970Scy#include <arpa/inet.h> 47275970Scy#include <unistd.h> 48275970Scy#endif 49275970Scy#ifdef EVENT__HAVE_NETINET_IN6_H 50275970Scy#include <netinet/in6.h> 51275970Scy#endif 52275970Scy#ifdef HAVE_NETDB_H 53275970Scy#include <netdb.h> 54275970Scy#endif 55275970Scy#include <fcntl.h> 56275970Scy#include <stdlib.h> 57275970Scy#include <stdio.h> 58275970Scy#include <string.h> 59275970Scy#include <errno.h> 60275970Scy 61275970Scy#include "event2/dns.h" 62275970Scy#include "event2/dns_struct.h" 63275970Scy#include "event2/event.h" 64275970Scy#include "event2/event_compat.h" 65275970Scy#include "event2/util.h" 66275970Scy#include "event2/listener.h" 67275970Scy#include "event2/bufferevent.h" 68275970Scy#include "log-internal.h" 69275970Scy#include "regress.h" 70275970Scy#include "regress_testutils.h" 71275970Scy 72275970Scy/* globals */ 73275970Scystatic struct evdns_server_port *dns_port; 74275970Scyevutil_socket_t dns_sock = -1; 75275970Scy 76275970Scy/* Helper: return the port that a socket is bound on, in host order. */ 77275970Scyint 78275970Scyregress_get_socket_port(evutil_socket_t fd) 79275970Scy{ 80275970Scy struct sockaddr_storage ss; 81275970Scy ev_socklen_t socklen = sizeof(ss); 82275970Scy if (getsockname(fd, (struct sockaddr*)&ss, &socklen) != 0) 83275970Scy return -1; 84275970Scy if (ss.ss_family == AF_INET) 85275970Scy return ntohs( ((struct sockaddr_in*)&ss)->sin_port); 86275970Scy else if (ss.ss_family == AF_INET6) 87275970Scy return ntohs( ((struct sockaddr_in6*)&ss)->sin6_port); 88275970Scy else 89275970Scy return -1; 90275970Scy} 91275970Scy 92275970Scystruct evdns_server_port * 93275970Scyregress_get_dnsserver(struct event_base *base, 94275970Scy ev_uint16_t *portnum, 95275970Scy evutil_socket_t *psock, 96275970Scy evdns_request_callback_fn_type cb, 97275970Scy void *arg) 98275970Scy{ 99275970Scy struct evdns_server_port *port = NULL; 100275970Scy evutil_socket_t sock; 101275970Scy struct sockaddr_in my_addr; 102275970Scy 103275970Scy sock = socket(AF_INET, SOCK_DGRAM, 0); 104275970Scy if (sock < 0) { 105275970Scy tt_abort_perror("socket"); 106275970Scy } 107275970Scy 108275970Scy evutil_make_socket_nonblocking(sock); 109275970Scy 110275970Scy memset(&my_addr, 0, sizeof(my_addr)); 111275970Scy my_addr.sin_family = AF_INET; 112275970Scy my_addr.sin_port = htons(*portnum); 113275970Scy my_addr.sin_addr.s_addr = htonl(0x7f000001UL); 114275970Scy if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) { 115275970Scy evutil_closesocket(sock); 116275970Scy tt_abort_perror("bind"); 117275970Scy } 118275970Scy port = evdns_add_server_port_with_base(base, sock, 0, cb, arg); 119275970Scy if (!*portnum) 120275970Scy *portnum = regress_get_socket_port(sock); 121275970Scy if (psock) 122275970Scy *psock = sock; 123275970Scy 124275970Scy return port; 125275970Scyend: 126275970Scy return NULL; 127275970Scy} 128275970Scy 129275970Scyvoid 130275970Scyregress_clean_dnsserver(void) 131275970Scy{ 132275970Scy if (dns_port) 133275970Scy evdns_close_server_port(dns_port); 134275970Scy if (dns_sock >= 0) 135275970Scy evutil_closesocket(dns_sock); 136275970Scy} 137275970Scy 138275970Scyvoid 139275970Scyregress_dns_server_cb(struct evdns_server_request *req, void *data) 140275970Scy{ 141275970Scy struct regress_dns_server_table *tab = data; 142275970Scy const char *question; 143275970Scy 144275970Scy if (req->nquestions != 1) 145275970Scy TT_DIE(("Only handling one question at a time; got %d", 146275970Scy req->nquestions)); 147275970Scy 148275970Scy question = req->questions[0]->name; 149275970Scy 150275970Scy while (tab->q && evutil_ascii_strcasecmp(question, tab->q) && 151275970Scy strcmp("*", tab->q)) 152275970Scy ++tab; 153275970Scy if (tab->q == NULL) 154275970Scy TT_DIE(("Unexpected question: '%s'", question)); 155275970Scy 156275970Scy ++tab->seen; 157275970Scy 158275970Scy if (!strcmp(tab->anstype, "err")) { 159275970Scy int err = atoi(tab->ans); 160275970Scy tt_assert(! evdns_server_request_respond(req, err)); 161275970Scy return; 162275970Scy } else if (!strcmp(tab->anstype, "errsoa")) { 163275970Scy int err = atoi(tab->ans); 164275970Scy char soa_record[] = 165275970Scy "\x04" "dns1" "\x05" "icann" "\x03" "org" "\0" 166275970Scy "\x0a" "hostmaster" "\x05" "icann" "\x03" "org" "\0" 167275970Scy "\x77\xde\x5e\xba" /* serial */ 168275970Scy "\x00\x00\x1c\x20" /* refreshtime = 2h */ 169275970Scy "\x00\x00\x0e\x10" /* retry = 1h */ 170275970Scy "\x00\x12\x75\x00" /* expiration = 14d */ 171275970Scy "\x00\x00\x0e\x10" /* min.ttl = 1h */ 172275970Scy ; 173275970Scy evdns_server_request_add_reply( 174275970Scy req, EVDNS_AUTHORITY_SECTION, 175275970Scy "example.com", EVDNS_TYPE_SOA, EVDNS_CLASS_INET, 176275970Scy 42, sizeof(soa_record) - 1, 0, soa_record); 177275970Scy tt_assert(! evdns_server_request_respond(req, err)); 178275970Scy return; 179275970Scy } else if (!strcmp(tab->anstype, "A")) { 180275970Scy struct in_addr in; 181275970Scy if (!evutil_inet_pton(AF_INET, tab->ans, &in)) { 182275970Scy TT_DIE(("Bad A value %s in table", tab->ans)); 183275970Scy } 184275970Scy evdns_server_request_add_a_reply(req, question, 1, &in.s_addr, 185275970Scy 100); 186275970Scy } else if (!strcmp(tab->anstype, "AAAA")) { 187275970Scy struct in6_addr in6; 188275970Scy if (!evutil_inet_pton(AF_INET6, tab->ans, &in6)) { 189275970Scy TT_DIE(("Bad AAAA value %s in table", tab->ans)); 190275970Scy } 191275970Scy evdns_server_request_add_aaaa_reply(req, 192275970Scy question, 1, &in6.s6_addr, 100); 193275970Scy } else { 194275970Scy TT_DIE(("Weird table entry with type '%s'", tab->anstype)); 195275970Scy } 196275970Scy tt_assert(! evdns_server_request_respond(req, 0)) 197275970Scy return; 198275970Scyend: 199275970Scy tt_want(! evdns_server_request_drop(req)); 200275970Scy} 201275970Scy 202275970Scyint 203275970Scyregress_dnsserver(struct event_base *base, ev_uint16_t *port, 204275970Scy struct regress_dns_server_table *search_table) 205275970Scy{ 206275970Scy dns_port = regress_get_dnsserver(base, port, &dns_sock, 207275970Scy regress_dns_server_cb, search_table); 208275970Scy return dns_port != NULL; 209275970Scy} 210275970Scy 211275970Scyint 212275970Scyregress_get_listener_addr(struct evconnlistener *lev, 213275970Scy struct sockaddr *sa, ev_socklen_t *socklen) 214275970Scy{ 215275970Scy evutil_socket_t s = evconnlistener_get_fd(lev); 216275970Scy if (s <= 0) 217275970Scy return -1; 218275970Scy return getsockname(s, sa, socklen); 219275970Scy} 220