clatd_test.cpp revision fcac410fa15613873a07143ccd46470b869346a3
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  int total_length, pos = 0;
290  uint8_t protocol;
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, (int) *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_data tunnel = {
428    "clat", "clat4",
429    fds[0], fds[1]
430  };
431  struct tun_pi tun_header = { 0, 0 };
432
433  char foo[512];
434  snprintf(foo, sizeof(foo), "%s: Invalid original packet", msg);
435  check_packet(original, original_len, foo);
436
437  int read_fd;
438  uint16_t expected_proto;
439  int version = ip_version(original);
440  switch (version) {
441    case 4:
442      tun_header.proto = htons(ETH_P_IP);
443      expected_proto = htons(ETH_P_IPV6);
444      read_fd = fds[1];
445      break;
446    case 6:
447      tun_header.proto = htons(ETH_P_IPV6);
448      expected_proto = htons(ETH_P_IP);
449      read_fd = fds[0];
450      break;
451    default:
452      FAIL() << msg << ": Unsupported IP version " << version << "\n";
453      break;
454  }
455
456  translate_packet(&tunnel, &tun_header, original, original_len);
457
458  struct tun_pi new_tun_header;
459  struct iovec iov[] = {
460    { &new_tun_header, sizeof(new_tun_header) },
461    { out, *outlen }
462  };
463  int len = readv(read_fd, iov, 2);
464  if (len > (int) sizeof(new_tun_header)) {
465    ASSERT_LT((size_t) len, *outlen) << msg << ": Translated packet buffer too small\n";
466    EXPECT_EQ(expected_proto, new_tun_header.proto) << msg << "Unexpected tun proto\n";
467    *outlen = len - sizeof(new_tun_header);
468  } else {
469    FAIL() << msg << ": Packet was not translated";
470    *outlen = 0;
471  }
472}
473
474void check_translated_packet(const uint8_t *original, size_t original_len,
475                             const uint8_t *expected, size_t expected_len, const char *msg) {
476  uint8_t translated[MAXMTU];
477  size_t translated_len = sizeof(translated);
478  do_translate_packet(original, original_len, translated, &translated_len, msg);
479  EXPECT_EQ(expected_len, translated_len) << msg << ": Translated packet length incorrect\n";
480  check_data_matches(expected, translated, translated_len, msg);
481}
482
483void check_fragment_translation(const uint8_t *original[], const size_t original_lengths[],
484                                const uint8_t *expected[], const size_t expected_lengths[],
485                                int numfragments, const char *msg) {
486  for (int i = 0; i < numfragments; i++) {
487    // Check that each of the fragments translates as expected.
488    char frag_msg[512];
489    snprintf(frag_msg, sizeof(frag_msg), "%s: fragment #%d", msg, i + 1);
490    check_translated_packet(original[i], original_lengths[i],
491                            expected[i], expected_lengths[i], frag_msg);
492  }
493
494  // Sanity check that reassembling the original and translated fragments produces valid packets.
495  uint8_t reassembled[MAXMTU];
496  size_t reassembled_len = sizeof(reassembled);
497  reassemble_packet(original, original_lengths, numfragments, reassembled, &reassembled_len, msg);
498  check_packet(reassembled, reassembled_len, msg);
499
500  uint8_t translated[MAXMTU];
501  size_t translated_len = sizeof(translated);
502  do_translate_packet(reassembled, reassembled_len, translated, &translated_len, msg);
503  check_packet(translated, translated_len, msg);
504}
505
506struct clat_config Global_Clatd_Config;
507
508class ClatdTest : public ::testing::Test {
509 protected:
510  virtual void SetUp() {
511    inet_pton(AF_INET, kIPv4LocalAddr, &Global_Clatd_Config.ipv4_local_subnet);
512    inet_pton(AF_INET6, kIPv6PlatSubnet, &Global_Clatd_Config.plat_subnet);
513    inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet);
514  }
515};
516
517TEST_F(ClatdTest, Sanitycheck) {
518  // Sanity checks the data.
519  uint8_t v4_header[] = { IPV4_UDP_HEADER };
520  ASSERT_EQ(sizeof(struct iphdr), sizeof(v4_header)) << "Test IPv4 header: incorrect length\n";
521
522  uint8_t v6_header[] = { IPV6_UDP_HEADER };
523  ASSERT_EQ(sizeof(struct ip6_hdr), sizeof(v6_header)) << "Test IPv6 header: incorrect length\n";
524
525  uint8_t udp_header[] = { UDP_HEADER };
526  ASSERT_EQ(sizeof(struct udphdr), sizeof(udp_header)) << "Test UDP header: incorrect length\n";
527
528  // Sanity checks check_packet.
529  struct udphdr *udp;
530  uint8_t v4_udp_packet[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
531  udp = (struct udphdr *) (v4_udp_packet + sizeof(struct iphdr));
532  fix_udp_checksum(v4_udp_packet);
533  ASSERT_EQ(kUdpV4Checksum, udp->check) << "UDP/IPv4 packet checksum sanity check\n";
534  check_packet(v4_udp_packet, sizeof(v4_udp_packet), "UDP/IPv4 packet sanity check");
535
536  uint8_t v6_udp_packet[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
537  udp = (struct udphdr *) (v6_udp_packet + sizeof(struct ip6_hdr));
538  fix_udp_checksum(v6_udp_packet);
539  ASSERT_EQ(kUdpV6Checksum, udp->check) << "UDP/IPv6 packet checksum sanity check\n";
540  check_packet(v6_udp_packet, sizeof(v6_udp_packet), "UDP/IPv6 packet sanity check");
541
542  uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD };
543  check_packet(ipv4_ping, sizeof(ipv4_ping), "IPv4 ping sanity check");
544
545  uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD };
546  check_packet(ipv6_ping, sizeof(ipv6_ping), "IPv6 ping sanity check");
547
548  // Sanity checks reassemble_packet.
549  uint8_t reassembled[MAXMTU];
550  size_t total_length = sizeof(reassembled);
551  reassemble_packet(kIPv4Fragments, kIPv4FragLengths, ARRAYSIZE(kIPv4Fragments),
552                    reassembled, &total_length, "Reassembly sanity check");
553  check_packet(reassembled, total_length, "IPv4 Reassembled packet is valid");
554  ASSERT_EQ(sizeof(kReassembledIPv4), total_length) << "IPv4 reassembly sanity check: length\n";
555  ASSERT_TRUE(!is_ipv4_fragment((struct iphdr *) reassembled))
556      << "Sanity check: reassembled packet is a fragment!\n";
557  check_data_matches(kReassembledIPv4, reassembled, total_length, "IPv4 reassembly sanity check");
558
559  total_length = sizeof(reassembled);
560  reassemble_packet(kIPv6Fragments, kIPv6FragLengths, ARRAYSIZE(kIPv6Fragments),
561                    reassembled, &total_length, "IPv6 reassembly sanity check");
562  ASSERT_TRUE(!is_ipv6_fragment((struct ip6_hdr *) reassembled, total_length))
563      << "Sanity check: reassembled packet is a fragment!\n";
564  check_packet(reassembled, total_length, "IPv6 Reassembled packet is valid");
565}
566
567TEST_F(ClatdTest, PseudoChecksum) {
568  uint32_t pseudo_checksum;
569
570  uint8_t v4_header[] = { IPV4_UDP_HEADER };
571  uint8_t v4_pseudo_header[] = { IPV4_PSEUDOHEADER(v4_header, UDP_LEN) };
572  pseudo_checksum = ipv4_pseudo_header_checksum((struct iphdr *) v4_header, UDP_LEN);
573  EXPECT_EQ(ip_checksum_finish(pseudo_checksum),
574            ip_checksum(v4_pseudo_header, sizeof(v4_pseudo_header)))
575            << "ipv4_pseudo_header_checksum incorrect\n";
576
577  uint8_t v6_header[] = { IPV6_UDP_HEADER };
578  uint8_t v6_pseudo_header[] = { IPV6_PSEUDOHEADER(v6_header, IPPROTO_UDP, UDP_LEN) };
579  pseudo_checksum = ipv6_pseudo_header_checksum((struct ip6_hdr *) v6_header, UDP_LEN, IPPROTO_UDP);
580  EXPECT_EQ(ip_checksum_finish(pseudo_checksum),
581            ip_checksum(v6_pseudo_header, sizeof(v6_pseudo_header)))
582            << "ipv6_pseudo_header_checksum incorrect\n";
583}
584
585TEST_F(ClatdTest, TransportChecksum) {
586  uint8_t udphdr[] = { UDP_HEADER };
587  uint8_t payload[] = { PAYLOAD };
588  EXPECT_EQ(kUdpPartialChecksum, ip_checksum_add(0, udphdr, sizeof(udphdr)))
589            << "UDP partial checksum\n";
590  EXPECT_EQ(kPayloadPartialChecksum, ip_checksum_add(0, payload, sizeof(payload)))
591            << "Payload partial checksum\n";
592
593  uint8_t ip[] = { IPV4_UDP_HEADER };
594  uint8_t ip6[] = { IPV6_UDP_HEADER };
595  uint32_t ipv4_pseudo_sum = ipv4_pseudo_header_checksum((struct iphdr *) ip, UDP_LEN);
596  uint32_t ipv6_pseudo_sum = ipv6_pseudo_header_checksum((struct ip6_hdr *) ip6, UDP_LEN,
597                                                         IPPROTO_UDP);
598
599  EXPECT_EQ(0x3ad0, ipv4_pseudo_sum) << "IPv4 pseudo-checksum sanity check\n";
600  EXPECT_EQ(0x2644b, ipv6_pseudo_sum) << "IPv6 pseudo-checksum sanity check\n";
601  EXPECT_EQ(
602      kUdpV4Checksum,
603      ip_checksum_finish(ipv4_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum))
604      << "Unexpected UDP/IPv4 checksum\n";
605  EXPECT_EQ(
606      kUdpV6Checksum,
607      ip_checksum_finish(ipv6_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum))
608      << "Unexpected UDP/IPv6 checksum\n";
609
610  EXPECT_EQ(kUdpV6Checksum,
611      ip_checksum_adjust(kUdpV4Checksum, ipv4_pseudo_sum, ipv6_pseudo_sum))
612      << "Adjust IPv4/UDP checksum to IPv6\n";
613  EXPECT_EQ(kUdpV4Checksum,
614      ip_checksum_adjust(kUdpV6Checksum, ipv6_pseudo_sum, ipv4_pseudo_sum))
615      << "Adjust IPv6/UDP checksum to IPv4\n";
616}
617
618TEST_F(ClatdTest, AdjustChecksum) {
619  struct checksum_data {
620    uint16_t checksum;
621    uint32_t old_hdr_sum;
622    uint32_t new_hdr_sum;
623    uint16_t result;
624  } DATA[] = {
625    { 0x1423, 0xb8ec, 0x2d757, 0xf5b5 },
626    { 0xf5b5, 0x2d757, 0xb8ec, 0x1423 },
627    { 0xdd2f, 0x5555, 0x3285, 0x0000 },
628    { 0x1215, 0x5560, 0x15560 + 20, 0x1200 },
629    { 0xd0c7, 0x3ad0, 0x2644b, 0xa74a },
630  };
631  unsigned i, failed = 0;
632
633  for (i = 0; i < ARRAYSIZE(DATA); i++) {
634    struct checksum_data *data = DATA + i;
635    uint16_t result = ip_checksum_adjust(data->checksum, data->old_hdr_sum, data->new_hdr_sum);
636    EXPECT_EQ(result, data->result)
637        << "Incorrect checksum" << std::showbase << std::hex
638        << "\n  Expected: " << data->result
639        << "\n  Actual:   " << result
640        << "\n    checksum=" << data->checksum
641        << " old_sum=" << data->old_hdr_sum << " new_sum=" << data->new_hdr_sum << "\n";
642  }
643}
644
645TEST_F(ClatdTest, Translate) {
646  uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
647  uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
648  fix_udp_checksum(udp_ipv4);
649  fix_udp_checksum(udp_ipv6);
650  check_translated_packet(udp_ipv4, sizeof(udp_ipv4), udp_ipv6, sizeof(udp_ipv6),
651                          "UDP/IPv4 -> UDP/IPv6 translation");
652  check_translated_packet(udp_ipv6, sizeof(udp_ipv6), udp_ipv4, sizeof(udp_ipv4),
653                          "UDP/IPv6 -> UDP/IPv4 translation");
654
655  uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD };
656  uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD };
657  check_translated_packet(ipv4_ping, sizeof(ipv4_ping), ipv6_ping, sizeof(ipv6_ping),
658                          "ICMP->ICMPv6 translation");
659  check_translated_packet(ipv6_ping, sizeof(ipv6_ping), ipv4_ping, sizeof(ipv4_ping),
660                          "ICMPv6->ICMP translation");
661}
662
663TEST_F(ClatdTest, Fragmentation) {
664  int len, i;
665  check_fragment_translation(kIPv4Fragments, kIPv4FragLengths,
666                             kIPv6Fragments, kIPv6FragLengths,
667                             ARRAYSIZE(kIPv4Fragments), "IPv4->IPv6 fragment translation");
668
669  check_fragment_translation(kIPv6Fragments, kIPv6FragLengths,
670                             kIPv4Fragments, kIPv4FragLengths,
671                             ARRAYSIZE(kIPv6Fragments), "IPv6->IPv4 fragment translation");
672}
673