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