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

     1  // Copyright 2019 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/in.h>
    16  #include <netinet/ip.h>
    17  #include <netinet/ip_icmp.h>
    18  #include <netinet/udp.h>
    19  #include <poll.h>
    20  #include <sys/socket.h>
    21  #include <sys/types.h>
    22  #include <unistd.h>
    23  
    24  #include <algorithm>
    25  #include <cstring>
    26  
    27  #include "gtest/gtest.h"
    28  #include "absl/base/internal/endian.h"
    29  #include "test/syscalls/linux/unix_domain_socket_test_util.h"
    30  #include "test/util/capability_util.h"
    31  #include "test/util/file_descriptor.h"
    32  #include "test/util/socket_util.h"
    33  #include "test/util/test_util.h"
    34  
    35  namespace gvisor {
    36  namespace testing {
    37  
    38  namespace {
    39  
    40  // Tests for IPPROTO_RAW raw sockets, which implies IP_HDRINCL.
    41  class RawHDRINCL : public ::testing::Test {
    42   protected:
    43    // Creates a socket to be used in tests.
    44    void SetUp() override;
    45  
    46    // Closes the socket created by SetUp().
    47    void TearDown() override;
    48  
    49    // Returns a valid looback IP header with no payload.
    50    struct iphdr LoopbackHeader();
    51  
    52    // Fills in buf with an IP header, UDP header, and payload. Returns false if
    53    // buf_size isn't large enough to hold everything.
    54    bool FillPacket(char* buf, size_t buf_size, int port, const char* payload,
    55                    uint16_t payload_size);
    56  
    57    // The socket used for both reading and writing.
    58    int socket_;
    59  
    60    // The loopback address.
    61    struct sockaddr_in addr_;
    62  };
    63  
    64  void RawHDRINCL::SetUp() {
    65    if (!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability())) {
    66      ASSERT_THAT(socket(AF_INET, SOCK_RAW, IPPROTO_RAW),
    67                  SyscallFailsWithErrno(EPERM));
    68      GTEST_SKIP();
    69    }
    70  
    71    ASSERT_THAT(socket_ = socket(AF_INET, SOCK_RAW, IPPROTO_RAW),
    72                SyscallSucceeds());
    73  
    74    addr_ = {};
    75  
    76    addr_.sin_port = IPPROTO_IP;
    77    addr_.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    78    addr_.sin_family = AF_INET;
    79  }
    80  
    81  void RawHDRINCL::TearDown() {
    82    // TearDown will be run even if we skip the test.
    83    if (ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability())) {
    84      EXPECT_THAT(close(socket_), SyscallSucceeds());
    85    }
    86  }
    87  
    88  struct iphdr RawHDRINCL::LoopbackHeader() {
    89    struct iphdr hdr = {};
    90    hdr.ihl = 5;
    91    hdr.version = 4;
    92    hdr.tos = 0;
    93    hdr.tot_len = absl::gbswap_16(sizeof(hdr));
    94    hdr.id = 0;
    95    hdr.frag_off = 0;
    96    hdr.ttl = 7;
    97    hdr.protocol = 1;
    98    hdr.daddr = htonl(INADDR_LOOPBACK);
    99    // hdr.check is set by the network stack.
   100    // hdr.tot_len is set by the network stack.
   101    // hdr.saddr is set by the network stack.
   102    return hdr;
   103  }
   104  
   105  bool RawHDRINCL::FillPacket(char* buf, size_t buf_size, int port,
   106                              const char* payload, uint16_t payload_size) {
   107    if (buf_size < sizeof(struct iphdr) + sizeof(struct udphdr) + payload_size) {
   108      return false;
   109    }
   110  
   111    struct iphdr ip = LoopbackHeader();
   112    ip.protocol = IPPROTO_UDP;
   113  
   114    struct udphdr udp = {};
   115    udp.source = absl::gbswap_16(port);
   116    udp.dest = absl::gbswap_16(port);
   117    udp.len = absl::gbswap_16(sizeof(udp) + payload_size);
   118    udp.check = 0;
   119  
   120    memcpy(buf, reinterpret_cast<char*>(&ip), sizeof(ip));
   121    memcpy(buf + sizeof(ip), reinterpret_cast<char*>(&udp), sizeof(udp));
   122    memcpy(buf + sizeof(ip) + sizeof(udp), payload, payload_size);
   123  
   124    return true;
   125  }
   126  
   127  // We should be able to create multiple IPPROTO_RAW sockets. RawHDRINCL::Setup
   128  // creates the first one, so we only have to create one more here.
   129  TEST_F(RawHDRINCL, MultipleCreation) {
   130    int s2;
   131    ASSERT_THAT(s2 = socket(AF_INET, SOCK_RAW, IPPROTO_RAW), SyscallSucceeds());
   132  
   133    ASSERT_THAT(close(s2), SyscallSucceeds());
   134  }
   135  
   136  // Test that shutting down an unconnected socket fails.
   137  TEST_F(RawHDRINCL, FailShutdownWithoutConnect) {
   138    ASSERT_THAT(shutdown(socket_, SHUT_WR), SyscallFailsWithErrno(ENOTCONN));
   139    ASSERT_THAT(shutdown(socket_, SHUT_RD), SyscallFailsWithErrno(ENOTCONN));
   140  }
   141  
   142  // Test that listen() fails.
   143  TEST_F(RawHDRINCL, FailListen) {
   144    ASSERT_THAT(listen(socket_, 1), SyscallFailsWithErrno(ENOTSUP));
   145  }
   146  
   147  // Test that accept() fails.
   148  TEST_F(RawHDRINCL, FailAccept) {
   149    struct sockaddr saddr;
   150    socklen_t addrlen;
   151    ASSERT_THAT(accept(socket_, &saddr, &addrlen),
   152                SyscallFailsWithErrno(ENOTSUP));
   153  }
   154  
   155  // Test that the socket is writable immediately.
   156  TEST_F(RawHDRINCL, PollWritableImmediately) {
   157    struct pollfd pfd = {};
   158    pfd.fd = socket_;
   159    pfd.events = POLLOUT;
   160    ASSERT_THAT(RetryEINTR(poll)(&pfd, 1, 0), SyscallSucceedsWithValue(1));
   161  }
   162  
   163  // Test that the socket isn't readable.
   164  TEST_F(RawHDRINCL, NotReadable) {
   165    // Try to receive data with MSG_DONTWAIT, which returns immediately if there's
   166    // nothing to be read.
   167    char buf[117];
   168    ASSERT_THAT(RetryEINTR(recv)(socket_, buf, sizeof(buf), MSG_DONTWAIT),
   169                SyscallFailsWithErrno(EAGAIN));
   170  }
   171  
   172  // Test that we can connect() to a valid IP (loopback).
   173  TEST_F(RawHDRINCL, ConnectToLoopback) {
   174    ASSERT_THAT(connect(socket_, reinterpret_cast<struct sockaddr*>(&addr_),
   175                        sizeof(addr_)),
   176                SyscallSucceeds());
   177  }
   178  
   179  TEST_F(RawHDRINCL, SendWithoutConnectFails) {
   180    struct iphdr hdr = LoopbackHeader();
   181    ASSERT_THAT(send(socket_, &hdr, sizeof(hdr), 0),
   182                SyscallFailsWithErrno(EDESTADDRREQ));
   183  }
   184  
   185  // HDRINCL implies write-only. Verify that we can't read a packet sent to
   186  // loopback.
   187  TEST_F(RawHDRINCL, NotReadableAfterWrite) {
   188    ASSERT_THAT(connect(socket_, reinterpret_cast<struct sockaddr*>(&addr_),
   189                        sizeof(addr_)),
   190                SyscallSucceeds());
   191  
   192    // Construct a packet with an IP header, UDP header, and payload.
   193    constexpr char kPayload[] = "odst";
   194    char packet[sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(kPayload)];
   195    ASSERT_TRUE(FillPacket(packet, sizeof(packet), 40000 /* port */, kPayload,
   196                           sizeof(kPayload)));
   197  
   198    socklen_t addrlen = sizeof(addr_);
   199    ASSERT_NO_FATAL_FAILURE(
   200        sendto(socket_, reinterpret_cast<void*>(&packet), sizeof(packet), 0,
   201               reinterpret_cast<struct sockaddr*>(&addr_), addrlen));
   202  
   203    struct pollfd pfd = {};
   204    pfd.fd = socket_;
   205    pfd.events = POLLIN;
   206    ASSERT_THAT(RetryEINTR(poll)(&pfd, 1, 1000), SyscallSucceedsWithValue(0));
   207  }
   208  
   209  TEST_F(RawHDRINCL, WriteTooSmall) {
   210    ASSERT_THAT(connect(socket_, reinterpret_cast<struct sockaddr*>(&addr_),
   211                        sizeof(addr_)),
   212                SyscallSucceeds());
   213  
   214    // This is smaller than the size of an IP header.
   215    constexpr char kBuf[] = "JP5";
   216    ASSERT_THAT(send(socket_, kBuf, sizeof(kBuf), 0),
   217                SyscallFailsWithErrno(EINVAL));
   218  }
   219  
   220  // Bind to localhost.
   221  TEST_F(RawHDRINCL, BindToLocalhost) {
   222    ASSERT_THAT(
   223        bind(socket_, reinterpret_cast<struct sockaddr*>(&addr_), sizeof(addr_)),
   224        SyscallSucceeds());
   225  }
   226  
   227  // Bind to a different address.
   228  TEST_F(RawHDRINCL, BindToInvalid) {
   229    struct sockaddr_in bind_addr = {};
   230    bind_addr.sin_family = AF_INET;
   231    bind_addr.sin_addr = {1};  // 1.0.0.0 - An address that we can't bind to.
   232    ASSERT_THAT(bind(socket_, reinterpret_cast<struct sockaddr*>(&bind_addr),
   233                     sizeof(bind_addr)),
   234                SyscallFailsWithErrno(EADDRNOTAVAIL));
   235  }
   236  
   237  // Send and receive a packet.
   238  TEST_F(RawHDRINCL, SendAndReceive) {
   239    int port = 40000;
   240    if (!IsRunningOnGvisor()) {
   241      port = static_cast<short>(ASSERT_NO_ERRNO_AND_VALUE(
   242          PortAvailable(0, AddressFamily::kIpv4, SocketType::kUdp, false)));
   243    }
   244  
   245    // IPPROTO_RAW sockets are write-only. We'll have to open another socket to
   246    // read what we write.
   247    FileDescriptor udp_sock =
   248        ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_RAW, IPPROTO_UDP));
   249  
   250    // Construct a packet with an IP header, UDP header, and payload.
   251    constexpr char kPayload[] = "toto";
   252    char packet[sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(kPayload)];
   253    ASSERT_TRUE(
   254        FillPacket(packet, sizeof(packet), port, kPayload, sizeof(kPayload)));
   255  
   256    socklen_t addrlen = sizeof(addr_);
   257    ASSERT_NO_FATAL_FAILURE(sendto(socket_, &packet, sizeof(packet), 0,
   258                                   reinterpret_cast<struct sockaddr*>(&addr_),
   259                                   addrlen));
   260  
   261    // Receive the payload.
   262    char recv_buf[sizeof(packet)];
   263    struct sockaddr_in src;
   264    socklen_t src_size = sizeof(src);
   265    ASSERT_THAT(recvfrom(udp_sock.get(), recv_buf, sizeof(recv_buf), 0,
   266                         reinterpret_cast<struct sockaddr*>(&src), &src_size),
   267                SyscallSucceedsWithValue(sizeof(packet)));
   268    EXPECT_EQ(
   269        memcmp(kPayload, recv_buf + sizeof(struct iphdr) + sizeof(struct udphdr),
   270               sizeof(kPayload)),
   271        0);
   272    // The network stack should have set the source address.
   273    EXPECT_EQ(src.sin_family, AF_INET);
   274    EXPECT_EQ(absl::gbswap_32(src.sin_addr.s_addr), INADDR_LOOPBACK);
   275  }
   276  
   277  // Send and receive a packet where the sendto address is not the same as the
   278  // provided destination.
   279  TEST_F(RawHDRINCL, SendAndReceiveDifferentAddress) {
   280    int port = 40000;
   281    if (!IsRunningOnGvisor()) {
   282      port = static_cast<short>(ASSERT_NO_ERRNO_AND_VALUE(
   283          PortAvailable(0, AddressFamily::kIpv4, SocketType::kUdp, false)));
   284    }
   285  
   286    // IPPROTO_RAW sockets are write-only. We'll have to open another socket to
   287    // read what we write.
   288    FileDescriptor udp_sock =
   289        ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_RAW, IPPROTO_UDP));
   290  
   291    // Construct a packet with an IP header, UDP header, and payload.
   292    constexpr char kPayload[] = "toto";
   293    char packet[sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(kPayload)];
   294    ASSERT_TRUE(
   295        FillPacket(packet, sizeof(packet), port, kPayload, sizeof(kPayload)));
   296    // Overwrite the IP destination address with an IP we can't get to.
   297    constexpr int32_t kUnreachable = 42;
   298    struct iphdr iphdr = {};
   299    memcpy(&iphdr, packet, sizeof(iphdr));
   300    iphdr.daddr = kUnreachable;
   301    memcpy(packet, &iphdr, sizeof(iphdr));
   302  
   303    // Send to localhost via loopback.
   304    socklen_t addrlen = sizeof(addr_);
   305    ASSERT_NO_FATAL_FAILURE(sendto(socket_, &packet, sizeof(packet), 0,
   306                                   reinterpret_cast<struct sockaddr*>(&addr_),
   307                                   addrlen));
   308  
   309    // Receive the payload. Despite an unreachable destination address, sendto
   310    // should have sent the packet through loopback.
   311    char recv_buf[sizeof(packet)];
   312    struct sockaddr_in src;
   313    socklen_t src_size = sizeof(src);
   314    ASSERT_THAT(recvfrom(udp_sock.get(), recv_buf, sizeof(recv_buf), 0,
   315                         reinterpret_cast<struct sockaddr*>(&src), &src_size),
   316                SyscallSucceedsWithValue(sizeof(packet)));
   317    EXPECT_EQ(
   318        memcmp(kPayload, recv_buf + sizeof(struct iphdr) + sizeof(struct udphdr),
   319               sizeof(kPayload)),
   320        0);
   321    // The network stack should have set the source address.
   322    EXPECT_EQ(src.sin_family, AF_INET);
   323    EXPECT_EQ(absl::gbswap_32(src.sin_addr.s_addr), INADDR_LOOPBACK);
   324    struct iphdr recv_iphdr = {};
   325    memcpy(&recv_iphdr, recv_buf, sizeof(recv_iphdr));
   326    // The destination address is kUnreachable despite arriving via loopback.
   327    EXPECT_EQ(recv_iphdr.daddr, kUnreachable);
   328  }
   329  
   330  // Send and receive a packet w/ the IP_HDRINCL option set.
   331  TEST_F(RawHDRINCL, SendAndReceiveIPHdrIncl) {
   332    int port = 40000;
   333    if (!IsRunningOnGvisor()) {
   334      port = static_cast<short>(ASSERT_NO_ERRNO_AND_VALUE(
   335          PortAvailable(0, AddressFamily::kIpv4, SocketType::kUdp, false)));
   336    }
   337  
   338    FileDescriptor recv_sock =
   339        ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_RAW, IPPROTO_UDP));
   340  
   341    FileDescriptor send_sock =
   342        ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_RAW, IPPROTO_UDP));
   343  
   344    // Enable IP_HDRINCL option so that we can build and send w/ an IP
   345    // header.
   346    constexpr int kSockOptOn = 1;
   347    ASSERT_THAT(setsockopt(send_sock.get(), SOL_IP, IP_HDRINCL, &kSockOptOn,
   348                           sizeof(kSockOptOn)),
   349                SyscallSucceeds());
   350    // This is not strictly required but we do it to make sure that setting
   351    // IP_HDRINCL on a non IPPROTO_RAW socket does not prevent it from receiving
   352    // packets.
   353    ASSERT_THAT(setsockopt(recv_sock.get(), SOL_IP, IP_HDRINCL, &kSockOptOn,
   354                           sizeof(kSockOptOn)),
   355                SyscallSucceeds());
   356  
   357    // Construct a packet with an IP header, UDP header, and payload.
   358    constexpr char kPayload[] = "toto";
   359    char packet[sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(kPayload)];
   360    ASSERT_TRUE(
   361        FillPacket(packet, sizeof(packet), port, kPayload, sizeof(kPayload)));
   362  
   363    socklen_t addrlen = sizeof(addr_);
   364    ASSERT_NO_FATAL_FAILURE(sendto(send_sock.get(), &packet, sizeof(packet), 0,
   365                                   reinterpret_cast<struct sockaddr*>(&addr_),
   366                                   addrlen));
   367  
   368    // Receive the payload.
   369    char recv_buf[sizeof(packet)];
   370    struct sockaddr_in src;
   371    socklen_t src_size = sizeof(src);
   372    ASSERT_THAT(recvfrom(recv_sock.get(), recv_buf, sizeof(recv_buf), 0,
   373                         reinterpret_cast<struct sockaddr*>(&src), &src_size),
   374                SyscallSucceedsWithValue(sizeof(packet)));
   375    EXPECT_EQ(
   376        memcmp(kPayload, recv_buf + sizeof(struct iphdr) + sizeof(struct udphdr),
   377               sizeof(kPayload)),
   378        0);
   379    // The network stack should have set the source address.
   380    EXPECT_EQ(src.sin_family, AF_INET);
   381    EXPECT_EQ(absl::gbswap_32(src.sin_addr.s_addr), INADDR_LOOPBACK);
   382    struct iphdr iphdr = {};
   383    memcpy(&iphdr, recv_buf, sizeof(iphdr));
   384  
   385    // Also verify that the packet we just sent was not delivered to the
   386    // IPPROTO_RAW socket.
   387    {
   388      char recv_buf[sizeof(packet)];
   389      struct sockaddr_in src;
   390      socklen_t src_size = sizeof(src);
   391      ASSERT_THAT(recvfrom(socket_, recv_buf, sizeof(recv_buf), MSG_DONTWAIT,
   392                           reinterpret_cast<struct sockaddr*>(&src), &src_size),
   393                  SyscallFailsWithErrno(EAGAIN));
   394    }
   395  }
   396  
   397  }  // namespace
   398  
   399  }  // namespace testing
   400  }  // namespace gvisor