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