1 /*
2 * Copyright (c) 2012-2021 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
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 <libkern/OSAtomic.h>
61
62 #include <kern/debug.h>
63
64 #include <sys/mcache.h>
65
66 #include <string.h>
67
68 extern struct inpcbinfo ripcbinfo;
69
70 struct pktap_softc {
71 LIST_ENTRY(pktap_softc) pktp_link;
72 uint32_t pktp_unit;
73 uint32_t pktp_dlt_raw_count;
74 uint32_t pktp_dlt_pkttap_count;
75 struct ifnet *pktp_ifp;
76 struct pktap_filter pktp_filters[PKTAP_MAX_FILTERS];
77 };
78
79 #ifndef PKTAP_DEBUG
80 #define PKTAP_DEBUG 0
81 #endif /* PKTAP_DEBUG */
82
83 #define PKTAP_FILTER_OK 0 /* Packet passes filter checks */
84 #define PKTAP_FILTER_SKIP 1 /* Do not tap this packet */
85
86 static int pktap_inited = 0;
87
88 SYSCTL_DECL(_net_link);
89 SYSCTL_NODE(_net_link, IFT_PKTAP, pktap,
90 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "pktap virtual interface");
91
92 uint32_t pktap_total_tap_count = 0;
93 SYSCTL_UINT(_net_link_pktap, OID_AUTO, total_tap_count,
94 CTLFLAG_RD | CTLFLAG_LOCKED, &pktap_total_tap_count, 0, "");
95
96 static u_int64_t pktap_count_unknown_if_type = 0;
97 SYSCTL_QUAD(_net_link_pktap, OID_AUTO, count_unknown_if_type,
98 CTLFLAG_RD | CTLFLAG_LOCKED, &pktap_count_unknown_if_type, "");
99
100 static int pktap_log = 0;
101 SYSCTL_INT(_net_link_pktap, OID_AUTO, log,
102 CTLFLAG_RW | CTLFLAG_LOCKED, &pktap_log, 0, "");
103
104 #define PKTAP_LOG(mask, fmt, ...) \
105 do { \
106 if ((pktap_log & mask)) \
107 printf("%s:%d " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
108 } while (false)
109
110 #define PKTP_LOG_FUNC 0x01
111 #define PKTP_LOG_FILTER 0x02
112 #define PKTP_LOG_INPUT 0x04
113 #define PKTP_LOG_OUTPUT 0x08
114 #define PKTP_LOG_ERROR 0x10
115 #define PKTP_LOG_NOPCB 0x20
116
117 /*
118 * pktap_lck_rw protects the global list of pktap interfaces
119 */
120 static LCK_GRP_DECLARE(pktap_lck_grp, "pktap");
121 #if PKTAP_DEBUG
122 static LCK_ATTR_DECLARE(pktap_lck_attr, LCK_ATTR_DEBUG, 0);
123 #else
124 static LCK_ATTR_DECLARE(pktap_lck_attr, 0, 0);
125 #endif
126 static LCK_RW_DECLARE_ATTR(pktap_lck_rw, &pktap_lck_grp, &pktap_lck_attr);
127
128
129 static LIST_HEAD(pktap_list, pktap_softc) pktap_list =
130 LIST_HEAD_INITIALIZER(pktap_list);
131
132 int pktap_clone_create(struct if_clone *, u_int32_t, void *);
133 int pktap_clone_destroy(struct ifnet *);
134
135 #define PKTAP_MAXUNIT IF_MAXUNIT
136 #define PKTAP_ZONE_MAX_ELEM MIN(IFNETS_MAX, PKTAP_MAXUNIT)
137
138 static struct if_clone pktap_cloner =
139 IF_CLONE_INITIALIZER(PKTAP_IFNAME,
140 pktap_clone_create,
141 pktap_clone_destroy,
142 0,
143 PKTAP_MAXUNIT,
144 PKTAP_ZONE_MAX_ELEM,
145 sizeof(struct pktap_softc));
146
147 errno_t pktap_if_output(ifnet_t, mbuf_t);
148 errno_t pktap_demux(ifnet_t, mbuf_t, char *, protocol_family_t *);
149 errno_t pktap_add_proto(ifnet_t, protocol_family_t,
150 const struct ifnet_demux_desc *, u_int32_t);
151 errno_t pktap_del_proto(ifnet_t, protocol_family_t);
152 errno_t pktap_getdrvspec(ifnet_t, struct ifdrv64 *);
153 errno_t pktap_setdrvspec(ifnet_t, struct ifdrv64 *);
154 errno_t pktap_ioctl(ifnet_t, unsigned long, void *);
155 void pktap_detach(ifnet_t);
156 int pktap_filter_evaluate(struct pktap_softc *, struct ifnet *);
157 void pktap_bpf_tap(struct ifnet *, protocol_family_t, struct mbuf *,
158 u_int32_t, u_int32_t, int);
159 errno_t pktap_tap_callback(ifnet_t, u_int32_t, bpf_tap_mode);
160
161 static void
pktap_hexdump(int mask,void * addr,size_t len)162 pktap_hexdump(int mask, void *addr, size_t len)
163 {
164 unsigned char *buf = addr;
165 size_t i;
166
167 if (!(pktap_log & mask)) {
168 return;
169 }
170
171 for (i = 0; i < len; i++) {
172 unsigned char h = (buf[i] & 0xf0) >> 4;
173 unsigned char l = buf[i] & 0x0f;
174
175 if (i != 0) {
176 if (i % 32 == 0) {
177 printf("\n");
178 } else if (i % 4 == 0) {
179 printf(" ");
180 }
181 }
182 printf("%c%c",
183 h < 10 ? h + '0' : h - 10 + 'a',
184 l < 10 ? l + '0' : l - 10 + 'a');
185 }
186 if (i % 32 != 0) {
187 printf("\n");
188 }
189 }
190
191 #define _CASSERT_OFFFSETOF_FIELD(s1, s2, f) \
192 _CASSERT(offsetof(struct s1, f) == offsetof(struct s2, f))
193
194 __private_extern__ void
pktap_init(void)195 pktap_init(void)
196 {
197 int error = 0;
198
199 _CASSERT_OFFFSETOF_FIELD(pktap_header, pktap_v2_hdr, pth_flags);
200
201 /* Make sure we're called only once */
202 VERIFY(pktap_inited == 0);
203
204 pktap_inited = 1;
205
206 LIST_INIT(&pktap_list);
207
208 error = if_clone_attach(&pktap_cloner);
209 if (error != 0) {
210 panic("%s: if_clone_attach() failed, error %d",
211 __func__, error);
212 }
213 }
214
215 __private_extern__ int
pktap_clone_create(struct if_clone * ifc,u_int32_t unit,__unused void * params)216 pktap_clone_create(struct if_clone *ifc, u_int32_t unit, __unused void *params)
217 {
218 int error = 0;
219 struct pktap_softc *pktap = NULL;
220 struct ifnet_init_eparams if_init;
221
222 PKTAP_LOG(PKTP_LOG_FUNC, "unit %u\n", unit);
223
224 pktap = if_clone_softc_allocate(&pktap_cloner);
225 pktap->pktp_unit = unit;
226
227 /*
228 * By default accept packet from physical interfaces
229 */
230 pktap->pktp_filters[0].filter_op = PKTAP_FILTER_OP_PASS;
231 pktap->pktp_filters[0].filter_param = PKTAP_FILTER_PARAM_IF_TYPE;
232 pktap->pktp_filters[0].filter_param_if_type = IFT_ETHER;
233
234 #if !XNU_TARGET_OS_OSX
235 pktap->pktp_filters[1].filter_op = PKTAP_FILTER_OP_PASS;
236 pktap->pktp_filters[1].filter_param = PKTAP_FILTER_PARAM_IF_TYPE;
237 pktap->pktp_filters[1].filter_param_if_type = IFT_CELLULAR;
238 #else /* XNU_TARGET_OS_OSX */
239 pktap->pktp_filters[1].filter_op = PKTAP_FILTER_OP_PASS;
240 pktap->pktp_filters[1].filter_param = PKTAP_FILTER_PARAM_IF_TYPE;
241 pktap->pktp_filters[1].filter_param_if_type = IFT_IEEE1394;
242 #endif /* XNU_TARGET_OS_OSX */
243
244 pktap->pktp_filters[2].filter_op = PKTAP_FILTER_OP_PASS;
245 pktap->pktp_filters[2].filter_param = PKTAP_FILTER_PARAM_IF_TYPE;
246 pktap->pktp_filters[2].filter_param_if_type = IFT_OTHER;
247
248 /*
249 * We do not use a set_bpf_tap() function as we rather rely on the more
250 * accurate callback passed to bpf_attach()
251 */
252 bzero(&if_init, sizeof(if_init));
253 if_init.ver = IFNET_INIT_CURRENT_VERSION;
254 if_init.len = sizeof(if_init);
255 if_init.flags = IFNET_INIT_LEGACY;
256 if_init.name = ifc->ifc_name;
257 if_init.unit = unit;
258 if_init.type = IFT_PKTAP;
259 if_init.family = IFNET_FAMILY_LOOPBACK;
260 if_init.output = pktap_if_output;
261 if_init.demux = pktap_demux;
262 if_init.add_proto = pktap_add_proto;
263 if_init.del_proto = pktap_del_proto;
264 if_init.softc = pktap;
265 if_init.ioctl = pktap_ioctl;
266 if_init.detach = pktap_detach;
267
268 error = ifnet_allocate_extended(&if_init, &pktap->pktp_ifp);
269 if (error != 0) {
270 printf("%s: ifnet_allocate failed, error %d\n",
271 __func__, error);
272 goto done;
273 }
274
275 ifnet_set_flags(pktap->pktp_ifp, IFF_UP, IFF_UP);
276
277 error = ifnet_attach(pktap->pktp_ifp, NULL);
278 if (error != 0) {
279 printf("%s: ifnet_attach failed - error %d\n", __func__, error);
280 ifnet_release(pktap->pktp_ifp);
281 goto done;
282 }
283
284 /* Attach DLT_PKTAP as the default DLT */
285 bpf_attach(pktap->pktp_ifp, DLT_PKTAP, sizeof(struct pktap_header),
286 NULL, pktap_tap_callback);
287 bpf_attach(pktap->pktp_ifp, DLT_RAW, 0, NULL, pktap_tap_callback);
288
289 /* Take a reference and add to the global list */
290 ifnet_reference(pktap->pktp_ifp);
291 lck_rw_lock_exclusive(&pktap_lck_rw);
292 LIST_INSERT_HEAD(&pktap_list, pktap, pktp_link);
293 lck_rw_done(&pktap_lck_rw);
294 done:
295 if (error != 0 && pktap != NULL) {
296 if_clone_softc_deallocate(&pktap_cloner, pktap);
297 }
298 return error;
299 }
300
301 __private_extern__ int
pktap_clone_destroy(struct ifnet * ifp)302 pktap_clone_destroy(struct ifnet *ifp)
303 {
304 int error = 0;
305
306 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
307
308 (void) ifnet_detach(ifp);
309
310 return error;
311 }
312
313 /*
314 * This function is called whenever a DLT is set on the interface:
315 * - When interface is attached to a BPF device via BIOCSETIF for the
316 * default DLT
317 * - Whenever a new DLT is selected via BIOCSDLT
318 * - When the interface is detached from a BPF device (direction is zero)
319 */
320 __private_extern__ errno_t
pktap_tap_callback(ifnet_t ifp,u_int32_t dlt,bpf_tap_mode direction)321 pktap_tap_callback(ifnet_t ifp, u_int32_t dlt, bpf_tap_mode direction)
322 {
323 struct pktap_softc *pktap;
324
325 pktap = ifp->if_softc;
326 if (pktap == NULL) {
327 printf("%s: if_softc is NULL for ifp %s\n", __func__,
328 ifp->if_xname);
329 goto done;
330 }
331 switch (dlt) {
332 case DLT_RAW:
333 if (direction == 0) {
334 if (pktap->pktp_dlt_raw_count > 0) {
335 pktap->pktp_dlt_raw_count--;
336 OSAddAtomic(-1, &pktap_total_tap_count);
337 }
338 } else {
339 pktap->pktp_dlt_raw_count++;
340 OSAddAtomic(1, &pktap_total_tap_count);
341 }
342 break;
343 case DLT_PKTAP:
344 if (direction == 0) {
345 if (pktap->pktp_dlt_pkttap_count > 0) {
346 pktap->pktp_dlt_pkttap_count--;
347 OSAddAtomic(-1, &pktap_total_tap_count);
348 }
349 } else {
350 pktap->pktp_dlt_pkttap_count++;
351 OSAddAtomic(1, &pktap_total_tap_count);
352 }
353 break;
354 }
355 done:
356 /*
357 * Attachements count must be positive and we're in trouble
358 * if we have more that 2**31 attachements
359 */
360 VERIFY(pktap_total_tap_count >= 0);
361
362 return 0;
363 }
364
365 __private_extern__ errno_t
pktap_if_output(ifnet_t ifp,mbuf_t m)366 pktap_if_output(ifnet_t ifp, mbuf_t m)
367 {
368 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
369 mbuf_freem(m);
370 return ENOTSUP;
371 }
372
373 __private_extern__ errno_t
pktap_demux(ifnet_t ifp,__unused mbuf_t m,__unused char * header,__unused protocol_family_t * ppf)374 pktap_demux(ifnet_t ifp, __unused mbuf_t m, __unused char *header,
375 __unused protocol_family_t *ppf)
376 {
377 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
378 return ENOTSUP;
379 }
380
381 __private_extern__ errno_t
pktap_add_proto(__unused ifnet_t ifp,protocol_family_t pf,__unused const struct ifnet_demux_desc * dmx,__unused u_int32_t cnt)382 pktap_add_proto(__unused ifnet_t ifp, protocol_family_t pf,
383 __unused const struct ifnet_demux_desc *dmx, __unused u_int32_t cnt)
384 {
385 PKTAP_LOG(PKTP_LOG_FUNC, "%s pf %u\n", ifp->if_xname, pf);
386 return 0;
387 }
388
389 __private_extern__ errno_t
pktap_del_proto(__unused ifnet_t ifp,__unused protocol_family_t pf)390 pktap_del_proto(__unused ifnet_t ifp, __unused protocol_family_t pf)
391 {
392 PKTAP_LOG(PKTP_LOG_FUNC, "%s pf %u\n", ifp->if_xname, pf);
393 return 0;
394 }
395
396 __private_extern__ errno_t
pktap_getdrvspec(ifnet_t ifp,struct ifdrv64 * ifd)397 pktap_getdrvspec(ifnet_t ifp, struct ifdrv64 *ifd)
398 {
399 errno_t error = 0;
400 struct pktap_softc *pktap;
401 int i;
402
403 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
404
405 pktap = ifp->if_softc;
406 if (pktap == NULL) {
407 error = ENOENT;
408 printf("%s: pktap NULL - error %d\n", __func__, error);
409 goto done;
410 }
411
412 switch (ifd->ifd_cmd) {
413 case PKTP_CMD_FILTER_GET: {
414 struct x_pktap_filter x_filters[PKTAP_MAX_FILTERS];
415
416 bzero(&x_filters, sizeof(x_filters));
417
418 if (ifd->ifd_len < PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)) {
419 printf("%s: PKTP_CMD_FILTER_GET ifd_len %llu too small - error %d\n",
420 __func__, ifd->ifd_len, error);
421 error = EINVAL;
422 break;
423 }
424 for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
425 struct pktap_filter *pktap_filter = pktap->pktp_filters + i;
426 struct x_pktap_filter *x_filter = x_filters + i;
427
428 x_filter->filter_op = pktap_filter->filter_op;
429 x_filter->filter_param = pktap_filter->filter_param;
430
431 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) {
432 x_filter->filter_param_if_type = pktap_filter->filter_param_if_type;
433 } else if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) {
434 strlcpy(x_filter->filter_param_if_name,
435 pktap_filter->filter_param_if_name,
436 sizeof(x_filter->filter_param_if_name));
437 }
438 }
439 error = copyout(x_filters, CAST_USER_ADDR_T(ifd->ifd_data),
440 PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter));
441 if (error) {
442 printf("%s: PKTP_CMD_FILTER_GET copyout - error %d\n", __func__, error);
443 goto done;
444 }
445 break;
446 }
447 case PKTP_CMD_TAP_COUNT: {
448 uint32_t tap_count = pktap->pktp_dlt_raw_count + pktap->pktp_dlt_pkttap_count;
449
450 if (ifd->ifd_len < sizeof(tap_count)) {
451 printf("%s: PKTP_CMD_TAP_COUNT ifd_len %llu too small - error %d\n",
452 __func__, ifd->ifd_len, error);
453 error = EINVAL;
454 break;
455 }
456 error = copyout(&tap_count, CAST_USER_ADDR_T(ifd->ifd_data), sizeof(tap_count));
457 if (error) {
458 printf("%s: PKTP_CMD_TAP_COUNT copyout - error %d\n", __func__, error);
459 goto done;
460 }
461 break;
462 }
463 default:
464 error = EINVAL;
465 break;
466 }
467
468 done:
469 return error;
470 }
471
472 __private_extern__ errno_t
pktap_setdrvspec(ifnet_t ifp,struct ifdrv64 * ifd)473 pktap_setdrvspec(ifnet_t ifp, struct ifdrv64 *ifd)
474 {
475 errno_t error = 0;
476 struct pktap_softc *pktap;
477
478 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
479
480 pktap = ifp->if_softc;
481 if (pktap == NULL) {
482 error = ENOENT;
483 printf("%s: pktap NULL - error %d\n", __func__, error);
484 goto done;
485 }
486
487 switch (ifd->ifd_cmd) {
488 case PKTP_CMD_FILTER_SET: {
489 struct x_pktap_filter user_filters[PKTAP_MAX_FILTERS];
490 int i;
491 int got_op_none = 0;
492
493 if (ifd->ifd_len != PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)) {
494 printf("%s: PKTP_CMD_FILTER_SET bad ifd_len %llu - error %d\n",
495 __func__, ifd->ifd_len, error);
496 error = EINVAL;
497 break;
498 }
499 error = copyin(CAST_USER_ADDR_T(ifd->ifd_data), &user_filters, (size_t)ifd->ifd_len);
500 if (error) {
501 printf("%s: copyin - error %d\n", __func__, error);
502 goto done;
503 }
504 /*
505 * Validate user provided parameters
506 */
507 for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
508 struct x_pktap_filter *x_filter = user_filters + i;
509
510 switch (x_filter->filter_op) {
511 case PKTAP_FILTER_OP_NONE:
512 /* Following entries must be PKTAP_FILTER_OP_NONE */
513 got_op_none = 1;
514 break;
515 case PKTAP_FILTER_OP_PASS:
516 case PKTAP_FILTER_OP_SKIP:
517 /* Invalid after PKTAP_FILTER_OP_NONE */
518 if (got_op_none) {
519 error = EINVAL;
520 break;
521 }
522 break;
523 default:
524 error = EINVAL;
525 break;
526 }
527 if (error != 0) {
528 break;
529 }
530
531 switch (x_filter->filter_param) {
532 case PKTAP_FILTER_OP_NONE:
533 if (x_filter->filter_op != PKTAP_FILTER_OP_NONE) {
534 error = EINVAL;
535 break;
536 }
537 break;
538
539 /*
540 * Do not allow to tap a pktap from a pktap
541 */
542 case PKTAP_FILTER_PARAM_IF_TYPE:
543 if (x_filter->filter_param_if_type == IFT_PKTAP ||
544 x_filter->filter_param_if_type > 0xff) {
545 error = EINVAL;
546 break;
547 }
548 break;
549
550 case PKTAP_FILTER_PARAM_IF_NAME:
551 if (strncmp(x_filter->filter_param_if_name, PKTAP_IFNAME,
552 strlen(PKTAP_IFNAME)) == 0) {
553 error = EINVAL;
554 break;
555 }
556 break;
557
558 default:
559 error = EINVAL;
560 break;
561 }
562 if (error != 0) {
563 break;
564 }
565 }
566 if (error != 0) {
567 break;
568 }
569 for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
570 struct pktap_filter *pktap_filter = pktap->pktp_filters + i;
571 struct x_pktap_filter *x_filter = user_filters + i;
572
573 pktap_filter->filter_op = x_filter->filter_op;
574 pktap_filter->filter_param = x_filter->filter_param;
575
576 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) {
577 pktap_filter->filter_param_if_type = x_filter->filter_param_if_type;
578 } else if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) {
579 size_t len;
580
581 strlcpy(pktap_filter->filter_param_if_name,
582 x_filter->filter_param_if_name,
583 sizeof(pktap_filter->filter_param_if_name));
584 /*
585 * If name does not end with a number then it's a "wildcard" match
586 * where we compare the prefix of the interface name
587 */
588 len = strlen(pktap_filter->filter_param_if_name);
589 if (pktap_filter->filter_param_if_name[len] < '0' ||
590 pktap_filter->filter_param_if_name[len] > '9') {
591 pktap_filter->filter_ifname_prefix_len = len;
592 }
593 }
594 }
595 break;
596 }
597 default:
598 error = EINVAL;
599 break;
600 }
601
602 done:
603 return error;
604 }
605
606 __private_extern__ errno_t
pktap_ioctl(ifnet_t ifp,unsigned long cmd,void * data)607 pktap_ioctl(ifnet_t ifp, unsigned long cmd, void *data)
608 {
609 errno_t error = 0;
610
611 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
612
613 if ((cmd & IOC_IN)) {
614 error = kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER);
615 if (error) {
616 PKTAP_LOG(PKTP_LOG_ERROR,
617 "%s: kauth_authorize_generic(KAUTH_GENERIC_ISSUSER) - error %d\n",
618 __func__, error);
619 goto done;
620 }
621 }
622
623 switch (cmd) {
624 case SIOCGDRVSPEC32: {
625 struct ifdrv64 ifd;
626 struct ifdrv32 *ifd32 = (struct ifdrv32 *)data;
627
628 memcpy(ifd.ifd_name, ifd32->ifd_name, sizeof(ifd.ifd_name));
629 ifd.ifd_cmd = ifd32->ifd_cmd;
630 ifd.ifd_len = ifd32->ifd_len;
631 ifd.ifd_data = ifd32->ifd_data;
632
633 error = pktap_getdrvspec(ifp, &ifd);
634
635 break;
636 }
637 case SIOCGDRVSPEC64: {
638 struct ifdrv64 *ifd64 = (struct ifdrv64 *)data;
639
640 error = pktap_getdrvspec(ifp, ifd64);
641
642 break;
643 }
644 case SIOCSDRVSPEC32: {
645 struct ifdrv64 ifd;
646 struct ifdrv32 *ifd32 = (struct ifdrv32 *)data;
647
648 memcpy(ifd.ifd_name, ifd32->ifd_name, sizeof(ifd.ifd_name));
649 ifd.ifd_cmd = ifd32->ifd_cmd;
650 ifd.ifd_len = ifd32->ifd_len;
651 ifd.ifd_data = ifd32->ifd_data;
652
653 error = pktap_setdrvspec(ifp, &ifd);
654 break;
655 }
656 case SIOCSDRVSPEC64: {
657 struct ifdrv64 *ifd64 = (struct ifdrv64 *)data;
658
659 error = pktap_setdrvspec(ifp, ifd64);
660
661 break;
662 }
663 default:
664 error = ENOTSUP;
665 break;
666 }
667 done:
668 return error;
669 }
670
671 __private_extern__ void
pktap_detach(ifnet_t ifp)672 pktap_detach(ifnet_t ifp)
673 {
674 struct pktap_softc *pktap;
675
676 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname);
677
678 lck_rw_lock_exclusive(&pktap_lck_rw);
679
680 pktap = ifp->if_softc;
681 ifp->if_softc = NULL;
682 LIST_REMOVE(pktap, pktp_link);
683
684 lck_rw_done(&pktap_lck_rw);
685
686 /* Drop reference as it's no more on the global list */
687 ifnet_release(ifp);
688
689 if_clone_softc_deallocate(&pktap_cloner, pktap);
690 /* This is for the reference taken by ifnet_attach() */
691 (void) ifnet_release(ifp);
692 }
693
694 __private_extern__ int
pktap_filter_evaluate(struct pktap_softc * pktap,struct ifnet * ifp)695 pktap_filter_evaluate(struct pktap_softc *pktap, struct ifnet *ifp)
696 {
697 int i;
698 int result = PKTAP_FILTER_SKIP; /* Need positive matching rule to pass */
699 int match = 0;
700
701 for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
702 struct pktap_filter *pktap_filter = pktap->pktp_filters + i;
703 size_t len = pktap_filter->filter_ifname_prefix_len != 0 ?
704 pktap_filter->filter_ifname_prefix_len : PKTAP_IFXNAMESIZE;
705
706 switch (pktap_filter->filter_op) {
707 case PKTAP_FILTER_OP_NONE:
708 match = 1;
709 break;
710
711 case PKTAP_FILTER_OP_PASS:
712 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) {
713 if (pktap_filter->filter_param_if_type == 0 ||
714 ifp->if_type == pktap_filter->filter_param_if_type) {
715 result = PKTAP_FILTER_OK;
716 match = 1;
717 PKTAP_LOG(PKTP_LOG_FILTER, "pass %s match type %u\n",
718 ifp->if_xname, pktap_filter->filter_param_if_type);
719 break;
720 }
721 }
722 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) {
723 if (strncmp(ifp->if_xname, pktap_filter->filter_param_if_name,
724 len) == 0) {
725 result = PKTAP_FILTER_OK;
726 match = 1;
727 PKTAP_LOG(PKTP_LOG_FILTER, "pass %s match name %s\n",
728 ifp->if_xname, pktap_filter->filter_param_if_name);
729 break;
730 }
731 }
732 break;
733
734 case PKTAP_FILTER_OP_SKIP:
735 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) {
736 if (pktap_filter->filter_param_if_type == 0 ||
737 ifp->if_type == pktap_filter->filter_param_if_type) {
738 result = PKTAP_FILTER_SKIP;
739 match = 1;
740 PKTAP_LOG(PKTP_LOG_FILTER, "skip %s match type %u\n",
741 ifp->if_xname, pktap_filter->filter_param_if_type);
742 break;
743 }
744 }
745 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) {
746 if (strncmp(ifp->if_xname, pktap_filter->filter_param_if_name,
747 len) == 0) {
748 result = PKTAP_FILTER_SKIP;
749 match = 1;
750 PKTAP_LOG(PKTP_LOG_FILTER, "skip %s match name %s\n",
751 ifp->if_xname, pktap_filter->filter_param_if_name);
752 break;
753 }
754 }
755 break;
756 }
757 if (match) {
758 break;
759 }
760 }
761
762 if (match == 0) {
763 PKTAP_LOG(PKTP_LOG_FILTER, "%s no match\n",
764 ifp->if_xname);
765 }
766 return result;
767 }
768
769 static void
pktap_set_procinfo(struct pktap_header * hdr,struct so_procinfo * soprocinfo)770 pktap_set_procinfo(struct pktap_header *hdr, struct so_procinfo *soprocinfo)
771 {
772 hdr->pth_pid = soprocinfo->spi_pid;
773 if (hdr->pth_comm[0] == 0) {
774 proc_name(soprocinfo->spi_pid, hdr->pth_comm, MAXCOMLEN);
775 }
776 strlcpy(&hdr->pth_comm[0], &soprocinfo->spi_proc_name[0], sizeof(hdr->pth_comm));
777
778 if (soprocinfo->spi_pid != 0) {
779 uuid_copy(hdr->pth_uuid, soprocinfo->spi_uuid);
780 }
781
782 if (soprocinfo->spi_delegated != 0) {
783 hdr->pth_flags |= PTH_FLAG_PROC_DELEGATED;
784 hdr->pth_epid = soprocinfo->spi_epid;
785 strlcpy(&hdr->pth_ecomm[0], &soprocinfo->spi_e_proc_name[0], sizeof(hdr->pth_ecomm));
786 uuid_copy(hdr->pth_euuid, soprocinfo->spi_euuid);
787 }
788 }
789
790 __private_extern__ void
pktap_finalize_proc_info(struct pktap_header * hdr)791 pktap_finalize_proc_info(struct pktap_header *hdr)
792 {
793 int found;
794 struct so_procinfo soprocinfo;
795
796 if (!(hdr->pth_flags & PTH_FLAG_DELAY_PKTAP)) {
797 return;
798 }
799
800 if (hdr->pth_ipproto == IPPROTO_TCP) {
801 found = inp_findinpcb_procinfo(&tcbinfo, hdr->pth_flowid,
802 &soprocinfo);
803 } else if (hdr->pth_ipproto == IPPROTO_UDP) {
804 found = inp_findinpcb_procinfo(&udbinfo, hdr->pth_flowid,
805 &soprocinfo);
806 } else {
807 found = inp_findinpcb_procinfo(&ripcbinfo, hdr->pth_flowid,
808 &soprocinfo);
809 }
810
811 if (found == 1) {
812 pktap_set_procinfo(hdr, &soprocinfo);
813 }
814 }
815
816 static void
pktap_v2_set_procinfo(struct pktap_v2_hdr * pktap_v2_hdr,struct so_procinfo * soprocinfo)817 pktap_v2_set_procinfo(struct pktap_v2_hdr *pktap_v2_hdr,
818 struct so_procinfo *soprocinfo)
819 {
820 pktap_v2_hdr->pth_pid = soprocinfo->spi_pid;
821
822 if (soprocinfo->spi_pid != 0 && soprocinfo->spi_pid != -1) {
823 if (pktap_v2_hdr->pth_comm_offset != 0) {
824 char *ptr = ((char *)pktap_v2_hdr) +
825 pktap_v2_hdr->pth_comm_offset;
826
827 strlcpy(ptr, &soprocinfo->spi_proc_name[0], PKTAP_MAX_COMM_SIZE);
828 }
829 if (pktap_v2_hdr->pth_uuid_offset != 0) {
830 uuid_t *ptr = (uuid_t *) (((char *)pktap_v2_hdr) +
831 pktap_v2_hdr->pth_uuid_offset);
832
833 uuid_copy(*ptr, soprocinfo->spi_uuid);
834 }
835 }
836
837 if (!(pktap_v2_hdr->pth_flags & PTH_FLAG_PROC_DELEGATED)) {
838 return;
839 }
840
841 /*
842 * The effective UUID may be set independently from the effective pid
843 */
844 if (soprocinfo->spi_delegated != 0) {
845 pktap_v2_hdr->pth_flags |= PTH_FLAG_PROC_DELEGATED;
846 pktap_v2_hdr->pth_e_pid = soprocinfo->spi_epid;
847
848 if (soprocinfo->spi_pid != 0 && soprocinfo->spi_pid != -1 &&
849 pktap_v2_hdr->pth_e_comm_offset != 0) {
850 char *ptr = ((char *)pktap_v2_hdr) +
851 pktap_v2_hdr->pth_e_comm_offset;
852
853 strlcpy(ptr, &soprocinfo->spi_e_proc_name[0], PKTAP_MAX_COMM_SIZE);
854 }
855 if (pktap_v2_hdr->pth_e_uuid_offset != 0) {
856 uuid_t *ptr = (uuid_t *) (((char *)pktap_v2_hdr) +
857 pktap_v2_hdr->pth_e_uuid_offset);
858
859 uuid_copy(*ptr, soprocinfo->spi_euuid);
860 }
861 }
862 }
863
864 __private_extern__ void
pktap_v2_finalize_proc_info(struct pktap_v2_hdr * pktap_v2_hdr)865 pktap_v2_finalize_proc_info(struct pktap_v2_hdr *pktap_v2_hdr)
866 {
867 int found;
868 struct so_procinfo soprocinfo;
869
870 if (!(pktap_v2_hdr->pth_flags & PTH_FLAG_DELAY_PKTAP)) {
871 return;
872 }
873
874 if (pktap_v2_hdr->pth_ipproto == IPPROTO_TCP) {
875 found = inp_findinpcb_procinfo(&tcbinfo,
876 pktap_v2_hdr->pth_flowid, &soprocinfo);
877 } else if (pktap_v2_hdr->pth_ipproto == IPPROTO_UDP) {
878 found = inp_findinpcb_procinfo(&udbinfo,
879 pktap_v2_hdr->pth_flowid, &soprocinfo);
880 } else {
881 found = inp_findinpcb_procinfo(&ripcbinfo,
882 pktap_v2_hdr->pth_flowid, &soprocinfo);
883 }
884 if (found == 1) {
885 pktap_v2_set_procinfo(pktap_v2_hdr, &soprocinfo);
886 }
887 }
888
889 __private_extern__ void
pktap_fill_proc_info(struct pktap_header * hdr,protocol_family_t proto,struct mbuf * m,u_int32_t pre,int outgoing,struct ifnet * ifp)890 pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto,
891 struct mbuf *m, u_int32_t pre, int outgoing, struct ifnet *ifp)
892 {
893 /*
894 * Getting the pid and procname is expensive
895 * For outgoing, do the lookup only if there's an
896 * associated socket as indicated by the flowhash
897 */
898 if (outgoing != 0 && m->m_pkthdr.pkt_flowsrc == FLOWSRC_INPCB) {
899 /*
900 * To avoid lock ordering issues we delay the proc UUID lookup
901 * to the BPF read as we cannot
902 * assume the socket lock is unlocked on output
903 */
904 hdr->pth_flags |= PTH_FLAG_DELAY_PKTAP;
905 hdr->pth_flags |= PTH_FLAG_SOCKET;
906 hdr->pth_flowid = m->m_pkthdr.pkt_flowid;
907
908 if (m->m_pkthdr.pkt_flags & PKTF_FLOW_RAWSOCK) {
909 hdr->pth_ipproto = IPPROTO_RAW;
910 } else {
911 hdr->pth_ipproto = m->m_pkthdr.pkt_proto;
912 }
913
914 if (hdr->pth_ipproto == IPPROTO_TCP) {
915 hdr->pth_pid = m->m_pkthdr.tx_tcp_pid;
916 hdr->pth_epid = m->m_pkthdr.tx_tcp_e_pid;
917 } else if (hdr->pth_ipproto == IPPROTO_UDP) {
918 hdr->pth_pid = m->m_pkthdr.tx_udp_pid;
919 hdr->pth_epid = m->m_pkthdr.tx_udp_e_pid;
920 } else if (hdr->pth_ipproto == IPPROTO_RAW) {
921 hdr->pth_pid = m->m_pkthdr.tx_rawip_pid;
922 hdr->pth_epid = m->m_pkthdr.tx_rawip_e_pid;
923 }
924
925 if (hdr->pth_pid != 0 && hdr->pth_pid != -1) {
926 proc_name(hdr->pth_pid, hdr->pth_comm, MAXCOMLEN);
927 } else {
928 hdr->pth_pid = -1;
929 }
930
931 if (hdr->pth_epid != 0 && hdr->pth_epid != -1) {
932 hdr->pth_flags |= PTH_FLAG_PROC_DELEGATED;
933 proc_name(hdr->pth_epid, hdr->pth_ecomm, MAXCOMLEN);
934 } else {
935 hdr->pth_epid = -1;
936 }
937
938 if (m->m_pkthdr.pkt_flags & PKTF_NEW_FLOW) {
939 hdr->pth_flags |= PTH_FLAG_NEW_FLOW;
940 }
941 } else if (outgoing == 0) {
942 int found = 0;
943 struct so_procinfo soprocinfo;
944 struct inpcb *inp = NULL;
945
946 memset(&soprocinfo, 0, sizeof(struct so_procinfo));
947
948 if (proto == PF_INET) {
949 struct ip ip;
950 errno_t error;
951 size_t hlen;
952 struct in_addr faddr, laddr;
953 u_short fport = 0, lport = 0;
954 struct inpcbinfo *pcbinfo = NULL;
955 int wildcard = 0;
956
957 error = mbuf_copydata(m, pre, sizeof(struct ip), &ip);
958 if (error != 0) {
959 PKTAP_LOG(PKTP_LOG_ERROR,
960 "mbuf_copydata tcp v4 failed for %s\n",
961 hdr->pth_ifname);
962 goto done;
963 }
964 hlen = IP_VHL_HL(ip.ip_vhl) << 2;
965
966 faddr = ip.ip_src;
967 laddr = ip.ip_dst;
968
969 if (ip.ip_p == IPPROTO_TCP) {
970 struct tcphdr th;
971
972 error = mbuf_copydata(m, pre + hlen,
973 sizeof(struct tcphdr), &th);
974 if (error != 0) {
975 goto done;
976 }
977
978 fport = th.th_sport;
979 lport = th.th_dport;
980
981 pcbinfo = &tcbinfo;
982 } else if (ip.ip_p == IPPROTO_UDP) {
983 struct udphdr uh;
984
985 error = mbuf_copydata(m, pre + hlen,
986 sizeof(struct udphdr), &uh);
987 if (error != 0) {
988 PKTAP_LOG(PKTP_LOG_ERROR,
989 "mbuf_copydata udp v4 failed for %s\n",
990 hdr->pth_ifname);
991 goto done;
992 }
993 fport = uh.uh_sport;
994 lport = uh.uh_dport;
995
996 pcbinfo = &udbinfo;
997 wildcard = 1;
998 }
999 if (pcbinfo != NULL) {
1000 inp = in_pcblookup_hash(pcbinfo, faddr, fport,
1001 laddr, lport, wildcard, outgoing ? NULL : ifp);
1002
1003 if (inp == NULL && hdr->pth_iftype != IFT_LOOP) {
1004 PKTAP_LOG(PKTP_LOG_NOPCB,
1005 "in_pcblookup_hash no pcb %s\n",
1006 hdr->pth_ifname);
1007 }
1008 } else {
1009 PKTAP_LOG(PKTP_LOG_NOPCB,
1010 "unknown ip_p %u on %s\n",
1011 ip.ip_p, hdr->pth_ifname);
1012 pktap_hexdump(PKTP_LOG_NOPCB, &ip, sizeof(struct ip));
1013 }
1014 } else if (proto == PF_INET6) {
1015 struct ip6_hdr ip6;
1016 errno_t error;
1017 struct in6_addr *faddr;
1018 struct in6_addr *laddr;
1019 u_short fport = 0, lport = 0;
1020 struct inpcbinfo *pcbinfo = NULL;
1021 int wildcard = 0;
1022
1023 error = mbuf_copydata(m, pre, sizeof(struct ip6_hdr), &ip6);
1024 if (error != 0) {
1025 goto done;
1026 }
1027
1028 faddr = &ip6.ip6_src;
1029 laddr = &ip6.ip6_dst;
1030
1031 if (ip6.ip6_nxt == IPPROTO_TCP) {
1032 struct tcphdr th;
1033
1034 error = mbuf_copydata(m, pre + sizeof(struct ip6_hdr),
1035 sizeof(struct tcphdr), &th);
1036 if (error != 0) {
1037 PKTAP_LOG(PKTP_LOG_ERROR,
1038 "mbuf_copydata tcp v6 failed for %s\n",
1039 hdr->pth_ifname);
1040 goto done;
1041 }
1042
1043 fport = th.th_sport;
1044 lport = th.th_dport;
1045
1046 pcbinfo = &tcbinfo;
1047 } else if (ip6.ip6_nxt == IPPROTO_UDP) {
1048 struct udphdr uh;
1049
1050 error = mbuf_copydata(m, pre + sizeof(struct ip6_hdr),
1051 sizeof(struct udphdr), &uh);
1052 if (error != 0) {
1053 PKTAP_LOG(PKTP_LOG_ERROR,
1054 "mbuf_copydata udp v6 failed for %s\n",
1055 hdr->pth_ifname);
1056 goto done;
1057 }
1058
1059 fport = uh.uh_sport;
1060 lport = uh.uh_dport;
1061
1062 pcbinfo = &udbinfo;
1063 wildcard = 1;
1064 }
1065 if (pcbinfo != NULL) {
1066 inp = in6_pcblookup_hash(pcbinfo, faddr, fport, ip6_input_getdstifscope(m),
1067 laddr, lport, ip6_input_getsrcifscope(m), wildcard, outgoing ? NULL : ifp);
1068
1069 if (inp == NULL && hdr->pth_iftype != IFT_LOOP) {
1070 PKTAP_LOG(PKTP_LOG_NOPCB,
1071 "in6_pcblookup_hash no pcb %s\n",
1072 hdr->pth_ifname);
1073 }
1074 } else {
1075 PKTAP_LOG(PKTP_LOG_NOPCB,
1076 "unknown ip6.ip6_nxt %u on %s\n",
1077 ip6.ip6_nxt, hdr->pth_ifname);
1078 pktap_hexdump(PKTP_LOG_NOPCB, &ip6, sizeof(struct ip6_hdr));
1079 }
1080 }
1081 if (inp != NULL) {
1082 hdr->pth_flags |= PTH_FLAG_SOCKET;
1083 if (inp->inp_state != INPCB_STATE_DEAD && inp->inp_socket != NULL) {
1084 found = 1;
1085 inp_get_soprocinfo(inp, &soprocinfo);
1086 }
1087 in_pcb_checkstate(inp, WNT_RELEASE, 0);
1088 }
1089 done:
1090 /*
1091 * -1 means PID not found
1092 */
1093 hdr->pth_pid = -1;
1094 hdr->pth_epid = -1;
1095
1096 if (found != 0) {
1097 pktap_set_procinfo(hdr, &soprocinfo);
1098 }
1099 }
1100 }
1101
1102 __private_extern__ void
pktap_bpf_tap(struct ifnet * ifp,protocol_family_t proto,struct mbuf * m,u_int32_t pre,u_int32_t post,int outgoing)1103 pktap_bpf_tap(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m,
1104 u_int32_t pre, u_int32_t post, int outgoing)
1105 {
1106 struct pktap_softc *pktap;
1107 void (*bpf_tap_func)(ifnet_t, u_int32_t, mbuf_t, void *, size_t) =
1108 outgoing ? bpf_tap_out : bpf_tap_in;
1109
1110 /*
1111 * Skip the coprocessor interface
1112 */
1113 if (!intcoproc_unrestricted && IFNET_IS_INTCOPROC(ifp)) {
1114 return;
1115 }
1116
1117 lck_rw_lock_shared(&pktap_lck_rw);
1118
1119 /*
1120 * No need to take the ifnet_lock as the struct ifnet field if_bpf is
1121 * protected by the BPF subsystem
1122 */
1123 LIST_FOREACH(pktap, &pktap_list, pktp_link) {
1124 int filter_result;
1125
1126 filter_result = pktap_filter_evaluate(pktap, ifp);
1127 if (filter_result == PKTAP_FILTER_SKIP) {
1128 continue;
1129 }
1130
1131 if (pktap->pktp_dlt_raw_count > 0) {
1132 /* We accept only IPv4 and IPv6 packets for the raw DLT */
1133 if ((proto == AF_INET || proto == AF_INET6) &&
1134 !(m->m_pkthdr.pkt_flags & PKTF_INET_RESOLVE)) {
1135 /*
1136 * We can play just with the length of the first mbuf in the
1137 * chain because bpf_tap_imp() disregard the packet length
1138 * of the mbuf packet header.
1139 */
1140 if (mbuf_setdata(m, m->m_data + pre, m->m_len - pre) == 0) {
1141 bpf_tap_func(pktap->pktp_ifp, DLT_RAW, m, NULL, 0);
1142 mbuf_setdata(m, m->m_data - pre, m->m_len + pre);
1143 }
1144 }
1145 }
1146
1147 if (pktap->pktp_dlt_pkttap_count > 0) {
1148 struct {
1149 struct pktap_header hdr;
1150 u_int32_t proto;
1151 } hdr_buffer;
1152 struct pktap_header *hdr = &hdr_buffer.hdr;
1153 size_t hdr_size = sizeof(struct pktap_header);
1154 int unknown_if_type = 0;
1155 size_t data_adjust = 0;
1156 u_int32_t pre_adjust = 0;
1157
1158 /* Verify the structure is packed */
1159 _CASSERT(sizeof(hdr_buffer) == sizeof(struct pktap_header) + sizeof(u_int32_t));
1160
1161 bzero(&hdr_buffer, sizeof(hdr_buffer));
1162 hdr->pth_length = sizeof(struct pktap_header);
1163 hdr->pth_type_next = PTH_TYPE_PACKET;
1164
1165 /*
1166 * Set DLT of packet based on interface type
1167 */
1168 switch (ifp->if_type) {
1169 case IFT_LOOP:
1170 case IFT_GIF:
1171 case IFT_STF:
1172 case IFT_CELLULAR:
1173 /*
1174 * Packets from pdp interfaces have no loopback
1175 * header that contain the protocol number.
1176 * As BPF just concatenate the header and the
1177 * packet content in a single buffer,
1178 * stash the protocol after the pktap header
1179 * and adjust the size of the header accordingly
1180 */
1181 hdr->pth_dlt = DLT_NULL;
1182 if (pre == 0) {
1183 hdr_buffer.proto = proto;
1184 hdr_size = sizeof(hdr_buffer);
1185 pre_adjust = sizeof(hdr_buffer.proto);
1186 }
1187 break;
1188 case IFT_ETHER:
1189 case IFT_BRIDGE:
1190 case IFT_L2VLAN:
1191 case IFT_IEEE8023ADLAG:
1192 hdr->pth_dlt = DLT_EN10MB;
1193 break;
1194 case IFT_PPP:
1195 hdr->pth_dlt = DLT_PPP;
1196 break;
1197 case IFT_IEEE1394:
1198 hdr->pth_dlt = DLT_APPLE_IP_OVER_IEEE1394;
1199 break;
1200 case IFT_OTHER:
1201 if (ifp->if_family == IFNET_FAMILY_IPSEC ||
1202 ifp->if_family == IFNET_FAMILY_UTUN) {
1203 /*
1204 * For utun:
1205 * - incoming packets do not have the prefix set to four
1206 * - some packets are as small as two bytes!
1207 */
1208 if (m_pktlen(m) < 4) {
1209 goto done;
1210 }
1211 if (proto != AF_INET && proto != AF_INET6) {
1212 goto done;
1213 }
1214 if (proto == AF_INET && (size_t) m_pktlen(m) - 4 < sizeof(struct ip)) {
1215 goto done;
1216 }
1217 if (proto == AF_INET6 && (size_t) m_pktlen(m) - 4 < sizeof(struct ip6_hdr)) {
1218 goto done;
1219 }
1220
1221 /*
1222 * Handle two cases:
1223 * - The old utun encapsulation with the protocol family in network order
1224 * - A raw IPv4 or IPv6 packet
1225 */
1226 uint8_t data = *(uint8_t *)mbuf_data(m);
1227 if ((data >> 4) == 4 || (data >> 4) == 6) {
1228 pre = 4;
1229 } else {
1230 /*
1231 * Skip the protocol in the mbuf as it's in network order
1232 */
1233 pre = 4;
1234 data_adjust = 4;
1235 }
1236 }
1237 hdr->pth_dlt = DLT_NULL;
1238 hdr_buffer.proto = proto;
1239 hdr_size = sizeof(hdr_buffer);
1240 break;
1241 default:
1242 if (pre == 0) {
1243 hdr->pth_dlt = DLT_RAW;
1244 } else {
1245 unknown_if_type = 1;
1246 }
1247 break;
1248 }
1249 if (unknown_if_type) {
1250 PKTAP_LOG(PKTP_LOG_FUNC,
1251 "unknown if_type %u for %s\n",
1252 ifp->if_type, ifp->if_xname);
1253 pktap_count_unknown_if_type += 1;
1254 } else {
1255 strlcpy(hdr->pth_ifname, ifp->if_xname,
1256 sizeof(hdr->pth_ifname));
1257 hdr->pth_flags |= outgoing ? PTH_FLAG_DIR_OUT : PTH_FLAG_DIR_IN;
1258 hdr->pth_protocol_family = proto;
1259 hdr->pth_frame_pre_length = pre + pre_adjust;
1260 hdr->pth_frame_post_length = post;
1261 hdr->pth_iftype = ifp->if_type;
1262 hdr->pth_ifunit = ifp->if_unit;
1263
1264 if (m->m_pkthdr.pkt_flags & PKTF_KEEPALIVE) {
1265 hdr->pth_flags |= PTH_FLAG_KEEP_ALIVE;
1266 }
1267 if (m->m_pkthdr.pkt_flags & PKTF_TCP_REXMT) {
1268 hdr->pth_flags |= PTH_FLAG_REXMIT;
1269 }
1270 if (m->m_pkthdr.pkt_flags & PKTF_WAKE_PKT) {
1271 hdr->pth_flags |= PTH_FLAG_WAKE_PKT;
1272 }
1273
1274 pktap_fill_proc_info(hdr, proto, m, pre, outgoing, ifp);
1275
1276 hdr->pth_svc = so_svc2tc(m->m_pkthdr.pkt_svc);
1277
1278 if (data_adjust == 0) {
1279 bpf_tap_func(pktap->pktp_ifp, DLT_PKTAP, m, hdr, hdr_size);
1280 } else {
1281 /*
1282 * We can play just with the length of the first mbuf in the
1283 * chain because bpf_tap_imp() disregard the packet length
1284 * of the mbuf packet header.
1285 */
1286 if (mbuf_setdata(m, m->m_data + data_adjust, m->m_len - data_adjust) == 0) {
1287 bpf_tap_func(pktap->pktp_ifp, DLT_PKTAP, m, hdr, hdr_size);
1288 mbuf_setdata(m, m->m_data - data_adjust, m->m_len + data_adjust);
1289 }
1290 }
1291 }
1292 }
1293 }
1294 done:
1295 lck_rw_done(&pktap_lck_rw);
1296 }
1297
1298 __private_extern__ void
pktap_input(struct ifnet * ifp,protocol_family_t proto,struct mbuf * m,char * frame_header)1299 pktap_input(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m,
1300 char *frame_header)
1301 {
1302 char *hdr;
1303 char *start;
1304
1305 /* Fast path */
1306 if (pktap_total_tap_count == 0 ||
1307 (m->m_pkthdr.pkt_flags & PKTF_SKIP_PKTAP) != 0) {
1308 return;
1309 }
1310
1311 hdr = (char *)mbuf_data(m);
1312 start = (char *)mbuf_datastart(m);
1313 /* Make sure the frame header is fully contained in the mbuf */
1314 if (frame_header != NULL && frame_header >= start && frame_header <= hdr) {
1315 size_t o_len = m->m_len;
1316 u_int32_t pre = (u_int32_t)(hdr - frame_header);
1317
1318 if (mbuf_setdata(m, frame_header, o_len + pre) == 0) {
1319 PKTAP_LOG(PKTP_LOG_INPUT, "ifp %s proto %u pre %u post %u\n",
1320 ifp->if_xname, proto, pre, 0);
1321
1322 pktap_bpf_tap(ifp, proto, m, pre, 0, 0);
1323 mbuf_setdata(m, hdr, o_len);
1324 }
1325 } else {
1326 PKTAP_LOG(PKTP_LOG_INPUT, "ifp %s proto %u pre %u post %u\n",
1327 ifp->if_xname, proto, 0, 0);
1328
1329 pktap_bpf_tap(ifp, proto, m, 0, 0, 0);
1330 }
1331 }
1332
1333 __private_extern__ void
pktap_output(struct ifnet * ifp,protocol_family_t proto,struct mbuf * m,u_int32_t pre,u_int32_t post)1334 pktap_output(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m,
1335 u_int32_t pre, u_int32_t post)
1336 {
1337 /* Fast path */
1338 if (pktap_total_tap_count == 0 ||
1339 (m->m_pkthdr.pkt_flags & PKTF_SKIP_PKTAP) != 0) {
1340 return;
1341 }
1342
1343 PKTAP_LOG(PKTP_LOG_OUTPUT, "ifp %s proto %u pre %u post %u\n",
1344 ifp->if_xname, proto, pre, post);
1345
1346 pktap_bpf_tap(ifp, proto, m, pre, post, 1);
1347 }
1348
1349 #if SKYWALK
1350
1351 typedef void (*tap_packet_func)(ifnet_t interface, u_int32_t dlt,
1352 kern_packet_t packet, void *header, size_t header_len);
1353
1354 static void
pktap_bpf_tap_packet(struct ifnet * ifp,protocol_family_t proto,uint32_t dlt,pid_t pid,const char * pname,pid_t epid,const char * epname,kern_packet_t pkt,const void * header,size_t header_length,uint8_t ipproto,uint32_t flowid,uint32_t flags,tap_packet_func tap_func)1355 pktap_bpf_tap_packet(struct ifnet *ifp, protocol_family_t proto, uint32_t dlt,
1356 pid_t pid, const char * pname, pid_t epid, const char * epname,
1357 kern_packet_t pkt, const void * header, size_t header_length,
1358 uint8_t ipproto, uint32_t flowid, uint32_t flags, tap_packet_func tap_func)
1359 {
1360 struct {
1361 struct pktap_header pkth;
1362 union {
1363 uint8_t llhdr[16];
1364 uint32_t proto;
1365 } extra;
1366 } hdr_buffer;
1367 struct pktap_header *hdr;
1368 size_t hdr_size;
1369 struct pktap_softc *pktap;
1370 uint32_t pre_length = 0;
1371
1372 /*
1373 * Skip the coprocessor interface
1374 */
1375 if (!intcoproc_unrestricted && IFNET_IS_INTCOPROC(ifp)) {
1376 return;
1377 }
1378
1379 if (proto != AF_INET && proto != AF_INET6) {
1380 PKTAP_LOG(PKTP_LOG_ERROR,
1381 "unsupported protocol %d\n",
1382 proto);
1383 return;
1384 }
1385
1386 /* assume that we'll be tapping using PKTAP */
1387 hdr = &hdr_buffer.pkth;
1388 bzero(&hdr_buffer, sizeof(hdr_buffer));
1389 hdr->pth_length = sizeof(struct pktap_header);
1390 hdr->pth_type_next = PTH_TYPE_PACKET;
1391 hdr->pth_dlt = dlt;
1392 hdr->pth_pid = pid;
1393 if (pid != epid) {
1394 hdr->pth_epid = epid;
1395 } else {
1396 hdr->pth_epid = -1;
1397 }
1398 if (pname != NULL) {
1399 strlcpy(hdr->pth_comm, pname, sizeof(hdr->pth_comm));
1400 }
1401 if (epname != NULL) {
1402 strlcpy(hdr->pth_ecomm, epname, sizeof(hdr->pth_ecomm));
1403 }
1404 strlcpy(hdr->pth_ifname, ifp->if_xname, sizeof(hdr->pth_ifname));
1405 hdr->pth_flags |= flags;
1406 hdr->pth_ipproto = ipproto;
1407 hdr->pth_flowid = flowid;
1408 /*
1409 * Do the same as pktap_fill_proc_info() to defer looking up inpcb.
1410 * We do it for both inbound and outbound packets unlike the mbuf case.
1411 */
1412 if ((flags & PTH_FLAG_SOCKET) != 0 && ipproto != 0 && flowid != 0) {
1413 hdr->pth_flags |= PTH_FLAG_DELAY_PKTAP;
1414 }
1415 if (kern_packet_get_wake_flag(pkt)) {
1416 hdr->pth_flags |= PTH_FLAG_WAKE_PKT;
1417 }
1418 hdr->pth_trace_tag = kern_packet_get_trace_tag(pkt);
1419 hdr->pth_protocol_family = proto;
1420 hdr->pth_svc = so_svc2tc((mbuf_svc_class_t)
1421 kern_packet_get_service_class(pkt));
1422 hdr->pth_iftype = ifp->if_type;
1423 hdr->pth_ifunit = ifp->if_unit;
1424 hdr_size = sizeof(struct pktap_header);
1425 if (header != NULL && header_length != 0) {
1426 if (header_length > sizeof(hdr_buffer.extra.llhdr)) {
1427 PKTAP_LOG(PKTP_LOG_ERROR,
1428 "%s: header %d > %d\n",
1429 if_name(ifp), (int)header_length,
1430 (int)sizeof(hdr_buffer.extra.llhdr));
1431 return;
1432 }
1433 bcopy(header, hdr_buffer.extra.llhdr, header_length);
1434 hdr_size += header_length;
1435 pre_length = (uint32_t)header_length;
1436 } else if (dlt == DLT_RAW) {
1437 /*
1438 * Use the same DLT as has been used for the mbuf path
1439 */
1440 hdr->pth_dlt = DLT_NULL;
1441 hdr_buffer.extra.proto = proto;
1442 hdr_size = sizeof(struct pktap_header) + sizeof(u_int32_t);
1443 pre_length = sizeof(hdr_buffer.extra.proto);
1444 } else if (dlt == DLT_EN10MB) {
1445 pre_length = ETHER_HDR_LEN;
1446 }
1447 hdr->pth_frame_pre_length = pre_length;
1448
1449 lck_rw_lock_shared(&pktap_lck_rw);
1450 /*
1451 * No need to take the ifnet_lock as the struct ifnet field if_bpf is
1452 * protected by the BPF subsystem
1453 */
1454 LIST_FOREACH(pktap, &pktap_list, pktp_link) {
1455 int filter_result;
1456
1457 filter_result = pktap_filter_evaluate(pktap, ifp);
1458 if (filter_result == PKTAP_FILTER_SKIP) {
1459 continue;
1460 }
1461
1462 if (dlt == DLT_RAW && pktap->pktp_dlt_raw_count > 0) {
1463 (*tap_func)(pktap->pktp_ifp, DLT_RAW, pkt, NULL, 0);
1464 }
1465 if (pktap->pktp_dlt_pkttap_count > 0) {
1466 (*tap_func)(pktap->pktp_ifp, DLT_PKTAP,
1467 pkt, hdr, hdr_size);
1468 }
1469 }
1470 lck_rw_done(&pktap_lck_rw);
1471 }
1472
1473 void
pktap_input_packet(struct ifnet * ifp,protocol_family_t proto,uint32_t dlt,pid_t pid,const char * pname,pid_t epid,const char * epname,kern_packet_t pkt,const void * header,size_t header_length,uint8_t ipproto,uint32_t flowid,uint32_t flags)1474 pktap_input_packet(struct ifnet *ifp, protocol_family_t proto, uint32_t dlt,
1475 pid_t pid, const char * pname, pid_t epid, const char * epname,
1476 kern_packet_t pkt, const void * header, size_t header_length,
1477 uint8_t ipproto, uint32_t flowid, uint32_t flags)
1478 {
1479 /* Fast path */
1480 if (pktap_total_tap_count == 0) {
1481 return;
1482 }
1483
1484 PKTAP_LOG(PKTP_LOG_INPUT, "IN %s proto %u pid %d epid %d\n",
1485 ifp->if_xname, proto, pid, epid);
1486 pktap_bpf_tap_packet(ifp, proto, dlt, pid, pname, epid, epname, pkt,
1487 header, header_length, ipproto, flowid,
1488 PTH_FLAG_DIR_IN | (flags & ~(PTH_FLAG_DIR_IN | PTH_FLAG_DIR_OUT)),
1489 bpf_tap_packet_in);
1490 }
1491
1492 void
pktap_output_packet(struct ifnet * ifp,protocol_family_t proto,uint32_t dlt,pid_t pid,const char * pname,pid_t epid,const char * epname,kern_packet_t pkt,const void * header,size_t header_length,uint8_t ipproto,uint32_t flowid,uint32_t flags)1493 pktap_output_packet(struct ifnet *ifp, protocol_family_t proto, uint32_t dlt,
1494 pid_t pid, const char * pname, pid_t epid, const char * epname,
1495 kern_packet_t pkt, const void * header, size_t header_length,
1496 uint8_t ipproto, uint32_t flowid, uint32_t flags)
1497 {
1498 /* Fast path */
1499 if (pktap_total_tap_count == 0) {
1500 return;
1501 }
1502
1503 PKTAP_LOG(PKTP_LOG_OUTPUT, "OUT %s proto %u pid %d epid %d\n",
1504 ifp->if_xname, proto, pid, epid);
1505 pktap_bpf_tap_packet(ifp, proto, dlt, pid, pname, epid, epname, pkt,
1506 header, header_length, ipproto, flowid,
1507 PTH_FLAG_DIR_OUT | (flags & ~(PTH_FLAG_DIR_IN | PTH_FLAG_DIR_OUT)),
1508 bpf_tap_packet_out);
1509 }
1510
1511 #endif /* SKYWALK */
1512
1513 void
convert_to_pktap_header_to_v2(struct bpf_packet * bpf_pkt,bool truncate)1514 convert_to_pktap_header_to_v2(struct bpf_packet *bpf_pkt, bool truncate)
1515 {
1516 struct pktap_header *pktap_header;
1517 size_t extra_src_size;
1518 struct pktap_buffer_v2_hdr_extra pktap_buffer_v2_hdr_extra;
1519 struct pktap_v2_hdr_space *pktap_v2_hdr_space;
1520 struct pktap_v2_hdr *pktap_v2_hdr;
1521 uint8_t *ptr;
1522
1523 pktap_header = (struct pktap_header *)bpf_pkt->bpfp_header;
1524
1525 if (pktap_header->pth_type_next != PTH_TYPE_PACKET) {
1526 return;
1527 }
1528
1529 VERIFY(bpf_pkt->bpfp_header_length >= sizeof(struct pktap_header));
1530
1531 /*
1532 * extra_src_size is the length of the optional link layer header
1533 */
1534 extra_src_size = bpf_pkt->bpfp_header_length -
1535 sizeof(struct pktap_header);
1536
1537 VERIFY(extra_src_size <= sizeof(union pktap_header_extra));
1538
1539 pktap_v2_hdr_space = &pktap_buffer_v2_hdr_extra.hdr_space;
1540 pktap_v2_hdr = &pktap_v2_hdr_space->pth_hdr;
1541 ptr = (uint8_t *) (pktap_v2_hdr + 1);
1542
1543 COPY_PKTAP_COMMON_FIELDS_TO_V2(pktap_v2_hdr, pktap_header);
1544
1545 /*
1546 * When truncating don't bother with the process UUIDs
1547 */
1548 if (!truncate) {
1549 if ((pktap_header->pth_flags & PTH_FLAG_DELAY_PKTAP)) {
1550 pktap_v2_hdr->pth_uuid_offset = pktap_v2_hdr->pth_length;
1551 pktap_v2_hdr->pth_length += sizeof(uuid_t);
1552 uuid_clear(*(uuid_t *)ptr);
1553 ptr += sizeof(uuid_t);
1554 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1555 } else if (!uuid_is_null(pktap_header->pth_uuid)) {
1556 pktap_v2_hdr->pth_uuid_offset = pktap_v2_hdr->pth_length;
1557 uuid_copy(*(uuid_t *)ptr, pktap_header->pth_uuid);
1558 pktap_v2_hdr->pth_length += sizeof(uuid_t);
1559 ptr += sizeof(uuid_t);
1560 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1561 }
1562
1563 if ((pktap_header->pth_flags & PTH_FLAG_DELAY_PKTAP)) {
1564 if (pktap_header->pth_flags & PTH_FLAG_PROC_DELEGATED) {
1565 pktap_v2_hdr->pth_e_uuid_offset = pktap_v2_hdr->pth_length;
1566 uuid_clear(*(uuid_t *)ptr);
1567 pktap_v2_hdr->pth_length += sizeof(uuid_t);
1568 ptr += sizeof(uuid_t);
1569 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1570 }
1571 } else if (!uuid_is_null(pktap_header->pth_euuid)) {
1572 pktap_v2_hdr->pth_e_uuid_offset = pktap_v2_hdr->pth_length;
1573 uuid_copy(*(uuid_t *)ptr, pktap_header->pth_euuid);
1574 pktap_v2_hdr->pth_length += sizeof(uuid_t);
1575 ptr += sizeof(uuid_t);
1576 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1577 }
1578 }
1579
1580 if (pktap_header->pth_ifname[0] != 0) {
1581 size_t strsize;
1582
1583 pktap_v2_hdr->pth_ifname_offset = pktap_v2_hdr->pth_length;
1584
1585 /*
1586 * Note: strlcpy() returns the length of the string so we need
1587 * to add one for the end-of-string
1588 */
1589 strsize = 1 + strlcpy((char *)ptr, pktap_header->pth_ifname,
1590 sizeof(pktap_v2_hdr_space->pth_ifname));
1591 pktap_v2_hdr->pth_length += strsize;
1592 ptr += strsize;
1593 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1594 }
1595
1596 /*
1597 * Do not waste space with the process name if we do not have a pid
1598 */
1599 if (pktap_header->pth_pid != 0 && pktap_header->pth_pid != -1) {
1600 if (pktap_header->pth_comm[0] != 0) {
1601 size_t strsize;
1602
1603 pktap_v2_hdr->pth_comm_offset = pktap_v2_hdr->pth_length;
1604
1605 strsize = 1 + strlcpy((char *)ptr, pktap_header->pth_comm,
1606 sizeof(pktap_v2_hdr_space->pth_comm));
1607 pktap_v2_hdr->pth_length += strsize;
1608 ptr += strsize;
1609 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1610 } else if ((pktap_header->pth_flags & PTH_FLAG_DELAY_PKTAP)) {
1611 size_t strsize = sizeof(pktap_v2_hdr_space->pth_comm);
1612
1613 pktap_v2_hdr->pth_comm_offset = pktap_v2_hdr->pth_length;
1614
1615 *ptr = 0; /* empty string by default */
1616 pktap_v2_hdr->pth_length += strsize;
1617 ptr += strsize;
1618 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1619 }
1620 }
1621
1622 /*
1623 * Do not waste space with the effective process name if we do not have
1624 * an effective pid or it's the same as the pid
1625 */
1626 if (pktap_header->pth_epid != 0 && pktap_header->pth_epid != -1 &&
1627 pktap_header->pth_epid != pktap_header->pth_pid) {
1628 if (pktap_header->pth_ecomm[0] != 0) {
1629 size_t strsize;
1630
1631 pktap_v2_hdr->pth_e_comm_offset = pktap_v2_hdr->pth_length;
1632
1633 strsize = 1 + strlcpy((char *)ptr, pktap_header->pth_ecomm,
1634 sizeof(pktap_v2_hdr_space->pth_e_comm));
1635 pktap_v2_hdr->pth_length += strsize;
1636 ptr += strsize;
1637 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1638 } else if ((pktap_header->pth_flags & PTH_FLAG_DELAY_PKTAP)) {
1639 size_t strsize = sizeof(pktap_v2_hdr_space->pth_e_comm);
1640
1641 pktap_v2_hdr->pth_e_comm_offset = pktap_v2_hdr->pth_length;
1642 *ptr = 0; /* empty string by default */
1643 pktap_v2_hdr->pth_length += strsize;
1644 ptr += strsize;
1645 VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1));
1646 }
1647 }
1648
1649 if (extra_src_size > 0) {
1650 char *extra_src_ptr = (char *)(pktap_header + 1);
1651 char *extra_dst_ptr = ((char *)pktap_v2_hdr) +
1652 pktap_v2_hdr->pth_length;
1653
1654 VERIFY(pktap_v2_hdr->pth_length + extra_src_size <=
1655 sizeof(struct pktap_buffer_v2_hdr_extra));
1656
1657 memcpy(extra_dst_ptr, extra_src_ptr, extra_src_size);
1658 }
1659
1660 VERIFY(pktap_v2_hdr->pth_length + extra_src_size <=
1661 bpf_pkt->bpfp_header_length);
1662
1663 memcpy(bpf_pkt->bpfp_header, pktap_v2_hdr,
1664 pktap_v2_hdr->pth_length + extra_src_size);
1665
1666 bpf_pkt->bpfp_total_length += pktap_v2_hdr->pth_length -
1667 sizeof(struct pktap_header);
1668 bpf_pkt->bpfp_header_length += pktap_v2_hdr->pth_length -
1669 sizeof(struct pktap_header);
1670 }
1671