blob: b61da9f65fa12d717be659785d086dff6742dc0e [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>
23#include <sys/uio.h>
24
25#include <gtest/gtest.h>
26
27extern "C" {
28#include "checksum.h"
29#include "translate.h"
30#include "config.h"
31#include "clatd.h"
32}
33
34// For convenience.
35#define ARRAYSIZE(x) sizeof((x)) / sizeof((x)[0])
36
37// Default translation parameters.
38static const char kIPv4LocalAddr[] = "192.0.0.4";
39static const char kIPv6LocalAddr[] = "2001:db8:0:b11::464";
40static const char kIPv6PlatSubnet[] = "64:ff9b::";
41
42// Test packet portions. Defined as macros because it's easy to concatenate them to make packets.
43#define IPV4_HEADER(p, c1, c2) \
44 0x45, 0x00, 0, 41, /* Version=4, IHL=5, ToS=0x80, len=41 */ \
45 0x00, 0x00, 0x40, 0x00, /* ID=0x0000, flags=IP_DF, offset=0 */ \
46 55, (p), (c1), (c2), /* TTL=55, protocol=p, checksum=c1,c2 */ \
47 192, 0, 0, 4, /* Src=192.0.0.4 */ \
48 8, 8, 8, 8, /* Dst=8.8.8.8 */
49#define IPV4_UDP_HEADER IPV4_HEADER(IPPROTO_UDP, 0x73, 0xb0)
50#define IPV4_ICMP_HEADER IPV4_HEADER(IPPROTO_ICMP, 0x73, 0xc0)
51
52#define IPV6_HEADER(p) \
53 0x60, 0x00, 0, 0, /* Version=6, tclass=0x00, flowlabel=0 */ \
54 0, 21, (p), 55, /* plen=11, nxthdr=p, hlim=55 */ \
55 0x20, 0x01, 0x0d, 0xb8, /* Src=2001:db8:0:b11::464 */ \
56 0x00, 0x00, 0x0b, 0x11, \
57 0x00, 0x00, 0x00, 0x00, \
58 0x00, 0x00, 0x04, 0x64, \
59 0x00, 0x64, 0xff, 0x9b, /* Dst=64:ff9b::8.8.8.8 */ \
60 0x00, 0x00, 0x00, 0x00, \
61 0x00, 0x00, 0x00, 0x00, \
62 0x08, 0x08, 0x08, 0x08,
63#define IPV6_UDP_HEADER IPV6_HEADER(IPPROTO_UDP)
64#define IPV6_ICMPV6_HEADER IPV6_HEADER(IPPROTO_ICMPV6)
65
66#define UDP_LEN 21
67#define UDP_HEADER \
68 0xc8, 0x8b, 0, 53, /* Port 51339->53 */ \
69 0x00, UDP_LEN, 0, 0, /* Length 21, checksum empty for now */
70
71#define PAYLOAD 'H', 'e', 'l', 'l', 'o', ' ', 0x4e, 0xb8, 0x96, 0xe7, 0x95, 0x8c, 0x00
72
73#define IPV4_PING \
74 0x08, 0x00, 0x88, 0xd0, /* Type 8, code 0, checksum 0x88d0 */ \
75 0xd0, 0x0d, 0x00, 0x03, /* ID=0xd00d, seq=3 */
76
77#define IPV6_PING \
78 0x80, 0x00, 0xc3, 0x42, /* Type 128, code 0, checksum 0xc342 */ \
79 0xd0, 0x0d, 0x00, 0x03, /* ID=0xd00d, seq=3 */
80
81// Macros to return pseudo-headers from packets.
82#define IPV4_PSEUDOHEADER(ip, tlen) \
83 ip[12], ip[13], ip[14], ip[15], /* Source address */ \
84 ip[16], ip[17], ip[18], ip[19], /* Destination address */ \
85 0, ip[9], /* 0, protocol */ \
86 ((tlen) >> 16) & 0xff, (tlen) & 0xff, /* Transport length */
87
88#define IPV6_PSEUDOHEADER(ip6, protocol, tlen) \
89 ip6[8], ip6[9], ip6[10], ip6[11], /* Source address */ \
90 ip6[12], ip6[13], ip6[14], ip6[15], \
91 ip6[16], ip6[17], ip6[18], ip6[19], \
92 ip6[20], ip6[21], ip6[22], ip6[23], \
93 ip6[24], ip6[25], ip6[26], ip6[27], /* Destination address */ \
94 ip6[28], ip6[29], ip6[30], ip6[31], \
95 ip6[32], ip6[33], ip6[34], ip6[35], \
96 ip6[36], ip6[37], ip6[38], ip6[39], \
97 ((tlen) >> 24) & 0xff, /* Transport length */ \
98 ((tlen) >> 16) & 0xff, \
99 ((tlen) >> 8) & 0xff, \
100 (tlen) & 0xff, \
101 0, 0, 0, (protocol),
102
103// A fragmented DNS request.
Brian Carlstromfcac4102014-02-24 20:03:01 -0800104static const uint8_t kIPv4Frag1[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900105 0x45, 0x00, 0x00, 0x24, 0xfe, 0x47, 0x20, 0x00, 0x40, 0x11,
106 0x8c, 0x6d, 0xc0, 0x00, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08,
107 0x14, 0x5d, 0x00, 0x35, 0x00, 0x29, 0x68, 0xbb, 0x50, 0x47,
108 0x01, 0x00, 0x00, 0x01, 0x00, 0x00
109};
Brian Carlstromfcac4102014-02-24 20:03:01 -0800110static const uint8_t kIPv4Frag2[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900111 0x45, 0x00, 0x00, 0x24, 0xfe, 0x47, 0x20, 0x02, 0x40, 0x11,
112 0x8c, 0x6b, 0xc0, 0x00, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08,
113 0x00, 0x00, 0x00, 0x00, 0x04, 0x69, 0x70, 0x76, 0x34, 0x06,
114 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65
115};
Brian Carlstromfcac4102014-02-24 20:03:01 -0800116static const uint8_t kIPv4Frag3[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900117 0x45, 0x00, 0x00, 0x1d, 0xfe, 0x47, 0x00, 0x04, 0x40, 0x11,
118 0xac, 0x70, 0xc0, 0x00, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08,
119 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
120};
Brian Carlstromfcac4102014-02-24 20:03:01 -0800121static const uint8_t *kIPv4Fragments[] = { kIPv4Frag1, kIPv4Frag2, kIPv4Frag3 };
122static const size_t kIPv4FragLengths[] = { sizeof(kIPv4Frag1), sizeof(kIPv4Frag2),
123 sizeof(kIPv4Frag3) };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900124
Brian Carlstromfcac4102014-02-24 20:03:01 -0800125static const uint8_t kIPv6Frag1[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900126 0x60, 0x00, 0x00, 0x00, 0x00, 0x18, 0x2c, 0x40, 0x20, 0x01,
127 0x0d, 0xb8, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x00, 0x00, 0x00,
128 0x00, 0x00, 0x04, 0x64, 0x00, 0x64, 0xff, 0x9b, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
130 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0xfe, 0x47, 0x14, 0x5d,
131 0x00, 0x35, 0x00, 0x29, 0xeb, 0x91, 0x50, 0x47, 0x01, 0x00,
132 0x00, 0x01, 0x00, 0x00
133};
134
Brian Carlstromfcac4102014-02-24 20:03:01 -0800135static const uint8_t kIPv6Frag2[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900136 0x60, 0x00, 0x00, 0x00, 0x00, 0x18, 0x2c, 0x40, 0x20, 0x01,
137 0x0d, 0xb8, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x00, 0x00, 0x00,
138 0x00, 0x00, 0x04, 0x64, 0x00, 0x64, 0xff, 0x9b, 0x00, 0x00,
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
140 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0xfe, 0x47, 0x00, 0x00,
141 0x00, 0x00, 0x04, 0x69, 0x70, 0x76, 0x34, 0x06, 0x67, 0x6f,
142 0x6f, 0x67, 0x6c, 0x65
143};
144
Brian Carlstromfcac4102014-02-24 20:03:01 -0800145static const uint8_t kIPv6Frag3[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900146 0x60, 0x00, 0x00, 0x00, 0x00, 0x11, 0x2c, 0x40, 0x20, 0x01,
147 0x0d, 0xb8, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x00, 0x00, 0x00,
148 0x00, 0x00, 0x04, 0x64, 0x00, 0x64, 0xff, 0x9b, 0x00, 0x00,
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
150 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0xfe, 0x47, 0x03, 0x63,
151 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
152};
Brian Carlstromfcac4102014-02-24 20:03:01 -0800153static const uint8_t *kIPv6Fragments[] = { kIPv6Frag1, kIPv6Frag2, kIPv6Frag3 };
154static const size_t kIPv6FragLengths[] = { sizeof(kIPv6Frag1), sizeof(kIPv6Frag2),
155 sizeof(kIPv6Frag3) };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900156
Brian Carlstromfcac4102014-02-24 20:03:01 -0800157static const uint8_t kReassembledIPv4[] = {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900158 0x45, 0x00, 0x00, 0x3d, 0xfe, 0x47, 0x00, 0x00, 0x40, 0x11,
159 0xac, 0x54, 0xc0, 0x00, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08,
160 0x14, 0x5d, 0x00, 0x35, 0x00, 0x29, 0x68, 0xbb, 0x50, 0x47,
161 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x04, 0x69, 0x70, 0x76, 0x34, 0x06, 0x67, 0x6f, 0x6f, 0x67,
163 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00,
164 0x01
165};
166
167// Expected checksums.
168static const uint32_t kUdpPartialChecksum = 0xd5c8;
169static const uint32_t kPayloadPartialChecksum = 0x31e9c;
170static const uint16_t kUdpV4Checksum = 0xd0c7;
171static const uint16_t kUdpV6Checksum = 0xa74a;
172
Brian Carlstromfcac4102014-02-24 20:03:01 -0800173uint8_t ip_version(const uint8_t *packet) {
174 uint8_t version = packet[0] >> 4;
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900175 return version;
176}
177
178int is_ipv4_fragment(struct iphdr *ip) {
179 // A packet is a fragment if its fragment offset is nonzero or if the MF flag is set.
180 return ntohs(ip->frag_off) & (IP_OFFMASK | IP_MF);
181}
182
183int is_ipv6_fragment(struct ip6_hdr *ip6, size_t len) {
184 if (ip6->ip6_nxt != IPPROTO_FRAGMENT) {
185 return 0;
186 }
187 struct ip6_frag *frag = (struct ip6_frag *) (ip6 + 1);
188 return len >= sizeof(*ip6) + sizeof(*frag) &&
189 (frag->ip6f_offlg & (IP6F_OFF_MASK | IP6F_MORE_FRAG));
190}
191
192int ipv4_fragment_offset(struct iphdr *ip) {
193 return ntohs(ip->frag_off) & IP_OFFMASK;
194}
195
196int ipv6_fragment_offset(struct ip6_frag *frag) {
197 return ntohs((frag->ip6f_offlg & IP6F_OFF_MASK) >> 3);
198}
199
Brian Carlstromfcac4102014-02-24 20:03:01 -0800200void check_packet(const uint8_t *packet, size_t len, const char *msg) {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900201 void *payload;
202 size_t payload_length = 0;
203 uint32_t pseudo_checksum = 0;
204 uint8_t protocol = 0;
205 int version = ip_version(packet);
206 switch (version) {
207 case 4: {
208 struct iphdr *ip = (struct iphdr *) packet;
209 ASSERT_GE(len, sizeof(*ip)) << msg << ": IPv4 packet shorter than IPv4 header\n";
210 EXPECT_EQ(5, ip->ihl) << msg << ": Unsupported IP header length\n";
211 EXPECT_EQ(len, ntohs(ip->tot_len)) << msg << ": Incorrect IPv4 length\n";
212 EXPECT_EQ(0, ip_checksum(ip, sizeof(*ip))) << msg << ": Incorrect IP checksum\n";
213 protocol = ip->protocol;
214 payload = ip + 1;
215 if (!is_ipv4_fragment(ip)) {
216 payload_length = len - sizeof(*ip);
217 pseudo_checksum = ipv4_pseudo_header_checksum(ip, payload_length);
218 }
219 ASSERT_TRUE(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP || protocol == IPPROTO_ICMP)
220 << msg << ": Unsupported IPv4 protocol " << protocol << "\n";
221 break;
222 }
223 case 6: {
224 struct ip6_hdr *ip6 = (struct ip6_hdr *) packet;
225 ASSERT_GE(len, sizeof(*ip6)) << msg << ": IPv6 packet shorter than IPv6 header\n";
226 EXPECT_EQ(len - sizeof(*ip6), htons(ip6->ip6_plen)) << msg << ": Incorrect IPv6 length\n";
227
228 if (ip6->ip6_nxt == IPPROTO_FRAGMENT) {
229 struct ip6_frag *frag = (struct ip6_frag *) (ip6 + 1);
230 ASSERT_GE(len, sizeof(*ip6) + sizeof(*frag))
231 << msg << ": IPv6 fragment: short fragment header\n";
232 protocol = frag->ip6f_nxt;
233 payload = frag + 1;
234 // Even though the packet has a Fragment header, it might not be a fragment.
235 if (!is_ipv6_fragment(ip6, len)) {
236 payload_length = len - sizeof(*ip6) - sizeof(*frag);
237 }
238 } else {
239 // Since there are no extension headers except Fragment, this must be the payload.
240 protocol = ip6->ip6_nxt;
241 payload = ip6 + 1;
242 payload_length = len - sizeof(*ip6);
243 }
244 ASSERT_TRUE(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP || protocol == IPPROTO_ICMPV6)
245 << msg << ": Unsupported IPv6 next header " << protocol;
246 if (payload_length) {
247 pseudo_checksum = ipv6_pseudo_header_checksum(ip6, payload_length, protocol);
248 }
249 break;
250 }
251 default:
252 FAIL() << msg << ": Unsupported IP version " << version << "\n";
253 return;
254 }
255
256 // If we understand the payload, verify the checksum.
257 if (payload_length) {
258 uint16_t checksum;
259 switch(protocol) {
260 case IPPROTO_UDP:
261 case IPPROTO_TCP:
262 case IPPROTO_ICMPV6:
263 checksum = ip_checksum_finish(ip_checksum_add(pseudo_checksum, payload, payload_length));
264 break;
265 case IPPROTO_ICMP:
266 checksum = ip_checksum(payload, payload_length);
267 break;
268 default:
269 checksum = 0; // Don't check.
270 break;
271 }
272 EXPECT_EQ(0, checksum) << msg << ": Incorrect transport checksum\n";
273 }
274
275 if (protocol == IPPROTO_UDP) {
276 struct udphdr *udp = (struct udphdr *) payload;
277 EXPECT_NE(0, udp->check) << msg << ": UDP checksum 0 should be 0xffff";
278 // If this is not a fragment, check the UDP length field.
279 if (payload_length) {
280 EXPECT_EQ(payload_length, ntohs(udp->len)) << msg << ": Incorrect UDP length\n";
281 }
282 }
283}
284
Brian Carlstromfcac4102014-02-24 20:03:01 -0800285void reassemble_packet(const uint8_t **fragments, const size_t lengths[], int numpackets,
286 uint8_t *reassembled, size_t *reassembled_len, const char *msg) {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900287 struct iphdr *ip = NULL;
288 struct ip6_hdr *ip6 = NULL;
Ben Cheng932614e2014-04-02 17:00:26 -0700289 size_t total_length, pos = 0;
290 uint8_t protocol = 0;
Brian Carlstromfcac4102014-02-24 20:03:01 -0800291 uint8_t version = ip_version(fragments[0]);
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900292
293 for (int i = 0; i < numpackets; i++) {
Brian Carlstromfcac4102014-02-24 20:03:01 -0800294 const uint8_t *packet = fragments[i];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900295 int len = lengths[i];
296 int headersize, payload_offset;
297
298 ASSERT_EQ(ip_version(packet), version) << msg << ": Inconsistent fragment versions\n";
299 check_packet(packet, len, "Fragment sanity check");
300
301 switch (version) {
302 case 4: {
303 struct iphdr *ip_orig = (struct iphdr *) packet;
304 headersize = sizeof(*ip_orig);
305 ASSERT_TRUE(is_ipv4_fragment(ip_orig))
306 << msg << ": IPv4 fragment #" << i + 1 << " not a fragment\n";
307 ASSERT_EQ(pos, ipv4_fragment_offset(ip_orig) * 8 + ((i != 0) ? sizeof(*ip): 0))
308 << msg << ": IPv4 fragment #" << i + 1 << ": inconsistent offset\n";
309
310 headersize = sizeof(*ip_orig);
311 payload_offset = headersize;
312 if (pos == 0) {
313 ip = (struct iphdr *) reassembled;
314 }
315 break;
316 }
317 case 6: {
318 struct ip6_hdr *ip6_orig = (struct ip6_hdr *) packet;
319 struct ip6_frag *frag = (struct ip6_frag *) (ip6_orig + 1);
320 ASSERT_TRUE(is_ipv6_fragment(ip6_orig, len))
321 << msg << ": IPv6 fragment #" << i + 1 << " not a fragment\n";
322 ASSERT_EQ(pos, ipv6_fragment_offset(frag) * 8 + ((i != 0) ? sizeof(*ip6): 0))
323 << msg << ": IPv6 fragment #" << i + 1 << ": inconsistent offset\n";
324
325 headersize = sizeof(*ip6_orig);
326 payload_offset = sizeof(*ip6_orig) + sizeof(*frag);
327 if (pos == 0) {
328 ip6 = (struct ip6_hdr *) reassembled;
329 protocol = frag->ip6f_nxt;
330 }
331 break;
332 }
333 default:
334 FAIL() << msg << ": Invalid IP version << " << version;
335 }
336
337 // If this is the first fragment, copy the header.
338 if (pos == 0) {
339 ASSERT_LT(headersize, (int) *reassembled_len) << msg << ": Reassembly buffer too small\n";
340 memcpy(reassembled, packet, headersize);
341 total_length = headersize;
342 pos += headersize;
343 }
344
345 // Copy the payload.
346 int payload_length = len - payload_offset;
347 total_length += payload_length;
Ben Cheng932614e2014-04-02 17:00:26 -0700348 ASSERT_LT(total_length, *reassembled_len) << msg << ": Reassembly buffer too small\n";
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900349 memcpy(reassembled + pos, packet + payload_offset, payload_length);
350 pos += payload_length;
351 }
352
353
354 // Fix up the reassembled headers to reflect fragmentation and length (and IPv4 checksum).
355 ASSERT_EQ(total_length, pos) << msg << ": Reassembled packet length incorrect\n";
356 if (ip) {
357 ip->frag_off &= ~htons(IP_MF);
358 ip->tot_len = htons(total_length);
359 ip->check = 0;
360 ip->check = ip_checksum(ip, sizeof(*ip));
361 ASSERT_FALSE(is_ipv4_fragment(ip)) << msg << ": reassembled IPv4 packet is a fragment!\n";
362 }
363 if (ip6) {
364 ip6->ip6_nxt = protocol;
365 ip6->ip6_plen = htons(total_length - sizeof(*ip6));
366 ASSERT_FALSE(is_ipv6_fragment(ip6, ip6->ip6_plen))
367 << msg << ": reassembled IPv6 packet is a fragment!\n";
368 }
369
370 *reassembled_len = total_length;
371}
372
Brian Carlstromfcac4102014-02-24 20:03:01 -0800373void check_data_matches(const uint8_t *expected, const uint8_t *actual, size_t len, const char *msg) {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900374 if (memcmp(expected, actual, len)) {
375 // Hex dump, 20 bytes per line, one space between bytes (1 byte = 3 chars), indented by 4.
376 int hexdump_len = len * 3 + (len / 20 + 1) * 5;
377 char expected_hexdump[hexdump_len], actual_hexdump[hexdump_len];
378 unsigned pos = 0;
379 for (unsigned i = 0; i < len; i++) {
380 if (i % 20 == 0) {
381 sprintf(expected_hexdump + pos, "\n ");
382 sprintf(actual_hexdump + pos, "\n ");
383 pos += 4;
384 }
385 sprintf(expected_hexdump + pos, " %02x", expected[i]);
386 sprintf(actual_hexdump + pos, " %02x", actual[i]);
387 pos += 3;
388 }
389 FAIL() << msg << ": Translated packet doesn't match"
390 << "\n Expected:" << (char *) expected_hexdump
391 << "\n Actual:" << (char *) actual_hexdump << "\n";
392 }
393}
394
Brian Carlstromfcac4102014-02-24 20:03:01 -0800395void fix_udp_checksum(uint8_t* packet) {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900396 uint32_t pseudo_checksum;
Brian Carlstromfcac4102014-02-24 20:03:01 -0800397 uint8_t version = ip_version(packet);
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900398 struct udphdr *udp;
399 switch (version) {
400 case 4: {
401 struct iphdr *ip = (struct iphdr *) packet;
402 udp = (struct udphdr *) (ip + 1);
403 pseudo_checksum = ipv4_pseudo_header_checksum(ip, ntohs(udp->len));
404 break;
405 }
406 case 6: {
407 struct ip6_hdr *ip6 = (struct ip6_hdr *) packet;
408 udp = (struct udphdr *) (ip6 + 1);
409 pseudo_checksum = ipv6_pseudo_header_checksum(ip6, ntohs(udp->len), IPPROTO_UDP);
410 break;
411 }
412 default:
413 FAIL() << "unsupported IP version" << version << "\n";
414 return;
415 }
416
417 udp->check = 0;
418 udp->check = ip_checksum_finish(ip_checksum_add(pseudo_checksum, udp, ntohs(udp->len)));
419}
420
Lorenzo Colittice140882014-06-02 21:20:40 +0900421// Testing stub for send_rawv6. The real version uses sendmsg() with a
422// destination IPv6 address, and attempting to call that on our test socketpair
423// fd results in EINVAL.
424extern "C" void send_rawv6(int fd, clat_packet out, int iov_len) {
425 writev(fd, out, iov_len);
426}
427
Brian Carlstromfcac4102014-02-24 20:03:01 -0800428void do_translate_packet(const uint8_t *original, size_t original_len, uint8_t *out, size_t *outlen,
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900429 const char *msg) {
430 int fds[2];
431 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, fds)) {
432 abort();
433 }
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900434
435 char foo[512];
436 snprintf(foo, sizeof(foo), "%s: Invalid original packet", msg);
437 check_packet(original, original_len, foo);
438
Lorenzo Colittie24982e2014-06-02 15:49:36 +0900439 int read_fd, write_fd;
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900440 uint16_t expected_proto;
441 int version = ip_version(original);
442 switch (version) {
443 case 4:
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900444 expected_proto = htons(ETH_P_IPV6);
445 read_fd = fds[1];
Lorenzo Colittie24982e2014-06-02 15:49:36 +0900446 write_fd = fds[0];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900447 break;
448 case 6:
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900449 expected_proto = htons(ETH_P_IP);
450 read_fd = fds[0];
Lorenzo Colittie24982e2014-06-02 15:49:36 +0900451 write_fd = fds[1];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900452 break;
453 default:
454 FAIL() << msg << ": Unsupported IP version " << version << "\n";
455 break;
456 }
457
Lorenzo Colittie24982e2014-06-02 15:49:36 +0900458 translate_packet(write_fd, (version == 4), original, original_len);
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900459
Lorenzo Colittice140882014-06-02 21:20:40 +0900460 if (version == 6) {
461 // Translating to IPv4. Expect a tun header.
462 struct tun_pi new_tun_header;
463 struct iovec iov[] = {
464 { &new_tun_header, sizeof(new_tun_header) },
465 { out, *outlen }
466 };
467 int len = readv(read_fd, iov, 2);
468 if (len > (int) sizeof(new_tun_header)) {
469 ASSERT_LT((size_t) len, *outlen) << msg << ": Translated packet buffer too small\n";
470 EXPECT_EQ(expected_proto, new_tun_header.proto) << msg << "Unexpected tun proto\n";
471 *outlen = len - sizeof(new_tun_header);
472 } else {
473 FAIL() << msg << ": Packet was not translated";
474 *outlen = 0;
475 }
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900476 } else {
Lorenzo Colittice140882014-06-02 21:20:40 +0900477 // Translating to IPv6. Expect raw packet.
478 *outlen = read(read_fd, out, *outlen);
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900479 }
480}
481
Brian Carlstromfcac4102014-02-24 20:03:01 -0800482void check_translated_packet(const uint8_t *original, size_t original_len,
483 const uint8_t *expected, size_t expected_len, const char *msg) {
484 uint8_t translated[MAXMTU];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900485 size_t translated_len = sizeof(translated);
486 do_translate_packet(original, original_len, translated, &translated_len, msg);
487 EXPECT_EQ(expected_len, translated_len) << msg << ": Translated packet length incorrect\n";
488 check_data_matches(expected, translated, translated_len, msg);
489}
490
Brian Carlstromfcac4102014-02-24 20:03:01 -0800491void check_fragment_translation(const uint8_t *original[], const size_t original_lengths[],
492 const uint8_t *expected[], const size_t expected_lengths[],
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900493 int numfragments, const char *msg) {
494 for (int i = 0; i < numfragments; i++) {
495 // Check that each of the fragments translates as expected.
496 char frag_msg[512];
497 snprintf(frag_msg, sizeof(frag_msg), "%s: fragment #%d", msg, i + 1);
498 check_translated_packet(original[i], original_lengths[i],
499 expected[i], expected_lengths[i], frag_msg);
500 }
501
502 // Sanity check that reassembling the original and translated fragments produces valid packets.
Brian Carlstromfcac4102014-02-24 20:03:01 -0800503 uint8_t reassembled[MAXMTU];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900504 size_t reassembled_len = sizeof(reassembled);
505 reassemble_packet(original, original_lengths, numfragments, reassembled, &reassembled_len, msg);
506 check_packet(reassembled, reassembled_len, msg);
507
Brian Carlstromfcac4102014-02-24 20:03:01 -0800508 uint8_t translated[MAXMTU];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900509 size_t translated_len = sizeof(translated);
510 do_translate_packet(reassembled, reassembled_len, translated, &translated_len, msg);
511 check_packet(translated, translated_len, msg);
512}
513
514struct clat_config Global_Clatd_Config;
515
516class ClatdTest : public ::testing::Test {
517 protected:
518 virtual void SetUp() {
519 inet_pton(AF_INET, kIPv4LocalAddr, &Global_Clatd_Config.ipv4_local_subnet);
520 inet_pton(AF_INET6, kIPv6PlatSubnet, &Global_Clatd_Config.plat_subnet);
521 inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet);
522 }
523};
524
525TEST_F(ClatdTest, Sanitycheck) {
526 // Sanity checks the data.
Brian Carlstromfcac4102014-02-24 20:03:01 -0800527 uint8_t v4_header[] = { IPV4_UDP_HEADER };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900528 ASSERT_EQ(sizeof(struct iphdr), sizeof(v4_header)) << "Test IPv4 header: incorrect length\n";
529
Brian Carlstromfcac4102014-02-24 20:03:01 -0800530 uint8_t v6_header[] = { IPV6_UDP_HEADER };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900531 ASSERT_EQ(sizeof(struct ip6_hdr), sizeof(v6_header)) << "Test IPv6 header: incorrect length\n";
532
Brian Carlstromfcac4102014-02-24 20:03:01 -0800533 uint8_t udp_header[] = { UDP_HEADER };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900534 ASSERT_EQ(sizeof(struct udphdr), sizeof(udp_header)) << "Test UDP header: incorrect length\n";
535
536 // Sanity checks check_packet.
537 struct udphdr *udp;
Brian Carlstromfcac4102014-02-24 20:03:01 -0800538 uint8_t v4_udp_packet[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900539 udp = (struct udphdr *) (v4_udp_packet + sizeof(struct iphdr));
540 fix_udp_checksum(v4_udp_packet);
541 ASSERT_EQ(kUdpV4Checksum, udp->check) << "UDP/IPv4 packet checksum sanity check\n";
542 check_packet(v4_udp_packet, sizeof(v4_udp_packet), "UDP/IPv4 packet sanity check");
543
Brian Carlstromfcac4102014-02-24 20:03:01 -0800544 uint8_t v6_udp_packet[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900545 udp = (struct udphdr *) (v6_udp_packet + sizeof(struct ip6_hdr));
546 fix_udp_checksum(v6_udp_packet);
547 ASSERT_EQ(kUdpV6Checksum, udp->check) << "UDP/IPv6 packet checksum sanity check\n";
548 check_packet(v6_udp_packet, sizeof(v6_udp_packet), "UDP/IPv6 packet sanity check");
549
Brian Carlstromfcac4102014-02-24 20:03:01 -0800550 uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900551 check_packet(ipv4_ping, sizeof(ipv4_ping), "IPv4 ping sanity check");
552
Brian Carlstromfcac4102014-02-24 20:03:01 -0800553 uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900554 check_packet(ipv6_ping, sizeof(ipv6_ping), "IPv6 ping sanity check");
555
556 // Sanity checks reassemble_packet.
Brian Carlstromfcac4102014-02-24 20:03:01 -0800557 uint8_t reassembled[MAXMTU];
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900558 size_t total_length = sizeof(reassembled);
559 reassemble_packet(kIPv4Fragments, kIPv4FragLengths, ARRAYSIZE(kIPv4Fragments),
560 reassembled, &total_length, "Reassembly sanity check");
561 check_packet(reassembled, total_length, "IPv4 Reassembled packet is valid");
562 ASSERT_EQ(sizeof(kReassembledIPv4), total_length) << "IPv4 reassembly sanity check: length\n";
563 ASSERT_TRUE(!is_ipv4_fragment((struct iphdr *) reassembled))
564 << "Sanity check: reassembled packet is a fragment!\n";
565 check_data_matches(kReassembledIPv4, reassembled, total_length, "IPv4 reassembly sanity check");
566
567 total_length = sizeof(reassembled);
568 reassemble_packet(kIPv6Fragments, kIPv6FragLengths, ARRAYSIZE(kIPv6Fragments),
569 reassembled, &total_length, "IPv6 reassembly sanity check");
570 ASSERT_TRUE(!is_ipv6_fragment((struct ip6_hdr *) reassembled, total_length))
571 << "Sanity check: reassembled packet is a fragment!\n";
572 check_packet(reassembled, total_length, "IPv6 Reassembled packet is valid");
573}
574
575TEST_F(ClatdTest, PseudoChecksum) {
576 uint32_t pseudo_checksum;
577
Brian Carlstromfcac4102014-02-24 20:03:01 -0800578 uint8_t v4_header[] = { IPV4_UDP_HEADER };
579 uint8_t v4_pseudo_header[] = { IPV4_PSEUDOHEADER(v4_header, UDP_LEN) };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900580 pseudo_checksum = ipv4_pseudo_header_checksum((struct iphdr *) v4_header, UDP_LEN);
581 EXPECT_EQ(ip_checksum_finish(pseudo_checksum),
582 ip_checksum(v4_pseudo_header, sizeof(v4_pseudo_header)))
583 << "ipv4_pseudo_header_checksum incorrect\n";
584
Brian Carlstromfcac4102014-02-24 20:03:01 -0800585 uint8_t v6_header[] = { IPV6_UDP_HEADER };
586 uint8_t v6_pseudo_header[] = { IPV6_PSEUDOHEADER(v6_header, IPPROTO_UDP, UDP_LEN) };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900587 pseudo_checksum = ipv6_pseudo_header_checksum((struct ip6_hdr *) v6_header, UDP_LEN, IPPROTO_UDP);
588 EXPECT_EQ(ip_checksum_finish(pseudo_checksum),
589 ip_checksum(v6_pseudo_header, sizeof(v6_pseudo_header)))
590 << "ipv6_pseudo_header_checksum incorrect\n";
591}
592
593TEST_F(ClatdTest, TransportChecksum) {
Brian Carlstromfcac4102014-02-24 20:03:01 -0800594 uint8_t udphdr[] = { UDP_HEADER };
595 uint8_t payload[] = { PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900596 EXPECT_EQ(kUdpPartialChecksum, ip_checksum_add(0, udphdr, sizeof(udphdr)))
597 << "UDP partial checksum\n";
598 EXPECT_EQ(kPayloadPartialChecksum, ip_checksum_add(0, payload, sizeof(payload)))
599 << "Payload partial checksum\n";
600
Brian Carlstromfcac4102014-02-24 20:03:01 -0800601 uint8_t ip[] = { IPV4_UDP_HEADER };
602 uint8_t ip6[] = { IPV6_UDP_HEADER };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900603 uint32_t ipv4_pseudo_sum = ipv4_pseudo_header_checksum((struct iphdr *) ip, UDP_LEN);
604 uint32_t ipv6_pseudo_sum = ipv6_pseudo_header_checksum((struct ip6_hdr *) ip6, UDP_LEN,
605 IPPROTO_UDP);
606
Ben Cheng932614e2014-04-02 17:00:26 -0700607 EXPECT_EQ(0x3ad0U, ipv4_pseudo_sum) << "IPv4 pseudo-checksum sanity check\n";
608 EXPECT_EQ(0x2644bU, ipv6_pseudo_sum) << "IPv6 pseudo-checksum sanity check\n";
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900609 EXPECT_EQ(
610 kUdpV4Checksum,
611 ip_checksum_finish(ipv4_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum))
612 << "Unexpected UDP/IPv4 checksum\n";
613 EXPECT_EQ(
614 kUdpV6Checksum,
615 ip_checksum_finish(ipv6_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum))
616 << "Unexpected UDP/IPv6 checksum\n";
617
618 EXPECT_EQ(kUdpV6Checksum,
619 ip_checksum_adjust(kUdpV4Checksum, ipv4_pseudo_sum, ipv6_pseudo_sum))
620 << "Adjust IPv4/UDP checksum to IPv6\n";
621 EXPECT_EQ(kUdpV4Checksum,
622 ip_checksum_adjust(kUdpV6Checksum, ipv6_pseudo_sum, ipv4_pseudo_sum))
623 << "Adjust IPv6/UDP checksum to IPv4\n";
624}
625
626TEST_F(ClatdTest, AdjustChecksum) {
627 struct checksum_data {
628 uint16_t checksum;
629 uint32_t old_hdr_sum;
630 uint32_t new_hdr_sum;
631 uint16_t result;
632 } DATA[] = {
633 { 0x1423, 0xb8ec, 0x2d757, 0xf5b5 },
634 { 0xf5b5, 0x2d757, 0xb8ec, 0x1423 },
635 { 0xdd2f, 0x5555, 0x3285, 0x0000 },
636 { 0x1215, 0x5560, 0x15560 + 20, 0x1200 },
637 { 0xd0c7, 0x3ad0, 0x2644b, 0xa74a },
638 };
Chih-Hung Hsieh05ff5082014-08-26 10:46:26 -0700639 unsigned i = 0;
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900640
641 for (i = 0; i < ARRAYSIZE(DATA); i++) {
642 struct checksum_data *data = DATA + i;
643 uint16_t result = ip_checksum_adjust(data->checksum, data->old_hdr_sum, data->new_hdr_sum);
644 EXPECT_EQ(result, data->result)
645 << "Incorrect checksum" << std::showbase << std::hex
646 << "\n Expected: " << data->result
647 << "\n Actual: " << result
648 << "\n checksum=" << data->checksum
649 << " old_sum=" << data->old_hdr_sum << " new_sum=" << data->new_hdr_sum << "\n";
650 }
651}
652
653TEST_F(ClatdTest, Translate) {
Brian Carlstromfcac4102014-02-24 20:03:01 -0800654 uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
655 uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900656 fix_udp_checksum(udp_ipv4);
657 fix_udp_checksum(udp_ipv6);
658 check_translated_packet(udp_ipv4, sizeof(udp_ipv4), udp_ipv6, sizeof(udp_ipv6),
659 "UDP/IPv4 -> UDP/IPv6 translation");
660 check_translated_packet(udp_ipv6, sizeof(udp_ipv6), udp_ipv4, sizeof(udp_ipv4),
661 "UDP/IPv6 -> UDP/IPv4 translation");
662
Brian Carlstromfcac4102014-02-24 20:03:01 -0800663 uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD };
664 uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD };
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900665 check_translated_packet(ipv4_ping, sizeof(ipv4_ping), ipv6_ping, sizeof(ipv6_ping),
666 "ICMP->ICMPv6 translation");
667 check_translated_packet(ipv6_ping, sizeof(ipv6_ping), ipv4_ping, sizeof(ipv4_ping),
668 "ICMPv6->ICMP translation");
669}
670
671TEST_F(ClatdTest, Fragmentation) {
Lorenzo Colittif3beefc2014-02-14 13:19:27 +0900672 check_fragment_translation(kIPv4Fragments, kIPv4FragLengths,
673 kIPv6Fragments, kIPv6FragLengths,
674 ARRAYSIZE(kIPv4Fragments), "IPv4->IPv6 fragment translation");
675
676 check_fragment_translation(kIPv6Fragments, kIPv6FragLengths,
677 kIPv4Fragments, kIPv4FragLengths,
678 ARRAYSIZE(kIPv6Fragments), "IPv6->IPv4 fragment translation");
679}