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