]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/iptap.c
xnu-3248.40.184.tar.gz
[apple/xnu.git] / bsd / net / iptap.c
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
70 struct 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
78 static LIST_HEAD(iptap_list, iptap_softc) iptap_list = LIST_HEAD_INITIALIZER(iptap_list);
79
80 static void iptap_lock_shared(void);
81 static void iptap_lock_exclusive(void);
82 static void iptap_lock_done(void);
83 static void iptap_alloc_lock(void);
84
85 decl_lck_rw_data(static, iptap_lck_rw);
86 static lck_grp_t *iptap_grp;
87
88 errno_t iptap_if_output(ifnet_t, mbuf_t);
89 errno_t iptap_demux(ifnet_t , mbuf_t, char *, protocol_family_t *);
90 errno_t iptap_add_proto(ifnet_t, protocol_family_t, const struct ifnet_demux_desc *,
91 u_int32_t);
92 errno_t iptap_del_proto(ifnet_t, protocol_family_t);
93 errno_t iptap_getdrvspec(ifnet_t , struct ifdrv64 *);
94 errno_t iptap_ioctl(ifnet_t, unsigned long, void *);
95 void iptap_detach(ifnet_t);
96 errno_t iptap_tap_callback(ifnet_t , u_int32_t , bpf_tap_mode );
97 int iptap_clone_create(struct if_clone *, u_int32_t, void *);
98 int iptap_clone_destroy(struct ifnet *);
99
100 static int iptap_ipf_register(void);
101 static int iptap_ipf_unregister(void);
102 static errno_t iptap_ipf_input(void *, mbuf_t *, int, u_int8_t);
103 static errno_t iptap_ipf_output(void *, mbuf_t *, ipf_pktopts_t);
104 static void iptap_ipf_detach(void *);
105
106 static ipfilter_t iptap_ipf4, iptap_ipf6;
107
108 void iptap_bpf_tap(struct mbuf *m, u_int32_t proto, int outgoing);
109
110 static 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
117 SYSCTL_DECL(_net_link);
118 SYSCTL_NODE(_net_link, OID_AUTO, iptap, CTLFLAG_RW|CTLFLAG_LOCKED, 0,
119 "iptap virtual interface");
120
121 static int iptap_total_tap_count = 0;
122 SYSCTL_INT(_net_link_iptap, OID_AUTO, total_tap_count, CTLFLAG_RD | CTLFLAG_LOCKED,
123 &iptap_total_tap_count, 0, "");
124
125 static int iptap_log = 0;
126 SYSCTL_INT(_net_link_iptap, OID_AUTO, log, CTLFLAG_RW | CTLFLAG_LOCKED,
127 &iptap_log, 0, "");
128
129 #define IPTAP_LOG(fmt, ...) \
130 do { \
131 if ((iptap_log)) \
132 printf("%s:%d " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
133 } while(false)
134
135 __private_extern__ void
136 iptap_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
147 static void
148 iptap_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
165 static void
166 iptap_lock_shared(void)
167 {
168 lck_rw_lock_shared(&iptap_lck_rw);
169 }
170
171 static void
172 iptap_lock_exclusive(void)
173 {
174 lck_rw_lock_exclusive(&iptap_lck_rw);
175 }
176
177 static void
178 iptap_lock_done(void)
179 {
180 lck_rw_done(&iptap_lck_rw);
181 }
182
183 __private_extern__ int
184 iptap_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();
250 done:
251 if (error != 0) {
252 if (iptap != NULL)
253 _FREE(iptap, M_DEVBUF);
254 }
255 return (error);
256 }
257
258 __private_extern__ int
259 iptap_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
275 iptap_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 }
310 done:
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
321 iptap_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
330 iptap_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
342 iptap_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
354 iptap_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
363 iptap_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
397 done:
398 return (error);
399 }
400
401 __private_extern__ errno_t
402 iptap_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 }
438 done:
439 return (error);
440 }
441
442 __private_extern__ void
443 iptap_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
467 static int
468 iptap_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
499 done:
500 return (err);
501 }
502
503 static int
504 iptap_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 }
529 done:
530 return (err);
531 }
532
533 static errno_t
534 iptap_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
553 static errno_t
554 iptap_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
572 static void
573 iptap_ipf_detach(void *arg)
574 {
575 #pragma unused(arg)
576 }
577
578 __private_extern__ void
579 iptap_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 }