Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
| 27 | extern "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. |
| 38 | static const char kIPv4LocalAddr[] = "192.0.0.4"; |
| 39 | static const char kIPv6LocalAddr[] = "2001:db8:0:b11::464"; |
| 40 | static const char kIPv6PlatSubnet[] = "64:ff9b::"; |
| 41 | |
| 42 | // Test packet portions. Defined as macros because it's easy to concatenate them to make packets. |
| 43 | #define IPV4_HEADER(p, c1, c2) \ |
| 44 | 0x45, 0x00, 0, 41, /* Version=4, IHL=5, ToS=0x80, len=41 */ \ |
| 45 | 0x00, 0x00, 0x40, 0x00, /* ID=0x0000, flags=IP_DF, offset=0 */ \ |
| 46 | 55, (p), (c1), (c2), /* TTL=55, protocol=p, checksum=c1,c2 */ \ |
| 47 | 192, 0, 0, 4, /* Src=192.0.0.4 */ \ |
| 48 | 8, 8, 8, 8, /* Dst=8.8.8.8 */ |
| 49 | #define IPV4_UDP_HEADER IPV4_HEADER(IPPROTO_UDP, 0x73, 0xb0) |
| 50 | #define IPV4_ICMP_HEADER IPV4_HEADER(IPPROTO_ICMP, 0x73, 0xc0) |
| 51 | |
| 52 | #define IPV6_HEADER(p) \ |
| 53 | 0x60, 0x00, 0, 0, /* Version=6, tclass=0x00, flowlabel=0 */ \ |
| 54 | 0, 21, (p), 55, /* plen=11, nxthdr=p, hlim=55 */ \ |
| 55 | 0x20, 0x01, 0x0d, 0xb8, /* Src=2001:db8:0:b11::464 */ \ |
| 56 | 0x00, 0x00, 0x0b, 0x11, \ |
| 57 | 0x00, 0x00, 0x00, 0x00, \ |
| 58 | 0x00, 0x00, 0x04, 0x64, \ |
| 59 | 0x00, 0x64, 0xff, 0x9b, /* Dst=64:ff9b::8.8.8.8 */ \ |
| 60 | 0x00, 0x00, 0x00, 0x00, \ |
| 61 | 0x00, 0x00, 0x00, 0x00, \ |
| 62 | 0x08, 0x08, 0x08, 0x08, |
| 63 | #define IPV6_UDP_HEADER IPV6_HEADER(IPPROTO_UDP) |
| 64 | #define IPV6_ICMPV6_HEADER IPV6_HEADER(IPPROTO_ICMPV6) |
| 65 | |
| 66 | #define UDP_LEN 21 |
| 67 | #define UDP_HEADER \ |
| 68 | 0xc8, 0x8b, 0, 53, /* Port 51339->53 */ \ |
| 69 | 0x00, UDP_LEN, 0, 0, /* Length 21, checksum empty for now */ |
| 70 | |
| 71 | #define PAYLOAD 'H', 'e', 'l', 'l', 'o', ' ', 0x4e, 0xb8, 0x96, 0xe7, 0x95, 0x8c, 0x00 |
| 72 | |
| 73 | #define IPV4_PING \ |
| 74 | 0x08, 0x00, 0x88, 0xd0, /* Type 8, code 0, checksum 0x88d0 */ \ |
| 75 | 0xd0, 0x0d, 0x00, 0x03, /* ID=0xd00d, seq=3 */ |
| 76 | |
| 77 | #define IPV6_PING \ |
| 78 | 0x80, 0x00, 0xc3, 0x42, /* Type 128, code 0, checksum 0xc342 */ \ |
| 79 | 0xd0, 0x0d, 0x00, 0x03, /* ID=0xd00d, seq=3 */ |
| 80 | |
| 81 | // Macros to return pseudo-headers from packets. |
| 82 | #define IPV4_PSEUDOHEADER(ip, tlen) \ |
| 83 | ip[12], ip[13], ip[14], ip[15], /* Source address */ \ |
| 84 | ip[16], ip[17], ip[18], ip[19], /* Destination address */ \ |
| 85 | 0, ip[9], /* 0, protocol */ \ |
| 86 | ((tlen) >> 16) & 0xff, (tlen) & 0xff, /* Transport length */ |
| 87 | |
| 88 | #define IPV6_PSEUDOHEADER(ip6, protocol, tlen) \ |
| 89 | ip6[8], ip6[9], ip6[10], ip6[11], /* Source address */ \ |
| 90 | ip6[12], ip6[13], ip6[14], ip6[15], \ |
| 91 | ip6[16], ip6[17], ip6[18], ip6[19], \ |
| 92 | ip6[20], ip6[21], ip6[22], ip6[23], \ |
| 93 | ip6[24], ip6[25], ip6[26], ip6[27], /* Destination address */ \ |
| 94 | ip6[28], ip6[29], ip6[30], ip6[31], \ |
| 95 | ip6[32], ip6[33], ip6[34], ip6[35], \ |
| 96 | ip6[36], ip6[37], ip6[38], ip6[39], \ |
| 97 | ((tlen) >> 24) & 0xff, /* Transport length */ \ |
| 98 | ((tlen) >> 16) & 0xff, \ |
| 99 | ((tlen) >> 8) & 0xff, \ |
| 100 | (tlen) & 0xff, \ |
| 101 | 0, 0, 0, (protocol), |
| 102 | |
| 103 | // A fragmented DNS request. |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 104 | static const uint8_t kIPv4Frag1[] = { |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | }; |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 110 | static const uint8_t kIPv4Frag2[] = { |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | }; |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 116 | static const uint8_t kIPv4Frag3[] = { |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | }; |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 121 | static const uint8_t *kIPv4Fragments[] = { kIPv4Frag1, kIPv4Frag2, kIPv4Frag3 }; |
| 122 | static const size_t kIPv4FragLengths[] = { sizeof(kIPv4Frag1), sizeof(kIPv4Frag2), |
| 123 | sizeof(kIPv4Frag3) }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 124 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 125 | static const uint8_t kIPv6Frag1[] = { |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 135 | static const uint8_t kIPv6Frag2[] = { |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 145 | static const uint8_t kIPv6Frag3[] = { |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | }; |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 153 | static const uint8_t *kIPv6Fragments[] = { kIPv6Frag1, kIPv6Frag2, kIPv6Frag3 }; |
| 154 | static const size_t kIPv6FragLengths[] = { sizeof(kIPv6Frag1), sizeof(kIPv6Frag2), |
| 155 | sizeof(kIPv6Frag3) }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 156 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 157 | static const uint8_t kReassembledIPv4[] = { |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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. |
| 168 | static const uint32_t kUdpPartialChecksum = 0xd5c8; |
| 169 | static const uint32_t kPayloadPartialChecksum = 0x31e9c; |
| 170 | static const uint16_t kUdpV4Checksum = 0xd0c7; |
| 171 | static const uint16_t kUdpV6Checksum = 0xa74a; |
| 172 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 173 | uint8_t ip_version(const uint8_t *packet) { |
| 174 | uint8_t version = packet[0] >> 4; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 175 | return version; |
| 176 | } |
| 177 | |
| 178 | int 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 | |
| 183 | int 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 | |
| 192 | int ipv4_fragment_offset(struct iphdr *ip) { |
| 193 | return ntohs(ip->frag_off) & IP_OFFMASK; |
| 194 | } |
| 195 | |
| 196 | int ipv6_fragment_offset(struct ip6_frag *frag) { |
| 197 | return ntohs((frag->ip6f_offlg & IP6F_OFF_MASK) >> 3); |
| 198 | } |
| 199 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 200 | void check_packet(const uint8_t *packet, size_t len, const char *msg) { |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 285 | void reassemble_packet(const uint8_t **fragments, const size_t lengths[], int numpackets, |
| 286 | uint8_t *reassembled, size_t *reassembled_len, const char *msg) { |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 287 | struct iphdr *ip = NULL; |
| 288 | struct ip6_hdr *ip6 = NULL; |
Ben Cheng | 932614e | 2014-04-02 17:00:26 -0700 | [diff] [blame^] | 289 | size_t total_length, pos = 0; |
| 290 | uint8_t protocol = 0; |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 291 | uint8_t version = ip_version(fragments[0]); |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 292 | |
| 293 | for (int i = 0; i < numpackets; i++) { |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 294 | const uint8_t *packet = fragments[i]; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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; |
Ben Cheng | 932614e | 2014-04-02 17:00:26 -0700 | [diff] [blame^] | 348 | ASSERT_LT(total_length, *reassembled_len) << msg << ": Reassembly buffer too small\n"; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 373 | void check_data_matches(const uint8_t *expected, const uint8_t *actual, size_t len, const char *msg) { |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 395 | void fix_udp_checksum(uint8_t* packet) { |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 396 | uint32_t pseudo_checksum; |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 397 | uint8_t version = ip_version(packet); |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 421 | void do_translate_packet(const uint8_t *original, size_t original_len, uint8_t *out, size_t *outlen, |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 474 | void 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]; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 483 | void check_fragment_translation(const uint8_t *original[], const size_t original_lengths[], |
| 484 | const uint8_t *expected[], const size_t expected_lengths[], |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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. |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 495 | uint8_t reassembled[MAXMTU]; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 500 | uint8_t translated[MAXMTU]; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
| 506 | struct clat_config Global_Clatd_Config; |
| 507 | |
| 508 | class 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 | |
| 517 | TEST_F(ClatdTest, Sanitycheck) { |
| 518 | // Sanity checks the data. |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 519 | uint8_t v4_header[] = { IPV4_UDP_HEADER }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 520 | ASSERT_EQ(sizeof(struct iphdr), sizeof(v4_header)) << "Test IPv4 header: incorrect length\n"; |
| 521 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 522 | uint8_t v6_header[] = { IPV6_UDP_HEADER }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 523 | ASSERT_EQ(sizeof(struct ip6_hdr), sizeof(v6_header)) << "Test IPv6 header: incorrect length\n"; |
| 524 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 525 | uint8_t udp_header[] = { UDP_HEADER }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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; |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 530 | uint8_t v4_udp_packet[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 536 | uint8_t v6_udp_packet[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 542 | uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 543 | check_packet(ipv4_ping, sizeof(ipv4_ping), "IPv4 ping sanity check"); |
| 544 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 545 | uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 546 | check_packet(ipv6_ping, sizeof(ipv6_ping), "IPv6 ping sanity check"); |
| 547 | |
| 548 | // Sanity checks reassemble_packet. |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 549 | uint8_t reassembled[MAXMTU]; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
| 567 | TEST_F(ClatdTest, PseudoChecksum) { |
| 568 | uint32_t pseudo_checksum; |
| 569 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 570 | uint8_t v4_header[] = { IPV4_UDP_HEADER }; |
| 571 | uint8_t v4_pseudo_header[] = { IPV4_PSEUDOHEADER(v4_header, UDP_LEN) }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 577 | uint8_t v6_header[] = { IPV6_UDP_HEADER }; |
| 578 | uint8_t v6_pseudo_header[] = { IPV6_PSEUDOHEADER(v6_header, IPPROTO_UDP, UDP_LEN) }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
| 585 | TEST_F(ClatdTest, TransportChecksum) { |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 586 | uint8_t udphdr[] = { UDP_HEADER }; |
| 587 | uint8_t payload[] = { PAYLOAD }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 593 | uint8_t ip[] = { IPV4_UDP_HEADER }; |
| 594 | uint8_t ip6[] = { IPV6_UDP_HEADER }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Ben Cheng | 932614e | 2014-04-02 17:00:26 -0700 | [diff] [blame^] | 599 | EXPECT_EQ(0x3ad0U, ipv4_pseudo_sum) << "IPv4 pseudo-checksum sanity check\n"; |
| 600 | EXPECT_EQ(0x2644bU, ipv6_pseudo_sum) << "IPv6 pseudo-checksum sanity check\n"; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
| 618 | TEST_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 | |
| 645 | TEST_F(ClatdTest, Translate) { |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 646 | uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD }; |
| 647 | uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
Brian Carlstrom | fcac410 | 2014-02-24 20:03:01 -0800 | [diff] [blame] | 655 | uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD }; |
| 656 | uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD }; |
Lorenzo Colitti | f3beefc | 2014-02-14 13:19:27 +0900 | [diff] [blame] | 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 | |
| 663 | TEST_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 | } |