xref: /openbmc/linux/tools/testing/selftests/net/reuseport_addr_any.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
16254e5c6SPeter Oskolkov // SPDX-License-Identifier: GPL-2.0
26254e5c6SPeter Oskolkov 
36254e5c6SPeter Oskolkov /* Test that sockets listening on a specific address are preferred
46254e5c6SPeter Oskolkov  * over sockets listening on addr_any.
56254e5c6SPeter Oskolkov  */
66254e5c6SPeter Oskolkov 
76254e5c6SPeter Oskolkov #define _GNU_SOURCE
86254e5c6SPeter Oskolkov 
96254e5c6SPeter Oskolkov #include <arpa/inet.h>
106254e5c6SPeter Oskolkov #include <errno.h>
116254e5c6SPeter Oskolkov #include <error.h>
1211fb60d1SPeter Oskolkov #include <linux/dccp.h>
136254e5c6SPeter Oskolkov #include <linux/in.h>
146254e5c6SPeter Oskolkov #include <linux/unistd.h>
156254e5c6SPeter Oskolkov #include <stdbool.h>
166254e5c6SPeter Oskolkov #include <stdio.h>
176254e5c6SPeter Oskolkov #include <stdlib.h>
186254e5c6SPeter Oskolkov #include <string.h>
196254e5c6SPeter Oskolkov #include <sys/epoll.h>
206254e5c6SPeter Oskolkov #include <sys/types.h>
216254e5c6SPeter Oskolkov #include <sys/socket.h>
226254e5c6SPeter Oskolkov #include <unistd.h>
236254e5c6SPeter Oskolkov 
24*83a9b6f6SAlan Maguire #ifndef SOL_DCCP
25*83a9b6f6SAlan Maguire #define SOL_DCCP 269
26*83a9b6f6SAlan Maguire #endif
27*83a9b6f6SAlan Maguire 
286254e5c6SPeter Oskolkov static const char *IP4_ADDR = "127.0.0.1";
296254e5c6SPeter Oskolkov static const char *IP6_ADDR = "::1";
306254e5c6SPeter Oskolkov static const char *IP4_MAPPED6 = "::ffff:127.0.0.1";
316254e5c6SPeter Oskolkov 
326254e5c6SPeter Oskolkov static const int PORT = 8888;
336254e5c6SPeter Oskolkov 
build_rcv_fd(int family,int proto,int * rcv_fds,int count,const char * addr_str)346254e5c6SPeter Oskolkov static void build_rcv_fd(int family, int proto, int *rcv_fds, int count,
356254e5c6SPeter Oskolkov 			 const char *addr_str)
366254e5c6SPeter Oskolkov {
376254e5c6SPeter Oskolkov 	struct sockaddr_in  addr4 = {0};
386254e5c6SPeter Oskolkov 	struct sockaddr_in6 addr6 = {0};
396254e5c6SPeter Oskolkov 	struct sockaddr *addr;
406254e5c6SPeter Oskolkov 	int opt, i, sz;
416254e5c6SPeter Oskolkov 
426254e5c6SPeter Oskolkov 	memset(&addr, 0, sizeof(addr));
436254e5c6SPeter Oskolkov 
446254e5c6SPeter Oskolkov 	switch (family) {
456254e5c6SPeter Oskolkov 	case AF_INET:
466254e5c6SPeter Oskolkov 		addr4.sin_family = family;
476254e5c6SPeter Oskolkov 		if (!addr_str)
486254e5c6SPeter Oskolkov 			addr4.sin_addr.s_addr = htonl(INADDR_ANY);
496254e5c6SPeter Oskolkov 		else if (!inet_pton(family, addr_str, &addr4.sin_addr.s_addr))
506254e5c6SPeter Oskolkov 			error(1, errno, "inet_pton failed: %s", addr_str);
516254e5c6SPeter Oskolkov 		addr4.sin_port = htons(PORT);
526254e5c6SPeter Oskolkov 		sz = sizeof(addr4);
536254e5c6SPeter Oskolkov 		addr = (struct sockaddr *)&addr4;
546254e5c6SPeter Oskolkov 		break;
556254e5c6SPeter Oskolkov 	case AF_INET6:
566254e5c6SPeter Oskolkov 		addr6.sin6_family = AF_INET6;
576254e5c6SPeter Oskolkov 		if (!addr_str)
586254e5c6SPeter Oskolkov 			addr6.sin6_addr = in6addr_any;
596254e5c6SPeter Oskolkov 		else if (!inet_pton(family, addr_str, &addr6.sin6_addr))
606254e5c6SPeter Oskolkov 			error(1, errno, "inet_pton failed: %s", addr_str);
616254e5c6SPeter Oskolkov 		addr6.sin6_port = htons(PORT);
626254e5c6SPeter Oskolkov 		sz = sizeof(addr6);
636254e5c6SPeter Oskolkov 		addr = (struct sockaddr *)&addr6;
646254e5c6SPeter Oskolkov 		break;
656254e5c6SPeter Oskolkov 	default:
666254e5c6SPeter Oskolkov 		error(1, 0, "Unsupported family %d", family);
67fa232332SPeter Oskolkov 		/* clang does not recognize error() above as terminating
68fa232332SPeter Oskolkov 		 * the program, so it complains that saddr, sz are
69fa232332SPeter Oskolkov 		 * not initialized when this code path is taken. Silence it.
70fa232332SPeter Oskolkov 		 */
71fa232332SPeter Oskolkov 		return;
726254e5c6SPeter Oskolkov 	}
736254e5c6SPeter Oskolkov 
746254e5c6SPeter Oskolkov 	for (i = 0; i < count; ++i) {
756254e5c6SPeter Oskolkov 		rcv_fds[i] = socket(family, proto, 0);
766254e5c6SPeter Oskolkov 		if (rcv_fds[i] < 0)
776254e5c6SPeter Oskolkov 			error(1, errno, "failed to create receive socket");
786254e5c6SPeter Oskolkov 
796254e5c6SPeter Oskolkov 		opt = 1;
806254e5c6SPeter Oskolkov 		if (setsockopt(rcv_fds[i], SOL_SOCKET, SO_REUSEPORT, &opt,
816254e5c6SPeter Oskolkov 			       sizeof(opt)))
826254e5c6SPeter Oskolkov 			error(1, errno, "failed to set SO_REUSEPORT");
836254e5c6SPeter Oskolkov 
846254e5c6SPeter Oskolkov 		if (bind(rcv_fds[i], addr, sz))
856254e5c6SPeter Oskolkov 			error(1, errno, "failed to bind receive socket");
866254e5c6SPeter Oskolkov 
876254e5c6SPeter Oskolkov 		if (proto == SOCK_STREAM && listen(rcv_fds[i], 10))
8811fb60d1SPeter Oskolkov 			error(1, errno, "tcp: failed to listen on receive port");
8911fb60d1SPeter Oskolkov 		else if (proto == SOCK_DCCP) {
9011fb60d1SPeter Oskolkov 			if (setsockopt(rcv_fds[i], SOL_DCCP,
9111fb60d1SPeter Oskolkov 					DCCP_SOCKOPT_SERVICE,
9211fb60d1SPeter Oskolkov 					&(int) {htonl(42)}, sizeof(int)))
9311fb60d1SPeter Oskolkov 				error(1, errno, "failed to setsockopt");
9411fb60d1SPeter Oskolkov 
9511fb60d1SPeter Oskolkov 			if (listen(rcv_fds[i], 10))
9611fb60d1SPeter Oskolkov 				error(1, errno, "dccp: failed to listen on receive port");
9711fb60d1SPeter Oskolkov 		}
986254e5c6SPeter Oskolkov 	}
996254e5c6SPeter Oskolkov }
1006254e5c6SPeter Oskolkov 
connect_and_send(int family,int proto)1016254e5c6SPeter Oskolkov static int connect_and_send(int family, int proto)
1026254e5c6SPeter Oskolkov {
1036254e5c6SPeter Oskolkov 	struct sockaddr_in  saddr4 = {0};
1046254e5c6SPeter Oskolkov 	struct sockaddr_in  daddr4 = {0};
1056254e5c6SPeter Oskolkov 	struct sockaddr_in6 saddr6 = {0};
1066254e5c6SPeter Oskolkov 	struct sockaddr_in6 daddr6 = {0};
1076254e5c6SPeter Oskolkov 	struct sockaddr *saddr, *daddr;
1086254e5c6SPeter Oskolkov 	int fd, sz;
1096254e5c6SPeter Oskolkov 
1106254e5c6SPeter Oskolkov 	switch (family) {
1116254e5c6SPeter Oskolkov 	case AF_INET:
1126254e5c6SPeter Oskolkov 		saddr4.sin_family = AF_INET;
1136254e5c6SPeter Oskolkov 		saddr4.sin_addr.s_addr = htonl(INADDR_ANY);
1146254e5c6SPeter Oskolkov 		saddr4.sin_port = 0;
1156254e5c6SPeter Oskolkov 
1166254e5c6SPeter Oskolkov 		daddr4.sin_family = AF_INET;
1176254e5c6SPeter Oskolkov 		if (!inet_pton(family, IP4_ADDR, &daddr4.sin_addr.s_addr))
1186254e5c6SPeter Oskolkov 			error(1, errno, "inet_pton failed: %s", IP4_ADDR);
1196254e5c6SPeter Oskolkov 		daddr4.sin_port = htons(PORT);
1206254e5c6SPeter Oskolkov 
1216254e5c6SPeter Oskolkov 		sz = sizeof(saddr4);
1226254e5c6SPeter Oskolkov 		saddr = (struct sockaddr *)&saddr4;
1236254e5c6SPeter Oskolkov 		daddr = (struct sockaddr *)&daddr4;
1246254e5c6SPeter Oskolkov 	break;
1256254e5c6SPeter Oskolkov 	case AF_INET6:
1266254e5c6SPeter Oskolkov 		saddr6.sin6_family = AF_INET6;
1276254e5c6SPeter Oskolkov 		saddr6.sin6_addr = in6addr_any;
1286254e5c6SPeter Oskolkov 
1296254e5c6SPeter Oskolkov 		daddr6.sin6_family = AF_INET6;
1306254e5c6SPeter Oskolkov 		if (!inet_pton(family, IP6_ADDR, &daddr6.sin6_addr))
1316254e5c6SPeter Oskolkov 			error(1, errno, "inet_pton failed: %s", IP6_ADDR);
1326254e5c6SPeter Oskolkov 		daddr6.sin6_port = htons(PORT);
1336254e5c6SPeter Oskolkov 
1346254e5c6SPeter Oskolkov 		sz = sizeof(saddr6);
1356254e5c6SPeter Oskolkov 		saddr = (struct sockaddr *)&saddr6;
1366254e5c6SPeter Oskolkov 		daddr = (struct sockaddr *)&daddr6;
1376254e5c6SPeter Oskolkov 	break;
1386254e5c6SPeter Oskolkov 	default:
1396254e5c6SPeter Oskolkov 		error(1, 0, "Unsupported family %d", family);
140fa232332SPeter Oskolkov 		/* clang does not recognize error() above as terminating
141fa232332SPeter Oskolkov 		 * the program, so it complains that saddr, daddr, sz are
142fa232332SPeter Oskolkov 		 * not initialized when this code path is taken. Silence it.
143fa232332SPeter Oskolkov 		 */
144fa232332SPeter Oskolkov 		return -1;
1456254e5c6SPeter Oskolkov 	}
1466254e5c6SPeter Oskolkov 
1476254e5c6SPeter Oskolkov 	fd = socket(family, proto, 0);
1486254e5c6SPeter Oskolkov 	if (fd < 0)
1496254e5c6SPeter Oskolkov 		error(1, errno, "failed to create send socket");
1506254e5c6SPeter Oskolkov 
15111fb60d1SPeter Oskolkov 	if (proto == SOCK_DCCP &&
15211fb60d1SPeter Oskolkov 		setsockopt(fd, SOL_DCCP, DCCP_SOCKOPT_SERVICE,
15311fb60d1SPeter Oskolkov 				&(int){htonl(42)}, sizeof(int)))
15411fb60d1SPeter Oskolkov 		error(1, errno, "failed to setsockopt");
15511fb60d1SPeter Oskolkov 
1566254e5c6SPeter Oskolkov 	if (bind(fd, saddr, sz))
1576254e5c6SPeter Oskolkov 		error(1, errno, "failed to bind send socket");
1586254e5c6SPeter Oskolkov 
1596254e5c6SPeter Oskolkov 	if (connect(fd, daddr, sz))
1606254e5c6SPeter Oskolkov 		error(1, errno, "failed to connect send socket");
1616254e5c6SPeter Oskolkov 
1626254e5c6SPeter Oskolkov 	if (send(fd, "a", 1, 0) < 0)
1636254e5c6SPeter Oskolkov 		error(1, errno, "failed to send message");
1646254e5c6SPeter Oskolkov 
1656254e5c6SPeter Oskolkov 	return fd;
1666254e5c6SPeter Oskolkov }
1676254e5c6SPeter Oskolkov 
receive_once(int epfd,int proto)1686254e5c6SPeter Oskolkov static int receive_once(int epfd, int proto)
1696254e5c6SPeter Oskolkov {
1706254e5c6SPeter Oskolkov 	struct epoll_event ev;
1716254e5c6SPeter Oskolkov 	int i, fd;
1726254e5c6SPeter Oskolkov 	char buf[8];
1736254e5c6SPeter Oskolkov 
1746254e5c6SPeter Oskolkov 	i = epoll_wait(epfd, &ev, 1, 3);
1756254e5c6SPeter Oskolkov 	if (i < 0)
1766254e5c6SPeter Oskolkov 		error(1, errno, "epoll_wait failed");
1776254e5c6SPeter Oskolkov 
17811fb60d1SPeter Oskolkov 	if (proto == SOCK_STREAM || proto == SOCK_DCCP) {
1796254e5c6SPeter Oskolkov 		fd = accept(ev.data.fd, NULL, NULL);
1806254e5c6SPeter Oskolkov 		if (fd < 0)
1816254e5c6SPeter Oskolkov 			error(1, errno, "failed to accept");
1826254e5c6SPeter Oskolkov 		i = recv(fd, buf, sizeof(buf), 0);
1836254e5c6SPeter Oskolkov 		close(fd);
1846254e5c6SPeter Oskolkov 	} else {
1856254e5c6SPeter Oskolkov 		i = recv(ev.data.fd, buf, sizeof(buf), 0);
1866254e5c6SPeter Oskolkov 	}
1876254e5c6SPeter Oskolkov 
1886254e5c6SPeter Oskolkov 	if (i < 0)
1896254e5c6SPeter Oskolkov 		error(1, errno, "failed to recv");
1906254e5c6SPeter Oskolkov 
1916254e5c6SPeter Oskolkov 	return ev.data.fd;
1926254e5c6SPeter Oskolkov }
1936254e5c6SPeter Oskolkov 
test(int * rcv_fds,int count,int family,int proto,int fd)1946254e5c6SPeter Oskolkov static void test(int *rcv_fds, int count, int family, int proto, int fd)
1956254e5c6SPeter Oskolkov {
1966254e5c6SPeter Oskolkov 	struct epoll_event ev;
1976254e5c6SPeter Oskolkov 	int epfd, i, send_fd, recv_fd;
1986254e5c6SPeter Oskolkov 
1996254e5c6SPeter Oskolkov 	epfd = epoll_create(1);
2006254e5c6SPeter Oskolkov 	if (epfd < 0)
2016254e5c6SPeter Oskolkov 		error(1, errno, "failed to create epoll");
2026254e5c6SPeter Oskolkov 
2036254e5c6SPeter Oskolkov 	ev.events = EPOLLIN;
2046254e5c6SPeter Oskolkov 	for (i = 0; i < count; ++i) {
2056254e5c6SPeter Oskolkov 		ev.data.fd = rcv_fds[i];
2066254e5c6SPeter Oskolkov 		if (epoll_ctl(epfd, EPOLL_CTL_ADD, rcv_fds[i], &ev))
2076254e5c6SPeter Oskolkov 			error(1, errno, "failed to register sock epoll");
2086254e5c6SPeter Oskolkov 	}
2096254e5c6SPeter Oskolkov 
2106254e5c6SPeter Oskolkov 	send_fd = connect_and_send(family, proto);
2116254e5c6SPeter Oskolkov 
2126254e5c6SPeter Oskolkov 	recv_fd = receive_once(epfd, proto);
2136254e5c6SPeter Oskolkov 	if (recv_fd != fd)
2146254e5c6SPeter Oskolkov 		error(1, 0, "received on an unexpected socket");
2156254e5c6SPeter Oskolkov 
2166254e5c6SPeter Oskolkov 	close(send_fd);
2176254e5c6SPeter Oskolkov 	close(epfd);
2186254e5c6SPeter Oskolkov }
2196254e5c6SPeter Oskolkov 
2203f2eadb1SPeter Oskolkov 
run_one_test(int fam_send,int fam_rcv,int proto,const char * addr_str)2213f2eadb1SPeter Oskolkov static void run_one_test(int fam_send, int fam_rcv, int proto,
2223f2eadb1SPeter Oskolkov 			 const char *addr_str)
2236254e5c6SPeter Oskolkov {
2246254e5c6SPeter Oskolkov 	/* Below we test that a socket listening on a specific address
2256254e5c6SPeter Oskolkov 	 * is always selected in preference over a socket listening
2266254e5c6SPeter Oskolkov 	 * on addr_any. Bugs where this is not the case often result
2276254e5c6SPeter Oskolkov 	 * in sockets created first or last to get picked. So below
2286254e5c6SPeter Oskolkov 	 * we make sure that there are always addr_any sockets created
2296254e5c6SPeter Oskolkov 	 * before and after a specific socket is created.
2306254e5c6SPeter Oskolkov 	 */
2316254e5c6SPeter Oskolkov 	int rcv_fds[10], i;
2326254e5c6SPeter Oskolkov 
2333f2eadb1SPeter Oskolkov 	build_rcv_fd(AF_INET, proto, rcv_fds, 2, NULL);
2343f2eadb1SPeter Oskolkov 	build_rcv_fd(AF_INET6, proto, rcv_fds + 2, 2, NULL);
2353f2eadb1SPeter Oskolkov 	build_rcv_fd(fam_rcv, proto, rcv_fds + 4, 1, addr_str);
2363f2eadb1SPeter Oskolkov 	build_rcv_fd(AF_INET, proto, rcv_fds + 5, 2, NULL);
2373f2eadb1SPeter Oskolkov 	build_rcv_fd(AF_INET6, proto, rcv_fds + 7, 2, NULL);
2383f2eadb1SPeter Oskolkov 	test(rcv_fds, 9, fam_send, proto, rcv_fds[4]);
2396254e5c6SPeter Oskolkov 	for (i = 0; i < 9; ++i)
2406254e5c6SPeter Oskolkov 		close(rcv_fds[i]);
2413f2eadb1SPeter Oskolkov 	fprintf(stderr, "pass\n");
2423f2eadb1SPeter Oskolkov }
2436254e5c6SPeter Oskolkov 
test_proto(int proto,const char * proto_str)2443f2eadb1SPeter Oskolkov static void test_proto(int proto, const char *proto_str)
2453f2eadb1SPeter Oskolkov {
2463f2eadb1SPeter Oskolkov 	if (proto == SOCK_DCCP) {
2473f2eadb1SPeter Oskolkov 		int test_fd;
2486254e5c6SPeter Oskolkov 
2493f2eadb1SPeter Oskolkov 		test_fd = socket(AF_INET, proto, 0);
2503f2eadb1SPeter Oskolkov 		if (test_fd < 0) {
2513f2eadb1SPeter Oskolkov 			if (errno == ESOCKTNOSUPPORT) {
2523f2eadb1SPeter Oskolkov 				fprintf(stderr, "DCCP not supported: skipping DCCP tests\n");
2533f2eadb1SPeter Oskolkov 				return;
2543f2eadb1SPeter Oskolkov 			} else
2553f2eadb1SPeter Oskolkov 				error(1, errno, "failed to create a DCCP socket");
2563f2eadb1SPeter Oskolkov 		}
2573f2eadb1SPeter Oskolkov 		close(test_fd);
2583f2eadb1SPeter Oskolkov 	}
2596254e5c6SPeter Oskolkov 
2603f2eadb1SPeter Oskolkov 	fprintf(stderr, "%s IPv4 ... ", proto_str);
2613f2eadb1SPeter Oskolkov 	run_one_test(AF_INET, AF_INET, proto, IP4_ADDR);
2626254e5c6SPeter Oskolkov 
2633f2eadb1SPeter Oskolkov 	fprintf(stderr, "%s IPv6 ... ", proto_str);
2643f2eadb1SPeter Oskolkov 	run_one_test(AF_INET6, AF_INET6, proto, IP6_ADDR);
2656254e5c6SPeter Oskolkov 
2663f2eadb1SPeter Oskolkov 	fprintf(stderr, "%s IPv4 mapped to IPv6 ... ", proto_str);
2673f2eadb1SPeter Oskolkov 	run_one_test(AF_INET, AF_INET6, proto, IP4_MAPPED6);
2683f2eadb1SPeter Oskolkov }
2696254e5c6SPeter Oskolkov 
main(void)2703f2eadb1SPeter Oskolkov int main(void)
2713f2eadb1SPeter Oskolkov {
2723f2eadb1SPeter Oskolkov 	test_proto(SOCK_DGRAM, "UDP");
2733f2eadb1SPeter Oskolkov 	test_proto(SOCK_STREAM, "TCP");
2743f2eadb1SPeter Oskolkov 	test_proto(SOCK_DCCP, "DCCP");
27511fb60d1SPeter Oskolkov 
2766254e5c6SPeter Oskolkov 	fprintf(stderr, "SUCCESS\n");
2776254e5c6SPeter Oskolkov 	return 0;
2786254e5c6SPeter Oskolkov }
279