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 struct clat_config Global_Clatd_Config;
563
564 class ClatdTest : public ::testing::Test {
565 protected:
566 static TunInterface sTun;
567
SetUp()568 virtual void SetUp() {
569 inet_pton(AF_INET, kIPv4LocalAddr, &Global_Clatd_Config.ipv4_local_subnet);
570 inet_pton(AF_INET6, kIPv6PlatSubnet, &Global_Clatd_Config.plat_subnet);
571 memset(&Global_Clatd_Config.ipv6_local_subnet, 0, sizeof(in6_addr));
572 Global_Clatd_Config.native_ipv6_interface = const_cast<char *>(sTun.name().c_str());
573 }
574
575 // Static because setting up the tun interface takes about 40ms.
SetUpTestCase()576 static void SetUpTestCase() { ASSERT_EQ(0, sTun.init()); }
577
578 // Closing the socket removes the interface and IP addresses.
TearDownTestCase()579 static void TearDownTestCase() { sTun.destroy(); }
580 };
581
582 TunInterface ClatdTest::sTun;
583
expect_ipv6_addr_equal(struct in6_addr * expected,struct in6_addr * actual)584 void expect_ipv6_addr_equal(struct in6_addr *expected, struct in6_addr *actual) {
585 if (!IN6_ARE_ADDR_EQUAL(expected, actual)) {
586 char expected_str[INET6_ADDRSTRLEN], actual_str[INET6_ADDRSTRLEN];
587 inet_ntop(AF_INET6, expected, expected_str, sizeof(expected_str));
588 inet_ntop(AF_INET6, actual, actual_str, sizeof(actual_str));
589 FAIL()
590 << "Unexpected IPv6 address:: "
591 << "\n Expected: " << expected_str
592 << "\n Actual: " << actual_str
593 << "\n";
594 }
595 }
596
TEST_F(ClatdTest,TestIPv6PrefixEqual)597 TEST_F(ClatdTest, TestIPv6PrefixEqual) {
598 EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.plat_subnet,
599 &Global_Clatd_Config.plat_subnet));
600 EXPECT_FALSE(ipv6_prefix_equal(&Global_Clatd_Config.plat_subnet,
601 &Global_Clatd_Config.ipv6_local_subnet));
602
603 struct in6_addr subnet2 = Global_Clatd_Config.ipv6_local_subnet;
604 EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &subnet2));
605 EXPECT_TRUE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet));
606
607 subnet2.s6_addr[6] = 0xff;
608 EXPECT_FALSE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &subnet2));
609 EXPECT_FALSE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet));
610 }
611
TEST_F(ClatdTest,DataSanitycheck)612 TEST_F(ClatdTest, DataSanitycheck) {
613 // Sanity checks the data.
614 uint8_t v4_header[] = { IPV4_UDP_HEADER };
615 ASSERT_EQ(sizeof(struct iphdr), sizeof(v4_header)) << "Test IPv4 header: incorrect length\n";
616
617 uint8_t v6_header[] = { IPV6_UDP_HEADER };
618 ASSERT_EQ(sizeof(struct ip6_hdr), sizeof(v6_header)) << "Test IPv6 header: incorrect length\n";
619
620 uint8_t udp_header[] = { UDP_HEADER };
621 ASSERT_EQ(sizeof(struct udphdr), sizeof(udp_header)) << "Test UDP header: incorrect length\n";
622
623 // Sanity checks check_packet.
624 struct udphdr *udp;
625 uint8_t v4_udp_packet[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
626 udp = (struct udphdr *)(v4_udp_packet + sizeof(struct iphdr));
627 fix_udp_checksum(v4_udp_packet);
628 ASSERT_EQ(kUdpV4Checksum, udp->check) << "UDP/IPv4 packet checksum sanity check\n";
629 check_packet(v4_udp_packet, sizeof(v4_udp_packet), "UDP/IPv4 packet sanity check");
630
631 uint8_t v6_udp_packet[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
632 udp = (struct udphdr *)(v6_udp_packet + sizeof(struct ip6_hdr));
633 fix_udp_checksum(v6_udp_packet);
634 ASSERT_EQ(kUdpV6Checksum, udp->check) << "UDP/IPv6 packet checksum sanity check\n";
635 check_packet(v6_udp_packet, sizeof(v6_udp_packet), "UDP/IPv6 packet sanity check");
636
637 uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD };
638 check_packet(ipv4_ping, sizeof(ipv4_ping), "IPv4 ping sanity check");
639
640 uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD };
641 check_packet(ipv6_ping, sizeof(ipv6_ping), "IPv6 ping sanity check");
642
643 // Sanity checks reassemble_packet.
644 uint8_t reassembled[MAXMTU];
645 size_t total_length = sizeof(reassembled);
646 reassemble_packet(kIPv4Fragments, kIPv4FragLengths, ARRAYSIZE(kIPv4Fragments), reassembled,
647 &total_length, "Reassembly sanity check");
648 check_packet(reassembled, total_length, "IPv4 Reassembled packet is valid");
649 ASSERT_EQ(sizeof(kReassembledIPv4), total_length) << "IPv4 reassembly sanity check: length\n";
650 ASSERT_TRUE(!is_ipv4_fragment((struct iphdr *)reassembled))
651 << "Sanity check: reassembled packet is a fragment!\n";
652 check_data_matches(kReassembledIPv4, reassembled, total_length, "IPv4 reassembly sanity check");
653
654 total_length = sizeof(reassembled);
655 reassemble_packet(kIPv6Fragments, kIPv6FragLengths, ARRAYSIZE(kIPv6Fragments), reassembled,
656 &total_length, "IPv6 reassembly sanity check");
657 ASSERT_TRUE(!is_ipv6_fragment((struct ip6_hdr *)reassembled, total_length))
658 << "Sanity check: reassembled packet is a fragment!\n";
659 check_packet(reassembled, total_length, "IPv6 Reassembled packet is valid");
660 }
661
TEST_F(ClatdTest,PseudoChecksum)662 TEST_F(ClatdTest, PseudoChecksum) {
663 uint32_t pseudo_checksum;
664
665 uint8_t v4_header[] = { IPV4_UDP_HEADER };
666 uint8_t v4_pseudo_header[] = { IPV4_PSEUDOHEADER(v4_header, UDP_LEN) };
667 pseudo_checksum = ipv4_pseudo_header_checksum((struct iphdr *)v4_header, UDP_LEN);
668 EXPECT_EQ(ip_checksum_finish(pseudo_checksum),
669 ip_checksum(v4_pseudo_header, sizeof(v4_pseudo_header)))
670 << "ipv4_pseudo_header_checksum incorrect\n";
671
672 uint8_t v6_header[] = { IPV6_UDP_HEADER };
673 uint8_t v6_pseudo_header[] = { IPV6_PSEUDOHEADER(v6_header, IPPROTO_UDP, UDP_LEN) };
674 pseudo_checksum = ipv6_pseudo_header_checksum((struct ip6_hdr *)v6_header, UDP_LEN, IPPROTO_UDP);
675 EXPECT_EQ(ip_checksum_finish(pseudo_checksum),
676 ip_checksum(v6_pseudo_header, sizeof(v6_pseudo_header)))
677 << "ipv6_pseudo_header_checksum incorrect\n";
678 }
679
TEST_F(ClatdTest,TransportChecksum)680 TEST_F(ClatdTest, TransportChecksum) {
681 uint8_t udphdr[] = { UDP_HEADER };
682 uint8_t payload[] = { PAYLOAD };
683 EXPECT_EQ(kUdpPartialChecksum, ip_checksum_add(0, udphdr, sizeof(udphdr)))
684 << "UDP partial checksum\n";
685 EXPECT_EQ(kPayloadPartialChecksum, ip_checksum_add(0, payload, sizeof(payload)))
686 << "Payload partial checksum\n";
687
688 uint8_t ip[] = { IPV4_UDP_HEADER };
689 uint8_t ip6[] = { IPV6_UDP_HEADER };
690 uint32_t ipv4_pseudo_sum = ipv4_pseudo_header_checksum((struct iphdr *)ip, UDP_LEN);
691 uint32_t ipv6_pseudo_sum =
692 ipv6_pseudo_header_checksum((struct ip6_hdr *)ip6, UDP_LEN, IPPROTO_UDP);
693
694 EXPECT_NE(0, ipv4_pseudo_sum);
695 EXPECT_NE(0, ipv6_pseudo_sum);
696 EXPECT_EQ(0x3ad0U, ipv4_pseudo_sum % 0xFFFF) << "IPv4 pseudo-checksum sanity check\n";
697 EXPECT_EQ(0x644dU, ipv6_pseudo_sum % 0xFFFF) << "IPv6 pseudo-checksum sanity check\n";
698 EXPECT_EQ(
699 kUdpV4Checksum,
700 ip_checksum_finish(ipv4_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum))
701 << "Unexpected UDP/IPv4 checksum\n";
702 EXPECT_EQ(
703 kUdpV6Checksum,
704 ip_checksum_finish(ipv6_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum))
705 << "Unexpected UDP/IPv6 checksum\n";
706
707 EXPECT_EQ(kUdpV6Checksum,
708 ip_checksum_adjust(kUdpV4Checksum, ipv4_pseudo_sum, ipv6_pseudo_sum))
709 << "Adjust IPv4/UDP checksum to IPv6\n";
710 EXPECT_EQ(kUdpV4Checksum,
711 ip_checksum_adjust(kUdpV6Checksum, ipv6_pseudo_sum, ipv4_pseudo_sum))
712 << "Adjust IPv6/UDP checksum to IPv4\n";
713 }
714
TEST_F(ClatdTest,AdjustChecksum)715 TEST_F(ClatdTest, AdjustChecksum) {
716 struct checksum_data {
717 uint16_t checksum;
718 uint32_t old_hdr_sum;
719 uint32_t new_hdr_sum;
720 uint16_t result;
721 } DATA[] = {
722 { 0x1423, 0xb8ec, 0x2d757, 0xf5b5 },
723 { 0xf5b5, 0x2d757, 0xb8ec, 0x1423 },
724 { 0xdd2f, 0x5555, 0x3285, 0x0000 },
725 { 0x1215, 0x5560, 0x15560 + 20, 0x1200 },
726 { 0xd0c7, 0x3ad0, 0x2644b, 0xa74a },
727 };
728 unsigned i = 0;
729
730 for (i = 0; i < ARRAYSIZE(DATA); i++) {
731 struct checksum_data *data = DATA + i;
732 uint16_t result = ip_checksum_adjust(data->checksum, data->old_hdr_sum, data->new_hdr_sum);
733 EXPECT_EQ(result, data->result)
734 << "Incorrect checksum" << std::showbase << std::hex
735 << "\n Expected: " << data->result
736 << "\n Actual: " << result
737 << "\n checksum=" << data->checksum
738 << " old_sum=" << data->old_hdr_sum << " new_sum=" << data->new_hdr_sum << "\n";
739 }
740 }
741
TEST_F(ClatdTest,Translate)742 TEST_F(ClatdTest, Translate) {
743 // This test uses hardcoded packets so the clatd address must be fixed.
744 inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet);
745
746 uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
747 uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
748 fix_udp_checksum(udp_ipv4);
749 fix_udp_checksum(udp_ipv6);
750 check_translated_packet(udp_ipv4, sizeof(udp_ipv4), udp_ipv6, sizeof(udp_ipv6),
751 "UDP/IPv4 -> UDP/IPv6 translation");
752 check_translated_packet(udp_ipv6, sizeof(udp_ipv6), udp_ipv4, sizeof(udp_ipv4),
753 "UDP/IPv6 -> UDP/IPv4 translation");
754
755 uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD };
756 uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD };
757 check_translated_packet(ipv4_ping, sizeof(ipv4_ping), ipv6_ping, sizeof(ipv6_ping),
758 "ICMP->ICMPv6 translation");
759 check_translated_packet(ipv6_ping, sizeof(ipv6_ping), ipv4_ping, sizeof(ipv4_ping),
760 "ICMPv6->ICMP translation");
761 }
762
TEST_F(ClatdTest,Fragmentation)763 TEST_F(ClatdTest, Fragmentation) {
764 // This test uses hardcoded packets so the clatd address must be fixed.
765 inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet);
766
767 check_fragment_translation(kIPv4Fragments, kIPv4FragLengths, kIPv6Fragments, kIPv6FragLengths,
768 ARRAYSIZE(kIPv4Fragments), "IPv4->IPv6 fragment translation");
769
770 check_fragment_translation(kIPv6Fragments, kIPv6FragLengths, kIPv4Fragments, kIPv4FragLengths,
771 ARRAYSIZE(kIPv6Fragments), "IPv6->IPv4 fragment translation");
772 }
773
774 // 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)775 void gen_random_iid(struct in6_addr *myaddr, struct in_addr *ipv4_local_subnet,
776 struct in6_addr *plat_subnet) {
777 // Fill last 8 bytes of IPv6 address with random bits.
778 arc4random_buf(&myaddr->s6_addr[8], 8);
779
780 // Make the IID checksum-neutral. That is, make it so that:
781 // checksum(Local IPv4 | Remote IPv4) = checksum(Local IPv6 | Remote IPv6)
782 // in other words (because remote IPv6 = NAT64 prefix | Remote IPv4):
783 // checksum(Local IPv4) = checksum(Local IPv6 | NAT64 prefix)
784 // Do this by adjusting the two bytes in the middle of the IID.
785
786 uint16_t middlebytes = (myaddr->s6_addr[11] << 8) + myaddr->s6_addr[12];
787
788 uint32_t c1 = ip_checksum_add(0, ipv4_local_subnet, sizeof(*ipv4_local_subnet));
789 uint32_t c2 = ip_checksum_add(0, plat_subnet, sizeof(*plat_subnet)) +
790 ip_checksum_add(0, myaddr, sizeof(*myaddr));
791
792 uint16_t delta = ip_checksum_adjust(middlebytes, c1, c2);
793 myaddr->s6_addr[11] = delta >> 8;
794 myaddr->s6_addr[12] = delta & 0xff;
795 }
796
check_translate_checksum_neutral(const uint8_t * original,size_t original_len,size_t expected_len,const char * msg)797 void check_translate_checksum_neutral(const uint8_t *original, size_t original_len,
798 size_t expected_len, const char *msg) {
799 uint8_t translated[MAXMTU];
800 size_t translated_len = sizeof(translated);
801 do_translate_packet(original, original_len, translated, &translated_len, msg);
802 EXPECT_EQ(expected_len, translated_len) << msg << ": Translated packet length incorrect\n";
803 // do_translate_packet already checks packets for validity and verifies the checksum.
804 int original_check = get_transport_checksum(original);
805 int translated_check = get_transport_checksum(translated);
806 ASSERT_NE(-1, original_check);
807 ASSERT_NE(-1, translated_check);
808 ASSERT_EQ(original_check, translated_check)
809 << "Not checksum neutral: original and translated checksums differ\n";
810 }
811
TEST_F(ClatdTest,TranslateChecksumNeutral)812 TEST_F(ClatdTest, TranslateChecksumNeutral) {
813 // Generate a random clat IPv6 address and check that translation is checksum-neutral.
814 ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54",
815 &Global_Clatd_Config.ipv6_local_subnet));
816
817 gen_random_iid(&Global_Clatd_Config.ipv6_local_subnet, &Global_Clatd_Config.ipv4_local_subnet,
818 &Global_Clatd_Config.plat_subnet);
819
820 ASSERT_NE(htonl((uint32_t)0x00000464), Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]);
821 ASSERT_NE((uint32_t)0, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]);
822
823 // Check that translating UDP packets is checksum-neutral. First, IPv4.
824 uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
825 fix_udp_checksum(udp_ipv4);
826 check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20,
827 "UDP/IPv4 -> UDP/IPv6 checksum neutral");
828
829 // Now try IPv6.
830 uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
831 // The test packet uses the static IID, not the random IID. Fix up the source address.
832 struct ip6_hdr *ip6 = (struct ip6_hdr *)udp_ipv6;
833 memcpy(&ip6->ip6_src, &Global_Clatd_Config.ipv6_local_subnet, sizeof(ip6->ip6_src));
834 fix_udp_checksum(udp_ipv6);
835 check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20,
836 "UDP/IPv4 -> UDP/IPv6 checksum neutral");
837 }
838