github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/socket_netlink_route.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 <fcntl.h> 17 #include <ifaddrs.h> 18 #include <linux/if.h> 19 #include <linux/netlink.h> 20 #include <linux/rtnetlink.h> 21 #include <sys/socket.h> 22 #include <sys/types.h> 23 #include <unistd.h> 24 25 #include <iostream> 26 #include <vector> 27 28 #include "gtest/gtest.h" 29 #include "absl/strings/str_format.h" 30 #include "test/syscalls/linux/socket_netlink_route_util.h" 31 #include "test/syscalls/linux/socket_netlink_util.h" 32 #include "test/syscalls/linux/socket_test_util.h" 33 #include "test/util/capability_util.h" 34 #include "test/util/cleanup.h" 35 #include "test/util/file_descriptor.h" 36 #include "test/util/test_util.h" 37 38 // Tests for NETLINK_ROUTE sockets. 39 40 namespace gvisor { 41 namespace testing { 42 43 namespace { 44 45 constexpr uint32_t kSeq = 12345; 46 47 using ::testing::AnyOf; 48 using ::testing::Eq; 49 50 // Parameters for SockOptTest. They are: 51 // 0: Socket option to query. 52 // 1: A predicate to run on the returned sockopt value. Should return true if 53 // the value is considered ok. 54 // 2: A description of what the sockopt value is expected to be. Should complete 55 // the sentence "<value> was unexpected, expected <description>" 56 using SockOptTest = ::testing::TestWithParam< 57 std::tuple<int, std::function<bool(int)>, std::string>>; 58 59 TEST_P(SockOptTest, GetSockOpt) { 60 int sockopt = std::get<0>(GetParam()); 61 auto verifier = std::get<1>(GetParam()); 62 std::string verifier_description = std::get<2>(GetParam()); 63 64 FileDescriptor fd = 65 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)); 66 67 int res; 68 socklen_t len = sizeof(res); 69 70 EXPECT_THAT(getsockopt(fd.get(), SOL_SOCKET, sockopt, &res, &len), 71 SyscallSucceeds()); 72 73 EXPECT_EQ(len, sizeof(res)); 74 EXPECT_TRUE(verifier(res)) << absl::StrFormat( 75 "getsockopt(%d, SOL_SOCKET, %d, &res, &len) => res=%d was unexpected, " 76 "expected %s", 77 fd.get(), sockopt, res, verifier_description); 78 } 79 80 std::function<bool(int)> IsPositive() { 81 return [](int val) { return val > 0; }; 82 } 83 84 std::function<bool(int)> IsEqual(int target) { 85 return [target](int val) { return val == target; }; 86 } 87 88 INSTANTIATE_TEST_SUITE_P( 89 NetlinkRouteTest, SockOptTest, 90 ::testing::Values( 91 std::make_tuple(SO_SNDBUF, IsPositive(), "positive send buffer size"), 92 std::make_tuple(SO_RCVBUF, IsPositive(), 93 "positive receive buffer size"), 94 std::make_tuple(SO_TYPE, IsEqual(SOCK_RAW), 95 absl::StrFormat("SOCK_RAW (%d)", SOCK_RAW)), 96 std::make_tuple(SO_DOMAIN, IsEqual(AF_NETLINK), 97 absl::StrFormat("AF_NETLINK (%d)", AF_NETLINK)), 98 std::make_tuple(SO_PROTOCOL, IsEqual(NETLINK_ROUTE), 99 absl::StrFormat("NETLINK_ROUTE (%d)", NETLINK_ROUTE)), 100 std::make_tuple(SO_PASSCRED, IsEqual(0), "0"))); 101 102 // Validates the reponses to RTM_GETLINK + NLM_F_DUMP. 103 void CheckGetLinkResponse(const struct nlmsghdr* hdr, int seq, int port) { 104 EXPECT_THAT(hdr->nlmsg_type, AnyOf(Eq(RTM_NEWLINK), Eq(NLMSG_DONE))); 105 106 EXPECT_TRUE((hdr->nlmsg_flags & NLM_F_MULTI) == NLM_F_MULTI) 107 << std::hex << hdr->nlmsg_flags; 108 109 EXPECT_EQ(hdr->nlmsg_seq, seq); 110 EXPECT_EQ(hdr->nlmsg_pid, port); 111 112 if (hdr->nlmsg_type != RTM_NEWLINK) { 113 return; 114 } 115 116 // RTM_NEWLINK contains at least the header and ifinfomsg. 117 EXPECT_GE(hdr->nlmsg_len, NLMSG_SPACE(sizeof(struct ifinfomsg))); 118 119 // TODO(mpratt): Check ifinfomsg contents and following attrs. 120 } 121 122 TEST(NetlinkRouteTest, GetLinkDump) { 123 FileDescriptor fd = 124 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 125 uint32_t port = ASSERT_NO_ERRNO_AND_VALUE(NetlinkPortID(fd.get())); 126 127 // Loopback is common among all tests, check that it's found. 128 bool loopbackFound = false; 129 ASSERT_NO_ERRNO(DumpLinks(fd, kSeq, [&](const struct nlmsghdr* hdr) { 130 CheckGetLinkResponse(hdr, kSeq, port); 131 if (hdr->nlmsg_type != RTM_NEWLINK) { 132 return; 133 } 134 ASSERT_GE(hdr->nlmsg_len, NLMSG_SPACE(sizeof(struct ifinfomsg))); 135 const struct ifinfomsg* msg = 136 reinterpret_cast<const struct ifinfomsg*>(NLMSG_DATA(hdr)); 137 std::cout << "Found interface idx=" << msg->ifi_index 138 << ", type=" << std::hex << msg->ifi_type << std::endl; 139 if (msg->ifi_type == ARPHRD_LOOPBACK) { 140 loopbackFound = true; 141 EXPECT_NE(msg->ifi_flags & IFF_LOOPBACK, 0); 142 } 143 })); 144 EXPECT_TRUE(loopbackFound); 145 } 146 147 // CheckLinkMsg checks a netlink message against an expected link. 148 void CheckLinkMsg(const struct nlmsghdr* hdr, const Link& link) { 149 ASSERT_THAT(hdr->nlmsg_type, Eq(RTM_NEWLINK)); 150 ASSERT_GE(hdr->nlmsg_len, NLMSG_SPACE(sizeof(struct ifinfomsg))); 151 const struct ifinfomsg* msg = 152 reinterpret_cast<const struct ifinfomsg*>(NLMSG_DATA(hdr)); 153 EXPECT_EQ(msg->ifi_index, link.index); 154 155 const struct rtattr* rta = FindRtAttr(hdr, msg, IFLA_IFNAME); 156 EXPECT_NE(nullptr, rta) << "IFLA_IFNAME not found in message."; 157 if (rta != nullptr) { 158 std::string name(reinterpret_cast<const char*>(RTA_DATA(rta))); 159 EXPECT_EQ(name, link.name); 160 } 161 } 162 163 TEST(NetlinkRouteTest, GetLinkByIndex) { 164 Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink()); 165 166 FileDescriptor fd = 167 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 168 169 struct request { 170 struct nlmsghdr hdr; 171 struct ifinfomsg ifm; 172 }; 173 174 struct request req = {}; 175 req.hdr.nlmsg_len = sizeof(req); 176 req.hdr.nlmsg_type = RTM_GETLINK; 177 req.hdr.nlmsg_flags = NLM_F_REQUEST; 178 req.hdr.nlmsg_seq = kSeq; 179 req.ifm.ifi_family = AF_UNSPEC; 180 req.ifm.ifi_index = loopback_link.index; 181 182 bool found = false; 183 ASSERT_NO_ERRNO(NetlinkRequestResponse( 184 fd, &req, sizeof(req), 185 [&](const struct nlmsghdr* hdr) { 186 CheckLinkMsg(hdr, loopback_link); 187 found = true; 188 }, 189 false)); 190 EXPECT_TRUE(found) << "Netlink response does not contain any links."; 191 } 192 193 TEST(NetlinkRouteTest, GetLinkByName) { 194 Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink()); 195 196 FileDescriptor fd = 197 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 198 199 struct request { 200 struct nlmsghdr hdr; 201 struct ifinfomsg ifm; 202 struct rtattr rtattr; 203 char ifname[IFNAMSIZ]; 204 char pad[NLMSG_ALIGNTO + RTA_ALIGNTO]; 205 }; 206 207 struct request req = {}; 208 req.hdr.nlmsg_type = RTM_GETLINK; 209 req.hdr.nlmsg_flags = NLM_F_REQUEST; 210 req.hdr.nlmsg_seq = kSeq; 211 req.ifm.ifi_family = AF_UNSPEC; 212 req.rtattr.rta_type = IFLA_IFNAME; 213 req.rtattr.rta_len = RTA_LENGTH(loopback_link.name.size() + 1); 214 strncpy(req.ifname, loopback_link.name.c_str(), sizeof(req.ifname)); 215 req.hdr.nlmsg_len = 216 NLMSG_LENGTH(sizeof(req.ifm)) + NLMSG_ALIGN(req.rtattr.rta_len); 217 218 bool found = false; 219 ASSERT_NO_ERRNO(NetlinkRequestResponse( 220 fd, &req, sizeof(req), 221 [&](const struct nlmsghdr* hdr) { 222 CheckLinkMsg(hdr, loopback_link); 223 found = true; 224 }, 225 false)); 226 EXPECT_TRUE(found) << "Netlink response does not contain any links."; 227 } 228 229 TEST(NetlinkRouteTest, GetLinkByIndexNotFound) { 230 FileDescriptor fd = 231 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 232 233 struct request { 234 struct nlmsghdr hdr; 235 struct ifinfomsg ifm; 236 }; 237 238 struct request req = {}; 239 req.hdr.nlmsg_len = sizeof(req); 240 req.hdr.nlmsg_type = RTM_GETLINK; 241 req.hdr.nlmsg_flags = NLM_F_REQUEST; 242 req.hdr.nlmsg_seq = kSeq; 243 req.ifm.ifi_family = AF_UNSPEC; 244 req.ifm.ifi_index = 1234590; 245 246 EXPECT_THAT(NetlinkRequestAckOrError(fd, kSeq, &req, sizeof(req)), 247 PosixErrorIs(ENODEV, ::testing::_)); 248 } 249 250 TEST(NetlinkRouteTest, GetLinkByNameNotFound) { 251 const std::string name = "nodevice?!"; 252 253 FileDescriptor fd = 254 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 255 256 struct request { 257 struct nlmsghdr hdr; 258 struct ifinfomsg ifm; 259 struct rtattr rtattr; 260 char ifname[IFNAMSIZ]; 261 char pad[NLMSG_ALIGNTO + RTA_ALIGNTO]; 262 }; 263 264 struct request req = {}; 265 req.hdr.nlmsg_type = RTM_GETLINK; 266 req.hdr.nlmsg_flags = NLM_F_REQUEST; 267 req.hdr.nlmsg_seq = kSeq; 268 req.ifm.ifi_family = AF_UNSPEC; 269 req.rtattr.rta_type = IFLA_IFNAME; 270 req.rtattr.rta_len = RTA_LENGTH(name.size() + 1); 271 strncpy(req.ifname, name.c_str(), sizeof(req.ifname)); 272 req.hdr.nlmsg_len = 273 NLMSG_LENGTH(sizeof(req.ifm)) + NLMSG_ALIGN(req.rtattr.rta_len); 274 275 EXPECT_THAT(NetlinkRequestAckOrError(fd, kSeq, &req, sizeof(req)), 276 PosixErrorIs(ENODEV, ::testing::_)); 277 } 278 279 TEST(NetlinkRouteTest, MsgHdrMsgUnsuppType) { 280 FileDescriptor fd = 281 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 282 283 struct request { 284 struct nlmsghdr hdr; 285 struct ifinfomsg ifm; 286 }; 287 288 struct request req = {}; 289 req.hdr.nlmsg_len = sizeof(req); 290 // If type & 0x3 is equal to 0x2, this means a get request 291 // which doesn't require CAP_SYS_ADMIN. 292 req.hdr.nlmsg_type = ((__RTM_MAX + 1024) & (~0x3)) | 0x2; 293 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 294 req.hdr.nlmsg_seq = kSeq; 295 req.ifm.ifi_family = AF_UNSPEC; 296 297 EXPECT_THAT(NetlinkRequestAckOrError(fd, kSeq, &req, sizeof(req)), 298 PosixErrorIs(EOPNOTSUPP, ::testing::_)); 299 } 300 301 TEST(NetlinkRouteTest, MsgHdrMsgTrunc) { 302 FileDescriptor fd = 303 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 304 305 struct request { 306 struct nlmsghdr hdr; 307 struct ifinfomsg ifm; 308 }; 309 310 struct request req = {}; 311 req.hdr.nlmsg_len = sizeof(req); 312 req.hdr.nlmsg_type = RTM_GETLINK; 313 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 314 req.hdr.nlmsg_seq = kSeq; 315 req.ifm.ifi_family = AF_UNSPEC; 316 317 struct iovec iov = {}; 318 iov.iov_base = &req; 319 iov.iov_len = sizeof(req); 320 321 struct msghdr msg = {}; 322 msg.msg_iov = &iov; 323 msg.msg_iovlen = 1; 324 // No destination required; it defaults to pid 0, the kernel. 325 326 ASSERT_THAT(RetryEINTR(sendmsg)(fd.get(), &msg, 0), SyscallSucceeds()); 327 328 // Small enough to ensure that the response doesn't fit. 329 constexpr size_t kBufferSize = 10; 330 std::vector<char> buf(kBufferSize); 331 iov.iov_base = buf.data(); 332 iov.iov_len = buf.size(); 333 334 ASSERT_THAT(RetryEINTR(recvmsg)(fd.get(), &msg, 0), 335 SyscallSucceedsWithValue(kBufferSize)); 336 EXPECT_EQ((msg.msg_flags & MSG_TRUNC), MSG_TRUNC); 337 } 338 339 TEST(NetlinkRouteTest, SpliceFromPipe) { 340 Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink()); 341 FileDescriptor fd = 342 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 343 344 int fds[2]; 345 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 346 FileDescriptor rfd(fds[0]); 347 FileDescriptor wfd(fds[1]); 348 349 struct request { 350 struct nlmsghdr hdr; 351 struct ifinfomsg ifm; 352 }; 353 354 struct request req = {}; 355 req.hdr.nlmsg_len = sizeof(req); 356 req.hdr.nlmsg_type = RTM_GETLINK; 357 req.hdr.nlmsg_flags = NLM_F_REQUEST; 358 req.hdr.nlmsg_seq = kSeq; 359 req.ifm.ifi_family = AF_UNSPEC; 360 req.ifm.ifi_index = loopback_link.index; 361 362 ASSERT_THAT(write(wfd.get(), &req, sizeof(req)), 363 SyscallSucceedsWithValue(sizeof(req))); 364 365 EXPECT_THAT(splice(rfd.get(), nullptr, fd.get(), nullptr, sizeof(req) + 1, 0), 366 SyscallSucceedsWithValue(sizeof(req))); 367 close(wfd.release()); 368 EXPECT_THAT(splice(rfd.get(), nullptr, fd.get(), nullptr, sizeof(req) + 1, 0), 369 SyscallSucceedsWithValue(0)); 370 371 bool found = false; 372 ASSERT_NO_ERRNO(NetlinkResponse( 373 fd, 374 [&](const struct nlmsghdr* hdr) { 375 CheckLinkMsg(hdr, loopback_link); 376 found = true; 377 }, 378 false)); 379 EXPECT_TRUE(found) << "Netlink response does not contain any links."; 380 } 381 382 TEST(NetlinkRouteTest, MsgTruncMsgHdrMsgTrunc) { 383 FileDescriptor fd = 384 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 385 386 struct request { 387 struct nlmsghdr hdr; 388 struct ifinfomsg ifm; 389 }; 390 391 struct request req = {}; 392 req.hdr.nlmsg_len = sizeof(req); 393 req.hdr.nlmsg_type = RTM_GETLINK; 394 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 395 req.hdr.nlmsg_seq = kSeq; 396 req.ifm.ifi_family = AF_UNSPEC; 397 398 struct iovec iov = {}; 399 iov.iov_base = &req; 400 iov.iov_len = sizeof(req); 401 402 struct msghdr msg = {}; 403 msg.msg_iov = &iov; 404 msg.msg_iovlen = 1; 405 // No destination required; it defaults to pid 0, the kernel. 406 407 ASSERT_THAT(RetryEINTR(sendmsg)(fd.get(), &msg, 0), SyscallSucceeds()); 408 409 // Small enough to ensure that the response doesn't fit. 410 constexpr size_t kBufferSize = 10; 411 std::vector<char> buf(kBufferSize); 412 iov.iov_base = buf.data(); 413 iov.iov_len = buf.size(); 414 415 int res = 0; 416 ASSERT_THAT(res = RetryEINTR(recvmsg)(fd.get(), &msg, MSG_TRUNC), 417 SyscallSucceeds()); 418 EXPECT_GT(res, kBufferSize); 419 EXPECT_EQ((msg.msg_flags & MSG_TRUNC), MSG_TRUNC); 420 } 421 422 TEST(NetlinkRouteTest, ControlMessageIgnored) { 423 FileDescriptor fd = 424 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 425 uint32_t port = ASSERT_NO_ERRNO_AND_VALUE(NetlinkPortID(fd.get())); 426 427 struct request { 428 struct nlmsghdr control_hdr; 429 struct nlmsghdr message_hdr; 430 struct ifinfomsg ifm; 431 }; 432 433 struct request req = {}; 434 435 // This control message is ignored. We still receive a response for the 436 // following RTM_GETLINK. 437 req.control_hdr.nlmsg_len = sizeof(req.control_hdr); 438 req.control_hdr.nlmsg_type = NLMSG_DONE; 439 req.control_hdr.nlmsg_seq = kSeq; 440 441 req.message_hdr.nlmsg_len = sizeof(req.message_hdr) + sizeof(req.ifm); 442 req.message_hdr.nlmsg_type = RTM_GETLINK; 443 req.message_hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 444 req.message_hdr.nlmsg_seq = kSeq; 445 446 req.ifm.ifi_family = AF_UNSPEC; 447 448 ASSERT_NO_ERRNO(NetlinkRequestResponse( 449 fd, &req, sizeof(req), 450 [&](const struct nlmsghdr* hdr) { 451 CheckGetLinkResponse(hdr, kSeq, port); 452 }, 453 false)); 454 } 455 456 TEST(NetlinkRouteTest, GetAddrDump) { 457 FileDescriptor fd = 458 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 459 uint32_t port = ASSERT_NO_ERRNO_AND_VALUE(NetlinkPortID(fd.get())); 460 461 struct request { 462 struct nlmsghdr hdr; 463 struct rtgenmsg rgm; 464 }; 465 466 struct request req; 467 req.hdr.nlmsg_len = sizeof(req); 468 req.hdr.nlmsg_type = RTM_GETADDR; 469 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 470 req.hdr.nlmsg_seq = kSeq; 471 req.rgm.rtgen_family = AF_UNSPEC; 472 473 ASSERT_NO_ERRNO(NetlinkRequestResponse( 474 fd, &req, sizeof(req), 475 [&](const struct nlmsghdr* hdr) { 476 EXPECT_THAT(hdr->nlmsg_type, AnyOf(Eq(RTM_NEWADDR), Eq(NLMSG_DONE))); 477 478 EXPECT_TRUE((hdr->nlmsg_flags & NLM_F_MULTI) == NLM_F_MULTI) 479 << std::hex << hdr->nlmsg_flags; 480 481 EXPECT_EQ(hdr->nlmsg_seq, kSeq); 482 EXPECT_EQ(hdr->nlmsg_pid, port); 483 484 if (hdr->nlmsg_type != RTM_NEWADDR) { 485 return; 486 } 487 488 // RTM_NEWADDR contains at least the header and ifaddrmsg. 489 EXPECT_GE(hdr->nlmsg_len, sizeof(*hdr) + sizeof(struct ifaddrmsg)); 490 491 // TODO(mpratt): Check ifaddrmsg contents and following attrs. 492 }, 493 false)); 494 } 495 496 TEST(NetlinkRouteTest, LookupAll) { 497 struct ifaddrs* if_addr_list = nullptr; 498 auto cleanup = Cleanup([&if_addr_list]() { freeifaddrs(if_addr_list); }); 499 500 // Not a syscall but we can use the syscall matcher as glibc sets errno. 501 ASSERT_THAT(getifaddrs(&if_addr_list), SyscallSucceeds()); 502 503 int count = 0; 504 for (struct ifaddrs* i = if_addr_list; i; i = i->ifa_next) { 505 if (!i->ifa_addr || (i->ifa_addr->sa_family != AF_INET && 506 i->ifa_addr->sa_family != AF_INET6)) { 507 continue; 508 } 509 count++; 510 } 511 ASSERT_GT(count, 0); 512 } 513 514 TEST(NetlinkRouteTest, AddAndRemoveAddr) { 515 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN))); 516 // Don't do cooperative save/restore because netstack state is not restored. 517 // TODO(gvisor.dev/issue/4595): enable cooperative save tests. 518 const DisableSave ds; 519 520 Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink()); 521 522 struct in_addr addr; 523 ASSERT_EQ(inet_pton(AF_INET, "10.0.0.1", &addr), 1); 524 525 // Create should succeed, as no such address in kernel. 526 ASSERT_NO_ERRNO(LinkAddLocalAddr(loopback_link.index, AF_INET, 527 /*prefixlen=*/24, &addr, sizeof(addr))); 528 529 Cleanup defer_addr_removal = Cleanup( 530 [loopback_link = std::move(loopback_link), addr = std::move(addr)] { 531 // First delete should succeed, as address exists. 532 EXPECT_NO_ERRNO(LinkDelLocalAddr(loopback_link.index, AF_INET, 533 /*prefixlen=*/24, &addr, 534 sizeof(addr))); 535 536 // Second delete should fail, as address no longer exists. 537 EXPECT_THAT(LinkDelLocalAddr(loopback_link.index, AF_INET, 538 /*prefixlen=*/24, &addr, sizeof(addr)), 539 PosixErrorIs(EADDRNOTAVAIL, ::testing::_)); 540 }); 541 542 // Replace an existing address should succeed. 543 ASSERT_NO_ERRNO(LinkReplaceLocalAddr(loopback_link.index, AF_INET, 544 /*prefixlen=*/24, &addr, sizeof(addr))); 545 546 // Create exclusive should fail, as we created the address above. 547 EXPECT_THAT(LinkAddExclusiveLocalAddr(loopback_link.index, AF_INET, 548 /*prefixlen=*/24, &addr, sizeof(addr)), 549 PosixErrorIs(EEXIST, ::testing::_)); 550 } 551 552 // GetRouteDump tests a RTM_GETROUTE + NLM_F_DUMP request. 553 TEST(NetlinkRouteTest, GetRouteDump) { 554 FileDescriptor fd = 555 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 556 uint32_t port = ASSERT_NO_ERRNO_AND_VALUE(NetlinkPortID(fd.get())); 557 558 struct request { 559 struct nlmsghdr hdr; 560 struct rtmsg rtm; 561 }; 562 563 struct request req = {}; 564 req.hdr.nlmsg_len = sizeof(req); 565 req.hdr.nlmsg_type = RTM_GETROUTE; 566 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 567 req.hdr.nlmsg_seq = kSeq; 568 req.rtm.rtm_family = AF_UNSPEC; 569 570 bool routeFound = false; 571 bool dstFound = true; 572 ASSERT_NO_ERRNO(NetlinkRequestResponse( 573 fd, &req, sizeof(req), 574 [&](const struct nlmsghdr* hdr) { 575 // Validate the reponse to RTM_GETROUTE + NLM_F_DUMP. 576 EXPECT_THAT(hdr->nlmsg_type, AnyOf(Eq(RTM_NEWROUTE), Eq(NLMSG_DONE))); 577 578 EXPECT_TRUE((hdr->nlmsg_flags & NLM_F_MULTI) == NLM_F_MULTI) 579 << std::hex << hdr->nlmsg_flags; 580 581 EXPECT_EQ(hdr->nlmsg_seq, kSeq); 582 EXPECT_EQ(hdr->nlmsg_pid, port); 583 584 // The test should not proceed if it's not a RTM_NEWROUTE message. 585 if (hdr->nlmsg_type != RTM_NEWROUTE) { 586 return; 587 } 588 589 // RTM_NEWROUTE contains at least the header and rtmsg. 590 ASSERT_GE(hdr->nlmsg_len, NLMSG_SPACE(sizeof(struct rtmsg))); 591 const struct rtmsg* msg = 592 reinterpret_cast<const struct rtmsg*>(NLMSG_DATA(hdr)); 593 // NOTE: rtmsg fields are char fields. 594 std::cout << "Found route table=" << static_cast<int>(msg->rtm_table) 595 << ", protocol=" << static_cast<int>(msg->rtm_protocol) 596 << ", scope=" << static_cast<int>(msg->rtm_scope) 597 << ", type=" << static_cast<int>(msg->rtm_type); 598 599 int len = RTM_PAYLOAD(hdr); 600 bool rtDstFound = false; 601 for (struct rtattr* attr = RTM_RTA(msg); RTA_OK(attr, len); 602 attr = RTA_NEXT(attr, len)) { 603 if (attr->rta_type == RTA_DST) { 604 char address[INET_ADDRSTRLEN] = {}; 605 inet_ntop(AF_INET, RTA_DATA(attr), address, sizeof(address)); 606 std::cout << ", dst=" << address; 607 rtDstFound = true; 608 } 609 } 610 611 std::cout << std::endl; 612 613 // If the test is running in a new network namespace, it will have only 614 // the local route table. 615 if (msg->rtm_table == RT_TABLE_MAIN || 616 (!IsRunningOnGvisor() && msg->rtm_table == RT_TABLE_LOCAL)) { 617 routeFound = true; 618 dstFound = rtDstFound && dstFound; 619 } 620 }, 621 false)); 622 // At least one route found in main route table. 623 EXPECT_TRUE(routeFound); 624 // Found RTA_DST for each route in main table. 625 EXPECT_TRUE(dstFound); 626 } 627 628 // GetRouteRequest tests a RTM_GETROUTE request with RTM_F_LOOKUP_TABLE flag. 629 TEST(NetlinkRouteTest, GetRouteRequest) { 630 FileDescriptor fd = 631 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 632 uint32_t port = ASSERT_NO_ERRNO_AND_VALUE(NetlinkPortID(fd.get())); 633 634 struct request { 635 struct nlmsghdr hdr; 636 struct rtmsg rtm; 637 struct nlattr nla; 638 struct in_addr sin_addr; 639 }; 640 641 constexpr uint32_t kSeq = 12345; 642 643 struct request req = {}; 644 req.hdr.nlmsg_len = sizeof(req); 645 req.hdr.nlmsg_type = RTM_GETROUTE; 646 req.hdr.nlmsg_flags = NLM_F_REQUEST; 647 req.hdr.nlmsg_seq = kSeq; 648 649 req.rtm.rtm_family = AF_INET; 650 req.rtm.rtm_dst_len = 32; 651 req.rtm.rtm_src_len = 0; 652 req.rtm.rtm_tos = 0; 653 req.rtm.rtm_table = RT_TABLE_UNSPEC; 654 req.rtm.rtm_protocol = RTPROT_UNSPEC; 655 req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; 656 req.rtm.rtm_type = RTN_UNSPEC; 657 req.rtm.rtm_flags = RTM_F_LOOKUP_TABLE; 658 659 req.nla.nla_len = 8; 660 req.nla.nla_type = RTA_DST; 661 inet_aton("127.0.0.2", &req.sin_addr); 662 663 bool rtDstFound = false; 664 ASSERT_NO_ERRNO(NetlinkRequestResponseSingle( 665 fd, &req, sizeof(req), [&](const struct nlmsghdr* hdr) { 666 // Validate the reponse to RTM_GETROUTE request with RTM_F_LOOKUP_TABLE 667 // flag. 668 EXPECT_THAT(hdr->nlmsg_type, RTM_NEWROUTE); 669 670 EXPECT_TRUE(hdr->nlmsg_flags == 0) << std::hex << hdr->nlmsg_flags; 671 672 EXPECT_EQ(hdr->nlmsg_seq, kSeq); 673 EXPECT_EQ(hdr->nlmsg_pid, port); 674 675 // RTM_NEWROUTE contains at least the header and rtmsg. 676 ASSERT_GE(hdr->nlmsg_len, NLMSG_SPACE(sizeof(struct rtmsg))); 677 const struct rtmsg* msg = 678 reinterpret_cast<const struct rtmsg*>(NLMSG_DATA(hdr)); 679 680 // NOTE: rtmsg fields are char fields. 681 std::cout << "Found route table=" << static_cast<int>(msg->rtm_table) 682 << ", protocol=" << static_cast<int>(msg->rtm_protocol) 683 << ", scope=" << static_cast<int>(msg->rtm_scope) 684 << ", type=" << static_cast<int>(msg->rtm_type); 685 686 EXPECT_EQ(msg->rtm_family, AF_INET); 687 EXPECT_EQ(msg->rtm_dst_len, 32); 688 EXPECT_TRUE((msg->rtm_flags & RTM_F_CLONED) == RTM_F_CLONED) 689 << std::hex << msg->rtm_flags; 690 691 int len = RTM_PAYLOAD(hdr); 692 std::cout << ", len=" << len; 693 for (struct rtattr* attr = RTM_RTA(msg); RTA_OK(attr, len); 694 attr = RTA_NEXT(attr, len)) { 695 if (attr->rta_type == RTA_DST) { 696 char address[INET_ADDRSTRLEN] = {}; 697 inet_ntop(AF_INET, RTA_DATA(attr), address, sizeof(address)); 698 std::cout << ", dst=" << address; 699 rtDstFound = true; 700 } else if (attr->rta_type == RTA_OIF) { 701 const char* oif = reinterpret_cast<const char*>(RTA_DATA(attr)); 702 std::cout << ", oif=" << oif; 703 } 704 } 705 706 std::cout << std::endl; 707 })); 708 // Found RTA_DST for RTM_F_LOOKUP_TABLE. 709 EXPECT_TRUE(rtDstFound); 710 } 711 712 // RecvmsgTrunc tests the recvmsg MSG_TRUNC flag with zero length output 713 // buffer. MSG_TRUNC with a zero length buffer should consume subsequent 714 // messages off the socket. 715 TEST(NetlinkRouteTest, RecvmsgTrunc) { 716 FileDescriptor fd = 717 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 718 719 struct request { 720 struct nlmsghdr hdr; 721 struct rtgenmsg rgm; 722 }; 723 724 struct request req; 725 req.hdr.nlmsg_len = sizeof(req); 726 req.hdr.nlmsg_type = RTM_GETADDR; 727 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 728 req.hdr.nlmsg_seq = kSeq; 729 req.rgm.rtgen_family = AF_UNSPEC; 730 731 struct iovec iov = {}; 732 iov.iov_base = &req; 733 iov.iov_len = sizeof(req); 734 735 struct msghdr msg = {}; 736 msg.msg_iov = &iov; 737 msg.msg_iovlen = 1; 738 739 ASSERT_THAT(RetryEINTR(sendmsg)(fd.get(), &msg, 0), SyscallSucceeds()); 740 741 iov.iov_base = NULL; 742 iov.iov_len = 0; 743 744 int trunclen, trunclen2; 745 746 // Note: This test assumes at least two messages are returned by the 747 // RTM_GETADDR request. That means at least one RTM_NEWLINK message and one 748 // NLMSG_DONE message. We cannot read all the messages without blocking 749 // because we would need to read the message into a buffer and check the 750 // nlmsg_type for NLMSG_DONE. However, the test depends on reading into a 751 // zero-length buffer. 752 753 // First, call recvmsg with MSG_TRUNC. This will read the full message from 754 // the socket and return it's full length. Subsequent calls to recvmsg will 755 // read the next messages from the socket. 756 ASSERT_THAT(trunclen = RetryEINTR(recvmsg)(fd.get(), &msg, MSG_TRUNC), 757 SyscallSucceeds()); 758 759 // Message should always be truncated. However, While the destination iov is 760 // zero length, MSG_TRUNC returns the size of the next message so it should 761 // not be zero. 762 ASSERT_EQ(msg.msg_flags & MSG_TRUNC, MSG_TRUNC); 763 ASSERT_NE(trunclen, 0); 764 // Returned length is at least the header and ifaddrmsg. 765 EXPECT_GE(trunclen, sizeof(struct nlmsghdr) + sizeof(struct ifaddrmsg)); 766 767 // Reset the msg_flags to make sure that the recvmsg call is setting them 768 // properly. 769 msg.msg_flags = 0; 770 771 // Make a second recvvmsg call to get the next message. 772 ASSERT_THAT(trunclen2 = RetryEINTR(recvmsg)(fd.get(), &msg, MSG_TRUNC), 773 SyscallSucceeds()); 774 ASSERT_EQ(msg.msg_flags & MSG_TRUNC, MSG_TRUNC); 775 ASSERT_NE(trunclen2, 0); 776 777 // Assert that the received messages are not the same. 778 // 779 // We are calling recvmsg with a zero length buffer so we have no way to 780 // inspect the messages to make sure they are not equal in value. The best 781 // we can do is to compare their lengths. 782 ASSERT_NE(trunclen, trunclen2); 783 } 784 785 // RecvmsgTruncPeek tests recvmsg with the combination of the MSG_TRUNC and 786 // MSG_PEEK flags and a zero length output buffer. This is normally used to 787 // read the full length of the next message on the socket without consuming 788 // it, so a properly sized buffer can be allocated to store the message. This 789 // test tests that scenario. 790 TEST(NetlinkRouteTest, RecvmsgTruncPeek) { 791 FileDescriptor fd = 792 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 793 794 struct request { 795 struct nlmsghdr hdr; 796 struct rtgenmsg rgm; 797 }; 798 799 struct request req; 800 req.hdr.nlmsg_len = sizeof(req); 801 req.hdr.nlmsg_type = RTM_GETADDR; 802 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 803 req.hdr.nlmsg_seq = kSeq; 804 req.rgm.rtgen_family = AF_UNSPEC; 805 806 struct iovec iov = {}; 807 iov.iov_base = &req; 808 iov.iov_len = sizeof(req); 809 810 struct msghdr msg = {}; 811 msg.msg_iov = &iov; 812 msg.msg_iovlen = 1; 813 814 ASSERT_THAT(RetryEINTR(sendmsg)(fd.get(), &msg, 0), SyscallSucceeds()); 815 816 int type = -1; 817 do { 818 int peeklen; 819 int len; 820 821 iov.iov_base = NULL; 822 iov.iov_len = 0; 823 824 // Call recvmsg with MSG_PEEK and MSG_TRUNC. This will peek at the message 825 // and return it's full length. 826 // See: MSG_TRUNC http://man7.org/linux/man-pages/man2/recv.2.html 827 ASSERT_THAT( 828 peeklen = RetryEINTR(recvmsg)(fd.get(), &msg, MSG_PEEK | MSG_TRUNC), 829 SyscallSucceeds()); 830 831 // Message should always be truncated. 832 ASSERT_EQ(msg.msg_flags & MSG_TRUNC, MSG_TRUNC); 833 ASSERT_NE(peeklen, 0); 834 835 // Reset the message flags for the next call. 836 msg.msg_flags = 0; 837 838 // Make the actual call to recvmsg to get the actual data. We will use 839 // the length returned from the peek call for the allocated buffer size.. 840 std::vector<char> buf(peeklen); 841 iov.iov_base = buf.data(); 842 iov.iov_len = buf.size(); 843 ASSERT_THAT(len = RetryEINTR(recvmsg)(fd.get(), &msg, 0), 844 SyscallSucceeds()); 845 846 // Message should not be truncated since we allocated the correct buffer 847 // size. 848 EXPECT_NE(msg.msg_flags & MSG_TRUNC, MSG_TRUNC); 849 850 // MSG_PEEK should have left data on the socket and the subsequent call 851 // with should have retrieved the same data. Both calls should have 852 // returned the message's full length so they should be equal. 853 ASSERT_NE(len, 0); 854 ASSERT_EQ(peeklen, len); 855 856 for (struct nlmsghdr* hdr = reinterpret_cast<struct nlmsghdr*>(buf.data()); 857 NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len)) { 858 type = hdr->nlmsg_type; 859 } 860 } while (type != NLMSG_DONE && type != NLMSG_ERROR); 861 } 862 863 // No SCM_CREDENTIALS are received without SO_PASSCRED set. 864 TEST(NetlinkRouteTest, NoPasscredNoCreds) { 865 FileDescriptor fd = 866 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 867 868 ASSERT_THAT(setsockopt(fd.get(), SOL_SOCKET, SO_PASSCRED, &kSockOptOff, 869 sizeof(kSockOptOff)), 870 SyscallSucceeds()); 871 872 struct request { 873 struct nlmsghdr hdr; 874 struct rtgenmsg rgm; 875 }; 876 877 struct request req; 878 req.hdr.nlmsg_len = sizeof(req); 879 req.hdr.nlmsg_type = RTM_GETADDR; 880 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 881 req.hdr.nlmsg_seq = kSeq; 882 req.rgm.rtgen_family = AF_UNSPEC; 883 884 struct iovec iov = {}; 885 iov.iov_base = &req; 886 iov.iov_len = sizeof(req); 887 888 struct msghdr msg = {}; 889 msg.msg_iov = &iov; 890 msg.msg_iovlen = 1; 891 892 ASSERT_THAT(RetryEINTR(sendmsg)(fd.get(), &msg, 0), SyscallSucceeds()); 893 894 iov.iov_base = NULL; 895 iov.iov_len = 0; 896 897 char control[CMSG_SPACE(sizeof(struct ucred))] = {}; 898 msg.msg_control = control; 899 msg.msg_controllen = sizeof(control); 900 901 // Note: This test assumes at least one message is returned by the 902 // RTM_GETADDR request. 903 ASSERT_THAT(RetryEINTR(recvmsg)(fd.get(), &msg, 0), SyscallSucceeds()); 904 905 // No control messages. 906 EXPECT_EQ(CMSG_FIRSTHDR(&msg), nullptr); 907 } 908 909 // SCM_CREDENTIALS are received with SO_PASSCRED set. 910 TEST(NetlinkRouteTest, PasscredCreds) { 911 FileDescriptor fd = 912 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 913 914 ASSERT_THAT(setsockopt(fd.get(), SOL_SOCKET, SO_PASSCRED, &kSockOptOn, 915 sizeof(kSockOptOn)), 916 SyscallSucceeds()); 917 918 struct request { 919 struct nlmsghdr hdr; 920 struct rtgenmsg rgm; 921 }; 922 923 struct request req; 924 req.hdr.nlmsg_len = sizeof(req); 925 req.hdr.nlmsg_type = RTM_GETADDR; 926 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 927 req.hdr.nlmsg_seq = kSeq; 928 req.rgm.rtgen_family = AF_UNSPEC; 929 930 struct iovec iov = {}; 931 iov.iov_base = &req; 932 iov.iov_len = sizeof(req); 933 934 struct msghdr msg = {}; 935 msg.msg_iov = &iov; 936 msg.msg_iovlen = 1; 937 938 ASSERT_THAT(RetryEINTR(sendmsg)(fd.get(), &msg, 0), SyscallSucceeds()); 939 940 iov.iov_base = NULL; 941 iov.iov_len = 0; 942 943 char control[CMSG_SPACE(sizeof(struct ucred))] = {}; 944 msg.msg_control = control; 945 msg.msg_controllen = sizeof(control); 946 947 // Note: This test assumes at least one message is returned by the 948 // RTM_GETADDR request. 949 ASSERT_THAT(RetryEINTR(recvmsg)(fd.get(), &msg, 0), SyscallSucceeds()); 950 951 struct ucred creds; 952 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); 953 ASSERT_NE(cmsg, nullptr); 954 ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(creds))); 955 ASSERT_EQ(cmsg->cmsg_level, SOL_SOCKET); 956 ASSERT_EQ(cmsg->cmsg_type, SCM_CREDENTIALS); 957 958 memcpy(&creds, CMSG_DATA(cmsg), sizeof(creds)); 959 960 // The peer is the kernel, which is "PID" 0. 961 EXPECT_EQ(creds.pid, 0); 962 // The kernel identifies as root. Also allow nobody in case this test is 963 // running in a userns without root mapped. 964 EXPECT_THAT(creds.uid, AnyOf(Eq(0), Eq(65534))); 965 EXPECT_THAT(creds.gid, AnyOf(Eq(0), Eq(65534))); 966 } 967 968 } // namespace 969 970 } // namespace testing 971 } // namespace gvisor