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