1/*
2 * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <kern/locks.h>
30#include <kern/zalloc.h>
31
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>
39#include <sys/proc.h>
40
41#include <net/if.h>
42#include <net/if_var.h>
43#include <net/if_types.h>
44#include <net/bpf.h>
45#include <net/net_osdep.h>
46#include <net/pktap.h>
47#include <net/iptap.h>
48
49#include <netinet/in_pcb.h>
50#include <netinet/tcp.h>
51#include <netinet/tcp_var.h>
52#define _IP_VHL
53#include <netinet/ip.h>
54#include <netinet/ip_var.h>
55#include <netinet/udp.h>
56#include <netinet/udp_var.h>
57
58#include <netinet/ip6.h>
59#include <netinet6/in6_pcb.h>
60
61#include <netinet/kpi_ipfilter.h>
62
63#include <libkern/OSAtomic.h>
64
65#include <kern/debug.h>
66
67#include <sys/mcache.h>
68
69#include <string.h>
70
71struct iptap_softc {
72 LIST_ENTRY(iptap_softc) iptap_link;
73 uint32_t iptap_unit;
74 uint32_t iptap_dlt_raw_count;
75 uint32_t iptap_dlt_pkttap_count;
76 struct ifnet *iptap_ifp;
77};
78
79static LIST_HEAD(iptap_list, iptap_softc) iptap_list = LIST_HEAD_INITIALIZER(iptap_list);
80
81static void iptap_lock_shared(void);
82static void iptap_lock_exclusive(void);
83static void iptap_lock_done(void);
84
85static LCK_GRP_DECLARE(iptap_grp, "IPTAP_IFNAME");
86static LCK_RW_DECLARE(iptap_lck_rw, &iptap_grp);
87
88errno_t iptap_if_output(ifnet_t, mbuf_t);
89errno_t iptap_demux(ifnet_t, mbuf_t, char *, protocol_family_t *);
90errno_t iptap_add_proto(ifnet_t, protocol_family_t, const struct ifnet_demux_desc *,
91 u_int32_t);
92errno_t iptap_del_proto(ifnet_t, protocol_family_t);
93errno_t iptap_getdrvspec(ifnet_t, struct ifdrv64 *);
94errno_t iptap_ioctl(ifnet_t, unsigned long, void *);
95void iptap_detach(ifnet_t);
96errno_t iptap_tap_callback(ifnet_t, u_int32_t, bpf_tap_mode );
97int iptap_clone_create(struct if_clone *, u_int32_t, void *);
98int iptap_clone_destroy(struct ifnet *);
99
100static int iptap_ipf_register(void);
101static int iptap_ipf_unregister(void);
102static errno_t iptap_ipf_input(void *, mbuf_t *, int, u_int8_t);
103static errno_t iptap_ipf_output(void *, mbuf_t *, ipf_pktopts_t);
104static void iptap_ipf_detach(void *);
105
106static ipfilter_t iptap_ipf4, iptap_ipf6;
107
108void iptap_bpf_tap(struct mbuf *m, u_int32_t proto, int outgoing);
109
110#define IPTAP_MAXUNIT IF_MAXUNIT
111#define IPTAP_ZONE_MAX_ELEM MIN(IFNETS_MAX, IPTAP_MAXUNIT)
112
113static struct if_clone iptap_cloner =
114 IF_CLONE_INITIALIZER(IPTAP_IFNAME,
115 iptap_clone_create,
116 iptap_clone_destroy,
117 0,
118 IPTAP_MAXUNIT);
119
120SYSCTL_DECL(_net_link);
121SYSCTL_NODE(_net_link, OID_AUTO, iptap, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
122 "iptap virtual interface");
123
124static int iptap_total_tap_count = 0;
125SYSCTL_INT(_net_link_iptap, OID_AUTO, total_tap_count, CTLFLAG_RD | CTLFLAG_LOCKED,
126 &iptap_total_tap_count, 0, "");
127
128static int iptap_log = 0;
129SYSCTL_INT(_net_link_iptap, OID_AUTO, log, CTLFLAG_RW | CTLFLAG_LOCKED,
130 &iptap_log, 0, "");
131
132#define IPTAP_LOG(fmt, ...) \
133do { \
134 if ((iptap_log)) \
135 printf("%s:%d " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
136} while(false)
137
138__private_extern__ void
139iptap_init(void)
140{
141 errno_t error;
142
143 error = if_clone_attach(&iptap_cloner);
144 if (error != 0) {
145 panic("%s: if_clone_attach() failed, error %d", __func__, error);
146 }
147}
148
149static void
150iptap_lock_shared(void)
151{
152 lck_rw_lock_shared(lck: &iptap_lck_rw);
153}
154
155static void
156iptap_lock_exclusive(void)
157{
158 lck_rw_lock_exclusive(lck: &iptap_lck_rw);
159}
160
161static void
162iptap_lock_done(void)
163{
164 lck_rw_done(lck: &iptap_lck_rw);
165}
166
167__private_extern__ int
168iptap_clone_create(struct if_clone *ifc, u_int32_t unit, void *params)
169{
170#pragma unused(params)
171
172 int error = 0;
173 struct iptap_softc *iptap = NULL;
174 struct ifnet_init_eparams if_init;
175
176 iptap = kalloc_type(struct iptap_softc, Z_WAITOK_ZERO_NOFAIL);
177 iptap->iptap_unit = unit;
178
179 /*
180 * We do not use a set_bpf_tap() function as we rather rely on the more
181 * accurate callback passed to bpf_attach()
182 */
183 bzero(s: &if_init, n: sizeof(if_init));
184 if_init.ver = IFNET_INIT_CURRENT_VERSION;
185 if_init.len = sizeof(if_init);
186 if_init.flags = IFNET_INIT_LEGACY;
187 if_init.name = ifc->ifc_name;
188 if_init.unit = unit;
189 if_init.type = IFT_OTHER;
190 if_init.family = IFNET_FAMILY_LOOPBACK;
191 if_init.output = iptap_if_output;
192 if_init.demux = iptap_demux;
193 if_init.add_proto = iptap_add_proto;
194 if_init.del_proto = iptap_del_proto;
195 if_init.softc = iptap;
196 if_init.ioctl = iptap_ioctl;
197 if_init.detach = iptap_detach;
198
199 error = ifnet_allocate_extended(init: &if_init, interface: &iptap->iptap_ifp);
200 if (error != 0) {
201 printf("%s: ifnet_allocate failed, error %d\n", __func__, error);
202 goto done;
203 }
204
205 ifnet_set_flags(interface: iptap->iptap_ifp, IFF_UP, IFF_UP);
206
207 error = ifnet_attach(interface: iptap->iptap_ifp, NULL);
208 if (error != 0) {
209 printf("%s: ifnet_attach failed - error %d\n", __func__, error);
210 ifnet_release(interface: iptap->iptap_ifp);
211 goto done;
212 }
213
214 /*
215 * Attach by default as DLT_PKTAP for packet metadata
216 * Provide DLT_RAW for legacy
217 */
218 bpf_attach(interface: iptap->iptap_ifp, DLT_PKTAP, header_length: sizeof(struct pktap_header), NULL,
219 tap: iptap_tap_callback);
220 bpf_attach(interface: iptap->iptap_ifp, DLT_RAW, header_length: 0, NULL,
221 tap: iptap_tap_callback);
222
223 /* Take a reference and add to the global list */
224 ifnet_reference(interface: iptap->iptap_ifp);
225
226 iptap_lock_exclusive();
227
228 if (LIST_EMPTY(&iptap_list)) {
229 iptap_ipf_register();
230 }
231 LIST_INSERT_HEAD(&iptap_list, iptap, iptap_link);
232 iptap_lock_done();
233done:
234 if (error != 0 && iptap != NULL) {
235 kfree_type(struct iptap_softc, iptap);
236 }
237 return error;
238}
239
240__private_extern__ int
241iptap_clone_destroy(struct ifnet *ifp)
242{
243 int error = 0;
244
245 (void) ifnet_detach(interface: ifp);
246
247 return error;
248}
249
250/*
251 * This function is called whenever a DLT is set on the interface:
252 * - When interface is attached to a BPF device via BIOCSETIF for the default DLT
253 * - Whenever a new DLT is selected via BIOCSDLT
254 * - When the interface is detached from a BPF device (direction is zero)
255 */
256__private_extern__ errno_t
257iptap_tap_callback(ifnet_t ifp, u_int32_t dlt, bpf_tap_mode direction)
258{
259 struct iptap_softc *iptap;
260
261 iptap = ifp->if_softc;
262 if (iptap == NULL) {
263 printf("%s: if_softc is NULL for ifp %s\n", __func__,
264 ifp->if_xname);
265 goto done;
266 }
267 switch (dlt) {
268 case DLT_RAW:
269 if (direction == 0) {
270 if (iptap->iptap_dlt_raw_count > 0) {
271 iptap->iptap_dlt_raw_count--;
272 OSAddAtomic(-1, &iptap_total_tap_count);
273 }
274 } else {
275 iptap->iptap_dlt_raw_count++;
276 OSAddAtomic(1, &iptap_total_tap_count);
277 }
278 break;
279 case DLT_PKTAP:
280 if (direction == 0) {
281 if (iptap->iptap_dlt_pkttap_count > 0) {
282 iptap->iptap_dlt_pkttap_count--;
283 OSAddAtomic(-1, &iptap_total_tap_count);
284 }
285 } else {
286 iptap->iptap_dlt_pkttap_count++;
287 OSAddAtomic(1, &iptap_total_tap_count);
288 }
289 break;
290 }
291done:
292 /*
293 * Attachements count must be positive and we're in trouble
294 * if we have more that 2**31 attachements
295 */
296 VERIFY(iptap_total_tap_count >= 0);
297
298 return 0;
299}
300
301__private_extern__ errno_t
302iptap_if_output(ifnet_t ifp, mbuf_t m)
303{
304#pragma unused(ifp)
305
306 mbuf_freem(mbuf: m);
307 return ENOTSUP;
308}
309
310__private_extern__ errno_t
311iptap_demux(ifnet_t ifp, mbuf_t m, char *header,
312 protocol_family_t *ppf)
313{
314#pragma unused(ifp)
315#pragma unused(m)
316#pragma unused(header)
317#pragma unused(ppf)
318
319 return ENOTSUP;
320}
321
322__private_extern__ errno_t
323iptap_add_proto(ifnet_t ifp, protocol_family_t pf,
324 const struct ifnet_demux_desc *dmx, u_int32_t cnt)
325{
326#pragma unused(ifp)
327#pragma unused(pf)
328#pragma unused(dmx)
329#pragma unused(cnt)
330
331 return 0;
332}
333
334__private_extern__ errno_t
335iptap_del_proto(ifnet_t ifp, protocol_family_t pf)
336{
337#pragma unused(ifp)
338#pragma unused(pf)
339
340 return 0;
341}
342
343__private_extern__ errno_t
344iptap_getdrvspec(ifnet_t ifp, struct ifdrv64 *ifd)
345{
346 errno_t error = 0;
347 struct iptap_softc *iptap;
348
349 iptap = ifp->if_softc;
350 if (iptap == NULL) {
351 error = ENOENT;
352 printf("%s: iptap NULL - error %d\n", __func__, error);
353 goto done;
354 }
355
356 switch (ifd->ifd_cmd) {
357 case PKTP_CMD_TAP_COUNT: {
358 uint32_t tap_count = iptap->iptap_dlt_raw_count + iptap->iptap_dlt_pkttap_count;
359
360 if (ifd->ifd_len < sizeof(tap_count)) {
361 printf("%s: PKTP_CMD_TAP_COUNT ifd_len %llu too small - error %d\n",
362 __func__, ifd->ifd_len, error);
363 error = EINVAL;
364 break;
365 }
366 error = copyout(&tap_count, ifd->ifd_data, sizeof(tap_count));
367 if (error) {
368 printf("%s: PKTP_CMD_TAP_COUNT copyout - error %d\n", __func__, error);
369 goto done;
370 }
371 break;
372 }
373 default:
374 error = EINVAL;
375 break;
376 }
377
378done:
379 return error;
380}
381
382__private_extern__ errno_t
383iptap_ioctl(ifnet_t ifp, unsigned long cmd, void *data)
384{
385 errno_t error = 0;
386
387 if ((cmd & IOC_IN)) {
388 error = kauth_authorize_generic(credential: kauth_cred_get(), KAUTH_GENERIC_ISSUSER);
389 if (error) {
390 goto done;
391 }
392 }
393
394 switch (cmd) {
395 case SIOCGDRVSPEC32: {
396 struct ifdrv64 ifd;
397 struct ifdrv32 *ifd32 = (struct ifdrv32 *)data;
398
399 memcpy(dst: ifd.ifd_name, src: ifd32->ifd_name, n: sizeof(ifd.ifd_name));
400 ifd.ifd_cmd = ifd32->ifd_cmd;
401 ifd.ifd_len = ifd32->ifd_len;
402 ifd.ifd_data = ifd32->ifd_data;
403
404 error = iptap_getdrvspec(ifp, ifd: &ifd);
405
406 break;
407 }
408 case SIOCGDRVSPEC64: {
409 struct ifdrv64 *ifd64 = (struct ifdrv64 *)data;
410
411 error = iptap_getdrvspec(ifp, ifd: ifd64);
412
413 break;
414 }
415 default:
416 error = ENOTSUP;
417 break;
418 }
419done:
420 return error;
421}
422
423__private_extern__ void
424iptap_detach(ifnet_t ifp)
425{
426 struct iptap_softc *iptap = NULL;
427
428 iptap_lock_exclusive();
429
430 iptap = ifp->if_softc;
431 ifp->if_softc = NULL;
432 LIST_REMOVE(iptap, iptap_link);
433
434 if (LIST_EMPTY(&iptap_list)) {
435 iptap_ipf_unregister();
436 }
437
438 iptap_lock_done();
439
440 /* Drop reference as it's no more on the global list */
441 ifnet_release(interface: ifp);
442 kfree_type(struct iptap_softc, iptap);
443
444 /* This is for the reference taken by ifnet_attach() */
445 (void) ifnet_release(interface: ifp);
446}
447
448static int
449iptap_ipf_register(void)
450{
451 struct ipf_filter iptap_ipfinit;
452 int err = 0;
453
454 IPTAP_LOG("\n");
455
456 bzero(s: &iptap_ipfinit, n: sizeof(iptap_ipfinit));
457 iptap_ipfinit.name = IPTAP_IFNAME;
458 iptap_ipfinit.cookie = &iptap_ipf4;
459 iptap_ipfinit.ipf_input = iptap_ipf_input;
460 iptap_ipfinit.ipf_output = iptap_ipf_output;
461 iptap_ipfinit.ipf_detach = iptap_ipf_detach;
462
463 err = ipf_addv4(&iptap_ipfinit, &iptap_ipf4);
464 if (err != 0) {
465 printf("%s: ipf_addv4 for %s0 failed - %d\n",
466 __func__, IPTAP_IFNAME, err);
467 goto done;
468 }
469
470 iptap_ipfinit.cookie = &iptap_ipf6;
471 err = ipf_addv6(&iptap_ipfinit, &iptap_ipf6);
472 if (err != 0) {
473 printf("%s: ipf_addv6 for %s0 failed - %d\n",
474 __func__, IPTAP_IFNAME, err);
475 (void) ipf_remove(filter_ref: iptap_ipf4);
476 iptap_ipf4 = NULL;
477 goto done;
478 }
479
480done:
481 return err;
482}
483
484static int
485iptap_ipf_unregister(void)
486{
487 int err = 0;
488
489 IPTAP_LOG("\n");
490
491 if (iptap_ipf4 != NULL) {
492 err = ipf_remove(filter_ref: iptap_ipf4);
493 if (err != 0) {
494 printf("%s: ipf_remove (ipv4) for %s0 failed - %d\n",
495 __func__, IPTAP_IFNAME, err);
496 goto done;
497 }
498 iptap_ipf4 = NULL;
499 }
500
501 if (iptap_ipf6 != NULL) {
502 err = ipf_remove(filter_ref: iptap_ipf6);
503 if (err != 0) {
504 printf("%s: ipf_remove (ipv6) for %s0 failed - %d\n",
505 __func__, IPTAP_IFNAME, err);
506 goto done;
507 }
508 iptap_ipf6 = NULL;
509 }
510done:
511 return err;
512}
513
514static errno_t
515iptap_ipf_input(void *arg, mbuf_t *mp, int off, u_int8_t proto)
516{
517#pragma unused(off)
518#pragma unused(proto)
519
520 if (arg == (void *)&iptap_ipf4) {
521 iptap_bpf_tap(m: *mp, AF_INET, outgoing: 0);
522 } else if (arg == (void *)&iptap_ipf6) {
523 iptap_bpf_tap(m: *mp, AF_INET6, outgoing: 0);
524 } else {
525 IPTAP_LOG("%s:%d bad cookie 0x%llx &iptap_ipf4 0x%llx "
526 "&iptap_ipf6 0x%llx\n", __func__, __LINE__,
527 (uint64_t)VM_KERNEL_ADDRPERM(arg),
528 (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf4),
529 (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf6));
530 }
531
532 return 0;
533}
534
535static errno_t
536iptap_ipf_output(void *arg, mbuf_t *mp, ipf_pktopts_t opt)
537{
538#pragma unused(opt)
539
540 if (arg == (void *)&iptap_ipf4) {
541 iptap_bpf_tap(m: *mp, AF_INET, outgoing: 1);
542 } else if (arg == (void *)&iptap_ipf6) {
543 iptap_bpf_tap(m: *mp, AF_INET6, outgoing: 1);
544 } else {
545 IPTAP_LOG("%s:%d bad cookie 0x%llx &iptap_ipf4 0x%llx "
546 "&iptap_ipf6 0x%llx\n", __func__, __LINE__,
547 (uint64_t)VM_KERNEL_ADDRPERM(arg),
548 (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf4),
549 (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf6));
550 }
551
552 return 0;
553}
554
555static void
556iptap_ipf_detach(void *arg)
557{
558#pragma unused(arg)
559}
560
561__private_extern__ void
562iptap_bpf_tap(struct mbuf *m, u_int32_t proto, int outgoing)
563{
564 struct iptap_softc *iptap;
565 void (*bpf_tap_func)(ifnet_t, u_int32_t, mbuf_t, void *, size_t ) =
566 outgoing ? bpf_tap_out : bpf_tap_in;
567 uint32_t src_scope_id = 0;
568 uint32_t dst_scope_id = 0;
569
570 if (proto == AF_INET6) {
571 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
572 /*
573 * Clear the embedded scope ID
574 */
575 if (in6_embedded_scope && IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) {
576 src_scope_id = ip6->ip6_src.s6_addr16[1];
577 ip6->ip6_src.s6_addr16[1] = 0;
578 }
579 if (in6_embedded_scope && IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) {
580 dst_scope_id = ip6->ip6_dst.s6_addr16[1];
581 ip6->ip6_dst.s6_addr16[1] = 0;
582 }
583 }
584
585 iptap_lock_shared();
586
587 LIST_FOREACH(iptap, &iptap_list, iptap_link) {
588 if (iptap->iptap_dlt_raw_count > 0) {
589 bpf_tap_func(iptap->iptap_ifp, DLT_RAW, m,
590 NULL, 0);
591 }
592 if (iptap->iptap_dlt_pkttap_count > 0) {
593 struct {
594 struct pktap_header hdr;
595 u_int32_t proto;
596 } hdr_buffer;
597 struct pktap_header *hdr = &hdr_buffer.hdr;
598 size_t hdr_size = sizeof(hdr_buffer);
599 struct ifnet *ifp = outgoing ? NULL : m->m_pkthdr.rcvif;
600
601 /* Verify the structure is packed */
602 _CASSERT(sizeof(hdr_buffer) == sizeof(struct pktap_header) + sizeof(u_int32_t));
603
604 bzero(s: hdr, n: sizeof(hdr_buffer));
605 hdr->pth_length = sizeof(struct pktap_header);
606 hdr->pth_type_next = PTH_TYPE_PACKET;
607 hdr->pth_dlt = DLT_NULL;
608 if (ifp != NULL) {
609 snprintf(hdr->pth_ifname, count: sizeof(hdr->pth_ifname), "%s",
610 ifp->if_xname);
611 }
612 hdr_buffer.proto = proto;
613 hdr->pth_flags = outgoing ? PTH_FLAG_DIR_OUT : PTH_FLAG_DIR_IN;
614 hdr->pth_protocol_family = proto;
615 hdr->pth_frame_pre_length = 0;
616 hdr->pth_frame_post_length = 0;
617 hdr->pth_iftype = ifp != NULL ? ifp->if_type : 0;
618 hdr->pth_ifunit = ifp != NULL ? ifp->if_unit : 0;
619
620 pktap_fill_proc_info(hdr, proto, m, 0, outgoing, ifp);
621
622 hdr->pth_svc = so_svc2tc(m->m_pkthdr.pkt_svc);
623
624 bpf_tap_func(iptap->iptap_ifp, DLT_PKTAP, m, hdr, hdr_size);
625 }
626 }
627
628 iptap_lock_done();
629
630 if (proto == AF_INET6) {
631 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
632
633 /*
634 * Restore the embedded scope ID
635 */
636 if (in6_embedded_scope && IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) {
637 ip6->ip6_src.s6_addr16[1] = (uint16_t)src_scope_id;
638 }
639 if (in6_embedded_scope && IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) {
640 ip6->ip6_dst.s6_addr16[1] = (uint16_t)dst_scope_id;
641 }
642 }
643}
644