1ae543965SJakub Sitnicki // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2ae543965SJakub Sitnicki // Copyright (c) 2023 Cloudflare
3ae543965SJakub Sitnicki 
4ae543965SJakub Sitnicki /* Test IP_LOCAL_PORT_RANGE socket option: IPv4 + IPv6, TCP + UDP.
5ae543965SJakub Sitnicki  *
6ae543965SJakub Sitnicki  * Tests assume that net.ipv4.ip_local_port_range is [40000, 49999].
7ae543965SJakub Sitnicki  * Don't run these directly but with ip_local_port_range.sh script.
8ae543965SJakub Sitnicki  */
9ae543965SJakub Sitnicki 
10ae543965SJakub Sitnicki #include <fcntl.h>
11ae543965SJakub Sitnicki #include <netinet/ip.h>
12ae543965SJakub Sitnicki 
13ae543965SJakub Sitnicki #include "../kselftest_harness.h"
14ae543965SJakub Sitnicki 
15ae543965SJakub Sitnicki #ifndef IP_LOCAL_PORT_RANGE
16ae543965SJakub Sitnicki #define IP_LOCAL_PORT_RANGE 51
17ae543965SJakub Sitnicki #endif
18ae543965SJakub Sitnicki 
19c2b3ec36SMaxim Galaganov #ifndef IPPROTO_MPTCP
20c2b3ec36SMaxim Galaganov #define IPPROTO_MPTCP 262
21c2b3ec36SMaxim Galaganov #endif
22c2b3ec36SMaxim Galaganov 
pack_port_range(__u16 lo,__u16 hi)23ae543965SJakub Sitnicki static __u32 pack_port_range(__u16 lo, __u16 hi)
24ae543965SJakub Sitnicki {
25ae543965SJakub Sitnicki 	return (hi << 16) | (lo << 0);
26ae543965SJakub Sitnicki }
27ae543965SJakub Sitnicki 
unpack_port_range(__u32 range,__u16 * lo,__u16 * hi)28ae543965SJakub Sitnicki static void unpack_port_range(__u32 range, __u16 *lo, __u16 *hi)
29ae543965SJakub Sitnicki {
30ae543965SJakub Sitnicki 	*lo = range & 0xffff;
31ae543965SJakub Sitnicki 	*hi = range >> 16;
32ae543965SJakub Sitnicki }
33ae543965SJakub Sitnicki 
get_so_domain(int fd)34ae543965SJakub Sitnicki static int get_so_domain(int fd)
35ae543965SJakub Sitnicki {
36ae543965SJakub Sitnicki 	int domain, err;
37ae543965SJakub Sitnicki 	socklen_t len;
38ae543965SJakub Sitnicki 
39ae543965SJakub Sitnicki 	len = sizeof(domain);
40ae543965SJakub Sitnicki 	err = getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &domain, &len);
41ae543965SJakub Sitnicki 	if (err)
42ae543965SJakub Sitnicki 		return -1;
43ae543965SJakub Sitnicki 
44ae543965SJakub Sitnicki 	return domain;
45ae543965SJakub Sitnicki }
46ae543965SJakub Sitnicki 
bind_to_loopback_any_port(int fd)47ae543965SJakub Sitnicki static int bind_to_loopback_any_port(int fd)
48ae543965SJakub Sitnicki {
49ae543965SJakub Sitnicki 	union {
50ae543965SJakub Sitnicki 		struct sockaddr sa;
51ae543965SJakub Sitnicki 		struct sockaddr_in v4;
52ae543965SJakub Sitnicki 		struct sockaddr_in6 v6;
53ae543965SJakub Sitnicki 	} addr;
54ae543965SJakub Sitnicki 	socklen_t addr_len;
55ae543965SJakub Sitnicki 
56ae543965SJakub Sitnicki 	memset(&addr, 0, sizeof(addr));
57ae543965SJakub Sitnicki 	switch (get_so_domain(fd)) {
58ae543965SJakub Sitnicki 	case AF_INET:
59ae543965SJakub Sitnicki 		addr.v4.sin_family = AF_INET;
60ae543965SJakub Sitnicki 		addr.v4.sin_port = htons(0);
61ae543965SJakub Sitnicki 		addr.v4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
62ae543965SJakub Sitnicki 		addr_len = sizeof(addr.v4);
63ae543965SJakub Sitnicki 		break;
64ae543965SJakub Sitnicki 	case AF_INET6:
65ae543965SJakub Sitnicki 		addr.v6.sin6_family = AF_INET6;
66ae543965SJakub Sitnicki 		addr.v6.sin6_port = htons(0);
67ae543965SJakub Sitnicki 		addr.v6.sin6_addr = in6addr_loopback;
68ae543965SJakub Sitnicki 		addr_len = sizeof(addr.v6);
69ae543965SJakub Sitnicki 		break;
70ae543965SJakub Sitnicki 	default:
71ae543965SJakub Sitnicki 		return -1;
72ae543965SJakub Sitnicki 	}
73ae543965SJakub Sitnicki 
74ae543965SJakub Sitnicki 	return bind(fd, &addr.sa, addr_len);
75ae543965SJakub Sitnicki }
76ae543965SJakub Sitnicki 
get_sock_port(int fd)77ae543965SJakub Sitnicki static int get_sock_port(int fd)
78ae543965SJakub Sitnicki {
79ae543965SJakub Sitnicki 	union {
80ae543965SJakub Sitnicki 		struct sockaddr sa;
81ae543965SJakub Sitnicki 		struct sockaddr_in v4;
82ae543965SJakub Sitnicki 		struct sockaddr_in6 v6;
83ae543965SJakub Sitnicki 	} addr;
84ae543965SJakub Sitnicki 	socklen_t addr_len;
85ae543965SJakub Sitnicki 	int err;
86ae543965SJakub Sitnicki 
87ae543965SJakub Sitnicki 	addr_len = sizeof(addr);
88ae543965SJakub Sitnicki 	memset(&addr, 0, sizeof(addr));
89ae543965SJakub Sitnicki 	err = getsockname(fd, &addr.sa, &addr_len);
90ae543965SJakub Sitnicki 	if (err)
91ae543965SJakub Sitnicki 		return -1;
92ae543965SJakub Sitnicki 
93ae543965SJakub Sitnicki 	switch (addr.sa.sa_family) {
94ae543965SJakub Sitnicki 	case AF_INET:
95ae543965SJakub Sitnicki 		return ntohs(addr.v4.sin_port);
96ae543965SJakub Sitnicki 	case AF_INET6:
97ae543965SJakub Sitnicki 		return ntohs(addr.v6.sin6_port);
98ae543965SJakub Sitnicki 	default:
99ae543965SJakub Sitnicki 		errno = EAFNOSUPPORT;
100ae543965SJakub Sitnicki 		return -1;
101ae543965SJakub Sitnicki 	}
102ae543965SJakub Sitnicki }
103ae543965SJakub Sitnicki 
get_ip_local_port_range(int fd,__u32 * range)104ae543965SJakub Sitnicki static int get_ip_local_port_range(int fd, __u32 *range)
105ae543965SJakub Sitnicki {
106ae543965SJakub Sitnicki 	socklen_t len;
107ae543965SJakub Sitnicki 	__u32 val;
108ae543965SJakub Sitnicki 	int err;
109ae543965SJakub Sitnicki 
110ae543965SJakub Sitnicki 	len = sizeof(val);
111ae543965SJakub Sitnicki 	err = getsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &val, &len);
112ae543965SJakub Sitnicki 	if (err)
113ae543965SJakub Sitnicki 		return -1;
114ae543965SJakub Sitnicki 
115ae543965SJakub Sitnicki 	*range = val;
116ae543965SJakub Sitnicki 	return 0;
117ae543965SJakub Sitnicki }
118ae543965SJakub Sitnicki 
FIXTURE(ip_local_port_range)119ae543965SJakub Sitnicki FIXTURE(ip_local_port_range) {};
120ae543965SJakub Sitnicki 
FIXTURE_SETUP(ip_local_port_range)121ae543965SJakub Sitnicki FIXTURE_SETUP(ip_local_port_range)
122ae543965SJakub Sitnicki {
123ae543965SJakub Sitnicki }
124ae543965SJakub Sitnicki 
FIXTURE_TEARDOWN(ip_local_port_range)125ae543965SJakub Sitnicki FIXTURE_TEARDOWN(ip_local_port_range)
126ae543965SJakub Sitnicki {
127ae543965SJakub Sitnicki }
128ae543965SJakub Sitnicki 
FIXTURE_VARIANT(ip_local_port_range)129ae543965SJakub Sitnicki FIXTURE_VARIANT(ip_local_port_range) {
130ae543965SJakub Sitnicki 	int so_domain;
131ae543965SJakub Sitnicki 	int so_type;
132ae543965SJakub Sitnicki 	int so_protocol;
133ae543965SJakub Sitnicki };
134ae543965SJakub Sitnicki 
FIXTURE_VARIANT_ADD(ip_local_port_range,ip4_tcp)135ae543965SJakub Sitnicki FIXTURE_VARIANT_ADD(ip_local_port_range, ip4_tcp) {
136ae543965SJakub Sitnicki 	.so_domain	= AF_INET,
137ae543965SJakub Sitnicki 	.so_type	= SOCK_STREAM,
138ae543965SJakub Sitnicki 	.so_protocol	= 0,
139ae543965SJakub Sitnicki };
140ae543965SJakub Sitnicki 
FIXTURE_VARIANT_ADD(ip_local_port_range,ip4_udp)141ae543965SJakub Sitnicki FIXTURE_VARIANT_ADD(ip_local_port_range, ip4_udp) {
142ae543965SJakub Sitnicki 	.so_domain	= AF_INET,
143ae543965SJakub Sitnicki 	.so_type	= SOCK_DGRAM,
144ae543965SJakub Sitnicki 	.so_protocol	= 0,
145ae543965SJakub Sitnicki };
146ae543965SJakub Sitnicki 
FIXTURE_VARIANT_ADD(ip_local_port_range,ip4_stcp)147ae543965SJakub Sitnicki FIXTURE_VARIANT_ADD(ip_local_port_range, ip4_stcp) {
148ae543965SJakub Sitnicki 	.so_domain	= AF_INET,
149ae543965SJakub Sitnicki 	.so_type	= SOCK_STREAM,
150ae543965SJakub Sitnicki 	.so_protocol	= IPPROTO_SCTP,
151ae543965SJakub Sitnicki };
152ae543965SJakub Sitnicki 
FIXTURE_VARIANT_ADD(ip_local_port_range,ip4_mptcp)153122db5e3SMaxim Galaganov FIXTURE_VARIANT_ADD(ip_local_port_range, ip4_mptcp) {
154122db5e3SMaxim Galaganov 	.so_domain	= AF_INET,
155122db5e3SMaxim Galaganov 	.so_type	= SOCK_STREAM,
156122db5e3SMaxim Galaganov 	.so_protocol	= IPPROTO_MPTCP,
157122db5e3SMaxim Galaganov };
158122db5e3SMaxim Galaganov 
FIXTURE_VARIANT_ADD(ip_local_port_range,ip6_tcp)159ae543965SJakub Sitnicki FIXTURE_VARIANT_ADD(ip_local_port_range, ip6_tcp) {
160ae543965SJakub Sitnicki 	.so_domain	= AF_INET6,
161ae543965SJakub Sitnicki 	.so_type	= SOCK_STREAM,
162ae543965SJakub Sitnicki 	.so_protocol	= 0,
163ae543965SJakub Sitnicki };
164ae543965SJakub Sitnicki 
FIXTURE_VARIANT_ADD(ip_local_port_range,ip6_udp)165ae543965SJakub Sitnicki FIXTURE_VARIANT_ADD(ip_local_port_range, ip6_udp) {
166ae543965SJakub Sitnicki 	.so_domain	= AF_INET6,
167ae543965SJakub Sitnicki 	.so_type	= SOCK_DGRAM,
168ae543965SJakub Sitnicki 	.so_protocol	= 0,
169ae543965SJakub Sitnicki };
170ae543965SJakub Sitnicki 
FIXTURE_VARIANT_ADD(ip_local_port_range,ip6_stcp)171ae543965SJakub Sitnicki FIXTURE_VARIANT_ADD(ip_local_port_range, ip6_stcp) {
172ae543965SJakub Sitnicki 	.so_domain	= AF_INET6,
173ae543965SJakub Sitnicki 	.so_type	= SOCK_STREAM,
174ae543965SJakub Sitnicki 	.so_protocol	= IPPROTO_SCTP,
175ae543965SJakub Sitnicki };
176ae543965SJakub Sitnicki 
FIXTURE_VARIANT_ADD(ip_local_port_range,ip6_mptcp)177122db5e3SMaxim Galaganov FIXTURE_VARIANT_ADD(ip_local_port_range, ip6_mptcp) {
178122db5e3SMaxim Galaganov 	.so_domain	= AF_INET6,
179122db5e3SMaxim Galaganov 	.so_type	= SOCK_STREAM,
180122db5e3SMaxim Galaganov 	.so_protocol	= IPPROTO_MPTCP,
181122db5e3SMaxim Galaganov };
182122db5e3SMaxim Galaganov 
TEST_F(ip_local_port_range,invalid_option_value)183ae543965SJakub Sitnicki TEST_F(ip_local_port_range, invalid_option_value)
184ae543965SJakub Sitnicki {
185ae543965SJakub Sitnicki 	__u16 val16;
186ae543965SJakub Sitnicki 	__u32 val32;
187ae543965SJakub Sitnicki 	__u64 val64;
188ae543965SJakub Sitnicki 	int fd, err;
189ae543965SJakub Sitnicki 
190ae543965SJakub Sitnicki 	fd = socket(variant->so_domain, variant->so_type, variant->so_protocol);
191ae543965SJakub Sitnicki 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
192ae543965SJakub Sitnicki 
193ae543965SJakub Sitnicki 	/* Too few bytes */
194ae543965SJakub Sitnicki 	val16 = 40000;
195ae543965SJakub Sitnicki 	err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &val16, sizeof(val16));
196ae543965SJakub Sitnicki 	EXPECT_TRUE(err) TH_LOG("expected setsockopt(IP_LOCAL_PORT_RANGE) to fail");
197ae543965SJakub Sitnicki 	EXPECT_EQ(errno, EINVAL);
198ae543965SJakub Sitnicki 
199ae543965SJakub Sitnicki 	/* Empty range: low port > high port */
200ae543965SJakub Sitnicki 	val32 = pack_port_range(40222, 40111);
201ae543965SJakub Sitnicki 	err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &val32, sizeof(val32));
202ae543965SJakub Sitnicki 	EXPECT_TRUE(err) TH_LOG("expected setsockopt(IP_LOCAL_PORT_RANGE) to fail");
203ae543965SJakub Sitnicki 	EXPECT_EQ(errno, EINVAL);
204ae543965SJakub Sitnicki 
205ae543965SJakub Sitnicki 	/* Too many bytes */
206ae543965SJakub Sitnicki 	val64 = pack_port_range(40333, 40444);
207ae543965SJakub Sitnicki 	err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &val64, sizeof(val64));
208ae543965SJakub Sitnicki 	EXPECT_TRUE(err) TH_LOG("expected setsockopt(IP_LOCAL_PORT_RANGE) to fail");
209ae543965SJakub Sitnicki 	EXPECT_EQ(errno, EINVAL);
210ae543965SJakub Sitnicki 
211ae543965SJakub Sitnicki 	err = close(fd);
212ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("close failed");
213ae543965SJakub Sitnicki }
214ae543965SJakub Sitnicki 
TEST_F(ip_local_port_range,port_range_out_of_netns_range)215ae543965SJakub Sitnicki TEST_F(ip_local_port_range, port_range_out_of_netns_range)
216ae543965SJakub Sitnicki {
217ae543965SJakub Sitnicki 	const struct test {
218ae543965SJakub Sitnicki 		__u16 range_lo;
219ae543965SJakub Sitnicki 		__u16 range_hi;
220ae543965SJakub Sitnicki 	} tests[] = {
221ae543965SJakub Sitnicki 		{ 30000, 39999 }, /* socket range below netns range */
222ae543965SJakub Sitnicki 		{ 50000, 59999 }, /* socket range above netns range */
223ae543965SJakub Sitnicki 	};
224ae543965SJakub Sitnicki 	const struct test *t;
225ae543965SJakub Sitnicki 
226ae543965SJakub Sitnicki 	for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
227ae543965SJakub Sitnicki 		/* Bind a couple of sockets, not just one, to check
228ae543965SJakub Sitnicki 		 * that the range wasn't clamped to a single port from
229ae543965SJakub Sitnicki 		 * the netns range. That is [40000, 40000] or [49999,
230ae543965SJakub Sitnicki 		 * 49999], respectively for each test case.
231ae543965SJakub Sitnicki 		 */
232ae543965SJakub Sitnicki 		int fds[2], i;
233ae543965SJakub Sitnicki 
234ae543965SJakub Sitnicki 		TH_LOG("lo %5hu, hi %5hu", t->range_lo, t->range_hi);
235ae543965SJakub Sitnicki 
236ae543965SJakub Sitnicki 		for (i = 0; i < ARRAY_SIZE(fds); i++) {
237ae543965SJakub Sitnicki 			int fd, err, port;
238ae543965SJakub Sitnicki 			__u32 range;
239ae543965SJakub Sitnicki 
240ae543965SJakub Sitnicki 			fd = socket(variant->so_domain, variant->so_type, variant->so_protocol);
241ae543965SJakub Sitnicki 			ASSERT_GE(fd, 0) TH_LOG("#%d: socket failed", i);
242ae543965SJakub Sitnicki 
243ae543965SJakub Sitnicki 			range = pack_port_range(t->range_lo, t->range_hi);
244ae543965SJakub Sitnicki 			err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
245ae543965SJakub Sitnicki 			ASSERT_TRUE(!err) TH_LOG("#%d: setsockopt(IP_LOCAL_PORT_RANGE) failed", i);
246ae543965SJakub Sitnicki 
247ae543965SJakub Sitnicki 			err = bind_to_loopback_any_port(fd);
248ae543965SJakub Sitnicki 			ASSERT_TRUE(!err) TH_LOG("#%d: bind failed", i);
249ae543965SJakub Sitnicki 
250ae543965SJakub Sitnicki 			/* Check that socket port range outside of ephemeral range is ignored */
251ae543965SJakub Sitnicki 			port = get_sock_port(fd);
252ae543965SJakub Sitnicki 			ASSERT_GE(port, 40000) TH_LOG("#%d: expected port within netns range", i);
253ae543965SJakub Sitnicki 			ASSERT_LE(port, 49999) TH_LOG("#%d: expected port within netns range", i);
254ae543965SJakub Sitnicki 
255ae543965SJakub Sitnicki 			fds[i] = fd;
256ae543965SJakub Sitnicki 		}
257ae543965SJakub Sitnicki 
258ae543965SJakub Sitnicki 		for (i = 0; i < ARRAY_SIZE(fds); i++)
259ae543965SJakub Sitnicki 			ASSERT_TRUE(close(fds[i]) == 0) TH_LOG("#%d: close failed", i);
260ae543965SJakub Sitnicki 	}
261ae543965SJakub Sitnicki }
262ae543965SJakub Sitnicki 
TEST_F(ip_local_port_range,single_port_range)263ae543965SJakub Sitnicki TEST_F(ip_local_port_range, single_port_range)
264ae543965SJakub Sitnicki {
265ae543965SJakub Sitnicki 	const struct test {
266ae543965SJakub Sitnicki 		__u16 range_lo;
267ae543965SJakub Sitnicki 		__u16 range_hi;
268ae543965SJakub Sitnicki 		__u16 expected;
269ae543965SJakub Sitnicki 	} tests[] = {
270ae543965SJakub Sitnicki 		/* single port range within ephemeral range */
271ae543965SJakub Sitnicki 		{ 45000, 45000, 45000 },
272ae543965SJakub Sitnicki 		/* first port in the ephemeral range (clamp from above) */
273ae543965SJakub Sitnicki 		{ 0, 40000, 40000 },
274ae543965SJakub Sitnicki 		/* last port in the ephemeral range (clamp from below)  */
275ae543965SJakub Sitnicki 		{ 49999, 0, 49999 },
276ae543965SJakub Sitnicki 	};
277ae543965SJakub Sitnicki 	const struct test *t;
278ae543965SJakub Sitnicki 
279ae543965SJakub Sitnicki 	for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
280ae543965SJakub Sitnicki 		int fd, err, port;
281ae543965SJakub Sitnicki 		__u32 range;
282ae543965SJakub Sitnicki 
283ae543965SJakub Sitnicki 		TH_LOG("lo %5hu, hi %5hu, expected %5hu",
284ae543965SJakub Sitnicki 		       t->range_lo, t->range_hi, t->expected);
285ae543965SJakub Sitnicki 
286ae543965SJakub Sitnicki 		fd = socket(variant->so_domain, variant->so_type, variant->so_protocol);
287ae543965SJakub Sitnicki 		ASSERT_GE(fd, 0) TH_LOG("socket failed");
288ae543965SJakub Sitnicki 
289ae543965SJakub Sitnicki 		range = pack_port_range(t->range_lo, t->range_hi);
290ae543965SJakub Sitnicki 		err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
291ae543965SJakub Sitnicki 		ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_LOCAL_PORT_RANGE) failed");
292ae543965SJakub Sitnicki 
293ae543965SJakub Sitnicki 		err = bind_to_loopback_any_port(fd);
294ae543965SJakub Sitnicki 		ASSERT_TRUE(!err) TH_LOG("bind failed");
295ae543965SJakub Sitnicki 
296ae543965SJakub Sitnicki 		port = get_sock_port(fd);
297ae543965SJakub Sitnicki 		ASSERT_EQ(port, t->expected) TH_LOG("unexpected local port");
298ae543965SJakub Sitnicki 
299ae543965SJakub Sitnicki 		err = close(fd);
300ae543965SJakub Sitnicki 		ASSERT_TRUE(!err) TH_LOG("close failed");
301ae543965SJakub Sitnicki 	}
302ae543965SJakub Sitnicki }
303ae543965SJakub Sitnicki 
TEST_F(ip_local_port_range,exhaust_8_port_range)304ae543965SJakub Sitnicki TEST_F(ip_local_port_range, exhaust_8_port_range)
305ae543965SJakub Sitnicki {
306ae543965SJakub Sitnicki 	__u8 port_set = 0;
307ae543965SJakub Sitnicki 	int i, fd, err;
308ae543965SJakub Sitnicki 	__u32 range;
309ae543965SJakub Sitnicki 	__u16 port;
310ae543965SJakub Sitnicki 	int fds[8];
311ae543965SJakub Sitnicki 
312ae543965SJakub Sitnicki 	for (i = 0; i < ARRAY_SIZE(fds); i++) {
313ae543965SJakub Sitnicki 		fd = socket(variant->so_domain, variant->so_type, variant->so_protocol);
314ae543965SJakub Sitnicki 		ASSERT_GE(fd, 0) TH_LOG("socket failed");
315ae543965SJakub Sitnicki 
316ae543965SJakub Sitnicki 		range = pack_port_range(40000, 40007);
317ae543965SJakub Sitnicki 		err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
318ae543965SJakub Sitnicki 		ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_LOCAL_PORT_RANGE) failed");
319ae543965SJakub Sitnicki 
320ae543965SJakub Sitnicki 		err = bind_to_loopback_any_port(fd);
321ae543965SJakub Sitnicki 		ASSERT_TRUE(!err) TH_LOG("bind failed");
322ae543965SJakub Sitnicki 
323ae543965SJakub Sitnicki 		port = get_sock_port(fd);
324ae543965SJakub Sitnicki 		ASSERT_GE(port, 40000) TH_LOG("expected port within sockopt range");
325ae543965SJakub Sitnicki 		ASSERT_LE(port, 40007) TH_LOG("expected port within sockopt range");
326ae543965SJakub Sitnicki 
327ae543965SJakub Sitnicki 		port_set |= 1 << (port - 40000);
328ae543965SJakub Sitnicki 		fds[i] = fd;
329ae543965SJakub Sitnicki 	}
330ae543965SJakub Sitnicki 
331ae543965SJakub Sitnicki 	/* Check that all every port from the test range is in use */
332ae543965SJakub Sitnicki 	ASSERT_EQ(port_set, 0xff) TH_LOG("expected all ports to be busy");
333ae543965SJakub Sitnicki 
334ae543965SJakub Sitnicki 	/* Check that bind() fails because the whole range is busy */
335ae543965SJakub Sitnicki 	fd = socket(variant->so_domain, variant->so_type, variant->so_protocol);
336ae543965SJakub Sitnicki 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
337ae543965SJakub Sitnicki 
338ae543965SJakub Sitnicki 	range = pack_port_range(40000, 40007);
339ae543965SJakub Sitnicki 	err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
340ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_LOCAL_PORT_RANGE) failed");
341ae543965SJakub Sitnicki 
342ae543965SJakub Sitnicki 	err = bind_to_loopback_any_port(fd);
343ae543965SJakub Sitnicki 	ASSERT_TRUE(err) TH_LOG("expected bind to fail");
344ae543965SJakub Sitnicki 	ASSERT_EQ(errno, EADDRINUSE);
345ae543965SJakub Sitnicki 
346ae543965SJakub Sitnicki 	err = close(fd);
347ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("close failed");
348ae543965SJakub Sitnicki 
349ae543965SJakub Sitnicki 	for (i = 0; i < ARRAY_SIZE(fds); i++) {
350ae543965SJakub Sitnicki 		err = close(fds[i]);
351ae543965SJakub Sitnicki 		ASSERT_TRUE(!err) TH_LOG("close failed");
352ae543965SJakub Sitnicki 	}
353ae543965SJakub Sitnicki }
354ae543965SJakub Sitnicki 
TEST_F(ip_local_port_range,late_bind)355ae543965SJakub Sitnicki TEST_F(ip_local_port_range, late_bind)
356ae543965SJakub Sitnicki {
357ae543965SJakub Sitnicki 	union {
358ae543965SJakub Sitnicki 		struct sockaddr sa;
359ae543965SJakub Sitnicki 		struct sockaddr_in v4;
360ae543965SJakub Sitnicki 		struct sockaddr_in6 v6;
361ae543965SJakub Sitnicki 	} addr;
362*eb709b5fSJohn Hubbard 	socklen_t addr_len = 0;
363ae543965SJakub Sitnicki 	const int one = 1;
364ae543965SJakub Sitnicki 	int fd, err;
365ae543965SJakub Sitnicki 	__u32 range;
366ae543965SJakub Sitnicki 	__u16 port;
367ae543965SJakub Sitnicki 
368ae543965SJakub Sitnicki 	fd = socket(variant->so_domain, variant->so_type, 0);
369ae543965SJakub Sitnicki 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
370ae543965SJakub Sitnicki 
371ae543965SJakub Sitnicki 	range = pack_port_range(40100, 40199);
372ae543965SJakub Sitnicki 	err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
373ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_LOCAL_PORT_RANGE) failed");
374ae543965SJakub Sitnicki 
375ae543965SJakub Sitnicki 	err = setsockopt(fd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &one, sizeof(one));
376ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_BIND_ADDRESS_NO_PORT) failed");
377ae543965SJakub Sitnicki 
378ae543965SJakub Sitnicki 	err = bind_to_loopback_any_port(fd);
379ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("bind failed");
380ae543965SJakub Sitnicki 
381ae543965SJakub Sitnicki 	port = get_sock_port(fd);
382ae543965SJakub Sitnicki 	ASSERT_EQ(port, 0) TH_LOG("getsockname failed");
383ae543965SJakub Sitnicki 
384ae543965SJakub Sitnicki 	/* Invalid destination */
385ae543965SJakub Sitnicki 	memset(&addr, 0, sizeof(addr));
386ae543965SJakub Sitnicki 	switch (variant->so_domain) {
387ae543965SJakub Sitnicki 	case AF_INET:
388ae543965SJakub Sitnicki 		addr.v4.sin_family = AF_INET;
389ae543965SJakub Sitnicki 		addr.v4.sin_port = htons(0);
390ae543965SJakub Sitnicki 		addr.v4.sin_addr.s_addr = htonl(INADDR_ANY);
391ae543965SJakub Sitnicki 		addr_len = sizeof(addr.v4);
392ae543965SJakub Sitnicki 		break;
393ae543965SJakub Sitnicki 	case AF_INET6:
394ae543965SJakub Sitnicki 		addr.v6.sin6_family = AF_INET6;
395ae543965SJakub Sitnicki 		addr.v6.sin6_port = htons(0);
396ae543965SJakub Sitnicki 		addr.v6.sin6_addr = in6addr_any;
397ae543965SJakub Sitnicki 		addr_len = sizeof(addr.v6);
398ae543965SJakub Sitnicki 		break;
399ae543965SJakub Sitnicki 	default:
400ae543965SJakub Sitnicki 		ASSERT_TRUE(false) TH_LOG("unsupported socket domain");
401ae543965SJakub Sitnicki 	}
402ae543965SJakub Sitnicki 
403ae543965SJakub Sitnicki 	/* connect() doesn't need to succeed for late bind to happen */
404ae543965SJakub Sitnicki 	connect(fd, &addr.sa, addr_len);
405ae543965SJakub Sitnicki 
406ae543965SJakub Sitnicki 	port = get_sock_port(fd);
407ae543965SJakub Sitnicki 	ASSERT_GE(port, 40100);
408ae543965SJakub Sitnicki 	ASSERT_LE(port, 40199);
409ae543965SJakub Sitnicki 
410ae543965SJakub Sitnicki 	err = close(fd);
411ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("close failed");
412ae543965SJakub Sitnicki }
413ae543965SJakub Sitnicki 
414c05bf0e9SJakub Kicinski XFAIL_ADD(ip_local_port_range, ip4_stcp, late_bind);
415c05bf0e9SJakub Kicinski XFAIL_ADD(ip_local_port_range, ip6_stcp, late_bind);
416c05bf0e9SJakub Kicinski 
TEST_F(ip_local_port_range,get_port_range)417ae543965SJakub Sitnicki TEST_F(ip_local_port_range, get_port_range)
418ae543965SJakub Sitnicki {
419ae543965SJakub Sitnicki 	__u16 lo, hi;
420ae543965SJakub Sitnicki 	__u32 range;
421ae543965SJakub Sitnicki 	int fd, err;
422ae543965SJakub Sitnicki 
423ae543965SJakub Sitnicki 	fd = socket(variant->so_domain, variant->so_type, variant->so_protocol);
424ae543965SJakub Sitnicki 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
425ae543965SJakub Sitnicki 
426ae543965SJakub Sitnicki 	/* Get range before it will be set */
427ae543965SJakub Sitnicki 	err = get_ip_local_port_range(fd, &range);
428ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("getsockopt(IP_LOCAL_PORT_RANGE) failed");
429ae543965SJakub Sitnicki 
430ae543965SJakub Sitnicki 	unpack_port_range(range, &lo, &hi);
431ae543965SJakub Sitnicki 	ASSERT_EQ(lo, 0) TH_LOG("unexpected low port");
432ae543965SJakub Sitnicki 	ASSERT_EQ(hi, 0) TH_LOG("unexpected high port");
433ae543965SJakub Sitnicki 
434ae543965SJakub Sitnicki 	range = pack_port_range(12345, 54321);
435ae543965SJakub Sitnicki 	err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
436ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_LOCAL_PORT_RANGE) failed");
437ae543965SJakub Sitnicki 
438ae543965SJakub Sitnicki 	/* Get range after it has been set */
439ae543965SJakub Sitnicki 	err = get_ip_local_port_range(fd, &range);
440ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("getsockopt(IP_LOCAL_PORT_RANGE) failed");
441ae543965SJakub Sitnicki 
442ae543965SJakub Sitnicki 	unpack_port_range(range, &lo, &hi);
443ae543965SJakub Sitnicki 	ASSERT_EQ(lo, 12345) TH_LOG("unexpected low port");
444ae543965SJakub Sitnicki 	ASSERT_EQ(hi, 54321) TH_LOG("unexpected high port");
445ae543965SJakub Sitnicki 
446ae543965SJakub Sitnicki 	/* Unset the port range  */
447ae543965SJakub Sitnicki 	range = pack_port_range(0, 0);
448ae543965SJakub Sitnicki 	err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
449ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_LOCAL_PORT_RANGE) failed");
450ae543965SJakub Sitnicki 
451ae543965SJakub Sitnicki 	/* Get range after it has been unset */
452ae543965SJakub Sitnicki 	err = get_ip_local_port_range(fd, &range);
453ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("getsockopt(IP_LOCAL_PORT_RANGE) failed");
454ae543965SJakub Sitnicki 
455ae543965SJakub Sitnicki 	unpack_port_range(range, &lo, &hi);
456ae543965SJakub Sitnicki 	ASSERT_EQ(lo, 0) TH_LOG("unexpected low port");
457ae543965SJakub Sitnicki 	ASSERT_EQ(hi, 0) TH_LOG("unexpected high port");
458ae543965SJakub Sitnicki 
459ae543965SJakub Sitnicki 	err = close(fd);
460ae543965SJakub Sitnicki 	ASSERT_TRUE(!err) TH_LOG("close failed");
461ae543965SJakub Sitnicki }
462ae543965SJakub Sitnicki 
463ae543965SJakub Sitnicki TEST_HARNESS_MAIN
464