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