blob: 171aecb3b7d30f2bc42926d886d4ea2bb8354e77 [file] [log] [blame]
Lorenzo Colittif3beefc2014-02-14 13:19:27 +09001/*
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>
Lorenzo Colitti98089522014-10-09 22:29:45 +090023#include <netinet/in6.h>
Lorenzo Colittif3beefc2014-02-14 13:19:27 +090024#include <sys/uio.h>
25
26#include <gtest/gtest.h>
27
28extern "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.
39static const char kIPv4LocalAddr[] = "192.0.0.4";
40static const char kIPv6LocalAddr[] = "2001:db8:0:b11::464";
41static 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.
Brian Carlstromfcac4102014-02-24 20:03:01 -0800105static const uint8_t kIPv4Frag1[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900106 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};
Brian Carlstromfcac4102014-02-24 20:03:01 -0800111static const uint8_t kIPv4Frag2[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900112 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};
Brian Carlstromfcac4102014-02-24 20:03:01 -0800117static const uint8_t kIPv4Frag3[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900118 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};
Brian Carlstromfcac4102014-02-24 20:03:01 -0800122static const uint8_t *kIPv4Fragments[] = { kIPv4Frag1, kIPv4Frag2, kIPv4Frag3 };
123static const size_t kIPv4FragLengths[] = { sizeof(kIPv4Frag1), sizeof(kIPv4Frag2),
124 sizeof(kIPv4Frag3) };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900125
Brian Carlstromfcac4102014-02-24 20:03:01 -0800126static const uint8_t kIPv6Frag1[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900127 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
Brian Carlstromfcac4102014-02-24 20:03:01 -0800136static const uint8_t kIPv6Frag2[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900137 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
Brian Carlstromfcac4102014-02-24 20:03:01 -0800146static const uint8_t kIPv6Frag3[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900147 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};
Brian Carlstromfcac4102014-02-24 20:03:01 -0800154static const uint8_t *kIPv6Fragments[] = { kIPv6Frag1, kIPv6Frag2, kIPv6Frag3 };
155static const size_t kIPv6FragLengths[] = { sizeof(kIPv6Frag1), sizeof(kIPv6Frag2),
156 sizeof(kIPv6Frag3) };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900157
Brian Carlstromfcac4102014-02-24 20:03:01 -0800158static const uint8_t kReassembledIPv4[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900159 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.
169static const uint32_t kUdpPartialChecksum = 0xd5c8;
170static const uint32_t kPayloadPartialChecksum = 0x31e9c;
171static const uint16_t kUdpV4Checksum = 0xd0c7;
172static const uint16_t kUdpV6Checksum = 0xa74a;
173
Brian Carlstromfcac4102014-02-24 20:03:01 -0800174uint8_t ip_version(const uint8_t *packet) {
175 uint8_t version = packet[0] >> 4;
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900176 return version;
177}
178
179int 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
184int 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
193int ipv4_fragment_offset(struct iphdr *ip) {
194 return ntohs(ip->frag_off) & IP_OFFMASK;
195}
196
197int ipv6_fragment_offset(struct ip6_frag *frag) {
198 return ntohs((frag->ip6f_offlg & IP6F_OFF_MASK) >> 3);
199}
200
Brian Carlstromfcac4102014-02-24 20:03:01 -0800201void check_packet(const uint8_t *packet, size_t len, const char *msg) {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900202 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
Brian Carlstromfcac4102014-02-24 20:03:01 -0800286void reassemble_packet(const uint8_t **fragments, const size_t lengths[], int numpackets,
287 uint8_t *reassembled, size_t *reassembled_len, const char *msg) {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900288 struct iphdr *ip = NULL;
289 struct ip6_hdr *ip6 = NULL;
Ben Cheng932614e2014-04-02 17:00:26 -0700290 size_t total_length, pos = 0;
291 uint8_t protocol = 0;
Brian Carlstromfcac4102014-02-24 20:03:01 -0800292 uint8_t version = ip_version(fragments[0]);
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900293
294 for (int i = 0; i < numpackets; i++) {
Brian Carlstromfcac4102014-02-24 20:03:01 -0800295 const uint8_t *packet = fragments[i];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900296 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;
Ben Cheng932614e2014-04-02 17:00:26 -0700349 ASSERT_LT(total_length, *reassembled_len) << msg << ": Reassembly buffer too small\n";
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900350 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
Lorenzo Colitti98089522014-10-09 22:29:45 +0900374void check_data_matches(const void *expected, const void *actual, size_t len, const char *msg) {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900375 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 }
Lorenzo Colitti98089522014-10-09 22:29:45 +0900386 sprintf(expected_hexdump + pos, " %02x", ((uint8_t *) expected)[i]);
387 sprintf(actual_hexdump + pos, " %02x", ((uint8_t *) actual)[i]);
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900388 pos += 3;
389 }
Lorenzo Colitti98089522014-10-09 22:29:45 +0900390 FAIL() << msg << ": Data doesn't match"
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900391 << "\n Expected:" << (char *) expected_hexdump
392 << "\n Actual:" << (char *) actual_hexdump << "\n";
393 }
394}
395
Brian Carlstromfcac4102014-02-24 20:03:01 -0800396void fix_udp_checksum(uint8_t* packet) {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900397 uint32_t pseudo_checksum;
Brian Carlstromfcac4102014-02-24 20:03:01 -0800398 uint8_t version = ip_version(packet);
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900399 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
Lorenzo Colitti10e88272014-06-02 21:20:40 +0900422// 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.
425extern "C" void send_rawv6(int fd, clat_packet out, int iov_len) {
426 writev(fd, out, iov_len);
427}
428
Brian Carlstromfcac4102014-02-24 20:03:01 -0800429void do_translate_packet(const uint8_t *original, size_t original_len, uint8_t *out, size_t *outlen,
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900430 const char *msg) {
431 int fds[2];
432 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, fds)) {
433 abort();
434 }
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900435 struct tun_pi tun_header = { 0, 0 };
436
437 char foo[512];
438 snprintf(foo, sizeof(foo), "%s: Invalid original packet", msg);
439 check_packet(original, original_len, foo);
440
Lorenzo Colitti91d0f1b2014-06-02 15:49:36 +0900441 int read_fd, write_fd;
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900442 uint16_t expected_proto;
443 int version = ip_version(original);
444 switch (version) {
445 case 4:
446 tun_header.proto = htons(ETH_P_IP);
447 expected_proto = htons(ETH_P_IPV6);
448 read_fd = fds[1];
Lorenzo Colitti91d0f1b2014-06-02 15:49:36 +0900449 write_fd = fds[0];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900450 break;
451 case 6:
452 tun_header.proto = htons(ETH_P_IPV6);
453 expected_proto = htons(ETH_P_IP);
454 read_fd = fds[0];
Lorenzo Colitti91d0f1b2014-06-02 15:49:36 +0900455 write_fd = fds[1];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900456 break;
457 default:
458 FAIL() << msg << ": Unsupported IP version " << version << "\n";
459 break;
460 }
461
Lorenzo Colitti91d0f1b2014-06-02 15:49:36 +0900462 translate_packet(write_fd, (version == 4), original, original_len);
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900463
Lorenzo Colitti98089522014-10-09 22:29:45 +0900464 snprintf(foo, sizeof(foo), "%s: Invalid translated packet", msg);
Lorenzo Colitti10e88272014-06-02 21:20:40 +0900465 if (version == 6) {
466 // Translating to IPv4. Expect a tun header.
467 struct tun_pi new_tun_header;
468 struct iovec iov[] = {
469 { &new_tun_header, sizeof(new_tun_header) },
470 { out, *outlen }
471 };
472 int len = readv(read_fd, iov, 2);
473 if (len > (int) sizeof(new_tun_header)) {
474 ASSERT_LT((size_t) len, *outlen) << msg << ": Translated packet buffer too small\n";
475 EXPECT_EQ(expected_proto, new_tun_header.proto) << msg << "Unexpected tun proto\n";
476 *outlen = len - sizeof(new_tun_header);
Lorenzo Colitti98089522014-10-09 22:29:45 +0900477 check_packet(out, *outlen, msg);
Lorenzo Colitti10e88272014-06-02 21:20:40 +0900478 } else {
Lorenzo Colitti98089522014-10-09 22:29:45 +0900479 FAIL() << msg << ": Packet was not translated: len=" << len;
Lorenzo Colitti10e88272014-06-02 21:20:40 +0900480 *outlen = 0;
481 }
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900482 } else {
Lorenzo Colitti10e88272014-06-02 21:20:40 +0900483 // Translating to IPv6. Expect raw packet.
484 *outlen = read(read_fd, out, *outlen);
Lorenzo Colitti98089522014-10-09 22:29:45 +0900485 check_packet(out, *outlen, msg);
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900486 }
487}
488
Brian Carlstromfcac4102014-02-24 20:03:01 -0800489void check_translated_packet(const uint8_t *original, size_t original_len,
490 const uint8_t *expected, size_t expected_len, const char *msg) {
491 uint8_t translated[MAXMTU];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900492 size_t translated_len = sizeof(translated);
493 do_translate_packet(original, original_len, translated, &translated_len, msg);
494 EXPECT_EQ(expected_len, translated_len) << msg << ": Translated packet length incorrect\n";
495 check_data_matches(expected, translated, translated_len, msg);
496}
497
Brian Carlstromfcac4102014-02-24 20:03:01 -0800498void check_fragment_translation(const uint8_t *original[], const size_t original_lengths[],
499 const uint8_t *expected[], const size_t expected_lengths[],
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900500 int numfragments, const char *msg) {
501 for (int i = 0; i < numfragments; i++) {
502 // Check that each of the fragments translates as expected.
503 char frag_msg[512];
504 snprintf(frag_msg, sizeof(frag_msg), "%s: fragment #%d", msg, i + 1);
505 check_translated_packet(original[i], original_lengths[i],
506 expected[i], expected_lengths[i], frag_msg);
507 }
508
509 // Sanity check that reassembling the original and translated fragments produces valid packets.
Brian Carlstromfcac4102014-02-24 20:03:01 -0800510 uint8_t reassembled[MAXMTU];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900511 size_t reassembled_len = sizeof(reassembled);
512 reassemble_packet(original, original_lengths, numfragments, reassembled, &reassembled_len, msg);
513 check_packet(reassembled, reassembled_len, msg);
514
Brian Carlstromfcac4102014-02-24 20:03:01 -0800515 uint8_t translated[MAXMTU];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900516 size_t translated_len = sizeof(translated);
517 do_translate_packet(reassembled, reassembled_len, translated, &translated_len, msg);
518 check_packet(translated, translated_len, msg);
519}
520
Lorenzo Colitti98089522014-10-09 22:29:45 +0900521int get_transport_checksum(const uint8_t *packet) {
522 struct iphdr *ip;
523 struct ip6_hdr *ip6;
524 uint8_t protocol;
525 const void *payload;
526
527 int version = ip_version(packet);
528 switch (version) {
529 case 4:
530 ip = (struct iphdr *) packet;
531 if (is_ipv4_fragment(ip)) {
532 return -1;
533 }
534 protocol = ip->protocol;
535 payload = ip + 1;
536 break;
537 case 6:
538 ip6 = (struct ip6_hdr *) packet;
539 protocol = ip6->ip6_nxt;
540 payload = ip6 + 1;
541 break;
542 default:
543 return -1;
544 }
545
546 switch (protocol) {
547 case IPPROTO_UDP:
548 return ((struct udphdr *) payload)->check;
549
550 case IPPROTO_TCP:
551 return ((struct tcphdr *) payload)->check;
552
553 case IPPROTO_FRAGMENT:
554 default:
555 return -1;
556 }
557}
558
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900559struct clat_config Global_Clatd_Config;
560
561class ClatdTest : public ::testing::Test {
562 protected:
563 virtual void SetUp() {
564 inet_pton(AF_INET, kIPv4LocalAddr, &Global_Clatd_Config.ipv4_local_subnet);
565 inet_pton(AF_INET6, kIPv6PlatSubnet, &Global_Clatd_Config.plat_subnet);
566 inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet);
Lorenzo Colitti98089522014-10-09 22:29:45 +0900567 Global_Clatd_Config.ipv6_host_id = in6addr_any;
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900568 }
569};
570
Lorenzo Colitti98089522014-10-09 22:29:45 +0900571void expect_ipv6_addr_equal(struct in6_addr *expected, struct in6_addr *actual) {
572 if (!IN6_ARE_ADDR_EQUAL(expected, actual)) {
573 char expected_str[INET6_ADDRSTRLEN], actual_str[INET6_ADDRSTRLEN];
574 inet_ntop(AF_INET6, expected, expected_str, sizeof(expected_str));
575 inet_ntop(AF_INET6, actual, actual_str, sizeof(actual_str));
576 FAIL()
577 << "Unexpected IPv6 address:: "
578 << "\n Expected: " << expected_str
579 << "\n Actual: " << actual_str
580 << "\n";
581 }
582}
583
584TEST_F(ClatdTest, TestIPv6PrefixEqual) {
585 EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.plat_subnet,
586 &Global_Clatd_Config.plat_subnet));
587 EXPECT_FALSE(ipv6_prefix_equal(&Global_Clatd_Config.plat_subnet,
588 &Global_Clatd_Config.ipv6_local_subnet));
589
590 struct in6_addr subnet2 = Global_Clatd_Config.ipv6_local_subnet;
591 EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &subnet2));
592 EXPECT_TRUE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet));
593
594 subnet2.s6_addr[6] = 0xff;
595 EXPECT_FALSE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &subnet2));
596 EXPECT_FALSE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet));
597}
598
599int count_onebits(const void *data, size_t size) {
600 int onebits = 0;
601 for (size_t pos = 0; pos < size; pos++) {
602 uint8_t *byte = ((uint8_t*) data) + pos;
603 for (int shift = 0; shift < 8; shift++) {
604 onebits += (*byte >> shift) & 1;
605 }
606 }
607 return onebits;
608}
609
610TEST_F(ClatdTest, TestCountOnebits) {
611 uint64_t i;
612 i = 1;
613 ASSERT_EQ(1, count_onebits(&i, sizeof(i)));
614 i <<= 61;
615 ASSERT_EQ(1, count_onebits(&i, sizeof(i)));
616 i |= ((uint64_t) 1 << 33);
617 ASSERT_EQ(2, count_onebits(&i, sizeof(i)));
618 i = 0xf1000202020000f0;
619 ASSERT_EQ(5 + 1 + 1 + 1 + 4, count_onebits(&i, sizeof(i)));
620}
621
622TEST_F(ClatdTest, TestGenIIDConfigured) {
623 struct in6_addr myaddr, expected;
624 ASSERT_TRUE(inet_pton(AF_INET6, "::bad:ace:d00d", &Global_Clatd_Config.ipv6_host_id));
625 ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:0:bad:ace:d00d", &expected));
626 ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54", &myaddr));
627 config_generate_local_ipv6_subnet(&myaddr);
628 expect_ipv6_addr_equal(&expected, &myaddr);
629}
630
631TEST_F(ClatdTest, TestGenIIDRandom) {
632 struct in6_addr interface_ipv6;
633 ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54", &interface_ipv6));
634 Global_Clatd_Config.ipv6_host_id = in6addr_any;
635
636 // Generate a boatload of random IIDs.
637 int onebits = 0;
638 uint64_t prev_iid = 0;
639 for (int i = 0; i < 100000; i++) {
640 struct in6_addr myaddr = interface_ipv6;
641
642 config_generate_local_ipv6_subnet(&myaddr);
643
644 // Check the generated IP address is in the same prefix as the interface IPv6 address.
645 EXPECT_TRUE(ipv6_prefix_equal(&interface_ipv6, &myaddr));
646
647 // Check that consecutive IIDs are not the same.
648 uint64_t iid = * (uint64_t*) (&myaddr.s6_addr[8]);
649 ASSERT_TRUE(iid != prev_iid)
650 << "Two consecutive random IIDs are the same: "
651 << std::showbase << std::hex
652 << iid << "\n";
653 prev_iid = iid;
654
655 // Check that the IID is checksum-neutral with the NAT64 prefix and the
656 // local prefix.
657 struct in_addr *ipv4addr = &Global_Clatd_Config.ipv4_local_subnet;
658 struct in6_addr *plat_subnet = &Global_Clatd_Config.plat_subnet;
659
660 uint16_t c1 = ip_checksum_finish(ip_checksum_add(0, ipv4addr, sizeof(*ipv4addr)));
661 uint16_t c2 = ip_checksum_finish(ip_checksum_add(0, plat_subnet, sizeof(*plat_subnet)) +
662 ip_checksum_add(0, &myaddr, sizeof(myaddr)));
663
664 if (c1 != c2) {
665 char myaddr_str[INET6_ADDRSTRLEN], plat_str[INET6_ADDRSTRLEN], ipv4_str[INET6_ADDRSTRLEN];
666 inet_ntop(AF_INET6, &myaddr, myaddr_str, sizeof(myaddr_str));
667 inet_ntop(AF_INET6, plat_subnet, plat_str, sizeof(plat_str));
668 inet_ntop(AF_INET, ipv4addr, ipv4_str, sizeof(ipv4_str));
669 FAIL()
670 << "Bad IID: " << myaddr_str
671 << " not checksum-neutral with " << ipv4_str << " and " << plat_str
672 << std::showbase << std::hex
673 << "\n IPv4 checksum: " << c1
674 << "\n IPv6 checksum: " << c2
675 << "\n";
676 }
677
678 // Check that IIDs are roughly random and use all the bits by counting the
679 // total number of bits set to 1 in a random sample of 100000 generated IIDs.
680 onebits += count_onebits(&iid, sizeof(iid));
681 }
682 EXPECT_LE(3190000, onebits);
683 EXPECT_GE(3210000, onebits);
684}
685
686TEST_F(ClatdTest, DataSanitycheck) {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900687 // Sanity checks the data.
Brian Carlstromfcac4102014-02-24 20:03:01 -0800688 uint8_t v4_header[] = { IPV4_UDP_HEADER };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900689 ASSERT_EQ(sizeof(struct iphdr), sizeof(v4_header)) << "Test IPv4 header: incorrect length\n";
690
Brian Carlstromfcac4102014-02-24 20:03:01 -0800691 uint8_t v6_header[] = { IPV6_UDP_HEADER };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900692 ASSERT_EQ(sizeof(struct ip6_hdr), sizeof(v6_header)) << "Test IPv6 header: incorrect length\n";
693
Brian Carlstromfcac4102014-02-24 20:03:01 -0800694 uint8_t udp_header[] = { UDP_HEADER };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900695 ASSERT_EQ(sizeof(struct udphdr), sizeof(udp_header)) << "Test UDP header: incorrect length\n";
696
697 // Sanity checks check_packet.
698 struct udphdr *udp;
Brian Carlstromfcac4102014-02-24 20:03:01 -0800699 uint8_t v4_udp_packet[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900700 udp = (struct udphdr *) (v4_udp_packet + sizeof(struct iphdr));
701 fix_udp_checksum(v4_udp_packet);
702 ASSERT_EQ(kUdpV4Checksum, udp->check) << "UDP/IPv4 packet checksum sanity check\n";
703 check_packet(v4_udp_packet, sizeof(v4_udp_packet), "UDP/IPv4 packet sanity check");
704
Brian Carlstromfcac4102014-02-24 20:03:01 -0800705 uint8_t v6_udp_packet[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900706 udp = (struct udphdr *) (v6_udp_packet + sizeof(struct ip6_hdr));
707 fix_udp_checksum(v6_udp_packet);
708 ASSERT_EQ(kUdpV6Checksum, udp->check) << "UDP/IPv6 packet checksum sanity check\n";
709 check_packet(v6_udp_packet, sizeof(v6_udp_packet), "UDP/IPv6 packet sanity check");
710
Brian Carlstromfcac4102014-02-24 20:03:01 -0800711 uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900712 check_packet(ipv4_ping, sizeof(ipv4_ping), "IPv4 ping sanity check");
713
Brian Carlstromfcac4102014-02-24 20:03:01 -0800714 uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900715 check_packet(ipv6_ping, sizeof(ipv6_ping), "IPv6 ping sanity check");
716
717 // Sanity checks reassemble_packet.
Brian Carlstromfcac4102014-02-24 20:03:01 -0800718 uint8_t reassembled[MAXMTU];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900719 size_t total_length = sizeof(reassembled);
720 reassemble_packet(kIPv4Fragments, kIPv4FragLengths, ARRAYSIZE(kIPv4Fragments),
721 reassembled, &total_length, "Reassembly sanity check");
722 check_packet(reassembled, total_length, "IPv4 Reassembled packet is valid");
723 ASSERT_EQ(sizeof(kReassembledIPv4), total_length) << "IPv4 reassembly sanity check: length\n";
724 ASSERT_TRUE(!is_ipv4_fragment((struct iphdr *) reassembled))
725 << "Sanity check: reassembled packet is a fragment!\n";
726 check_data_matches(kReassembledIPv4, reassembled, total_length, "IPv4 reassembly sanity check");
727
728 total_length = sizeof(reassembled);
729 reassemble_packet(kIPv6Fragments, kIPv6FragLengths, ARRAYSIZE(kIPv6Fragments),
730 reassembled, &total_length, "IPv6 reassembly sanity check");
731 ASSERT_TRUE(!is_ipv6_fragment((struct ip6_hdr *) reassembled, total_length))
732 << "Sanity check: reassembled packet is a fragment!\n";
733 check_packet(reassembled, total_length, "IPv6 Reassembled packet is valid");
734}
735
736TEST_F(ClatdTest, PseudoChecksum) {
737 uint32_t pseudo_checksum;
738
Brian Carlstromfcac4102014-02-24 20:03:01 -0800739 uint8_t v4_header[] = { IPV4_UDP_HEADER };
740 uint8_t v4_pseudo_header[] = { IPV4_PSEUDOHEADER(v4_header, UDP_LEN) };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900741 pseudo_checksum = ipv4_pseudo_header_checksum((struct iphdr *) v4_header, UDP_LEN);
742 EXPECT_EQ(ip_checksum_finish(pseudo_checksum),
743 ip_checksum(v4_pseudo_header, sizeof(v4_pseudo_header)))
744 << "ipv4_pseudo_header_checksum incorrect\n";
745
Brian Carlstromfcac4102014-02-24 20:03:01 -0800746 uint8_t v6_header[] = { IPV6_UDP_HEADER };
747 uint8_t v6_pseudo_header[] = { IPV6_PSEUDOHEADER(v6_header, IPPROTO_UDP, UDP_LEN) };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900748 pseudo_checksum = ipv6_pseudo_header_checksum((struct ip6_hdr *) v6_header, UDP_LEN, IPPROTO_UDP);
749 EXPECT_EQ(ip_checksum_finish(pseudo_checksum),
750 ip_checksum(v6_pseudo_header, sizeof(v6_pseudo_header)))
751 << "ipv6_pseudo_header_checksum incorrect\n";
752}
753
754TEST_F(ClatdTest, TransportChecksum) {
Brian Carlstromfcac4102014-02-24 20:03:01 -0800755 uint8_t udphdr[] = { UDP_HEADER };
756 uint8_t payload[] = { PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900757 EXPECT_EQ(kUdpPartialChecksum, ip_checksum_add(0, udphdr, sizeof(udphdr)))
758 << "UDP partial checksum\n";
759 EXPECT_EQ(kPayloadPartialChecksum, ip_checksum_add(0, payload, sizeof(payload)))
760 << "Payload partial checksum\n";
761
Brian Carlstromfcac4102014-02-24 20:03:01 -0800762 uint8_t ip[] = { IPV4_UDP_HEADER };
763 uint8_t ip6[] = { IPV6_UDP_HEADER };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900764 uint32_t ipv4_pseudo_sum = ipv4_pseudo_header_checksum((struct iphdr *) ip, UDP_LEN);
765 uint32_t ipv6_pseudo_sum = ipv6_pseudo_header_checksum((struct ip6_hdr *) ip6, UDP_LEN,
766 IPPROTO_UDP);
767
Ben Cheng932614e2014-04-02 17:00:26 -0700768 EXPECT_EQ(0x3ad0U, ipv4_pseudo_sum) << "IPv4 pseudo-checksum sanity check\n";
769 EXPECT_EQ(0x2644bU, ipv6_pseudo_sum) << "IPv6 pseudo-checksum sanity check\n";
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900770 EXPECT_EQ(
771 kUdpV4Checksum,
772 ip_checksum_finish(ipv4_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum))
773 << "Unexpected UDP/IPv4 checksum\n";
774 EXPECT_EQ(
775 kUdpV6Checksum,
776 ip_checksum_finish(ipv6_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum))
777 << "Unexpected UDP/IPv6 checksum\n";
778
779 EXPECT_EQ(kUdpV6Checksum,
780 ip_checksum_adjust(kUdpV4Checksum, ipv4_pseudo_sum, ipv6_pseudo_sum))
781 << "Adjust IPv4/UDP checksum to IPv6\n";
782 EXPECT_EQ(kUdpV4Checksum,
783 ip_checksum_adjust(kUdpV6Checksum, ipv6_pseudo_sum, ipv4_pseudo_sum))
784 << "Adjust IPv6/UDP checksum to IPv4\n";
785}
786
787TEST_F(ClatdTest, AdjustChecksum) {
788 struct checksum_data {
789 uint16_t checksum;
790 uint32_t old_hdr_sum;
791 uint32_t new_hdr_sum;
792 uint16_t result;
793 } DATA[] = {
794 { 0x1423, 0xb8ec, 0x2d757, 0xf5b5 },
795 { 0xf5b5, 0x2d757, 0xb8ec, 0x1423 },
796 { 0xdd2f, 0x5555, 0x3285, 0x0000 },
797 { 0x1215, 0x5560, 0x15560 + 20, 0x1200 },
798 { 0xd0c7, 0x3ad0, 0x2644b, 0xa74a },
799 };
800 unsigned i, failed = 0;
801
802 for (i = 0; i < ARRAYSIZE(DATA); i++) {
803 struct checksum_data *data = DATA + i;
804 uint16_t result = ip_checksum_adjust(data->checksum, data->old_hdr_sum, data->new_hdr_sum);
805 EXPECT_EQ(result, data->result)
806 << "Incorrect checksum" << std::showbase << std::hex
807 << "\n Expected: " << data->result
808 << "\n Actual: " << result
809 << "\n checksum=" << data->checksum
810 << " old_sum=" << data->old_hdr_sum << " new_sum=" << data->new_hdr_sum << "\n";
811 }
812}
813
814TEST_F(ClatdTest, Translate) {
Brian Carlstromfcac4102014-02-24 20:03:01 -0800815 uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
816 uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900817 fix_udp_checksum(udp_ipv4);
818 fix_udp_checksum(udp_ipv6);
819 check_translated_packet(udp_ipv4, sizeof(udp_ipv4), udp_ipv6, sizeof(udp_ipv6),
820 "UDP/IPv4 -> UDP/IPv6 translation");
821 check_translated_packet(udp_ipv6, sizeof(udp_ipv6), udp_ipv4, sizeof(udp_ipv4),
822 "UDP/IPv6 -> UDP/IPv4 translation");
823
Brian Carlstromfcac4102014-02-24 20:03:01 -0800824 uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD };
825 uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900826 check_translated_packet(ipv4_ping, sizeof(ipv4_ping), ipv6_ping, sizeof(ipv6_ping),
827 "ICMP->ICMPv6 translation");
828 check_translated_packet(ipv6_ping, sizeof(ipv6_ping), ipv4_ping, sizeof(ipv4_ping),
829 "ICMPv6->ICMP translation");
830}
831
832TEST_F(ClatdTest, Fragmentation) {
833 int len, i;
834 check_fragment_translation(kIPv4Fragments, kIPv4FragLengths,
835 kIPv6Fragments, kIPv6FragLengths,
836 ARRAYSIZE(kIPv4Fragments), "IPv4->IPv6 fragment translation");
837
838 check_fragment_translation(kIPv6Fragments, kIPv6FragLengths,
839 kIPv4Fragments, kIPv4FragLengths,
840 ARRAYSIZE(kIPv6Fragments), "IPv6->IPv4 fragment translation");
841}
Lorenzo Colitti98089522014-10-09 22:29:45 +0900842
843void check_translate_checksum_neutral(const uint8_t *original, size_t original_len,
844 size_t expected_len, const char *msg) {
845 uint8_t translated[MAXMTU];
846 size_t translated_len = sizeof(translated);
847 do_translate_packet(original, original_len, translated, &translated_len, msg);
848 EXPECT_EQ(expected_len, translated_len) << msg << ": Translated packet length incorrect\n";
849 // do_translate_packet already checks packets for validity and verifies the checksum.
850 int original_check = get_transport_checksum(original);
851 int translated_check = get_transport_checksum(translated);
852 ASSERT_NE(-1, original_check);
853 ASSERT_NE(-1, translated_check);
854 ASSERT_EQ(original_check, translated_check)
855 << "Not checksum neutral: original and translated checksums differ\n";
856}
857
858TEST_F(ClatdTest, TranslateChecksumNeutral) {
859 // Generate a random clat IPv6 address and check that translation is checksum-neutral.
860 Global_Clatd_Config.ipv6_host_id = in6addr_any;
861 ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54",
862 &Global_Clatd_Config.ipv6_local_subnet));
863 config_generate_local_ipv6_subnet(&Global_Clatd_Config.ipv6_local_subnet);
864 ASSERT_NE((uint32_t) 0x00000464, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]);
865 ASSERT_NE((uint32_t) 0, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]);
866
867 // Check that translating UDP packets is checksum-neutral. First, IPv4.
868 uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
869 fix_udp_checksum(udp_ipv4);
870 check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20,
871 "UDP/IPv4 -> UDP/IPv6 checksum neutral");
872
873 // Now try IPv6.
874 uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
875 // The test packet uses the static IID, not the random IID. Fix up the source address.
876 struct ip6_hdr *ip6 = (struct ip6_hdr *) udp_ipv6;
877 memcpy(&ip6->ip6_src, &Global_Clatd_Config.ipv6_local_subnet, sizeof(ip6->ip6_src));
878 fix_udp_checksum(udp_ipv6);
879 check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20,
880 "UDP/IPv4 -> UDP/IPv6 checksum neutral");
881}