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)
113 for (i
= 0; i
< NAT64_MAX_NUM_PREFIXES
; i
++) {
114 if (nat64prefixes
[i
].prefix_len
!= 0)
118 VERIFY (i
< NAT64_MAX_NUM_PREFIXES
);
120 struct in6_addr prefix
= nat64prefixes
[i
].ipv6_prefix
;
121 int prefix_len
= nat64prefixes
[i
].prefix_len
;
123 char *ptrv4
= __DECONST(char *, addrv4
);
124 char *ptr
= __DECONST(char *, addr
);
126 if (IN_ZERONET(ntohl(addrv4
->s_addr
)) || // 0.0.0.0/8 Source hosts on local network
127 IN_LOOPBACK(ntohl(addrv4
->s_addr
)) || // 127.0.0.0/8 Loopback
128 IN_LINKLOCAL(ntohl(addrv4
->s_addr
)) || // 169.254.0.0/16 Link Local
129 IN_DS_LITE(ntohl(addrv4
->s_addr
)) || // 192.0.0.0/29 DS-Lite
130 IN_6TO4_RELAY_ANYCAST(ntohl(addrv4
->s_addr
)) || // 192.88.99.0/24 6to4 Relay Anycast
131 IN_MULTICAST(ntohl(addrv4
->s_addr
)) || // 224.0.0.0/4 Multicast
132 INADDR_BROADCAST
== addrv4
->s_addr
) { // 255.255.255.255/32 Limited Broadcast
136 /* Check for the well-known prefix */
137 if (prefix_len
== NAT64_PREFIX_LEN_96
&&
138 IN6_ARE_ADDR_EQUAL(&prefix
, &well_known_prefix
)) { // https://tools.ietf.org/html/rfc6052#section-3.1
139 if (IN_PRIVATE(ntohl(addrv4
->s_addr
)) || // 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 Private-Use
140 IN_SHARED_ADDRESS_SPACE(ntohl(addrv4
->s_addr
))) // 100.64.0.0/10 Shared Address Space
144 memcpy(ptr
, (char *)&prefix
, prefix_len
);
146 switch (prefix_len
) {
147 case NAT64_PREFIX_LEN_96
:
148 memcpy(ptr
+ 12, ptrv4
, 4);
150 case NAT64_PREFIX_LEN_64
:
151 memcpy(ptr
+ 9, ptrv4
, 4);
153 case NAT64_PREFIX_LEN_56
:
154 memcpy(ptr
+ 7, ptrv4
, 1);
155 memcpy(ptr
+ 9, ptrv4
+ 1, 3);
157 case NAT64_PREFIX_LEN_48
:
158 memcpy(ptr
+ 6, ptrv4
, 2);
159 memcpy(ptr
+ 9, ptrv4
+ 2, 2);
161 case NAT64_PREFIX_LEN_40
:
162 memcpy(ptr
+ 5, ptrv4
, 3);
163 memcpy(ptr
+ 9, ptrv4
+ 3, 1);
165 case NAT64_PREFIX_LEN_32
:
166 memcpy(ptr
+ 4, ptrv4
, 4);
169 panic("NAT64-prefix len is wrong: %u\n", prefix_len
);
173 char buf
[MAX_IPv6_STR_LEN
];
174 clat_log2((LOG_DEBUG
, "%s synthesized %s\n", __func__
,
175 inet_ntop(AF_INET6
, (void *)addr
, buf
, sizeof(buf
))));
181 /* Synthesize ipv4 from ipv6 */
183 nat464_synthesize_ipv4(ifnet_t ifp
, const struct in6_addr
*addr
, struct in_addr
*addrv4
)
185 struct ipv6_prefix nat64prefixes
[NAT64_MAX_NUM_PREFIXES
];
186 int error
= 0, i
= 0;
188 /* Below call is not optimized as it creates a copy of prefixes */
189 if ((error
= ifnet_get_nat64prefix(ifp
, nat64prefixes
)) != 0)
192 for (i
= 0; i
< NAT64_MAX_NUM_PREFIXES
; i
++) {
193 if (nat64prefixes
[i
].prefix_len
!= 0)
197 VERIFY (i
< NAT64_MAX_NUM_PREFIXES
);
199 struct in6_addr prefix
= nat64prefixes
[i
].ipv6_prefix
;
200 int prefix_len
= nat64prefixes
[i
].prefix_len
;
202 char *ptrv4
= __DECONST(void *, addrv4
);
203 char *ptr
= __DECONST(void *, addr
);
205 if (memcmp(addr
, &prefix
, prefix_len
) != 0)
208 switch (prefix_len
) {
209 case NAT64_PREFIX_LEN_96
:
210 memcpy(ptrv4
, ptr
+ 12, 4);
212 case NAT64_PREFIX_LEN_64
:
213 memcpy(ptrv4
, ptr
+ 9, 4);
215 case NAT64_PREFIX_LEN_56
:
216 memcpy(ptrv4
, ptr
+ 7, 1);
217 memcpy(ptrv4
+ 1, ptr
+ 9, 3);
219 case NAT64_PREFIX_LEN_48
:
220 memcpy(ptrv4
, ptr
+ 6, 2);
221 memcpy(ptrv4
+ 2, ptr
+ 9, 2);
223 case NAT64_PREFIX_LEN_40
:
224 memcpy(ptrv4
, ptr
+ 5, 3);
225 memcpy(ptrv4
+ 3, ptr
+ 9, 1);
227 case NAT64_PREFIX_LEN_32
:
228 memcpy(ptrv4
, ptr
+ 4, 4);
231 panic("NAT64-prefix len is wrong: %u\n",
236 char buf
[MAX_IPv4_STR_LEN
];
237 clat_log2((LOG_DEBUG
, "%s desynthesized to %s\n", __func__
,
238 inet_ntop(AF_INET
, (void *)addrv4
, buf
, sizeof(buf
))));
243 #define PTR_IP(field) ((int32_t)offsetof(struct ip, field))
244 #define PTR_IP6(field) ((int32_t)offsetof(struct ip6_hdr, field))
247 Translate the ICMP header
250 nat464_translate_icmp(int naf
, void *arg
)
253 struct icmp6_hdr
*icmp6
;
262 type
= icmp6
->icmp6_type
;
263 code
= icmp6
->icmp6_code
;
264 mtu
= ntohl(icmp6
->icmp6_mtu
);
267 case ICMP6_ECHO_REQUEST
:
270 case ICMP6_ECHO_REPLY
:
271 type
= ICMP_ECHOREPLY
;
273 case ICMP6_DST_UNREACH
:
276 case ICMP6_DST_UNREACH_NOROUTE
:
277 case ICMP6_DST_UNREACH_BEYONDSCOPE
:
278 case ICMP6_DST_UNREACH_ADDR
:
279 code
= ICMP_UNREACH_HOST
;
281 case ICMP6_DST_UNREACH_ADMIN
:
282 code
= ICMP_UNREACH_HOST_PROHIB
;
284 case ICMP6_DST_UNREACH_NOPORT
:
285 code
= ICMP_UNREACH_PORT
;
291 case ICMP6_PACKET_TOO_BIG
:
293 code
= ICMP_UNREACH_NEEDFRAG
;
296 case ICMP6_TIME_EXCEEDED
:
297 type
= ICMP_TIMXCEED
;
299 case ICMP6_PARAM_PROB
:
301 case ICMP6_PARAMPROB_HEADER
:
302 type
= ICMP_PARAMPROB
;
303 code
= ICMP_PARAMPROB_ERRATPTR
;
304 ptr
= ntohl(icmp6
->icmp6_pptr
);
306 if (ptr
== PTR_IP6(ip6_vfc
))
308 else if (ptr
== PTR_IP6(ip6_vfc
) + 1)
309 ptr
= PTR_IP(ip_tos
);
310 else if (ptr
== PTR_IP6(ip6_plen
) ||
311 ptr
== PTR_IP6(ip6_plen
) + 1)
312 ptr
= PTR_IP(ip_len
);
313 else if (ptr
== PTR_IP6(ip6_nxt
))
315 else if (ptr
== PTR_IP6(ip6_hlim
))
316 ptr
= PTR_IP(ip_ttl
);
317 else if (ptr
>= PTR_IP6(ip6_src
) &&
318 ptr
< PTR_IP6(ip6_dst
))
319 ptr
= PTR_IP(ip_src
);
320 else if (ptr
>= PTR_IP6(ip6_dst
) &&
321 ptr
< (int32_t)sizeof(struct ip6_hdr
))
322 ptr
= PTR_IP(ip_dst
);
327 case ICMP6_PARAMPROB_NEXTHEADER
:
329 code
= ICMP_UNREACH_PROTOCOL
;
338 icmp6
->icmp6_type
= type
;
339 icmp6
->icmp6_code
= code
;
340 /* aligns well with a icmpv4 nextmtu */
341 icmp6
->icmp6_mtu
= htonl(mtu
);
342 /* icmpv4 pptr is a one most significant byte */
344 icmp6
->icmp6_pptr
= htonl(ptr
<< 24);
349 type
= icmp4
->icmp_type
;
350 code
= icmp4
->icmp_code
;
351 mtu
= ntohs(icmp4
->icmp_nextmtu
);
355 type
= ICMP6_ECHO_REQUEST
;
358 type
= ICMP6_ECHO_REPLY
;
361 type
= ICMP6_DST_UNREACH
;
363 case ICMP_UNREACH_NET
:
364 case ICMP_UNREACH_HOST
:
365 case ICMP_UNREACH_NET_UNKNOWN
:
366 case ICMP_UNREACH_HOST_UNKNOWN
:
367 case ICMP_UNREACH_ISOLATED
:
368 case ICMP_UNREACH_TOSNET
:
369 case ICMP_UNREACH_TOSHOST
:
370 code
= ICMP6_DST_UNREACH_NOROUTE
;
372 case ICMP_UNREACH_PORT
:
373 code
= ICMP6_DST_UNREACH_NOPORT
;
375 case ICMP_UNREACH_NET_PROHIB
:
376 case ICMP_UNREACH_HOST_PROHIB
:
377 case ICMP_UNREACH_FILTER_PROHIB
:
378 case ICMP_UNREACH_PRECEDENCE_CUTOFF
:
379 code
= ICMP6_DST_UNREACH_ADMIN
;
381 case ICMP_UNREACH_PROTOCOL
:
382 type
= ICMP6_PARAM_PROB
;
383 code
= ICMP6_PARAMPROB_NEXTHEADER
;
384 ptr
= offsetof(struct ip6_hdr
, ip6_nxt
);
386 case ICMP_UNREACH_NEEDFRAG
:
387 type
= ICMP6_PACKET_TOO_BIG
;
396 type
= ICMP6_TIME_EXCEEDED
;
399 type
= ICMP6_PARAM_PROB
;
401 case ICMP_PARAMPROB_ERRATPTR
:
402 code
= ICMP6_PARAMPROB_HEADER
;
404 case ICMP_PARAMPROB_LENGTH
:
405 code
= ICMP6_PARAMPROB_HEADER
;
411 ptr
= icmp4
->icmp_pptr
;
412 if (ptr
== 0 || ptr
== PTR_IP(ip_tos
))
414 else if (ptr
== PTR_IP(ip_len
) ||
415 ptr
== PTR_IP(ip_len
) + 1)
416 ptr
= PTR_IP6(ip6_plen
);
417 else if (ptr
== PTR_IP(ip_ttl
))
418 ptr
= PTR_IP6(ip6_hlim
);
419 else if (ptr
== PTR_IP(ip_p
))
420 ptr
= PTR_IP6(ip6_nxt
);
421 else if (ptr
>= PTR_IP(ip_src
) &&
422 ptr
< PTR_IP(ip_dst
))
423 ptr
= PTR_IP6(ip6_src
);
424 else if (ptr
>= PTR_IP(ip_dst
) &&
425 ptr
< (int32_t)sizeof(struct ip
))
426 ptr
= PTR_IP6(ip6_dst
);
434 icmp4
->icmp_type
= type
;
435 icmp4
->icmp_code
= code
;
436 icmp4
->icmp_nextmtu
= htons(mtu
);
438 icmp4
->icmp_void
= htonl(ptr
);
446 * @brief This routine is called to perform address family translation on the
447 * inner IP header (that may come as payload) of an ICMP(v4/v6) error
450 * @param pbuf Pointer to packet buffer
451 * @param off Points to end of ICMP header
452 * @param tot_len Pointer to total length of the outer IP header
453 * @param off2 Points to end of inner IP header
454 * @param proto2 Inner IP proto field
455 * @param ttl2 Inner IP ttl field
456 * @param tot_len2 Inner IP total length
457 * @param src Pointer to the generic v4/v6 src address
458 * @param dst Pointer to the generic v4/v6 dst address
459 * @param af Old protocol family
460 * @param naf New protocol family
462 * @return -1 on error and 0 on success
465 nat464_translate_icmp_ip(pbuf_t
*pbuf
, uint32_t off
, uint64_t *tot_len
, uint32_t *off2
,
466 uint8_t proto2
, uint8_t ttl2
, uint64_t tot_len2
, struct nat464_addr
*src
,
467 struct nat464_addr
*dst
, protocol_family_t af
, protocol_family_t naf
)
469 struct ip
*ip4
= NULL
;
470 struct ip6_hdr
*ip6
= NULL
;
472 int hlen
= 0, olen
= 0;
474 if (af
== naf
|| (af
!= AF_INET
&& af
!= AF_INET6
) ||
475 (naf
!= AF_INET
&& naf
!= AF_INET6
))
481 hlen
= naf
== PF_INET
? sizeof(*ip4
) : sizeof(*ip6
);
483 /* Modify the pbuf to accommodate the new header */
484 hdr
= pbuf_resize_segment(pbuf
, off
, olen
, hlen
);
488 /* translate inner ip/ip6 header */
492 bzero(ip4
, sizeof(*ip4
));
493 ip4
->ip_v
= IPVERSION
;
494 ip4
->ip_hl
= sizeof(*ip4
) >> 2;
495 ip4
->ip_len
= htons(sizeof(*ip4
) + tot_len2
- olen
);
496 ip4
->ip_id
= rfc6864
? 0 : htons(ip_randomid());
497 ip4
->ip_off
= htons(IP_DF
);
499 if (proto2
== IPPROTO_ICMPV6
)
500 ip4
->ip_p
= IPPROTO_ICMP
;
503 ip4
->ip_src
= src
->natv4addr
;
504 ip4
->ip_dst
= dst
->natv4addr
;
505 ip4
->ip_sum
= pbuf_inet_cksum(pbuf
, 0, 0, ip4
->ip_hl
<< 2);
508 char buf
[MAX_IPv4_STR_LEN
];
509 clat_log2((LOG_DEBUG
, "%s translated to IPv4 (inner) "
510 "ip_len: %#x ip_p: %d ip_sum: %#x ip_src: %s ip_dst: %s \n",
511 __func__
, ntohs(ip4
->ip_len
), ip4
->ip_p
, ntohs(ip4
->ip_sum
),
512 inet_ntop(AF_INET
, (void *)&ip4
->ip_src
, buf
, sizeof(buf
)),
513 inet_ntop(AF_INET
, (void *)&ip4
->ip_dst
, buf
, sizeof(buf
))));
518 bzero(ip6
, sizeof(*ip6
));
519 ip6
->ip6_vfc
= IPV6_VERSION
;
520 ip6
->ip6_plen
= htons(tot_len2
- olen
);
521 if (proto2
== IPPROTO_ICMP
)
522 ip6
->ip6_nxt
= IPPROTO_ICMPV6
;
524 ip6
->ip6_nxt
= proto2
;
525 if (!ttl2
|| ttl2
> IPV6_DEFHLIM
)
526 ip6
->ip6_hlim
= IPV6_DEFHLIM
;
528 ip6
->ip6_hlim
= ttl2
;
529 ip6
->ip6_src
= src
->natv6addr
;
530 ip6
->ip6_dst
= dst
->natv6addr
;
533 char buf2
[MAX_IPv6_STR_LEN
];
534 clat_log2((LOG_DEBUG
, "%s translated to IPv6 (inner) "
535 "ip6_plen: %#x ip6_nxt: %d ip6_src: %s ip6_dst: %s \n",
536 __func__
, ntohs(ip6
->ip6_plen
), ip6
->ip6_nxt
,
537 inet_ntop(AF_INET6
, (void *)&ip6
->ip6_src
, buf2
, sizeof(buf2
)),
538 inet_ntop(AF_INET6
, (void *)&ip6
->ip6_dst
, buf2
, sizeof(buf2
))));
543 /* adjust payload offset and total packet length */
544 *off2
+= hlen
- olen
;
545 *tot_len
+= hlen
- olen
;
550 * @brief The function inserts IPv6 fragmentation header
551 * and populates it with the passed parameters.
553 * @param pbuf Pointer to the packet buffer
554 * @param ip_id IP identifier (in network byte order)
555 * @param frag_offset Fragment offset (in network byte order)
556 * @param is_last_frag Boolean indicating if the fragment header is for
557 * last fragment or not.
559 * @return -1 on error and 0 on success.
562 nat464_insert_frag46(pbuf_t
*pbuf
, uint16_t ip_id_val
, uint16_t frag_offset
,
563 boolean_t is_last_frag
)
565 struct ip6_frag
*p_ip6_frag
= NULL
;
566 struct ip6_hdr
*p_ip6h
= NULL
;
568 /* Insert IPv6 fragmentation header */
569 if (pbuf_resize_segment(pbuf
, sizeof(struct ip6_hdr
), 0,
570 sizeof(struct ip6_frag
)) == NULL
)
573 p_ip6h
= mtod(pbuf
->pb_mbuf
, struct ip6_hdr
*);
574 p_ip6_frag
= (struct ip6_frag
*)pbuf_contig_segment(pbuf
,
575 sizeof(struct ip6_hdr
), sizeof(struct ip6_frag
));
577 if (p_ip6_frag
== NULL
)
580 /* Populate IPv6 fragmentation header */
581 p_ip6_frag
->ip6f_nxt
= p_ip6h
->ip6_nxt
;
582 p_ip6_frag
->ip6f_reserved
= 0;
583 p_ip6_frag
->ip6f_offlg
= (frag_offset
) << 3;
585 p_ip6_frag
->ip6f_offlg
|= 0x1;
586 p_ip6_frag
->ip6f_offlg
= htons(p_ip6_frag
->ip6f_offlg
);
587 p_ip6_frag
->ip6f_ident
= ip_id_val
;
589 /* Update IPv6 header */
590 p_ip6h
->ip6_nxt
= IPPROTO_FRAGMENT
;
591 p_ip6h
->ip6_plen
= htons(ntohs(p_ip6h
->ip6_plen
) +
592 sizeof(struct ip6_frag
));
598 nat464_translate_64(pbuf_t
*pbuf
, int off
, uint8_t tos
,
599 uint8_t *proto
, uint8_t ttl
, struct in_addr src_v4
,
600 struct in_addr dst_v4
, uint64_t tot_len
, boolean_t
*p_is_first_frag
)
603 struct ip6_frag
*p_frag6
= NULL
;
604 struct ip6_frag frag6
= {};
605 boolean_t is_frag
= FALSE
;
606 uint16_t ip_frag_off
= 0;
609 * ip_input asserts for rcvif to be not NULL
610 * That may not be true for two corner cases
611 * 1. If for some reason a local app sends DNS
612 * AAAA query to local host
613 * 2. If IPv6 stack in kernel internally generates a
614 * message destined for a synthesized IPv6 end-point.
616 if (pbuf
->pb_ifp
== NULL
)
619 if (*proto
== IPPROTO_FRAGMENT
) {
620 p_frag6
= (struct ip6_frag
*)pbuf_contig_segment(pbuf
,
621 sizeof(struct ip6_hdr
), sizeof(struct ip6_frag
));
622 if (p_frag6
== NULL
) {
623 ip6stat
.ip6s_clat464_in_64frag_transfail_drop
++;
629 *proto
= frag6
.ip6f_nxt
;
630 off
+= sizeof(struct ip6_frag
);
632 ip_frag_off
= (ntohs(frag6
.ip6f_offlg
& IP6F_OFF_MASK
)) >> 3;
633 if (ip_frag_off
!= 0) {
634 *p_is_first_frag
= FALSE
;
638 ip4
= (struct ip
*)pbuf_resize_segment(pbuf
, 0, off
, sizeof(*ip4
));
644 ip4
->ip_len
= htons(sizeof(*ip4
) + (tot_len
- off
));
650 ip4
->ip_src
= src_v4
;
651 ip4
->ip_dst
= dst_v4
;
654 * https://tools.ietf.org/html/rfc7915#section-5.1.1
655 * Identification: Copied from the low-order 16 bits in the
656 * Identification field in the Fragment Header.
658 ip4
->ip_id
= ntohl(frag6
.ip6f_ident
) & 0xffff;
659 ip4
->ip_id
= htons(ip4
->ip_id
);
660 if(frag6
.ip6f_offlg
& IP6F_MORE_FRAG
)
661 ip_frag_off
|= IP_MF
;
662 ip4
->ip_off
= htons(ip_frag_off
);
664 ip4
->ip_off
|= htons(IP_DF
);
668 * Defer calculating ip_sum for ICMPv6 as we do it
669 * later in Protocol translation
671 if (*proto
!= IPPROTO_ICMPV6
)
672 ip4
->ip_sum
= pbuf_inet_cksum(pbuf
, 0, 0, ip4
->ip_hl
<< 2);
675 char buf1
[MAX_IPv4_STR_LEN
], buf2
[MAX_IPv4_STR_LEN
];
676 clat_log2((LOG_DEBUG
, "%s translated to IPv4 ip_len: %#x "
677 "ip_p: %d ip_sum: %#x ip_src: %s ip_dst: %s \n", __func__
,
678 ntohs(ip4
->ip_len
), ip4
->ip_p
, ntohs(ip4
->ip_sum
),
679 inet_ntop(AF_INET
, (void *)&ip4
->ip_src
, buf1
, sizeof(buf1
)),
680 inet_ntop(AF_INET
, (void *)&ip4
->ip_dst
, buf2
, sizeof(buf2
))));
685 * @brief The routine translates the IPv4 header to IPv6 header.
687 * @param pbuf Pointer to the generic packet buffer
688 * @param off Offset to the end of IP header
689 * @param tos Type of service
690 * @param proto Protocol running over IP
691 * @param ttl Time to live
692 * @param src_v6 Source IPv6 address
693 * @param dst_v6 Destination IPv6 address
694 * @param tot_len Total payload length
696 * @return NT_NAT64 if IP header translation is successful, else error
699 nat464_translate_46(pbuf_t
*pbuf
, int off
, uint8_t tos
,
700 uint8_t proto
, uint8_t ttl
, struct in6_addr src_v6
,
701 struct in6_addr dst_v6
, uint64_t tot_len
)
705 if (pbuf
->pb_ifp
== NULL
)
709 * Trim the buffer from head of size equal to to off (which is equal to
710 * the size of IP header and prepend IPv6 header length to the buffer
712 ip6
= (struct ip6_hdr
*)pbuf_resize_segment(pbuf
, 0, off
, sizeof(*ip6
));
715 ip6
->ip6_flow
= htonl((6 << 28) | (tos
<< 20));
716 ip6
->ip6_plen
= htons(tot_len
- off
);
717 ip6
->ip6_nxt
= proto
;
719 ip6
->ip6_src
= src_v6
;
720 ip6
->ip6_dst
= dst_v6
;
723 char buf1
[MAX_IPv6_STR_LEN
], buf2
[MAX_IPv6_STR_LEN
];
724 clat_log2((LOG_DEBUG
, "%s translated to IPv6 ip6_plen: %#x "
725 " ip6_nxt: %d ip6_src: %s ip6_dst: %s \n", __func__
,
726 ntohs(ip6
->ip6_plen
), ip6
->ip6_nxt
,
727 inet_ntop(AF_INET6
, (void *)&ip6
->ip6_src
, buf1
, sizeof(buf1
)),
728 inet_ntop(AF_INET6
, (void *)&ip6
->ip6_dst
, buf2
, sizeof(buf2
))));
733 /* Handle the next protocol checksum */
735 * @brief This routine translates the Proto running over IP and updates the checksum
736 * for IP header translation. It also updates pbuf checksum flags and related fields.
738 * @param pbuf Pointer to protocol buffer
739 * @param nsrc New source address
740 * @param ndst New destination address
741 * @param af Old family
742 * @param naf New family
747 nat464_translate_proto(pbuf_t
*pbuf
, struct nat464_addr
*osrc
,
748 struct nat464_addr
*odst
, uint8_t oproto
, protocol_family_t af
,
749 protocol_family_t naf
, int direction
, boolean_t only_csum
)
751 struct ip
*iph
= NULL
;
752 struct ip6_hdr
*ip6h
= NULL
;
753 uint32_t hlen
= 0, plen
= 0;
754 uint64_t tot_len
= 0;
755 void *nsrc
= NULL
, *ndst
= NULL
;
757 uint16_t *psum
= NULL
;
758 boolean_t do_ones_complement
= FALSE
;
760 /* For now these routines only support 464 translations */
762 VERIFY(af
== PF_INET
|| af
== PF_INET6
);
765 * For now out must be for v4 to v6 translation
766 * and in must be for v6 to v4 translation.
771 hlen
= iph
->ip_hl
<< 2;
772 plen
= ntohs(iph
->ip_len
) - hlen
;
773 tot_len
= ntohs(iph
->ip_len
);
780 ip6h
= pbuf
->pb_data
;
781 hlen
= sizeof(*ip6h
);
782 plen
= ntohs(ip6h
->ip6_plen
);
783 tot_len
= hlen
+ plen
;
784 nsrc
= &ip6h
->ip6_src
;
785 ndst
= &ip6h
->ip6_dst
;
786 proto
= &ip6h
->ip6_nxt
;
791 VERIFY(*proto
== oproto
);
794 * We may want to manipulate csum flags in some cases
795 * and not act on the protocol header as it may not
796 * carry protocol checksums.
797 * For example, fragments other than the first one would
798 * not carry protocol headers.
802 * Only translate ICMP proto in the header
803 * and adjust checksums
805 if (*proto
== IPPROTO_ICMP
) {
809 *proto
= IPPROTO_ICMPV6
;
811 else if (*proto
== IPPROTO_ICMPV6
) {
815 *proto
= IPPROTO_ICMP
;
816 /* Recalculate IP checksum as proto field has changed */
818 iph
->ip_sum
= pbuf_inet_cksum(pbuf
, 0, 0, hlen
);
825 struct udphdr
*uh
= (struct udphdr
*)pbuf_contig_segment(pbuf
, hlen
,
831 if (!(*pbuf
->pb_csum_flags
& (CSUM_UDP
| CSUM_PARTIAL
)) &&
832 uh
->uh_sum
== 0 && af
== PF_INET
&& naf
== PF_INET6
) {
833 uh
->uh_sum
= pbuf_inet6_cksum(pbuf
, IPPROTO_UDP
,
834 hlen
, ntohs(ip6h
->ip6_plen
));
844 struct tcphdr
*th
= (struct tcphdr
*)pbuf_contig_segment(pbuf
, hlen
,
856 * Translate the protocol header, update IP header if needed,
857 * calculate checksums and update the checksum flags.
865 * If it is a locally generated and has CSUM flags set
866 * for TCP and UDP it means we have pseudo header checksum
867 * that has not yet been one's complemented.
869 if (direction
== NT_OUT
&&
870 (*pbuf
->pb_csum_flags
& CSUM_DELAY_DATA
))
871 do_ones_complement
= TRUE
;
873 nat464_addr_cksum_fixup(psum
, osrc
, (struct nat464_addr
*)nsrc
,
874 af
, naf
, (*proto
== IPPROTO_UDP
) ? 1 : 0, do_ones_complement
);
875 nat464_addr_cksum_fixup(psum
, odst
, (struct nat464_addr
*)ndst
,
876 af
, naf
, (*proto
== IPPROTO_UDP
) ? 1 : 0, do_ones_complement
);
881 if (naf
!= PF_INET6
) /* allow only v6 as naf for ICMP */
884 struct icmp
*icmph
= NULL
;
885 struct icmp6_hdr
*icmp6h
= NULL
;
886 uint32_t ip2off
= 0, hlen2
= 0, tot_len2
= 0;
888 icmph
= (struct icmp
*) pbuf_contig_segment(pbuf
, hlen
,
893 /* Translate the ICMP header */
894 if (nat464_translate_icmp(PF_INET6
, icmph
) != 0)
897 *proto
= IPPROTO_ICMPV6
;
898 icmp6h
= (struct icmp6_hdr
*)(uintptr_t)icmph
;
899 pbuf_copy_back(pbuf
, hlen
, sizeof(struct icmp6_hdr
),
902 /*Translate the inner IP header only for error messages */
903 if (ICMP6_ERRORTYPE(icmp6h
->icmp6_type
)) {
904 ip2off
= hlen
+ sizeof(*icmp6h
);
906 iph2
= (struct ip
*) pbuf_contig_segment(pbuf
, ip2off
,
911 hlen2
= ip2off
+ (iph2
->ip_hl
<< 2);
912 tot_len2
= ntohs(iph2
->ip_len
);
914 /* Destination in outer IP should be Source in inner IP */
915 VERIFY(IN_ARE_ADDR_EQUAL(&odst
->natv4addr
, &iph2
->ip_src
));
916 if (nat464_translate_icmp_ip(pbuf
, ip2off
, &tot_len
,
917 &hlen2
, iph2
->ip_p
, iph2
->ip_ttl
, tot_len2
,
918 (struct nat464_addr
*)ndst
, (struct nat464_addr
*)nsrc
,
919 PF_INET
, PF_INET6
) != 0)
921 /* Update total length/payload length for outer header */
924 iph
->ip_len
= htons(tot_len
);
927 ip6h
->ip6_plen
= htons(tot_len
- hlen
);
933 icmp6h
->icmp6_cksum
= 0;
934 icmp6h
->icmp6_cksum
= pbuf_inet6_cksum(pbuf
, IPPROTO_ICMPV6
, hlen
,
935 ntohs(ip6h
->ip6_plen
));
937 clat_log2((LOG_DEBUG
, "%s translated to ICMPV6 type: %d "
938 "code: %d checksum: %#x \n", __func__
, icmp6h
->icmp6_type
,
939 icmp6h
->icmp6_code
, icmp6h
->icmp6_cksum
));
946 { if (naf
!= PF_INET
) /* allow only v4 as naf for ICMPV6 */
949 struct icmp6_hdr
*icmp6h
= NULL
;
950 struct icmp
*icmph
= NULL
;
951 uint32_t ip2off
= 0, hlen2
= 0, tot_len2
= 0;
953 icmp6h
= (struct icmp6_hdr
*) pbuf_contig_segment(pbuf
, hlen
,
958 /* Translate the ICMP header */
959 if (nat464_translate_icmp(PF_INET
, icmp6h
) != 0)
962 *proto
= IPPROTO_ICMP
;
963 icmph
= (struct icmp
*)(uintptr_t)icmp6h
;
964 pbuf_copy_back(pbuf
, hlen
, ICMP_MINLEN
,
967 /*Translate the inner IP header only for error messages */
968 if (ICMP_ERRORTYPE(icmph
->icmp_type
)) {
969 ip2off
= hlen
+ ICMP_MINLEN
;
970 struct ip6_hdr
*iph2
;
971 iph2
= (struct ip6_hdr
*) pbuf_contig_segment(pbuf
, ip2off
,
976 /* hlen2 points to end of inner IP header from the beginning */
977 hlen2
= ip2off
+ sizeof(struct ip6_hdr
);
978 tot_len2
= ntohs(iph2
->ip6_plen
) + sizeof(struct ip6_hdr
);
980 if (nat464_translate_icmp_ip(pbuf
, ip2off
, &tot_len
,
981 &hlen2
, iph2
->ip6_nxt
, iph2
->ip6_hlim
, tot_len2
,
982 (struct nat464_addr
*)ndst
, (struct nat464_addr
*)nsrc
,
983 PF_INET6
, PF_INET
) != 0)
986 /* Update total length for outer header */
989 iph
->ip_len
= htons(tot_len
);
992 ip6h
->ip6_plen
= htons(tot_len
- hlen
);
997 /* Recalculate IP checksum as some IP fields might have changed */
999 iph
->ip_sum
= pbuf_inet_cksum(pbuf
, 0, 0, iph
->ip_hl
<< 2);
1000 icmph
->icmp_cksum
= 0;
1001 icmph
->icmp_cksum
= pbuf_inet_cksum(pbuf
, 0, hlen
,
1002 ntohs(iph
->ip_len
) - hlen
);
1004 clat_log2((LOG_DEBUG
, "%s translated to ICMP type: %d "
1005 "code: %d checksum: %#x \n", __func__
, icmph
->icmp_type
,
1006 icmph
->icmp_code
, icmph
->icmp_cksum
));
1014 * https://tools.ietf.org/html/rfc7915#section-5.1.1
1015 * If the Next Header field of the Fragment Header is an
1016 * extension header (except ESP, but including the Authentication
1017 * Header (AH)), then the packet SHOULD be dropped and logged.
1019 case IPPROTO_HOPOPTS
:
1020 case IPPROTO_ROUTING
:
1021 case IPPROTO_DSTOPTS
:
1025 case IPPROTO_FRAGMENT
:
1027 * The fragment header is appended after or removed before
1028 * calling into this routine.
1039 /* Update checksum flags and offsets based on direction */
1040 if (direction
== NT_OUT
) {
1041 if ((*pbuf
->pb_csum_flags
& (CSUM_DATA_VALID
| CSUM_PARTIAL
)) ==
1042 (CSUM_DATA_VALID
| CSUM_PARTIAL
)) {
1043 (pbuf
->pb_mbuf
)->m_pkthdr
.csum_tx_start
+= CLAT46_HDR_EXPANSION_OVERHD
;
1044 (pbuf
->pb_mbuf
)->m_pkthdr
.csum_tx_stuff
+= CLAT46_HDR_EXPANSION_OVERHD
;
1047 if(*pbuf
->pb_csum_flags
& CSUM_TCP
)
1048 *pbuf
->pb_csum_flags
|= CSUM_TCPIPV6
;
1049 if(*pbuf
->pb_csum_flags
& CSUM_UDP
)
1050 *pbuf
->pb_csum_flags
|= CSUM_UDPIPV6
;
1051 if (*pbuf
->pb_csum_flags
& CSUM_FRAGMENT
)
1052 *pbuf
->pb_csum_flags
|= CSUM_FRAGMENT_IPV6
;
1054 /* Clear IPv4 checksum flags */
1055 *pbuf
->pb_csum_flags
&= ~(CSUM_IP
| CSUM_IP_FRAGS
| CSUM_DELAY_DATA
| CSUM_FRAGMENT
);
1056 } else if (direction
== NT_IN
) {
1057 /* XXX On input just reset csum flags */
1058 *pbuf
->pb_csum_flags
= 0; /* Reset all flags for now */
1060 /* Update csum flags and offsets for rx */
1061 if (*pbuf
->pb_csum_flags
& CSUM_PARTIAL
) {
1062 (pbuf
->pb_mbuf
)->m_pkthdr
.csum_rx_start
-= CLAT46_HDR_EXPANSION_OVERHD
;
1069 /* Fix the proto checksum for address change */
1071 nat464_addr_cksum_fixup(uint16_t *pc
, struct nat464_addr
*ao
, struct nat464_addr
*an
,
1072 protocol_family_t af
, protocol_family_t naf
, uint8_t u
, boolean_t do_ones_complement
)
1074 /* Currently we only support v4 to v6 and vice versa */
1081 if (do_ones_complement
) {
1082 *pc
= ~nat464_cksum_fixup(nat464_cksum_fixup(
1083 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(
1084 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(~*pc
,
1085 ao
->nataddr16
[0], an
->nataddr16
[0], u
),
1086 ao
->nataddr16
[1], an
->nataddr16
[1], u
),
1087 0, an
->nataddr16
[2], u
),
1088 0, an
->nataddr16
[3], u
),
1089 0, an
->nataddr16
[4], u
),
1090 0, an
->nataddr16
[5], u
),
1091 0, an
->nataddr16
[6], u
),
1092 0, an
->nataddr16
[7], u
);
1094 *pc
= nat464_cksum_fixup(nat464_cksum_fixup(
1095 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(
1096 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(*pc
,
1097 ao
->nataddr16
[0], an
->nataddr16
[0], u
),
1098 ao
->nataddr16
[1], an
->nataddr16
[1], u
),
1099 0, an
->nataddr16
[2], u
),
1100 0, an
->nataddr16
[3], u
),
1101 0, an
->nataddr16
[4], u
),
1102 0, an
->nataddr16
[5], u
),
1103 0, an
->nataddr16
[6], u
),
1104 0, an
->nataddr16
[7], u
);
1111 * XXX For NAT464 this only applies to the incoming path.
1112 * The checksum therefore is already ones complemented.
1113 * Therefore we just perform normal fixup.
1117 *pc
= nat464_cksum_fixup(nat464_cksum_fixup(
1118 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(
1119 nat464_cksum_fixup(nat464_cksum_fixup(nat464_cksum_fixup(*pc
,
1120 ao
->nataddr16
[0], an
->nataddr16
[0], u
),
1121 ao
->nataddr16
[1], an
->nataddr16
[1], u
),
1122 ao
->nataddr16
[2], 0, u
),
1123 ao
->nataddr16
[3], 0, u
),
1124 ao
->nataddr16
[4], 0, u
),
1125 ao
->nataddr16
[5], 0, u
),
1126 ao
->nataddr16
[6], 0, u
),
1127 ao
->nataddr16
[7], 0, u
);
1135 nat464_cksum_fixup(uint16_t cksum
, uint16_t old
, uint16_t new, uint8_t udp
)
1141 l
= cksum
+ old
- new;
1142 l
= (l
>> 16) + (l
& 0xffff);
1149 /* CLAT46 event handlers */
1151 in6_clat46_eventhdlr_callback(struct eventhandler_entry_arg arg0 __unused
,
1152 in6_clat46_evhdlr_code_t in6_clat46_ev_code
, pid_t epid
, uuid_t euuid
)
1154 struct kev_msg ev_msg
;
1155 struct kev_netevent_clat46_data clat46_event_data
;
1157 bzero(&ev_msg
, sizeof(ev_msg
));
1158 bzero(&clat46_event_data
, sizeof(clat46_event_data
));
1160 ev_msg
.vendor_code
= KEV_VENDOR_APPLE
;
1161 ev_msg
.kev_class
= KEV_NETWORK_CLASS
;
1162 ev_msg
.kev_subclass
= KEV_NETEVENT_SUBCLASS
;
1163 ev_msg
.event_code
= KEV_NETEVENT_CLAT46_EVENT
;
1165 bzero(&clat46_event_data
, sizeof(clat46_event_data
));
1166 clat46_event_data
.clat46_event_code
= in6_clat46_ev_code
;
1167 clat46_event_data
.epid
= epid
;
1168 uuid_copy(clat46_event_data
.euuid
, euuid
);
1170 ev_msg
.dv
[0].data_ptr
= &clat46_event_data
;
1171 ev_msg
.dv
[0].data_length
= sizeof(clat46_event_data
);
1173 kev_post_msg(&ev_msg
);
1177 in6_clat46_event_callback(void *arg
)
1179 struct kev_netevent_clat46_data
*p_in6_clat46_ev
=
1180 (struct kev_netevent_clat46_data
*)arg
;
1182 EVENTHANDLER_INVOKE(&in6_clat46_evhdlr_ctxt
, in6_clat46_event
,
1183 p_in6_clat46_ev
->clat46_event_code
, p_in6_clat46_ev
->epid
,
1184 p_in6_clat46_ev
->euuid
);
1187 struct in6_clat46_event_nwk_wq_entry
1189 struct nwk_wq_entry nwk_wqe
;
1190 struct kev_netevent_clat46_data in6_clat46_ev_arg
;
1194 in6_clat46_event_enqueue_nwk_wq_entry(in6_clat46_evhdlr_code_t in6_clat46_event_code
,
1195 pid_t epid
, uuid_t euuid
)
1197 struct in6_clat46_event_nwk_wq_entry
*p_ev
= NULL
;
1199 MALLOC(p_ev
, struct in6_clat46_event_nwk_wq_entry
*,
1200 sizeof(struct in6_clat46_event_nwk_wq_entry
),
1201 M_NWKWQ
, M_WAITOK
| M_ZERO
);
1203 p_ev
->nwk_wqe
.func
= in6_clat46_event_callback
;
1204 p_ev
->nwk_wqe
.is_arg_managed
= TRUE
;
1205 p_ev
->nwk_wqe
.arg
= &p_ev
->in6_clat46_ev_arg
;
1207 p_ev
->in6_clat46_ev_arg
.clat46_event_code
= in6_clat46_event_code
;
1208 p_ev
->in6_clat46_ev_arg
.epid
= epid
;
1209 uuid_copy(p_ev
->in6_clat46_ev_arg
.euuid
, euuid
);
1211 nwk_wq_enqueue((struct nwk_wq_entry
*)p_ev
);