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