1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2015-2019 Yandex LLC 5 * Copyright (c) 2015-2019 Andrey V. Elsukov <ae@FreeBSD.org> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_ipstealth.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/counter.h> 37 #include <sys/errno.h> 38 #include <sys/kernel.h> 39 #include <sys/lock.h> 40 #include <sys/mbuf.h> 41 #include <sys/module.h> 42 #include <sys/rmlock.h> 43 #include <sys/rwlock.h> 44 #include <sys/socket.h> 45 #include <sys/queue.h> 46 47 #include <net/if.h> 48 #include <net/if_var.h> 49 #include <net/if_pflog.h> 50 #include <net/pfil.h> 51 #include <net/netisr.h> 52 #include <net/route.h> 53 #include <net/route/nhop.h> 54 55 #include <netinet/in.h> 56 #include <netinet/in_fib.h> 57 #include <netinet/in_var.h> 58 #include <netinet/ip.h> 59 #include <netinet/ip_var.h> 60 #include <netinet/ip_fw.h> 61 #include <netinet/ip6.h> 62 #include <netinet/icmp6.h> 63 #include <netinet/ip_icmp.h> 64 #include <netinet/tcp.h> 65 #include <netinet/udp.h> 66 #include <netinet6/in6_var.h> 67 #include <netinet6/in6_fib.h> 68 #include <netinet6/ip6_var.h> 69 #include <netinet6/ip_fw_nat64.h> 70 71 #include <netpfil/pf/pf.h> 72 #include <netpfil/ipfw/ip_fw_private.h> 73 #include <machine/in_cksum.h> 74 75 #include "ip_fw_nat64.h" 76 #include "nat64_translate.h" 77 78 typedef int (*nat64_output_t)(struct ifnet *, struct mbuf *, 79 struct sockaddr *, struct nat64_counters *, void *); 80 typedef int (*nat64_output_one_t)(struct mbuf *, struct nat64_counters *, 81 void *); 82 83 static struct nhop_object *nat64_find_route4(struct sockaddr_in *, 84 struct mbuf *); 85 static struct nhop_object *nat64_find_route6(struct sockaddr_in6 *, 86 struct mbuf *); 87 static int nat64_output_one(struct mbuf *, struct nat64_counters *, void *); 88 static int nat64_output(struct ifnet *, struct mbuf *, struct sockaddr *, 89 struct nat64_counters *, void *); 90 static int nat64_direct_output_one(struct mbuf *, struct nat64_counters *, 91 void *); 92 static int nat64_direct_output(struct ifnet *, struct mbuf *, 93 struct sockaddr *, struct nat64_counters *, void *); 94 95 struct nat64_methods { 96 nat64_output_t output; 97 nat64_output_one_t output_one; 98 }; 99 static const struct nat64_methods nat64_netisr = { 100 .output = nat64_output, 101 .output_one = nat64_output_one 102 }; 103 static const struct nat64_methods nat64_direct = { 104 .output = nat64_direct_output, 105 .output_one = nat64_direct_output_one 106 }; 107 108 /* These variables should be initialized explicitly on module loading */ 109 VNET_DEFINE_STATIC(const struct nat64_methods *, nat64out); 110 VNET_DEFINE_STATIC(const int *, nat64ipstealth); 111 VNET_DEFINE_STATIC(const int *, nat64ip6stealth); 112 #define V_nat64out VNET(nat64out) 113 #define V_nat64ipstealth VNET(nat64ipstealth) 114 #define V_nat64ip6stealth VNET(nat64ip6stealth) 115 116 static const int stealth_on = 1; 117 #ifndef IPSTEALTH 118 static const int stealth_off = 0; 119 #endif 120 121 void 122 nat64_set_output_method(int direct) 123 { 124 125 if (direct != 0) { 126 V_nat64out = &nat64_direct; 127 #ifdef IPSTEALTH 128 /* Honor corresponding variables, if IPSTEALTH is defined */ 129 V_nat64ipstealth = &V_ipstealth; 130 V_nat64ip6stealth = &V_ip6stealth; 131 #else 132 /* otherwise we need to decrement HLIM/TTL for direct case */ 133 V_nat64ipstealth = V_nat64ip6stealth = &stealth_off; 134 #endif 135 } else { 136 V_nat64out = &nat64_netisr; 137 /* Leave TTL/HLIM decrementing to forwarding code */ 138 V_nat64ipstealth = V_nat64ip6stealth = &stealth_on; 139 } 140 } 141 142 int 143 nat64_get_output_method(void) 144 { 145 146 return (V_nat64out == &nat64_direct ? 1: 0); 147 } 148 149 static void 150 nat64_log(struct pfloghdr *logdata, struct mbuf *m, sa_family_t family) 151 { 152 153 logdata->dir = PF_OUT; 154 logdata->af = family; 155 ipfw_bpf_mtap2(logdata, PFLOG_HDRLEN, m); 156 } 157 158 static int 159 nat64_direct_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 160 struct nat64_counters *stats, void *logdata) 161 { 162 int error; 163 164 if (logdata != NULL) 165 nat64_log(logdata, m, dst->sa_family); 166 error = (*ifp->if_output)(ifp, m, dst, NULL); 167 if (error != 0) 168 NAT64STAT_INC(stats, oerrors); 169 return (error); 170 } 171 172 static int 173 nat64_direct_output_one(struct mbuf *m, struct nat64_counters *stats, 174 void *logdata) 175 { 176 struct nhop_object *nh4 = NULL; 177 struct nhop_object *nh6 = NULL; 178 struct sockaddr_in6 dst6; 179 struct sockaddr_in dst4; 180 struct sockaddr *dst; 181 struct ip6_hdr *ip6; 182 struct ip *ip4; 183 struct ifnet *ifp; 184 int error; 185 186 ip4 = mtod(m, struct ip *); 187 error = 0; 188 switch (ip4->ip_v) { 189 case IPVERSION: 190 dst4.sin_addr = ip4->ip_dst; 191 nh4 = nat64_find_route4(&dst4, m); 192 if (nh4 == NULL) { 193 NAT64STAT_INC(stats, noroute4); 194 error = EHOSTUNREACH; 195 } else { 196 ifp = nh4->nh_ifp; 197 dst = (struct sockaddr *)&dst4; 198 } 199 break; 200 case (IPV6_VERSION >> 4): 201 ip6 = mtod(m, struct ip6_hdr *); 202 dst6.sin6_addr = ip6->ip6_dst; 203 nh6 = nat64_find_route6(&dst6, m); 204 if (nh6 == NULL) { 205 NAT64STAT_INC(stats, noroute6); 206 error = EHOSTUNREACH; 207 } else { 208 ifp = nh6->nh_ifp; 209 dst = (struct sockaddr *)&dst6; 210 } 211 break; 212 default: 213 m_freem(m); 214 NAT64STAT_INC(stats, dropped); 215 DPRINTF(DP_DROPS, "dropped due to unknown IP version"); 216 return (EAFNOSUPPORT); 217 } 218 if (error != 0) { 219 m_freem(m); 220 return (EHOSTUNREACH); 221 } 222 if (logdata != NULL) 223 nat64_log(logdata, m, dst->sa_family); 224 error = (*ifp->if_output)(ifp, m, dst, NULL); 225 if (error != 0) 226 NAT64STAT_INC(stats, oerrors); 227 return (error); 228 } 229 230 static int 231 nat64_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 232 struct nat64_counters *stats, void *logdata) 233 { 234 struct ip *ip4; 235 int ret, af; 236 237 ip4 = mtod(m, struct ip *); 238 switch (ip4->ip_v) { 239 case IPVERSION: 240 af = AF_INET; 241 ret = NETISR_IP; 242 break; 243 case (IPV6_VERSION >> 4): 244 af = AF_INET6; 245 ret = NETISR_IPV6; 246 break; 247 default: 248 m_freem(m); 249 NAT64STAT_INC(stats, dropped); 250 DPRINTF(DP_DROPS, "unknown IP version"); 251 return (EAFNOSUPPORT); 252 } 253 if (logdata != NULL) 254 nat64_log(logdata, m, af); 255 if (m->m_pkthdr.rcvif == NULL) 256 m->m_pkthdr.rcvif = V_loif; 257 ret = netisr_queue(ret, m); 258 if (ret != 0) 259 NAT64STAT_INC(stats, oerrors); 260 return (ret); 261 } 262 263 static int 264 nat64_output_one(struct mbuf *m, struct nat64_counters *stats, void *logdata) 265 { 266 267 return (nat64_output(NULL, m, NULL, stats, logdata)); 268 } 269 270 /* 271 * Check the given IPv6 prefix and length according to RFC6052: 272 * The prefixes can only have one of the following lengths: 273 * 32, 40, 48, 56, 64, or 96 (The Well-Known Prefix is 96 bits long). 274 * Returns zero on success, otherwise EINVAL. 275 */ 276 int 277 nat64_check_prefixlen(int length) 278 { 279 280 switch (length) { 281 case 32: 282 case 40: 283 case 48: 284 case 56: 285 case 64: 286 case 96: 287 return (0); 288 } 289 return (EINVAL); 290 } 291 292 int 293 nat64_check_prefix6(const struct in6_addr *prefix, int length) 294 { 295 296 if (nat64_check_prefixlen(length) != 0) 297 return (EINVAL); 298 299 /* Well-known prefix has 96 prefix length */ 300 if (IN6_IS_ADDR_WKPFX(prefix) && length != 96) 301 return (EINVAL); 302 303 /* Bits 64 to 71 must be set to zero */ 304 if (prefix->__u6_addr.__u6_addr8[8] != 0) 305 return (EINVAL); 306 307 /* Some extra checks */ 308 if (IN6_IS_ADDR_MULTICAST(prefix) || 309 IN6_IS_ADDR_UNSPECIFIED(prefix) || 310 IN6_IS_ADDR_LOOPBACK(prefix)) 311 return (EINVAL); 312 return (0); 313 } 314 315 int 316 nat64_check_private_ip4(const struct nat64_config *cfg, in_addr_t ia) 317 { 318 319 if (cfg->flags & NAT64_ALLOW_PRIVATE) 320 return (0); 321 322 /* WKPFX must not be used to represent non-global IPv4 addresses */ 323 if (cfg->flags & NAT64_WKPFX) { 324 /* IN_PRIVATE */ 325 if ((ia & htonl(0xff000000)) == htonl(0x0a000000) || 326 (ia & htonl(0xfff00000)) == htonl(0xac100000) || 327 (ia & htonl(0xffff0000)) == htonl(0xc0a80000)) 328 return (1); 329 /* 330 * RFC 5735: 331 * 192.0.0.0/24 - reserved for IETF protocol assignments 332 * 192.88.99.0/24 - for use as 6to4 relay anycast addresses 333 * 198.18.0.0/15 - for use in benchmark tests 334 * 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 - for use 335 * in documentation and example code 336 */ 337 if ((ia & htonl(0xffffff00)) == htonl(0xc0000000) || 338 (ia & htonl(0xffffff00)) == htonl(0xc0586300) || 339 (ia & htonl(0xfffffe00)) == htonl(0xc6120000) || 340 (ia & htonl(0xffffff00)) == htonl(0xc0000200) || 341 (ia & htonl(0xfffffe00)) == htonl(0xc6336400) || 342 (ia & htonl(0xffffff00)) == htonl(0xcb007100)) 343 return (1); 344 } 345 return (0); 346 } 347 348 /* 349 * Embed @ia IPv4 address into @ip6 IPv6 address. 350 * Place to embedding determined from prefix length @plen. 351 */ 352 void 353 nat64_embed_ip4(struct in6_addr *ip6, int plen, in_addr_t ia) 354 { 355 356 switch (plen) { 357 case 32: 358 case 96: 359 ip6->s6_addr32[plen / 32] = ia; 360 break; 361 case 40: 362 case 48: 363 case 56: 364 /* 365 * Preserve prefix bits. 366 * Since suffix bits should be zero and reserved for future 367 * use, we just overwrite the whole word, where they are. 368 */ 369 ip6->s6_addr32[1] &= 0xffffffff << (32 - plen % 32); 370 #if BYTE_ORDER == BIG_ENDIAN 371 ip6->s6_addr32[1] |= ia >> (plen % 32); 372 ip6->s6_addr32[2] = ia << (24 - plen % 32); 373 #elif BYTE_ORDER == LITTLE_ENDIAN 374 ip6->s6_addr32[1] |= ia << (plen % 32); 375 ip6->s6_addr32[2] = ia >> (24 - plen % 32); 376 #endif 377 break; 378 case 64: 379 #if BYTE_ORDER == BIG_ENDIAN 380 ip6->s6_addr32[2] = ia >> 8; 381 ip6->s6_addr32[3] = ia << 24; 382 #elif BYTE_ORDER == LITTLE_ENDIAN 383 ip6->s6_addr32[2] = ia << 8; 384 ip6->s6_addr32[3] = ia >> 24; 385 #endif 386 break; 387 default: 388 panic("Wrong plen: %d", plen); 389 }; 390 /* 391 * Bits 64 to 71 of the address are reserved for compatibility 392 * with the host identifier format defined in the IPv6 addressing 393 * architecture [RFC4291]. These bits MUST be set to zero. 394 */ 395 ip6->s6_addr8[8] = 0; 396 } 397 398 in_addr_t 399 nat64_extract_ip4(const struct in6_addr *ip6, int plen) 400 { 401 in_addr_t ia; 402 403 /* 404 * According to RFC 6052 p2.2: 405 * IPv4-embedded IPv6 addresses are composed of a variable-length 406 * prefix, the embedded IPv4 address, and a variable length suffix. 407 * The suffix bits are reserved for future extensions and SHOULD 408 * be set to zero. 409 */ 410 switch (plen) { 411 case 32: 412 if (ip6->s6_addr32[3] != 0 || ip6->s6_addr32[2] != 0) 413 goto badip6; 414 break; 415 case 40: 416 if (ip6->s6_addr32[3] != 0 || 417 (ip6->s6_addr32[2] & htonl(0xff00ffff)) != 0) 418 goto badip6; 419 break; 420 case 48: 421 if (ip6->s6_addr32[3] != 0 || 422 (ip6->s6_addr32[2] & htonl(0xff0000ff)) != 0) 423 goto badip6; 424 break; 425 case 56: 426 if (ip6->s6_addr32[3] != 0 || ip6->s6_addr8[8] != 0) 427 goto badip6; 428 break; 429 case 64: 430 if (ip6->s6_addr8[8] != 0 || 431 (ip6->s6_addr32[3] & htonl(0x00ffffff)) != 0) 432 goto badip6; 433 }; 434 switch (plen) { 435 case 32: 436 case 96: 437 ia = ip6->s6_addr32[plen / 32]; 438 break; 439 case 40: 440 case 48: 441 case 56: 442 #if BYTE_ORDER == BIG_ENDIAN 443 ia = (ip6->s6_addr32[1] << (plen % 32)) | 444 (ip6->s6_addr32[2] >> (24 - plen % 32)); 445 #elif BYTE_ORDER == LITTLE_ENDIAN 446 ia = (ip6->s6_addr32[1] >> (plen % 32)) | 447 (ip6->s6_addr32[2] << (24 - plen % 32)); 448 #endif 449 break; 450 case 64: 451 #if BYTE_ORDER == BIG_ENDIAN 452 ia = (ip6->s6_addr32[2] << 8) | (ip6->s6_addr32[3] >> 24); 453 #elif BYTE_ORDER == LITTLE_ENDIAN 454 ia = (ip6->s6_addr32[2] >> 8) | (ip6->s6_addr32[3] << 24); 455 #endif 456 break; 457 default: 458 return (0); 459 }; 460 if (nat64_check_ip4(ia) == 0) 461 return (ia); 462 463 DPRINTF(DP_GENERIC | DP_DROPS, 464 "invalid destination address: %08x", ia); 465 return (0); 466 badip6: 467 DPRINTF(DP_GENERIC | DP_DROPS, "invalid IPv4-embedded IPv6 address"); 468 return (0); 469 } 470 471 /* 472 * According to RFC 1624 the equation for incremental checksum update is: 473 * HC' = ~(~HC + ~m + m') -- [Eqn. 3] 474 * HC' = HC - ~m - m' -- [Eqn. 4] 475 * So, when we are replacing IPv4 addresses to IPv6, we 476 * can assume, that new bytes previously were zeros, and vise versa - 477 * when we replacing IPv6 addresses to IPv4, now unused bytes become 478 * zeros. The payload length in pseudo header has bigger size, but one 479 * half of it should be zero. Using the equation 4 we get: 480 * HC' = HC - (~m0 + m0') -- m0 is first changed word 481 * HC' = (HC - (~m0 + m0')) - (~m1 + m1') -- m1 is second changed word 482 * HC' = HC - ~m0 - m0' - ~m1 - m1' - ... = 483 * = HC - sum(~m[i] + m'[i]) 484 * 485 * The function result should be used as follows: 486 * IPv6 to IPv4: HC' = cksum_add(HC, result) 487 * IPv4 to IPv6: HC' = cksum_add(HC, ~result) 488 */ 489 static uint16_t 490 nat64_cksum_convert(struct ip6_hdr *ip6, struct ip *ip) 491 { 492 uint32_t sum; 493 uint16_t *p; 494 495 sum = ~ip->ip_src.s_addr >> 16; 496 sum += ~ip->ip_src.s_addr & 0xffff; 497 sum += ~ip->ip_dst.s_addr >> 16; 498 sum += ~ip->ip_dst.s_addr & 0xffff; 499 500 for (p = (uint16_t *)&ip6->ip6_src; 501 p < (uint16_t *)(&ip6->ip6_src + 2); p++) 502 sum += *p; 503 504 while (sum >> 16) 505 sum = (sum & 0xffff) + (sum >> 16); 506 return (sum); 507 } 508 509 static void 510 nat64_init_ip4hdr(const struct ip6_hdr *ip6, const struct ip6_frag *frag, 511 uint16_t plen, uint8_t proto, struct ip *ip) 512 { 513 514 /* assume addresses are already initialized */ 515 ip->ip_v = IPVERSION; 516 ip->ip_hl = sizeof(*ip) >> 2; 517 ip->ip_tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 518 ip->ip_len = htons(sizeof(*ip) + plen); 519 ip->ip_ttl = ip6->ip6_hlim; 520 if (*V_nat64ip6stealth == 0) 521 ip->ip_ttl -= IPV6_HLIMDEC; 522 ip->ip_sum = 0; 523 ip->ip_p = (proto == IPPROTO_ICMPV6) ? IPPROTO_ICMP: proto; 524 ip_fillid(ip); 525 if (frag != NULL) { 526 ip->ip_off = htons(ntohs(frag->ip6f_offlg) >> 3); 527 if (frag->ip6f_offlg & IP6F_MORE_FRAG) 528 ip->ip_off |= htons(IP_MF); 529 } else { 530 ip->ip_off = htons(IP_DF); 531 } 532 ip->ip_sum = in_cksum_hdr(ip); 533 } 534 535 #define FRAGSZ(mtu) ((mtu) - sizeof(struct ip6_hdr) - sizeof(struct ip6_frag)) 536 static NAT64NOINLINE int 537 nat64_fragment6(struct nat64_counters *stats, struct ip6_hdr *ip6, 538 struct mbufq *mq, struct mbuf *m, uint32_t mtu, uint16_t ip_id, 539 uint16_t ip_off) 540 { 541 struct ip6_frag ip6f; 542 struct mbuf *n; 543 uint16_t hlen, len, offset; 544 int plen; 545 546 plen = ntohs(ip6->ip6_plen); 547 hlen = sizeof(struct ip6_hdr); 548 549 /* Fragmentation isn't needed */ 550 if (ip_off == 0 && plen <= mtu - hlen) { 551 M_PREPEND(m, hlen, M_NOWAIT); 552 if (m == NULL) { 553 NAT64STAT_INC(stats, nomem); 554 return (ENOMEM); 555 } 556 bcopy(ip6, mtod(m, void *), hlen); 557 if (mbufq_enqueue(mq, m) != 0) { 558 m_freem(m); 559 NAT64STAT_INC(stats, dropped); 560 DPRINTF(DP_DROPS, "dropped due to mbufq overflow"); 561 return (ENOBUFS); 562 } 563 return (0); 564 } 565 566 hlen += sizeof(struct ip6_frag); 567 ip6f.ip6f_reserved = 0; 568 ip6f.ip6f_nxt = ip6->ip6_nxt; 569 ip6->ip6_nxt = IPPROTO_FRAGMENT; 570 if (ip_off != 0) { 571 /* 572 * We have got an IPv4 fragment. 573 * Use offset value and ip_id from original fragment. 574 */ 575 ip6f.ip6f_ident = htonl(ntohs(ip_id)); 576 offset = (ntohs(ip_off) & IP_OFFMASK) << 3; 577 NAT64STAT_INC(stats, ifrags); 578 } else { 579 /* The packet size exceeds interface MTU */ 580 ip6f.ip6f_ident = htonl(ip6_randomid()); 581 offset = 0; /* First fragment*/ 582 } 583 while (plen > 0 && m != NULL) { 584 n = NULL; 585 len = FRAGSZ(mtu) & ~7; 586 if (len > plen) 587 len = plen; 588 ip6->ip6_plen = htons(len + sizeof(ip6f)); 589 ip6f.ip6f_offlg = ntohs(offset); 590 if (len < plen || (ip_off & htons(IP_MF)) != 0) 591 ip6f.ip6f_offlg |= IP6F_MORE_FRAG; 592 offset += len; 593 plen -= len; 594 if (plen > 0) { 595 n = m_split(m, len, M_NOWAIT); 596 if (n == NULL) 597 goto fail; 598 } 599 M_PREPEND(m, hlen, M_NOWAIT); 600 if (m == NULL) 601 goto fail; 602 bcopy(ip6, mtod(m, void *), sizeof(struct ip6_hdr)); 603 bcopy(&ip6f, mtodo(m, sizeof(struct ip6_hdr)), 604 sizeof(struct ip6_frag)); 605 if (mbufq_enqueue(mq, m) != 0) 606 goto fail; 607 m = n; 608 } 609 NAT64STAT_ADD(stats, ofrags, mbufq_len(mq)); 610 return (0); 611 fail: 612 if (m != NULL) 613 m_freem(m); 614 if (n != NULL) 615 m_freem(n); 616 mbufq_drain(mq); 617 NAT64STAT_INC(stats, nomem); 618 return (ENOMEM); 619 } 620 621 static struct nhop_object * 622 nat64_find_route6(struct sockaddr_in6 *dst, struct mbuf *m) 623 { 624 struct nhop_object *nh; 625 NET_EPOCH_ASSERT(); 626 nh = fib6_lookup(M_GETFIB(m), &dst->sin6_addr, 0, 0, 0); 627 if (nh == NULL) 628 return NULL; 629 if (nh->nh_flags & (NHF_BLACKHOLE | NHF_REJECT)) 630 return NULL; 631 /* 632 * XXX: we need to use destination address with embedded scope 633 * zone id, because LLTABLE uses such form of addresses for lookup. 634 */ 635 dst->sin6_family = AF_INET6; 636 dst->sin6_len = sizeof(*dst); 637 dst->sin6_addr = ifatoia6(nh->nh_ifa)->ia_addr.sin6_addr; 638 if (IN6_IS_SCOPE_LINKLOCAL(&dst->sin6_addr)) 639 dst->sin6_addr.s6_addr16[1] = 640 htons(nh->nh_ifp->if_index & 0xffff); 641 dst->sin6_port = 0; 642 dst->sin6_scope_id = 0; 643 dst->sin6_flowinfo = 0; 644 645 return nh; 646 } 647 648 #define NAT64_ICMP6_PLEN 64 649 static NAT64NOINLINE void 650 nat64_icmp6_reflect(struct mbuf *m, uint8_t type, uint8_t code, uint32_t mtu, 651 struct nat64_counters *stats, void *logdata) 652 { 653 struct icmp6_hdr *icmp6; 654 struct ip6_hdr *ip6, *oip6; 655 struct mbuf *n; 656 int len, plen, proto; 657 658 len = 0; 659 proto = nat64_getlasthdr(m, &len); 660 if (proto < 0) { 661 DPRINTF(DP_DROPS, "mbuf isn't contigious"); 662 goto freeit; 663 } 664 /* 665 * Do not send ICMPv6 in reply to ICMPv6 errors. 666 */ 667 if (proto == IPPROTO_ICMPV6) { 668 if (m->m_len < len + sizeof(*icmp6)) { 669 DPRINTF(DP_DROPS, "mbuf isn't contigious"); 670 goto freeit; 671 } 672 icmp6 = mtodo(m, len); 673 if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST || 674 icmp6->icmp6_type == ND_REDIRECT) { 675 DPRINTF(DP_DROPS, "do not send ICMPv6 in reply to " 676 "ICMPv6 errors"); 677 goto freeit; 678 } 679 /* 680 * If there are extra headers between IPv6 and ICMPv6, 681 * strip off them. 682 */ 683 if (len > sizeof(struct ip6_hdr)) { 684 /* 685 * NOTE: ipfw_chk already did m_pullup() and it is 686 * expected that data is contigious from the start 687 * of IPv6 header up to the end of ICMPv6 header. 688 */ 689 bcopy(mtod(m, caddr_t), 690 mtodo(m, len - sizeof(struct ip6_hdr)), 691 sizeof(struct ip6_hdr)); 692 m_adj(m, len - sizeof(struct ip6_hdr)); 693 } 694 } 695 /* 696 if (icmp6_ratelimit(&ip6->ip6_src, type, code)) 697 goto freeit; 698 */ 699 ip6 = mtod(m, struct ip6_hdr *); 700 switch (type) { 701 case ICMP6_DST_UNREACH: 702 case ICMP6_PACKET_TOO_BIG: 703 case ICMP6_TIME_EXCEEDED: 704 case ICMP6_PARAM_PROB: 705 break; 706 default: 707 goto freeit; 708 } 709 /* Calculate length of ICMPv6 payload */ 710 len = (m->m_pkthdr.len > NAT64_ICMP6_PLEN) ? NAT64_ICMP6_PLEN: 711 m->m_pkthdr.len; 712 713 /* Create new ICMPv6 datagram */ 714 plen = len + sizeof(struct icmp6_hdr); 715 n = m_get2(sizeof(struct ip6_hdr) + plen + max_hdr, M_NOWAIT, 716 MT_HEADER, M_PKTHDR); 717 if (n == NULL) { 718 NAT64STAT_INC(stats, nomem); 719 m_freem(m); 720 return; 721 } 722 /* 723 * Move pkthdr from original mbuf. We should have initialized some 724 * fields, because we can reinject this mbuf to netisr and it will 725 * go trough input path (it requires at least rcvif should be set). 726 * Also do M_ALIGN() to reduce chances of need to allocate new mbuf 727 * in the chain, when we will do M_PREPEND() or make some type of 728 * tunneling. 729 */ 730 m_move_pkthdr(n, m); 731 M_ALIGN(n, sizeof(struct ip6_hdr) + plen + max_hdr); 732 733 n->m_len = n->m_pkthdr.len = sizeof(struct ip6_hdr) + plen; 734 oip6 = mtod(n, struct ip6_hdr *); 735 /* 736 * Make IPv6 source address selection for reflected datagram. 737 * nat64_check_ip6() doesn't allow scoped addresses, therefore 738 * we use zero scopeid. 739 */ 740 if (in6_selectsrc_addr(M_GETFIB(n), &ip6->ip6_src, 0, 741 n->m_pkthdr.rcvif, &oip6->ip6_src, NULL) != 0) { 742 /* 743 * Failed to find proper source address, drop the packet. 744 */ 745 m_freem(n); 746 goto freeit; 747 } 748 oip6->ip6_dst = ip6->ip6_src; 749 oip6->ip6_nxt = IPPROTO_ICMPV6; 750 oip6->ip6_flow = 0; 751 oip6->ip6_vfc |= IPV6_VERSION; 752 oip6->ip6_hlim = V_ip6_defhlim; 753 oip6->ip6_plen = htons(plen); 754 755 icmp6 = mtodo(n, sizeof(struct ip6_hdr)); 756 icmp6->icmp6_cksum = 0; 757 icmp6->icmp6_type = type; 758 icmp6->icmp6_code = code; 759 icmp6->icmp6_mtu = htonl(mtu); 760 761 m_copydata(m, 0, len, mtodo(n, sizeof(struct ip6_hdr) + 762 sizeof(struct icmp6_hdr))); 763 icmp6->icmp6_cksum = in6_cksum(n, IPPROTO_ICMPV6, 764 sizeof(struct ip6_hdr), plen); 765 m_freem(m); 766 V_nat64out->output_one(n, stats, logdata); 767 return; 768 freeit: 769 NAT64STAT_INC(stats, dropped); 770 m_freem(m); 771 } 772 773 static struct nhop_object * 774 nat64_find_route4(struct sockaddr_in *dst, struct mbuf *m) 775 { 776 struct nhop_object *nh; 777 778 NET_EPOCH_ASSERT(); 779 nh = fib4_lookup(M_GETFIB(m), dst->sin_addr, 0, 0, 0); 780 if (nh == NULL) 781 return NULL; 782 if (nh->nh_flags & (NHF_BLACKHOLE | NHF_BROADCAST | NHF_REJECT)) 783 return NULL; 784 785 dst->sin_family = AF_INET; 786 dst->sin_len = sizeof(*dst); 787 dst->sin_addr = IA_SIN(nh->nh_ifa)->sin_addr; 788 dst->sin_port = 0; 789 return nh; 790 } 791 792 #define NAT64_ICMP_PLEN 64 793 static NAT64NOINLINE void 794 nat64_icmp_reflect(struct mbuf *m, uint8_t type, 795 uint8_t code, uint16_t mtu, struct nat64_counters *stats, void *logdata) 796 { 797 struct icmp *icmp; 798 struct ip *ip, *oip; 799 struct mbuf *n; 800 int len, plen; 801 802 ip = mtod(m, struct ip *); 803 /* Do not send ICMP error if packet is not the first fragment */ 804 if (ip->ip_off & ~ntohs(IP_MF|IP_DF)) { 805 DPRINTF(DP_DROPS, "not first fragment"); 806 goto freeit; 807 } 808 /* Do not send ICMP in reply to ICMP errors */ 809 if (ip->ip_p == IPPROTO_ICMP) { 810 if (m->m_len < (ip->ip_hl << 2)) { 811 DPRINTF(DP_DROPS, "mbuf isn't contigious"); 812 goto freeit; 813 } 814 icmp = mtodo(m, ip->ip_hl << 2); 815 if (!ICMP_INFOTYPE(icmp->icmp_type)) { 816 DPRINTF(DP_DROPS, "do not send ICMP in reply to " 817 "ICMP errors"); 818 goto freeit; 819 } 820 } 821 switch (type) { 822 case ICMP_UNREACH: 823 case ICMP_TIMXCEED: 824 case ICMP_PARAMPROB: 825 break; 826 default: 827 goto freeit; 828 } 829 /* Calculate length of ICMP payload */ 830 len = (m->m_pkthdr.len > NAT64_ICMP_PLEN) ? (ip->ip_hl << 2) + 8: 831 m->m_pkthdr.len; 832 833 /* Create new ICMPv4 datagram */ 834 plen = len + sizeof(struct icmphdr) + sizeof(uint32_t); 835 n = m_get2(sizeof(struct ip) + plen + max_hdr, M_NOWAIT, 836 MT_HEADER, M_PKTHDR); 837 if (n == NULL) { 838 NAT64STAT_INC(stats, nomem); 839 m_freem(m); 840 return; 841 } 842 m_move_pkthdr(n, m); 843 M_ALIGN(n, sizeof(struct ip) + plen + max_hdr); 844 845 n->m_len = n->m_pkthdr.len = sizeof(struct ip) + plen; 846 oip = mtod(n, struct ip *); 847 oip->ip_v = IPVERSION; 848 oip->ip_hl = sizeof(struct ip) >> 2; 849 oip->ip_tos = 0; 850 oip->ip_len = htons(n->m_pkthdr.len); 851 oip->ip_ttl = V_ip_defttl; 852 oip->ip_p = IPPROTO_ICMP; 853 ip_fillid(oip); 854 oip->ip_off = htons(IP_DF); 855 oip->ip_src = ip->ip_dst; 856 oip->ip_dst = ip->ip_src; 857 oip->ip_sum = 0; 858 oip->ip_sum = in_cksum_hdr(oip); 859 860 icmp = mtodo(n, sizeof(struct ip)); 861 icmp->icmp_type = type; 862 icmp->icmp_code = code; 863 icmp->icmp_cksum = 0; 864 icmp->icmp_pmvoid = 0; 865 icmp->icmp_nextmtu = htons(mtu); 866 m_copydata(m, 0, len, mtodo(n, sizeof(struct ip) + 867 sizeof(struct icmphdr) + sizeof(uint32_t))); 868 icmp->icmp_cksum = in_cksum_skip(n, sizeof(struct ip) + plen, 869 sizeof(struct ip)); 870 m_freem(m); 871 V_nat64out->output_one(n, stats, logdata); 872 return; 873 freeit: 874 NAT64STAT_INC(stats, dropped); 875 m_freem(m); 876 } 877 878 /* Translate ICMP echo request/reply into ICMPv6 */ 879 static void 880 nat64_icmp_handle_echo(struct ip6_hdr *ip6, struct icmp6_hdr *icmp6, 881 uint16_t id, uint8_t type) 882 { 883 uint16_t old; 884 885 old = *(uint16_t *)icmp6; /* save type+code in one word */ 886 icmp6->icmp6_type = type; 887 /* Reflect ICMPv6 -> ICMPv4 type translation in the cksum */ 888 icmp6->icmp6_cksum = cksum_adjust(icmp6->icmp6_cksum, 889 old, *(uint16_t *)icmp6); 890 if (id != 0) { 891 old = icmp6->icmp6_id; 892 icmp6->icmp6_id = id; 893 /* Reflect ICMP id translation in the cksum */ 894 icmp6->icmp6_cksum = cksum_adjust(icmp6->icmp6_cksum, 895 old, id); 896 } 897 /* Reflect IPv6 pseudo header in the cksum */ 898 icmp6->icmp6_cksum = ~in6_cksum_pseudo(ip6, ntohs(ip6->ip6_plen), 899 IPPROTO_ICMPV6, ~icmp6->icmp6_cksum); 900 } 901 902 static NAT64NOINLINE struct mbuf * 903 nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *ip6, uint16_t icmpid, 904 int offset, struct nat64_config *cfg) 905 { 906 struct ip ip; 907 struct icmp *icmp; 908 struct tcphdr *tcp; 909 struct udphdr *udp; 910 struct ip6_hdr *eip6; 911 struct mbuf *n; 912 uint32_t mtu; 913 int len, hlen, plen; 914 uint8_t type, code; 915 916 if (m->m_len < offset + ICMP_MINLEN) 917 m = m_pullup(m, offset + ICMP_MINLEN); 918 if (m == NULL) { 919 NAT64STAT_INC(&cfg->stats, nomem); 920 return (m); 921 } 922 mtu = 0; 923 icmp = mtodo(m, offset); 924 /* RFC 7915 p4.2 */ 925 switch (icmp->icmp_type) { 926 case ICMP_ECHOREPLY: 927 type = ICMP6_ECHO_REPLY; 928 code = 0; 929 break; 930 case ICMP_UNREACH: 931 type = ICMP6_DST_UNREACH; 932 switch (icmp->icmp_code) { 933 case ICMP_UNREACH_NET: 934 case ICMP_UNREACH_HOST: 935 case ICMP_UNREACH_SRCFAIL: 936 case ICMP_UNREACH_NET_UNKNOWN: 937 case ICMP_UNREACH_HOST_UNKNOWN: 938 case ICMP_UNREACH_TOSNET: 939 case ICMP_UNREACH_TOSHOST: 940 code = ICMP6_DST_UNREACH_NOROUTE; 941 break; 942 case ICMP_UNREACH_PROTOCOL: 943 type = ICMP6_PARAM_PROB; 944 code = ICMP6_PARAMPROB_NEXTHEADER; 945 break; 946 case ICMP_UNREACH_PORT: 947 code = ICMP6_DST_UNREACH_NOPORT; 948 break; 949 case ICMP_UNREACH_NEEDFRAG: 950 type = ICMP6_PACKET_TOO_BIG; 951 code = 0; 952 /* XXX: needs an additional look */ 953 mtu = max(IPV6_MMTU, ntohs(icmp->icmp_nextmtu) + 20); 954 break; 955 case ICMP_UNREACH_NET_PROHIB: 956 case ICMP_UNREACH_HOST_PROHIB: 957 case ICMP_UNREACH_FILTER_PROHIB: 958 case ICMP_UNREACH_PRECEDENCE_CUTOFF: 959 code = ICMP6_DST_UNREACH_ADMIN; 960 break; 961 default: 962 DPRINTF(DP_DROPS, "Unsupported ICMP type %d, code %d", 963 icmp->icmp_type, icmp->icmp_code); 964 goto freeit; 965 } 966 break; 967 case ICMP_TIMXCEED: 968 type = ICMP6_TIME_EXCEEDED; 969 code = icmp->icmp_code; 970 break; 971 case ICMP_ECHO: 972 type = ICMP6_ECHO_REQUEST; 973 code = 0; 974 break; 975 case ICMP_PARAMPROB: 976 type = ICMP6_PARAM_PROB; 977 switch (icmp->icmp_code) { 978 case ICMP_PARAMPROB_ERRATPTR: 979 case ICMP_PARAMPROB_LENGTH: 980 code = ICMP6_PARAMPROB_HEADER; 981 switch (icmp->icmp_pptr) { 982 case 0: /* Version/IHL */ 983 case 1: /* Type Of Service */ 984 mtu = icmp->icmp_pptr; 985 break; 986 case 2: /* Total Length */ 987 case 3: mtu = 4; /* Payload Length */ 988 break; 989 case 8: /* Time to Live */ 990 mtu = 7; /* Hop Limit */ 991 break; 992 case 9: /* Protocol */ 993 mtu = 6; /* Next Header */ 994 break; 995 case 12: /* Source address */ 996 case 13: 997 case 14: 998 case 15: 999 mtu = 8; 1000 break; 1001 case 16: /* Destination address */ 1002 case 17: 1003 case 18: 1004 case 19: 1005 mtu = 24; 1006 break; 1007 default: /* Silently drop */ 1008 DPRINTF(DP_DROPS, "Unsupported ICMP type %d," 1009 " code %d, pptr %d", icmp->icmp_type, 1010 icmp->icmp_code, icmp->icmp_pptr); 1011 goto freeit; 1012 } 1013 break; 1014 default: 1015 DPRINTF(DP_DROPS, "Unsupported ICMP type %d," 1016 " code %d, pptr %d", icmp->icmp_type, 1017 icmp->icmp_code, icmp->icmp_pptr); 1018 goto freeit; 1019 } 1020 break; 1021 default: 1022 DPRINTF(DP_DROPS, "Unsupported ICMP type %d, code %d", 1023 icmp->icmp_type, icmp->icmp_code); 1024 goto freeit; 1025 } 1026 /* 1027 * For echo request/reply we can use original payload, 1028 * but we need adjust icmp_cksum, because ICMPv6 cksum covers 1029 * IPv6 pseudo header and ICMPv6 types differs from ICMPv4. 1030 */ 1031 if (type == ICMP6_ECHO_REQUEST || type == ICMP6_ECHO_REPLY) { 1032 nat64_icmp_handle_echo(ip6, ICMP6(icmp), icmpid, type); 1033 return (m); 1034 } 1035 /* 1036 * For other types of ICMP messages we need to translate inner 1037 * IPv4 header to IPv6 header. 1038 * Assume ICMP src is the same as payload dst 1039 * E.g. we have ( GWsrc1 , NATIP1 ) in outer header 1040 * and ( NATIP1, Hostdst1 ) in ICMP copy header. 1041 * In that case, we already have map for NATIP1 and GWsrc1. 1042 * The only thing we need is to copy IPv6 map prefix to 1043 * Hostdst1. 1044 */ 1045 hlen = offset + ICMP_MINLEN; 1046 if (m->m_pkthdr.len < hlen + sizeof(struct ip) + ICMP_MINLEN) { 1047 DPRINTF(DP_DROPS, "Message is too short %d", 1048 m->m_pkthdr.len); 1049 goto freeit; 1050 } 1051 m_copydata(m, hlen, sizeof(struct ip), (char *)&ip); 1052 if (ip.ip_v != IPVERSION) { 1053 DPRINTF(DP_DROPS, "Wrong IP version %d", ip.ip_v); 1054 goto freeit; 1055 } 1056 hlen += ip.ip_hl << 2; /* Skip inner IP header */ 1057 if (nat64_check_ip4(ip.ip_src.s_addr) != 0 || 1058 nat64_check_ip4(ip.ip_dst.s_addr) != 0 || 1059 nat64_check_private_ip4(cfg, ip.ip_src.s_addr) != 0 || 1060 nat64_check_private_ip4(cfg, ip.ip_dst.s_addr) != 0) { 1061 DPRINTF(DP_DROPS, "IP addresses checks failed %04x -> %04x", 1062 ntohl(ip.ip_src.s_addr), ntohl(ip.ip_dst.s_addr)); 1063 goto freeit; 1064 } 1065 if (m->m_pkthdr.len < hlen + ICMP_MINLEN) { 1066 DPRINTF(DP_DROPS, "Message is too short %d", 1067 m->m_pkthdr.len); 1068 goto freeit; 1069 } 1070 #if 0 1071 /* 1072 * Check that inner source matches the outer destination. 1073 * XXX: We need some method to convert IPv4 into IPv6 address here, 1074 * and compare IPv6 addresses. 1075 */ 1076 if (ip.ip_src.s_addr != nat64_get_ip4(&ip6->ip6_dst)) { 1077 DPRINTF(DP_GENERIC, "Inner source doesn't match destination ", 1078 "%04x vs %04x", ip.ip_src.s_addr, 1079 nat64_get_ip4(&ip6->ip6_dst)); 1080 goto freeit; 1081 } 1082 #endif 1083 /* 1084 * Create new mbuf for ICMPv6 datagram. 1085 * NOTE: len is data length just after inner IP header. 1086 */ 1087 len = m->m_pkthdr.len - hlen; 1088 if (sizeof(struct ip6_hdr) + 1089 sizeof(struct icmp6_hdr) + len > NAT64_ICMP6_PLEN) 1090 len = NAT64_ICMP6_PLEN - sizeof(struct icmp6_hdr) - 1091 sizeof(struct ip6_hdr); 1092 plen = sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + len; 1093 n = m_get2(offset + plen + max_hdr, M_NOWAIT, MT_HEADER, M_PKTHDR); 1094 if (n == NULL) { 1095 NAT64STAT_INC(&cfg->stats, nomem); 1096 m_freem(m); 1097 return (NULL); 1098 } 1099 m_move_pkthdr(n, m); 1100 M_ALIGN(n, offset + plen + max_hdr); 1101 n->m_len = n->m_pkthdr.len = offset + plen; 1102 /* Adjust ip6_plen in outer header */ 1103 ip6->ip6_plen = htons(plen); 1104 /* Construct new inner IPv6 header */ 1105 eip6 = mtodo(n, offset + sizeof(struct icmp6_hdr)); 1106 eip6->ip6_src = ip6->ip6_dst; 1107 1108 /* Use the same prefix that we have in outer header */ 1109 eip6->ip6_dst = ip6->ip6_src; 1110 MPASS(cfg->flags & NAT64_PLATPFX); 1111 nat64_embed_ip4(&eip6->ip6_dst, cfg->plat_plen, ip.ip_dst.s_addr); 1112 1113 eip6->ip6_flow = htonl(ip.ip_tos << 20); 1114 eip6->ip6_vfc |= IPV6_VERSION; 1115 eip6->ip6_hlim = ip.ip_ttl; 1116 eip6->ip6_plen = htons(ntohs(ip.ip_len) - (ip.ip_hl << 2)); 1117 eip6->ip6_nxt = (ip.ip_p == IPPROTO_ICMP) ? IPPROTO_ICMPV6: ip.ip_p; 1118 m_copydata(m, hlen, len, (char *)(eip6 + 1)); 1119 /* 1120 * We need to translate source port in the inner ULP header, 1121 * and adjust ULP checksum. 1122 */ 1123 switch (ip.ip_p) { 1124 case IPPROTO_TCP: 1125 if (len < offsetof(struct tcphdr, th_sum)) 1126 break; 1127 tcp = TCP(eip6 + 1); 1128 if (icmpid != 0) { 1129 tcp->th_sum = cksum_adjust(tcp->th_sum, 1130 tcp->th_sport, icmpid); 1131 tcp->th_sport = icmpid; 1132 } 1133 tcp->th_sum = cksum_add(tcp->th_sum, 1134 ~nat64_cksum_convert(eip6, &ip)); 1135 break; 1136 case IPPROTO_UDP: 1137 if (len < offsetof(struct udphdr, uh_sum)) 1138 break; 1139 udp = UDP(eip6 + 1); 1140 if (icmpid != 0) { 1141 udp->uh_sum = cksum_adjust(udp->uh_sum, 1142 udp->uh_sport, icmpid); 1143 udp->uh_sport = icmpid; 1144 } 1145 udp->uh_sum = cksum_add(udp->uh_sum, 1146 ~nat64_cksum_convert(eip6, &ip)); 1147 break; 1148 case IPPROTO_ICMP: 1149 /* 1150 * Check if this is an ICMP error message for echo request 1151 * that we sent. I.e. ULP in the data containing invoking 1152 * packet is IPPROTO_ICMP and its type is ICMP_ECHO. 1153 */ 1154 icmp = (struct icmp *)(eip6 + 1); 1155 if (icmp->icmp_type != ICMP_ECHO) { 1156 m_freem(n); 1157 goto freeit; 1158 } 1159 /* 1160 * For our client this original datagram should looks 1161 * like it was ICMPv6 datagram with type ICMP6_ECHO_REQUEST. 1162 * Thus we need adjust icmp_cksum and convert type from 1163 * ICMP_ECHO to ICMP6_ECHO_REQUEST. 1164 */ 1165 nat64_icmp_handle_echo(eip6, ICMP6(icmp), icmpid, 1166 ICMP6_ECHO_REQUEST); 1167 } 1168 m_freem(m); 1169 /* Convert ICMPv4 into ICMPv6 header */ 1170 icmp = mtodo(n, offset); 1171 ICMP6(icmp)->icmp6_type = type; 1172 ICMP6(icmp)->icmp6_code = code; 1173 ICMP6(icmp)->icmp6_mtu = htonl(mtu); 1174 ICMP6(icmp)->icmp6_cksum = 0; 1175 ICMP6(icmp)->icmp6_cksum = cksum_add( 1176 ~in6_cksum_pseudo(ip6, plen, IPPROTO_ICMPV6, 0), 1177 in_cksum_skip(n, n->m_pkthdr.len, offset)); 1178 return (n); 1179 freeit: 1180 m_freem(m); 1181 NAT64STAT_INC(&cfg->stats, dropped); 1182 return (NULL); 1183 } 1184 1185 int 1186 nat64_getlasthdr(struct mbuf *m, int *offset) 1187 { 1188 struct ip6_hdr *ip6; 1189 struct ip6_hbh *hbh; 1190 int proto, hlen; 1191 1192 if (offset != NULL) 1193 hlen = *offset; 1194 else 1195 hlen = 0; 1196 1197 if (m->m_len < hlen + sizeof(*ip6)) 1198 return (-1); 1199 1200 ip6 = mtodo(m, hlen); 1201 hlen += sizeof(*ip6); 1202 proto = ip6->ip6_nxt; 1203 /* Skip extension headers */ 1204 while (proto == IPPROTO_HOPOPTS || proto == IPPROTO_ROUTING || 1205 proto == IPPROTO_DSTOPTS) { 1206 hbh = mtodo(m, hlen); 1207 /* 1208 * We expect mbuf has contigious data up to 1209 * upper level header. 1210 */ 1211 if (m->m_len < hlen) 1212 return (-1); 1213 /* 1214 * We doesn't support Jumbo payload option, 1215 * so return error. 1216 */ 1217 if (proto == IPPROTO_HOPOPTS && ip6->ip6_plen == 0) 1218 return (-1); 1219 proto = hbh->ip6h_nxt; 1220 hlen += (hbh->ip6h_len + 1) << 3; 1221 } 1222 if (offset != NULL) 1223 *offset = hlen; 1224 return (proto); 1225 } 1226 1227 int 1228 nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *saddr, 1229 struct in6_addr *daddr, uint16_t lport, struct nat64_config *cfg, 1230 void *logdata) 1231 { 1232 struct nhop_object *nh; 1233 struct ip6_hdr ip6; 1234 struct sockaddr_in6 dst; 1235 struct ip *ip; 1236 struct mbufq mq; 1237 uint16_t ip_id, ip_off; 1238 uint16_t *csum; 1239 int plen, hlen; 1240 uint8_t proto; 1241 1242 ip = mtod(m, struct ip*); 1243 1244 if (*V_nat64ipstealth == 0 && ip->ip_ttl <= IPTTLDEC) { 1245 nat64_icmp_reflect(m, ICMP_TIMXCEED, 1246 ICMP_TIMXCEED_INTRANS, 0, &cfg->stats, logdata); 1247 return (NAT64RETURN); 1248 } 1249 1250 ip6.ip6_dst = *daddr; 1251 ip6.ip6_src = *saddr; 1252 1253 hlen = ip->ip_hl << 2; 1254 plen = ntohs(ip->ip_len) - hlen; 1255 proto = ip->ip_p; 1256 1257 /* Save ip_id and ip_off, both are in network byte order */ 1258 ip_id = ip->ip_id; 1259 ip_off = ip->ip_off & htons(IP_OFFMASK | IP_MF); 1260 1261 /* Fragment length must be multiple of 8 octets */ 1262 if ((ip->ip_off & htons(IP_MF)) != 0 && (plen & 0x7) != 0) { 1263 nat64_icmp_reflect(m, ICMP_PARAMPROB, 1264 ICMP_PARAMPROB_LENGTH, 0, &cfg->stats, logdata); 1265 return (NAT64RETURN); 1266 } 1267 /* Fragmented ICMP is unsupported */ 1268 if (proto == IPPROTO_ICMP && ip_off != 0) { 1269 DPRINTF(DP_DROPS, "dropped due to fragmented ICMP"); 1270 NAT64STAT_INC(&cfg->stats, dropped); 1271 return (NAT64MFREE); 1272 } 1273 1274 dst.sin6_addr = ip6.ip6_dst; 1275 nh = nat64_find_route6(&dst, m); 1276 if (nh == NULL) { 1277 NAT64STAT_INC(&cfg->stats, noroute6); 1278 nat64_icmp_reflect(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 1279 &cfg->stats, logdata); 1280 return (NAT64RETURN); 1281 } 1282 if (nh->nh_mtu < plen + sizeof(ip6) && 1283 (ip->ip_off & htons(IP_DF)) != 0) { 1284 nat64_icmp_reflect(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 1285 FRAGSZ(nh->nh_mtu) + sizeof(struct ip), &cfg->stats, logdata); 1286 return (NAT64RETURN); 1287 } 1288 1289 ip6.ip6_flow = htonl(ip->ip_tos << 20); 1290 ip6.ip6_vfc |= IPV6_VERSION; 1291 ip6.ip6_hlim = ip->ip_ttl; 1292 if (*V_nat64ipstealth == 0) 1293 ip6.ip6_hlim -= IPTTLDEC; 1294 ip6.ip6_plen = htons(plen); 1295 ip6.ip6_nxt = (proto == IPPROTO_ICMP) ? IPPROTO_ICMPV6: proto; 1296 1297 /* Handle delayed checksums if needed. */ 1298 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 1299 in_delayed_cksum(m); 1300 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 1301 } 1302 /* Convert checksums. */ 1303 switch (proto) { 1304 case IPPROTO_TCP: 1305 csum = &TCP(mtodo(m, hlen))->th_sum; 1306 if (lport != 0) { 1307 struct tcphdr *tcp = TCP(mtodo(m, hlen)); 1308 *csum = cksum_adjust(*csum, tcp->th_dport, lport); 1309 tcp->th_dport = lport; 1310 } 1311 *csum = cksum_add(*csum, ~nat64_cksum_convert(&ip6, ip)); 1312 break; 1313 case IPPROTO_UDP: 1314 csum = &UDP(mtodo(m, hlen))->uh_sum; 1315 if (lport != 0) { 1316 struct udphdr *udp = UDP(mtodo(m, hlen)); 1317 *csum = cksum_adjust(*csum, udp->uh_dport, lport); 1318 udp->uh_dport = lport; 1319 } 1320 *csum = cksum_add(*csum, ~nat64_cksum_convert(&ip6, ip)); 1321 break; 1322 case IPPROTO_ICMP: 1323 m = nat64_icmp_translate(m, &ip6, lport, hlen, cfg); 1324 if (m == NULL) /* stats already accounted */ 1325 return (NAT64RETURN); 1326 } 1327 1328 m_adj(m, hlen); 1329 mbufq_init(&mq, 255); 1330 nat64_fragment6(&cfg->stats, &ip6, &mq, m, nh->nh_mtu, ip_id, ip_off); 1331 while ((m = mbufq_dequeue(&mq)) != NULL) { 1332 if (V_nat64out->output(nh->nh_ifp, m, (struct sockaddr *)&dst, 1333 &cfg->stats, logdata) != 0) 1334 break; 1335 NAT64STAT_INC(&cfg->stats, opcnt46); 1336 } 1337 mbufq_drain(&mq); 1338 return (NAT64RETURN); 1339 } 1340 1341 int 1342 nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport, 1343 struct nat64_config *cfg, void *logdata) 1344 { 1345 struct ip ip; 1346 struct icmp6_hdr *icmp6; 1347 struct ip6_frag *ip6f; 1348 struct ip6_hdr *ip6, *ip6i; 1349 uint32_t mtu; 1350 int plen, proto; 1351 uint8_t type, code; 1352 1353 if (hlen == 0) { 1354 ip6 = mtod(m, struct ip6_hdr *); 1355 if (nat64_check_ip6(&ip6->ip6_src) != 0 || 1356 nat64_check_ip6(&ip6->ip6_dst) != 0) 1357 return (NAT64SKIP); 1358 1359 proto = nat64_getlasthdr(m, &hlen); 1360 if (proto != IPPROTO_ICMPV6) { 1361 DPRINTF(DP_DROPS, 1362 "dropped due to mbuf isn't contigious"); 1363 NAT64STAT_INC(&cfg->stats, dropped); 1364 return (NAT64MFREE); 1365 } 1366 } 1367 1368 /* 1369 * Translate ICMPv6 type and code to ICMPv4 (RFC7915). 1370 * NOTE: ICMPv6 echo handled by nat64_do_handle_ip6(). 1371 */ 1372 icmp6 = mtodo(m, hlen); 1373 mtu = 0; 1374 switch (icmp6->icmp6_type) { 1375 case ICMP6_DST_UNREACH: 1376 type = ICMP_UNREACH; 1377 switch (icmp6->icmp6_code) { 1378 case ICMP6_DST_UNREACH_NOROUTE: 1379 case ICMP6_DST_UNREACH_BEYONDSCOPE: 1380 case ICMP6_DST_UNREACH_ADDR: 1381 code = ICMP_UNREACH_HOST; 1382 break; 1383 case ICMP6_DST_UNREACH_ADMIN: 1384 code = ICMP_UNREACH_HOST_PROHIB; 1385 break; 1386 case ICMP6_DST_UNREACH_NOPORT: 1387 code = ICMP_UNREACH_PORT; 1388 break; 1389 default: 1390 DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d," 1391 " code %d", icmp6->icmp6_type, 1392 icmp6->icmp6_code); 1393 NAT64STAT_INC(&cfg->stats, dropped); 1394 return (NAT64MFREE); 1395 } 1396 break; 1397 case ICMP6_PACKET_TOO_BIG: 1398 type = ICMP_UNREACH; 1399 code = ICMP_UNREACH_NEEDFRAG; 1400 mtu = ntohl(icmp6->icmp6_mtu); 1401 if (mtu < IPV6_MMTU) { 1402 DPRINTF(DP_DROPS, "Wrong MTU %d in ICMPv6 type %d," 1403 " code %d", mtu, icmp6->icmp6_type, 1404 icmp6->icmp6_code); 1405 NAT64STAT_INC(&cfg->stats, dropped); 1406 return (NAT64MFREE); 1407 } 1408 /* 1409 * Adjust MTU to reflect difference between 1410 * IPv6 an IPv4 headers. 1411 */ 1412 mtu -= sizeof(struct ip6_hdr) - sizeof(struct ip); 1413 break; 1414 case ICMP6_TIME_EXCEEDED: 1415 type = ICMP_TIMXCEED; 1416 code = icmp6->icmp6_code; 1417 break; 1418 case ICMP6_PARAM_PROB: 1419 switch (icmp6->icmp6_code) { 1420 case ICMP6_PARAMPROB_HEADER: 1421 type = ICMP_PARAMPROB; 1422 code = ICMP_PARAMPROB_ERRATPTR; 1423 mtu = ntohl(icmp6->icmp6_pptr); 1424 switch (mtu) { 1425 case 0: /* Version/Traffic Class */ 1426 case 1: /* Traffic Class/Flow Label */ 1427 break; 1428 case 4: /* Payload Length */ 1429 case 5: 1430 mtu = 2; 1431 break; 1432 case 6: /* Next Header */ 1433 mtu = 9; 1434 break; 1435 case 7: /* Hop Limit */ 1436 mtu = 8; 1437 break; 1438 default: 1439 if (mtu >= 8 && mtu <= 23) { 1440 mtu = 12; /* Source address */ 1441 break; 1442 } 1443 if (mtu >= 24 && mtu <= 39) { 1444 mtu = 16; /* Destination address */ 1445 break; 1446 } 1447 DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d," 1448 " code %d, pptr %d", icmp6->icmp6_type, 1449 icmp6->icmp6_code, mtu); 1450 NAT64STAT_INC(&cfg->stats, dropped); 1451 return (NAT64MFREE); 1452 } 1453 case ICMP6_PARAMPROB_NEXTHEADER: 1454 type = ICMP_UNREACH; 1455 code = ICMP_UNREACH_PROTOCOL; 1456 break; 1457 default: 1458 DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d," 1459 " code %d, pptr %d", icmp6->icmp6_type, 1460 icmp6->icmp6_code, ntohl(icmp6->icmp6_pptr)); 1461 NAT64STAT_INC(&cfg->stats, dropped); 1462 return (NAT64MFREE); 1463 } 1464 break; 1465 default: 1466 DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d, code %d", 1467 icmp6->icmp6_type, icmp6->icmp6_code); 1468 NAT64STAT_INC(&cfg->stats, dropped); 1469 return (NAT64MFREE); 1470 } 1471 1472 hlen += sizeof(struct icmp6_hdr); 1473 if (m->m_pkthdr.len < hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN) { 1474 NAT64STAT_INC(&cfg->stats, dropped); 1475 DPRINTF(DP_DROPS, "Message is too short %d", 1476 m->m_pkthdr.len); 1477 return (NAT64MFREE); 1478 } 1479 /* 1480 * We need at least ICMP_MINLEN bytes of original datagram payload 1481 * to generate ICMP message. It is nice that ICMP_MINLEN is equal 1482 * to sizeof(struct ip6_frag). So, if embedded datagram had a fragment 1483 * header we will not have to do m_pullup() again. 1484 * 1485 * What we have here: 1486 * Outer header: (IPv6iGW, v4mapPRefix+v4exthost) 1487 * Inner header: (v4mapPRefix+v4host, IPv6iHost) [sport, dport] 1488 * We need to translate it to: 1489 * 1490 * Outer header: (alias_host, v4exthost) 1491 * Inner header: (v4exthost, alias_host) [sport, alias_port] 1492 * 1493 * Assume caller function has checked if v4mapPRefix+v4host 1494 * matches configured prefix. 1495 * The only two things we should be provided with are mapping between 1496 * IPv6iHost <> alias_host and between dport and alias_port. 1497 */ 1498 if (m->m_len < hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN) 1499 m = m_pullup(m, hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN); 1500 if (m == NULL) { 1501 NAT64STAT_INC(&cfg->stats, nomem); 1502 return (NAT64RETURN); 1503 } 1504 ip6 = mtod(m, struct ip6_hdr *); 1505 ip6i = mtodo(m, hlen); 1506 ip6f = NULL; 1507 proto = ip6i->ip6_nxt; 1508 plen = ntohs(ip6i->ip6_plen); 1509 hlen += sizeof(struct ip6_hdr); 1510 if (proto == IPPROTO_FRAGMENT) { 1511 if (m->m_pkthdr.len < hlen + sizeof(struct ip6_frag) + 1512 ICMP_MINLEN) 1513 goto fail; 1514 ip6f = mtodo(m, hlen); 1515 proto = ip6f->ip6f_nxt; 1516 plen -= sizeof(struct ip6_frag); 1517 hlen += sizeof(struct ip6_frag); 1518 /* Ajust MTU to reflect frag header size */ 1519 if (type == ICMP_UNREACH && code == ICMP_UNREACH_NEEDFRAG) 1520 mtu -= sizeof(struct ip6_frag); 1521 } 1522 if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) { 1523 DPRINTF(DP_DROPS, "Unsupported proto %d in the inner header", 1524 proto); 1525 goto fail; 1526 } 1527 if (nat64_check_ip6(&ip6i->ip6_src) != 0 || 1528 nat64_check_ip6(&ip6i->ip6_dst) != 0) { 1529 DPRINTF(DP_DROPS, "Inner addresses do not passes the check"); 1530 goto fail; 1531 } 1532 /* Check if outer dst is the same as inner src */ 1533 if (!IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &ip6i->ip6_src)) { 1534 DPRINTF(DP_DROPS, "Inner src doesn't match outer dst"); 1535 goto fail; 1536 } 1537 1538 /* Now we need to make a fake IPv4 packet to generate ICMP message */ 1539 ip.ip_dst.s_addr = aaddr; 1540 ip.ip_src.s_addr = nat64_extract_ip4(&ip6i->ip6_src, cfg->plat_plen); 1541 if (ip.ip_src.s_addr == 0) 1542 goto fail; 1543 /* XXX: Make fake ulp header */ 1544 if (V_nat64out == &nat64_direct) /* init_ip4hdr will decrement it */ 1545 ip6i->ip6_hlim += IPV6_HLIMDEC; 1546 nat64_init_ip4hdr(ip6i, ip6f, plen, proto, &ip); 1547 m_adj(m, hlen - sizeof(struct ip)); 1548 bcopy(&ip, mtod(m, void *), sizeof(ip)); 1549 nat64_icmp_reflect(m, type, code, (uint16_t)mtu, &cfg->stats, 1550 logdata); 1551 return (NAT64RETURN); 1552 fail: 1553 /* 1554 * We must call m_freem() because mbuf pointer could be 1555 * changed with m_pullup(). 1556 */ 1557 m_freem(m); 1558 NAT64STAT_INC(&cfg->stats, dropped); 1559 return (NAT64RETURN); 1560 } 1561 1562 int 1563 nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport, 1564 struct nat64_config *cfg, void *logdata) 1565 { 1566 struct ip ip; 1567 struct nhop_object *nh; 1568 struct sockaddr_in dst; 1569 struct ip6_frag *frag; 1570 struct ip6_hdr *ip6; 1571 struct icmp6_hdr *icmp6; 1572 uint16_t *csum; 1573 int plen, hlen, proto; 1574 1575 /* 1576 * XXX: we expect ipfw_chk() did m_pullup() up to upper level 1577 * protocol's headers. Also we skip some checks, that ip6_input(), 1578 * ip6_forward(), ip6_fastfwd() and ipfw_chk() already did. 1579 */ 1580 ip6 = mtod(m, struct ip6_hdr *); 1581 if (nat64_check_ip6(&ip6->ip6_src) != 0 || 1582 nat64_check_ip6(&ip6->ip6_dst) != 0) { 1583 return (NAT64SKIP); 1584 } 1585 1586 /* Starting from this point we must not return zero */ 1587 ip.ip_src.s_addr = aaddr; 1588 if (nat64_check_ip4(ip.ip_src.s_addr) != 0) { 1589 DPRINTF(DP_GENERIC | DP_DROPS, "invalid source address: %08x", 1590 ip.ip_src.s_addr); 1591 NAT64STAT_INC(&cfg->stats, dropped); 1592 return (NAT64MFREE); 1593 } 1594 1595 ip.ip_dst.s_addr = nat64_extract_ip4(&ip6->ip6_dst, cfg->plat_plen); 1596 if (ip.ip_dst.s_addr == 0) { 1597 NAT64STAT_INC(&cfg->stats, dropped); 1598 return (NAT64MFREE); 1599 } 1600 1601 if (*V_nat64ip6stealth == 0 && ip6->ip6_hlim <= IPV6_HLIMDEC) { 1602 nat64_icmp6_reflect(m, ICMP6_TIME_EXCEEDED, 1603 ICMP6_TIME_EXCEED_TRANSIT, 0, &cfg->stats, logdata); 1604 return (NAT64RETURN); 1605 } 1606 1607 hlen = 0; 1608 plen = ntohs(ip6->ip6_plen); 1609 proto = nat64_getlasthdr(m, &hlen); 1610 if (proto < 0) { 1611 DPRINTF(DP_DROPS, "dropped due to mbuf isn't contigious"); 1612 NAT64STAT_INC(&cfg->stats, dropped); 1613 return (NAT64MFREE); 1614 } 1615 frag = NULL; 1616 if (proto == IPPROTO_FRAGMENT) { 1617 /* ipfw_chk should m_pullup up to frag header */ 1618 if (m->m_len < hlen + sizeof(*frag)) { 1619 DPRINTF(DP_DROPS, 1620 "dropped due to mbuf isn't contigious"); 1621 NAT64STAT_INC(&cfg->stats, dropped); 1622 return (NAT64MFREE); 1623 } 1624 frag = mtodo(m, hlen); 1625 proto = frag->ip6f_nxt; 1626 hlen += sizeof(*frag); 1627 /* Fragmented ICMPv6 is unsupported */ 1628 if (proto == IPPROTO_ICMPV6) { 1629 DPRINTF(DP_DROPS, "dropped due to fragmented ICMPv6"); 1630 NAT64STAT_INC(&cfg->stats, dropped); 1631 return (NAT64MFREE); 1632 } 1633 /* Fragment length must be multiple of 8 octets */ 1634 if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0 && 1635 ((plen + sizeof(struct ip6_hdr) - hlen) & 0x7) != 0) { 1636 nat64_icmp6_reflect(m, ICMP6_PARAM_PROB, 1637 ICMP6_PARAMPROB_HEADER, 1638 offsetof(struct ip6_hdr, ip6_plen), &cfg->stats, 1639 logdata); 1640 return (NAT64RETURN); 1641 } 1642 } 1643 plen -= hlen - sizeof(struct ip6_hdr); 1644 if (plen < 0 || m->m_pkthdr.len < plen + hlen) { 1645 DPRINTF(DP_DROPS, "plen %d, pkthdr.len %d, hlen %d", 1646 plen, m->m_pkthdr.len, hlen); 1647 NAT64STAT_INC(&cfg->stats, dropped); 1648 return (NAT64MFREE); 1649 } 1650 1651 icmp6 = NULL; /* Make gcc happy */ 1652 if (proto == IPPROTO_ICMPV6) { 1653 icmp6 = mtodo(m, hlen); 1654 if (icmp6->icmp6_type != ICMP6_ECHO_REQUEST && 1655 icmp6->icmp6_type != ICMP6_ECHO_REPLY) 1656 return (nat64_handle_icmp6(m, hlen, aaddr, aport, 1657 cfg, logdata)); 1658 } 1659 dst.sin_addr.s_addr = ip.ip_dst.s_addr; 1660 nh = nat64_find_route4(&dst, m); 1661 if (nh == NULL) { 1662 NAT64STAT_INC(&cfg->stats, noroute4); 1663 nat64_icmp6_reflect(m, ICMP6_DST_UNREACH, 1664 ICMP6_DST_UNREACH_NOROUTE, 0, &cfg->stats, logdata); 1665 return (NAT64RETURN); 1666 } 1667 if (nh->nh_mtu < plen + sizeof(ip)) { 1668 nat64_icmp6_reflect(m, ICMP6_PACKET_TOO_BIG, 0, nh->nh_mtu, 1669 &cfg->stats, logdata); 1670 return (NAT64RETURN); 1671 } 1672 nat64_init_ip4hdr(ip6, frag, plen, proto, &ip); 1673 1674 /* Handle delayed checksums if needed. */ 1675 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { 1676 in6_delayed_cksum(m, plen, hlen); 1677 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; 1678 } 1679 /* Convert checksums. */ 1680 switch (proto) { 1681 case IPPROTO_TCP: 1682 csum = &TCP(mtodo(m, hlen))->th_sum; 1683 if (aport != 0) { 1684 struct tcphdr *tcp = TCP(mtodo(m, hlen)); 1685 *csum = cksum_adjust(*csum, tcp->th_sport, aport); 1686 tcp->th_sport = aport; 1687 } 1688 *csum = cksum_add(*csum, nat64_cksum_convert(ip6, &ip)); 1689 break; 1690 case IPPROTO_UDP: 1691 csum = &UDP(mtodo(m, hlen))->uh_sum; 1692 if (aport != 0) { 1693 struct udphdr *udp = UDP(mtodo(m, hlen)); 1694 *csum = cksum_adjust(*csum, udp->uh_sport, aport); 1695 udp->uh_sport = aport; 1696 } 1697 *csum = cksum_add(*csum, nat64_cksum_convert(ip6, &ip)); 1698 break; 1699 case IPPROTO_ICMPV6: 1700 /* Checksum in ICMPv6 covers pseudo header */ 1701 csum = &icmp6->icmp6_cksum; 1702 *csum = cksum_add(*csum, in6_cksum_pseudo(ip6, plen, 1703 IPPROTO_ICMPV6, 0)); 1704 /* Convert ICMPv6 types to ICMP */ 1705 proto = *(uint16_t *)icmp6; /* save old word for cksum_adjust */ 1706 if (icmp6->icmp6_type == ICMP6_ECHO_REQUEST) 1707 icmp6->icmp6_type = ICMP_ECHO; 1708 else /* ICMP6_ECHO_REPLY */ 1709 icmp6->icmp6_type = ICMP_ECHOREPLY; 1710 *csum = cksum_adjust(*csum, (uint16_t)proto, 1711 *(uint16_t *)icmp6); 1712 if (aport != 0) { 1713 uint16_t old_id = icmp6->icmp6_id; 1714 icmp6->icmp6_id = aport; 1715 *csum = cksum_adjust(*csum, old_id, aport); 1716 } 1717 break; 1718 }; 1719 1720 m_adj(m, hlen - sizeof(ip)); 1721 bcopy(&ip, mtod(m, void *), sizeof(ip)); 1722 if (V_nat64out->output(nh->nh_ifp, m, (struct sockaddr *)&dst, 1723 &cfg->stats, logdata) == 0) 1724 NAT64STAT_INC(&cfg->stats, opcnt64); 1725 return (NAT64RETURN); 1726 } 1727