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