blob: 7cea68f62293f765255f6bad1cda0dd73a02edae [file] [log] [blame]
Hugo Benichi2ac4d072019-05-28 14:51:23 +09001// Copyright 2019 The Chromium OS 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
Garrick Evans3388a032020-03-24 11:25:55 +09005#include "patchpanel/net_util.h"
Hugo Benichi2ac4d072019-05-28 14:51:23 +09006
7#include <arpa/inet.h>
8#include <byteswap.h>
Jason Jeremy Iman16f91722020-01-14 09:53:28 +09009#include <net/ethernet.h>
Hugo Benichi2ac4d072019-05-28 14:51:23 +090010
11#include <gtest/gtest.h>
12
Garrick Evans3388a032020-03-24 11:25:55 +090013namespace patchpanel {
Hugo Benichi2ac4d072019-05-28 14:51:23 +090014
Jason Jeremy Iman16f91722020-01-14 09:53:28 +090015const uint8_t ping_frame[] =
16 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x86\xdd\x60\x0b"
17 "\x8d\xb4\x00\x40\x3a\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
18 "\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
19 "\x00\x00\x00\x00\x00\x01\x80\x00\xb9\x3c\x13\x8f\x00\x09\xde\x6a"
20 "\x78\x5d\x00\x00\x00\x00\x8e\x13\x0f\x00\x00\x00\x00\x00\x10\x11"
21 "\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21"
22 "\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31"
23 "\x32\x33\x34\x35\x36\x37";
24
25const uint8_t rs_frame[] =
26 "\x33\x33\x00\x00\x00\x02\x1a\x9b\x82\xbd\xc0\xa0\x86\xdd\x60\x00"
27 "\x00\x00\x00\x10\x3a\xff\xfe\x80\x00\x00\x00\x00\x00\x00\x2d\x75"
28 "\xb2\x80\x97\x83\x76\xbf\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00"
29 "\x00\x00\x00\x00\x00\x02\x85\x00\x2f\xfc\x00\x00\x00\x00\x01\x01"
30 "\x1a\x9b\x82\xbd\xc0\xa0";
31
32const uint8_t ip_header[] =
33 "\x45\x00\x00\x3d\x7c\x8e\x40\x00\x40\x11\x3d\x36\x64\x73\x5c\x02"
34 "\x64\x73\x5c\x03";
35
36const uint8_t udp_packet[] =
37 "\x45\x00\x00\x65\x44\xf7\x40\x00\x3f\x11\x7d\x62\x64\x57\x54\x5a"
38 "\x64\x73\x5c\x0a\x9d\x6c\x09\xa4\x00\x51\x58\xfb\x70\x72\x6f\x74"
39 "\x6f\x63\x6f\x6c\x20\x20\x61\x73\x73\x75\x6d\x65\x73\x20\x20\x74"
40 "\x68\x61\x74\x20\x74\x68\x65\x20\x49\x6e\x74\x65\x72\x6e\x65\x74"
41 "\x20\x20\x50\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x20\x28\x49\x50\x29"
42 "\x20\x20\x5b\x31\x5d\x20\x69\x73\x20\x75\x73\x65\x64\x20\x61\x73"
43 "\x20\x74\x68\x65\x0a";
44
Hugo Benichi2ac4d072019-05-28 14:51:23 +090045TEST(Byteswap, 16bits) {
46 uint32_t test_cases[] = {
47 0x0000, 0x0001, 0x1000, 0xffff, 0x2244, 0xfffe,
48 };
49
50 for (uint32_t value : test_cases) {
51 EXPECT_EQ(Byteswap16(value), bswap_16(value));
52 EXPECT_EQ(ntohs(value), Ntohs(value));
53 EXPECT_EQ(htons(value), Htons(value));
54 }
55}
56
57TEST(Byteswap, 32bits) {
58 uint32_t test_cases[] = {
59 0x00000000, 0x00000001, 0x10000000, 0xffffffff, 0x11335577, 0xdeadbeef,
60 };
61
62 for (uint32_t value : test_cases) {
63 EXPECT_EQ(Byteswap32(value), bswap_32(value));
64 EXPECT_EQ(ntohl(value), Ntohl(value));
65 EXPECT_EQ(htonl(value), Htonl(value));
66 }
67}
68
69TEST(Ipv4, CreationAndStringConversion) {
70 struct {
71 std::string literal_address;
72 uint8_t bytes[4];
73 } test_cases[] = {
74 {"0.0.0.0", {0, 0, 0, 0}},
75 {"8.8.8.8", {8, 8, 8, 8}},
76 {"8.8.4.4", {8, 8, 4, 4}},
77 {"192.168.0.0", {192, 168, 0, 0}},
78 {"100.115.92.5", {100, 115, 92, 5}},
79 {"100.115.92.6", {100, 115, 92, 6}},
80 {"224.0.0.251", {224, 0, 0, 251}},
81 {"255.255.255.255", {255, 255, 255, 255}},
82 };
83
84 for (auto const& test_case : test_cases) {
85 uint32_t addr = Ipv4Addr(test_case.bytes[0], test_case.bytes[1],
86 test_case.bytes[2], test_case.bytes[3]);
87 EXPECT_EQ(test_case.literal_address, IPv4AddressToString(addr));
88 }
89}
90
Hugo Benichiaf02c262021-01-26 10:24:10 +090091TEST(Ipv6, CreationAndStringConversion) {
92 struct {
93 std::string literal_address;
94 uint8_t bytes[16];
95 } test_cases[] = {
96 {"::", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
97 {"2001:da8:ff:5002:1034:56ff:fe78:9abc",
98 {0x20, 0x01, 0xd, 0xa8, 0, 0xff, 0x50, 0x02, 0x10, 0x34, 0x56, 0xff,
99 0xfe, 0x78, 0x9a, 0xbc}},
100 {"fe80::1122",
101 {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x11, 0x22}},
102 };
103
104 for (auto const& test_case : test_cases) {
105 struct in6_addr addr = {};
106 memcpy(addr.s6_addr, test_case.bytes, sizeof(addr.s6_addr));
107 EXPECT_EQ(test_case.literal_address, IPv6AddressToString(addr));
108 }
109}
110
Hugo Benichi2ac4d072019-05-28 14:51:23 +0900111TEST(Ipv4, CreationAndCidrStringConversion) {
112 struct {
113 std::string literal_address;
114 uint8_t bytes[4];
115 uint32_t prefix_length;
116 } test_cases[] = {
117 {"0.0.0.0/0", {0, 0, 0, 0}, 0},
118 {"192.168.0.0/24", {192, 168, 0, 0}, 24},
119 {"100.115.92.5/30", {100, 115, 92, 5}, 30},
120 {"100.115.92.6/30", {100, 115, 92, 6}, 30},
121 };
122
123 for (auto const& test_case : test_cases) {
124 uint32_t addr = Ipv4Addr(test_case.bytes[0], test_case.bytes[1],
125 test_case.bytes[2], test_case.bytes[3]);
126 EXPECT_EQ(test_case.literal_address,
127 IPv4AddressToCidrString(addr, test_case.prefix_length));
128 }
129}
130
Jason Jeremy Iman16f91722020-01-14 09:53:28 +0900131TEST(Ipv4, IpChecksum) {
132 alignas(4) uint8_t buffer[IP_MAXPACKET];
133
134 iphdr* ip = reinterpret_cast<iphdr*>(buffer);
135
136 memcpy(buffer, ip_header, sizeof(ip_header));
137 uint16_t ori_cksum = ip->check;
138 ip->check = 0;
139 EXPECT_EQ(ori_cksum, Ipv4Checksum(ip));
140}
141
142TEST(Ipv4, UdpChecksum) {
143 alignas(4) uint8_t buffer[IP_MAXPACKET];
144
145 iphdr* ip = reinterpret_cast<iphdr*>(buffer);
146 udphdr* udp = reinterpret_cast<udphdr*>(buffer + sizeof(iphdr));
147
148 memcpy(buffer, udp_packet, sizeof(udp_packet));
149 uint16_t ori_cksum = udp->check;
150 udp->check = 0;
151 EXPECT_EQ(ori_cksum, Udpv4Checksum(ip, udp));
152}
153
154TEST(Ipv6, IcmpChecksum) {
155 alignas(4) uint8_t buffer_extended[IP_MAXPACKET + ETHER_HDR_LEN + 2];
156 uint8_t* buffer = buffer_extended + 2;
157
158 ip6_hdr* ip6 = reinterpret_cast<ip6_hdr*>(buffer + ETHER_HDR_LEN);
159 icmp6_hdr* icmp6 =
160 reinterpret_cast<icmp6_hdr*>(buffer + ETHER_HDR_LEN + sizeof(ip6_hdr));
161
162 memcpy(buffer, ping_frame, sizeof(ping_frame));
163 uint16_t ori_cksum = icmp6->icmp6_cksum;
164 icmp6->icmp6_cksum = 0;
165 EXPECT_EQ(ori_cksum, Icmpv6Checksum(ip6, icmp6));
166
167 memcpy(buffer, rs_frame, sizeof(rs_frame));
168 ori_cksum = icmp6->icmp6_cksum;
169 icmp6->icmp6_cksum = 0;
170 EXPECT_EQ(ori_cksum, Icmpv6Checksum(ip6, icmp6));
171}
172
Taoyu Lia0727dc2020-09-24 19:54:59 +0900173TEST(Ipv6, EUI64Addr) {
174 struct {
175 std::string prefix;
176 MacAddress mac_address;
177 std::string eui64_address;
178 } test_cases[] = {{"::", {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, "::200:ff:fe00:0"},
179 {"2001:da8:ff:5002::",
180 {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc},
181 "2001:da8:ff:5002:1034:56ff:fe78:9abc"},
182 {"fe80::",
183 {0xf4, 0x99, 0x9f, 0xf4, 0x4f, 0xe4},
184 "fe80::f699:9fff:fef4:4fe4"}};
185 in6_addr prefix;
186 in6_addr addr;
187 for (auto const& test_case : test_cases) {
188 inet_pton(AF_INET6, test_case.prefix.c_str(), &prefix);
189 GenerateEUI64Address(&addr, prefix, test_case.mac_address);
190 char eui64_addr_str[INET6_ADDRSTRLEN];
191 inet_ntop(AF_INET6, &addr, eui64_addr_str, INET6_ADDRSTRLEN);
192 EXPECT_EQ(test_case.eui64_address, eui64_addr_str);
193 }
194}
195
Garrick Evans6f4fa3a2020-02-10 16:15:09 +0900196TEST(Ipv4, BroadcastAddr) {
197 uint32_t base = Ipv4Addr(100, 115, 92, 0);
198 struct {
199 uint32_t prefix_len;
200 uint32_t want;
201 } test_cases[] = {
202 {24, Ipv4Addr(100, 115, 92, 255)},
203 {29, Ipv4Addr(100, 115, 92, 7)},
204 {30, Ipv4Addr(100, 115, 92, 3)},
205 {31, Ipv4Addr(100, 115, 92, 1)},
206 };
207
208 for (const auto& t : test_cases) {
209 EXPECT_EQ(Ipv4BroadcastAddr(base, t.prefix_len), t.want);
210 }
211}
212
Hugo Benichie8758b52020-04-03 14:49:01 +0900213TEST(IPv4, SetSockaddrIn) {
214 struct sockaddr_storage sockaddr = {};
215 std::ostringstream stream;
216
217 SetSockaddrIn((struct sockaddr*)&sockaddr, 0);
218 stream << sockaddr;
219 EXPECT_EQ("{family: AF_INET, port: 0, addr: 0.0.0.0}", stream.str());
220
221 stream.str("");
222 SetSockaddrIn((struct sockaddr*)&sockaddr, Ipv4Addr(192, 168, 1, 37));
223 stream << sockaddr;
224 EXPECT_EQ("{family: AF_INET, port: 0, addr: 192.168.1.37}", stream.str());
225}
226
Hugo Benichidcc32392020-02-27 09:14:40 +0900227TEST(PrettyPrint, SocketAddrIn) {
228 struct sockaddr_in ipv4_sockaddr = {};
229 std::ostringstream stream;
230
231 stream << ipv4_sockaddr;
232 EXPECT_EQ("{family: AF_INET, port: 0, addr: 0.0.0.0}", stream.str());
233
234 ipv4_sockaddr.sin_family = AF_INET;
235 ipv4_sockaddr.sin_port = htons(1234);
236 ipv4_sockaddr.sin_addr.s_addr = Ipv4Addr(100, 115, 92, 10);
237 std::string expected_output =
238 "{family: AF_INET, port: 1234, addr: 100.115.92.10}";
239
240 stream.str("");
241 stream << ipv4_sockaddr;
242 EXPECT_EQ(expected_output, stream.str());
243
244 stream.str("");
245 stream << (const struct sockaddr&)ipv4_sockaddr;
246 EXPECT_EQ(expected_output, stream.str());
247
248 struct sockaddr_storage sockaddr_storage = {};
249 memcpy(&sockaddr_storage, &ipv4_sockaddr, sizeof(ipv4_sockaddr));
250
251 stream.str("");
252 stream << sockaddr_storage;
253 EXPECT_EQ(expected_output, stream.str());
254}
255
256TEST(PrettyPrint, SocketAddrIn6) {
257 struct sockaddr_in6 ipv6_sockaddr = {};
258 std::ostringstream stream;
259
260 stream << ipv6_sockaddr;
261 EXPECT_EQ("{family: AF_INET6, port: 0, addr: ::}", stream.str());
262
263 ipv6_sockaddr.sin6_family = AF_INET6;
264 ipv6_sockaddr.sin6_port = htons(2345);
265 unsigned char addr[16] = {0x20, 0x01, 0xd, 0xb1, 0, 0, 0, 0,
266 0xab, 0xcd, 0x12, 0x34, 0x56, 0x78, 0xfe, 0xaa};
267 memcpy(ipv6_sockaddr.sin6_addr.s6_addr, addr, sizeof(addr));
268 std::string expected_output =
269 "{family: AF_INET6, port: 2345, addr: 2001:db1::abcd:1234:5678:feaa}";
270
271 stream.str("");
272 stream << ipv6_sockaddr;
273 EXPECT_EQ(expected_output, stream.str());
274
275 stream.str("");
276 stream << (const struct sockaddr&)ipv6_sockaddr;
277 EXPECT_EQ(expected_output, stream.str());
278
279 struct sockaddr_storage sockaddr_storage = {};
280 memcpy(&sockaddr_storage, &ipv6_sockaddr, sizeof(ipv6_sockaddr));
281
282 stream.str("");
283 stream << sockaddr_storage;
284 EXPECT_EQ(expected_output, stream.str());
285}
286
287TEST(PrettyPrint, SocketAddrVsock) {
288 struct sockaddr_vm vm_sockaddr = {};
289 std::ostringstream stream;
290
291 stream << vm_sockaddr;
292 EXPECT_EQ("{family: AF_VSOCK, port: 0, cid: 0}", stream.str());
293
294 vm_sockaddr.svm_family = AF_VSOCK;
295 vm_sockaddr.svm_port = 5555;
296 vm_sockaddr.svm_cid = 4;
297 std::string expected_output = "{family: AF_VSOCK, port: 5555, cid: 4}";
298
299 stream.str("");
300 stream << vm_sockaddr;
301 EXPECT_EQ(expected_output, stream.str());
302
303 stream.str("");
304 stream << (const struct sockaddr&)vm_sockaddr;
305 EXPECT_EQ(expected_output, stream.str());
306
307 struct sockaddr_storage sockaddr_storage = {};
308 memcpy(&sockaddr_storage, &vm_sockaddr, sizeof(vm_sockaddr));
309
310 stream.str("");
311 stream << sockaddr_storage;
312 EXPECT_EQ(expected_output, stream.str());
313}
314
315TEST(PrettyPrint, SocketAddrUnix) {
316 struct sockaddr_un unix_sockaddr = {};
317 std::ostringstream stream;
318
319 stream << unix_sockaddr;
320 EXPECT_EQ("{family: AF_UNIX, path: @}", stream.str());
321
322 // Fill |sun_path| with an invalid non-null-terminated c string.
323 std::string bogus_output = "{family: AF_UNIX, path: ";
324 for (size_t i = 0; i < sizeof(unix_sockaddr.sun_path); i++) {
325 unix_sockaddr.sun_path[i] = 'a';
326 bogus_output += 'a';
327 }
328 bogus_output += '}';
329 stream.str("");
330 stream << unix_sockaddr;
331 EXPECT_EQ(bogus_output, stream.str());
332
333 memset(&unix_sockaddr, 0, sizeof(unix_sockaddr));
334 unix_sockaddr.sun_family = AF_UNIX;
335 std::string sun_path = "/run/arc/adb";
336 memcpy(&unix_sockaddr.sun_path, sun_path.c_str(), strlen(sun_path.c_str()));
337 std::string expected_output = "{family: AF_UNIX, path: /run/arc/adb}";
338
339 stream.str("");
340 stream << unix_sockaddr;
341 EXPECT_EQ(expected_output, stream.str());
342
343 stream.str("");
344 stream << (const struct sockaddr&)unix_sockaddr;
345 EXPECT_EQ(expected_output, stream.str());
346
347 struct sockaddr_storage sockaddr_storage = {};
348 memcpy(&sockaddr_storage, &unix_sockaddr, sizeof(unix_sockaddr));
349
350 stream.str("");
351 stream << sockaddr_storage;
352 EXPECT_EQ(expected_output, stream.str());
353}
354
Hugo Benichie8758b52020-04-03 14:49:01 +0900355TEST(PrettyPrint, Rtentry) {
356 struct rtentry route;
357 memset(&route, 0, sizeof(route));
358 std::ostringstream stream;
359
360 stream << route;
361 EXPECT_EQ(
362 "{rt_dst: {unset}, rt_genmask: {unset}, rt_gateway: {unset}, rt_dev: "
363 "null, rt_flags: 0}",
364 stream.str());
365
366 SetSockaddrIn(&route.rt_dst, Ipv4Addr(100, 115, 92, 128));
367 SetSockaddrIn(&route.rt_genmask, Ipv4Addr(255, 255, 255, 252));
368 SetSockaddrIn(&route.rt_gateway, Ipv4Addr(192, 168, 1, 1));
369 std::string rt_dev = "eth0";
370 route.rt_dev = (char*)rt_dev.c_str();
371 route.rt_flags =
372 RTF_UP | RTF_GATEWAY | RTF_DYNAMIC | RTF_MODIFIED | RTF_REJECT;
373 stream.str("");
374 stream << route;
375 EXPECT_EQ(
376 "{rt_dst: {family: AF_INET, port: 0, addr: 100.115.92.128}, rt_genmask: "
377 "{family: AF_INET, port: 0, addr: 255.255.255.252}, rt_gateway: {family: "
378 "AF_INET, port: 0, addr: 192.168.1.1}, rt_dev: eth0, rt_flags: RTF_UP | "
379 "RTF_GATEWAY | RTF_DYNAMIC | RTF_MODIFIED | RTF_REJECT}",
380 stream.str());
381}
382
Garrick Evans3388a032020-03-24 11:25:55 +0900383} // namespace patchpanel