gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/socket_inet_loopback_isolated.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 <netinet/tcp.h>
    16  #include <sys/socket.h>
    17  
    18  #include "gmock/gmock.h"
    19  #include "gtest/gtest.h"
    20  #include "absl/time/clock.h"
    21  #include "absl/time/time.h"
    22  #include "test/syscalls/linux/socket_inet_loopback_test_params.h"
    23  #include "test/util/capability_util.h"
    24  #include "test/util/save_util.h"
    25  #include "test/util/socket_util.h"
    26  #include "test/util/test_util.h"
    27  
    28  // Unit tests in this file will run in their own network namespace.
    29  
    30  namespace gvisor {
    31  namespace testing {
    32  
    33  namespace {
    34  
    35  using SocketInetLoopbackIsolatedTest =
    36      ::testing::TestWithParam<SocketInetTestParam>;
    37  
    38  TEST_P(SocketInetLoopbackIsolatedTest, TCPActiveCloseTimeWaitTest) {
    39    SocketInetTestParam const& param = GetParam();
    40    sockaddr_storage listen_addr, conn_bound_addr;
    41    listen_addr = param.listener.addr;
    42    SetupTimeWaitClose(&param.listener, &param.connector, false /*reuse*/,
    43                       false /*accept_close*/, &listen_addr, &conn_bound_addr);
    44    FileDescriptor conn_fd = ASSERT_NO_ERRNO_AND_VALUE(
    45        Socket(param.connector.family(), SOCK_STREAM, IPPROTO_TCP));
    46  
    47    ASSERT_THAT(bind(conn_fd.get(), AsSockAddr(&conn_bound_addr),
    48                     param.connector.addr_len),
    49                SyscallFailsWithErrno(EADDRINUSE));
    50  }
    51  
    52  TEST_P(SocketInetLoopbackIsolatedTest, TCPActiveCloseTimeWaitReuseTest) {
    53    SocketInetTestParam const& param = GetParam();
    54    sockaddr_storage listen_addr, conn_bound_addr;
    55    listen_addr = param.listener.addr;
    56    SetupTimeWaitClose(&param.listener, &param.connector, true /*reuse*/,
    57                       false /*accept_close*/, &listen_addr, &conn_bound_addr);
    58    FileDescriptor conn_fd = ASSERT_NO_ERRNO_AND_VALUE(
    59        Socket(param.connector.family(), SOCK_STREAM, IPPROTO_TCP));
    60    ASSERT_THAT(setsockopt(conn_fd.get(), SOL_SOCKET, SO_REUSEADDR, &kSockOptOn,
    61                           sizeof(kSockOptOn)),
    62                SyscallSucceeds());
    63    ASSERT_THAT(bind(conn_fd.get(), AsSockAddr(&conn_bound_addr),
    64                     param.connector.addr_len),
    65                SyscallFailsWithErrno(EADDRINUSE));
    66  }
    67  
    68  // These tests are disabled under random save as the restore run
    69  // results in the stack.Seed() being different which can cause
    70  // sequence number of final connect to be one that is considered
    71  // old and can cause the test to be flaky.
    72  //
    73  // Test re-binding of client and server bound addresses when the older
    74  // connection is in TIME_WAIT.
    75  TEST_P(SocketInetLoopbackIsolatedTest, TCPPassiveCloseNoTimeWaitTest) {
    76    SocketInetTestParam const& param = GetParam();
    77    sockaddr_storage listen_addr, conn_bound_addr;
    78    listen_addr = param.listener.addr;
    79    SetupTimeWaitClose(&param.listener, &param.connector, false /*reuse*/,
    80                       true /*accept_close*/, &listen_addr, &conn_bound_addr);
    81  
    82    // Now bind a new socket and verify that we can immediately rebind the address
    83    // bound by the conn_fd as it never entered TIME_WAIT.
    84    const FileDescriptor conn_fd = ASSERT_NO_ERRNO_AND_VALUE(
    85        Socket(param.connector.family(), SOCK_STREAM, IPPROTO_TCP));
    86    ASSERT_THAT(bind(conn_fd.get(), AsSockAddr(&conn_bound_addr),
    87                     param.connector.addr_len),
    88                SyscallSucceeds());
    89  
    90    FileDescriptor listen_fd = ASSERT_NO_ERRNO_AND_VALUE(
    91        Socket(param.listener.family(), SOCK_STREAM, IPPROTO_TCP));
    92    ASSERT_THAT(
    93        bind(listen_fd.get(), AsSockAddr(&listen_addr), param.listener.addr_len),
    94        SyscallFailsWithErrno(EADDRINUSE));
    95  }
    96  
    97  TEST_P(SocketInetLoopbackIsolatedTest, TCPPassiveCloseNoTimeWaitReuseTest) {
    98    SocketInetTestParam const& param = GetParam();
    99    sockaddr_storage listen_addr, conn_bound_addr;
   100    listen_addr = param.listener.addr;
   101    SetupTimeWaitClose(&param.listener, &param.connector, true /*reuse*/,
   102                       true /*accept_close*/, &listen_addr, &conn_bound_addr);
   103  
   104    FileDescriptor listen_fd = ASSERT_NO_ERRNO_AND_VALUE(
   105        Socket(param.listener.family(), SOCK_STREAM, IPPROTO_TCP));
   106    ASSERT_THAT(setsockopt(listen_fd.get(), SOL_SOCKET, SO_REUSEADDR, &kSockOptOn,
   107                           sizeof(kSockOptOn)),
   108                SyscallSucceeds());
   109    ASSERT_THAT(
   110        bind(listen_fd.get(), AsSockAddr(&listen_addr), param.listener.addr_len),
   111        SyscallSucceeds());
   112    ASSERT_THAT(listen(listen_fd.get(), SOMAXCONN), SyscallSucceeds());
   113  
   114    // Now bind and connect  new socket and verify that we can immediately rebind
   115    // the address bound by the conn_fd as it never entered TIME_WAIT.
   116    const FileDescriptor conn_fd = ASSERT_NO_ERRNO_AND_VALUE(
   117        Socket(param.connector.family(), SOCK_STREAM, IPPROTO_TCP));
   118    ASSERT_THAT(setsockopt(conn_fd.get(), SOL_SOCKET, SO_REUSEADDR, &kSockOptOn,
   119                           sizeof(kSockOptOn)),
   120                SyscallSucceeds());
   121    ASSERT_THAT(bind(conn_fd.get(), AsSockAddr(&conn_bound_addr),
   122                     param.connector.addr_len),
   123                SyscallSucceeds());
   124  
   125    uint16_t const port =
   126        ASSERT_NO_ERRNO_AND_VALUE(AddrPort(param.listener.family(), listen_addr));
   127    sockaddr_storage conn_addr = param.connector.addr;
   128    ASSERT_NO_ERRNO(SetAddrPort(param.connector.family(), &conn_addr, port));
   129    ASSERT_THAT(RetryEINTR(connect)(conn_fd.get(), AsSockAddr(&conn_addr),
   130                                    param.connector.addr_len),
   131                SyscallSucceeds());
   132  }
   133  
   134  // TCPFinWait2Test creates a pair of connected sockets then closes one end to
   135  // trigger FIN_WAIT2 state for the closed endpoint. Then it binds the same local
   136  // IP/port on a new socket and tries to connect. The connect should fail w/
   137  // an EADDRINUSE. Then we wait till the FIN_WAIT2 timeout is over and try the
   138  // bind/connect again with a new socket and this time it should succeed.
   139  //
   140  // TCP timers are not S/R today, this can cause this test to be flaky when run
   141  // under random S/R due to timer being reset on a restore.
   142  TEST_P(SocketInetLoopbackIsolatedTest, TCPFinWait2Test) {
   143    SocketInetTestParam const& param = GetParam();
   144    TestAddress const& listener = param.listener;
   145    TestAddress const& connector = param.connector;
   146  
   147    // Disable cooperative saves after this point. As a save between the first
   148    // bind/connect and the second one can cause the linger timeout timer to
   149    // be restarted causing the final bind/connect to fail.
   150    DisableSave ds;
   151  
   152    // Create the listening socket.
   153    const FileDescriptor listen_fd = ASSERT_NO_ERRNO_AND_VALUE(
   154        Socket(listener.family(), SOCK_STREAM, IPPROTO_TCP));
   155    sockaddr_storage listen_addr = listener.addr;
   156    ASSERT_THAT(
   157        bind(listen_fd.get(), AsSockAddr(&listen_addr), listener.addr_len),
   158        SyscallSucceeds());
   159    ASSERT_THAT(listen(listen_fd.get(), SOMAXCONN), SyscallSucceeds());
   160  
   161    // Get the port bound by the listening socket.
   162    socklen_t addrlen = listener.addr_len;
   163    ASSERT_THAT(getsockname(listen_fd.get(), AsSockAddr(&listen_addr), &addrlen),
   164                SyscallSucceeds());
   165  
   166    uint16_t const port =
   167        ASSERT_NO_ERRNO_AND_VALUE(AddrPort(listener.family(), listen_addr));
   168  
   169    // Connect to the listening socket.
   170    FileDescriptor conn_fd = ASSERT_NO_ERRNO_AND_VALUE(
   171        Socket(connector.family(), SOCK_STREAM, IPPROTO_TCP));
   172  
   173    // Lower FIN_WAIT2 state to 5 seconds for test.
   174    constexpr int kTCPLingerTimeout = 5;
   175    EXPECT_THAT(setsockopt(conn_fd.get(), IPPROTO_TCP, TCP_LINGER2,
   176                           &kTCPLingerTimeout, sizeof(kTCPLingerTimeout)),
   177                SyscallSucceedsWithValue(0));
   178  
   179    sockaddr_storage conn_addr = connector.addr;
   180    ASSERT_NO_ERRNO(SetAddrPort(connector.family(), &conn_addr, port));
   181    ASSERT_THAT(RetryEINTR(connect)(conn_fd.get(), AsSockAddr(&conn_addr),
   182                                    connector.addr_len),
   183                SyscallSucceeds());
   184  
   185    // Accept the connection.
   186    auto accepted =
   187        ASSERT_NO_ERRNO_AND_VALUE(Accept(listen_fd.get(), nullptr, nullptr));
   188  
   189    // Get the address/port bound by the connecting socket.
   190    sockaddr_storage conn_bound_addr;
   191    socklen_t conn_addrlen = connector.addr_len;
   192    ASSERT_THAT(
   193        getsockname(conn_fd.get(), AsSockAddr(&conn_bound_addr), &conn_addrlen),
   194        SyscallSucceeds());
   195  
   196    // close the connecting FD to trigger FIN_WAIT2  on the connected fd.
   197    conn_fd.reset();
   198  
   199    // Now bind and connect a new socket.
   200    const FileDescriptor conn_fd2 = ASSERT_NO_ERRNO_AND_VALUE(
   201        Socket(connector.family(), SOCK_STREAM, IPPROTO_TCP));
   202  
   203    ASSERT_THAT(bind(conn_fd2.get(), AsSockAddr(&conn_bound_addr), conn_addrlen),
   204                SyscallFailsWithErrno(EADDRINUSE));
   205  
   206    // Sleep for a little over the linger timeout to reduce flakiness in
   207    // save/restore tests.
   208    absl::SleepFor(absl::Seconds(kTCPLingerTimeout + 2));
   209  
   210    ASSERT_THAT(bind(conn_fd2.get(), AsSockAddr(&conn_bound_addr), conn_addrlen),
   211                SyscallSucceeds());
   212  
   213    ASSERT_THAT(
   214        RetryEINTR(connect)(conn_fd2.get(), AsSockAddr(&conn_addr), conn_addrlen),
   215        SyscallSucceeds());
   216  }
   217  
   218  // TCPLinger2TimeoutAfterClose creates a pair of connected sockets
   219  // then closes one end to trigger FIN_WAIT2 state for the closed endpoint.
   220  // It then sleeps for the TCP_LINGER2 timeout and verifies that bind/
   221  // connecting the same address succeeds.
   222  //
   223  // TCP timers are not S/R today, this can cause this test to be flaky when run
   224  // under random S/R due to timer being reset on a restore.
   225  TEST_P(SocketInetLoopbackIsolatedTest, TCPLinger2TimeoutAfterClose) {
   226    SocketInetTestParam const& param = GetParam();
   227    TestAddress const& listener = param.listener;
   228    TestAddress const& connector = param.connector;
   229  
   230    // Create the listening socket.
   231    const FileDescriptor listen_fd = ASSERT_NO_ERRNO_AND_VALUE(
   232        Socket(listener.family(), SOCK_STREAM, IPPROTO_TCP));
   233    sockaddr_storage listen_addr = listener.addr;
   234    ASSERT_THAT(
   235        bind(listen_fd.get(), AsSockAddr(&listen_addr), listener.addr_len),
   236        SyscallSucceeds());
   237    ASSERT_THAT(listen(listen_fd.get(), SOMAXCONN), SyscallSucceeds());
   238  
   239    // Get the port bound by the listening socket.
   240    socklen_t addrlen = listener.addr_len;
   241    ASSERT_THAT(getsockname(listen_fd.get(), AsSockAddr(&listen_addr), &addrlen),
   242                SyscallSucceeds());
   243  
   244    uint16_t const port =
   245        ASSERT_NO_ERRNO_AND_VALUE(AddrPort(listener.family(), listen_addr));
   246  
   247    // Connect to the listening socket.
   248    FileDescriptor conn_fd = ASSERT_NO_ERRNO_AND_VALUE(
   249        Socket(connector.family(), SOCK_STREAM, IPPROTO_TCP));
   250  
   251    sockaddr_storage conn_addr = connector.addr;
   252    ASSERT_NO_ERRNO(SetAddrPort(connector.family(), &conn_addr, port));
   253    ASSERT_THAT(RetryEINTR(connect)(conn_fd.get(), AsSockAddr(&conn_addr),
   254                                    connector.addr_len),
   255                SyscallSucceeds());
   256  
   257    // Accept the connection.
   258    auto accepted =
   259        ASSERT_NO_ERRNO_AND_VALUE(Accept(listen_fd.get(), nullptr, nullptr));
   260  
   261    // Get the address/port bound by the connecting socket.
   262    sockaddr_storage conn_bound_addr;
   263    socklen_t conn_addrlen = connector.addr_len;
   264    ASSERT_THAT(
   265        getsockname(conn_fd.get(), AsSockAddr(&conn_bound_addr), &conn_addrlen),
   266        SyscallSucceeds());
   267  
   268    // Disable cooperative saves after this point as TCP timers are not restored
   269    // across a S/R.
   270    {
   271      DisableSave ds;
   272      constexpr int kTCPLingerTimeout = 4;
   273      EXPECT_THAT(setsockopt(conn_fd.get(), IPPROTO_TCP, TCP_LINGER2,
   274                             &kTCPLingerTimeout, sizeof(kTCPLingerTimeout)),
   275                  SyscallSucceedsWithValue(0));
   276  
   277      // close the connecting FD to trigger FIN_WAIT2  on the connected fd.
   278      conn_fd.reset();
   279  
   280      absl::SleepFor(absl::Seconds(kTCPLingerTimeout + 2));
   281  
   282      // ds going out of scope will Re-enable S/R's since at this point the timer
   283      // must have fired and cleaned up the endpoint.
   284    }
   285  
   286    // Now bind and connect a new socket and verify that we can immediately
   287    // rebind the address bound by the conn_fd as it never entered TIME_WAIT.
   288    const FileDescriptor conn_fd2 = ASSERT_NO_ERRNO_AND_VALUE(
   289        Socket(connector.family(), SOCK_STREAM, IPPROTO_TCP));
   290  
   291    ASSERT_THAT(bind(conn_fd2.get(), AsSockAddr(&conn_bound_addr), conn_addrlen),
   292                SyscallSucceeds());
   293    ASSERT_THAT(
   294        RetryEINTR(connect)(conn_fd2.get(), AsSockAddr(&conn_addr), conn_addrlen),
   295        SyscallSucceeds());
   296  }
   297  
   298  TEST_P(SocketInetLoopbackIsolatedTest, TCPConnectionReuseAddrConflicts) {
   299    SocketInetTestParam const& param = GetParam();
   300    TestAddress const& listener = param.listener;
   301    TestAddress const& connector = param.connector;
   302  
   303    const FileDescriptor listen_fd =
   304        ASSERT_NO_ERRNO_AND_VALUE(Socket(listener.family(), SOCK_STREAM, 0));
   305  
   306    sockaddr_storage listen_addr = listener.addr;
   307    ASSERT_THAT(
   308        bind(listen_fd.get(), AsSockAddr(&listen_addr), listener.addr_len),
   309        SyscallSucceeds());
   310    ASSERT_THAT(listen(listen_fd.get(), SOMAXCONN), SyscallSucceeds());
   311  
   312    // Get the port bound by the listening socket.
   313    socklen_t addrlen = listener.addr_len;
   314    ASSERT_THAT(getsockname(listen_fd.get(), AsSockAddr(&listen_addr), &addrlen),
   315                SyscallSucceeds());
   316  
   317    const uint16_t port =
   318        ASSERT_NO_ERRNO_AND_VALUE(AddrPort(listener.family(), listen_addr));
   319  
   320    // Create a first connection.
   321    FileDescriptor conn_fd1 = ASSERT_NO_ERRNO_AND_VALUE(
   322        Socket(connector.family(), SOCK_STREAM, IPPROTO_TCP));
   323    ASSERT_THAT(setsockopt(conn_fd1.get(), SOL_SOCKET, SO_REUSEADDR, &kSockOptOn,
   324                           sizeof(kSockOptOn)),
   325                SyscallSucceeds());
   326  
   327    sockaddr_storage conn_addr = connector.addr;
   328    ASSERT_NO_ERRNO(SetAddrPort(connector.family(), &conn_addr, port));
   329    ASSERT_THAT(RetryEINTR(connect)(conn_fd1.get(), AsSockAddr(&conn_addr),
   330                                    connector.addr_len),
   331                SyscallSucceeds());
   332    sockaddr_storage conn_bound_addr;
   333    addrlen = sizeof(conn_bound_addr);
   334    ASSERT_THAT(
   335        getsockname(conn_fd1.get(), AsSockAddr(&conn_bound_addr), &addrlen),
   336        SyscallSucceeds());
   337    ASSERT_EQ(addrlen, connector.addr_len);
   338  
   339    // Create the second connection that is bind to the same local address as the
   340    // first.
   341    FileDescriptor conn_fd2 = ASSERT_NO_ERRNO_AND_VALUE(
   342        Socket(connector.family(), SOCK_STREAM, IPPROTO_TCP));
   343    ASSERT_THAT(setsockopt(conn_fd2.get(), SOL_SOCKET, SO_REUSEADDR, &kSockOptOn,
   344                           sizeof(kSockOptOn)),
   345                SyscallSucceeds());
   346    // Bind should succeed.
   347    ASSERT_THAT(bind(conn_fd2.get(), AsSockAddr(&conn_bound_addr), addrlen),
   348                SyscallSucceeds());
   349  
   350    // Connect should fail.
   351    ASSERT_NO_ERRNO(SetAddrPort(connector.family(), &conn_addr, port));
   352    ASSERT_THAT(RetryEINTR(connect)(conn_fd2.get(), AsSockAddr(&conn_addr),
   353                                    connector.addr_len),
   354                SyscallFailsWithErrno(EADDRNOTAVAIL));
   355  }
   356  
   357  INSTANTIATE_TEST_SUITE_P(All, SocketInetLoopbackIsolatedTest,
   358                           SocketInetLoopbackTestValues(),
   359                           DescribeSocketInetTestParam);
   360  
   361  using SocketMultiProtocolInetLoopbackIsolatedTest =
   362      ::testing::TestWithParam<ProtocolTestParam>;
   363  
   364  TEST_P(SocketMultiProtocolInetLoopbackIsolatedTest, BindToDeviceReusePort) {
   365    // setsockopt(SO_BINDTODEVICE) requires CAP_NET_RAW.
   366    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
   367  
   368    ProtocolTestParam const& param = GetParam();
   369    TestAddress const& test_addr = V4Loopback();
   370  
   371    auto socket1 =
   372        ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0));
   373    auto socket2 =
   374        ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0));
   375  
   376    const char kLoopbackDeviceName[] = "lo";
   377  
   378    // Bind socket1 with REUSEPORT and BINDTODEVICE.
   379    ASSERT_THAT(setsockopt(socket1.get(), SOL_SOCKET, SO_REUSEPORT, &kSockOptOn,
   380                           sizeof(kSockOptOn)),
   381                SyscallSucceeds());
   382    ASSERT_THAT(setsockopt(socket1.get(), SOL_SOCKET, SO_BINDTODEVICE,
   383                           kLoopbackDeviceName, strlen(kLoopbackDeviceName)),
   384                SyscallSucceeds());
   385  
   386    // Bind the first socket to the loopback and take note of the selected port.
   387    auto addr = V4Loopback();
   388    ASSERT_THAT(bind(socket1.get(), AsSockAddr(&addr.addr), addr.addr_len),
   389                SyscallSucceeds());
   390    socklen_t addr_len = addr.addr_len;
   391    ASSERT_THAT(getsockname(socket1.get(), AsSockAddr(&addr.addr), &addr_len),
   392                SyscallSucceeds());
   393    EXPECT_EQ(addr_len, addr.addr_len);
   394  
   395    // Bind socket2 to the same device and address as socket1.
   396    ASSERT_THAT(setsockopt(socket2.get(), SOL_SOCKET, SO_BINDTODEVICE,
   397                           kLoopbackDeviceName, strlen(kLoopbackDeviceName)),
   398                SyscallSucceeds());
   399    ASSERT_THAT(setsockopt(socket2.get(), SOL_SOCKET, SO_REUSEPORT, &kSockOptOn,
   400                           sizeof(kSockOptOn)),
   401                SyscallSucceeds());
   402    ASSERT_THAT(bind(socket2.get(), AsSockAddr(&addr.addr), addr.addr_len),
   403                SyscallSucceeds());
   404  }
   405  
   406  TEST_P(SocketMultiProtocolInetLoopbackIsolatedTest,
   407         V4EphemeralPortReservedReuseAddr) {
   408    ProtocolTestParam const& param = GetParam();
   409  
   410    // Bind the v4 loopback on a v4 socket.
   411    TestAddress const& test_addr = V4Loopback();
   412    sockaddr_storage bound_addr = test_addr.addr;
   413    const FileDescriptor bound_fd =
   414        ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0));
   415  
   416    ASSERT_THAT(setsockopt(bound_fd.get(), SOL_SOCKET, SO_REUSEADDR, &kSockOptOn,
   417                           sizeof(kSockOptOn)),
   418                SyscallSucceeds());
   419  
   420    ASSERT_THAT(bind(bound_fd.get(), AsSockAddr(&bound_addr), test_addr.addr_len),
   421                SyscallSucceeds());
   422  
   423    // Listen iff TCP.
   424    if (param.type == SOCK_STREAM) {
   425      ASSERT_THAT(listen(bound_fd.get(), SOMAXCONN), SyscallSucceeds());
   426    }
   427  
   428    // Get the port that we bound.
   429    socklen_t bound_addr_len = test_addr.addr_len;
   430    ASSERT_THAT(
   431        getsockname(bound_fd.get(), AsSockAddr(&bound_addr), &bound_addr_len),
   432        SyscallSucceeds());
   433  
   434    // Connect to bind an ephemeral port.
   435    const FileDescriptor connected_fd =
   436        ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0));
   437  
   438    ASSERT_THAT(setsockopt(connected_fd.get(), SOL_SOCKET, SO_REUSEADDR,
   439                           &kSockOptOn, sizeof(kSockOptOn)),
   440                SyscallSucceeds());
   441  
   442    ASSERT_THAT(RetryEINTR(connect)(connected_fd.get(), AsSockAddr(&bound_addr),
   443                                    bound_addr_len),
   444                SyscallSucceeds());
   445  
   446    // Get the ephemeral port.
   447    sockaddr_storage connected_addr = {};
   448    socklen_t connected_addr_len = sizeof(connected_addr);
   449    ASSERT_THAT(getsockname(connected_fd.get(), AsSockAddr(&connected_addr),
   450                            &connected_addr_len),
   451                SyscallSucceeds());
   452    uint16_t const ephemeral_port =
   453        ASSERT_NO_ERRNO_AND_VALUE(AddrPort(test_addr.family(), connected_addr));
   454  
   455    // Verify that we actually got an ephemeral port.
   456    ASSERT_NE(ephemeral_port, 0);
   457  
   458    // Verify that the ephemeral port is not reserved.
   459    const FileDescriptor checking_fd =
   460        ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0));
   461    ASSERT_THAT(setsockopt(checking_fd.get(), SOL_SOCKET, SO_REUSEADDR,
   462                           &kSockOptOn, sizeof(kSockOptOn)),
   463                SyscallSucceeds());
   464    EXPECT_THAT(
   465        bind(checking_fd.get(), AsSockAddr(&connected_addr), connected_addr_len),
   466        SyscallSucceeds());
   467  }
   468  
   469  TEST_P(SocketMultiProtocolInetLoopbackIsolatedTest,
   470         V4MappedEphemeralPortReservedReuseAddr) {
   471    ProtocolTestParam const& param = GetParam();
   472  
   473    // Bind the v4 loopback on a dual stack socket.
   474    TestAddress const& test_addr = V4MappedLoopback();
   475    sockaddr_storage bound_addr = test_addr.addr;
   476    const FileDescriptor bound_fd =
   477        ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0));
   478    ASSERT_THAT(bind(bound_fd.get(), AsSockAddr(&bound_addr), test_addr.addr_len),
   479                SyscallSucceeds());
   480  
   481    ASSERT_THAT(setsockopt(bound_fd.get(), SOL_SOCKET, SO_REUSEADDR, &kSockOptOn,
   482                           sizeof(kSockOptOn)),
   483                SyscallSucceeds());
   484  
   485    // Listen iff TCP.
   486    if (param.type == SOCK_STREAM) {
   487      ASSERT_THAT(listen(bound_fd.get(), SOMAXCONN), SyscallSucceeds());
   488    }
   489  
   490    // Get the port that we bound.
   491    socklen_t bound_addr_len = test_addr.addr_len;
   492    ASSERT_THAT(
   493        getsockname(bound_fd.get(), AsSockAddr(&bound_addr), &bound_addr_len),
   494        SyscallSucceeds());
   495  
   496    // Connect to bind an ephemeral port.
   497    const FileDescriptor connected_fd =
   498        ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0));
   499    ASSERT_THAT(setsockopt(connected_fd.get(), SOL_SOCKET, SO_REUSEADDR,
   500                           &kSockOptOn, sizeof(kSockOptOn)),
   501                SyscallSucceeds());
   502    ASSERT_THAT(RetryEINTR(connect)(connected_fd.get(), AsSockAddr(&bound_addr),
   503                                    bound_addr_len),
   504                SyscallSucceeds());
   505  
   506    // Get the ephemeral port.
   507    sockaddr_storage connected_addr = {};
   508    socklen_t connected_addr_len = sizeof(connected_addr);
   509    ASSERT_THAT(getsockname(connected_fd.get(), AsSockAddr(&connected_addr),
   510                            &connected_addr_len),
   511                SyscallSucceeds());
   512    uint16_t const ephemeral_port =
   513        ASSERT_NO_ERRNO_AND_VALUE(AddrPort(test_addr.family(), connected_addr));
   514  
   515    // Verify that we actually got an ephemeral port.
   516    ASSERT_NE(ephemeral_port, 0);
   517  
   518    // Verify that the ephemeral port is not reserved.
   519    const FileDescriptor checking_fd =
   520        ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0));
   521    ASSERT_THAT(setsockopt(checking_fd.get(), SOL_SOCKET, SO_REUSEADDR,
   522                           &kSockOptOn, sizeof(kSockOptOn)),
   523                SyscallSucceeds());
   524    EXPECT_THAT(
   525        bind(checking_fd.get(), AsSockAddr(&connected_addr), connected_addr_len),
   526        SyscallSucceeds());
   527  }
   528  
   529  TEST_P(SocketMultiProtocolInetLoopbackIsolatedTest,
   530         V6EphemeralPortReservedReuseAddr) {
   531    ProtocolTestParam const& param = GetParam();
   532  
   533    // Bind the v6 loopback on a dual stack socket.
   534    TestAddress const& test_addr = V6Loopback();
   535    sockaddr_storage bound_addr = test_addr.addr;
   536    const FileDescriptor bound_fd =
   537        ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0));
   538    ASSERT_THAT(bind(bound_fd.get(), AsSockAddr(&bound_addr), test_addr.addr_len),
   539                SyscallSucceeds());
   540    ASSERT_THAT(setsockopt(bound_fd.get(), SOL_SOCKET, SO_REUSEADDR, &kSockOptOn,
   541                           sizeof(kSockOptOn)),
   542                SyscallSucceeds());
   543  
   544    // Listen iff TCP.
   545    if (param.type == SOCK_STREAM) {
   546      ASSERT_THAT(listen(bound_fd.get(), SOMAXCONN), SyscallSucceeds());
   547    }
   548  
   549    // Get the port that we bound.
   550    socklen_t bound_addr_len = test_addr.addr_len;
   551    ASSERT_THAT(
   552        getsockname(bound_fd.get(), AsSockAddr(&bound_addr), &bound_addr_len),
   553        SyscallSucceeds());
   554  
   555    // Connect to bind an ephemeral port.
   556    const FileDescriptor connected_fd =
   557        ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0));
   558    ASSERT_THAT(setsockopt(connected_fd.get(), SOL_SOCKET, SO_REUSEADDR,
   559                           &kSockOptOn, sizeof(kSockOptOn)),
   560                SyscallSucceeds());
   561    ASSERT_THAT(RetryEINTR(connect)(connected_fd.get(), AsSockAddr(&bound_addr),
   562                                    bound_addr_len),
   563                SyscallSucceeds());
   564  
   565    // Get the ephemeral port.
   566    sockaddr_storage connected_addr = {};
   567    socklen_t connected_addr_len = sizeof(connected_addr);
   568    ASSERT_THAT(getsockname(connected_fd.get(), AsSockAddr(&connected_addr),
   569                            &connected_addr_len),
   570                SyscallSucceeds());
   571    uint16_t const ephemeral_port =
   572        ASSERT_NO_ERRNO_AND_VALUE(AddrPort(test_addr.family(), connected_addr));
   573  
   574    // Verify that we actually got an ephemeral port.
   575    ASSERT_NE(ephemeral_port, 0);
   576  
   577    // Verify that the ephemeral port is not reserved.
   578    const FileDescriptor checking_fd =
   579        ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0));
   580    ASSERT_THAT(setsockopt(checking_fd.get(), SOL_SOCKET, SO_REUSEADDR,
   581                           &kSockOptOn, sizeof(kSockOptOn)),
   582                SyscallSucceeds());
   583    EXPECT_THAT(
   584        bind(checking_fd.get(), AsSockAddr(&connected_addr), connected_addr_len),
   585        SyscallSucceeds());
   586  }
   587  
   588  INSTANTIATE_TEST_SUITE_P(AllFamilies,
   589                           SocketMultiProtocolInetLoopbackIsolatedTest,
   590                           ProtocolTestValues(), DescribeProtocolTestParam);
   591  
   592  }  // namespace
   593  
   594  }  // namespace testing
   595  }  // namespace gvisor