xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/qbone/platform/netlink_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/qbone/platform/netlink.h"
6 
7 #include <utility>
8 
9 #include "absl/container/node_hash_set.h"
10 #include "quiche/quic/platform/api/quic_bug_tracker.h"
11 #include "quiche/quic/platform/api/quic_test.h"
12 #include "quiche/quic/qbone/platform/mock_kernel.h"
13 #include "quiche/quic/qbone/qbone_constants.h"
14 
15 namespace quic::test {
16 namespace {
17 
18 using ::testing::_;
19 using ::testing::Contains;
20 using ::testing::InSequence;
21 using ::testing::Invoke;
22 using ::testing::Return;
23 using ::testing::Unused;
24 
25 const int kSocketFd = 101;
26 
27 class NetlinkTest : public QuicTest {
28  protected:
NetlinkTest()29   NetlinkTest() {
30     ON_CALL(mock_kernel_, socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE))
31         .WillByDefault(Invoke([this](Unused, Unused, Unused) {
32           EXPECT_CALL(mock_kernel_, close(kSocketFd)).WillOnce(Return(0));
33           return kSocketFd;
34         }));
35   }
36 
ExpectNetlinkPacket(uint16_t type,uint16_t flags,const std::function<ssize_t (void * buf,size_t len,int seq)> & recv_callback,const std::function<void (const void * buf,size_t len)> & send_callback=nullptr)37   void ExpectNetlinkPacket(
38       uint16_t type, uint16_t flags,
39       const std::function<ssize_t(void* buf, size_t len, int seq)>&
40           recv_callback,
41       const std::function<void(const void* buf, size_t len)>& send_callback =
42           nullptr) {
43     static int seq = -1;
44     InSequence s;
45 
46     EXPECT_CALL(mock_kernel_, sendmsg(kSocketFd, _, _))
47         .WillOnce(Invoke([type, flags, send_callback](
48                              Unused, const struct msghdr* msg, int) {
49           EXPECT_EQ(sizeof(struct sockaddr_nl), msg->msg_namelen);
50           auto* nl_addr =
51               reinterpret_cast<const struct sockaddr_nl*>(msg->msg_name);
52           EXPECT_EQ(AF_NETLINK, nl_addr->nl_family);
53           EXPECT_EQ(0, nl_addr->nl_pid);
54           EXPECT_EQ(0, nl_addr->nl_groups);
55 
56           EXPECT_GE(msg->msg_iovlen, 1);
57           EXPECT_GE(msg->msg_iov[0].iov_len, sizeof(struct nlmsghdr));
58 
59           std::string buf;
60           for (int i = 0; i < msg->msg_iovlen; i++) {
61             buf.append(
62                 std::string(reinterpret_cast<char*>(msg->msg_iov[i].iov_base),
63                             msg->msg_iov[i].iov_len));
64           }
65 
66           auto* netlink_message =
67               reinterpret_cast<const struct nlmsghdr*>(buf.c_str());
68           EXPECT_EQ(type, netlink_message->nlmsg_type);
69           EXPECT_EQ(flags, netlink_message->nlmsg_flags);
70           EXPECT_GE(buf.size(), netlink_message->nlmsg_len);
71 
72           if (send_callback != nullptr) {
73             send_callback(buf.c_str(), buf.size());
74           }
75 
76           QUICHE_CHECK_EQ(seq, -1);
77           seq = netlink_message->nlmsg_seq;
78           return buf.size();
79         }));
80 
81     EXPECT_CALL(mock_kernel_,
82                 recvfrom(kSocketFd, _, 0, MSG_PEEK | MSG_TRUNC, _, _))
83         .WillOnce(Invoke([this, recv_callback](Unused, Unused, Unused, Unused,
84                                                struct sockaddr* src_addr,
85                                                socklen_t* addrlen) {
86           auto* nl_addr = reinterpret_cast<struct sockaddr_nl*>(src_addr);
87           nl_addr->nl_family = AF_NETLINK;
88           nl_addr->nl_pid = 0;     // from kernel
89           nl_addr->nl_groups = 0;  // no multicast
90 
91           int ret = recv_callback(reply_packet_, sizeof(reply_packet_), seq);
92           QUICHE_CHECK_LE(ret, sizeof(reply_packet_));
93           return ret;
94         }));
95 
96     EXPECT_CALL(mock_kernel_, recvfrom(kSocketFd, _, _, _, _, _))
97         .WillOnce(Invoke([recv_callback](Unused, void* buf, size_t len, Unused,
98                                          struct sockaddr* src_addr,
99                                          socklen_t* addrlen) {
100           auto* nl_addr = reinterpret_cast<struct sockaddr_nl*>(src_addr);
101           nl_addr->nl_family = AF_NETLINK;
102           nl_addr->nl_pid = 0;     // from kernel
103           nl_addr->nl_groups = 0;  // no multicast
104 
105           int ret = recv_callback(buf, len, seq);
106           EXPECT_GE(len, ret);
107           seq = -1;
108           return ret;
109         }));
110   }
111 
112   char reply_packet_[4096];
113   MockKernel mock_kernel_;
114 };
115 
AddRTA(struct nlmsghdr * netlink_message,uint16_t type,const void * data,size_t len)116 void AddRTA(struct nlmsghdr* netlink_message, uint16_t type, const void* data,
117             size_t len) {
118   auto* next_header_ptr = reinterpret_cast<char*>(netlink_message) +
119                           NLMSG_ALIGN(netlink_message->nlmsg_len);
120 
121   auto* rta = reinterpret_cast<struct rtattr*>(next_header_ptr);
122   rta->rta_type = type;
123   rta->rta_len = RTA_LENGTH(len);
124   memcpy(RTA_DATA(rta), data, len);
125 
126   netlink_message->nlmsg_len =
127       NLMSG_ALIGN(netlink_message->nlmsg_len) + RTA_LENGTH(len);
128 }
129 
CreateIfinfomsg(struct nlmsghdr * netlink_message,const std::string & interface_name,uint16_t type,int index,unsigned int flags,unsigned int change,uint8_t address[],int address_len,uint8_t broadcast[],int broadcast_len)130 void CreateIfinfomsg(struct nlmsghdr* netlink_message,
131                      const std::string& interface_name, uint16_t type,
132                      int index, unsigned int flags, unsigned int change,
133                      uint8_t address[], int address_len, uint8_t broadcast[],
134                      int broadcast_len) {
135   auto* interface_info =
136       reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(netlink_message));
137   interface_info->ifi_family = AF_UNSPEC;
138   interface_info->ifi_type = type;
139   interface_info->ifi_index = index;
140   interface_info->ifi_flags = flags;
141   interface_info->ifi_change = change;
142   netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
143 
144   // Add address
145   AddRTA(netlink_message, IFLA_ADDRESS, address, address_len);
146 
147   // Add broadcast address
148   AddRTA(netlink_message, IFLA_BROADCAST, broadcast, broadcast_len);
149 
150   // Add name
151   AddRTA(netlink_message, IFLA_IFNAME, interface_name.c_str(),
152          interface_name.size());
153 }
154 
CreateNetlinkMessage(void * buf,struct nlmsghdr * previous_netlink_message,uint16_t type,int seq)155 struct nlmsghdr* CreateNetlinkMessage(void* buf,  // NOLINT
156                                       struct nlmsghdr* previous_netlink_message,
157                                       uint16_t type, int seq) {
158   auto* next_header_ptr = reinterpret_cast<char*>(buf);
159   if (previous_netlink_message != nullptr) {
160     next_header_ptr = reinterpret_cast<char*>(previous_netlink_message) +
161                       NLMSG_ALIGN(previous_netlink_message->nlmsg_len);
162   }
163   auto* netlink_message = reinterpret_cast<nlmsghdr*>(next_header_ptr);
164   netlink_message->nlmsg_len = NLMSG_LENGTH(0);
165   netlink_message->nlmsg_type = type;
166   netlink_message->nlmsg_flags = NLM_F_MULTI;
167   netlink_message->nlmsg_pid = 0;  // from the kernel
168   netlink_message->nlmsg_seq = seq;
169 
170   return netlink_message;
171 }
172 
CreateIfaddrmsg(struct nlmsghdr * nlm,int interface_index,unsigned char prefixlen,unsigned char flags,unsigned char scope,QuicIpAddress ip)173 void CreateIfaddrmsg(struct nlmsghdr* nlm, int interface_index,
174                      unsigned char prefixlen, unsigned char flags,
175                      unsigned char scope, QuicIpAddress ip) {
176   QUICHE_CHECK(ip.IsInitialized());
177   unsigned char family;
178   switch (ip.address_family()) {
179     case IpAddressFamily::IP_V4:
180       family = AF_INET;
181       break;
182     case IpAddressFamily::IP_V6:
183       family = AF_INET6;
184       break;
185     default:
186       QUIC_BUG(quic_bug_11034_1)
187           << absl::StrCat("unexpected address family: ", ip.address_family());
188       family = AF_UNSPEC;
189   }
190   auto* msg = reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(nlm));
191   msg->ifa_family = family;
192   msg->ifa_prefixlen = prefixlen;
193   msg->ifa_flags = flags;
194   msg->ifa_scope = scope;
195   msg->ifa_index = interface_index;
196   nlm->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
197 
198   // Add local address
199   AddRTA(nlm, IFA_LOCAL, ip.ToPackedString().c_str(),
200          ip.ToPackedString().size());
201 }
202 
CreateRtmsg(struct nlmsghdr * nlm,unsigned char family,unsigned char destination_length,unsigned char source_length,unsigned char tos,unsigned char table,unsigned char protocol,unsigned char scope,unsigned char type,unsigned int flags,QuicIpAddress destination,int interface_index,int init_cwnd)203 void CreateRtmsg(struct nlmsghdr* nlm, unsigned char family,
204                  unsigned char destination_length, unsigned char source_length,
205                  unsigned char tos, unsigned char table, unsigned char protocol,
206                  unsigned char scope, unsigned char type, unsigned int flags,
207                  QuicIpAddress destination, int interface_index,
208                  int init_cwnd) {
209   auto* msg = reinterpret_cast<struct rtmsg*>(NLMSG_DATA(nlm));
210   msg->rtm_family = family;
211   msg->rtm_dst_len = destination_length;
212   msg->rtm_src_len = source_length;
213   msg->rtm_tos = tos;
214   msg->rtm_table = table;
215   msg->rtm_protocol = protocol;
216   msg->rtm_scope = scope;
217   msg->rtm_type = type;
218   msg->rtm_flags = flags;
219   nlm->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
220 
221   // Add destination
222   AddRTA(nlm, RTA_DST, destination.ToPackedString().c_str(),
223          destination.ToPackedString().size());
224 
225   // Add egress interface
226   AddRTA(nlm, RTA_OIF, &interface_index, sizeof(interface_index));
227 
228   // Add initcwnd
229   if (init_cwnd > 0) {
230     char data[RTA_LENGTH(sizeof(uint32_t))];
231     struct rtattr* rta = reinterpret_cast<struct rtattr*>(data);
232     rta->rta_len = sizeof(data);
233     rta->rta_type = RTA_METRICS;
234     *reinterpret_cast<uint32_t*>(RTA_DATA(rta)) = init_cwnd;
235     AddRTA(nlm, RTA_METRICS, data, sizeof(data));
236   }
237 }
238 
TEST_F(NetlinkTest,GetLinkInfoWorks)239 TEST_F(NetlinkTest, GetLinkInfoWorks) {
240   auto netlink = std::make_unique<Netlink>(&mock_kernel_);
241 
242   uint8_t hwaddr[] = {'a', 'b', 'c', 'd', 'e', 'f'};
243   uint8_t bcaddr[] = {'c', 'b', 'a', 'f', 'e', 'd'};
244 
245   ExpectNetlinkPacket(
246       RTM_GETLINK, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
247       [&hwaddr, &bcaddr](void* buf, size_t len, int seq) {
248         int ret = 0;
249 
250         struct nlmsghdr* netlink_message =
251             CreateNetlinkMessage(buf, nullptr, RTM_NEWLINK, seq);
252         CreateIfinfomsg(netlink_message, "tun0", /* type = */ 1,
253                         /* index = */ 7,
254                         /* flags = */ 0,
255                         /* change = */ 0xFFFFFFFF, hwaddr, 6, bcaddr, 6);
256         ret += NLMSG_ALIGN(netlink_message->nlmsg_len);
257 
258         netlink_message =
259             CreateNetlinkMessage(buf, netlink_message, NLMSG_DONE, seq);
260         ret += NLMSG_ALIGN(netlink_message->nlmsg_len);
261 
262         return ret;
263       });
264 
265   Netlink::LinkInfo link_info;
266   EXPECT_TRUE(netlink->GetLinkInfo("tun0", &link_info));
267 
268   EXPECT_EQ(7, link_info.index);
269   EXPECT_EQ(1, link_info.type);
270 
271   for (int i = 0; i < link_info.hardware_address_length; ++i) {
272     EXPECT_EQ(hwaddr[i], link_info.hardware_address[i]);
273   }
274   for (int i = 0; i < link_info.broadcast_address_length; ++i) {
275     EXPECT_EQ(bcaddr[i], link_info.broadcast_address[i]);
276   }
277 }
278 
TEST_F(NetlinkTest,GetAddressesWorks)279 TEST_F(NetlinkTest, GetAddressesWorks) {
280   auto netlink = std::make_unique<Netlink>(&mock_kernel_);
281 
282   absl::node_hash_set<std::string> addresses = {
283       QuicIpAddress::Any4().ToString(), QuicIpAddress::Any6().ToString()};
284 
285   ExpectNetlinkPacket(
286       RTM_GETADDR, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
287       [&addresses](void* buf, size_t len, int seq) {
288         int ret = 0;
289 
290         struct nlmsghdr* nlm = nullptr;
291 
292         for (const auto& address : addresses) {
293           QuicIpAddress ip;
294           ip.FromString(address);
295           nlm = CreateNetlinkMessage(buf, nlm, RTM_NEWADDR, seq);
296           CreateIfaddrmsg(nlm, /* interface_index = */ 7, /* prefixlen = */ 24,
297                           /* flags = */ 0, /* scope = */ RT_SCOPE_UNIVERSE, ip);
298 
299           ret += NLMSG_ALIGN(nlm->nlmsg_len);
300         }
301 
302         // Create IPs with unwanted flags.
303         {
304           QuicIpAddress ip;
305           ip.FromString("10.0.0.1");
306           nlm = CreateNetlinkMessage(buf, nlm, RTM_NEWADDR, seq);
307           CreateIfaddrmsg(nlm, /* interface_index = */ 7, /* prefixlen = */ 16,
308                           /* flags = */ IFA_F_OPTIMISTIC, /* scope = */
309                           RT_SCOPE_UNIVERSE, ip);
310 
311           ret += NLMSG_ALIGN(nlm->nlmsg_len);
312 
313           ip.FromString("10.0.0.2");
314           nlm = CreateNetlinkMessage(buf, nlm, RTM_NEWADDR, seq);
315           CreateIfaddrmsg(nlm, /* interface_index = */ 7, /* prefixlen = */ 16,
316                           /* flags = */ IFA_F_TENTATIVE, /* scope = */
317                           RT_SCOPE_UNIVERSE, ip);
318 
319           ret += NLMSG_ALIGN(nlm->nlmsg_len);
320         }
321 
322         nlm = CreateNetlinkMessage(buf, nlm, NLMSG_DONE, seq);
323         ret += NLMSG_ALIGN(nlm->nlmsg_len);
324 
325         return ret;
326       });
327 
328   std::vector<Netlink::AddressInfo> reported_addresses;
329   int num_ipv6_nodad_dadfailed_addresses = 0;
330   EXPECT_TRUE(netlink->GetAddresses(7, IFA_F_TENTATIVE | IFA_F_OPTIMISTIC,
331                                     &reported_addresses,
332                                     &num_ipv6_nodad_dadfailed_addresses));
333 
334   for (const auto& reported_address : reported_addresses) {
335     EXPECT_TRUE(reported_address.local_address.IsInitialized());
336     EXPECT_FALSE(reported_address.interface_address.IsInitialized());
337     EXPECT_THAT(addresses, Contains(reported_address.local_address.ToString()));
338     addresses.erase(reported_address.local_address.ToString());
339 
340     EXPECT_EQ(24, reported_address.prefix_length);
341   }
342 
343   EXPECT_TRUE(addresses.empty());
344 }
345 
TEST_F(NetlinkTest,ChangeLocalAddressAdd)346 TEST_F(NetlinkTest, ChangeLocalAddressAdd) {
347   auto netlink = std::make_unique<Netlink>(&mock_kernel_);
348 
349   QuicIpAddress ip = QuicIpAddress::Any6();
350   ExpectNetlinkPacket(
351       RTM_NEWADDR, NLM_F_ACK | NLM_F_REQUEST,
352       [](void* buf, size_t len, int seq) {
353         struct nlmsghdr* netlink_message =
354             CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
355         auto* err =
356             reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
357         // Ack the request
358         err->error = 0;
359         netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
360         return netlink_message->nlmsg_len;
361       },
362       [ip](const void* buf, size_t len) {
363         auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
364         auto* ifa = reinterpret_cast<const struct ifaddrmsg*>(
365             NLMSG_DATA(netlink_message));
366         EXPECT_EQ(19, ifa->ifa_prefixlen);
367         EXPECT_EQ(RT_SCOPE_UNIVERSE, ifa->ifa_scope);
368         EXPECT_EQ(IFA_F_PERMANENT, ifa->ifa_flags);
369         EXPECT_EQ(7, ifa->ifa_index);
370         EXPECT_EQ(AF_INET6, ifa->ifa_family);
371 
372         const struct rtattr* rta;
373         int payload_length = IFA_PAYLOAD(netlink_message);
374         int num_rta = 0;
375         for (rta = IFA_RTA(ifa); RTA_OK(rta, payload_length);
376              rta = RTA_NEXT(rta, payload_length)) {
377           switch (rta->rta_type) {
378             case IFA_LOCAL: {
379               EXPECT_EQ(ip.ToPackedString().size(), RTA_PAYLOAD(rta));
380               const auto* raw_address =
381                   reinterpret_cast<const char*>(RTA_DATA(rta));
382               ASSERT_EQ(sizeof(in6_addr), RTA_PAYLOAD(rta));
383               QuicIpAddress address;
384               address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
385               EXPECT_EQ(ip, address);
386               break;
387             }
388             case IFA_CACHEINFO: {
389               EXPECT_EQ(sizeof(struct ifa_cacheinfo), RTA_PAYLOAD(rta));
390               const auto* cache_info =
391                   reinterpret_cast<const struct ifa_cacheinfo*>(RTA_DATA(rta));
392               EXPECT_EQ(8, cache_info->ifa_prefered);  // common_typos_disable
393               EXPECT_EQ(6, cache_info->ifa_valid);
394               EXPECT_EQ(4, cache_info->cstamp);
395               EXPECT_EQ(2, cache_info->tstamp);
396               break;
397             }
398             default:
399               EXPECT_TRUE(false) << "Seeing rtattr that should not exist";
400           }
401           ++num_rta;
402         }
403         EXPECT_EQ(2, num_rta);
404       });
405 
406   struct {
407     struct rtattr rta;
408     struct ifa_cacheinfo cache_info;
409   } additional_rta;
410 
411   additional_rta.rta.rta_type = IFA_CACHEINFO;
412   additional_rta.rta.rta_len = RTA_LENGTH(sizeof(struct ifa_cacheinfo));
413   additional_rta.cache_info.ifa_prefered = 8;
414   additional_rta.cache_info.ifa_valid = 6;
415   additional_rta.cache_info.cstamp = 4;
416   additional_rta.cache_info.tstamp = 2;
417 
418   EXPECT_TRUE(netlink->ChangeLocalAddress(7, Netlink::Verb::kAdd, ip, 19,
419                                           IFA_F_PERMANENT, RT_SCOPE_UNIVERSE,
420                                           {&additional_rta.rta}));
421 }
422 
TEST_F(NetlinkTest,ChangeLocalAddressRemove)423 TEST_F(NetlinkTest, ChangeLocalAddressRemove) {
424   auto netlink = std::make_unique<Netlink>(&mock_kernel_);
425 
426   QuicIpAddress ip = QuicIpAddress::Any4();
427   ExpectNetlinkPacket(
428       RTM_DELADDR, NLM_F_ACK | NLM_F_REQUEST,
429       [](void* buf, size_t len, int seq) {
430         struct nlmsghdr* netlink_message =
431             CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
432         auto* err =
433             reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
434         // Ack the request
435         err->error = 0;
436         netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
437         return netlink_message->nlmsg_len;
438       },
439       [ip](const void* buf, size_t len) {
440         auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
441         auto* ifa = reinterpret_cast<const struct ifaddrmsg*>(
442             NLMSG_DATA(netlink_message));
443         EXPECT_EQ(32, ifa->ifa_prefixlen);
444         EXPECT_EQ(RT_SCOPE_UNIVERSE, ifa->ifa_scope);
445         EXPECT_EQ(0, ifa->ifa_flags);
446         EXPECT_EQ(7, ifa->ifa_index);
447         EXPECT_EQ(AF_INET, ifa->ifa_family);
448 
449         const struct rtattr* rta;
450         int payload_length = IFA_PAYLOAD(netlink_message);
451         int num_rta = 0;
452         for (rta = IFA_RTA(ifa); RTA_OK(rta, payload_length);
453              rta = RTA_NEXT(rta, payload_length)) {
454           switch (rta->rta_type) {
455             case IFA_LOCAL: {
456               const auto* raw_address =
457                   reinterpret_cast<const char*>(RTA_DATA(rta));
458               ASSERT_EQ(sizeof(in_addr), RTA_PAYLOAD(rta));
459               QuicIpAddress address;
460               address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
461               EXPECT_EQ(ip, address);
462               break;
463             }
464             default:
465               EXPECT_TRUE(false) << "Seeing rtattr that should not exist";
466           }
467           ++num_rta;
468         }
469         EXPECT_EQ(1, num_rta);
470       });
471 
472   EXPECT_TRUE(netlink->ChangeLocalAddress(7, Netlink::Verb::kRemove, ip, 32, 0,
473                                           RT_SCOPE_UNIVERSE, {}));
474 }
475 
TEST_F(NetlinkTest,GetRouteInfoWorks)476 TEST_F(NetlinkTest, GetRouteInfoWorks) {
477   auto netlink = std::make_unique<Netlink>(&mock_kernel_);
478 
479   QuicIpAddress destination;
480   ASSERT_TRUE(destination.FromString("f800::2"));
481   ExpectNetlinkPacket(RTM_GETROUTE, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
482                       [destination](void* buf, size_t len, int seq) {
483                         int ret = 0;
484                         struct nlmsghdr* netlink_message = CreateNetlinkMessage(
485                             buf, nullptr, RTM_NEWROUTE, seq);
486                         CreateRtmsg(netlink_message, AF_INET6, 48, 0, 0,
487                                     RT_TABLE_MAIN, RTPROT_STATIC, RT_SCOPE_LINK,
488                                     RTN_UNICAST, 0, destination, 7, 0);
489                         ret += NLMSG_ALIGN(netlink_message->nlmsg_len);
490 
491                         netlink_message = CreateNetlinkMessage(
492                             buf, netlink_message, NLMSG_DONE, seq);
493                         ret += NLMSG_ALIGN(netlink_message->nlmsg_len);
494 
495                         QUIC_LOG(INFO) << "ret: " << ret;
496                         return ret;
497                       });
498 
499   std::vector<Netlink::RoutingRule> routing_rules;
500   EXPECT_TRUE(netlink->GetRouteInfo(&routing_rules));
501 
502   ASSERT_EQ(1, routing_rules.size());
503   EXPECT_EQ(RT_SCOPE_LINK, routing_rules[0].scope);
504   EXPECT_EQ(IpRange(destination, 48).ToString(),
505             routing_rules[0].destination_subnet.ToString());
506   EXPECT_FALSE(routing_rules[0].preferred_source.IsInitialized());
507   EXPECT_EQ(7, routing_rules[0].out_interface);
508   EXPECT_EQ(0, routing_rules[0].init_cwnd);
509 }
510 
TEST_F(NetlinkTest,ChangeRouteAdd)511 TEST_F(NetlinkTest, ChangeRouteAdd) {
512   auto netlink = std::make_unique<Netlink>(&mock_kernel_);
513 
514   QuicIpAddress preferred_ip;
515   preferred_ip.FromString("ff80:dead:beef::1");
516   IpRange subnet;
517   subnet.FromString("ff80:dead:beef::/48");
518   int egress_interface_index = 7;
519   uint32_t init_cwnd = 32;
520   ExpectNetlinkPacket(
521       RTM_NEWROUTE, NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL,
522       [](void* buf, size_t len, int seq) {
523         struct nlmsghdr* netlink_message =
524             CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
525         auto* err =
526             reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
527         // Ack the request
528         err->error = 0;
529         netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
530         return netlink_message->nlmsg_len;
531       },
532       [preferred_ip, subnet, egress_interface_index, init_cwnd](const void* buf,
533                                                                 size_t len) {
534         auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
535         auto* rtm =
536             reinterpret_cast<const struct rtmsg*>(NLMSG_DATA(netlink_message));
537         EXPECT_EQ(AF_INET6, rtm->rtm_family);
538         EXPECT_EQ(48, rtm->rtm_dst_len);
539         EXPECT_EQ(0, rtm->rtm_src_len);
540         EXPECT_EQ(RT_TABLE_MAIN, rtm->rtm_table);
541         EXPECT_EQ(RTPROT_STATIC, rtm->rtm_protocol);
542         EXPECT_EQ(RT_SCOPE_LINK, rtm->rtm_scope);
543         EXPECT_EQ(RTN_UNICAST, rtm->rtm_type);
544 
545         const struct rtattr* rta;
546         int payload_length = RTM_PAYLOAD(netlink_message);
547         int num_rta = 0;
548         for (rta = RTM_RTA(rtm); RTA_OK(rta, payload_length);
549              rta = RTA_NEXT(rta, payload_length)) {
550           switch (rta->rta_type) {
551             case RTA_PREFSRC: {
552               const auto* raw_address =
553                   reinterpret_cast<const char*>(RTA_DATA(rta));
554               ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
555               QuicIpAddress address;
556               address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
557               EXPECT_EQ(preferred_ip, address);
558               break;
559             }
560             case RTA_GATEWAY: {
561               const auto* raw_address =
562                   reinterpret_cast<const char*>(RTA_DATA(rta));
563               ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
564               QuicIpAddress address;
565               address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
566               EXPECT_EQ(*QboneConstants::GatewayAddress(), address);
567               break;
568             }
569             case RTA_OIF: {
570               ASSERT_EQ(sizeof(int), RTA_PAYLOAD(rta));
571               const auto* interface_index =
572                   reinterpret_cast<const int*>(RTA_DATA(rta));
573               EXPECT_EQ(egress_interface_index, *interface_index);
574               break;
575             }
576             case RTA_DST: {
577               const auto* raw_address =
578                   reinterpret_cast<const char*>(RTA_DATA(rta));
579               ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
580               QuicIpAddress address;
581               address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
582               EXPECT_EQ(subnet.ToString(),
583                         IpRange(address, rtm->rtm_dst_len).ToString());
584               break;
585             }
586             case RTA_TABLE: {
587               ASSERT_EQ(*reinterpret_cast<uint32_t*>(RTA_DATA(rta)),
588                         QboneConstants::kQboneRouteTableId);
589               break;
590             }
591             case RTA_METRICS: {
592               struct rtattr* rtax =
593                   reinterpret_cast<struct rtattr*>(RTA_DATA(rta));
594               ASSERT_EQ(rtax->rta_type, RTAX_INITCWND);
595               ASSERT_EQ(rtax->rta_len, RTA_LENGTH(sizeof(uint32_t)));
596               ASSERT_EQ(*reinterpret_cast<uint32_t*>(RTA_DATA(rtax)),
597                         init_cwnd);
598               break;
599             }
600             default:
601               EXPECT_TRUE(false) << "Seeing rtattr that should not be sent";
602           }
603           ++num_rta;
604         }
605         EXPECT_EQ(6, num_rta);
606       });
607   EXPECT_TRUE(netlink->ChangeRoute(
608       Netlink::Verb::kAdd, QboneConstants::kQboneRouteTableId, subnet,
609       RT_SCOPE_LINK, preferred_ip, egress_interface_index, init_cwnd));
610 }
611 
TEST_F(NetlinkTest,ChangeRouteRemove)612 TEST_F(NetlinkTest, ChangeRouteRemove) {
613   auto netlink = std::make_unique<Netlink>(&mock_kernel_);
614 
615   QuicIpAddress preferred_ip;
616   preferred_ip.FromString("ff80:dead:beef::1");
617   IpRange subnet;
618   subnet.FromString("ff80:dead:beef::/48");
619   int egress_interface_index = 7;
620   ExpectNetlinkPacket(
621       RTM_DELROUTE, NLM_F_ACK | NLM_F_REQUEST,
622       [](void* buf, size_t len, int seq) {
623         struct nlmsghdr* netlink_message =
624             CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
625         auto* err =
626             reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
627         // Ack the request
628         err->error = 0;
629         netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
630         return netlink_message->nlmsg_len;
631       },
632       [preferred_ip, subnet, egress_interface_index](const void* buf,
633                                                      size_t len) {
634         auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
635         auto* rtm =
636             reinterpret_cast<const struct rtmsg*>(NLMSG_DATA(netlink_message));
637         EXPECT_EQ(AF_INET6, rtm->rtm_family);
638         EXPECT_EQ(48, rtm->rtm_dst_len);
639         EXPECT_EQ(0, rtm->rtm_src_len);
640         EXPECT_EQ(RT_TABLE_MAIN, rtm->rtm_table);
641         EXPECT_EQ(RTPROT_UNSPEC, rtm->rtm_protocol);
642         EXPECT_EQ(RT_SCOPE_LINK, rtm->rtm_scope);
643         EXPECT_EQ(RTN_UNICAST, rtm->rtm_type);
644 
645         const struct rtattr* rta;
646         int payload_length = RTM_PAYLOAD(netlink_message);
647         int num_rta = 0;
648         for (rta = RTM_RTA(rtm); RTA_OK(rta, payload_length);
649              rta = RTA_NEXT(rta, payload_length)) {
650           switch (rta->rta_type) {
651             case RTA_PREFSRC: {
652               const auto* raw_address =
653                   reinterpret_cast<const char*>(RTA_DATA(rta));
654               ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
655               QuicIpAddress address;
656               address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
657               EXPECT_EQ(preferred_ip, address);
658               break;
659             }
660             case RTA_OIF: {
661               ASSERT_EQ(sizeof(int), RTA_PAYLOAD(rta));
662               const auto* interface_index =
663                   reinterpret_cast<const int*>(RTA_DATA(rta));
664               EXPECT_EQ(egress_interface_index, *interface_index);
665               break;
666             }
667             case RTA_DST: {
668               const auto* raw_address =
669                   reinterpret_cast<const char*>(RTA_DATA(rta));
670               ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
671               QuicIpAddress address;
672               address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
673               EXPECT_EQ(subnet.ToString(),
674                         IpRange(address, rtm->rtm_dst_len).ToString());
675               break;
676             }
677             case RTA_TABLE: {
678               ASSERT_EQ(*reinterpret_cast<uint32_t*>(RTA_DATA(rta)),
679                         QboneConstants::kQboneRouteTableId);
680               break;
681             }
682             default:
683               EXPECT_TRUE(false) << "Seeing rtattr that should not be sent";
684           }
685           ++num_rta;
686         }
687         EXPECT_EQ(4, num_rta);
688       });
689   EXPECT_TRUE(netlink->ChangeRoute(
690       Netlink::Verb::kRemove, QboneConstants::kQboneRouteTableId, subnet,
691       RT_SCOPE_LINK, preferred_ip, egress_interface_index,
692       Netlink::kUnspecifiedInitCwnd));
693 }
694 
TEST_F(NetlinkTest,ChangeRouteReplace)695 TEST_F(NetlinkTest, ChangeRouteReplace) {
696   auto netlink = std::make_unique<Netlink>(&mock_kernel_);
697 
698   QuicIpAddress preferred_ip;
699   preferred_ip.FromString("ff80:dead:beef::1");
700   IpRange subnet;
701   subnet.FromString("ff80:dead:beef::/48");
702   int egress_interface_index = 7;
703   ExpectNetlinkPacket(
704       RTM_NEWROUTE, NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
705       [](void* buf, size_t len, int seq) {
706         struct nlmsghdr* netlink_message =
707             CreateNetlinkMessage(buf, nullptr, NLMSG_ERROR, seq);
708         auto* err =
709             reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(netlink_message));
710         // Ack the request
711         err->error = 0;
712         netlink_message->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
713         return netlink_message->nlmsg_len;
714       },
715       [preferred_ip, subnet, egress_interface_index](const void* buf,
716                                                      size_t len) {
717         auto* netlink_message = reinterpret_cast<const struct nlmsghdr*>(buf);
718         auto* rtm =
719             reinterpret_cast<const struct rtmsg*>(NLMSG_DATA(netlink_message));
720         EXPECT_EQ(AF_INET6, rtm->rtm_family);
721         EXPECT_EQ(48, rtm->rtm_dst_len);
722         EXPECT_EQ(0, rtm->rtm_src_len);
723         EXPECT_EQ(RT_TABLE_MAIN, rtm->rtm_table);
724         EXPECT_EQ(RTPROT_STATIC, rtm->rtm_protocol);
725         EXPECT_EQ(RT_SCOPE_LINK, rtm->rtm_scope);
726         EXPECT_EQ(RTN_UNICAST, rtm->rtm_type);
727 
728         const struct rtattr* rta;
729         int payload_length = RTM_PAYLOAD(netlink_message);
730         int num_rta = 0;
731         for (rta = RTM_RTA(rtm); RTA_OK(rta, payload_length);
732              rta = RTA_NEXT(rta, payload_length)) {
733           switch (rta->rta_type) {
734             case RTA_PREFSRC: {
735               const auto* raw_address =
736                   reinterpret_cast<const char*>(RTA_DATA(rta));
737               ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
738               QuicIpAddress address;
739               address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
740               EXPECT_EQ(preferred_ip, address);
741               break;
742             }
743             case RTA_GATEWAY: {
744               const auto* raw_address =
745                   reinterpret_cast<const char*>(RTA_DATA(rta));
746               ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
747               QuicIpAddress address;
748               address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
749               EXPECT_EQ(*QboneConstants::GatewayAddress(), address);
750               break;
751             }
752             case RTA_OIF: {
753               ASSERT_EQ(sizeof(int), RTA_PAYLOAD(rta));
754               const auto* interface_index =
755                   reinterpret_cast<const int*>(RTA_DATA(rta));
756               EXPECT_EQ(egress_interface_index, *interface_index);
757               break;
758             }
759             case RTA_DST: {
760               const auto* raw_address =
761                   reinterpret_cast<const char*>(RTA_DATA(rta));
762               ASSERT_EQ(sizeof(struct in6_addr), RTA_PAYLOAD(rta));
763               QuicIpAddress address;
764               address.FromPackedString(raw_address, RTA_PAYLOAD(rta));
765               EXPECT_EQ(subnet.ToString(),
766                         IpRange(address, rtm->rtm_dst_len).ToString());
767               break;
768             }
769             case RTA_TABLE: {
770               ASSERT_EQ(*reinterpret_cast<uint32_t*>(RTA_DATA(rta)),
771                         QboneConstants::kQboneRouteTableId);
772               break;
773             }
774             default:
775               EXPECT_TRUE(false) << "Seeing rtattr that should not be sent";
776           }
777           ++num_rta;
778         }
779         EXPECT_EQ(5, num_rta);
780       });
781   EXPECT_TRUE(netlink->ChangeRoute(
782       Netlink::Verb::kReplace, QboneConstants::kQboneRouteTableId, subnet,
783       RT_SCOPE_LINK, preferred_ip, egress_interface_index,
784       Netlink::kUnspecifiedInitCwnd));
785 }
786 
787 }  // namespace
788 }  // namespace quic::test
789