xref: /netbsd-src/external/bsd/ntp/dist/sntp/libevent/test/regress_testutils.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
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