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