1 /*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * clatd_test.cpp - unit tests for clatd
17 */
18
19 #include <iostream>
20
21 #include <arpa/inet.h>
22 #include <linux/if_packet.h>
23 #include <netinet/in6.h>
24 #include <stdio.h>
25 #include <sys/uio.h>
26
27 #include <gtest/gtest.h>
28
29 #include "netutils/ifc.h"
30 #include "tun_interface.h"
31
32 extern "C" {
33 #include "checksum.h"
34 #include "clatd.h"
35 #include "config.h"
36 #include "translate.h"
37 }
38
39 // For convenience.
40 #define ARRAYSIZE(x) sizeof((x)) / sizeof((x)[0])
41
42 using android::net::TunInterface;
43
44 // Default translation parameters.
45 static const char kIPv4LocalAddr[] = "192.0.0.4";
46 static const char kIPv6LocalAddr[] = "2001:db8:0:b11::464";
47 static const char kIPv6PlatSubnet[] = "64:ff9b::";
48
49 // clang-format off
50 // Test packet portions. Defined as macros because it's easy to concatenate them to make packets.
51 #define IPV4_HEADER(p, c1, c2) \
52 0x45, 0x00, 0, 41, /* Version=4, IHL=5, ToS=0x80, len=41 */ \
53 0x00, 0x00, 0x40, 0x00, /* ID=0x0000, flags=IP_DF, offset=0 */ \
54 55, (p), (c1), (c2), /* TTL=55, protocol=p, checksum=c1,c2 */ \
55 192, 0, 0, 4, /* Src=192.0.0.4 */ \
56 8, 8, 8, 8, /* Dst=8.8.8.8 */
57 #define IPV4_UDP_HEADER IPV4_HEADER(IPPROTO_UDP, 0x73, 0xb0)
58 #define IPV4_ICMP_HEADER IPV4_HEADER(IPPROTO_ICMP, 0x73, 0xc0)
59
60 #define IPV6_HEADER(p) \
61 0x60, 0x00, 0, 0, /* Version=6, tclass=0x00, flowlabel=0 */ \
62 0, 21, (p), 55, /* plen=11, nxthdr=p, hlim=55 */ \
63 0x20, 0x01, 0x0d, 0xb8, /* Src=2001:db8:0:b11::464 */ \
64 0x00, 0x00, 0x0b, 0x11, \
65 0x00, 0x00, 0x00, 0x00, \
66 0x00, 0x00, 0x04, 0x64, \
67 0x00, 0x64, 0xff, 0x9b, /* Dst=64:ff9b::8.8.8.8 */ \
68 0x00, 0x00, 0x00, 0x00, \
69 0x00, 0x00, 0x00, 0x00, \
70 0x08, 0x08, 0x08, 0x08,
71 #define IPV6_UDP_HEADER IPV6_HEADER(IPPROTO_UDP)
72 #define IPV6_ICMPV6_HEADER IPV6_HEADER(IPPROTO_ICMPV6)
73
74 #define UDP_LEN 21
75 #define UDP_HEADER \
76 0xc8, 0x8b, 0, 53, /* Port 51339->53 */ \
77 0x00, UDP_LEN, 0, 0, /* Length 21, checksum empty for now */
78
79 #define PAYLOAD 'H', 'e', 'l', 'l', 'o', ' ', 0x4e, 0xb8, 0x96, 0xe7, 0x95, 0x8c, 0x00
80
81 #define IPV4_PING \
82 0x08, 0x00, 0x88, 0xd0, /* Type 8, code 0, checksum 0x88d0 */ \
83 0xd0, 0x0d, 0x00, 0x03, /* ID=0xd00d, seq=3 */
84
85 #define IPV6_PING \
86 0x80, 0x00, 0xc3, 0x42, /* Type 128, code 0, checksum 0xc342 */ \
87 0xd0, 0x0d, 0x00, 0x03, /* ID=0xd00d, seq=3 */
88
89 // Macros to return pseudo-headers from packets.
90 #define IPV4_PSEUDOHEADER(ip, tlen) \
91 ip[12], ip[13], ip[14], ip[15], /* Source address */ \
92 ip[16], ip[17], ip[18], ip[19], /* Destination address */ \
93 0, ip[9], /* 0, protocol */ \
94 ((tlen) >> 16) & 0xff, (tlen) & 0xff, /* Transport length */
95
96 #define IPV6_PSEUDOHEADER(ip6, protocol, tlen) \
97 ip6[8], ip6[9], ip6[10], ip6[11], /* Source address */ \
98 ip6[12], ip6[13], ip6[14], ip6[15], \
99 ip6[16], ip6[17], ip6[18], ip6[19], \
100 ip6[20], ip6[21], ip6[22], ip6[23], \
101 ip6[24], ip6[25], ip6[26], ip6[27], /* Destination address */ \
102 ip6[28], ip6[29], ip6[30], ip6[31], \
103 ip6[32], ip6[33], ip6[34], ip6[35], \
104 ip6[36], ip6[37], ip6[38], ip6[39], \
105 ((tlen) >> 24) & 0xff, /* Transport length */ \
106 ((tlen) >> 16) & 0xff, \
107 ((tlen) >> 8) & 0xff, \
108 (tlen) & 0xff, \
109 0, 0, 0, (protocol),
110
111 // A fragmented DNS request.
112 static const uint8_t kIPv4Frag1[] = {
113 0x45, 0x00, 0x00, 0x24, 0xfe, 0x47, 0x20, 0x00, 0x40, 0x11,
114 0x8c, 0x6d, 0xc0, 0x00, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08,
115 0x14, 0x5d, 0x00, 0x35, 0x00, 0x29, 0x68, 0xbb, 0x50, 0x47,
116 0x01, 0x00, 0x00, 0x01, 0x00, 0x00
117 };
118 static const uint8_t kIPv4Frag2[] = {
119 0x45, 0x00, 0x00, 0x24, 0xfe, 0x47, 0x20, 0x02, 0x40, 0x11,
120 0x8c, 0x6b, 0xc0, 0x00, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08,
121 0x00, 0x00, 0x00, 0x00, 0x04, 0x69, 0x70, 0x76, 0x34, 0x06,
122 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65
123 };
124 static const uint8_t kIPv4Frag3[] = {
125 0x45, 0x00, 0x00, 0x1d, 0xfe, 0x47, 0x00, 0x04, 0x40, 0x11,
126 0xac, 0x70, 0xc0, 0x00, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08,
127 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
128 };
129 static const uint8_t *kIPv4Fragments[] = { kIPv4Frag1, kIPv4Frag2, kIPv4Frag3 };
130 static const size_t kIPv4FragLengths[] = { sizeof(kIPv4Frag1), sizeof(kIPv4Frag2),
131 sizeof(kIPv4Frag3) };
132
133 static const uint8_t kIPv6Frag1[] = {
134 0x60, 0x00, 0x00, 0x00, 0x00, 0x18, 0x2c, 0x40, 0x20, 0x01,
135 0x0d, 0xb8, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x00, 0x00, 0x00,
136 0x00, 0x00, 0x04, 0x64, 0x00, 0x64, 0xff, 0x9b, 0x00, 0x00,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
138 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0xfe, 0x47, 0x14, 0x5d,
139 0x00, 0x35, 0x00, 0x29, 0xeb, 0x91, 0x50, 0x47, 0x01, 0x00,
140 0x00, 0x01, 0x00, 0x00
141 };
142
143 static const uint8_t kIPv6Frag2[] = {
144 0x60, 0x00, 0x00, 0x00, 0x00, 0x18, 0x2c, 0x40, 0x20, 0x01,
145 0x0d, 0xb8, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x00, 0x00, 0x00,
146 0x00, 0x00, 0x04, 0x64, 0x00, 0x64, 0xff, 0x9b, 0x00, 0x00,
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
148 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0xfe, 0x47, 0x00, 0x00,
149 0x00, 0x00, 0x04, 0x69, 0x70, 0x76, 0x34, 0x06, 0x67, 0x6f,
150 0x6f, 0x67, 0x6c, 0x65
151 };
152
153 static const uint8_t kIPv6Frag3[] = {
154 0x60, 0x00, 0x00, 0x00, 0x00, 0x11, 0x2c, 0x40, 0x20, 0x01,
155 0x0d, 0xb8, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0x04, 0x64, 0x00, 0x64, 0xff, 0x9b, 0x00, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
158 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0xfe, 0x47, 0x03, 0x63,
159 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
160 };
161 static const uint8_t *kIPv6Fragments[] = { kIPv6Frag1, kIPv6Frag2, kIPv6Frag3 };
162 static const size_t kIPv6FragLengths[] = { sizeof(kIPv6Frag1), sizeof(kIPv6Frag2),
163 sizeof(kIPv6Frag3) };
164
165 static const uint8_t kReassembledIPv4[] = {
166 0x45, 0x00, 0x00, 0x3d, 0xfe, 0x47, 0x00, 0x00, 0x40, 0x11,
167 0xac, 0x54, 0xc0, 0x00, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08,
168 0x14, 0x5d, 0x00, 0x35, 0x00, 0x29, 0x68, 0xbb, 0x50, 0x47,
169 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 0x04, 0x69, 0x70, 0x76, 0x34, 0x06, 0x67, 0x6f, 0x6f, 0x67,
171 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00,
172 0x01
173 };
174 // clang-format on
175
176 // Expected checksums.
177 static const uint32_t kUdpPartialChecksum = 0xd5c8;
178 static const uint32_t kPayloadPartialChecksum = 0x31e9c;
179 static const uint16_t kUdpV4Checksum = 0xd0c7;
180 static const uint16_t kUdpV6Checksum = 0xa74a;
181
ip_version(const uint8_t * packet)182 uint8_t ip_version(const uint8_t *packet) {
183 uint8_t version = packet[0] >> 4;
184 return version;
185 }
186
is_ipv4_fragment(struct iphdr * ip)187 int is_ipv4_fragment(struct iphdr *ip) {
188 // A packet is a fragment if its fragment offset is nonzero or if the MF flag is set.
189 return ntohs(ip->frag_off) & (IP_OFFMASK | IP_MF);
190 }
191
is_ipv6_fragment(struct ip6_hdr * ip6,size_t len)192 int is_ipv6_fragment(struct ip6_hdr *ip6, size_t len) {
193 if (ip6->ip6_nxt != IPPROTO_FRAGMENT) {
194 return 0;
195 }
196 struct ip6_frag *frag = (struct ip6_frag *)(ip6 + 1);
197 return len >= sizeof(*ip6) + sizeof(*frag) &&
198 (frag->ip6f_offlg & (IP6F_OFF_MASK | IP6F_MORE_FRAG));
199 }
200
ipv4_fragment_offset(struct iphdr * ip)201 int ipv4_fragment_offset(struct iphdr *ip) {
202 return ntohs(ip->frag_off) & IP_OFFMASK;
203 }
204
ipv6_fragment_offset(struct ip6_frag * frag)205 int ipv6_fragment_offset(struct ip6_frag *frag) {
206 return ntohs((frag->ip6f_offlg & IP6F_OFF_MASK) >> 3);
207 }
208
check_packet(const uint8_t * packet,size_t len,const char * msg)209 void check_packet(const uint8_t *packet, size_t len, const char *msg) {
210 void *payload;
211 size_t payload_length = 0;
212 uint32_t pseudo_checksum = 0;
213 uint8_t protocol = 0;
214 int version = ip_version(packet);
215 switch (version) {
216 case 4: {
217 struct iphdr *ip = (struct iphdr *)packet;
218 ASSERT_GE(len, sizeof(*ip)) << msg << ": IPv4 packet shorter than IPv4 header\n";
219 EXPECT_EQ(5, ip->ihl) << msg << ": Unsupported IP header length\n";
220 EXPECT_EQ(len, ntohs(ip->tot_len)) << msg << ": Incorrect IPv4 length\n";
221 EXPECT_EQ(0, ip_checksum(ip, sizeof(*ip))) << msg << ": Incorrect IP checksum\n";
222 protocol = ip->protocol;
223 payload = ip + 1;
224 if (!is_ipv4_fragment(ip)) {
225 payload_length = len - sizeof(*ip);
226 pseudo_checksum = ipv4_pseudo_header_checksum(ip, payload_length);
227 }
228 ASSERT_TRUE(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP || protocol == IPPROTO_ICMP)
229 << msg << ": Unsupported IPv4 protocol " << protocol << "\n";
230 break;
231 }
232 case 6: {
233 struct ip6_hdr *ip6 = (struct ip6_hdr *)packet;
234 ASSERT_GE(len, sizeof(*ip6)) << msg << ": IPv6 packet shorter than IPv6 header\n";
235 EXPECT_EQ(len - sizeof(*ip6), htons(ip6->ip6_plen)) << msg << ": Incorrect IPv6 length\n";
236
237 if (ip6->ip6_nxt == IPPROTO_FRAGMENT) {
238 struct ip6_frag *frag = (struct ip6_frag *)(ip6 + 1);
239 ASSERT_GE(len, sizeof(*ip6) + sizeof(*frag))
240 << msg << ": IPv6 fragment: short fragment header\n";
241 protocol = frag->ip6f_nxt;
242 payload = frag + 1;
243 // Even though the packet has a Fragment header, it might not be a fragment.
244 if (!is_ipv6_fragment(ip6, len)) {
245 payload_length = len - sizeof(*ip6) - sizeof(*frag);
246 }
247 } else {
248 // Since there are no extension headers except Fragment, this must be the payload.
249 protocol = ip6->ip6_nxt;
250 payload = ip6 + 1;
251 payload_length = len - sizeof(*ip6);
252 }
253 ASSERT_TRUE(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP || protocol == IPPROTO_ICMPV6)
254 << msg << ": Unsupported IPv6 next header " << protocol;
255 if (payload_length) {
256 pseudo_checksum = ipv6_pseudo_header_checksum(ip6, payload_length, protocol);
257 }
258 break;
259 }
260 default:
261 FAIL() << msg << ": Unsupported IP version " << version << "\n";
262 return;
263 }
264
265 // If we understand the payload, verify the checksum.
266 if (payload_length) {
267 uint16_t checksum;
268 switch (protocol) {
269 case IPPROTO_UDP:
270 case IPPROTO_TCP:
271 case IPPROTO_ICMPV6:
272 checksum = ip_checksum_finish(ip_checksum_add(pseudo_checksum, payload, payload_length));
273 break;
274 case IPPROTO_ICMP:
275 checksum = ip_checksum(payload, payload_length);
276 break;
277 default:
278 checksum = 0; // Don't check.
279 break;
280 }
281 EXPECT_EQ(0, checksum) << msg << ": Incorrect transport checksum\n";
282 }
283
284 if (protocol == IPPROTO_UDP) {
285 struct udphdr *udp = (struct udphdr *)payload;
286 EXPECT_NE(0, udp->check) << msg << ": UDP checksum 0 should be 0xffff";
287 // If this is not a fragment, check the UDP length field.
288 if (payload_length) {
289 EXPECT_EQ(payload_length, ntohs(udp->len)) << msg << ": Incorrect UDP length\n";
290 }
291 }
292 }
293
reassemble_packet(const uint8_t ** fragments,const size_t lengths[],int numpackets,uint8_t * reassembled,size_t * reassembled_len,const char * msg)294 void reassemble_packet(const uint8_t **fragments, const size_t lengths[], int numpackets,
295 uint8_t *reassembled, size_t *reassembled_len, const char *msg) {
296 struct iphdr *ip = nullptr;
297 struct ip6_hdr *ip6 = nullptr;
298 size_t total_length, pos = 0;
299 uint8_t protocol = 0;
300 uint8_t version = ip_version(fragments[0]);
301
302 for (int i = 0; i < numpackets; i++) {
303 const uint8_t *packet = fragments[i];
304 int len = lengths[i];
305 int headersize, payload_offset;
306
307 ASSERT_EQ(ip_version(packet), version) << msg << ": Inconsistent fragment versions\n";
308 check_packet(packet, len, "Fragment sanity check");
309
310 switch (version) {
311 case 4: {
312 struct iphdr *ip_orig = (struct iphdr *)packet;
313 headersize = sizeof(*ip_orig);
314 ASSERT_TRUE(is_ipv4_fragment(ip_orig))
315 << msg << ": IPv4 fragment #" << i + 1 << " not a fragment\n";
316 ASSERT_EQ(pos, ipv4_fragment_offset(ip_orig) * 8 + ((i != 0) ? sizeof(*ip) : 0))
317 << msg << ": IPv4 fragment #" << i + 1 << ": inconsistent offset\n";
318
319 headersize = sizeof(*ip_orig);
320 payload_offset = headersize;
321 if (pos == 0) {
322 ip = (struct iphdr *)reassembled;
323 }
324 break;
325 }
326 case 6: {
327 struct ip6_hdr *ip6_orig = (struct ip6_hdr *)packet;
328 struct ip6_frag *frag = (struct ip6_frag *)(ip6_orig + 1);
329 ASSERT_TRUE(is_ipv6_fragment(ip6_orig, len))
330 << msg << ": IPv6 fragment #" << i + 1 << " not a fragment\n";
331 ASSERT_EQ(pos, ipv6_fragment_offset(frag) * 8 + ((i != 0) ? sizeof(*ip6) : 0))
332 << msg << ": IPv6 fragment #" << i + 1 << ": inconsistent offset\n";
333
334 headersize = sizeof(*ip6_orig);
335 payload_offset = sizeof(*ip6_orig) + sizeof(*frag);
336 if (pos == 0) {
337 ip6 = (struct ip6_hdr *)reassembled;
338 protocol = frag->ip6f_nxt;
339 }
340 break;
341 }
342 default:
343 FAIL() << msg << ": Invalid IP version << " << version;
344 }
345
346 // If this is the first fragment, copy the header.
347 if (pos == 0) {
348 ASSERT_LT(headersize, (int)*reassembled_len) << msg << ": Reassembly buffer too small\n";
349 memcpy(reassembled, packet, headersize);
350 total_length = headersize;
351 pos += headersize;
352 }
353
354 // Copy the payload.
355 int payload_length = len - payload_offset;
356 total_length += payload_length;
357 ASSERT_LT(total_length, *reassembled_len) << msg << ": Reassembly buffer too small\n";
358 memcpy(reassembled + pos, packet + payload_offset, payload_length);
359 pos += payload_length;
360 }
361
362 // Fix up the reassembled headers to reflect fragmentation and length (and IPv4 checksum).
363 ASSERT_EQ(total_length, pos) << msg << ": Reassembled packet length incorrect\n";
364 if (ip) {
365 ip->frag_off &= ~htons(IP_MF);
366 ip->tot_len = htons(total_length);
367 ip->check = 0;
368 ip->check = ip_checksum(ip, sizeof(*ip));
369 ASSERT_FALSE(is_ipv4_fragment(ip)) << msg << ": reassembled IPv4 packet is a fragment!\n";
370 }
371 if (ip6) {
372 ip6->ip6_nxt = protocol;
373 ip6->ip6_plen = htons(total_length - sizeof(*ip6));
374 ASSERT_FALSE(is_ipv6_fragment(ip6, ip6->ip6_plen))
375 << msg << ": reassembled IPv6 packet is a fragment!\n";
376 }
377
378 *reassembled_len = total_length;
379 }
380
check_data_matches(const void * expected,const void * actual,size_t len,const char * msg)381 void check_data_matches(const void *expected, const void *actual, size_t len, const char *msg) {
382 if (memcmp(expected, actual, len)) {
383 // Hex dump, 20 bytes per line, one space between bytes (1 byte = 3 chars), indented by 4.
384 int hexdump_len = len * 3 + (len / 20 + 1) * 5;
385 char expected_hexdump[hexdump_len], actual_hexdump[hexdump_len];
386 unsigned pos = 0;
387 for (unsigned i = 0; i < len; i++) {
388 if (i % 20 == 0) {
389 snprintf(expected_hexdump + pos, hexdump_len - pos, "\n ");
390 snprintf(actual_hexdump + pos, hexdump_len - pos, "\n ");
391 pos += 4;
392 }
393 snprintf(expected_hexdump + pos, hexdump_len - pos, " %02x", ((uint8_t *)expected)[i]);
394 snprintf(actual_hexdump + pos, hexdump_len - pos, " %02x", ((uint8_t *)actual)[i]);
395 pos += 3;
396 }
397 FAIL() << msg << ": Data doesn't match"
398 << "\n Expected:" << (char *) expected_hexdump
399 << "\n Actual:" << (char *) actual_hexdump << "\n";
400 }
401 }
402
fix_udp_checksum(uint8_t * packet)403 void fix_udp_checksum(uint8_t *packet) {
404 uint32_t pseudo_checksum;
405 uint8_t version = ip_version(packet);
406 struct udphdr *udp;
407 switch (version) {
408 case 4: {
409 struct iphdr *ip = (struct iphdr *)packet;
410 udp = (struct udphdr *)(ip + 1);
411 pseudo_checksum = ipv4_pseudo_header_checksum(ip, ntohs(udp->len));
412 break;
413 }
414 case 6: {
415 struct ip6_hdr *ip6 = (struct ip6_hdr *)packet;
416 udp = (struct udphdr *)(ip6 + 1);
417 pseudo_checksum = ipv6_pseudo_header_checksum(ip6, ntohs(udp->len), IPPROTO_UDP);
418 break;
419 }
420 default:
421 FAIL() << "unsupported IP version" << version << "\n";
422 return;
423 }
424
425 udp->check = 0;
426 udp->check = ip_checksum_finish(ip_checksum_add(pseudo_checksum, udp, ntohs(udp->len)));
427 }
428
429 // Testing stub for send_rawv6. The real version uses sendmsg() with a
430 // destination IPv6 address, and attempting to call that on our test socketpair
431 // fd results in EINVAL.
send_rawv6(int fd,clat_packet out,int iov_len)432 extern "C" void send_rawv6(int fd, clat_packet out, int iov_len) { writev(fd, out, iov_len); }
433
do_translate_packet(const uint8_t * original,size_t original_len,uint8_t * out,size_t * outlen,const char * msg)434 void do_translate_packet(const uint8_t *original, size_t original_len, uint8_t *out, size_t *outlen,
435 const char *msg) {
436 int fds[2];
437 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, fds)) {
438 abort();
439 }
440
441 char foo[512];
442 snprintf(foo, sizeof(foo), "%s: Invalid original packet", msg);
443 check_packet(original, original_len, foo);
444
445 int read_fd, write_fd;
446 uint16_t expected_proto;
447 int version = ip_version(original);
448 switch (version) {
449 case 4:
450 expected_proto = htons(ETH_P_IPV6);
451 read_fd = fds[1];
452 write_fd = fds[0];
453 break;
454 case 6:
455 expected_proto = htons(ETH_P_IP);
456 read_fd = fds[0];
457 write_fd = fds[1];
458 break;
459 default:
460 FAIL() << msg << ": Unsupported IP version " << version << "\n";
461 break;
462 }
463
464 translate_packet(write_fd, (version == 4), original, original_len);
465
466 snprintf(foo, sizeof(foo), "%s: Invalid translated packet", msg);
467 if (version == 6) {
468 // Translating to IPv4. Expect a tun header.
469 struct tun_pi new_tun_header;
470 struct iovec iov[] = {
471 { &new_tun_header, sizeof(new_tun_header) },
472 { out, *outlen },
473 };
474
475 int len = readv(read_fd, iov, 2);
476 if (len > (int)sizeof(new_tun_header)) {
477 ASSERT_LT((size_t)len, *outlen) << msg << ": Translated packet buffer too small\n";
478 EXPECT_EQ(expected_proto, new_tun_header.proto) << msg << "Unexpected tun proto\n";
479 *outlen = len - sizeof(new_tun_header);
480 check_packet(out, *outlen, msg);
481 } else {
482 FAIL() << msg << ": Packet was not translated: len=" << len;
483 *outlen = 0;
484 }
485 } else {
486 // Translating to IPv6. Expect raw packet.
487 *outlen = read(read_fd, out, *outlen);
488 check_packet(out, *outlen, msg);
489 }
490 }
491
check_translated_packet(const uint8_t * original,size_t original_len,const uint8_t * expected,size_t expected_len,const char * msg)492 void check_translated_packet(const uint8_t *original, size_t original_len, const uint8_t *expected,
493 size_t expected_len, const char *msg) {
494 uint8_t translated[MAXMTU];
495 size_t translated_len = sizeof(translated);
496 do_translate_packet(original, original_len, translated, &translated_len, msg);
497 EXPECT_EQ(expected_len, translated_len) << msg << ": Translated packet length incorrect\n";
498 check_data_matches(expected, translated, translated_len, msg);
499 }
500
check_fragment_translation(const uint8_t * original[],const size_t original_lengths[],const uint8_t * expected[],const size_t expected_lengths[],int numfragments,const char * msg)501 void check_fragment_translation(const uint8_t *original[], const size_t original_lengths[],
502 const uint8_t *expected[], const size_t expected_lengths[],
503 int numfragments, const char *msg) {
504 for (int i = 0; i < numfragments; i++) {
505 // Check that each of the fragments translates as expected.
506 char frag_msg[512];
507 snprintf(frag_msg, sizeof(frag_msg), "%s: fragment #%d", msg, i + 1);
508 check_translated_packet(original[i], original_lengths[i], expected[i], expected_lengths[i],
509 frag_msg);
510 }
511
512 // Sanity check that reassembling the original and translated fragments produces valid packets.
513 uint8_t reassembled[MAXMTU];
514 size_t reassembled_len = sizeof(reassembled);
515 reassemble_packet(original, original_lengths, numfragments, reassembled, &reassembled_len, msg);
516 check_packet(reassembled, reassembled_len, msg);
517
518 uint8_t translated[MAXMTU];
519 size_t translated_len = sizeof(translated);
520 do_translate_packet(reassembled, reassembled_len, translated, &translated_len, msg);
521 check_packet(translated, translated_len, msg);
522 }
523
get_transport_checksum(const uint8_t * packet)524 int get_transport_checksum(const uint8_t *packet) {
525 struct iphdr *ip;
526 struct ip6_hdr *ip6;
527 uint8_t protocol;
528 const void *payload;
529
530 int version = ip_version(packet);
531 switch (version) {
532 case 4:
533 ip = (struct iphdr *)packet;
534 if (is_ipv4_fragment(ip)) {
535 return -1;
536 }
537 protocol = ip->protocol;
538 payload = ip + 1;
539 break;
540 case 6:
541 ip6 = (struct ip6_hdr *)packet;
542 protocol = ip6->ip6_nxt;
543 payload = ip6 + 1;
544 break;
545 default:
546 return -1;
547 }
548
549 switch (protocol) {
550 case IPPROTO_UDP:
551 return ((struct udphdr *)payload)->check;
552
553 case IPPROTO_TCP:
554 return ((struct tcphdr *)payload)->check;
555
556 case IPPROTO_FRAGMENT:
557 default:
558 return -1;
559 }
560 }
561
562 class ClatdTest : public ::testing::Test {
563 protected:
564 static TunInterface sTun;
565
SetUp()566 virtual void SetUp() {
567 inet_pton(AF_INET, kIPv4LocalAddr, &Global_Clatd_Config.ipv4_local_subnet);
568 inet_pton(AF_INET6, kIPv6PlatSubnet, &Global_Clatd_Config.plat_subnet);
569 memset(&Global_Clatd_Config.ipv6_local_subnet, 0, sizeof(in6_addr));
570 Global_Clatd_Config.native_ipv6_interface = const_cast<char *>(sTun.name().c_str());
571 }
572
573 // Static because setting up the tun interface takes about 40ms.
SetUpTestCase()574 static void SetUpTestCase() { ASSERT_EQ(0, sTun.init()); }
575
576 // Closing the socket removes the interface and IP addresses.
TearDownTestCase()577 static void TearDownTestCase() { sTun.destroy(); }
578 };
579
580 TunInterface ClatdTest::sTun;
581
expect_ipv6_addr_equal(struct in6_addr * expected,struct in6_addr * actual)582 void expect_ipv6_addr_equal(struct in6_addr *expected, struct in6_addr *actual) {
583 if (!IN6_ARE_ADDR_EQUAL(expected, actual)) {
584 char expected_str[INET6_ADDRSTRLEN], actual_str[INET6_ADDRSTRLEN];
585 inet_ntop(AF_INET6, expected, expected_str, sizeof(expected_str));
586 inet_ntop(AF_INET6, actual, actual_str, sizeof(actual_str));
587 FAIL()
588 << "Unexpected IPv6 address:: "
589 << "\n Expected: " << expected_str
590 << "\n Actual: " << actual_str
591 << "\n";
592 }
593 }
594
TEST_F(ClatdTest,TestIPv6PrefixEqual)595 TEST_F(ClatdTest, TestIPv6PrefixEqual) {
596 EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.plat_subnet,
597 &Global_Clatd_Config.plat_subnet));
598 EXPECT_FALSE(ipv6_prefix_equal(&Global_Clatd_Config.plat_subnet,
599 &Global_Clatd_Config.ipv6_local_subnet));
600
601 struct in6_addr subnet2 = Global_Clatd_Config.ipv6_local_subnet;
602 EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &subnet2));
603 EXPECT_TRUE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet));
604
605 subnet2.s6_addr[6] = 0xff;
606 EXPECT_FALSE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &subnet2));
607 EXPECT_FALSE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet));
608 }
609
TEST_F(ClatdTest,DataSanitycheck)610 TEST_F(ClatdTest, DataSanitycheck) {
611 // Sanity checks the data.
612 uint8_t v4_header[] = { IPV4_UDP_HEADER };
613 ASSERT_EQ(sizeof(struct iphdr), sizeof(v4_header)) << "Test IPv4 header: incorrect length\n";
614
615 uint8_t v6_header[] = { IPV6_UDP_HEADER };
616 ASSERT_EQ(sizeof(struct ip6_hdr), sizeof(v6_header)) << "Test IPv6 header: incorrect length\n";
617
618 uint8_t udp_header[] = { UDP_HEADER };
619 ASSERT_EQ(sizeof(struct udphdr), sizeof(udp_header)) << "Test UDP header: incorrect length\n";
620
621 // Sanity checks check_packet.
622 struct udphdr *udp;
623 uint8_t v4_udp_packet[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
624 udp = (struct udphdr *)(v4_udp_packet + sizeof(struct iphdr));
625 fix_udp_checksum(v4_udp_packet);
626 ASSERT_EQ(kUdpV4Checksum, udp->check) << "UDP/IPv4 packet checksum sanity check\n";
627 check_packet(v4_udp_packet, sizeof(v4_udp_packet), "UDP/IPv4 packet sanity check");
628
629 uint8_t v6_udp_packet[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
630 udp = (struct udphdr *)(v6_udp_packet + sizeof(struct ip6_hdr));
631 fix_udp_checksum(v6_udp_packet);
632 ASSERT_EQ(kUdpV6Checksum, udp->check) << "UDP/IPv6 packet checksum sanity check\n";
633 check_packet(v6_udp_packet, sizeof(v6_udp_packet), "UDP/IPv6 packet sanity check");
634
635 uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD };
636 check_packet(ipv4_ping, sizeof(ipv4_ping), "IPv4 ping sanity check");
637
638 uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD };
639 check_packet(ipv6_ping, sizeof(ipv6_ping), "IPv6 ping sanity check");
640
641 // Sanity checks reassemble_packet.
642 uint8_t reassembled[MAXMTU];
643 size_t total_length = sizeof(reassembled);
644 reassemble_packet(kIPv4Fragments, kIPv4FragLengths, ARRAYSIZE(kIPv4Fragments), reassembled,
645 &total_length, "Reassembly sanity check");
646 check_packet(reassembled, total_length, "IPv4 Reassembled packet is valid");
647 ASSERT_EQ(sizeof(kReassembledIPv4), total_length) << "IPv4 reassembly sanity check: length\n";
648 ASSERT_TRUE(!is_ipv4_fragment((struct iphdr *)reassembled))
649 << "Sanity check: reassembled packet is a fragment!\n";
650 check_data_matches(kReassembledIPv4, reassembled, total_length, "IPv4 reassembly sanity check");
651
652 total_length = sizeof(reassembled);
653 reassemble_packet(kIPv6Fragments, kIPv6FragLengths, ARRAYSIZE(kIPv6Fragments), reassembled,
654 &total_length, "IPv6 reassembly sanity check");
655 ASSERT_TRUE(!is_ipv6_fragment((struct ip6_hdr *)reassembled, total_length))
656 << "Sanity check: reassembled packet is a fragment!\n";
657 check_packet(reassembled, total_length, "IPv6 Reassembled packet is valid");
658 }
659
TEST_F(ClatdTest,PseudoChecksum)660 TEST_F(ClatdTest, PseudoChecksum) {
661 uint32_t pseudo_checksum;
662
663 uint8_t v4_header[] = { IPV4_UDP_HEADER };
664 uint8_t v4_pseudo_header[] = { IPV4_PSEUDOHEADER(v4_header, UDP_LEN) };
665 pseudo_checksum = ipv4_pseudo_header_checksum((struct iphdr *)v4_header, UDP_LEN);
666 EXPECT_EQ(ip_checksum_finish(pseudo_checksum),
667 ip_checksum(v4_pseudo_header, sizeof(v4_pseudo_header)))
668 << "ipv4_pseudo_header_checksum incorrect\n";
669
670 uint8_t v6_header[] = { IPV6_UDP_HEADER };
671 uint8_t v6_pseudo_header[] = { IPV6_PSEUDOHEADER(v6_header, IPPROTO_UDP, UDP_LEN) };
672 pseudo_checksum = ipv6_pseudo_header_checksum((struct ip6_hdr *)v6_header, UDP_LEN, IPPROTO_UDP);
673 EXPECT_EQ(ip_checksum_finish(pseudo_checksum),
674 ip_checksum(v6_pseudo_header, sizeof(v6_pseudo_header)))
675 << "ipv6_pseudo_header_checksum incorrect\n";
676 }
677
TEST_F(ClatdTest,TransportChecksum)678 TEST_F(ClatdTest, TransportChecksum) {
679 uint8_t udphdr[] = { UDP_HEADER };
680 uint8_t payload[] = { PAYLOAD };
681 EXPECT_EQ(kUdpPartialChecksum, ip_checksum_add(0, udphdr, sizeof(udphdr)))
682 << "UDP partial checksum\n";
683 EXPECT_EQ(kPayloadPartialChecksum, ip_checksum_add(0, payload, sizeof(payload)))
684 << "Payload partial checksum\n";
685
686 uint8_t ip[] = { IPV4_UDP_HEADER };
687 uint8_t ip6[] = { IPV6_UDP_HEADER };
688 uint32_t ipv4_pseudo_sum = ipv4_pseudo_header_checksum((struct iphdr *)ip, UDP_LEN);
689 uint32_t ipv6_pseudo_sum =
690 ipv6_pseudo_header_checksum((struct ip6_hdr *)ip6, UDP_LEN, IPPROTO_UDP);
691
692 EXPECT_NE(0, ipv4_pseudo_sum);
693 EXPECT_NE(0, ipv6_pseudo_sum);
694 EXPECT_EQ(0x3ad0U, ipv4_pseudo_sum % 0xFFFF) << "IPv4 pseudo-checksum sanity check\n";
695 EXPECT_EQ(0x644dU, ipv6_pseudo_sum % 0xFFFF) << "IPv6 pseudo-checksum sanity check\n";
696 EXPECT_EQ(
697 kUdpV4Checksum,
698 ip_checksum_finish(ipv4_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum))
699 << "Unexpected UDP/IPv4 checksum\n";
700 EXPECT_EQ(
701 kUdpV6Checksum,
702 ip_checksum_finish(ipv6_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum))
703 << "Unexpected UDP/IPv6 checksum\n";
704
705 EXPECT_EQ(kUdpV6Checksum,
706 ip_checksum_adjust(kUdpV4Checksum, ipv4_pseudo_sum, ipv6_pseudo_sum))
707 << "Adjust IPv4/UDP checksum to IPv6\n";
708 EXPECT_EQ(kUdpV4Checksum,
709 ip_checksum_adjust(kUdpV6Checksum, ipv6_pseudo_sum, ipv4_pseudo_sum))
710 << "Adjust IPv6/UDP checksum to IPv4\n";
711 }
712
TEST_F(ClatdTest,AdjustChecksum)713 TEST_F(ClatdTest, AdjustChecksum) {
714 struct checksum_data {
715 uint16_t checksum;
716 uint32_t old_hdr_sum;
717 uint32_t new_hdr_sum;
718 uint16_t result;
719 } DATA[] = {
720 { 0x1423, 0xb8ec, 0x2d757, 0xf5b5 },
721 { 0xf5b5, 0x2d757, 0xb8ec, 0x1423 },
722 { 0xdd2f, 0x5555, 0x3285, 0x0000 },
723 { 0x1215, 0x5560, 0x15560 + 20, 0x1200 },
724 { 0xd0c7, 0x3ad0, 0x2644b, 0xa74a },
725 };
726 unsigned i = 0;
727
728 for (i = 0; i < ARRAYSIZE(DATA); i++) {
729 struct checksum_data *data = DATA + i;
730 uint16_t result = ip_checksum_adjust(data->checksum, data->old_hdr_sum, data->new_hdr_sum);
731 EXPECT_EQ(result, data->result)
732 << "Incorrect checksum" << std::showbase << std::hex
733 << "\n Expected: " << data->result
734 << "\n Actual: " << result
735 << "\n checksum=" << data->checksum
736 << " old_sum=" << data->old_hdr_sum << " new_sum=" << data->new_hdr_sum << "\n";
737 }
738 }
739
TEST_F(ClatdTest,Translate)740 TEST_F(ClatdTest, Translate) {
741 // This test uses hardcoded packets so the clatd address must be fixed.
742 inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet);
743
744 uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
745 uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
746 fix_udp_checksum(udp_ipv4);
747 fix_udp_checksum(udp_ipv6);
748 check_translated_packet(udp_ipv4, sizeof(udp_ipv4), udp_ipv6, sizeof(udp_ipv6),
749 "UDP/IPv4 -> UDP/IPv6 translation");
750 check_translated_packet(udp_ipv6, sizeof(udp_ipv6), udp_ipv4, sizeof(udp_ipv4),
751 "UDP/IPv6 -> UDP/IPv4 translation");
752
753 uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD };
754 uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD };
755 check_translated_packet(ipv4_ping, sizeof(ipv4_ping), ipv6_ping, sizeof(ipv6_ping),
756 "ICMP->ICMPv6 translation");
757 check_translated_packet(ipv6_ping, sizeof(ipv6_ping), ipv4_ping, sizeof(ipv4_ping),
758 "ICMPv6->ICMP translation");
759 }
760
TEST_F(ClatdTest,Fragmentation)761 TEST_F(ClatdTest, Fragmentation) {
762 // This test uses hardcoded packets so the clatd address must be fixed.
763 inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet);
764
765 check_fragment_translation(kIPv4Fragments, kIPv4FragLengths, kIPv6Fragments, kIPv6FragLengths,
766 ARRAYSIZE(kIPv4Fragments), "IPv4->IPv6 fragment translation");
767
768 check_fragment_translation(kIPv6Fragments, kIPv6FragLengths, kIPv4Fragments, kIPv4FragLengths,
769 ARRAYSIZE(kIPv6Fragments), "IPv6->IPv4 fragment translation");
770 }
771
772 // picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix
gen_random_iid(struct in6_addr * myaddr,struct in_addr * ipv4_local_subnet,struct in6_addr * plat_subnet)773 void gen_random_iid(struct in6_addr *myaddr, struct in_addr *ipv4_local_subnet,
774 struct in6_addr *plat_subnet) {
775 // Fill last 8 bytes of IPv6 address with random bits.
776 arc4random_buf(&myaddr->s6_addr[8], 8);
777
778 // Make the IID checksum-neutral. That is, make it so that:
779 // checksum(Local IPv4 | Remote IPv4) = checksum(Local IPv6 | Remote IPv6)
780 // in other words (because remote IPv6 = NAT64 prefix | Remote IPv4):
781 // checksum(Local IPv4) = checksum(Local IPv6 | NAT64 prefix)
782 // Do this by adjusting the two bytes in the middle of the IID.
783
784 uint16_t middlebytes = (myaddr->s6_addr[11] << 8) + myaddr->s6_addr[12];
785
786 uint32_t c1 = ip_checksum_add(0, ipv4_local_subnet, sizeof(*ipv4_local_subnet));
787 uint32_t c2 = ip_checksum_add(0, plat_subnet, sizeof(*plat_subnet)) +
788 ip_checksum_add(0, myaddr, sizeof(*myaddr));
789
790 uint16_t delta = ip_checksum_adjust(middlebytes, c1, c2);
791 myaddr->s6_addr[11] = delta >> 8;
792 myaddr->s6_addr[12] = delta & 0xff;
793 }
794
check_translate_checksum_neutral(const uint8_t * original,size_t original_len,size_t expected_len,const char * msg)795 void check_translate_checksum_neutral(const uint8_t *original, size_t original_len,
796 size_t expected_len, const char *msg) {
797 uint8_t translated[MAXMTU];
798 size_t translated_len = sizeof(translated);
799 do_translate_packet(original, original_len, translated, &translated_len, msg);
800 EXPECT_EQ(expected_len, translated_len) << msg << ": Translated packet length incorrect\n";
801 // do_translate_packet already checks packets for validity and verifies the checksum.
802 int original_check = get_transport_checksum(original);
803 int translated_check = get_transport_checksum(translated);
804 ASSERT_NE(-1, original_check);
805 ASSERT_NE(-1, translated_check);
806 ASSERT_EQ(original_check, translated_check)
807 << "Not checksum neutral: original and translated checksums differ\n";
808 }
809
TEST_F(ClatdTest,TranslateChecksumNeutral)810 TEST_F(ClatdTest, TranslateChecksumNeutral) {
811 // Generate a random clat IPv6 address and check that translation is checksum-neutral.
812 ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54",
813 &Global_Clatd_Config.ipv6_local_subnet));
814
815 gen_random_iid(&Global_Clatd_Config.ipv6_local_subnet, &Global_Clatd_Config.ipv4_local_subnet,
816 &Global_Clatd_Config.plat_subnet);
817
818 ASSERT_NE(htonl((uint32_t)0x00000464), Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]);
819 ASSERT_NE((uint32_t)0, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]);
820
821 // Check that translating UDP packets is checksum-neutral. First, IPv4.
822 uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
823 fix_udp_checksum(udp_ipv4);
824 check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20,
825 "UDP/IPv4 -> UDP/IPv6 checksum neutral");
826
827 // Now try IPv6.
828 uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
829 // The test packet uses the static IID, not the random IID. Fix up the source address.
830 struct ip6_hdr *ip6 = (struct ip6_hdr *)udp_ipv6;
831 memcpy(&ip6->ip6_src, &Global_Clatd_Config.ipv6_local_subnet, sizeof(ip6->ip6_src));
832 fix_udp_checksum(udp_ipv6);
833 check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20,
834 "UDP/IPv4 -> UDP/IPv6 checksum neutral");
835 }
836