2 * Copyright (c) 2018 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
;
403 type
= ICMP6_TIME_EXCEEDED
;
406 type
= ICMP6_PARAM_PROB
;
408 case ICMP_PARAMPROB_ERRATPTR
:
409 code
= ICMP6_PARAMPROB_HEADER
;
411 case ICMP_PARAMPROB_LENGTH
:
412 code
= ICMP6_PARAMPROB_HEADER
;
418 ptr
= icmp4
->icmp_pptr
;
419 if (ptr
== 0 || ptr
== PTR_IP(ip_tos
)) {
421 } else if (ptr
== PTR_IP(ip_len
) ||
422 ptr
== PTR_IP(ip_len
) + 1) {
423 ptr
= PTR_IP6(ip6_plen
);
424 } else if (ptr
== PTR_IP(ip_ttl
)) {
425 ptr
= PTR_IP6(ip6_hlim
);
426 } else if (ptr
== PTR_IP(ip_p
)) {
427 ptr
= PTR_IP6(ip6_nxt
);
428 } else if (ptr
>= PTR_IP(ip_src
) &&
429 ptr
< PTR_IP(ip_dst
)) {
430 ptr
= PTR_IP6(ip6_src
);
431 } else if (ptr
>= PTR_IP(ip_dst
) &&
432 ptr
< (int32_t)sizeof(struct ip
)) {
433 ptr
= PTR_IP6(ip6_dst
);
441 icmp4
->icmp_type
= type
;
442 icmp4
->icmp_code
= code
;
443 icmp4
->icmp_nextmtu
= htons(mtu
);
445 icmp4
->icmp_void
= htonl(ptr
);
454 * @brief This routine is called to perform address family translation on the
455 * inner IP header (that may come as payload) of an ICMP(v4/v6) error
458 * @param pbuf Pointer to packet buffer
459 * @param off Points to end of ICMP header
460 * @param tot_len Pointer to total length of the outer IP header
461 * @param off2 Points to end of inner IP header
462 * @param proto2 Inner IP proto field
463 * @param ttl2 Inner IP ttl field
464 * @param tot_len2 Inner IP total length
465 * @param src Pointer to the generic v4/v6 src address
466 * @param dst Pointer to the generic v4/v6 dst address
467 * @param af Old protocol family
468 * @param naf New protocol family
470 * @return -1 on error and 0 on success
473 nat464_translate_icmp_ip(pbuf_t
*pbuf
, uint32_t off
, uint64_t *tot_len
, uint32_t *off2
,
474 uint8_t proto2
, uint8_t ttl2
, uint64_t tot_len2
, struct nat464_addr
*src
,
475 struct nat464_addr
*dst
, protocol_family_t af
, protocol_family_t naf
)
477 struct ip
*ip4
= NULL
;
478 struct ip6_hdr
*ip6
= NULL
;
480 int hlen
= 0, olen
= 0;
482 if (af
== naf
|| (af
!= AF_INET
&& af
!= AF_INET6
) ||
483 (naf
!= AF_INET
&& naf
!= AF_INET6
)) {
490 hlen
= naf
== PF_INET
? sizeof(*ip4
) : sizeof(*ip6
);
492 /* Modify the pbuf to accommodate the new header */
493 hdr
= pbuf_resize_segment(pbuf
, off
, olen
, hlen
);
498 /* translate inner ip/ip6 header */
502 bzero(ip4
, sizeof(*ip4
));
503 ip4
->ip_v
= IPVERSION
;
504 ip4
->ip_hl
= sizeof(*ip4
) >> 2;
505 ip4
->ip_len
= htons(sizeof(*ip4
) + tot_len2
- olen
);
506 ip4
->ip_id
= rfc6864
? 0 : htons(ip_randomid());
507 ip4
->ip_off
= htons(IP_DF
);
509 if (proto2
== IPPROTO_ICMPV6
) {
510 ip4
->ip_p
= IPPROTO_ICMP
;
514 ip4
->ip_src
= src
->natv4addr
;
515 ip4
->ip_dst
= dst
->natv4addr
;
516 ip4
->ip_sum
= pbuf_inet_cksum(pbuf
, 0, 0, ip4
->ip_hl
<< 2);
519 char buf
[MAX_IPv4_STR_LEN
];
520 clat_log2((LOG_DEBUG
, "%s translated to IPv4 (inner) "
521 "ip_len: %#x ip_p: %d ip_sum: %#x ip_src: %s ip_dst: %s \n",
522 __func__
, ntohs(ip4
->ip_len
), ip4
->ip_p
, ntohs(ip4
->ip_sum
),
523 inet_ntop(AF_INET
, (void *)&ip4
->ip_src
, buf
, sizeof(buf
)),
524 inet_ntop(AF_INET
, (void *)&ip4
->ip_dst
, buf
, sizeof(buf
))));
529 bzero(ip6
, sizeof(*ip6
));
530 ip6
->ip6_vfc
= IPV6_VERSION
;
531 ip6
->ip6_plen
= htons(tot_len2
- olen
);
532 if (proto2
== IPPROTO_ICMP
) {
533 ip6
->ip6_nxt
= IPPROTO_ICMPV6
;
535 ip6
->ip6_nxt
= proto2
;
537 if (!ttl2
|| ttl2
> IPV6_DEFHLIM
) {
538 ip6
->ip6_hlim
= IPV6_DEFHLIM
;
540 ip6
->ip6_hlim
= ttl2
;
542 ip6
->ip6_src
= src
->natv6addr
;
543 ip6
->ip6_dst
= dst
->natv6addr
;
546 char buf2
[MAX_IPv6_STR_LEN
];
547 clat_log2((LOG_DEBUG
, "%s translated to IPv6 (inner) "
548 "ip6_plen: %#x ip6_nxt: %d ip6_src: %s ip6_dst: %s \n",
549 __func__
, ntohs(ip6
->ip6_plen
), ip6
->ip6_nxt
,
550 inet_ntop(AF_INET6
, (void *)&ip6
->ip6_src
, buf2
, sizeof(buf2
)),
551 inet_ntop(AF_INET6
, (void *)&ip6
->ip6_dst
, buf2
, sizeof(buf2
))));
556 /* adjust payload offset and total packet length */
557 *off2
+= hlen
- olen
;
558 *tot_len
+= hlen
- olen
;
563 * @brief The function inserts IPv6 fragmentation header
564 * and populates it with the passed parameters.
566 * @param pbuf Pointer to the packet buffer
567 * @param ip_id IP identifier (in network byte order)
568 * @param frag_offset Fragment offset (in network byte order)
569 * @param is_last_frag Boolean indicating if the fragment header is for
570 * last fragment or not.
572 * @return -1 on error and 0 on success.
575 nat464_insert_frag46(pbuf_t
*pbuf
, uint16_t ip_id_val
, uint16_t frag_offset
,
576 boolean_t is_last_frag
)
578 struct ip6_frag
*p_ip6_frag
= NULL
;
579 struct ip6_hdr
*p_ip6h
= NULL
;
581 /* Insert IPv6 fragmentation header */
582 if (pbuf_resize_segment(pbuf
, sizeof(struct ip6_hdr
), 0,
583 sizeof(struct ip6_frag
)) == NULL
) {
587 p_ip6h
= mtod(pbuf
->pb_mbuf
, struct ip6_hdr
*);
588 p_ip6_frag
= (struct ip6_frag
*)pbuf_contig_segment(pbuf
,
589 sizeof(struct ip6_hdr
), sizeof(struct ip6_frag
));
591 if (p_ip6_frag
== NULL
) {
595 /* Populate IPv6 fragmentation header */
596 p_ip6_frag
->ip6f_nxt
= p_ip6h
->ip6_nxt
;
597 p_ip6_frag
->ip6f_reserved
= 0;
598 p_ip6_frag
->ip6f_offlg
= (frag_offset
) << 3;
600 p_ip6_frag
->ip6f_offlg
|= 0x1;
602 p_ip6_frag
->ip6f_offlg
= htons(p_ip6_frag
->ip6f_offlg
);
603 p_ip6_frag
->ip6f_ident
= ip_id_val
;
605 /* Update IPv6 header */
606 p_ip6h
->ip6_nxt
= IPPROTO_FRAGMENT
;
607 p_ip6h
->ip6_plen
= htons(ntohs(p_ip6h
->ip6_plen
) +
608 sizeof(struct ip6_frag
));
614 nat464_translate_64(pbuf_t
*pbuf
, int off
, uint8_t tos
,
615 uint8_t *proto
, uint8_t ttl
, struct in_addr src_v4
,
616 struct in_addr dst_v4
, uint64_t tot_len
, boolean_t
*p_is_first_frag
)
619 struct ip6_frag
*p_frag6
= NULL
;
620 struct ip6_frag frag6
= {};
621 boolean_t is_frag
= FALSE
;
622 uint16_t ip_frag_off
= 0;
625 * ip_input asserts for rcvif to be not NULL
626 * That may not be true for two corner cases
627 * 1. If for some reason a local app sends DNS
628 * AAAA query to local host
629 * 2. If IPv6 stack in kernel internally generates a
630 * message destined for a synthesized IPv6 end-point.
632 if (pbuf
->pb_ifp
== NULL
) {
636 if (*proto
== IPPROTO_FRAGMENT
) {
637 p_frag6
= (struct ip6_frag
*)pbuf_contig_segment(pbuf
,
638 sizeof(struct ip6_hdr
), sizeof(struct ip6_frag
));
639 if (p_frag6
== NULL
) {
640 ip6stat
.ip6s_clat464_in_64frag_transfail_drop
++;
646 *proto
= frag6
.ip6f_nxt
;
647 off
+= sizeof(struct ip6_frag
);
649 ip_frag_off
= (ntohs(frag6
.ip6f_offlg
& IP6F_OFF_MASK
)) >> 3;
650 if (ip_frag_off
!= 0) {
651 *p_is_first_frag
= FALSE
;
655 ip4
= (struct ip
*)pbuf_resize_segment(pbuf
, 0, off
, sizeof(*ip4
));
662 ip4
->ip_len
= htons(sizeof(*ip4
) + (tot_len
- off
));
668 ip4
->ip_src
= src_v4
;
669 ip4
->ip_dst
= dst_v4
;
672 * https://tools.ietf.org/html/rfc7915#section-5.1.1
673 * Identification: Copied from the low-order 16 bits in the
674 * Identification field in the Fragment Header.
676 ip4
->ip_id
= ntohl(frag6
.ip6f_ident
) & 0xffff;
677 ip4
->ip_id
= htons(ip4
->ip_id
);
678 if (frag6
.ip6f_offlg
& IP6F_MORE_FRAG
) {
679 ip_frag_off
|= IP_MF
;
681 ip4
->ip_off
= htons(ip_frag_off
);
683 ip4
->ip_off
|= htons(IP_DF
);
687 * Defer calculating ip_sum for ICMPv6 as we do it
688 * later in Protocol translation
690 if (*proto
!= IPPROTO_ICMPV6
) {
691 ip4
->ip_sum
= pbuf_inet_cksum(pbuf
, 0, 0, ip4
->ip_hl
<< 2);
695 char buf1
[MAX_IPv4_STR_LEN
], buf2
[MAX_IPv4_STR_LEN
];
696 clat_log2((LOG_DEBUG
, "%s translated to IPv4 ip_len: %#x "
697 "ip_p: %d ip_sum: %#x ip_src: %s ip_dst: %s \n", __func__
,
698 ntohs(ip4
->ip_len
), ip4
->ip_p
, ntohs(ip4
->ip_sum
),
699 inet_ntop(AF_INET
, (void *)&ip4
->ip_src
, buf1
, sizeof(buf1
)),
700 inet_ntop(AF_INET
, (void *)&ip4
->ip_dst
, buf2
, sizeof(buf2
))));
705 * @brief The routine translates the IPv4 header to IPv6 header.
707 * @param pbuf Pointer to the generic packet buffer
708 * @param off Offset to the end of IP header
709 * @param tos Type of service
710 * @param proto Protocol running over IP
711 * @param ttl Time to live
712 * @param src_v6 Source IPv6 address
713 * @param dst_v6 Destination IPv6 address
714 * @param tot_len Total payload length
716 * @return NT_NAT64 if IP header translation is successful, else error
719 nat464_translate_46(pbuf_t
*pbuf
, int off
, uint8_t tos
,
720 uint8_t proto
, uint8_t ttl
, struct in6_addr src_v6
,
721 struct in6_addr dst_v6
, uint64_t tot_len
)
725 if (pbuf
->pb_ifp
== NULL
) {
730 * Trim the buffer from head of size equal to to off (which is equal to
731 * the size of IP header and prepend IPv6 header length to the buffer
733 ip6
= (struct ip6_hdr
*)pbuf_resize_segment(pbuf
, 0, off
, sizeof(*ip6
));
737 ip6
->ip6_flow
= htonl((6 << 28) | (tos
<< 20));
738 ip6
->ip6_plen
= htons(tot_len
- off
);
739 ip6
->ip6_nxt
= proto
;
741 ip6
->ip6_src
= src_v6
;
742 ip6
->ip6_dst
= dst_v6
;
745 char buf1
[MAX_IPv6_STR_LEN
], buf2
[MAX_IPv6_STR_LEN
];
746 clat_log2((LOG_DEBUG
, "%s translated to IPv6 ip6_plen: %#x "
747 " ip6_nxt: %d ip6_src: %s ip6_dst: %s \n", __func__
,
748 ntohs(ip6
->ip6_plen
), ip6
->ip6_nxt
,
749 inet_ntop(AF_INET6
, (void *)&ip6
->ip6_src
, buf1
, sizeof(buf1
)),
750 inet_ntop(AF_INET6
, (void *)&ip6
->ip6_dst
, buf2
, sizeof(buf2
))));
755 /* Handle the next protocol checksum */
757 * @brief This routine translates the Proto running over IP and updates the checksum
758 * for IP header translation. It also updates pbuf checksum flags and related fields.
760 * @param pbuf Pointer to protocol buffer
761 * @param nsrc New source address
762 * @param ndst New destination address
763 * @param af Old family
764 * @param naf New family
769 nat464_translate_proto(pbuf_t
*pbuf
, struct nat464_addr
*osrc
,
770 struct nat464_addr
*odst
, uint8_t oproto
, protocol_family_t af
,
771 protocol_family_t naf
, int direction
, boolean_t only_csum
)
773 struct ip
*iph
= NULL
;
774 struct ip6_hdr
*ip6h
= NULL
;
775 uint32_t hlen
= 0, plen
= 0;
776 uint64_t tot_len
= 0;
777 void *nsrc
= NULL
, *ndst
= NULL
;
779 uint16_t *psum
= NULL
;
780 boolean_t do_ones_complement
= FALSE
;
782 /* For now these routines only support 464 translations */
784 VERIFY(af
== PF_INET
|| af
== PF_INET6
);
787 * For now out must be for v4 to v6 translation
788 * and in must be for v6 to v4 translation.
793 hlen
= iph
->ip_hl
<< 2;
794 plen
= ntohs(iph
->ip_len
) - hlen
;
795 tot_len
= ntohs(iph
->ip_len
);
802 ip6h
= pbuf
->pb_data
;
803 hlen
= sizeof(*ip6h
);
804 plen
= ntohs(ip6h
->ip6_plen
);
805 tot_len
= hlen
+ plen
;
806 nsrc
= &ip6h
->ip6_src
;
807 ndst
= &ip6h
->ip6_dst
;
808 proto
= &ip6h
->ip6_nxt
;
812 return NT_DROP
; /* We should never come here */
815 if (*proto
!= oproto
) {
820 * We may want to manipulate csum flags in some cases
821 * and not act on the protocol header as it may not
822 * carry protocol checksums.
823 * For example, fragments other than the first one would
824 * not carry protocol headers.
828 * Only translate ICMP proto in the header
829 * and adjust checksums
831 if (*proto
== IPPROTO_ICMP
) {
832 if (naf
!= PF_INET6
) {
836 *proto
= IPPROTO_ICMPV6
;
837 } else if (*proto
== IPPROTO_ICMPV6
) {
838 if (naf
!= PF_INET
) {
842 *proto
= IPPROTO_ICMP
;
843 /* Recalculate IP checksum as proto field has changed */
845 iph
->ip_sum
= pbuf_inet_cksum(pbuf
, 0, 0, hlen
);
852 struct udphdr
*uh
= (struct udphdr
*)pbuf_contig_segment(pbuf
, hlen
,
859 if (!(*pbuf
->pb_csum_flags
& (CSUM_UDP
| CSUM_PARTIAL
)) &&
860 uh
->uh_sum
== 0 && af
== PF_INET
&& naf
== PF_INET6
) {
861 uh
->uh_sum
= pbuf_inet6_cksum(pbuf
, IPPROTO_UDP
,
862 hlen
, ntohs(ip6h
->ip6_plen
));
863 if (uh
->uh_sum
== 0) {
873 struct tcphdr
*th
= (struct tcphdr
*)pbuf_contig_segment(pbuf
, hlen
,
886 * Translate the protocol header, update IP header if needed,
887 * calculate checksums and update the checksum flags.
895 * If it is a locally generated and has CSUM flags set
896 * for TCP and UDP it means we have pseudo header checksum
897 * that has not yet been one's complemented.
899 if (direction
== NT_OUT
&&
900 (*pbuf
->pb_csum_flags
& CSUM_DELAY_DATA
)) {
901 do_ones_complement
= TRUE
;
904 nat464_addr_cksum_fixup(psum
, osrc
, (struct nat464_addr
*)nsrc
,
905 af
, naf
, (*proto
== IPPROTO_UDP
) ? 1 : 0, do_ones_complement
);
906 nat464_addr_cksum_fixup(psum
, odst
, (struct nat464_addr
*)ndst
,
907 af
, naf
, (*proto
== IPPROTO_UDP
) ? 1 : 0, do_ones_complement
);
912 if (naf
!= PF_INET6
) { /* allow only v6 as naf for ICMP */
916 struct icmp
*icmph
= NULL
;
917 struct icmp6_hdr
*icmp6h
= NULL
;
918 uint32_t ip2off
= 0, hlen2
= 0, tot_len2
= 0;
920 icmph
= (struct icmp
*) pbuf_contig_segment(pbuf
, hlen
,
926 /* Translate the ICMP header */
927 if (nat464_translate_icmp(PF_INET6
, icmph
) != 0) {
931 *proto
= IPPROTO_ICMPV6
;
932 icmp6h
= (struct icmp6_hdr
*)(uintptr_t)icmph
;
933 pbuf_copy_back(pbuf
, hlen
, sizeof(struct icmp6_hdr
),
936 /*Translate the inner IP header only for error messages */
937 if (ICMP6_ERRORTYPE(icmp6h
->icmp6_type
)) {
938 ip2off
= hlen
+ sizeof(*icmp6h
);
940 iph2
= (struct ip
*) pbuf_contig_segment(pbuf
, ip2off
,
946 hlen2
= ip2off
+ (iph2
->ip_hl
<< 2);
947 tot_len2
= ntohs(iph2
->ip_len
);
949 /* Destination in outer IP should be Source in inner IP */
950 VERIFY(IN_ARE_ADDR_EQUAL(&odst
->natv4addr
, &iph2
->ip_src
));
951 if (nat464_translate_icmp_ip(pbuf
, ip2off
, &tot_len
,
952 &hlen2
, iph2
->ip_p
, iph2
->ip_ttl
, tot_len2
,
953 (struct nat464_addr
*)ndst
, (struct nat464_addr
*)nsrc
,
954 PF_INET
, PF_INET6
) != 0) {
957 /* Update total length/payload length for outer header */
960 iph
->ip_len
= htons(tot_len
);
963 ip6h
->ip6_plen
= htons(tot_len
- hlen
);
969 icmp6h
->icmp6_cksum
= 0;
970 icmp6h
->icmp6_cksum
= pbuf_inet6_cksum(pbuf
, IPPROTO_ICMPV6
, hlen
,
971 ntohs(ip6h
->ip6_plen
));
973 clat_log2((LOG_DEBUG
, "%s translated to ICMPV6 type: %d "
974 "code: %d checksum: %#x \n", __func__
, icmp6h
->icmp6_type
,
975 icmp6h
->icmp6_code
, icmp6h
->icmp6_cksum
));
982 { if (naf
!= PF_INET
) { /* allow only v4 as naf for ICMPV6 */
986 struct icmp6_hdr
*icmp6h
= NULL
;
987 struct icmp
*icmph
= NULL
;
988 uint32_t ip2off
= 0, hlen2
= 0, tot_len2
= 0;
990 icmp6h
= (struct icmp6_hdr
*) pbuf_contig_segment(pbuf
, hlen
,
992 if (icmp6h
== NULL
) {
996 /* Translate the ICMP header */
997 if (nat464_translate_icmp(PF_INET
, icmp6h
) != 0) {
1001 *proto
= IPPROTO_ICMP
;
1002 icmph
= (struct icmp
*)(uintptr_t)icmp6h
;
1003 pbuf_copy_back(pbuf
, hlen
, ICMP_MINLEN
,
1006 /*Translate the inner IP header only for error messages */
1007 if (ICMP_ERRORTYPE(icmph
->icmp_type
)) {
1008 ip2off
= hlen
+ ICMP_MINLEN
;
1009 struct ip6_hdr
*iph2
;
1010 iph2
= (struct ip6_hdr
*) pbuf_contig_segment(pbuf
, ip2off
,
1016 /* hlen2 points to end of inner IP header from the beginning */
1017 hlen2
= ip2off
+ sizeof(struct ip6_hdr
);
1018 tot_len2
= ntohs(iph2
->ip6_plen
) + sizeof(struct ip6_hdr
);
1020 if (nat464_translate_icmp_ip(pbuf
, ip2off
, &tot_len
,
1021 &hlen2
, iph2
->ip6_nxt
, iph2
->ip6_hlim
, tot_len2
,
1022 (struct nat464_addr
*)ndst
, (struct nat464_addr
*)nsrc
,
1023 PF_INET6
, PF_INET
) != 0) {
1027 /* Update total length for outer header */
1030 iph
->ip_len
= htons(tot_len
);
1033 ip6h
->ip6_plen
= htons(tot_len
- hlen
);
1038 /* Recalculate IP checksum as some IP fields might have changed */
1040 iph
->ip_sum
= pbuf_inet_cksum(pbuf
, 0, 0, iph
->ip_hl
<< 2);
1041 icmph
->icmp_cksum
= 0;
1042 icmph
->icmp_cksum
= pbuf_inet_cksum(pbuf
, 0, hlen
,
1043 ntohs(iph
->ip_len
) - hlen
);
1045 clat_log2((LOG_DEBUG
, "%s translated to ICMP type: %d "
1046 "code: %d checksum: %#x \n", __func__
, icmph
->icmp_type
,
1047 icmph
->icmp_code
, icmph
->icmp_cksum
));
1054 * https://tools.ietf.org/html/rfc7915#section-5.1.1
1055 * If the Next Header field of the Fragment Header is an
1056 * extension header (except ESP, but including the Authentication
1057 * Header (AH)), then the packet SHOULD be dropped and logged.
1059 case IPPROTO_HOPOPTS
:
1060 case IPPROTO_ROUTING
:
1061 case IPPROTO_DSTOPTS
:
1065 case IPPROTO_FRAGMENT
:
1067 * The fragment header is appended after or removed before
1068 * calling into this routine.
1079 /* Update checksum flags and offsets based on direction */
1080 if (direction
== NT_OUT
) {
1081 if ((*pbuf
->pb_csum_flags
& (CSUM_DATA_VALID
| CSUM_PARTIAL
)) ==
1082 (CSUM_DATA_VALID
| CSUM_PARTIAL
)) {
1083 (pbuf
->pb_mbuf
)->m_pkthdr
.csum_tx_start
+= CLAT46_HDR_EXPANSION_OVERHD
;
1084 (pbuf
->pb_mbuf
)->m_pkthdr
.csum_tx_stuff
+= CLAT46_HDR_EXPANSION_OVERHD
;
1087 if (*pbuf
->pb_csum_flags
& CSUM_TCP
) {
1088 *pbuf
->pb_csum_flags
|= CSUM_TCPIPV6
;
1090 if (*pbuf
->pb_csum_flags
& CSUM_UDP
) {
1091 *pbuf
->pb_csum_flags
|= CSUM_UDPIPV6
;
1093 if (*pbuf
->pb_csum_flags
& CSUM_FRAGMENT
) {
1094 *pbuf
->pb_csum_flags
|= CSUM_FRAGMENT_IPV6
;
1097 /* Clear IPv4 checksum flags */
1098 *pbuf
->pb_csum_flags
&= ~(CSUM_IP
| CSUM_IP_FRAGS
| CSUM_DELAY_DATA
| CSUM_FRAGMENT
);
1099 } else if (direction
== NT_IN
) {
1100 /* XXX On input just reset csum flags */
1101 *pbuf
->pb_csum_flags
= 0; /* Reset all flags for now */
1103 /* Update csum flags and offsets for rx */
1104 if (*pbuf
->pb_csum_flags
& CSUM_PARTIAL
) {
1105 (pbuf
->pb_mbuf
)->m_pkthdr
.csum_rx_start
-= CLAT46_HDR_EXPANSION_OVERHD
;
1112 /* Fix the proto checksum for address change */
1114 nat464_addr_cksum_fixup(uint16_t *pc
, struct nat464_addr
*ao
, struct nat464_addr
*an
,
1115 protocol_family_t af
, protocol_family_t naf
, uint8_t u
, boolean_t do_ones_complement
)
1117 /* Currently we only support v4 to v6 and vice versa */
1124 if (do_ones_complement
) {
1125 *pc
= ~nat464_cksum_fixup(nat464_cksum_fixup(
1126 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(
1127 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(~*pc
,
1128 ao
->nataddr16
[0], an
->nataddr16
[0], u
),
1129 ao
->nataddr16
[1], an
->nataddr16
[1], u
),
1130 0, an
->nataddr16
[2], u
),
1131 0, an
->nataddr16
[3], u
),
1132 0, an
->nataddr16
[4], u
),
1133 0, an
->nataddr16
[5], u
),
1134 0, an
->nataddr16
[6], u
),
1135 0, an
->nataddr16
[7], u
);
1137 *pc
= nat464_cksum_fixup(nat464_cksum_fixup(
1138 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(
1139 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(*pc
,
1140 ao
->nataddr16
[0], an
->nataddr16
[0], u
),
1141 ao
->nataddr16
[1], an
->nataddr16
[1], u
),
1142 0, an
->nataddr16
[2], u
),
1143 0, an
->nataddr16
[3], u
),
1144 0, an
->nataddr16
[4], u
),
1145 0, an
->nataddr16
[5], u
),
1146 0, an
->nataddr16
[6], u
),
1147 0, an
->nataddr16
[7], u
);
1154 * XXX For NAT464 this only applies to the incoming path.
1155 * The checksum therefore is already ones complemented.
1156 * Therefore we just perform normal fixup.
1160 *pc
= nat464_cksum_fixup(nat464_cksum_fixup(
1161 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(
1162 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(*pc
,
1163 ao
->nataddr16
[0], an
->nataddr16
[0], u
),
1164 ao
->nataddr16
[1], an
->nataddr16
[1], u
),
1165 ao
->nataddr16
[2], 0, u
),
1166 ao
->nataddr16
[3], 0, u
),
1167 ao
->nataddr16
[4], 0, u
),
1168 ao
->nataddr16
[5], 0, u
),
1169 ao
->nataddr16
[6], 0, u
),
1170 ao
->nataddr16
[7], 0, u
);
1178 nat464_cksum_fixup(uint16_t cksum
, uint16_t old
, uint16_t new, uint8_t udp
)
1182 if (udp
&& !cksum
) {
1185 l
= cksum
+ old
- new;
1186 l
= (l
>> 16) + (l
& 0xffff);
1194 /* CLAT46 event handlers */
1196 in6_clat46_eventhdlr_callback(struct eventhandler_entry_arg arg0 __unused
,
1197 in6_clat46_evhdlr_code_t in6_clat46_ev_code
, pid_t epid
, uuid_t euuid
)
1199 struct kev_msg ev_msg
;
1200 struct kev_netevent_clat46_data clat46_event_data
;
1202 bzero(&ev_msg
, sizeof(ev_msg
));
1203 bzero(&clat46_event_data
, sizeof(clat46_event_data
));
1205 ev_msg
.vendor_code
= KEV_VENDOR_APPLE
;
1206 ev_msg
.kev_class
= KEV_NETWORK_CLASS
;
1207 ev_msg
.kev_subclass
= KEV_NETEVENT_SUBCLASS
;
1208 ev_msg
.event_code
= KEV_NETEVENT_CLAT46_EVENT
;
1210 bzero(&clat46_event_data
, sizeof(clat46_event_data
));
1211 clat46_event_data
.clat46_event_code
= in6_clat46_ev_code
;
1212 clat46_event_data
.epid
= epid
;
1213 uuid_copy(clat46_event_data
.euuid
, euuid
);
1215 ev_msg
.dv
[0].data_ptr
= &clat46_event_data
;
1216 ev_msg
.dv
[0].data_length
= sizeof(clat46_event_data
);
1218 kev_post_msg(&ev_msg
);
1222 in6_clat46_event_callback(void *arg
)
1224 struct kev_netevent_clat46_data
*p_in6_clat46_ev
=
1225 (struct kev_netevent_clat46_data
*)arg
;
1227 EVENTHANDLER_INVOKE(&in6_clat46_evhdlr_ctxt
, in6_clat46_event
,
1228 p_in6_clat46_ev
->clat46_event_code
, p_in6_clat46_ev
->epid
,
1229 p_in6_clat46_ev
->euuid
);
1232 struct in6_clat46_event_nwk_wq_entry
{
1233 struct nwk_wq_entry nwk_wqe
;
1234 struct kev_netevent_clat46_data in6_clat46_ev_arg
;
1238 in6_clat46_event_enqueue_nwk_wq_entry(in6_clat46_evhdlr_code_t in6_clat46_event_code
,
1239 pid_t epid
, uuid_t euuid
)
1241 struct in6_clat46_event_nwk_wq_entry
*p_ev
= NULL
;
1243 MALLOC(p_ev
, struct in6_clat46_event_nwk_wq_entry
*,
1244 sizeof(struct in6_clat46_event_nwk_wq_entry
),
1245 M_NWKWQ
, M_WAITOK
| M_ZERO
);
1247 p_ev
->nwk_wqe
.func
= in6_clat46_event_callback
;
1248 p_ev
->nwk_wqe
.is_arg_managed
= TRUE
;
1249 p_ev
->nwk_wqe
.arg
= &p_ev
->in6_clat46_ev_arg
;
1251 p_ev
->in6_clat46_ev_arg
.clat46_event_code
= in6_clat46_event_code
;
1252 p_ev
->in6_clat46_ev_arg
.epid
= epid
;
1253 uuid_copy(p_ev
->in6_clat46_ev_arg
.euuid
, euuid
);
1255 nwk_wq_enqueue((struct nwk_wq_entry
*)p_ev
);