github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/ping_socket.cc (about) 1 // Copyright 2020 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 <errno.h> 16 #include <netinet/in.h> 17 #include <netinet/ip.h> 18 #include <netinet/ip_icmp.h> 19 #include <sys/socket.h> 20 #include <sys/types.h> 21 #include <unistd.h> 22 23 #include <cctype> 24 #include <cstring> 25 #include <vector> 26 27 #include "gtest/gtest.h" 28 #include "absl/algorithm/container.h" 29 #include "absl/strings/str_join.h" 30 #include "absl/types/optional.h" 31 #include "test/syscalls/linux/ip_socket_test_util.h" 32 #include "test/syscalls/linux/socket_test_util.h" 33 #include "test/util/file_descriptor.h" 34 #include "test/util/test_util.h" 35 36 // Note: These tests require /proc/sys/net/ipv4/ping_group_range to be 37 // configured to allow the tester to create ping sockets (see icmp(7)). 38 39 namespace gvisor { 40 namespace testing { 41 namespace { 42 43 // Test ICMP port exhaustion returns EAGAIN. 44 // 45 // We disable both random/cooperative S/R for this test as it makes way too many 46 // syscalls. 47 TEST(PingSocket, ICMPPortExhaustion) { 48 DisableSave ds; 49 50 { 51 auto s = Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 52 if (!s.ok()) { 53 ASSERT_EQ(s.error().errno_value(), EACCES); 54 GTEST_SKIP() << "TODO(gvisor.dev/issue/6126): Buildkite does not allow " 55 "creation of ICMP or ICMPv6 sockets"; 56 } 57 } 58 59 const struct sockaddr_in addr = { 60 .sin_family = AF_INET, 61 .sin_addr = 62 { 63 .s_addr = htonl(INADDR_LOOPBACK), 64 }, 65 }; 66 67 std::vector<FileDescriptor> sockets; 68 constexpr int kSockets = 65536; 69 for (int i = 0; i < kSockets; i++) { 70 auto s = 71 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP)); 72 int ret = connect(s.get(), reinterpret_cast<const struct sockaddr*>(&addr), 73 sizeof(addr)); 74 if (ret == 0) { 75 sockets.push_back(std::move(s)); 76 continue; 77 } 78 ASSERT_THAT(ret, SyscallFailsWithErrno(EAGAIN)); 79 break; 80 } 81 } 82 83 struct BindTestCase { 84 TestAddress bind_to; 85 int want = 0; 86 absl::optional<int> want_gvisor; 87 }; 88 89 // Test fixture for socket binding. 90 class Fixture 91 : public ::testing::TestWithParam<std::tuple<SocketKind, BindTestCase>> {}; 92 93 TEST_P(Fixture, Bind) { 94 auto [socket_factory, test_case] = GetParam(); 95 auto socket = socket_factory.Create(); 96 if (!socket.ok()) { 97 ASSERT_EQ(socket.error().errno_value(), EACCES); 98 GTEST_SKIP() << "TODO(gvisor.dev/issue/6126): Buildkite does not allow " 99 "creation of ICMP or ICMPv6 sockets"; 100 } 101 auto socket_fd = std::move(socket).ValueOrDie(); 102 103 const int want = test_case.want_gvisor.has_value() && IsRunningOnGvisor() 104 ? *test_case.want_gvisor 105 : test_case.want; 106 if (want == 0) { 107 EXPECT_THAT(bind(socket_fd->get(), AsSockAddr(&test_case.bind_to.addr), 108 test_case.bind_to.addr_len), 109 SyscallSucceeds()); 110 } else { 111 EXPECT_THAT(bind(socket_fd->get(), AsSockAddr(&test_case.bind_to.addr), 112 test_case.bind_to.addr_len), 113 SyscallFailsWithErrno(want)); 114 } 115 } 116 117 std::vector<std::tuple<SocketKind, BindTestCase>> ICMPTestCases() { 118 return ApplyVec<std::tuple<SocketKind, BindTestCase>>( 119 [](const BindTestCase& test_case) { 120 return std::make_tuple(ICMPUnboundSocket(0), test_case); 121 }, 122 std::vector<BindTestCase>{ 123 { 124 .bind_to = V4Any(), 125 .want = 0, 126 .want_gvisor = 0, 127 }, 128 { 129 .bind_to = V4Broadcast(), 130 .want = EADDRNOTAVAIL, 131 // TODO(gvisor.dev/issue/5711): Remove want_gvisor once ICMP 132 // sockets are no longer allowed to bind to broadcast addresses. 133 .want_gvisor = 0, 134 }, 135 { 136 .bind_to = V4Loopback(), 137 .want = 0, 138 }, 139 { 140 .bind_to = V4LoopbackSubnetBroadcast(), 141 .want = EADDRNOTAVAIL, 142 // TODO(gvisor.dev/issue/5711): Remove want_gvisor once ICMP 143 // sockets are no longer allowed to bind to broadcast addresses. 144 .want_gvisor = 0, 145 }, 146 { 147 .bind_to = V4Multicast(), 148 .want = EADDRNOTAVAIL, 149 }, 150 { 151 .bind_to = V4MulticastAllHosts(), 152 .want = EADDRNOTAVAIL, 153 }, 154 { 155 .bind_to = V4AddrStr("IPv4UnknownUnicast", "192.168.1.1"), 156 .want = EADDRNOTAVAIL, 157 }, 158 // TODO(gvisor.dev/issue/6021): Remove want_gvisor from all the test 159 // cases below once ICMP sockets return EAFNOSUPPORT when binding to 160 // IPv6 addresses. 161 { 162 .bind_to = V6Any(), 163 .want = EAFNOSUPPORT, 164 .want_gvisor = EINVAL, 165 }, 166 { 167 .bind_to = V6Loopback(), 168 .want = EAFNOSUPPORT, 169 .want_gvisor = EINVAL, 170 }, 171 { 172 .bind_to = V6Multicast(), 173 .want = EAFNOSUPPORT, 174 .want_gvisor = EINVAL, 175 }, 176 { 177 .bind_to = V6MulticastInterfaceLocalAllNodes(), 178 .want = EAFNOSUPPORT, 179 .want_gvisor = EINVAL, 180 }, 181 { 182 .bind_to = V6MulticastLinkLocalAllNodes(), 183 .want = EAFNOSUPPORT, 184 .want_gvisor = EINVAL, 185 }, 186 { 187 .bind_to = V6MulticastLinkLocalAllRouters(), 188 .want = EAFNOSUPPORT, 189 .want_gvisor = EINVAL, 190 }, 191 { 192 .bind_to = V6AddrStr("IPv6UnknownUnicast", "fc00::1"), 193 .want = EAFNOSUPPORT, 194 .want_gvisor = EINVAL, 195 }, 196 }); 197 } 198 199 std::vector<std::tuple<SocketKind, BindTestCase>> ICMPv6TestCases() { 200 return ApplyVec<std::tuple<SocketKind, BindTestCase>>( 201 [](const BindTestCase& test_case) { 202 return std::make_tuple(ICMPv6UnboundSocket(0), test_case); 203 }, 204 std::vector<BindTestCase>{ 205 { 206 .bind_to = V4Any(), 207 .want = EINVAL, 208 }, 209 { 210 .bind_to = V4Broadcast(), 211 .want = EINVAL, 212 }, 213 { 214 .bind_to = V4Loopback(), 215 .want = EINVAL, 216 }, 217 { 218 .bind_to = V4LoopbackSubnetBroadcast(), 219 .want = EINVAL, 220 }, 221 { 222 .bind_to = V4Multicast(), 223 .want = EINVAL, 224 }, 225 { 226 .bind_to = V4MulticastAllHosts(), 227 .want = EINVAL, 228 }, 229 { 230 .bind_to = V4AddrStr("IPv4UnknownUnicast", "192.168.1.1"), 231 .want = EINVAL, 232 }, 233 { 234 .bind_to = V6Any(), 235 .want = 0, 236 }, 237 { 238 .bind_to = V6Loopback(), 239 .want = 0, 240 }, 241 // TODO(gvisor.dev/issue/6021): Remove want_gvisor from all the 242 // multicast test cases below once ICMPv6 sockets return EINVAL when 243 // binding to IPv6 multicast addresses. 244 { 245 .bind_to = V6Multicast(), 246 .want = EINVAL, 247 .want_gvisor = EADDRNOTAVAIL, 248 }, 249 { 250 .bind_to = V6MulticastInterfaceLocalAllNodes(), 251 .want = EINVAL, 252 .want_gvisor = EADDRNOTAVAIL, 253 }, 254 { 255 .bind_to = V6MulticastLinkLocalAllNodes(), 256 .want = EINVAL, 257 .want_gvisor = EADDRNOTAVAIL, 258 }, 259 { 260 .bind_to = V6MulticastLinkLocalAllRouters(), 261 .want = EINVAL, 262 .want_gvisor = EADDRNOTAVAIL, 263 }, 264 { 265 .bind_to = V6AddrStr("IPv6UnknownUnicast", "fc00::1"), 266 .want = EADDRNOTAVAIL, 267 }, 268 }); 269 } 270 271 std::vector<std::tuple<SocketKind, BindTestCase>> AllTestCases() { 272 return VecCat<std::tuple<SocketKind, BindTestCase>>(ICMPTestCases(), 273 ICMPv6TestCases()); 274 } 275 276 std::string TestDescription( 277 const ::testing::TestParamInfo<Fixture::ParamType>& info) { 278 auto [socket_factory, test_case] = info.param; 279 std::string name = absl::StrJoin( 280 {socket_factory.description, test_case.bind_to.description}, "_"); 281 absl::c_replace_if( 282 name, [](char c) { return !std::isalnum(c); }, '_'); 283 return name; 284 } 285 286 INSTANTIATE_TEST_SUITE_P(PingSockets, Fixture, 287 ::testing::ValuesIn(AllTestCases()), TestDescription); 288 289 } // namespace 290 } // namespace testing 291 } // namespace gvisor