gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/udp_bind.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 <arpa/inet.h> 16 #include <sys/socket.h> 17 #include <sys/types.h> 18 19 #include "gtest/gtest.h" 20 #include "test/util/file_descriptor.h" 21 #include "test/util/socket_util.h" 22 #include "test/util/test_util.h" 23 24 namespace gvisor { 25 namespace testing { 26 27 namespace { 28 29 struct sockaddr_in_common { 30 sa_family_t sin_family; 31 in_port_t sin_port; 32 }; 33 34 struct SendtoTestParam { 35 // Human readable description of test parameter. 36 std::string description; 37 38 // Test is broken in gVisor, skip. 39 bool skip_on_gvisor; 40 41 // Domain for the socket that will do the sending. 42 int send_domain; 43 44 // Address to bind for the socket that will do the sending. 45 struct sockaddr_storage send_addr; 46 socklen_t send_addr_len; // 0 for unbound. 47 48 // Address to connect to for the socket that will do the sending. 49 struct sockaddr_storage connect_addr; 50 socklen_t connect_addr_len; // 0 for no connection. 51 52 // Domain for the socket that will do the receiving. 53 int recv_domain; 54 55 // Address to bind for the socket that will do the receiving. 56 struct sockaddr_storage recv_addr; 57 socklen_t recv_addr_len; 58 59 // Address to send to. 60 struct sockaddr_storage sendto_addr; 61 socklen_t sendto_addr_len; 62 63 // Expected errno for the sendto call. 64 std::vector<int> sendto_errnos; // empty on success. 65 }; 66 67 class SendtoTest : public ::testing::TestWithParam<SendtoTestParam> { 68 protected: 69 SendtoTest() { 70 // gUnit uses printf, so so will we. 71 printf("Testing with %s\n", GetParam().description.c_str()); 72 } 73 }; 74 75 TEST_P(SendtoTest, Sendto) { 76 auto param = GetParam(); 77 78 SKIP_IF(param.skip_on_gvisor && IsRunningOnGvisor()); 79 80 const FileDescriptor s1 = 81 ASSERT_NO_ERRNO_AND_VALUE(Socket(param.send_domain, SOCK_DGRAM, 0)); 82 const FileDescriptor s2 = 83 ASSERT_NO_ERRNO_AND_VALUE(Socket(param.recv_domain, SOCK_DGRAM, 0)); 84 85 if (param.send_addr_len > 0) { 86 ASSERT_THAT( 87 bind(s1.get(), AsSockAddr(¶m.send_addr), param.send_addr_len), 88 SyscallSucceeds()); 89 } 90 91 if (param.connect_addr_len > 0) { 92 ASSERT_THAT(connect(s1.get(), AsSockAddr(¶m.connect_addr), 93 param.connect_addr_len), 94 SyscallSucceeds()); 95 } 96 97 ASSERT_THAT(bind(s2.get(), AsSockAddr(¶m.recv_addr), param.recv_addr_len), 98 SyscallSucceeds()); 99 100 struct sockaddr_storage real_recv_addr = {}; 101 socklen_t real_recv_addr_len = param.recv_addr_len; 102 ASSERT_THAT( 103 getsockname(s2.get(), AsSockAddr(&real_recv_addr), &real_recv_addr_len), 104 SyscallSucceeds()); 105 106 ASSERT_EQ(real_recv_addr_len, param.recv_addr_len); 107 108 int recv_port = 109 reinterpret_cast<sockaddr_in_common*>(&real_recv_addr)->sin_port; 110 111 struct sockaddr_storage sendto_addr = param.sendto_addr; 112 reinterpret_cast<sockaddr_in_common*>(&sendto_addr)->sin_port = recv_port; 113 114 char buf[20] = {}; 115 if (!param.sendto_errnos.empty()) { 116 ASSERT_THAT( 117 RetryEINTR(sendto)(s1.get(), buf, sizeof(buf), 0, 118 AsSockAddr(&sendto_addr), param.sendto_addr_len), 119 SyscallFailsWithErrno(ElementOf(param.sendto_errnos))); 120 return; 121 } 122 123 ASSERT_THAT( 124 RetryEINTR(sendto)(s1.get(), buf, sizeof(buf), 0, 125 AsSockAddr(&sendto_addr), param.sendto_addr_len), 126 SyscallSucceedsWithValue(sizeof(buf))); 127 128 struct sockaddr_storage got_addr = {}; 129 socklen_t got_addr_len = sizeof(sockaddr_storage); 130 ASSERT_THAT(RetryEINTR(recvfrom)(s2.get(), buf, sizeof(buf), 0, 131 AsSockAddr(&got_addr), &got_addr_len), 132 SyscallSucceedsWithValue(sizeof(buf))); 133 134 ASSERT_GT(got_addr_len, sizeof(sockaddr_in_common)); 135 int got_port = reinterpret_cast<sockaddr_in_common*>(&got_addr)->sin_port; 136 137 struct sockaddr_storage sender_addr = {}; 138 socklen_t sender_addr_len = sizeof(sockaddr_storage); 139 ASSERT_THAT(getsockname(s1.get(), AsSockAddr(&sender_addr), &sender_addr_len), 140 SyscallSucceeds()); 141 142 ASSERT_GT(sender_addr_len, sizeof(sockaddr_in_common)); 143 int sender_port = 144 reinterpret_cast<sockaddr_in_common*>(&sender_addr)->sin_port; 145 146 EXPECT_EQ(got_port, sender_port); 147 } 148 149 socklen_t Ipv4Addr(sockaddr_storage* addr, int port = 0) { 150 auto addr4 = reinterpret_cast<sockaddr_in*>(addr); 151 addr4->sin_family = AF_INET; 152 addr4->sin_port = port; 153 inet_pton(AF_INET, "127.0.0.1", &addr4->sin_addr.s_addr); 154 return sizeof(struct sockaddr_in); 155 } 156 157 socklen_t Ipv6Addr(sockaddr_storage* addr, int port = 0) { 158 auto addr6 = reinterpret_cast<sockaddr_in6*>(addr); 159 addr6->sin6_family = AF_INET6; 160 addr6->sin6_port = port; 161 inet_pton(AF_INET6, "::1", &addr6->sin6_addr.s6_addr); 162 return sizeof(struct sockaddr_in6); 163 } 164 165 socklen_t Ipv4MappedIpv6Addr(sockaddr_storage* addr, int port = 0) { 166 auto addr6 = reinterpret_cast<sockaddr_in6*>(addr); 167 addr6->sin6_family = AF_INET6; 168 addr6->sin6_port = port; 169 inet_pton(AF_INET6, "::ffff:127.0.0.1", &addr6->sin6_addr.s6_addr); 170 return sizeof(struct sockaddr_in6); 171 } 172 173 INSTANTIATE_TEST_SUITE_P( 174 UdpBindTest, SendtoTest, 175 ::testing::Values( 176 []() { 177 SendtoTestParam param = {}; 178 param.description = "IPv4 mapped IPv6 sendto IPv4 mapped IPv6"; 179 param.send_domain = AF_INET6; 180 param.send_addr_len = Ipv4MappedIpv6Addr(¶m.send_addr); 181 param.recv_domain = AF_INET6; 182 param.recv_addr_len = Ipv4MappedIpv6Addr(¶m.recv_addr); 183 param.sendto_addr_len = Ipv4MappedIpv6Addr(¶m.sendto_addr); 184 return param; 185 }(), 186 []() { 187 SendtoTestParam param = {}; 188 param.description = "IPv6 sendto IPv6"; 189 param.send_domain = AF_INET6; 190 param.send_addr_len = Ipv6Addr(¶m.send_addr); 191 param.recv_domain = AF_INET6; 192 param.recv_addr_len = Ipv6Addr(¶m.recv_addr); 193 param.sendto_addr_len = Ipv6Addr(¶m.sendto_addr); 194 return param; 195 }(), 196 []() { 197 SendtoTestParam param = {}; 198 param.description = "IPv4 sendto IPv4"; 199 param.send_domain = AF_INET; 200 param.send_addr_len = Ipv4Addr(¶m.send_addr); 201 param.recv_domain = AF_INET; 202 param.recv_addr_len = Ipv4Addr(¶m.recv_addr); 203 param.sendto_addr_len = Ipv4Addr(¶m.sendto_addr); 204 return param; 205 }(), 206 []() { 207 SendtoTestParam param = {}; 208 param.description = "IPv4 mapped IPv6 sendto IPv4"; 209 param.send_domain = AF_INET6; 210 param.send_addr_len = Ipv4MappedIpv6Addr(¶m.send_addr); 211 param.recv_domain = AF_INET; 212 param.recv_addr_len = Ipv4Addr(¶m.recv_addr); 213 param.sendto_addr_len = Ipv4MappedIpv6Addr(¶m.sendto_addr); 214 return param; 215 }(), 216 []() { 217 SendtoTestParam param = {}; 218 param.description = "IPv4 sendto IPv4 mapped IPv6"; 219 param.send_domain = AF_INET; 220 param.send_addr_len = Ipv4Addr(¶m.send_addr); 221 param.recv_domain = AF_INET6; 222 param.recv_addr_len = Ipv4MappedIpv6Addr(¶m.recv_addr); 223 param.sendto_addr_len = Ipv4Addr(¶m.sendto_addr); 224 return param; 225 }(), 226 []() { 227 SendtoTestParam param = {}; 228 param.description = "unbound IPv6 sendto IPv4 mapped IPv6"; 229 param.send_domain = AF_INET6; 230 param.recv_domain = AF_INET6; 231 param.recv_addr_len = Ipv4MappedIpv6Addr(¶m.recv_addr); 232 param.sendto_addr_len = Ipv4MappedIpv6Addr(¶m.sendto_addr); 233 return param; 234 }(), 235 []() { 236 SendtoTestParam param = {}; 237 param.description = "unbound IPv6 sendto IPv4"; 238 param.send_domain = AF_INET6; 239 param.recv_domain = AF_INET; 240 param.recv_addr_len = Ipv4Addr(¶m.recv_addr); 241 param.sendto_addr_len = Ipv4MappedIpv6Addr(¶m.sendto_addr); 242 return param; 243 }(), 244 []() { 245 SendtoTestParam param = {}; 246 param.description = "IPv6 sendto IPv4"; 247 param.send_domain = AF_INET6; 248 param.send_addr_len = Ipv6Addr(¶m.send_addr); 249 param.recv_domain = AF_INET; 250 param.recv_addr_len = Ipv4Addr(¶m.recv_addr); 251 param.sendto_addr_len = Ipv4MappedIpv6Addr(¶m.sendto_addr); 252 param.sendto_errnos = {ENETUNREACH}; 253 return param; 254 }(), 255 []() { 256 SendtoTestParam param = {}; 257 param.description = "IPv4 mapped IPv6 sendto IPv6"; 258 param.send_domain = AF_INET6; 259 param.send_addr_len = Ipv4MappedIpv6Addr(¶m.send_addr); 260 param.recv_domain = AF_INET6; 261 param.recv_addr_len = Ipv6Addr(¶m.recv_addr); 262 param.sendto_addr_len = Ipv6Addr(¶m.sendto_addr); 263 param.sendto_errnos = {EAFNOSUPPORT}; 264 // The errno returned changed in Linux commit c8e6ad0829a723. 265 param.sendto_errnos = {EINVAL, EAFNOSUPPORT}; 266 return param; 267 }(), 268 []() { 269 SendtoTestParam param = {}; 270 param.description = "connected IPv4 mapped IPv6 sendto IPv6"; 271 param.send_domain = AF_INET6; 272 param.connect_addr_len = 273 Ipv4MappedIpv6Addr(¶m.connect_addr, 5000); 274 param.recv_domain = AF_INET6; 275 param.recv_addr_len = Ipv6Addr(¶m.recv_addr); 276 param.sendto_addr_len = Ipv6Addr(¶m.sendto_addr); 277 // The errno returned changed in Linux commit c8e6ad0829a723. 278 param.sendto_errnos = {EINVAL, EAFNOSUPPORT}; 279 return param; 280 }(), 281 []() { 282 SendtoTestParam param = {}; 283 param.description = "connected IPv6 sendto IPv4 mapped IPv6"; 284 // TODO(igudger): Determine if this inconsistent behavior is worth 285 // implementing. 286 param.skip_on_gvisor = true; 287 param.send_domain = AF_INET6; 288 param.connect_addr_len = Ipv6Addr(¶m.connect_addr, 5000); 289 param.recv_domain = AF_INET6; 290 param.recv_addr_len = Ipv4MappedIpv6Addr(¶m.recv_addr); 291 param.sendto_addr_len = Ipv4MappedIpv6Addr(¶m.sendto_addr); 292 return param; 293 }(), 294 []() { 295 SendtoTestParam param = {}; 296 param.description = "connected IPv6 sendto IPv4"; 297 // TODO(igudger): Determine if this inconsistent behavior is worth 298 // implementing. 299 param.skip_on_gvisor = true; 300 param.send_domain = AF_INET6; 301 param.connect_addr_len = Ipv6Addr(¶m.connect_addr, 5000); 302 param.recv_domain = AF_INET; 303 param.recv_addr_len = Ipv4Addr(¶m.recv_addr); 304 param.sendto_addr_len = Ipv4MappedIpv6Addr(¶m.sendto_addr); 305 return param; 306 }())); 307 308 } // namespace 309 310 } // namespace testing 311 } // namespace gvisor