1*eabc0478Schristos /* $NetBSD: regress_testutils.c,v 1.6 2024/08/18 20:47:23 christos Exp $ */ 28585484eSchristos 38585484eSchristos /* 48585484eSchristos * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson 58585484eSchristos * 68585484eSchristos * Redistribution and use in source and binary forms, with or without 78585484eSchristos * modification, are permitted provided that the following conditions 88585484eSchristos * are met: 98585484eSchristos * 1. Redistributions of source code must retain the above copyright 108585484eSchristos * notice, this list of conditions and the following disclaimer. 118585484eSchristos * 2. Redistributions in binary form must reproduce the above copyright 128585484eSchristos * notice, this list of conditions and the following disclaimer in the 138585484eSchristos * documentation and/or other materials provided with the distribution. 148585484eSchristos * 3. The name of the author may not be used to endorse or promote products 158585484eSchristos * derived from this software without specific prior written permission. 168585484eSchristos * 178585484eSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 188585484eSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 198585484eSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 208585484eSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 218585484eSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 228585484eSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 238585484eSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 248585484eSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 258585484eSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 268585484eSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 278585484eSchristos */ 288585484eSchristos #include "../util-internal.h" 298585484eSchristos 308585484eSchristos #ifdef _WIN32 318585484eSchristos #include <winsock2.h> 328585484eSchristos #include <windows.h> 338585484eSchristos #include <ws2tcpip.h> 348585484eSchristos #endif 358585484eSchristos 368585484eSchristos #include "event2/event-config.h" 378585484eSchristos 388585484eSchristos #include <sys/types.h> 398585484eSchristos #include <sys/stat.h> 408585484eSchristos #ifdef EVENT__HAVE_SYS_TIME_H 418585484eSchristos #include <sys/time.h> 428585484eSchristos #endif 438585484eSchristos #include <sys/queue.h> 448585484eSchristos #ifndef _WIN32 458585484eSchristos #include <sys/socket.h> 468585484eSchristos #include <signal.h> 478585484eSchristos #include <netinet/in.h> 488585484eSchristos #include <arpa/inet.h> 498585484eSchristos #include <unistd.h> 508585484eSchristos #endif 518585484eSchristos #ifdef EVENT__HAVE_NETINET_IN6_H 528585484eSchristos #include <netinet/in6.h> 538585484eSchristos #endif 548585484eSchristos #ifdef HAVE_NETDB_H 558585484eSchristos #include <netdb.h> 568585484eSchristos #endif 578585484eSchristos #include <fcntl.h> 588585484eSchristos #include <stdlib.h> 598585484eSchristos #include <stdio.h> 608585484eSchristos #include <string.h> 618585484eSchristos #include <errno.h> 628585484eSchristos 638585484eSchristos #include "event2/dns.h" 648585484eSchristos #include "event2/dns_struct.h" 658585484eSchristos #include "event2/event.h" 668585484eSchristos #include "event2/event_compat.h" 678585484eSchristos #include "event2/util.h" 688585484eSchristos #include "event2/listener.h" 698585484eSchristos #include "event2/bufferevent.h" 708585484eSchristos #include "log-internal.h" 718585484eSchristos #include "regress.h" 728585484eSchristos #include "regress_testutils.h" 738585484eSchristos 748585484eSchristos /* globals */ 758585484eSchristos static struct evdns_server_port *dns_port; 768585484eSchristos evutil_socket_t dns_sock = -1; 778585484eSchristos 788585484eSchristos /* Helper: return the port that a socket is bound on, in host order. */ 798585484eSchristos int 808585484eSchristos regress_get_socket_port(evutil_socket_t fd) 818585484eSchristos { 828585484eSchristos struct sockaddr_storage ss; 838585484eSchristos ev_socklen_t socklen = sizeof(ss); 848585484eSchristos if (getsockname(fd, (struct sockaddr*)&ss, &socklen) != 0) 858585484eSchristos return -1; 868585484eSchristos if (ss.ss_family == AF_INET) 878585484eSchristos return ntohs( ((struct sockaddr_in*)&ss)->sin_port); 888585484eSchristos else if (ss.ss_family == AF_INET6) 898585484eSchristos return ntohs( ((struct sockaddr_in6*)&ss)->sin6_port); 908585484eSchristos else 918585484eSchristos return -1; 928585484eSchristos } 938585484eSchristos 948585484eSchristos struct evdns_server_port * 958585484eSchristos regress_get_dnsserver(struct event_base *base, 968585484eSchristos ev_uint16_t *portnum, 978585484eSchristos evutil_socket_t *psock, 988585484eSchristos evdns_request_callback_fn_type cb, 998585484eSchristos void *arg) 1008585484eSchristos { 1018585484eSchristos struct evdns_server_port *port = NULL; 1028585484eSchristos evutil_socket_t sock; 1038585484eSchristos struct sockaddr_in my_addr; 1048585484eSchristos 1058585484eSchristos sock = socket(AF_INET, SOCK_DGRAM, 0); 1068585484eSchristos if (sock < 0) { 1078585484eSchristos tt_abort_perror("socket"); 1088585484eSchristos } 1098585484eSchristos 1108585484eSchristos evutil_make_socket_nonblocking(sock); 1118585484eSchristos 1128585484eSchristos memset(&my_addr, 0, sizeof(my_addr)); 1138585484eSchristos my_addr.sin_family = AF_INET; 1148585484eSchristos my_addr.sin_port = htons(*portnum); 115*eabc0478Schristos my_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 1168585484eSchristos if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) { 1178585484eSchristos evutil_closesocket(sock); 1188585484eSchristos tt_abort_perror("bind"); 1198585484eSchristos } 1208585484eSchristos port = evdns_add_server_port_with_base(base, sock, 0, cb, arg); 1218585484eSchristos if (!*portnum) 1228585484eSchristos *portnum = regress_get_socket_port(sock); 1238585484eSchristos if (psock) 1248585484eSchristos *psock = sock; 1258585484eSchristos 1268585484eSchristos return port; 1278585484eSchristos end: 1288585484eSchristos return NULL; 1298585484eSchristos } 1308585484eSchristos 1318585484eSchristos void 1328585484eSchristos regress_clean_dnsserver(void) 1338585484eSchristos { 134*eabc0478Schristos if (dns_port) { 1358585484eSchristos evdns_close_server_port(dns_port); 136*eabc0478Schristos dns_port = NULL; 137*eabc0478Schristos } 138*eabc0478Schristos if (dns_sock >= 0) { 1398585484eSchristos evutil_closesocket(dns_sock); 140*eabc0478Schristos dns_sock = -1; 141*eabc0478Schristos } 1428585484eSchristos } 1438585484eSchristos 144*eabc0478Schristos static void strtolower(char *s) 145*eabc0478Schristos { 146*eabc0478Schristos while (*s) { 147*eabc0478Schristos *s = EVUTIL_TOLOWER_(*s); 148*eabc0478Schristos ++s; 149*eabc0478Schristos } 150*eabc0478Schristos } 1518585484eSchristos void 1528585484eSchristos regress_dns_server_cb(struct evdns_server_request *req, void *data) 1538585484eSchristos { 1548585484eSchristos struct regress_dns_server_table *tab = data; 155*eabc0478Schristos char *question; 1568585484eSchristos 1578585484eSchristos if (req->nquestions != 1) 1588585484eSchristos TT_DIE(("Only handling one question at a time; got %d", 1598585484eSchristos req->nquestions)); 1608585484eSchristos 1618585484eSchristos question = req->questions[0]->name; 1628585484eSchristos 1638585484eSchristos while (tab->q && evutil_ascii_strcasecmp(question, tab->q) && 1648585484eSchristos strcmp("*", tab->q)) 1658585484eSchristos ++tab; 1668585484eSchristos if (tab->q == NULL) 1678585484eSchristos TT_DIE(("Unexpected question: '%s'", question)); 1688585484eSchristos 1698585484eSchristos ++tab->seen; 1708585484eSchristos 171*eabc0478Schristos if (tab->lower) 172*eabc0478Schristos strtolower(question); 173*eabc0478Schristos 1748585484eSchristos if (!strcmp(tab->anstype, "err")) { 1758585484eSchristos int err = atoi(tab->ans); 1768585484eSchristos tt_assert(! evdns_server_request_respond(req, err)); 1778585484eSchristos return; 1788585484eSchristos } else if (!strcmp(tab->anstype, "errsoa")) { 1798585484eSchristos int err = atoi(tab->ans); 1808585484eSchristos char soa_record[] = 1818585484eSchristos "\x04" "dns1" "\x05" "icann" "\x03" "org" "\0" 1828585484eSchristos "\x0a" "hostmaster" "\x05" "icann" "\x03" "org" "\0" 1838585484eSchristos "\x77\xde\x5e\xba" /* serial */ 1848585484eSchristos "\x00\x00\x1c\x20" /* refreshtime = 2h */ 1858585484eSchristos "\x00\x00\x0e\x10" /* retry = 1h */ 1868585484eSchristos "\x00\x12\x75\x00" /* expiration = 14d */ 1878585484eSchristos "\x00\x00\x0e\x10" /* min.ttl = 1h */ 1888585484eSchristos ; 1898585484eSchristos evdns_server_request_add_reply( 1908585484eSchristos req, EVDNS_AUTHORITY_SECTION, 1918585484eSchristos "example.com", EVDNS_TYPE_SOA, EVDNS_CLASS_INET, 1928585484eSchristos 42, sizeof(soa_record) - 1, 0, soa_record); 1938585484eSchristos tt_assert(! evdns_server_request_respond(req, err)); 1948585484eSchristos return; 1958585484eSchristos } else if (!strcmp(tab->anstype, "A")) { 1968585484eSchristos struct in_addr in; 1978585484eSchristos if (!evutil_inet_pton(AF_INET, tab->ans, &in)) { 1988585484eSchristos TT_DIE(("Bad A value %s in table", tab->ans)); 1998585484eSchristos } 2008585484eSchristos evdns_server_request_add_a_reply(req, question, 1, &in.s_addr, 2018585484eSchristos 100); 2028585484eSchristos } else if (!strcmp(tab->anstype, "AAAA")) { 2038585484eSchristos struct in6_addr in6; 2048585484eSchristos if (!evutil_inet_pton(AF_INET6, tab->ans, &in6)) { 2058585484eSchristos TT_DIE(("Bad AAAA value %s in table", tab->ans)); 2068585484eSchristos } 2078585484eSchristos evdns_server_request_add_aaaa_reply(req, 2088585484eSchristos question, 1, &in6.s6_addr, 100); 2098585484eSchristos } else { 2108585484eSchristos TT_DIE(("Weird table entry with type '%s'", tab->anstype)); 2118585484eSchristos } 2128585484eSchristos tt_assert(! evdns_server_request_respond(req, 0)) 2138585484eSchristos return; 2148585484eSchristos end: 2158585484eSchristos tt_want(! evdns_server_request_drop(req)); 2168585484eSchristos } 2178585484eSchristos 2188585484eSchristos int 2198585484eSchristos regress_dnsserver(struct event_base *base, ev_uint16_t *port, 2208585484eSchristos struct regress_dns_server_table *search_table) 2218585484eSchristos { 2228585484eSchristos dns_port = regress_get_dnsserver(base, port, &dns_sock, 2238585484eSchristos regress_dns_server_cb, search_table); 2248585484eSchristos return dns_port != NULL; 2258585484eSchristos } 2268585484eSchristos 2278585484eSchristos int 2288585484eSchristos regress_get_listener_addr(struct evconnlistener *lev, 2298585484eSchristos struct sockaddr *sa, ev_socklen_t *socklen) 2308585484eSchristos { 2318585484eSchristos evutil_socket_t s = evconnlistener_get_fd(lev); 2328585484eSchristos if (s <= 0) 2338585484eSchristos return -1; 2348585484eSchristos return getsockname(s, sa, socklen); 2358585484eSchristos } 236