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