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