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
pack_port_range(__u16 lo,__u16 hi)19 static __u32 pack_port_range(__u16 lo, __u16 hi)
20 {
21 return (hi << 16) | (lo << 0);
22 }
23
unpack_port_range(__u32 range,__u16 * lo,__u16 * hi)24 static void unpack_port_range(__u32 range, __u16 *lo, __u16 *hi)
25 {
26 *lo = range & 0xffff;
27 *hi = range >> 16;
28 }
29
get_so_domain(int fd)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
bind_to_loopback_any_port(int fd)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
get_sock_port(int fd)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
get_ip_local_port_range(int fd,__u32 * range)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
FIXTURE(ip_local_port_range)115 FIXTURE(ip_local_port_range) {};
116
FIXTURE_SETUP(ip_local_port_range)117 FIXTURE_SETUP(ip_local_port_range)
118 {
119 }
120
FIXTURE_TEARDOWN(ip_local_port_range)121 FIXTURE_TEARDOWN(ip_local_port_range)
122 {
123 }
124
FIXTURE_VARIANT(ip_local_port_range)125 FIXTURE_VARIANT(ip_local_port_range) {
126 int so_domain;
127 int so_type;
128 int so_protocol;
129 };
130
FIXTURE_VARIANT_ADD(ip_local_port_range,ip4_tcp)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
FIXTURE_VARIANT_ADD(ip_local_port_range,ip4_udp)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
FIXTURE_VARIANT_ADD(ip_local_port_range,ip4_stcp)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
FIXTURE_VARIANT_ADD(ip_local_port_range,ip6_tcp)149 FIXTURE_VARIANT_ADD(ip_local_port_range, ip6_tcp) {
150 .so_domain = AF_INET6,
151 .so_type = SOCK_STREAM,
152 .so_protocol = 0,
153 };
154
FIXTURE_VARIANT_ADD(ip_local_port_range,ip6_udp)155 FIXTURE_VARIANT_ADD(ip_local_port_range, ip6_udp) {
156 .so_domain = AF_INET6,
157 .so_type = SOCK_DGRAM,
158 .so_protocol = 0,
159 };
160
FIXTURE_VARIANT_ADD(ip_local_port_range,ip6_stcp)161 FIXTURE_VARIANT_ADD(ip_local_port_range, ip6_stcp) {
162 .so_domain = AF_INET6,
163 .so_type = SOCK_STREAM,
164 .so_protocol = IPPROTO_SCTP,
165 };
166
TEST_F(ip_local_port_range,invalid_option_value)167 TEST_F(ip_local_port_range, invalid_option_value)
168 {
169 __u16 val16;
170 __u32 val32;
171 __u64 val64;
172 int fd, err;
173
174 fd = socket(variant->so_domain, variant->so_type, variant->so_protocol);
175 ASSERT_GE(fd, 0) TH_LOG("socket failed");
176
177 /* Too few bytes */
178 val16 = 40000;
179 err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &val16, sizeof(val16));
180 EXPECT_TRUE(err) TH_LOG("expected setsockopt(IP_LOCAL_PORT_RANGE) to fail");
181 EXPECT_EQ(errno, EINVAL);
182
183 /* Empty range: low port > high port */
184 val32 = pack_port_range(40222, 40111);
185 err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &val32, sizeof(val32));
186 EXPECT_TRUE(err) TH_LOG("expected setsockopt(IP_LOCAL_PORT_RANGE) to fail");
187 EXPECT_EQ(errno, EINVAL);
188
189 /* Too many bytes */
190 val64 = pack_port_range(40333, 40444);
191 err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &val64, sizeof(val64));
192 EXPECT_TRUE(err) TH_LOG("expected setsockopt(IP_LOCAL_PORT_RANGE) to fail");
193 EXPECT_EQ(errno, EINVAL);
194
195 err = close(fd);
196 ASSERT_TRUE(!err) TH_LOG("close failed");
197 }
198
TEST_F(ip_local_port_range,port_range_out_of_netns_range)199 TEST_F(ip_local_port_range, port_range_out_of_netns_range)
200 {
201 const struct test {
202 __u16 range_lo;
203 __u16 range_hi;
204 } tests[] = {
205 { 30000, 39999 }, /* socket range below netns range */
206 { 50000, 59999 }, /* socket range above netns range */
207 };
208 const struct test *t;
209
210 for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
211 /* Bind a couple of sockets, not just one, to check
212 * that the range wasn't clamped to a single port from
213 * the netns range. That is [40000, 40000] or [49999,
214 * 49999], respectively for each test case.
215 */
216 int fds[2], i;
217
218 TH_LOG("lo %5hu, hi %5hu", t->range_lo, t->range_hi);
219
220 for (i = 0; i < ARRAY_SIZE(fds); i++) {
221 int fd, err, port;
222 __u32 range;
223
224 fd = socket(variant->so_domain, variant->so_type, variant->so_protocol);
225 ASSERT_GE(fd, 0) TH_LOG("#%d: socket failed", i);
226
227 range = pack_port_range(t->range_lo, t->range_hi);
228 err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
229 ASSERT_TRUE(!err) TH_LOG("#%d: setsockopt(IP_LOCAL_PORT_RANGE) failed", i);
230
231 err = bind_to_loopback_any_port(fd);
232 ASSERT_TRUE(!err) TH_LOG("#%d: bind failed", i);
233
234 /* Check that socket port range outside of ephemeral range is ignored */
235 port = get_sock_port(fd);
236 ASSERT_GE(port, 40000) TH_LOG("#%d: expected port within netns range", i);
237 ASSERT_LE(port, 49999) TH_LOG("#%d: expected port within netns range", i);
238
239 fds[i] = fd;
240 }
241
242 for (i = 0; i < ARRAY_SIZE(fds); i++)
243 ASSERT_TRUE(close(fds[i]) == 0) TH_LOG("#%d: close failed", i);
244 }
245 }
246
TEST_F(ip_local_port_range,single_port_range)247 TEST_F(ip_local_port_range, single_port_range)
248 {
249 const struct test {
250 __u16 range_lo;
251 __u16 range_hi;
252 __u16 expected;
253 } tests[] = {
254 /* single port range within ephemeral range */
255 { 45000, 45000, 45000 },
256 /* first port in the ephemeral range (clamp from above) */
257 { 0, 40000, 40000 },
258 /* last port in the ephemeral range (clamp from below) */
259 { 49999, 0, 49999 },
260 };
261 const struct test *t;
262
263 for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
264 int fd, err, port;
265 __u32 range;
266
267 TH_LOG("lo %5hu, hi %5hu, expected %5hu",
268 t->range_lo, t->range_hi, t->expected);
269
270 fd = socket(variant->so_domain, variant->so_type, variant->so_protocol);
271 ASSERT_GE(fd, 0) TH_LOG("socket failed");
272
273 range = pack_port_range(t->range_lo, t->range_hi);
274 err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
275 ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_LOCAL_PORT_RANGE) failed");
276
277 err = bind_to_loopback_any_port(fd);
278 ASSERT_TRUE(!err) TH_LOG("bind failed");
279
280 port = get_sock_port(fd);
281 ASSERT_EQ(port, t->expected) TH_LOG("unexpected local port");
282
283 err = close(fd);
284 ASSERT_TRUE(!err) TH_LOG("close failed");
285 }
286 }
287
TEST_F(ip_local_port_range,exhaust_8_port_range)288 TEST_F(ip_local_port_range, exhaust_8_port_range)
289 {
290 __u8 port_set = 0;
291 int i, fd, err;
292 __u32 range;
293 __u16 port;
294 int fds[8];
295
296 for (i = 0; i < ARRAY_SIZE(fds); i++) {
297 fd = socket(variant->so_domain, variant->so_type, variant->so_protocol);
298 ASSERT_GE(fd, 0) TH_LOG("socket failed");
299
300 range = pack_port_range(40000, 40007);
301 err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
302 ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_LOCAL_PORT_RANGE) failed");
303
304 err = bind_to_loopback_any_port(fd);
305 ASSERT_TRUE(!err) TH_LOG("bind failed");
306
307 port = get_sock_port(fd);
308 ASSERT_GE(port, 40000) TH_LOG("expected port within sockopt range");
309 ASSERT_LE(port, 40007) TH_LOG("expected port within sockopt range");
310
311 port_set |= 1 << (port - 40000);
312 fds[i] = fd;
313 }
314
315 /* Check that all every port from the test range is in use */
316 ASSERT_EQ(port_set, 0xff) TH_LOG("expected all ports to be busy");
317
318 /* Check that bind() fails because the whole range is busy */
319 fd = socket(variant->so_domain, variant->so_type, variant->so_protocol);
320 ASSERT_GE(fd, 0) TH_LOG("socket failed");
321
322 range = pack_port_range(40000, 40007);
323 err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
324 ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_LOCAL_PORT_RANGE) failed");
325
326 err = bind_to_loopback_any_port(fd);
327 ASSERT_TRUE(err) TH_LOG("expected bind to fail");
328 ASSERT_EQ(errno, EADDRINUSE);
329
330 err = close(fd);
331 ASSERT_TRUE(!err) TH_LOG("close failed");
332
333 for (i = 0; i < ARRAY_SIZE(fds); i++) {
334 err = close(fds[i]);
335 ASSERT_TRUE(!err) TH_LOG("close failed");
336 }
337 }
338
TEST_F(ip_local_port_range,late_bind)339 TEST_F(ip_local_port_range, late_bind)
340 {
341 union {
342 struct sockaddr sa;
343 struct sockaddr_in v4;
344 struct sockaddr_in6 v6;
345 } addr;
346 socklen_t addr_len = 0;
347 const int one = 1;
348 int fd, err;
349 __u32 range;
350 __u16 port;
351
352 if (variant->so_protocol == IPPROTO_SCTP)
353 SKIP(return, "SCTP doesn't support IP_BIND_ADDRESS_NO_PORT");
354
355 fd = socket(variant->so_domain, variant->so_type, 0);
356 ASSERT_GE(fd, 0) TH_LOG("socket failed");
357
358 range = pack_port_range(40100, 40199);
359 err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
360 ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_LOCAL_PORT_RANGE) failed");
361
362 err = setsockopt(fd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &one, sizeof(one));
363 ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_BIND_ADDRESS_NO_PORT) failed");
364
365 err = bind_to_loopback_any_port(fd);
366 ASSERT_TRUE(!err) TH_LOG("bind failed");
367
368 port = get_sock_port(fd);
369 ASSERT_EQ(port, 0) TH_LOG("getsockname failed");
370
371 /* Invalid destination */
372 memset(&addr, 0, sizeof(addr));
373 switch (variant->so_domain) {
374 case AF_INET:
375 addr.v4.sin_family = AF_INET;
376 addr.v4.sin_port = htons(0);
377 addr.v4.sin_addr.s_addr = htonl(INADDR_ANY);
378 addr_len = sizeof(addr.v4);
379 break;
380 case AF_INET6:
381 addr.v6.sin6_family = AF_INET6;
382 addr.v6.sin6_port = htons(0);
383 addr.v6.sin6_addr = in6addr_any;
384 addr_len = sizeof(addr.v6);
385 break;
386 default:
387 ASSERT_TRUE(false) TH_LOG("unsupported socket domain");
388 }
389
390 /* connect() doesn't need to succeed for late bind to happen */
391 connect(fd, &addr.sa, addr_len);
392
393 port = get_sock_port(fd);
394 ASSERT_GE(port, 40100);
395 ASSERT_LE(port, 40199);
396
397 err = close(fd);
398 ASSERT_TRUE(!err) TH_LOG("close failed");
399 }
400
TEST_F(ip_local_port_range,get_port_range)401 TEST_F(ip_local_port_range, get_port_range)
402 {
403 __u16 lo, hi;
404 __u32 range;
405 int fd, err;
406
407 fd = socket(variant->so_domain, variant->so_type, variant->so_protocol);
408 ASSERT_GE(fd, 0) TH_LOG("socket failed");
409
410 /* Get range before it will be set */
411 err = get_ip_local_port_range(fd, &range);
412 ASSERT_TRUE(!err) TH_LOG("getsockopt(IP_LOCAL_PORT_RANGE) failed");
413
414 unpack_port_range(range, &lo, &hi);
415 ASSERT_EQ(lo, 0) TH_LOG("unexpected low port");
416 ASSERT_EQ(hi, 0) TH_LOG("unexpected high port");
417
418 range = pack_port_range(12345, 54321);
419 err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
420 ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_LOCAL_PORT_RANGE) failed");
421
422 /* Get range after it has been 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, 12345) TH_LOG("unexpected low port");
428 ASSERT_EQ(hi, 54321) TH_LOG("unexpected high port");
429
430 /* Unset the port range */
431 range = pack_port_range(0, 0);
432 err = setsockopt(fd, SOL_IP, IP_LOCAL_PORT_RANGE, &range, sizeof(range));
433 ASSERT_TRUE(!err) TH_LOG("setsockopt(IP_LOCAL_PORT_RANGE) failed");
434
435 /* Get range after it has been unset */
436 err = get_ip_local_port_range(fd, &range);
437 ASSERT_TRUE(!err) TH_LOG("getsockopt(IP_LOCAL_PORT_RANGE) failed");
438
439 unpack_port_range(range, &lo, &hi);
440 ASSERT_EQ(lo, 0) TH_LOG("unexpected low port");
441 ASSERT_EQ(hi, 0) TH_LOG("unexpected high port");
442
443 err = close(fd);
444 ASSERT_TRUE(!err) TH_LOG("close failed");
445 }
446
447 TEST_HARNESS_MAIN
448