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