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