gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/util/socket_util.cc (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "test/util/socket_util.h" 16 17 #include <arpa/inet.h> 18 #include <netinet/in.h> 19 #include <poll.h> 20 #include <sys/socket.h> 21 22 #include <cstddef> 23 #include <functional> 24 #include <memory> 25 #include <stack> 26 27 #include "gtest/gtest.h" 28 #include "absl/strings/str_cat.h" 29 #include "absl/strings/str_split.h" 30 #include "absl/time/clock.h" 31 #include "absl/types/optional.h" 32 #include "test/util/file_descriptor.h" 33 #include "test/util/posix_error.h" 34 #include "test/util/temp_path.h" 35 #include "test/util/test_util.h" 36 #include "test/util/thread_util.h" 37 38 namespace gvisor { 39 namespace testing { 40 41 Creator<SocketPair> SyscallSocketPairCreator(int domain, int type, 42 int protocol) { 43 return [=]() -> PosixErrorOr<std::unique_ptr<FDSocketPair>> { 44 int pair[2]; 45 RETURN_ERROR_IF_SYSCALL_FAIL(socketpair(domain, type, protocol, pair)); 46 MaybeSave(); // Save on successful creation. 47 return std::make_unique<FDSocketPair>(FileDescriptor(pair[0]), 48 FileDescriptor(pair[1])); 49 }; 50 } 51 52 Creator<FileDescriptor> SyscallSocketCreator(int domain, int type, 53 int protocol) { 54 return [=]() -> PosixErrorOr<std::unique_ptr<FileDescriptor>> { 55 int fd = 0; 56 RETURN_ERROR_IF_SYSCALL_FAIL(fd = socket(domain, type, protocol)); 57 MaybeSave(); // Save on successful creation. 58 return std::make_unique<FileDescriptor>(fd); 59 }; 60 } 61 62 PosixErrorOr<struct sockaddr_un> UniqueUnixAddr(bool abstract, int domain) { 63 struct sockaddr_un addr = {}; 64 65 #ifdef ANDROID 66 // Using NewTempAbsPath() can cause the tmp directory path to exceed the max 67 // length (i.e., sizeof(addr.sun_path)). 68 // 69 // However, existing systems that are built with the ANDROID configuration 70 // have their temp directory in a different location, and must respect the 71 // TEST_TMPDIR. 72 std::string path = NewTempAbsPath(); 73 #else 74 std::string path = NewTempAbsPathInDir("/tmp"); 75 #endif // ANDROID 76 77 if (path.size() >= sizeof(addr.sun_path)) { 78 return PosixError(EINVAL, 79 "Unable to generate a temp path of appropriate length"); 80 } 81 82 if (abstract) { 83 // Indicate that the path is in the abstract namespace. 84 path[0] = 0; 85 } 86 memcpy(addr.sun_path, path.c_str(), path.length()); 87 addr.sun_family = domain; 88 return addr; 89 } 90 91 Creator<SocketPair> AcceptBindSocketPairCreator(bool abstract, int domain, 92 int type, int protocol) { 93 return [=]() -> PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> { 94 ASSIGN_OR_RETURN_ERRNO(struct sockaddr_un bind_addr, 95 UniqueUnixAddr(abstract, domain)); 96 ASSIGN_OR_RETURN_ERRNO(struct sockaddr_un extra_addr, 97 UniqueUnixAddr(abstract, domain)); 98 99 ASSIGN_OR_RETURN_ERRNO(auto bound, Socket(domain, type, protocol)); 100 MaybeSave(); // Successful socket creation. 101 RETURN_ERROR_IF_SYSCALL_FAIL( 102 bind(bound.get(), AsSockAddr(&bind_addr), sizeof(bind_addr))); 103 MaybeSave(); // Successful bind. 104 RETURN_ERROR_IF_SYSCALL_FAIL(listen( 105 bound.get(), /* backlog = */ 5)); // NOLINT(bugprone-argument-comment) 106 MaybeSave(); // Successful listen. 107 108 ASSIGN_OR_RETURN_ERRNO(auto connected, Socket(domain, type, protocol)); 109 MaybeSave(); // Successful socket creation. 110 RETURN_ERROR_IF_SYSCALL_FAIL( 111 connect(connected.get(), AsSockAddr(&bind_addr), sizeof(bind_addr))); 112 MaybeSave(); // Successful connect. 113 114 ASSIGN_OR_RETURN_ERRNO(auto accepted, 115 Accept4(bound.get(), nullptr, nullptr, 116 type & (SOCK_NONBLOCK | SOCK_CLOEXEC))); 117 MaybeSave(); // Successful connect. 118 119 // Cleanup no longer needed resources. 120 RETURN_ERROR_IF_SYSCALL_FAIL(close(bound.release())); 121 MaybeSave(); // Dropped original socket. 122 123 // Only unlink if path is not in abstract namespace. 124 if (bind_addr.sun_path[0] != 0) { 125 RETURN_ERROR_IF_SYSCALL_FAIL(unlink(bind_addr.sun_path)); 126 MaybeSave(); // Unlinked path. 127 } 128 129 // accepted is before connected to destruct connected before accepted. 130 // Destructors for nonstatic member objects are called in the reverse order 131 // in which they appear in the class declaration. 132 return std::make_unique<AddrFDSocketPair>( 133 std::move(accepted), std::move(connected), bind_addr, extra_addr); 134 }; 135 } 136 137 Creator<SocketPair> FilesystemAcceptBindSocketPairCreator(int domain, int type, 138 int protocol) { 139 return AcceptBindSocketPairCreator(/* abstract= */ false, domain, type, 140 protocol); 141 } 142 143 Creator<SocketPair> AbstractAcceptBindSocketPairCreator(int domain, int type, 144 int protocol) { 145 return AcceptBindSocketPairCreator(/* abstract= */ true, domain, type, 146 protocol); 147 } 148 149 Creator<SocketPair> BidirectionalBindSocketPairCreator(bool abstract, 150 int domain, int type, 151 int protocol) { 152 return [=]() -> PosixErrorOr<std::unique_ptr<FDSocketPair>> { 153 ASSIGN_OR_RETURN_ERRNO(struct sockaddr_un addr1, 154 UniqueUnixAddr(abstract, domain)); 155 ASSIGN_OR_RETURN_ERRNO(struct sockaddr_un addr2, 156 UniqueUnixAddr(abstract, domain)); 157 158 ASSIGN_OR_RETURN_ERRNO(auto sock1, Socket(domain, type, protocol)); 159 MaybeSave(); // Successful socket creation. 160 RETURN_ERROR_IF_SYSCALL_FAIL( 161 bind(sock1.get(), AsSockAddr(&addr1), sizeof(addr1))); 162 MaybeSave(); // Successful bind. 163 164 ASSIGN_OR_RETURN_ERRNO(auto sock2, Socket(domain, type, protocol)); 165 MaybeSave(); // Successful socket creation. 166 RETURN_ERROR_IF_SYSCALL_FAIL( 167 bind(sock2.get(), AsSockAddr(&addr2), sizeof(addr2))); 168 MaybeSave(); // Successful bind. 169 170 RETURN_ERROR_IF_SYSCALL_FAIL( 171 connect(sock1.get(), AsSockAddr(&addr2), sizeof(addr2))); 172 MaybeSave(); // Successful connect. 173 174 RETURN_ERROR_IF_SYSCALL_FAIL( 175 connect(sock2.get(), AsSockAddr(&addr1), sizeof(addr1))); 176 MaybeSave(); // Successful connect. 177 178 // Cleanup no longer needed resources. 179 180 // Only unlink if path is not in abstract namespace. 181 if (addr1.sun_path[0] != 0) { 182 RETURN_ERROR_IF_SYSCALL_FAIL(unlink(addr1.sun_path)); 183 MaybeSave(); // Successful unlink. 184 } 185 186 // Only unlink if path is not in abstract namespace. 187 if (addr2.sun_path[0] != 0) { 188 RETURN_ERROR_IF_SYSCALL_FAIL(unlink(addr2.sun_path)); 189 MaybeSave(); // Successful unlink. 190 } 191 192 return std::make_unique<FDSocketPair>(std::move(sock1), std::move(sock2)); 193 }; 194 } 195 196 Creator<SocketPair> FilesystemBidirectionalBindSocketPairCreator(int domain, 197 int type, 198 int protocol) { 199 return BidirectionalBindSocketPairCreator(/* abstract= */ false, domain, type, 200 protocol); 201 } 202 203 Creator<SocketPair> AbstractBidirectionalBindSocketPairCreator(int domain, 204 int type, 205 int protocol) { 206 return BidirectionalBindSocketPairCreator(/* abstract= */ true, domain, type, 207 protocol); 208 } 209 210 Creator<SocketPair> SocketpairGoferSocketPairCreator(int domain, int type, 211 int protocol) { 212 return [=]() -> PosixErrorOr<std::unique_ptr<FDSocketPair>> { 213 struct sockaddr_un addr = {}; 214 constexpr char kSocketGoferPath[] = "/socket"; 215 memcpy(addr.sun_path, kSocketGoferPath, sizeof(kSocketGoferPath)); 216 addr.sun_family = domain; 217 218 ASSIGN_OR_RETURN_ERRNO(auto sock1, Socket(domain, type, protocol)); 219 MaybeSave(); // Successful socket creation. 220 RETURN_ERROR_IF_SYSCALL_FAIL( 221 connect(sock1.get(), AsSockAddr(&addr), sizeof(addr))); 222 MaybeSave(); // Successful connect. 223 224 ASSIGN_OR_RETURN_ERRNO(auto sock2, Socket(domain, type, protocol)); 225 MaybeSave(); // Successful socket creation. 226 RETURN_ERROR_IF_SYSCALL_FAIL( 227 connect(sock2.get(), AsSockAddr(&addr), sizeof(addr))); 228 MaybeSave(); // Successful connect. 229 230 // Make and close another socketpair to ensure that the duped ends of the 231 // first socketpair get closed. 232 // 233 // The problem is that there is no way to atomically send and close an FD. 234 // The closest that we can do is send and then immediately close the FD, 235 // which is what we do in the gofer. The gofer won't respond to another 236 // request until the reply is sent and the FD is closed, so forcing the 237 // gofer to handle another request will ensure that this has happened. 238 for (int i = 0; i < 2; i++) { 239 int sock; 240 RETURN_ERROR_IF_SYSCALL_FAIL(sock = socket(domain, type, protocol)); 241 RETURN_ERROR_IF_SYSCALL_FAIL( 242 connect(sock, AsSockAddr(&addr), sizeof(addr))); 243 RETURN_ERROR_IF_SYSCALL_FAIL(close(sock)); 244 } 245 246 return std::make_unique<FDSocketPair>(std::move(sock1), std::move(sock2)); 247 }; 248 } 249 250 Creator<SocketPair> SocketpairGoferFileSocketPairCreator(int flags) { 251 return [=]() -> PosixErrorOr<std::unique_ptr<FDSocketPair>> { 252 constexpr char kSocketGoferPath[] = "/socket"; 253 254 FileDescriptor sock1; 255 { 256 int sock1_fd; 257 RETURN_ERROR_IF_SYSCALL_FAIL(sock1_fd = 258 open(kSocketGoferPath, O_RDWR | flags)); 259 MaybeSave(); // Successful socket creation. 260 sock1.reset(sock1_fd); 261 } 262 263 FileDescriptor sock2; 264 { 265 int sock2_fd; 266 RETURN_ERROR_IF_SYSCALL_FAIL(sock2_fd = 267 open(kSocketGoferPath, O_RDWR | flags)); 268 MaybeSave(); // Successful socket creation. 269 sock2.reset(sock2_fd); 270 } 271 272 return std::make_unique<FDSocketPair>(std::move(sock1), std::move(sock2)); 273 }; 274 } 275 276 Creator<SocketPair> UnboundSocketPairCreator(bool abstract, int domain, 277 int type, int protocol) { 278 return [=]() -> PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> { 279 ASSIGN_OR_RETURN_ERRNO(struct sockaddr_un addr1, 280 UniqueUnixAddr(abstract, domain)); 281 ASSIGN_OR_RETURN_ERRNO(struct sockaddr_un addr2, 282 UniqueUnixAddr(abstract, domain)); 283 284 ASSIGN_OR_RETURN_ERRNO(auto sock1, Socket(domain, type, protocol)); 285 MaybeSave(); // Successful socket creation. 286 ASSIGN_OR_RETURN_ERRNO(auto sock2, Socket(domain, type, protocol)); 287 MaybeSave(); // Successful socket creation. 288 return std::make_unique<AddrFDSocketPair>(std::move(sock1), 289 std::move(sock2), addr1, addr2); 290 }; 291 } 292 293 Creator<SocketPair> FilesystemUnboundSocketPairCreator(int domain, int type, 294 int protocol) { 295 return UnboundSocketPairCreator(/* abstract= */ false, domain, type, 296 protocol); 297 } 298 299 Creator<SocketPair> AbstractUnboundSocketPairCreator(int domain, int type, 300 int protocol) { 301 return UnboundSocketPairCreator(/* abstract= */ true, domain, type, protocol); 302 } 303 304 void LocalhostAddr(struct sockaddr_in* addr, bool dual_stack) { 305 addr->sin_family = AF_INET; 306 addr->sin_port = htons(0); 307 inet_pton(AF_INET, "127.0.0.1", 308 reinterpret_cast<void*>(&addr->sin_addr.s_addr)); 309 } 310 311 void LocalhostAddr(struct sockaddr_in6* addr, bool dual_stack) { 312 addr->sin6_family = AF_INET6; 313 addr->sin6_port = htons(0); 314 if (dual_stack) { 315 inet_pton(AF_INET6, "::ffff:127.0.0.1", 316 reinterpret_cast<void*>(&addr->sin6_addr.s6_addr)); 317 } else { 318 inet_pton(AF_INET6, "::1", 319 reinterpret_cast<void*>(&addr->sin6_addr.s6_addr)); 320 } 321 addr->sin6_scope_id = 0; 322 } 323 324 template <typename T> 325 PosixErrorOr<T> BindIP(int fd, bool dual_stack) { 326 T addr = {}; 327 LocalhostAddr(&addr, dual_stack); 328 RETURN_ERROR_IF_SYSCALL_FAIL(bind(fd, AsSockAddr(&addr), sizeof(addr))); 329 socklen_t addrlen = sizeof(addr); 330 RETURN_ERROR_IF_SYSCALL_FAIL(getsockname(fd, AsSockAddr(&addr), &addrlen)); 331 return addr; 332 } 333 334 template <typename T> 335 PosixErrorOr<T> TCPBindAndListen(int fd, bool dual_stack) { 336 ASSIGN_OR_RETURN_ERRNO(T addr, BindIP<T>(fd, dual_stack)); 337 RETURN_ERROR_IF_SYSCALL_FAIL( 338 listen(fd, /* backlog = */ 5)); // NOLINT(bugprone-argument-comment) 339 return addr; 340 } 341 342 template <typename T> 343 PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> 344 CreateTCPConnectAcceptSocketPair(int bound, FileDescriptor connected, int type, 345 bool dual_stack, T bind_addr) { 346 int connect_result = 0; 347 RETURN_ERROR_IF_SYSCALL_FAIL( 348 (connect_result = RetryEINTR(connect)( 349 connected.get(), AsSockAddr(&bind_addr), sizeof(bind_addr))) == -1 && 350 errno == EINPROGRESS 351 ? 0 352 : connect_result); 353 MaybeSave(); // Successful connect. 354 355 if (connect_result == -1) { 356 struct pollfd connect_poll = {connected.get(), POLLOUT | POLLERR | POLLHUP, 357 0}; 358 int num_fds; 359 RETURN_ERROR_IF_SYSCALL_FAIL( 360 (num_fds = RetryEINTR(poll)(&connect_poll, 1, -1))); 361 if (num_fds != 1) { 362 return PosixError(ENOTCONN, "connect failed"); 363 } 364 int error = 0; 365 socklen_t errorlen = sizeof(error); 366 RETURN_ERROR_IF_SYSCALL_FAIL( 367 getsockopt(connected.get(), SOL_SOCKET, SO_ERROR, &error, &errorlen)); 368 errno = error; 369 RETURN_ERROR_IF_SYSCALL_FAIL( 370 /* connect */ error == 0 ? 0 : -1); 371 } 372 373 int accepted_fd = -1; 374 struct pollfd accept_poll = {bound, POLLIN, 0}; 375 while (accepted_fd == -1) { 376 RETURN_ERROR_IF_SYSCALL_FAIL(RetryEINTR(poll)(&accept_poll, 1, 0)); 377 378 RETURN_ERROR_IF_SYSCALL_FAIL( 379 (accepted_fd = RetryEINTR(accept4)( 380 bound, nullptr, nullptr, type & (SOCK_NONBLOCK | SOCK_CLOEXEC))) == 381 -1 && 382 errno == EAGAIN 383 ? 0 384 : accepted_fd); 385 } 386 FileDescriptor accepted(accepted_fd); 387 MaybeSave(); // Successful accept. 388 389 T extra_addr = {}; 390 LocalhostAddr(&extra_addr, dual_stack); 391 return std::make_unique<AddrFDSocketPair>( 392 std::move(connected), std::move(accepted), bind_addr, extra_addr); 393 } 394 395 template <typename T> 396 PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> CreateTCPAcceptBindSocketPair( 397 FileDescriptor bound, FileDescriptor connected, int type, bool dual_stack) { 398 ASSIGN_OR_RETURN_ERRNO(T bind_addr, 399 TCPBindAndListen<T>(bound.get(), dual_stack)); 400 401 auto result = CreateTCPConnectAcceptSocketPair( 402 bound.get(), std::move(connected), type, dual_stack, bind_addr); 403 404 // Cleanup no longer needed resources. 405 RETURN_ERROR_IF_SYSCALL_FAIL(close(bound.release())); 406 MaybeSave(); // Successful close. 407 408 return result; 409 } 410 411 Creator<SocketPair> TCPAcceptBindSocketPairCreator(int domain, int type, 412 int protocol, 413 bool dual_stack) { 414 return [=]() -> PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> { 415 ASSIGN_OR_RETURN_ERRNO(auto bound, Socket(domain, type, protocol)); 416 MaybeSave(); // Successful socket creation. 417 418 ASSIGN_OR_RETURN_ERRNO(auto connected, Socket(domain, type, protocol)); 419 MaybeSave(); // Successful socket creation. 420 421 if (domain == AF_INET) { 422 return CreateTCPAcceptBindSocketPair<sockaddr_in>( 423 std::move(bound), std::move(connected), type, dual_stack); 424 } 425 return CreateTCPAcceptBindSocketPair<sockaddr_in6>( 426 std::move(bound), std::move(connected), type, dual_stack); 427 }; 428 } 429 430 Creator<SocketPair> TCPAcceptBindPersistentListenerSocketPairCreator( 431 int domain, int type, int protocol, bool dual_stack) { 432 // These are lazily initialized below, on the first call to the returned 433 // lambda. These values are private to each returned lambda, but shared across 434 // invocations of a specific lambda. 435 // 436 // The sharing allows pairs created with the same parameters to share a 437 // listener. This prevents future connects from failing if the connecting 438 // socket selects a port which had previously been used by a listening socket 439 // that still has some connections in TIME-WAIT. 440 // 441 // The lazy initialization is to avoid creating sockets during parameter 442 // enumeration. This is important because parameters are enumerated during the 443 // build process where networking may not be available. 444 auto listener = std::make_shared<absl::optional<int>>(absl::optional<int>()); 445 auto addr4 = std::make_shared<absl::optional<sockaddr_in>>( 446 absl::optional<sockaddr_in>()); 447 auto addr6 = std::make_shared<absl::optional<sockaddr_in6>>( 448 absl::optional<sockaddr_in6>()); 449 450 return [=]() -> PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> { 451 ASSIGN_OR_RETURN_ERRNO(auto connected, Socket(domain, type, protocol)); 452 MaybeSave(); // Successful socket creation. 453 454 // Share the listener across invocations. 455 if (!listener->has_value()) { 456 int fd = socket(domain, type, protocol); 457 if (fd < 0) { 458 return PosixError(errno, absl::StrCat("socket(", domain, ", ", type, 459 ", ", protocol, ")")); 460 } 461 listener->emplace(fd); 462 MaybeSave(); // Successful socket creation. 463 } 464 465 // Bind the listener once, but create a new connect/accept pair each 466 // time. 467 if (domain == AF_INET) { 468 if (!addr4->has_value()) { 469 addr4->emplace( 470 TCPBindAndListen<sockaddr_in>(listener->value(), dual_stack) 471 .ValueOrDie()); 472 } 473 return CreateTCPConnectAcceptSocketPair(listener->value(), 474 std::move(connected), type, 475 dual_stack, addr4->value()); 476 } 477 if (!addr6->has_value()) { 478 addr6->emplace( 479 TCPBindAndListen<sockaddr_in6>(listener->value(), dual_stack) 480 .ValueOrDie()); 481 } 482 return CreateTCPConnectAcceptSocketPair(listener->value(), 483 std::move(connected), type, 484 dual_stack, addr6->value()); 485 }; 486 } 487 488 template <typename T> 489 PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> CreateUDPBoundSocketPair( 490 FileDescriptor sock1, FileDescriptor sock2, int type, bool dual_stack) { 491 ASSIGN_OR_RETURN_ERRNO(T addr1, BindIP<T>(sock1.get(), dual_stack)); 492 ASSIGN_OR_RETURN_ERRNO(T addr2, BindIP<T>(sock2.get(), dual_stack)); 493 494 return std::make_unique<AddrFDSocketPair>(std::move(sock1), std::move(sock2), 495 addr1, addr2); 496 } 497 498 template <typename T> 499 PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> 500 CreateUDPBidirectionalBindSocketPair(FileDescriptor sock1, FileDescriptor sock2, 501 int type, bool dual_stack) { 502 ASSIGN_OR_RETURN_ERRNO( 503 auto socks, CreateUDPBoundSocketPair<T>( 504 std::move(sock1), std::move(sock2), type, dual_stack)); 505 506 // Connect sock1 to sock2. 507 RETURN_ERROR_IF_SYSCALL_FAIL(connect(socks->first_fd(), socks->second_addr(), 508 socks->second_addr_size())); 509 MaybeSave(); // Successful connection. 510 511 // Connect sock2 to sock1. 512 RETURN_ERROR_IF_SYSCALL_FAIL(connect(socks->second_fd(), socks->first_addr(), 513 socks->first_addr_size())); 514 MaybeSave(); // Successful connection. 515 516 return socks; 517 } 518 519 Creator<SocketPair> UDPBidirectionalBindSocketPairCreator(int domain, int type, 520 int protocol, 521 bool dual_stack) { 522 return [=]() -> PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> { 523 ASSIGN_OR_RETURN_ERRNO(auto sock1, Socket(domain, type, protocol)); 524 MaybeSave(); // Successful socket creation. 525 526 ASSIGN_OR_RETURN_ERRNO(auto sock2, Socket(domain, type, protocol)); 527 MaybeSave(); // Successful socket creation. 528 529 if (domain == AF_INET) { 530 return CreateUDPBidirectionalBindSocketPair<sockaddr_in>( 531 std::move(sock1), std::move(sock2), type, dual_stack); 532 } 533 return CreateUDPBidirectionalBindSocketPair<sockaddr_in6>( 534 std::move(sock1), std::move(sock2), type, dual_stack); 535 }; 536 } 537 538 Creator<SocketPair> UDPUnboundSocketPairCreator(int domain, int type, 539 int protocol, bool dual_stack) { 540 return [=]() -> PosixErrorOr<std::unique_ptr<FDSocketPair>> { 541 ASSIGN_OR_RETURN_ERRNO(auto sock1, Socket(domain, type, protocol)); 542 MaybeSave(); // Successful socket creation. 543 544 ASSIGN_OR_RETURN_ERRNO(auto sock2, Socket(domain, type, protocol)); 545 MaybeSave(); // Successful socket creation. 546 547 return std::make_unique<FDSocketPair>(std::move(sock1), std::move(sock2)); 548 }; 549 } 550 551 SocketPairKind Reversed(SocketPairKind const& base) { 552 auto const& creator = base.creator; 553 return SocketPairKind{ 554 absl::StrCat("reversed ", base.description), base.domain, base.type, 555 base.protocol, 556 [creator]() -> PosixErrorOr<std::unique_ptr<ReversedSocketPair>> { 557 ASSIGN_OR_RETURN_ERRNO(auto creator_value, creator()); 558 return std::make_unique<ReversedSocketPair>(std::move(creator_value)); 559 }}; 560 } 561 562 Creator<FileDescriptor> UnboundSocketCreator(int domain, int type, 563 int protocol) { 564 return [=]() -> PosixErrorOr<std::unique_ptr<FileDescriptor>> { 565 int sock; 566 RETURN_ERROR_IF_SYSCALL_FAIL(sock = socket(domain, type, protocol)); 567 MaybeSave(); // Successful socket creation. 568 569 return std::make_unique<FileDescriptor>(sock); 570 }; 571 } 572 573 std::vector<SocketPairKind> IncludeReversals(std::vector<SocketPairKind> vec) { 574 return ApplyVecToVec<SocketPairKind>(std::vector<Middleware>{NoOp, Reversed}, 575 vec); 576 } 577 578 SocketPairKind NoOp(SocketPairKind const& base) { return base; } 579 580 void TransferTest(int fd1, int fd2) { 581 char buf1[20]; 582 RandomizeBuffer(buf1, sizeof(buf1)); 583 ASSERT_THAT(WriteFd(fd1, buf1, sizeof(buf1)), 584 SyscallSucceedsWithValue(sizeof(buf1))); 585 586 char buf2[20]; 587 ASSERT_THAT(ReadFd(fd2, buf2, sizeof(buf2)), 588 SyscallSucceedsWithValue(sizeof(buf2))); 589 590 EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1))); 591 592 RandomizeBuffer(buf1, sizeof(buf1)); 593 ASSERT_THAT(WriteFd(fd2, buf1, sizeof(buf1)), 594 SyscallSucceedsWithValue(sizeof(buf1))); 595 596 ASSERT_THAT(ReadFd(fd1, buf2, sizeof(buf2)), 597 SyscallSucceedsWithValue(sizeof(buf2))); 598 599 EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1))); 600 } 601 602 size_t CalculateUnixSockAddrLen(const char* sun_path) { 603 // Abstract addresses always return the full length. 604 if (sun_path[0] == 0) { 605 return sizeof(sockaddr_un); 606 } 607 // Filesystem addresses use the address length plus the 2 byte sun_family 608 // and null terminator. 609 return strlen(sun_path) + 3; 610 } 611 612 struct sockaddr_storage AddrFDSocketPair::to_storage(const sockaddr_un& addr) { 613 struct sockaddr_storage addr_storage = {}; 614 memcpy(&addr_storage, &addr, sizeof(addr)); 615 return addr_storage; 616 } 617 618 struct sockaddr_storage AddrFDSocketPair::to_storage(const sockaddr_in& addr) { 619 struct sockaddr_storage addr_storage = {}; 620 memcpy(&addr_storage, &addr, sizeof(addr)); 621 return addr_storage; 622 } 623 624 struct sockaddr_storage AddrFDSocketPair::to_storage(const sockaddr_in6& addr) { 625 struct sockaddr_storage addr_storage = {}; 626 memcpy(&addr_storage, &addr, sizeof(addr)); 627 return addr_storage; 628 } 629 630 SocketKind SimpleSocket(int fam, int type, int proto) { 631 return SocketKind{ 632 absl::StrCat("Family ", fam, ", type ", type, ", proto ", proto), fam, 633 type, proto, SyscallSocketCreator(fam, type, proto)}; 634 } 635 636 ssize_t SendLargeSendMsg(const std::unique_ptr<SocketPair>& sockets, 637 size_t size, bool reader) { 638 const int rfd = sockets->second_fd(); 639 ScopedThread t([rfd, size, reader] { 640 if (!reader) { 641 return; 642 } 643 644 // Potentially too many syscalls in the loop. 645 const DisableSave ds; 646 647 std::vector<char> buf(size); 648 size_t total = 0; 649 650 while (total < size) { 651 int ret = read(rfd, buf.data(), buf.size()); 652 if (ret == -1 && errno == EAGAIN) { 653 continue; 654 } 655 if (ret > 0) { 656 total += ret; 657 } 658 659 // Assert to return on first failure. 660 ASSERT_THAT(ret, SyscallSucceeds()); 661 } 662 }); 663 664 std::vector<char> buf(size); 665 666 struct iovec iov = {}; 667 iov.iov_base = buf.data(); 668 iov.iov_len = buf.size(); 669 670 struct msghdr msg = {}; 671 msg.msg_iov = &iov; 672 msg.msg_iovlen = 1; 673 674 return RetryEINTR(sendmsg)(sockets->first_fd(), &msg, 0); 675 } 676 677 namespace internal { 678 PosixErrorOr<int> TryPortAvailable(int port, AddressFamily family, 679 SocketType type, bool reuse_addr) { 680 if (port < 0) { 681 return PosixError(EINVAL, "Invalid port"); 682 } 683 684 // Both Ipv6 and Dualstack are AF_INET6. 685 int sock_fam = (family == AddressFamily::kIpv4 ? AF_INET : AF_INET6); 686 int sock_type = (type == SocketType::kTcp ? SOCK_STREAM : SOCK_DGRAM); 687 ASSIGN_OR_RETURN_ERRNO(auto fd, Socket(sock_fam, sock_type, 0)); 688 689 if (reuse_addr) { 690 int one = 1; 691 RETURN_ERROR_IF_SYSCALL_FAIL( 692 setsockopt(fd.get(), SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))); 693 } 694 695 // Try to bind. 696 sockaddr_storage storage = {}; 697 int storage_size = 0; 698 if (family == AddressFamily::kIpv4) { 699 sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(&storage); 700 storage_size = sizeof(*addr); 701 addr->sin_family = AF_INET; 702 addr->sin_port = htons(port); 703 addr->sin_addr.s_addr = htonl(INADDR_ANY); 704 } else { 705 sockaddr_in6* addr = reinterpret_cast<sockaddr_in6*>(&storage); 706 storage_size = sizeof(*addr); 707 addr->sin6_family = AF_INET6; 708 addr->sin6_port = htons(port); 709 if (family == AddressFamily::kDualStack) { 710 inet_pton(AF_INET6, "::ffff:0.0.0.0", 711 reinterpret_cast<void*>(&addr->sin6_addr.s6_addr)); 712 } else { 713 addr->sin6_addr = in6addr_any; 714 } 715 } 716 717 RETURN_ERROR_IF_SYSCALL_FAIL( 718 bind(fd.get(), AsSockAddr(&storage), storage_size)); 719 720 // If the user specified 0 as the port, we will return the port that the 721 // kernel gave us, otherwise we will validate that this socket bound to the 722 // requested port. 723 sockaddr_storage bound_storage = {}; 724 socklen_t bound_storage_size = sizeof(bound_storage); 725 RETURN_ERROR_IF_SYSCALL_FAIL( 726 getsockname(fd.get(), AsSockAddr(&bound_storage), &bound_storage_size)); 727 728 int available_port = -1; 729 if (bound_storage.ss_family == AF_INET) { 730 sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(&bound_storage); 731 available_port = ntohs(addr->sin_port); 732 } else if (bound_storage.ss_family == AF_INET6) { 733 sockaddr_in6* addr = reinterpret_cast<sockaddr_in6*>(&bound_storage); 734 available_port = ntohs(addr->sin6_port); 735 } else { 736 return PosixError(EPROTOTYPE, "Getsockname returned invalid family"); 737 } 738 739 // If we requested a specific port make sure our bound port is that port. 740 if (port != 0 && available_port != port) { 741 return PosixError(EINVAL, 742 absl::StrCat("Bound port ", available_port, 743 " was not equal to requested port ", port)); 744 } 745 746 // If we're trying to do a TCP socket, let's also try to listen. 747 if (type == SocketType::kTcp) { 748 RETURN_ERROR_IF_SYSCALL_FAIL(listen(fd.get(), 1)); 749 } 750 751 return available_port; 752 } 753 } // namespace internal 754 755 PosixErrorOr<int> SendMsg(int sock, msghdr* msg, char buf[], int buf_size) { 756 struct iovec iov; 757 iov.iov_base = buf; 758 iov.iov_len = buf_size; 759 msg->msg_iov = &iov; 760 msg->msg_iovlen = 1; 761 762 int ret; 763 RETURN_ERROR_IF_SYSCALL_FAIL(ret = RetryEINTR(sendmsg)(sock, msg, 0)); 764 return ret; 765 } 766 767 PosixErrorOr<int> RecvTimeout(int sock, char buf[], int buf_size, int timeout) { 768 fd_set rfd; 769 struct timeval to = {.tv_sec = timeout, .tv_usec = 0}; 770 struct timeval* to_ptr = timeout < 0 ? nullptr : &to; 771 FD_ZERO(&rfd); 772 FD_SET(sock, &rfd); 773 int ret; 774 RETURN_ERROR_IF_SYSCALL_FAIL(ret = 775 select(sock + 1, &rfd, NULL, NULL, to_ptr)); 776 RETURN_ERROR_IF_SYSCALL_FAIL( 777 ret = RetryEINTR(recv)(sock, buf, buf_size, MSG_DONTWAIT)); 778 return ret; 779 } 780 781 PosixErrorOr<int> RecvMsgTimeout(int sock, struct msghdr* msg, int timeout) { 782 fd_set rfd; 783 struct timeval to = {.tv_sec = timeout, .tv_usec = 0}; 784 struct timeval* to_ptr = timeout < 0 ? nullptr : &to; 785 FD_ZERO(&rfd); 786 FD_SET(sock, &rfd); 787 788 int ret; 789 RETURN_ERROR_IF_SYSCALL_FAIL(ret = 790 select(sock + 1, &rfd, NULL, NULL, to_ptr)); 791 RETURN_ERROR_IF_SYSCALL_FAIL( 792 ret = RetryEINTR(recvmsg)(sock, msg, MSG_DONTWAIT)); 793 return ret; 794 } 795 796 void RecvNoData(int sock) { 797 char data = 0; 798 struct iovec iov; 799 iov.iov_base = &data; 800 iov.iov_len = 1; 801 struct msghdr msg = {}; 802 msg.msg_iov = &iov; 803 msg.msg_iovlen = 1; 804 ASSERT_THAT(RetryEINTR(recvmsg)(sock, &msg, MSG_DONTWAIT), 805 SyscallFailsWithErrno(EAGAIN)); 806 } 807 808 TestAddress TestAddress::WithPort(uint16_t port) const { 809 TestAddress addr = *this; 810 switch (addr.family()) { 811 case AF_INET: 812 reinterpret_cast<sockaddr_in*>(&addr.addr)->sin_port = htons(port); 813 break; 814 case AF_INET6: 815 reinterpret_cast<sockaddr_in6*>(&addr.addr)->sin6_port = htons(port); 816 break; 817 } 818 return addr; 819 } 820 821 namespace { 822 823 TestAddress V4Addr(std::string description, in_addr_t addr) { 824 TestAddress t(std::move(description)); 825 t.addr.ss_family = AF_INET; 826 t.addr_len = sizeof(sockaddr_in); 827 reinterpret_cast<sockaddr_in*>(&t.addr)->sin_addr.s_addr = addr; 828 return t; 829 } 830 831 TestAddress V6Addr(std::string description, const in6_addr& addr) { 832 TestAddress t(std::move(description)); 833 t.addr.ss_family = AF_INET6; 834 t.addr_len = sizeof(sockaddr_in6); 835 reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr = addr; 836 return t; 837 } 838 839 } // namespace 840 841 TestAddress V4AddrStr(std::string description, const char* addr) { 842 in_addr_t s_addr; 843 inet_pton(AF_INET, addr, &s_addr); 844 return V4Addr(description, s_addr); 845 } 846 847 TestAddress V6AddrStr(std::string description, const char* addr) { 848 struct in6_addr s_addr; 849 inet_pton(AF_INET6, addr, &s_addr); 850 return V6Addr(description, s_addr); 851 } 852 853 TestAddress V4Any() { return V4Addr("V4Any", htonl(INADDR_ANY)); } 854 855 TestAddress V4Broadcast() { 856 return V4Addr("V4Broadcast", htonl(INADDR_BROADCAST)); 857 } 858 859 TestAddress V4Loopback() { 860 return V4Addr("V4Loopback", htonl(INADDR_LOOPBACK)); 861 } 862 863 TestAddress V4LoopbackSubnetBroadcast() { 864 return V4AddrStr("V4LoopbackSubnetBroadcast", "127.255.255.255"); 865 } 866 867 TestAddress V4MappedAny() { return V6AddrStr("V4MappedAny", "::ffff:0.0.0.0"); } 868 869 TestAddress V4MappedLoopback() { 870 return V6AddrStr("V4MappedLoopback", "::ffff:127.0.0.1"); 871 } 872 873 TestAddress V4Multicast() { 874 return V4Addr("V4Multicast", inet_addr(kMulticastAddress)); 875 } 876 877 TestAddress V4MulticastAllHosts() { 878 return V4Addr("V4MulticastAllHosts", htonl(INADDR_ALLHOSTS_GROUP)); 879 } 880 881 TestAddress V6Any() { return V6Addr("V6Any", in6addr_any); } 882 883 TestAddress V6Loopback() { return V6Addr("V6Loopback", in6addr_loopback); } 884 885 TestAddress V6Multicast() { return V6AddrStr("V6Multicast", "ff05::1234"); } 886 887 TestAddress V6MulticastInterfaceLocalAllNodes() { 888 return V6AddrStr("V6MulticastInterfaceLocalAllNodes", "ff01::1"); 889 } 890 891 TestAddress V6MulticastLinkLocalAllNodes() { 892 return V6AddrStr("V6MulticastLinkLocalAllNodes", "ff02::1"); 893 } 894 895 TestAddress V6MulticastLinkLocalAllRouters() { 896 return V6AddrStr("V6MulticastLinkLocalAllRouters", "ff02::2"); 897 } 898 899 // Checksum computes the internet checksum of a buffer. 900 uint16_t Checksum(uint16_t* buf, ssize_t buf_size) { 901 // Add up the 16-bit values in the buffer. 902 uint32_t total = 0; 903 for (unsigned int i = 0; i < buf_size; i += sizeof(*buf)) { 904 total += *buf; 905 buf++; 906 } 907 908 // If buf has an odd size, add the remaining byte. 909 if (buf_size % 2) { 910 total += *(reinterpret_cast<unsigned char*>(buf) - 1); 911 } 912 913 // This carries any bits past the lower 16 until everything fits in 16 bits. 914 while (total >> 16) { 915 uint16_t lower = total & 0xffff; 916 uint16_t upper = total >> 16; 917 total = lower + upper; 918 } 919 920 return ~total; 921 } 922 923 uint16_t IPChecksum(struct iphdr ip) { 924 return Checksum(reinterpret_cast<uint16_t*>(&ip), sizeof(ip)); 925 } 926 927 // The pseudo-header defined in RFC 768 for calculating the UDP checksum. 928 struct udp_pseudo_hdr { 929 uint32_t srcip; 930 uint32_t destip; 931 char zero; 932 char protocol; 933 uint16_t udplen; 934 }; 935 936 static_assert(sizeof(udp_pseudo_hdr) == 12); 937 938 uint16_t UDPChecksum(struct iphdr iphdr, struct udphdr udphdr, 939 const char* payload, ssize_t payload_len) { 940 struct udp_pseudo_hdr phdr = {}; 941 phdr.srcip = iphdr.saddr; 942 phdr.destip = iphdr.daddr; 943 phdr.zero = 0; 944 phdr.protocol = IPPROTO_UDP; 945 phdr.udplen = udphdr.len; 946 947 ssize_t buf_size = sizeof(phdr) + sizeof(udphdr) + payload_len; 948 char* buf = static_cast<char*>(malloc(buf_size)); 949 memcpy(buf, &phdr, sizeof(phdr)); 950 memcpy(buf + sizeof(phdr), &udphdr, sizeof(udphdr)); 951 memcpy(buf + sizeof(phdr) + sizeof(udphdr), payload, payload_len); 952 953 uint16_t csum = Checksum(reinterpret_cast<uint16_t*>(buf), buf_size); 954 free(buf); 955 return csum; 956 } 957 958 // IPv6 pseudo-header for UDP checksum calculation. 959 struct udpv6_pseudo_hdr { 960 in6_addr srcip; 961 in6_addr destip; 962 char zero; 963 char protocol; 964 uint16_t udplen; 965 }; 966 static_assert(sizeof(udpv6_pseudo_hdr) == 36); 967 968 uint16_t UDPChecksum(struct ip6_hdr iphdr, struct udphdr udphdr, 969 const char* payload, ssize_t payload_len) { 970 struct udpv6_pseudo_hdr phdr = {}; 971 phdr.srcip = iphdr.ip6_src; 972 phdr.destip = iphdr.ip6_dst; 973 phdr.zero = 0; 974 phdr.protocol = IPPROTO_UDP; 975 phdr.udplen = udphdr.len; 976 977 ssize_t buf_size = sizeof(phdr) + sizeof(udphdr) + payload_len; 978 char* buf = static_cast<char*>(malloc(buf_size)); 979 memcpy(buf, &phdr, sizeof(phdr)); 980 memcpy(buf + sizeof(phdr), &udphdr, sizeof(udphdr)); 981 memcpy(buf + sizeof(phdr) + sizeof(udphdr), payload, payload_len); 982 983 uint16_t csum = Checksum(reinterpret_cast<uint16_t*>(buf), buf_size); 984 free(buf); 985 return csum; 986 } 987 988 uint16_t ICMPChecksum(struct icmphdr icmphdr, const char* payload, 989 ssize_t payload_len) { 990 ssize_t buf_size = sizeof(icmphdr) + payload_len; 991 char* buf = static_cast<char*>(malloc(buf_size)); 992 memcpy(buf, &icmphdr, sizeof(icmphdr)); 993 memcpy(buf + sizeof(icmphdr), payload, payload_len); 994 995 uint16_t csum = Checksum(reinterpret_cast<uint16_t*>(buf), buf_size); 996 free(buf); 997 return csum; 998 } 999 1000 PosixErrorOr<uint16_t> AddrPort(int family, sockaddr_storage const& addr) { 1001 switch (family) { 1002 case AF_INET: 1003 return static_cast<uint16_t>( 1004 reinterpret_cast<sockaddr_in const*>(&addr)->sin_port); 1005 case AF_INET6: 1006 return static_cast<uint16_t>( 1007 reinterpret_cast<sockaddr_in6 const*>(&addr)->sin6_port); 1008 default: 1009 return PosixError(EINVAL, 1010 absl::StrCat("unknown socket family: ", family)); 1011 } 1012 } 1013 1014 PosixError SetAddrPort(int family, sockaddr_storage* addr, uint16_t port) { 1015 switch (family) { 1016 case AF_INET: 1017 reinterpret_cast<sockaddr_in*>(addr)->sin_port = port; 1018 return NoError(); 1019 case AF_INET6: 1020 reinterpret_cast<sockaddr_in6*>(addr)->sin6_port = port; 1021 return NoError(); 1022 default: 1023 return PosixError(EINVAL, 1024 absl::StrCat("unknown socket family: ", family)); 1025 } 1026 } 1027 1028 sockaddr_storage InetLoopbackAddr(int family) { 1029 struct sockaddr_storage addr; 1030 memset(&addr, 0, sizeof(addr)); 1031 AsSockAddr(&addr)->sa_family = family; 1032 1033 if (family == AF_INET) { 1034 auto sin = reinterpret_cast<struct sockaddr_in*>(&addr); 1035 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 1036 sin->sin_port = htons(0); 1037 return addr; 1038 } 1039 auto sin6 = reinterpret_cast<struct sockaddr_in6*>(&addr); 1040 sin6->sin6_addr = in6addr_loopback; 1041 sin6->sin6_port = htons(0); 1042 return addr; 1043 } 1044 1045 void SetupTimeWaitClose(const TestAddress* listener, 1046 const TestAddress* connector, bool reuse, 1047 bool accept_close, sockaddr_storage* listen_addr, 1048 sockaddr_storage* conn_bound_addr) { 1049 // Create the listening socket. 1050 FileDescriptor listen_fd = ASSERT_NO_ERRNO_AND_VALUE( 1051 Socket(listener->family(), SOCK_STREAM, IPPROTO_TCP)); 1052 if (reuse) { 1053 ASSERT_THAT(setsockopt(listen_fd.get(), SOL_SOCKET, SO_REUSEADDR, 1054 &kSockOptOn, sizeof(kSockOptOn)), 1055 SyscallSucceeds()); 1056 } 1057 ASSERT_THAT( 1058 bind(listen_fd.get(), AsSockAddr(listen_addr), listener->addr_len), 1059 SyscallSucceeds()); 1060 ASSERT_THAT(listen(listen_fd.get(), SOMAXCONN), SyscallSucceeds()); 1061 1062 // Get the port bound by the listening socket. 1063 socklen_t addrlen = listener->addr_len; 1064 ASSERT_THAT(getsockname(listen_fd.get(), AsSockAddr(listen_addr), &addrlen), 1065 SyscallSucceeds()); 1066 1067 uint16_t const port = 1068 ASSERT_NO_ERRNO_AND_VALUE(AddrPort(listener->family(), *listen_addr)); 1069 1070 // Connect to the listening socket. 1071 FileDescriptor conn_fd = ASSERT_NO_ERRNO_AND_VALUE( 1072 Socket(connector->family(), SOCK_STREAM, IPPROTO_TCP)); 1073 1074 // We disable saves after this point as a S/R causes the netstack seed 1075 // to be regenerated which changes what ports/ISN is picked for a given 1076 // tuple (src ip,src port, dst ip, dst port). This can cause the final 1077 // SYN to use a sequence number that looks like one from the current 1078 // connection in TIME_WAIT and will not be accepted causing the test 1079 // to timeout. 1080 // 1081 // TODO(gvisor.dev/issue/940): S/R portSeed/portHint 1082 DisableSave ds; 1083 1084 sockaddr_storage conn_addr = connector->addr; 1085 ASSERT_NO_ERRNO(SetAddrPort(connector->family(), &conn_addr, port)); 1086 ASSERT_THAT(RetryEINTR(connect)(conn_fd.get(), AsSockAddr(&conn_addr), 1087 connector->addr_len), 1088 SyscallSucceeds()); 1089 1090 // Accept the connection. 1091 auto accepted = 1092 ASSERT_NO_ERRNO_AND_VALUE(Accept(listen_fd.get(), nullptr, nullptr)); 1093 1094 // Get the address/port bound by the connecting socket. 1095 socklen_t conn_addrlen = connector->addr_len; 1096 ASSERT_THAT( 1097 getsockname(conn_fd.get(), AsSockAddr(conn_bound_addr), &conn_addrlen), 1098 SyscallSucceeds()); 1099 1100 FileDescriptor active_closefd, passive_closefd; 1101 if (accept_close) { 1102 active_closefd = std::move(accepted); 1103 passive_closefd = std::move(conn_fd); 1104 } else { 1105 active_closefd = std::move(conn_fd); 1106 passive_closefd = std::move(accepted); 1107 } 1108 1109 // shutdown to trigger TIME_WAIT. 1110 ASSERT_THAT(shutdown(active_closefd.get(), SHUT_WR), SyscallSucceeds()); 1111 { 1112 constexpr int kTimeout = 10000; 1113 pollfd pfd = { 1114 .fd = passive_closefd.get(), 1115 .events = POLLIN, 1116 }; 1117 ASSERT_THAT(poll(&pfd, 1, kTimeout), SyscallSucceedsWithValue(1)); 1118 ASSERT_EQ(pfd.revents, POLLIN); 1119 } 1120 // Send/recv some data to be sure that the fin packet has been acked. 1121 char c = 0; 1122 ASSERT_THAT(send(passive_closefd.get(), &c, 1, 0), 1123 SyscallSucceedsWithValue(sizeof(c))); 1124 ASSERT_THAT(recv(active_closefd.get(), &c, 1, 0), 1125 SyscallSucceedsWithValue(sizeof(c))); 1126 ASSERT_THAT(shutdown(passive_closefd.get(), SHUT_WR), SyscallSucceeds()); 1127 { 1128 constexpr int kTimeout = 10000; 1129 constexpr int16_t want_events = POLLHUP; 1130 pollfd pfd = { 1131 .fd = active_closefd.get(), 1132 .events = want_events, 1133 }; 1134 ASSERT_THAT(poll(&pfd, 1, kTimeout), SyscallSucceedsWithValue(1)); 1135 } 1136 1137 // This sleep is needed to reduce flake to ensure that the passive-close 1138 // ensures the state transitions to CLOSE from LAST_ACK. 1139 absl::SleepFor(absl::Seconds(1)); 1140 } 1141 1142 constexpr char kRangeFile[] = "/proc/sys/net/ipv4/ip_local_port_range"; 1143 1144 PosixErrorOr<int> MaybeLimitEphemeralPorts() { 1145 int min = 0; 1146 int max = 1 << 16; 1147 1148 // Read the ephemeral range from /proc. 1149 ASSIGN_OR_RETURN_ERRNO(std::string rangefile, GetContents(kRangeFile)); 1150 const std::string err_msg = 1151 absl::StrFormat("%s has invalid content: %s", kRangeFile, rangefile); 1152 if (rangefile.back() != '\n') { 1153 return PosixError(EINVAL, err_msg); 1154 } 1155 rangefile.pop_back(); 1156 std::vector<std::string> range = 1157 absl::StrSplit(rangefile, absl::ByAnyChar("\t ")); 1158 if (range.size() < 2 || !absl::SimpleAtoi(range.front(), &min) || 1159 !absl::SimpleAtoi(range.back(), &max)) { 1160 return PosixError(EINVAL, err_msg); 1161 } 1162 1163 // If we can open as writable, limit the range. 1164 if (!access(kRangeFile, W_OK)) { 1165 ASSIGN_OR_RETURN_ERRNO(FileDescriptor fd, 1166 Open(kRangeFile, O_WRONLY | O_TRUNC, 0)); 1167 int newMax = min + 50; 1168 const std::string small_range = absl::StrFormat("%d %d", min, newMax); 1169 int n = write(fd.get(), small_range.c_str(), small_range.size()); 1170 if (n < 0) { 1171 // Hostinet doesn't allow modifying the host port range. And if we're root 1172 // (as we are in some tests), access and open will succeed even if the 1173 // file mode is readonly. 1174 if (errno != EACCES) { 1175 return PosixError( 1176 errno, 1177 absl::StrFormat("write(%d [%s], \"%s\", %d)", fd.get(), kRangeFile, 1178 small_range.c_str(), small_range.size())); 1179 } 1180 } else { 1181 max = newMax; 1182 } 1183 } 1184 return max - min; 1185 } 1186 1187 PosixErrorOr<std::function<PosixError()>> AllowMartianPacketsOnLoopback() { 1188 if (IsRunningOnGvisor()) { 1189 return std::function<PosixError()>([]() { return NoError(); }); 1190 } 1191 1192 constexpr std::array<const char*, 2> files = { 1193 "/proc/sys/net/ipv4/conf/lo/accept_local", 1194 "/proc/sys/net/ipv4/conf/lo/route_localnet", 1195 }; 1196 std::stack<std::pair<const char*, char>> initial_configs; 1197 1198 // Record and update the initial configurations. 1199 PosixError err = [&]() -> PosixError { 1200 for (const char* f : files) { 1201 ASSIGN_OR_RETURN_ERRNO(FileDescriptor fd, Open(f, O_RDWR)); 1202 char initial_config; 1203 RETURN_ERROR_IF_SYSCALL_FAIL( 1204 read(fd.get(), &initial_config, sizeof(initial_config))); 1205 1206 constexpr char kEnabled = '1'; 1207 RETURN_ERROR_IF_SYSCALL_FAIL(lseek(fd.get(), 0, SEEK_SET)); 1208 RETURN_ERROR_IF_SYSCALL_FAIL( 1209 write(fd.get(), &kEnabled, sizeof(kEnabled))); 1210 initial_configs.push(std::make_pair(f, initial_config)); 1211 } 1212 return NoError(); 1213 }(); 1214 1215 // Only define the restore function after we're done updating the config to 1216 // capture the initialized initial_configs std::stack. 1217 std::function<PosixError()> restore = [initial_configs]() mutable { 1218 while (!initial_configs.empty()) { 1219 std::pair<const char*, char> cfg = initial_configs.top(); 1220 initial_configs.pop(); 1221 ASSIGN_OR_RETURN_ERRNO(FileDescriptor fd, Open(cfg.first, O_WRONLY)); 1222 RETURN_ERROR_IF_SYSCALL_FAIL( 1223 write(fd.get(), &cfg.second, sizeof(cfg.second))); 1224 } 1225 return NoError(); 1226 }; 1227 1228 if (!err.ok()) { 1229 restore().IgnoreError(); 1230 return err; 1231 } 1232 1233 return restore; 1234 } 1235 1236 } // namespace testing 1237 } // namespace gvisor