2 * Copyright (c) 2018-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * Copyright (c) 2001 Daniel Hartmeier
31 * Copyright (c) 2002 - 2013 Henning Brauer
32 * NAT64 - Copyright (c) 2010 Viagenie Inc. (http://www.viagenie.ca)
33 * All rights reserved.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
39 * - Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * - Redistributions in binary form must reproduce the above
42 * copyright notice, this list of conditions and the following
43 * disclaimer in the documentation and/or other materials provided
44 * with the distribution.
46 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
47 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
48 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
49 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
50 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
52 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
53 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
54 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
56 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57 * POSSIBILITY OF SUCH DAMAGE.
59 * Effort sponsored in part by the Defense Advanced Research Projects
60 * Agency (DARPA) and Air Force Research Laboratory, Air Force
61 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
64 #include <sys/param.h>
65 #include <sys/types.h>
69 #include <net/if_types.h>
71 #include <net/nat464_utils.h>
72 #include <net/nwk_wq.h>
74 #include <netinet/in.h>
75 #include <netinet/in_var.h>
76 #include <netinet/in_systm.h>
77 #include <netinet/ip.h>
78 #include <netinet/ip6.h>
79 #include <netinet/ip_var.h>
80 #include <netinet/ip_icmp.h>
81 #include <netinet/in_pcb.h>
82 #include <netinet/icmp_var.h>
83 #include <netinet/icmp6.h>
84 #include <netinet/tcp.h>
85 #include <netinet/udp.h>
86 #include <netinet/udp_var.h>
91 os_log_t nat_log_handle
;
94 nat464_addr_cksum_fixup(uint16_t *, struct nat464_addr
*, struct nat464_addr
*,
95 protocol_family_t
, protocol_family_t
, uint8_t, boolean_t
);
97 /* Synthesize ipv6 from ipv4 */
99 nat464_synthesize_ipv6(ifnet_t ifp
, const struct in_addr
*addrv4
, struct in6_addr
*addr
)
101 static const struct in6_addr well_known_prefix
= {
102 .__u6_addr
.__u6_addr8
= {0x00, 0x64, 0xff, 0x9b, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00},
107 struct ipv6_prefix nat64prefixes
[NAT64_MAX_NUM_PREFIXES
];
108 int error
= 0, i
= 0;
109 /* Below call is not optimized as it creates a copy of prefixes */
110 if ((error
= ifnet_get_nat64prefix(ifp
, nat64prefixes
)) != 0) {
114 for (i
= 0; i
< NAT64_MAX_NUM_PREFIXES
; i
++) {
115 if (nat64prefixes
[i
].prefix_len
!= 0) {
120 VERIFY(i
< NAT64_MAX_NUM_PREFIXES
);
122 struct in6_addr prefix
= nat64prefixes
[i
].ipv6_prefix
;
123 int prefix_len
= nat64prefixes
[i
].prefix_len
;
125 char *ptrv4
= __DECONST(char *, addrv4
);
126 char *ptr
= __DECONST(char *, addr
);
128 if (IN_ZERONET(ntohl(addrv4
->s_addr
)) || // 0.0.0.0/8 Source hosts on local network
129 IN_LOOPBACK(ntohl(addrv4
->s_addr
)) || // 127.0.0.0/8 Loopback
130 IN_LINKLOCAL(ntohl(addrv4
->s_addr
)) || // 169.254.0.0/16 Link Local
131 IN_DS_LITE(ntohl(addrv4
->s_addr
)) || // 192.0.0.0/29 DS-Lite
132 IN_6TO4_RELAY_ANYCAST(ntohl(addrv4
->s_addr
)) || // 192.88.99.0/24 6to4 Relay Anycast
133 IN_MULTICAST(ntohl(addrv4
->s_addr
)) || // 224.0.0.0/4 Multicast
134 INADDR_BROADCAST
== addrv4
->s_addr
) { // 255.255.255.255/32 Limited Broadcast
138 /* Check for the well-known prefix */
139 if (prefix_len
== NAT64_PREFIX_LEN_96
&&
140 IN6_ARE_ADDR_EQUAL(&prefix
, &well_known_prefix
)) { // https://tools.ietf.org/html/rfc6052#section-3.1
141 if (IN_PRIVATE(ntohl(addrv4
->s_addr
)) || // 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 Private-Use
142 IN_SHARED_ADDRESS_SPACE(ntohl(addrv4
->s_addr
))) { // 100.64.0.0/10 Shared Address Space
147 memcpy(ptr
, (char *)&prefix
, prefix_len
);
149 switch (prefix_len
) {
150 case NAT64_PREFIX_LEN_96
:
151 memcpy(ptr
+ 12, ptrv4
, 4);
153 case NAT64_PREFIX_LEN_64
:
154 memcpy(ptr
+ 9, ptrv4
, 4);
156 case NAT64_PREFIX_LEN_56
:
157 memcpy(ptr
+ 7, ptrv4
, 1);
158 memcpy(ptr
+ 9, ptrv4
+ 1, 3);
160 case NAT64_PREFIX_LEN_48
:
161 memcpy(ptr
+ 6, ptrv4
, 2);
162 memcpy(ptr
+ 9, ptrv4
+ 2, 2);
164 case NAT64_PREFIX_LEN_40
:
165 memcpy(ptr
+ 5, ptrv4
, 3);
166 memcpy(ptr
+ 9, ptrv4
+ 3, 1);
168 case NAT64_PREFIX_LEN_32
:
169 memcpy(ptr
+ 4, ptrv4
, 4);
172 panic("NAT64-prefix len is wrong: %u\n", prefix_len
);
176 char buf
[MAX_IPv6_STR_LEN
];
177 clat_log2((LOG_DEBUG
, "%s synthesized %s\n", __func__
,
178 inet_ntop(AF_INET6
, (void *)addr
, buf
, sizeof(buf
))));
184 /* Synthesize ipv4 from ipv6 */
186 nat464_synthesize_ipv4(ifnet_t ifp
, const struct in6_addr
*addr
, struct in_addr
*addrv4
)
188 struct ipv6_prefix nat64prefixes
[NAT64_MAX_NUM_PREFIXES
];
189 int error
= 0, i
= 0;
191 /* Below call is not optimized as it creates a copy of prefixes */
192 if ((error
= ifnet_get_nat64prefix(ifp
, nat64prefixes
)) != 0) {
196 for (i
= 0; i
< NAT64_MAX_NUM_PREFIXES
; i
++) {
197 if (nat64prefixes
[i
].prefix_len
!= 0) {
202 VERIFY(i
< NAT64_MAX_NUM_PREFIXES
);
204 struct in6_addr prefix
= nat64prefixes
[i
].ipv6_prefix
;
205 int prefix_len
= nat64prefixes
[i
].prefix_len
;
207 char *ptrv4
= __DECONST(void *, addrv4
);
208 char *ptr
= __DECONST(void *, addr
);
210 if (memcmp(addr
, &prefix
, prefix_len
) != 0) {
214 switch (prefix_len
) {
215 case NAT64_PREFIX_LEN_96
:
216 memcpy(ptrv4
, ptr
+ 12, 4);
218 case NAT64_PREFIX_LEN_64
:
219 memcpy(ptrv4
, ptr
+ 9, 4);
221 case NAT64_PREFIX_LEN_56
:
222 memcpy(ptrv4
, ptr
+ 7, 1);
223 memcpy(ptrv4
+ 1, ptr
+ 9, 3);
225 case NAT64_PREFIX_LEN_48
:
226 memcpy(ptrv4
, ptr
+ 6, 2);
227 memcpy(ptrv4
+ 2, ptr
+ 9, 2);
229 case NAT64_PREFIX_LEN_40
:
230 memcpy(ptrv4
, ptr
+ 5, 3);
231 memcpy(ptrv4
+ 3, ptr
+ 9, 1);
233 case NAT64_PREFIX_LEN_32
:
234 memcpy(ptrv4
, ptr
+ 4, 4);
237 panic("NAT64-prefix len is wrong: %u\n",
242 char buf
[MAX_IPv4_STR_LEN
];
243 clat_log2((LOG_DEBUG
, "%s desynthesized to %s\n", __func__
,
244 inet_ntop(AF_INET
, (void *)addrv4
, buf
, sizeof(buf
))));
249 #define PTR_IP(field) ((int32_t)offsetof(struct ip, field))
250 #define PTR_IP6(field) ((int32_t)offsetof(struct ip6_hdr, field))
253 * Translate the ICMP header
256 nat464_translate_icmp(int naf
, void *arg
)
259 struct icmp6_hdr
*icmp6
;
268 type
= icmp6
->icmp6_type
;
269 code
= icmp6
->icmp6_code
;
270 mtu
= ntohl(icmp6
->icmp6_mtu
);
273 case ICMP6_ECHO_REQUEST
:
276 case ICMP6_ECHO_REPLY
:
277 type
= ICMP_ECHOREPLY
;
279 case ICMP6_DST_UNREACH
:
282 case ICMP6_DST_UNREACH_NOROUTE
:
283 case ICMP6_DST_UNREACH_BEYONDSCOPE
:
284 case ICMP6_DST_UNREACH_ADDR
:
285 code
= ICMP_UNREACH_HOST
;
287 case ICMP6_DST_UNREACH_ADMIN
:
288 code
= ICMP_UNREACH_HOST_PROHIB
;
290 case ICMP6_DST_UNREACH_NOPORT
:
291 code
= ICMP_UNREACH_PORT
;
297 case ICMP6_PACKET_TOO_BIG
:
299 code
= ICMP_UNREACH_NEEDFRAG
;
302 case ICMP6_TIME_EXCEEDED
:
303 type
= ICMP_TIMXCEED
;
305 case ICMP6_PARAM_PROB
:
307 case ICMP6_PARAMPROB_HEADER
:
308 type
= ICMP_PARAMPROB
;
309 code
= ICMP_PARAMPROB_ERRATPTR
;
310 ptr
= ntohl(icmp6
->icmp6_pptr
);
312 if (ptr
== PTR_IP6(ip6_vfc
)) {
314 } else if (ptr
== PTR_IP6(ip6_vfc
) + 1) {
315 ptr
= PTR_IP(ip_tos
);
316 } else if (ptr
== PTR_IP6(ip6_plen
) ||
317 ptr
== PTR_IP6(ip6_plen
) + 1) {
318 ptr
= PTR_IP(ip_len
);
319 } else if (ptr
== PTR_IP6(ip6_nxt
)) {
321 } else if (ptr
== PTR_IP6(ip6_hlim
)) {
322 ptr
= PTR_IP(ip_ttl
);
323 } else if (ptr
>= PTR_IP6(ip6_src
) &&
324 ptr
< PTR_IP6(ip6_dst
)) {
325 ptr
= PTR_IP(ip_src
);
326 } else if (ptr
>= PTR_IP6(ip6_dst
) &&
327 ptr
< (int32_t)sizeof(struct ip6_hdr
)) {
328 ptr
= PTR_IP(ip_dst
);
333 case ICMP6_PARAMPROB_NEXTHEADER
:
335 code
= ICMP_UNREACH_PROTOCOL
;
344 icmp6
->icmp6_type
= type
;
345 icmp6
->icmp6_code
= code
;
346 /* aligns well with a icmpv4 nextmtu */
347 icmp6
->icmp6_mtu
= htonl(mtu
);
348 /* icmpv4 pptr is a one most significant byte */
350 icmp6
->icmp6_pptr
= htonl(ptr
<< 24);
356 type
= icmp4
->icmp_type
;
357 code
= icmp4
->icmp_code
;
358 mtu
= ntohs(icmp4
->icmp_nextmtu
);
362 type
= ICMP6_ECHO_REQUEST
;
365 type
= ICMP6_ECHO_REPLY
;
368 type
= ICMP6_DST_UNREACH
;
370 case ICMP_UNREACH_NET
:
371 case ICMP_UNREACH_HOST
:
372 case ICMP_UNREACH_NET_UNKNOWN
:
373 case ICMP_UNREACH_HOST_UNKNOWN
:
374 case ICMP_UNREACH_ISOLATED
:
375 case ICMP_UNREACH_TOSNET
:
376 case ICMP_UNREACH_TOSHOST
:
377 code
= ICMP6_DST_UNREACH_NOROUTE
;
379 case ICMP_UNREACH_PORT
:
380 code
= ICMP6_DST_UNREACH_NOPORT
;
382 case ICMP_UNREACH_NET_PROHIB
:
383 case ICMP_UNREACH_HOST_PROHIB
:
384 case ICMP_UNREACH_FILTER_PROHIB
:
385 case ICMP_UNREACH_PRECEDENCE_CUTOFF
:
386 code
= ICMP6_DST_UNREACH_ADMIN
;
388 case ICMP_UNREACH_PROTOCOL
:
389 type
= ICMP6_PARAM_PROB
;
390 code
= ICMP6_PARAMPROB_NEXTHEADER
;
391 ptr
= offsetof(struct ip6_hdr
, ip6_nxt
);
393 case ICMP_UNREACH_NEEDFRAG
:
394 type
= ICMP6_PACKET_TOO_BIG
;
397 * Make sure we don't overflow adjusting for
398 * translation overhead.
399 * If we do, just work with a lower mtu as is.
401 if (mtu
<= (UINT16_MAX
- CLAT46_HDR_EXPANSION_OVERHD
)) {
402 mtu
+= CLAT46_HDR_EXPANSION_OVERHD
;
410 type
= ICMP6_TIME_EXCEEDED
;
413 type
= ICMP6_PARAM_PROB
;
415 case ICMP_PARAMPROB_ERRATPTR
:
416 code
= ICMP6_PARAMPROB_HEADER
;
418 case ICMP_PARAMPROB_LENGTH
:
419 code
= ICMP6_PARAMPROB_HEADER
;
425 ptr
= icmp4
->icmp_pptr
;
426 if (ptr
== 0 || ptr
== PTR_IP(ip_tos
)) {
428 } else if (ptr
== PTR_IP(ip_len
) ||
429 ptr
== PTR_IP(ip_len
) + 1) {
430 ptr
= PTR_IP6(ip6_plen
);
431 } else if (ptr
== PTR_IP(ip_ttl
)) {
432 ptr
= PTR_IP6(ip6_hlim
);
433 } else if (ptr
== PTR_IP(ip_p
)) {
434 ptr
= PTR_IP6(ip6_nxt
);
435 } else if (ptr
>= PTR_IP(ip_src
) &&
436 ptr
< PTR_IP(ip_dst
)) {
437 ptr
= PTR_IP6(ip6_src
);
438 } else if (ptr
>= PTR_IP(ip_dst
) &&
439 ptr
< (int32_t)sizeof(struct ip
)) {
440 ptr
= PTR_IP6(ip6_dst
);
448 icmp4
->icmp_type
= type
;
449 icmp4
->icmp_code
= code
;
450 icmp4
->icmp_nextmtu
= htons((uint16_t)mtu
);
453 icmp4
->icmp_void
= htonl(ptr
);
462 * @brief This routine is called to perform address family translation on the
463 * inner IP header (that may come as payload) of an ICMP(v4/v6) error
466 * @param pbuf Pointer to packet buffer
467 * @param off Points to end of ICMP header
468 * @param tot_len Pointer to total length of the outer IP header
469 * @param off2 Points to end of inner IP header
470 * @param proto2 Inner IP proto field
471 * @param ttl2 Inner IP ttl field
472 * @param tot_len2 Inner IP total length
473 * @param src Pointer to the generic v4/v6 src address
474 * @param dst Pointer to the generic v4/v6 dst address
475 * @param af Old protocol family
476 * @param naf New protocol family
478 * @return -1 on error and 0 on success
481 nat464_translate_icmp_ip(pbuf_t
*pbuf
, uint16_t off
, uint16_t *tot_len
, uint16_t *off2
,
482 uint8_t proto2
, uint8_t ttl2
, uint16_t tot_len2
, struct nat464_addr
*src
,
483 struct nat464_addr
*dst
, protocol_family_t af
, protocol_family_t naf
)
485 struct ip
*ip4
= NULL
;
486 struct ip6_hdr
*ip6
= NULL
;
488 int hlen
= 0, olen
= 0;
490 if (af
== naf
|| (af
!= AF_INET
&& af
!= AF_INET6
) ||
491 (naf
!= AF_INET
&& naf
!= AF_INET6
)) {
498 hlen
= naf
== PF_INET
? sizeof(*ip4
) : sizeof(*ip6
);
500 /* Modify the pbuf to accommodate the new header */
501 hdr
= pbuf_resize_segment(pbuf
, off
, olen
, hlen
);
506 /* translate inner ip/ip6 header */
510 bzero(ip4
, sizeof(*ip4
));
511 ip4
->ip_v
= IPVERSION
;
512 ip4
->ip_hl
= sizeof(*ip4
) >> 2;
513 ip4
->ip_len
= htons((uint16_t)(sizeof(*ip4
) + tot_len2
- olen
));
514 ip4
->ip_id
= rfc6864
? 0 : htons(ip_randomid());
515 ip4
->ip_off
= htons(IP_DF
);
517 if (proto2
== IPPROTO_ICMPV6
) {
518 ip4
->ip_p
= IPPROTO_ICMP
;
522 ip4
->ip_src
= src
->natv4addr
;
523 ip4
->ip_dst
= dst
->natv4addr
;
524 ip4
->ip_sum
= pbuf_inet_cksum(pbuf
, 0, 0, ip4
->ip_hl
<< 2);
527 char buf
[MAX_IPv4_STR_LEN
];
528 clat_log2((LOG_DEBUG
, "%s translated to IPv4 (inner) "
529 "ip_len: %#x ip_p: %d ip_sum: %#x ip_src: %s ip_dst: %s \n",
530 __func__
, ntohs(ip4
->ip_len
), ip4
->ip_p
, ntohs(ip4
->ip_sum
),
531 inet_ntop(AF_INET
, (void *)&ip4
->ip_src
, buf
, sizeof(buf
)),
532 inet_ntop(AF_INET
, (void *)&ip4
->ip_dst
, buf
, sizeof(buf
))));
537 bzero(ip6
, sizeof(*ip6
));
538 ip6
->ip6_vfc
= IPV6_VERSION
;
539 ip6
->ip6_plen
= htons((uint16_t)(tot_len2
- olen
));
540 if (proto2
== IPPROTO_ICMP
) {
541 ip6
->ip6_nxt
= IPPROTO_ICMPV6
;
543 ip6
->ip6_nxt
= proto2
;
545 if (!ttl2
|| ttl2
> IPV6_DEFHLIM
) {
546 ip6
->ip6_hlim
= IPV6_DEFHLIM
;
548 ip6
->ip6_hlim
= ttl2
;
550 ip6
->ip6_src
= src
->natv6addr
;
551 ip6
->ip6_dst
= dst
->natv6addr
;
554 char buf2
[MAX_IPv6_STR_LEN
];
555 clat_log2((LOG_DEBUG
, "%s translated to IPv6 (inner) "
556 "ip6_plen: %#x ip6_nxt: %d ip6_src: %s ip6_dst: %s \n",
557 __func__
, ntohs(ip6
->ip6_plen
), ip6
->ip6_nxt
,
558 inet_ntop(AF_INET6
, (void *)&ip6
->ip6_src
, buf2
, sizeof(buf2
)),
559 inet_ntop(AF_INET6
, (void *)&ip6
->ip6_dst
, buf2
, sizeof(buf2
))));
564 /* adjust payload offset and total packet length */
565 *off2
+= hlen
- olen
;
566 *tot_len
+= hlen
- olen
;
571 * @brief The function inserts IPv6 fragmentation header
572 * and populates it with the passed parameters.
574 * @param pbuf Pointer to the packet buffer
575 * @param ip_id IP identifier (in network byte order)
576 * @param frag_offset Fragment offset (in network byte order)
577 * @param is_last_frag Boolean indicating if the fragment header is for
578 * last fragment or not.
580 * @return -1 on error and 0 on success.
583 nat464_insert_frag46(pbuf_t
*pbuf
, uint16_t ip_id_val
, uint16_t frag_offset
,
584 boolean_t is_last_frag
)
586 struct ip6_frag
*p_ip6_frag
= NULL
;
587 struct ip6_hdr
*p_ip6h
= NULL
;
589 /* Insert IPv6 fragmentation header */
590 if (pbuf_resize_segment(pbuf
, sizeof(struct ip6_hdr
), 0,
591 sizeof(struct ip6_frag
)) == NULL
) {
595 p_ip6h
= mtod(pbuf
->pb_mbuf
, struct ip6_hdr
*);
596 p_ip6_frag
= (struct ip6_frag
*)pbuf_contig_segment(pbuf
,
597 sizeof(struct ip6_hdr
), sizeof(struct ip6_frag
));
599 if (p_ip6_frag
== NULL
) {
603 /* Populate IPv6 fragmentation header */
604 p_ip6_frag
->ip6f_nxt
= p_ip6h
->ip6_nxt
;
605 p_ip6_frag
->ip6f_reserved
= 0;
606 p_ip6_frag
->ip6f_offlg
= (uint16_t)(frag_offset
<< 3);
608 p_ip6_frag
->ip6f_offlg
|= 0x1;
610 p_ip6_frag
->ip6f_offlg
= htons(p_ip6_frag
->ip6f_offlg
);
611 p_ip6_frag
->ip6f_ident
= ip_id_val
;
613 /* Update IPv6 header */
614 p_ip6h
->ip6_nxt
= IPPROTO_FRAGMENT
;
615 p_ip6h
->ip6_plen
= htons(ntohs(p_ip6h
->ip6_plen
) +
616 sizeof(struct ip6_frag
));
622 nat464_translate_64(pbuf_t
*pbuf
, int off
, uint8_t tos
,
623 uint8_t *proto
, uint8_t ttl
, struct in_addr src_v4
,
624 struct in_addr dst_v4
, uint64_t tot_len
, boolean_t
*p_is_first_frag
)
627 struct ip6_frag
*p_frag6
= NULL
;
628 struct ip6_frag frag6
= {};
629 boolean_t is_frag
= FALSE
;
630 uint16_t ip_frag_off
= 0;
633 * ip_input asserts for rcvif to be not NULL
634 * That may not be true for two corner cases
635 * 1. If for some reason a local app sends DNS
636 * AAAA query to local host
637 * 2. If IPv6 stack in kernel internally generates a
638 * message destined for a synthesized IPv6 end-point.
640 if (pbuf
->pb_ifp
== NULL
) {
644 if (*proto
== IPPROTO_FRAGMENT
) {
645 p_frag6
= (struct ip6_frag
*)pbuf_contig_segment(pbuf
,
646 sizeof(struct ip6_hdr
), sizeof(struct ip6_frag
));
647 if (p_frag6
== NULL
) {
648 ip6stat
.ip6s_clat464_in_64frag_transfail_drop
++;
654 *proto
= frag6
.ip6f_nxt
;
655 off
+= sizeof(struct ip6_frag
);
657 ip_frag_off
= (ntohs(frag6
.ip6f_offlg
& IP6F_OFF_MASK
)) >> 3;
658 if (ip_frag_off
!= 0) {
659 *p_is_first_frag
= FALSE
;
663 ip4
= (struct ip
*)pbuf_resize_segment(pbuf
, 0, off
, sizeof(*ip4
));
670 ip4
->ip_len
= htons((uint16_t)(sizeof(*ip4
) + (tot_len
- off
)));
676 ip4
->ip_src
= src_v4
;
677 ip4
->ip_dst
= dst_v4
;
680 * https://tools.ietf.org/html/rfc7915#section-5.1.1
681 * Identification: Copied from the low-order 16 bits in the
682 * Identification field in the Fragment Header.
684 ip4
->ip_id
= ntohl(frag6
.ip6f_ident
) & 0xffff;
685 ip4
->ip_id
= htons(ip4
->ip_id
);
686 if (frag6
.ip6f_offlg
& IP6F_MORE_FRAG
) {
687 ip_frag_off
|= IP_MF
;
689 ip4
->ip_off
= htons(ip_frag_off
);
691 ip4
->ip_off
|= htons(IP_DF
);
695 * Defer calculating ip_sum for ICMPv6 as we do it
696 * later in Protocol translation
698 if (*proto
!= IPPROTO_ICMPV6
) {
699 ip4
->ip_sum
= pbuf_inet_cksum(pbuf
, 0, 0, ip4
->ip_hl
<< 2);
703 char buf1
[MAX_IPv4_STR_LEN
], buf2
[MAX_IPv4_STR_LEN
];
704 clat_log2((LOG_DEBUG
, "%s translated to IPv4 ip_len: %#x "
705 "ip_p: %d ip_sum: %#x ip_src: %s ip_dst: %s \n", __func__
,
706 ntohs(ip4
->ip_len
), ip4
->ip_p
, ntohs(ip4
->ip_sum
),
707 inet_ntop(AF_INET
, (void *)&ip4
->ip_src
, buf1
, sizeof(buf1
)),
708 inet_ntop(AF_INET
, (void *)&ip4
->ip_dst
, buf2
, sizeof(buf2
))));
713 * @brief The routine translates the IPv4 header to IPv6 header.
715 * @param pbuf Pointer to the generic packet buffer
716 * @param off Offset to the end of IP header
717 * @param tos Type of service
718 * @param proto Protocol running over IP
719 * @param ttl Time to live
720 * @param src_v6 Source IPv6 address
721 * @param dst_v6 Destination IPv6 address
722 * @param tot_len Total payload length
724 * @return NT_NAT64 if IP header translation is successful, else error
727 nat464_translate_46(pbuf_t
*pbuf
, uint16_t off
, uint8_t tos
,
728 uint8_t proto
, uint8_t ttl
, struct in6_addr src_v6
,
729 struct in6_addr dst_v6
, uint16_t tot_len
)
733 if (pbuf
->pb_ifp
== NULL
) {
738 * Trim the buffer from head of size equal to to off (which is equal to
739 * the size of IP header and prepend IPv6 header length to the buffer
741 ip6
= (struct ip6_hdr
*)pbuf_resize_segment(pbuf
, 0, off
, sizeof(*ip6
));
745 ip6
->ip6_flow
= htonl((6 << 28) | (tos
<< 20));
746 ip6
->ip6_plen
= htons(tot_len
- off
);
747 ip6
->ip6_nxt
= proto
;
749 ip6
->ip6_src
= src_v6
;
750 ip6
->ip6_dst
= dst_v6
;
753 char buf1
[MAX_IPv6_STR_LEN
], buf2
[MAX_IPv6_STR_LEN
];
754 clat_log2((LOG_DEBUG
, "%s translated to IPv6 ip6_plen: %#x "
755 " ip6_nxt: %d ip6_src: %s ip6_dst: %s \n", __func__
,
756 ntohs(ip6
->ip6_plen
), ip6
->ip6_nxt
,
757 inet_ntop(AF_INET6
, (void *)&ip6
->ip6_src
, buf1
, sizeof(buf1
)),
758 inet_ntop(AF_INET6
, (void *)&ip6
->ip6_dst
, buf2
, sizeof(buf2
))));
763 /* Handle the next protocol checksum */
765 * @brief This routine translates the Proto running over IP and updates the checksum
766 * for IP header translation. It also updates pbuf checksum flags and related fields.
768 * @param pbuf Pointer to protocol buffer
769 * @param nsrc New source address
770 * @param ndst New destination address
771 * @param af Old family
772 * @param naf New family
777 nat464_translate_proto(pbuf_t
*pbuf
, struct nat464_addr
*osrc
,
778 struct nat464_addr
*odst
, uint8_t oproto
, protocol_family_t af
,
779 protocol_family_t naf
, int direction
, boolean_t only_csum
)
781 struct ip
*iph
= NULL
;
782 struct ip6_hdr
*ip6h
= NULL
;
783 uint16_t hlen
= 0, plen
= 0;
784 uint16_t tot_len
= 0;
785 void *nsrc
= NULL
, *ndst
= NULL
;
787 uint16_t *psum
= NULL
;
788 boolean_t do_ones_complement
= FALSE
;
790 /* For now these routines only support 464 translations */
792 VERIFY(af
== PF_INET
|| af
== PF_INET6
);
795 * For now out must be for v4 to v6 translation
796 * and in must be for v6 to v4 translation.
801 hlen
= (uint16_t)(iph
->ip_hl
<< 2);
802 plen
= ntohs(iph
->ip_len
) - hlen
;
803 tot_len
= ntohs(iph
->ip_len
);
810 ip6h
= pbuf
->pb_data
;
811 hlen
= (uint16_t)sizeof(*ip6h
);
812 plen
= ntohs(ip6h
->ip6_plen
);
813 tot_len
= hlen
+ plen
;
814 nsrc
= &ip6h
->ip6_src
;
815 ndst
= &ip6h
->ip6_dst
;
816 proto
= &ip6h
->ip6_nxt
;
820 return NT_DROP
; /* We should never come here */
823 if (*proto
!= oproto
) {
828 * We may want to manipulate csum flags in some cases
829 * and not act on the protocol header as it may not
830 * carry protocol checksums.
831 * For example, fragments other than the first one would
832 * not carry protocol headers.
836 * Only translate ICMP proto in the header
837 * and adjust checksums
839 if (*proto
== IPPROTO_ICMP
) {
840 if (naf
!= PF_INET6
) {
844 *proto
= IPPROTO_ICMPV6
;
845 } else if (*proto
== IPPROTO_ICMPV6
) {
846 if (naf
!= PF_INET
) {
850 *proto
= IPPROTO_ICMP
;
851 /* Recalculate IP checksum as proto field has changed */
853 iph
->ip_sum
= pbuf_inet_cksum(pbuf
, 0, 0, hlen
);
860 struct udphdr
*uh
= (struct udphdr
*)pbuf_contig_segment(pbuf
, hlen
,
867 if (!(*pbuf
->pb_csum_flags
& (CSUM_UDP
| CSUM_PARTIAL
)) &&
868 uh
->uh_sum
== 0 && af
== PF_INET
&& naf
== PF_INET6
) {
869 uh
->uh_sum
= pbuf_inet6_cksum(pbuf
, IPPROTO_UDP
,
870 hlen
, ntohs(ip6h
->ip6_plen
));
871 if (uh
->uh_sum
== 0) {
881 struct tcphdr
*th
= (struct tcphdr
*)pbuf_contig_segment(pbuf
, hlen
,
894 * Translate the protocol header, update IP header if needed,
895 * calculate checksums and update the checksum flags.
903 * If it is a locally generated and has CSUM flags set
904 * for TCP and UDP it means we have pseudo header checksum
905 * that has not yet been one's complemented.
907 if (direction
== NT_OUT
&&
908 (*pbuf
->pb_csum_flags
& CSUM_DELAY_DATA
)) {
909 do_ones_complement
= TRUE
;
912 nat464_addr_cksum_fixup(psum
, osrc
, (struct nat464_addr
*)nsrc
,
913 af
, naf
, (*proto
== IPPROTO_UDP
) ? 1 : 0, do_ones_complement
);
914 nat464_addr_cksum_fixup(psum
, odst
, (struct nat464_addr
*)ndst
,
915 af
, naf
, (*proto
== IPPROTO_UDP
) ? 1 : 0, do_ones_complement
);
920 if (naf
!= PF_INET6
) { /* allow only v6 as naf for ICMP */
924 struct icmp
*icmph
= NULL
;
925 struct icmp6_hdr
*icmp6h
= NULL
;
926 uint16_t ip2off
= 0, hlen2
= 0, tot_len2
= 0;
928 icmph
= (struct icmp
*) pbuf_contig_segment(pbuf
, hlen
,
934 /* Translate the ICMP header */
935 if (nat464_translate_icmp(PF_INET6
, icmph
) != 0) {
939 *proto
= IPPROTO_ICMPV6
;
940 icmp6h
= (struct icmp6_hdr
*)(uintptr_t)icmph
;
941 pbuf_copy_back(pbuf
, hlen
, sizeof(struct icmp6_hdr
),
944 /*Translate the inner IP header only for error messages */
945 if (ICMP6_ERRORTYPE(icmp6h
->icmp6_type
)) {
946 ip2off
= (uint16_t)(hlen
+ sizeof(*icmp6h
));
947 struct ip
*iph2
= NULL
;
948 iph2
= (struct ip
*) pbuf_contig_segment(pbuf
, ip2off
,
954 hlen2
= (uint16_t)(ip2off
+ (iph2
->ip_hl
<< 2));
955 tot_len2
= ntohs(iph2
->ip_len
);
957 /* Destination in outer IP should be Source in inner IP */
958 VERIFY(IN_ARE_ADDR_EQUAL(&odst
->natv4addr
, &iph2
->ip_src
));
959 if (nat464_translate_icmp_ip(pbuf
, ip2off
, &tot_len
,
960 &hlen2
, iph2
->ip_p
, iph2
->ip_ttl
, tot_len2
,
961 (struct nat464_addr
*)ndst
, (struct nat464_addr
*)nsrc
,
962 PF_INET
, PF_INET6
) != 0) {
965 /* Update total length/payload length for outer header */
968 iph
->ip_len
= htons(tot_len
);
971 ip6h
->ip6_plen
= htons(tot_len
- hlen
);
977 icmp6h
->icmp6_cksum
= 0;
978 icmp6h
->icmp6_cksum
= pbuf_inet6_cksum(pbuf
, IPPROTO_ICMPV6
, hlen
,
979 ntohs(ip6h
->ip6_plen
));
981 clat_log2((LOG_DEBUG
, "%s translated to ICMPV6 type: %d "
982 "code: %d checksum: %#x \n", __func__
, icmp6h
->icmp6_type
,
983 icmp6h
->icmp6_code
, icmp6h
->icmp6_cksum
));
990 { if (naf
!= PF_INET
) { /* allow only v4 as naf for ICMPV6 */
994 struct icmp6_hdr
*icmp6h
= NULL
;
995 struct icmp
*icmph
= NULL
;
996 uint16_t ip2off
= 0, hlen2
= 0, tot_len2
= 0;
998 icmp6h
= (struct icmp6_hdr
*) pbuf_contig_segment(pbuf
, hlen
,
1000 if (icmp6h
== NULL
) {
1004 /* Translate the ICMP header */
1005 if (nat464_translate_icmp(PF_INET
, icmp6h
) != 0) {
1009 *proto
= IPPROTO_ICMP
;
1010 icmph
= (struct icmp
*)(uintptr_t)icmp6h
;
1011 pbuf_copy_back(pbuf
, hlen
, ICMP_MINLEN
,
1014 /*Translate the inner IP header only for error messages */
1015 if (ICMP_ERRORTYPE(icmph
->icmp_type
)) {
1016 ip2off
= hlen
+ ICMP_MINLEN
;
1017 struct ip6_hdr
*iph2
= NULL
;
1018 iph2
= (struct ip6_hdr
*) pbuf_contig_segment(pbuf
, ip2off
,
1024 /* hlen2 points to end of inner IP header from the beginning */
1025 hlen2
= ip2off
+ sizeof(struct ip6_hdr
);
1026 tot_len2
= ntohs(iph2
->ip6_plen
) + sizeof(struct ip6_hdr
);
1028 if (nat464_translate_icmp_ip(pbuf
, ip2off
, &tot_len
,
1029 &hlen2
, iph2
->ip6_nxt
, iph2
->ip6_hlim
, tot_len2
,
1030 (struct nat464_addr
*)ndst
, (struct nat464_addr
*)nsrc
,
1031 PF_INET6
, PF_INET
) != 0) {
1035 /* Update total length for outer header */
1038 iph
->ip_len
= htons(tot_len
);
1041 ip6h
->ip6_plen
= htons(tot_len
- hlen
);
1046 /* Recalculate IP checksum as some IP fields might have changed */
1048 iph
->ip_sum
= pbuf_inet_cksum(pbuf
, 0, 0, iph
->ip_hl
<< 2);
1049 icmph
->icmp_cksum
= 0;
1050 icmph
->icmp_cksum
= pbuf_inet_cksum(pbuf
, 0, hlen
,
1051 ntohs(iph
->ip_len
) - hlen
);
1053 clat_log2((LOG_DEBUG
, "%s translated to ICMP type: %d "
1054 "code: %d checksum: %#x \n", __func__
, icmph
->icmp_type
,
1055 icmph
->icmp_code
, icmph
->icmp_cksum
));
1062 * https://tools.ietf.org/html/rfc7915#section-5.1.1
1063 * If the Next Header field of the Fragment Header is an
1064 * extension header (except ESP, but including the Authentication
1065 * Header (AH)), then the packet SHOULD be dropped and logged.
1067 case IPPROTO_HOPOPTS
:
1068 case IPPROTO_ROUTING
:
1069 case IPPROTO_DSTOPTS
:
1073 case IPPROTO_FRAGMENT
:
1075 * The fragment header is appended after or removed before
1076 * calling into this routine.
1087 /* Update checksum flags and offsets based on direction */
1088 if (direction
== NT_OUT
) {
1089 if ((*pbuf
->pb_csum_flags
& (CSUM_DATA_VALID
| CSUM_PARTIAL
)) ==
1090 (CSUM_DATA_VALID
| CSUM_PARTIAL
)) {
1091 (pbuf
->pb_mbuf
)->m_pkthdr
.csum_tx_start
+= CLAT46_HDR_EXPANSION_OVERHD
;
1092 (pbuf
->pb_mbuf
)->m_pkthdr
.csum_tx_stuff
+= CLAT46_HDR_EXPANSION_OVERHD
;
1095 if (*pbuf
->pb_csum_flags
& CSUM_TCP
) {
1096 *pbuf
->pb_csum_flags
|= CSUM_TCPIPV6
;
1098 if (*pbuf
->pb_csum_flags
& CSUM_UDP
) {
1099 *pbuf
->pb_csum_flags
|= CSUM_UDPIPV6
;
1101 if (*pbuf
->pb_csum_flags
& CSUM_FRAGMENT
) {
1102 *pbuf
->pb_csum_flags
|= CSUM_FRAGMENT_IPV6
;
1105 /* Clear IPv4 checksum flags */
1106 *pbuf
->pb_csum_flags
&= ~(CSUM_IP
| CSUM_IP_FRAGS
| CSUM_DELAY_DATA
| CSUM_FRAGMENT
);
1108 * If the packet requires TCP segmentation due to TSO offload,
1109 * then change the checksum flag to indicate that an IPv6
1110 * TCP segmentation is needed now.
1112 if (*pbuf
->pb_csum_flags
& CSUM_TSO_IPV4
) {
1113 *pbuf
->pb_csum_flags
&= ~CSUM_TSO_IPV4
;
1114 *pbuf
->pb_csum_flags
|= CSUM_TSO_IPV6
;
1116 } else if (direction
== NT_IN
) {
1117 /* XXX On input just reset csum flags */
1118 *pbuf
->pb_csum_flags
= 0; /* Reset all flags for now */
1120 /* Update csum flags and offsets for rx */
1121 if (*pbuf
->pb_csum_flags
& CSUM_PARTIAL
) {
1122 (pbuf
->pb_mbuf
)->m_pkthdr
.csum_rx_start
-= CLAT46_HDR_EXPANSION_OVERHD
;
1129 /* Fix the proto checksum for address change */
1131 nat464_addr_cksum_fixup(uint16_t *pc
, struct nat464_addr
*ao
, struct nat464_addr
*an
,
1132 protocol_family_t af
, protocol_family_t naf
, uint8_t u
, boolean_t do_ones_complement
)
1134 /* Currently we only support v4 to v6 and vice versa */
1141 if (do_ones_complement
) {
1142 *pc
= ~nat464_cksum_fixup(nat464_cksum_fixup(
1143 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(
1144 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(~*pc
,
1145 ao
->nataddr16
[0], an
->nataddr16
[0], u
),
1146 ao
->nataddr16
[1], an
->nataddr16
[1], u
),
1147 0, an
->nataddr16
[2], u
),
1148 0, an
->nataddr16
[3], u
),
1149 0, an
->nataddr16
[4], u
),
1150 0, an
->nataddr16
[5], u
),
1151 0, an
->nataddr16
[6], u
),
1152 0, an
->nataddr16
[7], u
);
1154 *pc
= nat464_cksum_fixup(nat464_cksum_fixup(
1155 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(
1156 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(*pc
,
1157 ao
->nataddr16
[0], an
->nataddr16
[0], u
),
1158 ao
->nataddr16
[1], an
->nataddr16
[1], u
),
1159 0, an
->nataddr16
[2], u
),
1160 0, an
->nataddr16
[3], u
),
1161 0, an
->nataddr16
[4], u
),
1162 0, an
->nataddr16
[5], u
),
1163 0, an
->nataddr16
[6], u
),
1164 0, an
->nataddr16
[7], u
);
1171 * XXX For NAT464 this only applies to the incoming path.
1172 * The checksum therefore is already ones complemented.
1173 * Therefore we just perform normal fixup.
1177 *pc
= nat464_cksum_fixup(nat464_cksum_fixup(
1178 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(
1179 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(*pc
,
1180 ao
->nataddr16
[0], an
->nataddr16
[0], u
),
1181 ao
->nataddr16
[1], an
->nataddr16
[1], u
),
1182 ao
->nataddr16
[2], 0, u
),
1183 ao
->nataddr16
[3], 0, u
),
1184 ao
->nataddr16
[4], 0, u
),
1185 ao
->nataddr16
[5], 0, u
),
1186 ao
->nataddr16
[6], 0, u
),
1187 ao
->nataddr16
[7], 0, u
);
1195 nat464_cksum_fixup(uint16_t cksum
, uint16_t old
, uint16_t new, uint8_t udp
)
1199 if (udp
&& !cksum
) {
1202 l
= cksum
+ old
- new;
1203 l
= (l
>> 16) + (l
& 0xffff);
1211 /* CLAT46 event handlers */
1213 in6_clat46_eventhdlr_callback(struct eventhandler_entry_arg arg0 __unused
,
1214 in6_clat46_evhdlr_code_t in6_clat46_ev_code
, pid_t epid
, uuid_t euuid
)
1216 struct kev_msg ev_msg
;
1217 struct kev_netevent_clat46_data clat46_event_data
;
1219 bzero(&ev_msg
, sizeof(ev_msg
));
1220 bzero(&clat46_event_data
, sizeof(clat46_event_data
));
1222 ev_msg
.vendor_code
= KEV_VENDOR_APPLE
;
1223 ev_msg
.kev_class
= KEV_NETWORK_CLASS
;
1224 ev_msg
.kev_subclass
= KEV_NETEVENT_SUBCLASS
;
1225 ev_msg
.event_code
= KEV_NETEVENT_CLAT46_EVENT
;
1227 bzero(&clat46_event_data
, sizeof(clat46_event_data
));
1228 clat46_event_data
.clat46_event_code
= in6_clat46_ev_code
;
1229 clat46_event_data
.epid
= epid
;
1230 uuid_copy(clat46_event_data
.euuid
, euuid
);
1232 ev_msg
.dv
[0].data_ptr
= &clat46_event_data
;
1233 ev_msg
.dv
[0].data_length
= sizeof(clat46_event_data
);
1235 kev_post_msg(&ev_msg
);
1239 in6_clat46_event_callback(void *arg
)
1241 struct kev_netevent_clat46_data
*p_in6_clat46_ev
=
1242 (struct kev_netevent_clat46_data
*)arg
;
1244 EVENTHANDLER_INVOKE(&in6_clat46_evhdlr_ctxt
, in6_clat46_event
,
1245 p_in6_clat46_ev
->clat46_event_code
, p_in6_clat46_ev
->epid
,
1246 p_in6_clat46_ev
->euuid
);
1249 struct in6_clat46_event_nwk_wq_entry
{
1250 struct nwk_wq_entry nwk_wqe
;
1251 struct kev_netevent_clat46_data in6_clat46_ev_arg
;
1255 in6_clat46_event_enqueue_nwk_wq_entry(in6_clat46_evhdlr_code_t in6_clat46_event_code
,
1256 pid_t epid
, uuid_t euuid
)
1258 struct in6_clat46_event_nwk_wq_entry
*p_ev
= NULL
;
1260 MALLOC(p_ev
, struct in6_clat46_event_nwk_wq_entry
*,
1261 sizeof(struct in6_clat46_event_nwk_wq_entry
),
1262 M_NWKWQ
, M_WAITOK
| M_ZERO
);
1264 p_ev
->nwk_wqe
.func
= in6_clat46_event_callback
;
1265 p_ev
->nwk_wqe
.is_arg_managed
= TRUE
;
1266 p_ev
->nwk_wqe
.arg
= &p_ev
->in6_clat46_ev_arg
;
1268 p_ev
->in6_clat46_ev_arg
.clat46_event_code
= in6_clat46_event_code
;
1269 p_ev
->in6_clat46_ev_arg
.epid
= epid
;
1270 uuid_copy(p_ev
->in6_clat46_ev_arg
.euuid
, euuid
);
1272 nwk_wq_enqueue((struct nwk_wq_entry
*)p_ev
);