2 * Copyright (c) 1999-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@
29 #include <kern/locks.h>
30 #include <kern/zalloc.h>
32 #include <sys/types.h>
33 #include <sys/kernel_types.h>
34 #include <sys/kauth.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37 #include <sys/sockio.h>
38 #include <sys/sysctl.h>
42 #include <net/if_var.h>
43 #include <net/if_types.h>
45 #include <net/net_osdep.h>
46 #include <net/pktap.h>
47 #include <net/iptap.h>
49 #include <netinet/in_pcb.h>
50 #include <netinet/tcp.h>
51 #include <netinet/tcp_var.h>
53 #include <netinet/ip.h>
54 #include <netinet/ip_var.h>
55 #include <netinet/udp.h>
56 #include <netinet/udp_var.h>
58 #include <netinet/ip6.h>
59 #include <netinet6/in6_pcb.h>
61 #include <netinet/kpi_ipfilter.h>
63 #include <libkern/OSAtomic.h>
65 #include <kern/debug.h>
67 #include <sys/mcache.h>
72 LIST_ENTRY(iptap_softc
) iptap_link
;
74 uint32_t iptap_dlt_raw_count
;
75 uint32_t iptap_dlt_pkttap_count
;
76 struct ifnet
*iptap_ifp
;
79 static LIST_HEAD(iptap_list
, iptap_softc
) iptap_list
= LIST_HEAD_INITIALIZER(iptap_list
);
81 static void iptap_lock_shared(void);
82 static void iptap_lock_exclusive(void);
83 static void iptap_lock_done(void);
84 static void iptap_alloc_lock(void);
86 decl_lck_rw_data(static, iptap_lck_rw
);
87 static lck_grp_t
*iptap_grp
;
89 errno_t
iptap_if_output(ifnet_t
, mbuf_t
);
90 errno_t
iptap_demux(ifnet_t
, mbuf_t
, char *, protocol_family_t
*);
91 errno_t
iptap_add_proto(ifnet_t
, protocol_family_t
, const struct ifnet_demux_desc
*,
93 errno_t
iptap_del_proto(ifnet_t
, protocol_family_t
);
94 errno_t
iptap_getdrvspec(ifnet_t
, struct ifdrv64
*);
95 errno_t
iptap_ioctl(ifnet_t
, unsigned long, void *);
96 void iptap_detach(ifnet_t
);
97 errno_t
iptap_tap_callback(ifnet_t
, u_int32_t
, bpf_tap_mode
);
98 int iptap_clone_create(struct if_clone
*, u_int32_t
, void *);
99 int iptap_clone_destroy(struct ifnet
*);
101 static int iptap_ipf_register(void);
102 static int iptap_ipf_unregister(void);
103 static errno_t
iptap_ipf_input(void *, mbuf_t
*, int, u_int8_t
);
104 static errno_t
iptap_ipf_output(void *, mbuf_t
*, ipf_pktopts_t
);
105 static void iptap_ipf_detach(void *);
107 static ipfilter_t iptap_ipf4
, iptap_ipf6
;
109 void iptap_bpf_tap(struct mbuf
*m
, u_int32_t proto
, int outgoing
);
111 #define IPTAP_MAXUNIT IF_MAXUNIT
112 #define IPTAP_ZONE_MAX_ELEM MIN(IFNETS_MAX, IPTAP_MAXUNIT)
114 static struct if_clone iptap_cloner
=
115 IF_CLONE_INITIALIZER(IPTAP_IFNAME
,
121 sizeof(struct iptap_softc
));
123 SYSCTL_DECL(_net_link
);
124 SYSCTL_NODE(_net_link
, OID_AUTO
, iptap
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0,
125 "iptap virtual interface");
127 static int iptap_total_tap_count
= 0;
128 SYSCTL_INT(_net_link_iptap
, OID_AUTO
, total_tap_count
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
129 &iptap_total_tap_count
, 0, "");
131 static int iptap_log
= 0;
132 SYSCTL_INT(_net_link_iptap
, OID_AUTO
, log
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
135 #define IPTAP_LOG(fmt, ...) \
138 printf("%s:%d " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
141 __private_extern__
void
148 error
= if_clone_attach(&iptap_cloner
);
150 panic("%s: if_clone_attach() failed, error %d\n", __func__
, error
);
155 iptap_alloc_lock(void)
157 lck_grp_attr_t
*grp_attr
;
160 grp_attr
= lck_grp_attr_alloc_init();
161 lck_grp_attr_setdefault(grp_attr
);
162 iptap_grp
= lck_grp_alloc_init(IPTAP_IFNAME
, grp_attr
);
163 lck_grp_attr_free(grp_attr
);
165 attr
= lck_attr_alloc_init();
166 lck_attr_setdefault(attr
);
168 lck_rw_init(&iptap_lck_rw
, iptap_grp
, attr
);
173 iptap_lock_shared(void)
175 lck_rw_lock_shared(&iptap_lck_rw
);
179 iptap_lock_exclusive(void)
181 lck_rw_lock_exclusive(&iptap_lck_rw
);
185 iptap_lock_done(void)
187 lck_rw_done(&iptap_lck_rw
);
190 __private_extern__
int
191 iptap_clone_create(struct if_clone
*ifc
, u_int32_t unit
, void *params
)
193 #pragma unused(params)
196 struct iptap_softc
*iptap
= NULL
;
197 struct ifnet_init_eparams if_init
;
199 iptap
= if_clone_softc_allocate(&iptap_cloner
);
201 printf("%s: _MALLOC failed\n", __func__
);
205 iptap
->iptap_unit
= unit
;
208 * We do not use a set_bpf_tap() function as we rather rely on the more
209 * accurate callback passed to bpf_attach()
211 bzero(&if_init
, sizeof(if_init
));
212 if_init
.ver
= IFNET_INIT_CURRENT_VERSION
;
213 if_init
.len
= sizeof(if_init
);
214 if_init
.flags
= IFNET_INIT_LEGACY
;
215 if_init
.name
= ifc
->ifc_name
;
217 if_init
.type
= IFT_OTHER
;
218 if_init
.family
= IFNET_FAMILY_LOOPBACK
;
219 if_init
.output
= iptap_if_output
;
220 if_init
.demux
= iptap_demux
;
221 if_init
.add_proto
= iptap_add_proto
;
222 if_init
.del_proto
= iptap_del_proto
;
223 if_init
.softc
= iptap
;
224 if_init
.ioctl
= iptap_ioctl
;
225 if_init
.detach
= iptap_detach
;
227 error
= ifnet_allocate_extended(&if_init
, &iptap
->iptap_ifp
);
229 printf("%s: ifnet_allocate failed, error %d\n", __func__
, error
);
233 ifnet_set_flags(iptap
->iptap_ifp
, IFF_UP
, IFF_UP
);
235 error
= ifnet_attach(iptap
->iptap_ifp
, NULL
);
237 printf("%s: ifnet_attach failed - error %d\n", __func__
, error
);
238 ifnet_release(iptap
->iptap_ifp
);
243 * Attach by default as DLT_PKTAP for packet metadata
244 * Provide DLT_RAW for legacy
246 bpf_attach(iptap
->iptap_ifp
, DLT_PKTAP
, sizeof(struct pktap_header
), NULL
,
248 bpf_attach(iptap
->iptap_ifp
, DLT_RAW
, 0, NULL
,
251 /* Take a reference and add to the global list */
252 ifnet_reference(iptap
->iptap_ifp
);
254 iptap_lock_exclusive();
256 if (LIST_EMPTY(&iptap_list
)) {
257 iptap_ipf_register();
259 LIST_INSERT_HEAD(&iptap_list
, iptap
, iptap_link
);
264 if_clone_softc_deallocate(&iptap_cloner
, iptap
);
270 __private_extern__
int
271 iptap_clone_destroy(struct ifnet
*ifp
)
275 (void) ifnet_detach(ifp
);
281 * This function is called whenever a DLT is set on the interface:
282 * - When interface is attached to a BPF device via BIOCSETIF for the default DLT
283 * - Whenever a new DLT is selected via BIOCSDLT
284 * - When the interface is detached from a BPF device (direction is zero)
286 __private_extern__ errno_t
287 iptap_tap_callback(ifnet_t ifp
, u_int32_t dlt
, bpf_tap_mode direction
)
289 struct iptap_softc
*iptap
;
291 iptap
= ifp
->if_softc
;
293 printf("%s: if_softc is NULL for ifp %s\n", __func__
,
299 if (direction
== 0) {
300 if (iptap
->iptap_dlt_raw_count
> 0) {
301 iptap
->iptap_dlt_raw_count
--;
302 OSAddAtomic(-1, &iptap_total_tap_count
);
305 iptap
->iptap_dlt_raw_count
++;
306 OSAddAtomic(1, &iptap_total_tap_count
);
310 if (direction
== 0) {
311 if (iptap
->iptap_dlt_pkttap_count
> 0) {
312 iptap
->iptap_dlt_pkttap_count
--;
313 OSAddAtomic(-1, &iptap_total_tap_count
);
316 iptap
->iptap_dlt_pkttap_count
++;
317 OSAddAtomic(1, &iptap_total_tap_count
);
323 * Attachements count must be positive and we're in trouble
324 * if we have more that 2**31 attachements
326 VERIFY(iptap_total_tap_count
>= 0);
331 __private_extern__ errno_t
332 iptap_if_output(ifnet_t ifp
, mbuf_t m
)
340 __private_extern__ errno_t
341 iptap_demux(ifnet_t ifp
, mbuf_t m
, char *header
,
342 protocol_family_t
*ppf
)
346 #pragma unused(header)
352 __private_extern__ errno_t
353 iptap_add_proto(ifnet_t ifp
, protocol_family_t pf
,
354 const struct ifnet_demux_desc
*dmx
, u_int32_t cnt
)
364 __private_extern__ errno_t
365 iptap_del_proto(ifnet_t ifp
, protocol_family_t pf
)
373 __private_extern__ errno_t
374 iptap_getdrvspec(ifnet_t ifp
, struct ifdrv64
*ifd
)
377 struct iptap_softc
*iptap
;
379 iptap
= ifp
->if_softc
;
382 printf("%s: iptap NULL - error %d\n", __func__
, error
);
386 switch (ifd
->ifd_cmd
) {
387 case PKTP_CMD_TAP_COUNT
: {
388 uint32_t tap_count
= iptap
->iptap_dlt_raw_count
+ iptap
->iptap_dlt_pkttap_count
;
390 if (ifd
->ifd_len
< sizeof(tap_count
)) {
391 printf("%s: PKTP_CMD_TAP_COUNT ifd_len %llu too small - error %d\n",
392 __func__
, ifd
->ifd_len
, error
);
396 error
= copyout(&tap_count
, ifd
->ifd_data
, sizeof(tap_count
));
398 printf("%s: PKTP_CMD_TAP_COUNT copyout - error %d\n", __func__
, error
);
412 __private_extern__ errno_t
413 iptap_ioctl(ifnet_t ifp
, unsigned long cmd
, void *data
)
417 if ((cmd
& IOC_IN
)) {
418 error
= kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER
);
425 case SIOCGDRVSPEC32
: {
427 struct ifdrv32
*ifd32
= (struct ifdrv32
*)data
;
429 memcpy(ifd
.ifd_name
, ifd32
->ifd_name
, sizeof(ifd
.ifd_name
));
430 ifd
.ifd_cmd
= ifd32
->ifd_cmd
;
431 ifd
.ifd_len
= ifd32
->ifd_len
;
432 ifd
.ifd_data
= ifd32
->ifd_data
;
434 error
= iptap_getdrvspec(ifp
, &ifd
);
438 case SIOCGDRVSPEC64
: {
439 struct ifdrv64
*ifd64
= (struct ifdrv64
*)data
;
441 error
= iptap_getdrvspec(ifp
, ifd64
);
453 __private_extern__
void
454 iptap_detach(ifnet_t ifp
)
456 struct iptap_softc
*iptap
= NULL
;
458 iptap_lock_exclusive();
460 iptap
= ifp
->if_softc
;
461 ifp
->if_softc
= NULL
;
462 LIST_REMOVE(iptap
, iptap_link
);
464 if (LIST_EMPTY(&iptap_list
)) {
465 iptap_ipf_unregister();
470 /* Drop reference as it's no more on the global list */
472 if_clone_softc_deallocate(&iptap_cloner
, iptap
);
474 /* This is for the reference taken by ifnet_attach() */
475 (void) ifnet_release(ifp
);
479 iptap_ipf_register(void)
481 struct ipf_filter iptap_ipfinit
;
486 bzero(&iptap_ipfinit
, sizeof(iptap_ipfinit
));
487 iptap_ipfinit
.name
= IPTAP_IFNAME
;
488 iptap_ipfinit
.cookie
= &iptap_ipf4
;
489 iptap_ipfinit
.ipf_input
= iptap_ipf_input
;
490 iptap_ipfinit
.ipf_output
= iptap_ipf_output
;
491 iptap_ipfinit
.ipf_detach
= iptap_ipf_detach
;
493 err
= ipf_addv4(&iptap_ipfinit
, &iptap_ipf4
);
495 printf("%s: ipf_addv4 for %s0 failed - %d\n",
496 __func__
, IPTAP_IFNAME
, err
);
500 iptap_ipfinit
.cookie
= &iptap_ipf6
;
501 err
= ipf_addv6(&iptap_ipfinit
, &iptap_ipf6
);
503 printf("%s: ipf_addv6 for %s0 failed - %d\n",
504 __func__
, IPTAP_IFNAME
, err
);
505 (void) ipf_remove(iptap_ipf4
);
515 iptap_ipf_unregister(void)
521 if (iptap_ipf4
!= NULL
) {
522 err
= ipf_remove(iptap_ipf4
);
524 printf("%s: ipf_remove (ipv4) for %s0 failed - %d\n",
525 __func__
, IPTAP_IFNAME
, err
);
531 if (iptap_ipf6
!= NULL
) {
532 err
= ipf_remove(iptap_ipf6
);
534 printf("%s: ipf_remove (ipv6) for %s0 failed - %d\n",
535 __func__
, IPTAP_IFNAME
, err
);
545 iptap_ipf_input(void *arg
, mbuf_t
*mp
, int off
, u_int8_t proto
)
548 #pragma unused(proto)
550 if (arg
== (void *)&iptap_ipf4
) {
551 iptap_bpf_tap(*mp
, AF_INET
, 0);
552 } else if (arg
== (void *)&iptap_ipf6
) {
553 iptap_bpf_tap(*mp
, AF_INET6
, 0);
555 IPTAP_LOG("%s:%d bad cookie 0x%llx &iptap_ipf4 0x%llx "
556 "&iptap_ipf6 0x%llx\n", __func__
, __LINE__
,
557 (uint64_t)VM_KERNEL_ADDRPERM(arg
),
558 (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf4
),
559 (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf6
));
566 iptap_ipf_output(void *arg
, mbuf_t
*mp
, ipf_pktopts_t opt
)
570 if (arg
== (void *)&iptap_ipf4
) {
571 iptap_bpf_tap(*mp
, AF_INET
, 1);
572 } else if (arg
== (void *)&iptap_ipf6
) {
573 iptap_bpf_tap(*mp
, AF_INET6
, 1);
575 IPTAP_LOG("%s:%d bad cookie 0x%llx &iptap_ipf4 0x%llx "
576 "&iptap_ipf6 0x%llx\n", __func__
, __LINE__
,
577 (uint64_t)VM_KERNEL_ADDRPERM(arg
),
578 (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf4
),
579 (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf6
));
586 iptap_ipf_detach(void *arg
)
591 __private_extern__
void
592 iptap_bpf_tap(struct mbuf
*m
, u_int32_t proto
, int outgoing
)
594 struct iptap_softc
*iptap
;
595 void (*bpf_tap_func
)(ifnet_t
, u_int32_t
, mbuf_t
, void *, size_t ) =
596 outgoing
? bpf_tap_out
: bpf_tap_in
;
597 uint16_t src_scope_id
= 0;
598 uint16_t dst_scope_id
= 0;
600 if (proto
== AF_INET6
) {
601 struct ip6_hdr
*ip6
= mtod(m
, struct ip6_hdr
*);
603 * Clear the embedded scope ID
605 if (IN6_IS_SCOPE_EMBED(&ip6
->ip6_src
)) {
606 src_scope_id
= ip6
->ip6_src
.s6_addr16
[1];
607 ip6
->ip6_src
.s6_addr16
[1] = 0;
609 if (IN6_IS_SCOPE_EMBED(&ip6
->ip6_dst
)) {
610 dst_scope_id
= ip6
->ip6_dst
.s6_addr16
[1];
611 ip6
->ip6_dst
.s6_addr16
[1] = 0;
617 LIST_FOREACH(iptap
, &iptap_list
, iptap_link
) {
618 if (iptap
->iptap_dlt_raw_count
> 0) {
619 bpf_tap_func(iptap
->iptap_ifp
, DLT_RAW
, m
,
622 if (iptap
->iptap_dlt_pkttap_count
> 0) {
624 struct pktap_header hdr
;
627 struct pktap_header
*hdr
= &hdr_buffer
.hdr
;
628 size_t hdr_size
= sizeof(hdr_buffer
);
629 struct ifnet
*ifp
= outgoing
? NULL
: m
->m_pkthdr
.rcvif
;
631 /* Verify the structure is packed */
632 _CASSERT(sizeof(hdr_buffer
) == sizeof(struct pktap_header
) + sizeof(u_int32_t
));
634 bzero(hdr
, sizeof(hdr_buffer
));
635 hdr
->pth_length
= sizeof(struct pktap_header
);
636 hdr
->pth_type_next
= PTH_TYPE_PACKET
;
637 hdr
->pth_dlt
= DLT_NULL
;
639 snprintf(hdr
->pth_ifname
, sizeof(hdr
->pth_ifname
), "%s",
642 hdr_buffer
.proto
= proto
;
643 hdr
->pth_flags
= outgoing
? PTH_FLAG_DIR_OUT
: PTH_FLAG_DIR_IN
;
644 hdr
->pth_protocol_family
= proto
;
645 hdr
->pth_frame_pre_length
= 0;
646 hdr
->pth_frame_post_length
= 0;
647 hdr
->pth_iftype
= ifp
!= NULL
? ifp
->if_type
: 0;
648 hdr
->pth_ifunit
= ifp
!= NULL
? ifp
->if_unit
: 0;
650 pktap_fill_proc_info(hdr
, proto
, m
, 0, outgoing
, ifp
);
652 hdr
->pth_svc
= so_svc2tc(m
->m_pkthdr
.pkt_svc
);
654 bpf_tap_func(iptap
->iptap_ifp
, DLT_PKTAP
, m
, hdr
, hdr_size
);
660 if (proto
== AF_INET6
) {
661 struct ip6_hdr
*ip6
= mtod(m
, struct ip6_hdr
*);
664 * Restore the embedded scope ID
666 if (IN6_IS_SCOPE_EMBED(&ip6
->ip6_src
)) {
667 ip6
->ip6_src
.s6_addr16
[1] = src_scope_id
;
669 if (IN6_IS_SCOPE_EMBED(&ip6
->ip6_dst
)) {
670 ip6
->ip6_dst
.s6_addr16
[1] = dst_scope_id
;