gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/udp_raw_socket.cc (about) 1 // Copyright 2023 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 <arpa/inet.h> 16 #include <fcntl.h> 17 #include <net/ethernet.h> 18 #include <netinet/icmp6.h> 19 #include <netinet/ip.h> 20 #include <netinet/ip6.h> 21 #include <netinet/ip_icmp.h> 22 #include <netinet/udp.h> 23 #include <netpacket/packet.h> 24 25 #ifdef __linux__ 26 #include <linux/errqueue.h> 27 #include <linux/filter.h> 28 #endif // __linux__ 29 #include <netinet/in.h> 30 #include <poll.h> 31 #include <sys/ioctl.h> 32 #include <sys/socket.h> 33 #include <sys/types.h> 34 35 #ifndef SIOCGSTAMP 36 #include <linux/sockios.h> 37 #endif 38 39 #include "gtest/gtest.h" 40 #include "test/util/capability_util.h" 41 #include "test/util/file_descriptor.h" 42 #include "test/util/posix_error.h" 43 #include "test/util/socket_util.h" 44 #include "test/util/test_util.h" 45 46 namespace gvisor { 47 namespace testing { 48 49 namespace { 50 51 // Tests for UDP that require raw socket access. 52 class UdpSocketRawTest : public ::testing::TestWithParam<int> {}; 53 54 TEST_P(UdpSocketRawTest, ReceiveWithZeroSourcePort) { 55 // UDP sockets can't bind to port 0, so send a UDP packet via a raw IP 56 // socket instead. If those aren't available, skip the test. 57 if (!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability())) { 58 GTEST_SKIP(); 59 } 60 61 FileDescriptor udp_socket = 62 ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_DGRAM, 0)); 63 sockaddr_storage bind_addr = InetLoopbackAddr(GetParam()); 64 ASSERT_THAT(bind(udp_socket.get(), AsSockAddr(&bind_addr), sizeof(bind_addr)), 65 SyscallSucceeds()); 66 socklen_t bind_addr_len = sizeof(bind_addr); 67 ASSERT_THAT( 68 getsockname(udp_socket.get(), AsSockAddr(&bind_addr), &bind_addr_len), 69 SyscallSucceeds()); 70 uint16_t udp_port = 71 ASSERT_NO_ERRNO_AND_VALUE(AddrPort(GetParam(), bind_addr)); 72 73 constexpr absl::string_view kMessage = "hi"; 74 75 // Set up the UDP body. 76 struct udphdr udphdr = { 77 .source = 0, 78 .dest = udp_port, 79 .len = htons(sizeof(udphdr) + kMessage.size()), 80 .check = 0, 81 }; 82 83 if (GetParam() == AF_INET) { 84 udphdr.check = UDPChecksum( 85 iphdr{ 86 .saddr = htonl(INADDR_LOOPBACK), 87 .daddr = htonl(INADDR_LOOPBACK), 88 }, 89 udphdr, kMessage.data(), kMessage.size()); 90 } else { 91 udphdr.check = UDPChecksum( 92 ip6_hdr{ 93 .ip6_src = in6addr_loopback, 94 .ip6_dst = in6addr_loopback, 95 }, 96 udphdr, kMessage.data(), kMessage.size()); 97 } 98 // Copy the header and the payload into our packet buffer. 99 char send_buf[sizeof(udphdr) + kMessage.size()]; 100 memcpy(send_buf, &udphdr, sizeof(udphdr)); 101 memcpy(send_buf + sizeof(udphdr), kMessage.data(), kMessage.size()); 102 103 { 104 // Send the packet out a raw socket. 105 struct sockaddr_storage raw_socket_addr = InetLoopbackAddr(GetParam()); 106 FileDescriptor raw_socket = 107 ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_RAW, IPPROTO_UDP)); 108 ASSERT_THAT(sendto(raw_socket.get(), send_buf, sizeof(send_buf), 0, 109 reinterpret_cast<struct sockaddr*>(&raw_socket_addr), 110 sizeof(raw_socket_addr)), 111 SyscallSucceedsWithValue(sizeof(send_buf))); 112 } 113 114 // Receive and validate the data. 115 char received[kMessage.size() + 1]; 116 struct sockaddr_storage src; 117 socklen_t addr2len = sizeof(src); 118 EXPECT_THAT(recvfrom(udp_socket.get(), received, sizeof(received), 0, 119 AsSockAddr(&src), &addr2len), 120 SyscallSucceedsWithValue(kMessage.size())); 121 ASSERT_EQ(src.ss_family, GetParam()); 122 ASSERT_EQ(ASSERT_NO_ERRNO_AND_VALUE(AddrPort(GetParam(), src)), 0); 123 ASSERT_EQ(absl::string_view(received, kMessage.size()), kMessage); 124 } 125 126 INSTANTIATE_TEST_SUITE_P(AllInetTests, UdpSocketRawTest, 127 ::testing::Values(AF_INET, AF_INET6)); 128 129 } // namespace 130 } // namespace testing 131 } // namespace gvisor