gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/ping_socket.cc (about)

     1  // Copyright 2020 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 <errno.h>
    16  #include <netinet/icmp6.h>
    17  #include <netinet/in.h>
    18  #include <netinet/ip.h>
    19  #include <netinet/ip_icmp.h>
    20  #include <sys/socket.h>
    21  #include <sys/types.h>
    22  #include <unistd.h>
    23  
    24  #include <cctype>
    25  #include <cstring>
    26  #include <vector>
    27  
    28  #include "gtest/gtest.h"
    29  #include "absl/algorithm/container.h"
    30  #include "absl/strings/str_join.h"
    31  #include "absl/types/optional.h"
    32  #include "test/syscalls/linux/ip_socket_test_util.h"
    33  #include "test/util/file_descriptor.h"
    34  #include "test/util/socket_util.h"
    35  #include "test/util/test_util.h"
    36  
    37  // Note: These tests require /proc/sys/net/ipv4/ping_group_range to be
    38  // configured to allow the tester to create ping sockets (see icmp(7)).
    39  
    40  namespace gvisor {
    41  namespace testing {
    42  namespace {
    43  
    44  // Test ICMP port exhaustion returns EAGAIN.
    45  //
    46  // We disable both random/cooperative S/R for this test as it makes way too many
    47  // syscalls.
    48  TEST(PingSocket, ICMPPortExhaustion) {
    49    DisableSave ds;
    50  
    51    {
    52      auto s = Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
    53      if (!s.ok()) {
    54        ASSERT_EQ(s.error().errno_value(), EACCES);
    55        GTEST_SKIP() << "TODO(gvisor.dev/issue/6126): Buildkite does not allow "
    56                        "creation of ICMP or ICMPv6 sockets";
    57      }
    58    }
    59  
    60    const struct sockaddr_in addr = {
    61        .sin_family = AF_INET,
    62        .sin_addr =
    63            {
    64                .s_addr = htonl(INADDR_LOOPBACK),
    65            },
    66    };
    67  
    68    std::vector<FileDescriptor> sockets;
    69    constexpr int kSockets = 65536;
    70    for (int i = 0; i < kSockets; i++) {
    71      auto s =
    72          ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP));
    73      int ret = connect(s.get(), reinterpret_cast<const struct sockaddr*>(&addr),
    74                        sizeof(addr));
    75      if (ret == 0) {
    76        sockets.push_back(std::move(s));
    77        continue;
    78      }
    79      ASSERT_THAT(ret, SyscallFailsWithErrno(EAGAIN));
    80      break;
    81    }
    82  }
    83  
    84  TEST(PingSocket, PayloadTooLarge) {
    85    PosixErrorOr<FileDescriptor> result =
    86        Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
    87    if (!result.ok()) {
    88      int errno_value = result.error().errno_value();
    89      ASSERT_EQ(errno_value, EACCES) << strerror(errno_value);
    90      GTEST_SKIP() << "ping socket not supported";
    91    }
    92    FileDescriptor& ping = result.ValueOrDie();
    93  
    94    constexpr icmphdr kSendIcmp = {
    95        .type = ICMP_ECHO,
    96    };
    97    constexpr size_t kGiantSize = 1 << 21;  // 2MB.
    98    const sockaddr_in kAddr = {
    99        .sin_family = AF_INET,
   100        .sin_addr = {.s_addr = htonl(INADDR_LOOPBACK)},
   101    };
   102    ASSERT_THAT(sendto(ping.get(), &kSendIcmp, kGiantSize, 0,
   103                       reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)),
   104                SyscallFailsWithErrno(EMSGSIZE));
   105  }
   106  
   107  TEST(PingSocket, ReceiveTOS) {
   108    PosixErrorOr<FileDescriptor> result =
   109        Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
   110    if (!result.ok()) {
   111      int errno_value = result.error().errno_value();
   112      ASSERT_EQ(errno_value, EACCES) << strerror(errno_value);
   113      GTEST_SKIP() << "ping socket not supported";
   114    }
   115    FileDescriptor& ping = result.ValueOrDie();
   116  
   117    const sockaddr_in kAddr = {
   118        .sin_family = AF_INET,
   119        .sin_addr = {.s_addr = htonl(INADDR_LOOPBACK)},
   120    };
   121    ASSERT_THAT(bind(ping.get(), reinterpret_cast<const sockaddr*>(&kAddr),
   122                     sizeof(kAddr)),
   123                SyscallSucceeds());
   124  
   125    constexpr int kArbitraryTOS = 42;
   126    ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IP, IP_TOS, &kArbitraryTOS,
   127                           sizeof(kArbitraryTOS)),
   128                SyscallSucceeds());
   129  
   130    constexpr icmphdr kSendIcmp = {
   131        .type = ICMP_ECHO,
   132    };
   133    ASSERT_THAT(sendto(ping.get(), &kSendIcmp, sizeof(kSendIcmp), 0,
   134                       reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)),
   135                SyscallSucceedsWithValue(sizeof(kSendIcmp)));
   136  
   137    // Register to receive TOS.
   138    ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IP, IP_RECVTOS, &kSockOptOn,
   139                           sizeof(kSockOptOn)),
   140                SyscallSucceeds());
   141  
   142    icmphdr recv_buf;
   143    size_t recv_buf_len = sizeof(recv_buf);
   144    uint8_t received_tos;
   145    ASSERT_NO_FATAL_FAILURE(RecvTOS(ping.get(),
   146                                    reinterpret_cast<char*>(&recv_buf),
   147                                    &recv_buf_len, &received_tos));
   148    ASSERT_EQ(recv_buf_len, sizeof(kSendIcmp));
   149  
   150    EXPECT_EQ(recv_buf.type, ICMP_ECHOREPLY);
   151    EXPECT_EQ(recv_buf.code, 0);
   152  
   153    EXPECT_EQ(received_tos, kArbitraryTOS);
   154  }
   155  
   156  TEST(PingSocket, ReceiveTClass) {
   157    PosixErrorOr<FileDescriptor> result =
   158        Socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
   159    if (!result.ok()) {
   160      int errno_value = result.error().errno_value();
   161      ASSERT_EQ(errno_value, EACCES) << strerror(errno_value);
   162      GTEST_SKIP() << "ping socket not supported";
   163    }
   164    FileDescriptor& ping = result.ValueOrDie();
   165  
   166    const sockaddr_in6 kAddr = {
   167        .sin6_family = AF_INET6,
   168        .sin6_addr = in6addr_loopback,
   169    };
   170    ASSERT_THAT(bind(ping.get(), reinterpret_cast<const sockaddr*>(&kAddr),
   171                     sizeof(kAddr)),
   172                SyscallSucceeds());
   173  
   174    constexpr int kArbitraryTClass = 42;
   175    ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IPV6, IPV6_TCLASS,
   176                           &kArbitraryTClass, sizeof(kArbitraryTClass)),
   177                SyscallSucceeds());
   178  
   179    constexpr icmp6_hdr kSendIcmp = {
   180        .icmp6_type = ICMP6_ECHO_REQUEST,
   181    };
   182    ASSERT_THAT(sendto(ping.get(), &kSendIcmp, sizeof(kSendIcmp), 0,
   183                       reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)),
   184                SyscallSucceedsWithValue(sizeof(kSendIcmp)));
   185  
   186    // Register to receive TCLASS.
   187    ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IPV6, IPV6_RECVTCLASS, &kSockOptOn,
   188                           sizeof(kSockOptOn)),
   189                SyscallSucceeds());
   190  
   191    struct {
   192      icmp6_hdr icmpv6;
   193  
   194      // Add an extra byte to confirm we did not read unexpected bytes.
   195      char unused;
   196    } ABSL_ATTRIBUTE_PACKED recv_buf;
   197    size_t recv_buf_len = sizeof(recv_buf);
   198    int received_tclass;
   199    ASSERT_NO_FATAL_FAILURE(RecvTClass(ping.get(),
   200                                       reinterpret_cast<char*>(&recv_buf),
   201                                       &recv_buf_len, &received_tclass));
   202    ASSERT_EQ(recv_buf_len, sizeof(kSendIcmp));
   203  
   204    EXPECT_EQ(recv_buf.icmpv6.icmp6_type, ICMP6_ECHO_REPLY);
   205    EXPECT_EQ(recv_buf.icmpv6.icmp6_code, 0);
   206  
   207    EXPECT_EQ(received_tclass, kArbitraryTClass);
   208  }
   209  
   210  TEST(PingSocket, ReceiveTTL) {
   211    PosixErrorOr<FileDescriptor> result =
   212        Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
   213    if (!result.ok()) {
   214      int errno_value = result.error().errno_value();
   215      ASSERT_EQ(errno_value, EACCES) << strerror(errno_value);
   216      GTEST_SKIP() << "ping socket not supported";
   217    }
   218    FileDescriptor& ping = result.ValueOrDie();
   219  
   220    const sockaddr_in kAddr = {
   221        .sin_family = AF_INET,
   222        .sin_addr = {.s_addr = htonl(INADDR_LOOPBACK)},
   223    };
   224    ASSERT_THAT(bind(ping.get(), reinterpret_cast<const sockaddr*>(&kAddr),
   225                     sizeof(kAddr)),
   226                SyscallSucceeds());
   227  
   228    constexpr icmphdr kSendIcmp = {
   229        .type = ICMP_ECHO,
   230    };
   231    ASSERT_THAT(sendto(ping.get(), &kSendIcmp, sizeof(kSendIcmp), 0,
   232                       reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)),
   233                SyscallSucceedsWithValue(sizeof(kSendIcmp)));
   234  
   235    // Register to receive TTL.
   236    constexpr int kOne = 1;
   237    ASSERT_THAT(
   238        setsockopt(ping.get(), IPPROTO_IP, IP_RECVTTL, &kOne, sizeof(kOne)),
   239        SyscallSucceeds());
   240  
   241    icmphdr recv_icmp;
   242    size_t recv_len = sizeof(recv_icmp);
   243    int received_ttl;
   244    ASSERT_NO_FATAL_FAILURE(RecvTTL(ping.get(),
   245                                    reinterpret_cast<char*>(&recv_icmp),
   246                                    &recv_len, &received_ttl));
   247    ASSERT_EQ(recv_len, sizeof(kSendIcmp));
   248  
   249    EXPECT_EQ(recv_icmp.type, ICMP_ECHOREPLY);
   250    EXPECT_EQ(recv_icmp.code, 0);
   251  
   252    constexpr int kDefaultTTL = 64;
   253    EXPECT_EQ(received_ttl, kDefaultTTL);
   254  }
   255  
   256  TEST(PingSocket, ReceiveHopLimit) {
   257    PosixErrorOr<FileDescriptor> result =
   258        Socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
   259    if (!result.ok()) {
   260      int errno_value = result.error().errno_value();
   261      ASSERT_EQ(errno_value, EACCES) << strerror(errno_value);
   262      GTEST_SKIP() << "ping socket not supported";
   263    }
   264    FileDescriptor& ping = result.ValueOrDie();
   265  
   266    const sockaddr_in6 kAddr = {
   267        .sin6_family = AF_INET6,
   268        .sin6_addr = in6addr_loopback,
   269    };
   270    ASSERT_THAT(bind(ping.get(), reinterpret_cast<const sockaddr*>(&kAddr),
   271                     sizeof(kAddr)),
   272                SyscallSucceeds());
   273  
   274    constexpr icmp6_hdr kSendIcmp = {
   275        .icmp6_type = ICMP6_ECHO_REQUEST,
   276    };
   277    ASSERT_THAT(sendto(ping.get(), &kSendIcmp, sizeof(kSendIcmp), 0,
   278                       reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)),
   279                SyscallSucceedsWithValue(sizeof(kSendIcmp)));
   280  
   281    // Register to receive HOPLIMIT.
   282    constexpr int kOne = 1;
   283    ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kOne,
   284                           sizeof(kOne)),
   285                SyscallSucceeds());
   286  
   287    icmp6_hdr recv_icmpv6;
   288    size_t recv_len = sizeof(recv_icmpv6);
   289    int received_hoplimit;
   290    ASSERT_NO_FATAL_FAILURE(RecvHopLimit(ping.get(),
   291                                         reinterpret_cast<char*>(&recv_icmpv6),
   292                                         &recv_len, &received_hoplimit));
   293    ASSERT_EQ(recv_len, sizeof(kSendIcmp));
   294  
   295    EXPECT_EQ(recv_icmpv6.icmp6_type, ICMP6_ECHO_REPLY);
   296    EXPECT_EQ(recv_icmpv6.icmp6_code, 0);
   297  
   298    constexpr int kDefaultHopLimit = 64;
   299    EXPECT_EQ(received_hoplimit, kDefaultHopLimit);
   300  }
   301  
   302  TEST(PingSocket, ReceiveIPPacketInfo) {
   303    PosixErrorOr<FileDescriptor> result =
   304        Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
   305    if (!result.ok()) {
   306      int errno_value = result.error().errno_value();
   307      ASSERT_EQ(errno_value, EACCES) << strerror(errno_value);
   308      GTEST_SKIP() << "ping socket not supported";
   309    }
   310    FileDescriptor& ping = result.ValueOrDie();
   311  
   312    const sockaddr_in kAddr = {
   313        .sin_family = AF_INET,
   314        .sin_addr = {.s_addr = htonl(INADDR_LOOPBACK)},
   315    };
   316    ASSERT_THAT(bind(ping.get(), reinterpret_cast<const sockaddr*>(&kAddr),
   317                     sizeof(kAddr)),
   318                SyscallSucceeds());
   319  
   320    constexpr icmphdr kSendIcmp = {
   321        .type = ICMP_ECHO,
   322    };
   323    ASSERT_THAT(sendto(ping.get(), &kSendIcmp, sizeof(kSendIcmp), 0,
   324                       reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)),
   325                SyscallSucceedsWithValue(sizeof(kSendIcmp)));
   326  
   327    // Register to receive PKTINFO.
   328    ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IP, IP_PKTINFO, &kSockOptOn,
   329                           sizeof(kSockOptOn)),
   330                SyscallSucceeds());
   331  
   332    struct {
   333      icmphdr icmp;
   334  
   335      // Add an extra byte to confirm we did not read unexpected bytes.
   336      char unused;
   337    } ABSL_ATTRIBUTE_PACKED recv_buf;
   338    size_t recv_buf_len = sizeof(recv_buf);
   339    in_pktinfo received_pktinfo;
   340    ASSERT_NO_FATAL_FAILURE(RecvPktInfo(ping.get(),
   341                                        reinterpret_cast<char*>(&recv_buf),
   342                                        &recv_buf_len, &received_pktinfo));
   343    ASSERT_EQ(recv_buf_len, sizeof(icmphdr));
   344  
   345    EXPECT_EQ(recv_buf.icmp.type, ICMP_ECHOREPLY);
   346    EXPECT_EQ(recv_buf.icmp.code, 0);
   347  
   348    EXPECT_EQ(received_pktinfo.ipi_ifindex,
   349              ASSERT_NO_ERRNO_AND_VALUE(GetLoopbackIndex()));
   350    EXPECT_EQ(ntohl(received_pktinfo.ipi_spec_dst.s_addr), INADDR_ANY);
   351    EXPECT_EQ(ntohl(received_pktinfo.ipi_addr.s_addr), INADDR_LOOPBACK);
   352  }
   353  
   354  TEST(PingSocket, ReceiveIPv6PktInfo) {
   355    PosixErrorOr<FileDescriptor> result =
   356        Socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
   357    if (!result.ok()) {
   358      int errno_value = result.error().errno_value();
   359      ASSERT_EQ(errno_value, EACCES) << strerror(errno_value);
   360      GTEST_SKIP() << "ping socket not supported";
   361    }
   362    FileDescriptor& ping = result.ValueOrDie();
   363  
   364    const sockaddr_in6 kAddr = {
   365        .sin6_family = AF_INET6,
   366        .sin6_addr = in6addr_loopback,
   367    };
   368    ASSERT_THAT(bind(ping.get(), reinterpret_cast<const sockaddr*>(&kAddr),
   369                     sizeof(kAddr)),
   370                SyscallSucceeds());
   371  
   372    constexpr icmp6_hdr kSendIcmp = {
   373        .icmp6_type = ICMP6_ECHO_REQUEST,
   374    };
   375    ASSERT_THAT(sendto(ping.get(), &kSendIcmp, sizeof(kSendIcmp), 0,
   376                       reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)),
   377                SyscallSucceedsWithValue(sizeof(kSendIcmp)));
   378  
   379    // Register to receive PKTINFO.
   380    ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IPV6, IPV6_RECVPKTINFO,
   381                           &kSockOptOn, sizeof(kSockOptOn)),
   382                SyscallSucceeds());
   383  
   384    struct {
   385      icmp6_hdr icmpv6;
   386  
   387      // Add an extra byte to confirm we did not read unexpected bytes.
   388      char unused;
   389    } ABSL_ATTRIBUTE_PACKED recv_buf;
   390    size_t recv_buf_len = sizeof(recv_buf);
   391    in6_pktinfo received_pktinfo;
   392    ASSERT_NO_FATAL_FAILURE(RecvIPv6PktInfo(ping.get(),
   393                                            reinterpret_cast<char*>(&recv_buf),
   394                                            &recv_buf_len, &received_pktinfo));
   395    ASSERT_EQ(recv_buf_len, sizeof(kSendIcmp));
   396  
   397    EXPECT_EQ(recv_buf.icmpv6.icmp6_type, ICMP6_ECHO_REPLY);
   398    EXPECT_EQ(recv_buf.icmpv6.icmp6_code, 0);
   399  
   400    EXPECT_EQ(received_pktinfo.ipi6_ifindex,
   401              ASSERT_NO_ERRNO_AND_VALUE(GetLoopbackIndex()));
   402    ASSERT_EQ(memcmp(&received_pktinfo.ipi6_addr, &in6addr_loopback,
   403                     sizeof(in6addr_loopback)),
   404              0);
   405  }
   406  
   407  struct BindTestCase {
   408    TestAddress bind_to;
   409    int want = 0;
   410    absl::optional<int> want_gvisor;
   411  };
   412  
   413  // Test fixture for socket binding.
   414  class Fixture
   415      : public ::testing::TestWithParam<std::tuple<SocketKind, BindTestCase>> {};
   416  
   417  TEST_P(Fixture, Bind) {
   418    auto [socket_factory, test_case] = GetParam();
   419    auto socket = socket_factory.Create();
   420    if (!socket.ok()) {
   421      ASSERT_EQ(socket.error().errno_value(), EACCES);
   422      GTEST_SKIP() << "TODO(gvisor.dev/issue/6126): Buildkite does not allow "
   423                      "creation of ICMP or ICMPv6 sockets";
   424    }
   425    auto socket_fd = std::move(socket).ValueOrDie();
   426  
   427    const int want = test_case.want_gvisor.has_value() && IsRunningOnGvisor()
   428                         ? *test_case.want_gvisor
   429                         : test_case.want;
   430    if (want == 0) {
   431      EXPECT_THAT(bind(socket_fd->get(), AsSockAddr(&test_case.bind_to.addr),
   432                       test_case.bind_to.addr_len),
   433                  SyscallSucceeds());
   434    } else {
   435      EXPECT_THAT(bind(socket_fd->get(), AsSockAddr(&test_case.bind_to.addr),
   436                       test_case.bind_to.addr_len),
   437                  SyscallFailsWithErrno(want));
   438    }
   439  }
   440  
   441  std::vector<std::tuple<SocketKind, BindTestCase>> ICMPTestCases() {
   442    return ApplyVec<std::tuple<SocketKind, BindTestCase>>(
   443        [](const BindTestCase& test_case) {
   444          return std::make_tuple(ICMPUnboundSocket(0), test_case);
   445        },
   446        std::vector<BindTestCase>{
   447            {
   448                .bind_to = V4Any(),
   449                .want = 0,
   450                .want_gvisor = 0,
   451            },
   452            {
   453                .bind_to = V4Broadcast(),
   454                .want = EADDRNOTAVAIL,
   455            },
   456            {
   457                .bind_to = V4Loopback(),
   458                .want = 0,
   459            },
   460            {
   461                .bind_to = V4LoopbackSubnetBroadcast(),
   462                .want = EADDRNOTAVAIL,
   463            },
   464            {
   465                .bind_to = V4Multicast(),
   466                .want = EADDRNOTAVAIL,
   467            },
   468            {
   469                .bind_to = V4MulticastAllHosts(),
   470                .want = EADDRNOTAVAIL,
   471            },
   472            {
   473                .bind_to = V4AddrStr("IPv4UnknownUnicast", "192.168.1.1"),
   474                .want = EADDRNOTAVAIL,
   475            },
   476            {
   477                .bind_to = V6Any(),
   478                .want = EAFNOSUPPORT,
   479            },
   480            {
   481                .bind_to = V6Loopback(),
   482                .want = EAFNOSUPPORT,
   483            },
   484            {
   485                .bind_to = V6Multicast(),
   486                .want = EAFNOSUPPORT,
   487            },
   488            {
   489                .bind_to = V6MulticastInterfaceLocalAllNodes(),
   490                .want = EAFNOSUPPORT,
   491            },
   492            {
   493                .bind_to = V6MulticastLinkLocalAllNodes(),
   494                .want = EAFNOSUPPORT,
   495            },
   496            {
   497                .bind_to = V6MulticastLinkLocalAllRouters(),
   498                .want = EAFNOSUPPORT,
   499            },
   500            {
   501                .bind_to = V6AddrStr("IPv6UnknownUnicast", "fc00::1"),
   502                .want = EAFNOSUPPORT,
   503            },
   504        });
   505  }
   506  
   507  std::vector<std::tuple<SocketKind, BindTestCase>> ICMPv6TestCases() {
   508    return ApplyVec<std::tuple<SocketKind, BindTestCase>>(
   509        [](const BindTestCase& test_case) {
   510          return std::make_tuple(ICMPv6UnboundSocket(0), test_case);
   511        },
   512        std::vector<BindTestCase>{
   513            {
   514                .bind_to = V4Any(),
   515                .want = EINVAL,
   516            },
   517            {
   518                .bind_to = V4Broadcast(),
   519                .want = EINVAL,
   520            },
   521            {
   522                .bind_to = V4Loopback(),
   523                .want = EINVAL,
   524            },
   525            {
   526                .bind_to = V4LoopbackSubnetBroadcast(),
   527                .want = EINVAL,
   528            },
   529            {
   530                .bind_to = V4Multicast(),
   531                .want = EINVAL,
   532            },
   533            {
   534                .bind_to = V4MulticastAllHosts(),
   535                .want = EINVAL,
   536            },
   537            {
   538                .bind_to = V4AddrStr("IPv4UnknownUnicast", "192.168.1.1"),
   539                .want = EINVAL,
   540            },
   541            {
   542                .bind_to = V6Any(),
   543                .want = 0,
   544            },
   545            {
   546                .bind_to = V6Loopback(),
   547                .want = 0,
   548            },
   549            // TODO(gvisor.dev/issue/6021): Remove want_gvisor from all the
   550            // multicast test cases below once ICMPv6 sockets return EINVAL when
   551            // binding to IPv6 multicast addresses.
   552            {
   553                .bind_to = V6Multicast(),
   554                .want = EINVAL,
   555                .want_gvisor = EADDRNOTAVAIL,
   556            },
   557            {
   558                .bind_to = V6MulticastInterfaceLocalAllNodes(),
   559                .want = EINVAL,
   560                .want_gvisor = EADDRNOTAVAIL,
   561            },
   562            {
   563                .bind_to = V6MulticastLinkLocalAllNodes(),
   564                .want = EINVAL,
   565                .want_gvisor = EADDRNOTAVAIL,
   566            },
   567            {
   568                .bind_to = V6MulticastLinkLocalAllRouters(),
   569                .want = EINVAL,
   570                .want_gvisor = EADDRNOTAVAIL,
   571            },
   572            {
   573                .bind_to = V6AddrStr("IPv6UnknownUnicast", "fc00::1"),
   574                .want = EADDRNOTAVAIL,
   575            },
   576        });
   577  }
   578  
   579  std::vector<std::tuple<SocketKind, BindTestCase>> AllTestCases() {
   580    return VecCat<std::tuple<SocketKind, BindTestCase>>(ICMPTestCases(),
   581                                                        ICMPv6TestCases());
   582  }
   583  
   584  std::string TestDescription(
   585      const ::testing::TestParamInfo<Fixture::ParamType>& info) {
   586    auto [socket_factory, test_case] = info.param;
   587    std::string name = absl::StrJoin(
   588        {socket_factory.description, test_case.bind_to.description}, "_");
   589    absl::c_replace_if(
   590        name, [](char c) { return !std::isalnum(c); }, '_');
   591    return name;
   592  }
   593  
   594  INSTANTIATE_TEST_SUITE_P(PingSockets, Fixture,
   595                           ::testing::ValuesIn(AllTestCases()), TestDescription);
   596  
   597  }  // namespace
   598  }  // namespace testing
   599  }  // namespace gvisor