gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/ip_socket_test_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/syscalls/linux/ip_socket_test_util.h"
    16  
    17  #include <net/if.h>
    18  #include <netinet/in.h>
    19  #include <netpacket/packet.h>
    20  #include <sys/socket.h>
    21  
    22  #include <cstring>
    23  
    24  namespace gvisor {
    25  namespace testing {
    26  
    27  using ::testing::IsNull;
    28  using ::testing::NotNull;
    29  
    30  uint32_t IPFromInetSockaddr(const struct sockaddr* addr) {
    31    auto* in_addr = reinterpret_cast<const struct sockaddr_in*>(addr);
    32    return in_addr->sin_addr.s_addr;
    33  }
    34  
    35  uint16_t PortFromInetSockaddr(const struct sockaddr* addr) {
    36    auto* in_addr = reinterpret_cast<const struct sockaddr_in*>(addr);
    37    return ntohs(in_addr->sin_port);
    38  }
    39  
    40  PosixErrorOr<int> InterfaceIndex(std::string name) {
    41    int index = if_nametoindex(name.c_str());
    42    if (index) {
    43      return index;
    44    }
    45    return PosixError(errno);
    46  }
    47  
    48  namespace {
    49  
    50  std::string DescribeSocketType(int type) {
    51    return absl::StrCat(((type & SOCK_NONBLOCK) != 0) ? "non-blocking " : "",
    52                        ((type & SOCK_CLOEXEC) != 0) ? "close-on-exec " : "");
    53  }
    54  
    55  }  // namespace
    56  
    57  SocketPairKind IPv6TCPAcceptBindSocketPair(int type) {
    58    std::string description =
    59        absl::StrCat(DescribeSocketType(type), "connected IPv6 TCP socket");
    60    return SocketPairKind{
    61        description, AF_INET6, type | SOCK_STREAM, IPPROTO_TCP,
    62        TCPAcceptBindSocketPairCreator(AF_INET6, type | SOCK_STREAM, 0,
    63                                       /* dual_stack = */ false)};
    64  }
    65  
    66  SocketPairKind IPv4TCPAcceptBindSocketPair(int type) {
    67    std::string description =
    68        absl::StrCat(DescribeSocketType(type), "connected IPv4 TCP socket");
    69    return SocketPairKind{
    70        description, AF_INET, type | SOCK_STREAM, IPPROTO_TCP,
    71        TCPAcceptBindSocketPairCreator(AF_INET, type | SOCK_STREAM, 0,
    72                                       /* dual_stack = */ false)};
    73  }
    74  
    75  SocketPairKind DualStackTCPAcceptBindSocketPair(int type) {
    76    std::string description =
    77        absl::StrCat(DescribeSocketType(type), "connected dual stack TCP socket");
    78    return SocketPairKind{
    79        description, AF_INET6, type | SOCK_STREAM, IPPROTO_TCP,
    80        TCPAcceptBindSocketPairCreator(AF_INET6, type | SOCK_STREAM, 0,
    81                                       /* dual_stack = */ true)};
    82  }
    83  
    84  SocketPairKind IPv6TCPAcceptBindPersistentListenerSocketPair(int type) {
    85    std::string description =
    86        absl::StrCat(DescribeSocketType(type), "connected IPv6 TCP socket");
    87    return SocketPairKind{description, AF_INET6, type | SOCK_STREAM, IPPROTO_TCP,
    88                          TCPAcceptBindPersistentListenerSocketPairCreator(
    89                              AF_INET6, type | SOCK_STREAM, 0,
    90                              /* dual_stack = */ false)};
    91  }
    92  
    93  SocketPairKind IPv4TCPAcceptBindPersistentListenerSocketPair(int type) {
    94    std::string description =
    95        absl::StrCat(DescribeSocketType(type), "connected IPv4 TCP socket");
    96    return SocketPairKind{description, AF_INET, type | SOCK_STREAM, IPPROTO_TCP,
    97                          TCPAcceptBindPersistentListenerSocketPairCreator(
    98                              AF_INET, type | SOCK_STREAM, 0,
    99                              /* dual_stack = */ false)};
   100  }
   101  
   102  SocketPairKind DualStackTCPAcceptBindPersistentListenerSocketPair(int type) {
   103    std::string description =
   104        absl::StrCat(DescribeSocketType(type), "connected dual stack TCP socket");
   105    return SocketPairKind{description, AF_INET6, type | SOCK_STREAM, IPPROTO_TCP,
   106                          TCPAcceptBindPersistentListenerSocketPairCreator(
   107                              AF_INET6, type | SOCK_STREAM, 0,
   108                              /* dual_stack = */ true)};
   109  }
   110  
   111  SocketPairKind IPv6UDPBidirectionalBindSocketPair(int type) {
   112    std::string description =
   113        absl::StrCat(DescribeSocketType(type), "connected IPv6 UDP socket");
   114    return SocketPairKind{
   115        description, AF_INET6, type | SOCK_DGRAM, IPPROTO_UDP,
   116        UDPBidirectionalBindSocketPairCreator(AF_INET6, type | SOCK_DGRAM, 0,
   117                                              /* dual_stack = */ false)};
   118  }
   119  
   120  SocketPairKind IPv4UDPBidirectionalBindSocketPair(int type) {
   121    std::string description =
   122        absl::StrCat(DescribeSocketType(type), "connected IPv4 UDP socket");
   123    return SocketPairKind{
   124        description, AF_INET, type | SOCK_DGRAM, IPPROTO_UDP,
   125        UDPBidirectionalBindSocketPairCreator(AF_INET, type | SOCK_DGRAM, 0,
   126                                              /* dual_stack = */ false)};
   127  }
   128  
   129  SocketPairKind DualStackUDPBidirectionalBindSocketPair(int type) {
   130    std::string description =
   131        absl::StrCat(DescribeSocketType(type), "connected dual stack UDP socket");
   132    return SocketPairKind{
   133        description, AF_INET6, type | SOCK_DGRAM, IPPROTO_UDP,
   134        UDPBidirectionalBindSocketPairCreator(AF_INET6, type | SOCK_DGRAM, 0,
   135                                              /* dual_stack = */ true)};
   136  }
   137  
   138  SocketPairKind IPv4UDPUnboundSocketPair(int type) {
   139    std::string description =
   140        absl::StrCat(DescribeSocketType(type), "IPv4 UDP socket");
   141    return SocketPairKind{
   142        description, AF_INET, type | SOCK_DGRAM, IPPROTO_UDP,
   143        UDPUnboundSocketPairCreator(AF_INET, type | SOCK_DGRAM, 0,
   144                                    /* dual_stack = */ false)};
   145  }
   146  
   147  SocketKind ICMPUnboundSocket(int type) {
   148    std::string description =
   149        absl::StrCat(DescribeSocketType(type), "ICMP socket");
   150    return SocketKind{
   151        description, AF_INET, type | SOCK_DGRAM, IPPROTO_ICMP,
   152        UnboundSocketCreator(AF_INET, type | SOCK_DGRAM, IPPROTO_ICMP)};
   153  }
   154  
   155  SocketKind ICMPv6UnboundSocket(int type) {
   156    std::string description =
   157        absl::StrCat(DescribeSocketType(type), "ICMPv6 socket");
   158    return SocketKind{
   159        description, AF_INET6, type | SOCK_DGRAM, IPPROTO_ICMPV6,
   160        UnboundSocketCreator(AF_INET6, type | SOCK_DGRAM, IPPROTO_ICMPV6)};
   161  }
   162  
   163  SocketKind IPv4RawUDPUnboundSocket(int type) {
   164    std::string description =
   165        absl::StrCat(DescribeSocketType(type), "IPv4 Raw UDP socket");
   166    return SocketKind{
   167        description, AF_INET, type | SOCK_RAW, IPPROTO_UDP,
   168        UnboundSocketCreator(AF_INET, type | SOCK_RAW, IPPROTO_UDP)};
   169  }
   170  
   171  SocketKind IPv4UDPUnboundSocket(int type) {
   172    std::string description =
   173        absl::StrCat(DescribeSocketType(type), "IPv4 UDP socket");
   174    return SocketKind{
   175        description, AF_INET, type | SOCK_DGRAM, IPPROTO_UDP,
   176        UnboundSocketCreator(AF_INET, type | SOCK_DGRAM, IPPROTO_UDP)};
   177  }
   178  
   179  SocketKind IPv6UDPUnboundSocket(int type) {
   180    std::string description =
   181        absl::StrCat(DescribeSocketType(type), "IPv6 UDP socket");
   182    return SocketKind{
   183        description, AF_INET6, type | SOCK_DGRAM, IPPROTO_UDP,
   184        UnboundSocketCreator(AF_INET6, type | SOCK_DGRAM, IPPROTO_UDP)};
   185  }
   186  
   187  SocketKind IPv4TCPUnboundSocket(int type) {
   188    std::string description =
   189        absl::StrCat(DescribeSocketType(type), "IPv4 TCP socket");
   190    return SocketKind{
   191        description, AF_INET, type | SOCK_STREAM, IPPROTO_TCP,
   192        UnboundSocketCreator(AF_INET, type | SOCK_STREAM, IPPROTO_TCP)};
   193  }
   194  
   195  SocketKind IPv6TCPUnboundSocket(int type) {
   196    std::string description =
   197        absl::StrCat(DescribeSocketType(type), "IPv6 TCP socket");
   198    return SocketKind{
   199        description, AF_INET6, type | SOCK_STREAM, IPPROTO_TCP,
   200        UnboundSocketCreator(AF_INET6, type | SOCK_STREAM, IPPROTO_TCP)};
   201  }
   202  
   203  std::string GetAddr4Str(const in_addr* a) {
   204    char str[INET_ADDRSTRLEN];
   205    return inet_ntop(AF_INET, a, str, sizeof(str));
   206  }
   207  
   208  std::string GetAddr6Str(const in6_addr* a) {
   209    char str[INET6_ADDRSTRLEN];
   210    return inet_ntop(AF_INET6, a, str, sizeof(str));
   211  }
   212  
   213  std::string GetAddrStr(const sockaddr* a) {
   214    switch (a->sa_family) {
   215      case AF_INET: {
   216        return GetAddr4Str(&(reinterpret_cast<const sockaddr_in*>(a)->sin_addr));
   217      }
   218      case AF_INET6: {
   219        return GetAddr6Str(
   220            &(reinterpret_cast<const sockaddr_in6*>(a)->sin6_addr));
   221      }
   222      case AF_PACKET: {
   223        const sockaddr_ll& ll = *reinterpret_cast<const sockaddr_ll*>(a);
   224        std::ostringstream ss;
   225        ss << std::hex;
   226        ss << std::showbase;
   227        ss << '{';
   228        ss << " protocol=" << ntohs(ll.sll_protocol);
   229        ss << " ifindex=" << ll.sll_ifindex;
   230        ss << " hatype=" << ll.sll_hatype;
   231        ss << " pkttype=" << static_cast<unsigned short>(ll.sll_pkttype);
   232        if (ll.sll_halen != 0) {
   233          ss << " addr=";
   234          for (unsigned char i = 0; i < ll.sll_halen; ++i) {
   235            if (i != 0) {
   236              ss << ':';
   237            }
   238            ss << static_cast<unsigned short>(ll.sll_addr[i]);
   239          }
   240        }
   241        ss << " }";
   242        return ss.str();
   243      }
   244      default: {
   245        std::ostringstream ss;
   246        ss << "invalid(sa_family=" << a->sa_family << ")";
   247        return ss.str();
   248      }
   249    }
   250  }
   251  
   252  namespace {
   253  template <typename T>
   254  void RecvCmsg(int sock, int cmsg_level, int cmsg_type, char buf[],
   255                size_t* buf_size, T* out_cmsg_value) {
   256    iovec iov = {
   257        iov.iov_base = buf,
   258        iov.iov_len = *buf_size,
   259    };
   260    // Add an extra byte to confirm we only read what we expected.
   261    alignas(struct cmsghdr) char control[CMSG_SPACE(sizeof(*out_cmsg_value)) + 1];
   262    msghdr msg = {
   263        .msg_iov = &iov,
   264        .msg_iovlen = 1,
   265        .msg_control = control,
   266        .msg_controllen = sizeof(control),
   267    };
   268  
   269    ASSERT_THAT(*buf_size = RetryEINTR(recvmsg)(sock, &msg, /*flags=*/0),
   270                SyscallSucceeds());
   271    ASSERT_EQ(msg.msg_controllen, CMSG_SPACE(sizeof(*out_cmsg_value)));
   272  
   273    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
   274    ASSERT_THAT(cmsg, NotNull());
   275    ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(*out_cmsg_value)));
   276    ASSERT_EQ(cmsg->cmsg_level, cmsg_level);
   277    ASSERT_EQ(cmsg->cmsg_type, cmsg_type);
   278    ASSERT_THAT(CMSG_NXTHDR(&msg, cmsg), IsNull());
   279  
   280    std::copy_n(CMSG_DATA(cmsg), sizeof(*out_cmsg_value),
   281                reinterpret_cast<uint8_t*>(out_cmsg_value));
   282  }
   283  
   284  template <typename T>
   285  void SendCmsg(int sock, int cmsg_level, int cmsg_type, char buf[],
   286                size_t buf_size, T cmsg_value) {
   287    iovec iov = {
   288        .iov_base = buf,
   289        .iov_len = buf_size,
   290    };
   291  
   292    std::vector<uint8_t> control(CMSG_SPACE(sizeof(cmsg_value)));
   293    msghdr msg = {
   294        .msg_iov = &iov,
   295        .msg_iovlen = 1,
   296        .msg_control = control.data(),
   297        .msg_controllen = CMSG_LEN(sizeof(cmsg_value)),
   298    };
   299  
   300    // Manually add control message.
   301    cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
   302    ASSERT_THAT(cmsg, NotNull());
   303    cmsg->cmsg_len = CMSG_LEN(sizeof(cmsg_value));
   304    cmsg->cmsg_level = cmsg_level;
   305    cmsg->cmsg_type = cmsg_type;
   306    std::copy_n(reinterpret_cast<uint8_t*>(&cmsg_value), sizeof(cmsg_value),
   307                CMSG_DATA(cmsg));
   308  
   309    ASSERT_THAT(RetryEINTR(sendmsg)(sock, &msg, 0),
   310                SyscallSucceedsWithValue(buf_size));
   311  }
   312  }  // namespace
   313  
   314  void RecvTOS(int sock, char buf[], size_t* buf_size, uint8_t* out_tos) {
   315    RecvCmsg(sock, SOL_IP, IP_TOS, buf, buf_size, out_tos);
   316  }
   317  
   318  void SendTOS(int sock, char buf[], size_t buf_size, uint8_t tos) {
   319    SendCmsg(sock, SOL_IP, IP_TOS, buf, buf_size, tos);
   320  }
   321  
   322  void RecvTClass(int sock, char buf[], size_t* buf_size, int* out_tclass) {
   323    RecvCmsg(sock, SOL_IPV6, IPV6_TCLASS, buf, buf_size, out_tclass);
   324  }
   325  
   326  void SendTClass(int sock, char buf[], size_t buf_size, int tclass) {
   327    SendCmsg(sock, SOL_IPV6, IPV6_TCLASS, buf, buf_size, tclass);
   328  }
   329  
   330  void RecvTTL(int sock, char buf[], size_t* buf_size, int* out_ttl) {
   331    RecvCmsg(sock, SOL_IP, IP_TTL, buf, buf_size, out_ttl);
   332  }
   333  
   334  void SendTTL(int sock, char buf[], size_t buf_size, int ttl) {
   335    SendCmsg(sock, SOL_IP, IP_TTL, buf, buf_size, ttl);
   336  }
   337  
   338  void RecvHopLimit(int sock, char buf[], size_t* buf_size, int* out_hoplimit) {
   339    RecvCmsg(sock, SOL_IPV6, IPV6_HOPLIMIT, buf, buf_size, out_hoplimit);
   340  }
   341  
   342  void SendHopLimit(int sock, char buf[], size_t buf_size, int hoplimit) {
   343    SendCmsg(sock, SOL_IPV6, IPV6_HOPLIMIT, buf, buf_size, hoplimit);
   344  }
   345  
   346  void RecvPktInfo(int sock, char buf[], size_t* buf_size,
   347                   in_pktinfo* out_pktinfo) {
   348    RecvCmsg(sock, SOL_IP, IP_PKTINFO, buf, buf_size, out_pktinfo);
   349  }
   350  
   351  void RecvIPv6PktInfo(int sock, char buf[], size_t* buf_size,
   352                       in6_pktinfo* out_pktinfo) {
   353    RecvCmsg(sock, SOL_IPV6, IPV6_PKTINFO, buf, buf_size, out_pktinfo);
   354  }
   355  
   356  }  // namespace testing
   357  }  // namespace gvisor