clatd_test.cpp revision 91d0f1bc6dd24e54ed3caef9b08525b332ab0adf
1/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * clatd_test.cpp - unit tests for clatd
17 */
18
19#include <iostream>
20
21#include <stdio.h>
22#include <arpa/inet.h>
23#include <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.
104static const uint8_t kIPv4Frag1[] = {
105    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};
110static const uint8_t kIPv4Frag2[] = {
111    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};
116static const uint8_t kIPv4Frag3[] = {
117    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};
121static const uint8_t *kIPv4Fragments[] = { kIPv4Frag1, kIPv4Frag2, kIPv4Frag3 };
122static const size_t kIPv4FragLengths[] = { sizeof(kIPv4Frag1), sizeof(kIPv4Frag2),
123                                           sizeof(kIPv4Frag3) };
124
125static const uint8_t kIPv6Frag1[] = {
126    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
135static const uint8_t kIPv6Frag2[] = {
136    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
145static const uint8_t kIPv6Frag3[] = {
146    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};
153static const uint8_t *kIPv6Fragments[] = { kIPv6Frag1, kIPv6Frag2, kIPv6Frag3 };
154static const size_t kIPv6FragLengths[] = { sizeof(kIPv6Frag1), sizeof(kIPv6Frag2),
155                                           sizeof(kIPv6Frag3) };
156
157static const uint8_t kReassembledIPv4[] = {
158    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
173uint8_t ip_version(const uint8_t *packet) {
174  uint8_t version = packet[0] >> 4;
175  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
200void check_packet(const uint8_t *packet, size_t len, const char *msg) {
201  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
285void reassemble_packet(const uint8_t **fragments, const size_t lengths[], int numpackets,
286                       uint8_t *reassembled, size_t *reassembled_len, const char *msg) {
287  struct iphdr *ip = NULL;
288  struct ip6_hdr *ip6 = NULL;
289  size_t  total_length, pos = 0;
290  uint8_t protocol = 0;
291  uint8_t version = ip_version(fragments[0]);
292
293  for (int i = 0; i < numpackets; i++) {
294    const uint8_t *packet = fragments[i];
295    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;
348    ASSERT_LT(total_length, *reassembled_len) << msg << ": Reassembly buffer too small\n";
349    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
373void check_data_matches(const uint8_t *expected, const uint8_t *actual, size_t len, const char *msg) {
374  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
395void fix_udp_checksum(uint8_t* packet) {
396  uint32_t pseudo_checksum;
397  uint8_t version = ip_version(packet);
398  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
421void do_translate_packet(const uint8_t *original, size_t original_len, uint8_t *out, size_t *outlen,
422                         const char *msg) {
423  int fds[2];
424  if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, fds)) {
425    abort();
426  }
427  struct tun_pi tun_header = { 0, 0 };
428
429  char foo[512];
430  snprintf(foo, sizeof(foo), "%s: Invalid original packet", msg);
431  check_packet(original, original_len, foo);
432
433  int read_fd, write_fd;
434  uint16_t expected_proto;
435  int version = ip_version(original);
436  switch (version) {
437    case 4:
438      tun_header.proto = htons(ETH_P_IP);
439      expected_proto = htons(ETH_P_IPV6);
440      read_fd = fds[1];
441      write_fd = fds[0];
442      break;
443    case 6:
444      tun_header.proto = htons(ETH_P_IPV6);
445      expected_proto = htons(ETH_P_IP);
446      read_fd = fds[0];
447      write_fd = fds[1];
448      break;
449    default:
450      FAIL() << msg << ": Unsupported IP version " << version << "\n";
451      break;
452  }
453
454  translate_packet(write_fd, (version == 4), original, original_len);
455
456  struct tun_pi new_tun_header;
457  struct iovec iov[] = {
458    { &new_tun_header, sizeof(new_tun_header) },
459    { out, *outlen }
460  };
461  int len = readv(read_fd, iov, 2);
462  if (len > (int) sizeof(new_tun_header)) {
463    ASSERT_LT((size_t) len, *outlen) << msg << ": Translated packet buffer too small\n";
464    EXPECT_EQ(expected_proto, new_tun_header.proto) << msg << "Unexpected tun proto\n";
465    *outlen = len - sizeof(new_tun_header);
466  } else {
467    FAIL() << msg << ": Packet was not translated";
468    *outlen = 0;
469  }
470}
471
472void check_translated_packet(const uint8_t *original, size_t original_len,
473                             const uint8_t *expected, size_t expected_len, const char *msg) {
474  uint8_t translated[MAXMTU];
475  size_t translated_len = sizeof(translated);
476  do_translate_packet(original, original_len, translated, &translated_len, msg);
477  EXPECT_EQ(expected_len, translated_len) << msg << ": Translated packet length incorrect\n";
478  check_data_matches(expected, translated, translated_len, msg);
479}
480
481void check_fragment_translation(const uint8_t *original[], const size_t original_lengths[],
482                                const uint8_t *expected[], const size_t expected_lengths[],
483                                int numfragments, const char *msg) {
484  for (int i = 0; i < numfragments; i++) {
485    // Check that each of the fragments translates as expected.
486    char frag_msg[512];
487    snprintf(frag_msg, sizeof(frag_msg), "%s: fragment #%d", msg, i + 1);
488    check_translated_packet(original[i], original_lengths[i],
489                            expected[i], expected_lengths[i], frag_msg);
490  }
491
492  // Sanity check that reassembling the original and translated fragments produces valid packets.
493  uint8_t reassembled[MAXMTU];
494  size_t reassembled_len = sizeof(reassembled);
495  reassemble_packet(original, original_lengths, numfragments, reassembled, &reassembled_len, msg);
496  check_packet(reassembled, reassembled_len, msg);
497
498  uint8_t translated[MAXMTU];
499  size_t translated_len = sizeof(translated);
500  do_translate_packet(reassembled, reassembled_len, translated, &translated_len, msg);
501  check_packet(translated, translated_len, msg);
502}
503
504struct clat_config Global_Clatd_Config;
505
506class ClatdTest : public ::testing::Test {
507 protected:
508  virtual void SetUp() {
509    inet_pton(AF_INET, kIPv4LocalAddr, &Global_Clatd_Config.ipv4_local_subnet);
510    inet_pton(AF_INET6, kIPv6PlatSubnet, &Global_Clatd_Config.plat_subnet);
511    inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet);
512  }
513};
514
515TEST_F(ClatdTest, Sanitycheck) {
516  // Sanity checks the data.
517  uint8_t v4_header[] = { IPV4_UDP_HEADER };
518  ASSERT_EQ(sizeof(struct iphdr), sizeof(v4_header)) << "Test IPv4 header: incorrect length\n";
519
520  uint8_t v6_header[] = { IPV6_UDP_HEADER };
521  ASSERT_EQ(sizeof(struct ip6_hdr), sizeof(v6_header)) << "Test IPv6 header: incorrect length\n";
522
523  uint8_t udp_header[] = { UDP_HEADER };
524  ASSERT_EQ(sizeof(struct udphdr), sizeof(udp_header)) << "Test UDP header: incorrect length\n";
525
526  // Sanity checks check_packet.
527  struct udphdr *udp;
528  uint8_t v4_udp_packet[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
529  udp = (struct udphdr *) (v4_udp_packet + sizeof(struct iphdr));
530  fix_udp_checksum(v4_udp_packet);
531  ASSERT_EQ(kUdpV4Checksum, udp->check) << "UDP/IPv4 packet checksum sanity check\n";
532  check_packet(v4_udp_packet, sizeof(v4_udp_packet), "UDP/IPv4 packet sanity check");
533
534  uint8_t v6_udp_packet[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
535  udp = (struct udphdr *) (v6_udp_packet + sizeof(struct ip6_hdr));
536  fix_udp_checksum(v6_udp_packet);
537  ASSERT_EQ(kUdpV6Checksum, udp->check) << "UDP/IPv6 packet checksum sanity check\n";
538  check_packet(v6_udp_packet, sizeof(v6_udp_packet), "UDP/IPv6 packet sanity check");
539
540  uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD };
541  check_packet(ipv4_ping, sizeof(ipv4_ping), "IPv4 ping sanity check");
542
543  uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD };
544  check_packet(ipv6_ping, sizeof(ipv6_ping), "IPv6 ping sanity check");
545
546  // Sanity checks reassemble_packet.
547  uint8_t reassembled[MAXMTU];
548  size_t total_length = sizeof(reassembled);
549  reassemble_packet(kIPv4Fragments, kIPv4FragLengths, ARRAYSIZE(kIPv4Fragments),
550                    reassembled, &total_length, "Reassembly sanity check");
551  check_packet(reassembled, total_length, "IPv4 Reassembled packet is valid");
552  ASSERT_EQ(sizeof(kReassembledIPv4), total_length) << "IPv4 reassembly sanity check: length\n";
553  ASSERT_TRUE(!is_ipv4_fragment((struct iphdr *) reassembled))
554      << "Sanity check: reassembled packet is a fragment!\n";
555  check_data_matches(kReassembledIPv4, reassembled, total_length, "IPv4 reassembly sanity check");
556
557  total_length = sizeof(reassembled);
558  reassemble_packet(kIPv6Fragments, kIPv6FragLengths, ARRAYSIZE(kIPv6Fragments),
559                    reassembled, &total_length, "IPv6 reassembly sanity check");
560  ASSERT_TRUE(!is_ipv6_fragment((struct ip6_hdr *) reassembled, total_length))
561      << "Sanity check: reassembled packet is a fragment!\n";
562  check_packet(reassembled, total_length, "IPv6 Reassembled packet is valid");
563}
564
565TEST_F(ClatdTest, PseudoChecksum) {
566  uint32_t pseudo_checksum;
567
568  uint8_t v4_header[] = { IPV4_UDP_HEADER };
569  uint8_t v4_pseudo_header[] = { IPV4_PSEUDOHEADER(v4_header, UDP_LEN) };
570  pseudo_checksum = ipv4_pseudo_header_checksum((struct iphdr *) v4_header, UDP_LEN);
571  EXPECT_EQ(ip_checksum_finish(pseudo_checksum),
572            ip_checksum(v4_pseudo_header, sizeof(v4_pseudo_header)))
573            << "ipv4_pseudo_header_checksum incorrect\n";
574
575  uint8_t v6_header[] = { IPV6_UDP_HEADER };
576  uint8_t v6_pseudo_header[] = { IPV6_PSEUDOHEADER(v6_header, IPPROTO_UDP, UDP_LEN) };
577  pseudo_checksum = ipv6_pseudo_header_checksum((struct ip6_hdr *) v6_header, UDP_LEN, IPPROTO_UDP);
578  EXPECT_EQ(ip_checksum_finish(pseudo_checksum),
579            ip_checksum(v6_pseudo_header, sizeof(v6_pseudo_header)))
580            << "ipv6_pseudo_header_checksum incorrect\n";
581}
582
583TEST_F(ClatdTest, TransportChecksum) {
584  uint8_t udphdr[] = { UDP_HEADER };
585  uint8_t payload[] = { PAYLOAD };
586  EXPECT_EQ(kUdpPartialChecksum, ip_checksum_add(0, udphdr, sizeof(udphdr)))
587            << "UDP partial checksum\n";
588  EXPECT_EQ(kPayloadPartialChecksum, ip_checksum_add(0, payload, sizeof(payload)))
589            << "Payload partial checksum\n";
590
591  uint8_t ip[] = { IPV4_UDP_HEADER };
592  uint8_t ip6[] = { IPV6_UDP_HEADER };
593  uint32_t ipv4_pseudo_sum = ipv4_pseudo_header_checksum((struct iphdr *) ip, UDP_LEN);
594  uint32_t ipv6_pseudo_sum = ipv6_pseudo_header_checksum((struct ip6_hdr *) ip6, UDP_LEN,
595                                                         IPPROTO_UDP);
596
597  EXPECT_EQ(0x3ad0U, ipv4_pseudo_sum) << "IPv4 pseudo-checksum sanity check\n";
598  EXPECT_EQ(0x2644bU, ipv6_pseudo_sum) << "IPv6 pseudo-checksum sanity check\n";
599  EXPECT_EQ(
600      kUdpV4Checksum,
601      ip_checksum_finish(ipv4_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum))
602      << "Unexpected UDP/IPv4 checksum\n";
603  EXPECT_EQ(
604      kUdpV6Checksum,
605      ip_checksum_finish(ipv6_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum))
606      << "Unexpected UDP/IPv6 checksum\n";
607
608  EXPECT_EQ(kUdpV6Checksum,
609      ip_checksum_adjust(kUdpV4Checksum, ipv4_pseudo_sum, ipv6_pseudo_sum))
610      << "Adjust IPv4/UDP checksum to IPv6\n";
611  EXPECT_EQ(kUdpV4Checksum,
612      ip_checksum_adjust(kUdpV6Checksum, ipv6_pseudo_sum, ipv4_pseudo_sum))
613      << "Adjust IPv6/UDP checksum to IPv4\n";
614}
615
616TEST_F(ClatdTest, AdjustChecksum) {
617  struct checksum_data {
618    uint16_t checksum;
619    uint32_t old_hdr_sum;
620    uint32_t new_hdr_sum;
621    uint16_t result;
622  } DATA[] = {
623    { 0x1423, 0xb8ec, 0x2d757, 0xf5b5 },
624    { 0xf5b5, 0x2d757, 0xb8ec, 0x1423 },
625    { 0xdd2f, 0x5555, 0x3285, 0x0000 },
626    { 0x1215, 0x5560, 0x15560 + 20, 0x1200 },
627    { 0xd0c7, 0x3ad0, 0x2644b, 0xa74a },
628  };
629  unsigned i, failed = 0;
630
631  for (i = 0; i < ARRAYSIZE(DATA); i++) {
632    struct checksum_data *data = DATA + i;
633    uint16_t result = ip_checksum_adjust(data->checksum, data->old_hdr_sum, data->new_hdr_sum);
634    EXPECT_EQ(result, data->result)
635        << "Incorrect checksum" << std::showbase << std::hex
636        << "\n  Expected: " << data->result
637        << "\n  Actual:   " << result
638        << "\n    checksum=" << data->checksum
639        << " old_sum=" << data->old_hdr_sum << " new_sum=" << data->new_hdr_sum << "\n";
640  }
641}
642
643TEST_F(ClatdTest, Translate) {
644  uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
645  uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
646  fix_udp_checksum(udp_ipv4);
647  fix_udp_checksum(udp_ipv6);
648  check_translated_packet(udp_ipv4, sizeof(udp_ipv4), udp_ipv6, sizeof(udp_ipv6),
649                          "UDP/IPv4 -> UDP/IPv6 translation");
650  check_translated_packet(udp_ipv6, sizeof(udp_ipv6), udp_ipv4, sizeof(udp_ipv4),
651                          "UDP/IPv6 -> UDP/IPv4 translation");
652
653  uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD };
654  uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD };
655  check_translated_packet(ipv4_ping, sizeof(ipv4_ping), ipv6_ping, sizeof(ipv6_ping),
656                          "ICMP->ICMPv6 translation");
657  check_translated_packet(ipv6_ping, sizeof(ipv6_ping), ipv4_ping, sizeof(ipv4_ping),
658                          "ICMPv6->ICMP translation");
659}
660
661TEST_F(ClatdTest, Fragmentation) {
662  int len, i;
663  check_fragment_translation(kIPv4Fragments, kIPv4FragLengths,
664                             kIPv6Fragments, kIPv6FragLengths,
665                             ARRAYSIZE(kIPv4Fragments), "IPv4->IPv6 fragment translation");
666
667  check_fragment_translation(kIPv6Fragments, kIPv6FragLengths,
668                             kIPv4Fragments, kIPv4FragLengths,
669                             ARRAYSIZE(kIPv6Fragments), "IPv6->IPv4 fragment translation");
670}
671