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/rtnetlink_message.h"
6
7 #include <net/if_arp.h>
8
9 #include "quiche/quic/platform/api/quic_ip_address.h"
10 #include "quiche/quic/platform/api/quic_test.h"
11
12 namespace quic {
13 namespace {
14
15 using ::testing::StrEq;
16
TEST(RtnetlinkMessageTest,LinkMessageCanBeCreatedForGetOperation)17 TEST(RtnetlinkMessageTest, LinkMessageCanBeCreatedForGetOperation) {
18 uint16_t flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
19 uint32_t seq = 42;
20 uint32_t pid = 7;
21 auto message = LinkMessage::New(RtnetlinkMessage::Operation::GET, flags, seq,
22 pid, nullptr);
23
24 // No rtattr appended.
25 EXPECT_EQ(1, message.IoVecSize());
26
27 // nlmsghdr is built properly.
28 auto iov = message.BuildIoVec();
29 EXPECT_EQ(NLMSG_SPACE(sizeof(struct rtgenmsg)), iov[0].iov_len);
30 auto* netlink_message = reinterpret_cast<struct nlmsghdr*>(iov[0].iov_base);
31 EXPECT_EQ(NLMSG_LENGTH(sizeof(struct rtgenmsg)), netlink_message->nlmsg_len);
32 EXPECT_EQ(RTM_GETLINK, netlink_message->nlmsg_type);
33 EXPECT_EQ(flags, netlink_message->nlmsg_flags);
34 EXPECT_EQ(seq, netlink_message->nlmsg_seq);
35 EXPECT_EQ(pid, netlink_message->nlmsg_pid);
36
37 // We actually included rtgenmsg instead of the passed in ifinfomsg since this
38 // is a GET operation.
39 EXPECT_EQ(NLMSG_LENGTH(sizeof(struct rtgenmsg)), netlink_message->nlmsg_len);
40 }
41
TEST(RtnetlinkMessageTest,LinkMessageCanBeCreatedForNewOperation)42 TEST(RtnetlinkMessageTest, LinkMessageCanBeCreatedForNewOperation) {
43 struct ifinfomsg interface_info_header = {AF_INET, /* pad */ 0, ARPHRD_TUNNEL,
44 3, 0, 0xffffffff};
45 uint16_t flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
46 uint32_t seq = 42;
47 uint32_t pid = 7;
48 auto message = LinkMessage::New(RtnetlinkMessage::Operation::NEW, flags, seq,
49 pid, &interface_info_header);
50
51 std::string device_name = "device0";
52 message.AppendAttribute(IFLA_IFNAME, device_name.c_str(), device_name.size());
53
54 // One rtattr appended.
55 EXPECT_EQ(2, message.IoVecSize());
56
57 // nlmsghdr is built properly.
58 auto iov = message.BuildIoVec();
59 EXPECT_EQ(NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct ifinfomsg))),
60 iov[0].iov_len);
61 auto* netlink_message = reinterpret_cast<struct nlmsghdr*>(iov[0].iov_base);
62 EXPECT_EQ(NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct ifinfomsg))) +
63 RTA_LENGTH(device_name.size()),
64 netlink_message->nlmsg_len);
65 EXPECT_EQ(RTM_NEWLINK, netlink_message->nlmsg_type);
66 EXPECT_EQ(flags, netlink_message->nlmsg_flags);
67 EXPECT_EQ(seq, netlink_message->nlmsg_seq);
68 EXPECT_EQ(pid, netlink_message->nlmsg_pid);
69
70 // ifinfomsg is included properly.
71 auto* parsed_header =
72 reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(netlink_message));
73 EXPECT_EQ(interface_info_header.ifi_family, parsed_header->ifi_family);
74 EXPECT_EQ(interface_info_header.ifi_type, parsed_header->ifi_type);
75 EXPECT_EQ(interface_info_header.ifi_index, parsed_header->ifi_index);
76 EXPECT_EQ(interface_info_header.ifi_flags, parsed_header->ifi_flags);
77 EXPECT_EQ(interface_info_header.ifi_change, parsed_header->ifi_change);
78
79 // rtattr is handled properly.
80 EXPECT_EQ(RTA_SPACE(device_name.size()), iov[1].iov_len);
81 auto* rta = reinterpret_cast<struct rtattr*>(iov[1].iov_base);
82 EXPECT_EQ(IFLA_IFNAME, rta->rta_type);
83 EXPECT_EQ(RTA_LENGTH(device_name.size()), rta->rta_len);
84 EXPECT_THAT(device_name,
85 StrEq(std::string(reinterpret_cast<char*>(RTA_DATA(rta)),
86 RTA_PAYLOAD(rta))));
87 }
88
TEST(RtnetlinkMessageTest,AddressMessageCanBeCreatedForGetOperation)89 TEST(RtnetlinkMessageTest, AddressMessageCanBeCreatedForGetOperation) {
90 uint16_t flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
91 uint32_t seq = 42;
92 uint32_t pid = 7;
93 auto message = AddressMessage::New(RtnetlinkMessage::Operation::GET, flags,
94 seq, pid, nullptr);
95
96 // No rtattr appended.
97 EXPECT_EQ(1, message.IoVecSize());
98
99 // nlmsghdr is built properly.
100 auto iov = message.BuildIoVec();
101 EXPECT_EQ(NLMSG_SPACE(sizeof(struct rtgenmsg)), iov[0].iov_len);
102 auto* netlink_message = reinterpret_cast<struct nlmsghdr*>(iov[0].iov_base);
103 EXPECT_EQ(NLMSG_LENGTH(sizeof(struct rtgenmsg)), netlink_message->nlmsg_len);
104 EXPECT_EQ(RTM_GETADDR, netlink_message->nlmsg_type);
105 EXPECT_EQ(flags, netlink_message->nlmsg_flags);
106 EXPECT_EQ(seq, netlink_message->nlmsg_seq);
107 EXPECT_EQ(pid, netlink_message->nlmsg_pid);
108
109 // We actually included rtgenmsg instead of the passed in ifinfomsg since this
110 // is a GET operation.
111 EXPECT_EQ(NLMSG_LENGTH(sizeof(struct rtgenmsg)), netlink_message->nlmsg_len);
112 }
113
TEST(RtnetlinkMessageTest,AddressMessageCanBeCreatedForNewOperation)114 TEST(RtnetlinkMessageTest, AddressMessageCanBeCreatedForNewOperation) {
115 struct ifaddrmsg interface_address_header = {AF_INET,
116 /* prefixlen */ 24,
117 /* flags */ 0,
118 /* scope */ RT_SCOPE_LINK,
119 /* index */ 4};
120 uint16_t flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
121 uint32_t seq = 42;
122 uint32_t pid = 7;
123 auto message = AddressMessage::New(RtnetlinkMessage::Operation::NEW, flags,
124 seq, pid, &interface_address_header);
125
126 QuicIpAddress ip;
127 QUICHE_CHECK(ip.FromString("10.0.100.3"));
128 message.AppendAttribute(IFA_ADDRESS, ip.ToPackedString().c_str(),
129 ip.ToPackedString().size());
130
131 // One rtattr is appended.
132 EXPECT_EQ(2, message.IoVecSize());
133
134 // nlmsghdr is built properly.
135 auto iov = message.BuildIoVec();
136 EXPECT_EQ(NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct ifaddrmsg))),
137 iov[0].iov_len);
138 auto* netlink_message = reinterpret_cast<struct nlmsghdr*>(iov[0].iov_base);
139 EXPECT_EQ(NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct ifaddrmsg))) +
140 RTA_LENGTH(ip.ToPackedString().size()),
141 netlink_message->nlmsg_len);
142 EXPECT_EQ(RTM_NEWADDR, netlink_message->nlmsg_type);
143 EXPECT_EQ(flags, netlink_message->nlmsg_flags);
144 EXPECT_EQ(seq, netlink_message->nlmsg_seq);
145 EXPECT_EQ(pid, netlink_message->nlmsg_pid);
146
147 // ifaddrmsg is included properly.
148 auto* parsed_header =
149 reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(netlink_message));
150 EXPECT_EQ(interface_address_header.ifa_family, parsed_header->ifa_family);
151 EXPECT_EQ(interface_address_header.ifa_prefixlen,
152 parsed_header->ifa_prefixlen);
153 EXPECT_EQ(interface_address_header.ifa_flags, parsed_header->ifa_flags);
154 EXPECT_EQ(interface_address_header.ifa_scope, parsed_header->ifa_scope);
155 EXPECT_EQ(interface_address_header.ifa_index, parsed_header->ifa_index);
156
157 // rtattr is handled properly.
158 EXPECT_EQ(RTA_SPACE(ip.ToPackedString().size()), iov[1].iov_len);
159 auto* rta = reinterpret_cast<struct rtattr*>(iov[1].iov_base);
160 EXPECT_EQ(IFA_ADDRESS, rta->rta_type);
161 EXPECT_EQ(RTA_LENGTH(ip.ToPackedString().size()), rta->rta_len);
162 EXPECT_THAT(ip.ToPackedString(),
163 StrEq(std::string(reinterpret_cast<char*>(RTA_DATA(rta)),
164 RTA_PAYLOAD(rta))));
165 }
166
TEST(RtnetlinkMessageTest,RouteMessageCanBeCreatedFromNewOperation)167 TEST(RtnetlinkMessageTest, RouteMessageCanBeCreatedFromNewOperation) {
168 struct rtmsg route_message_header = {AF_INET6,
169 /* rtm_dst_len */ 48,
170 /* rtm_src_len */ 0,
171 /* rtm_tos */ 0,
172 /* rtm_table */ RT_TABLE_MAIN,
173 /* rtm_protocol */ RTPROT_STATIC,
174 /* rtm_scope */ RT_SCOPE_LINK,
175 /* rtm_type */ RTN_LOCAL,
176 /* rtm_flags */ 0};
177 uint16_t flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
178 uint32_t seq = 42;
179 uint32_t pid = 7;
180 auto message = RouteMessage::New(RtnetlinkMessage::Operation::NEW, flags, seq,
181 pid, &route_message_header);
182
183 QuicIpAddress preferred_source;
184 QUICHE_CHECK(preferred_source.FromString("ff80::1"));
185 message.AppendAttribute(RTA_PREFSRC,
186 preferred_source.ToPackedString().c_str(),
187 preferred_source.ToPackedString().size());
188
189 // One rtattr is appended.
190 EXPECT_EQ(2, message.IoVecSize());
191
192 // nlmsghdr is built properly
193 auto iov = message.BuildIoVec();
194 EXPECT_EQ(NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct rtmsg))), iov[0].iov_len);
195 auto* netlink_message = reinterpret_cast<struct nlmsghdr*>(iov[0].iov_base);
196 EXPECT_EQ(NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct rtmsg))) +
197 RTA_LENGTH(preferred_source.ToPackedString().size()),
198 netlink_message->nlmsg_len);
199 EXPECT_EQ(RTM_NEWROUTE, netlink_message->nlmsg_type);
200 EXPECT_EQ(flags, netlink_message->nlmsg_flags);
201 EXPECT_EQ(seq, netlink_message->nlmsg_seq);
202 EXPECT_EQ(pid, netlink_message->nlmsg_pid);
203
204 // rtmsg is included properly.
205 auto* parsed_header =
206 reinterpret_cast<struct rtmsg*>(NLMSG_DATA(netlink_message));
207 EXPECT_EQ(route_message_header.rtm_family, parsed_header->rtm_family);
208 EXPECT_EQ(route_message_header.rtm_dst_len, parsed_header->rtm_dst_len);
209 EXPECT_EQ(route_message_header.rtm_src_len, parsed_header->rtm_src_len);
210 EXPECT_EQ(route_message_header.rtm_tos, parsed_header->rtm_tos);
211 EXPECT_EQ(route_message_header.rtm_table, parsed_header->rtm_table);
212 EXPECT_EQ(route_message_header.rtm_protocol, parsed_header->rtm_protocol);
213 EXPECT_EQ(route_message_header.rtm_scope, parsed_header->rtm_scope);
214 EXPECT_EQ(route_message_header.rtm_type, parsed_header->rtm_type);
215 EXPECT_EQ(route_message_header.rtm_flags, parsed_header->rtm_flags);
216
217 // rtattr is handled properly.
218 EXPECT_EQ(RTA_SPACE(preferred_source.ToPackedString().size()),
219 iov[1].iov_len);
220 auto* rta = reinterpret_cast<struct rtattr*>(iov[1].iov_base);
221 EXPECT_EQ(RTA_PREFSRC, rta->rta_type);
222 EXPECT_EQ(RTA_LENGTH(preferred_source.ToPackedString().size()), rta->rta_len);
223 EXPECT_THAT(preferred_source.ToPackedString(),
224 StrEq(std::string(reinterpret_cast<char*>(RTA_DATA(rta)),
225 RTA_PAYLOAD(rta))));
226 }
227
228 } // namespace
229 } // namespace quic
230