1/* 2 * Copyright (c) 2012-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 47#include <netinet/in_pcb.h> 48#include <netinet/tcp.h> 49#include <netinet/tcp_var.h> 50#define _IP_VHL 51#include <netinet/ip.h> 52#include <netinet/ip_var.h> 53#include <netinet/udp.h> 54#include <netinet/udp_var.h> 55 56#include <netinet/ip6.h> 57#include <netinet6/in6_pcb.h> 58 59#include <libkern/OSAtomic.h> 60 61#include <kern/debug.h> 62 63#include <sys/mcache.h> 64 65#include <string.h> 66 67extern struct inpcbinfo ripcbinfo; 68 69struct pktap_softc { 70 LIST_ENTRY(pktap_softc) pktp_link; 71 uint32_t pktp_unit; 72 uint32_t pktp_dlt_raw_count; 73 uint32_t pktp_dlt_pkttap_count; 74 struct ifnet *pktp_ifp; 75 struct pktap_filter pktp_filters[PKTAP_MAX_FILTERS]; 76}; 77 78#ifndef PKTAP_DEBUG 79#define PKTAP_DEBUG 1 80#endif /* PKTAP_DEBUG */ 81 82#define PKTAP_FILTER_OK 0 /* Packet passes filter checks */ 83#define PKTAP_FILTER_SKIP 1 /* Do not tap this packet */ 84 85static int pktap_inited = 0; 86 87SYSCTL_DECL(_net_link); 88SYSCTL_NODE(_net_link, IFT_PKTAP, pktap, CTLFLAG_RW|CTLFLAG_LOCKED, 0, 89 "pktap virtual interface"); 90 91static int pktap_total_tap_count = 0; 92SYSCTL_INT(_net_link_pktap, OID_AUTO, total_tap_count, CTLFLAG_RD | CTLFLAG_LOCKED, 93 &pktap_total_tap_count, 0, ""); 94 95static u_int64_t pktap_count_unknown_if_type = 0; 96SYSCTL_QUAD(_net_link_pktap, OID_AUTO, count_unknown_if_type, CTLFLAG_RD | CTLFLAG_LOCKED, 97 &pktap_count_unknown_if_type, ""); 98 99static int pktap_log = 0; 100SYSCTL_INT(_net_link_pktap, OID_AUTO, log, CTLFLAG_RW | CTLFLAG_LOCKED, 101 &pktap_log, 0, ""); 102 103#define PKTAP_LOG(mask, fmt, ...) \ 104do { \ 105 if ((pktap_log & mask)) \ 106 printf("%s:%d " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ 107} while(false) 108 109#define PKTP_LOG_FUNC 0x01 110#define PKTP_LOG_FILTER 0x02 111#define PKTP_LOG_INPUT 0x04 112#define PKTP_LOG_OUTPUT 0x08 113#define PKTP_LOG_ERROR 0x10 114#define PKTP_LOG_NOPCB 0x20 115 116/* 117 * pktap_lck_rw protects the global list of pktap interfaces 118 */ 119decl_lck_rw_data(static, pktap_lck_rw_data); 120static lck_rw_t *pktap_lck_rw = &pktap_lck_rw_data; 121static lck_grp_t *pktap_lck_grp = NULL; 122static lck_attr_t *pktap_lck_attr = NULL; 123 124static LIST_HEAD(pktap_list, pktap_softc) pktap_list = LIST_HEAD_INITIALIZER(pktap_list); 125 126int pktap_clone_create(struct if_clone *, u_int32_t, void *); 127int pktap_clone_destroy(struct ifnet *); 128 129static struct if_clone pktap_cloner = 130 IF_CLONE_INITIALIZER(PKTAP_IFNAME, 131 pktap_clone_create, 132 pktap_clone_destroy, 133 0, 134 IF_MAXUNIT); 135 136errno_t pktap_if_output(ifnet_t, mbuf_t); 137errno_t pktap_demux(ifnet_t , mbuf_t, char *, protocol_family_t *); 138errno_t pktap_add_proto(ifnet_t, protocol_family_t, const struct ifnet_demux_desc *, 139 u_int32_t); 140errno_t pktap_del_proto(ifnet_t, protocol_family_t); 141errno_t pktap_getdrvspec(ifnet_t, struct ifdrv64 *); 142errno_t pktap_setdrvspec(ifnet_t, struct ifdrv64 *); 143errno_t pktap_ioctl(ifnet_t, unsigned long, void *); 144void pktap_detach(ifnet_t); 145int pktap_filter_evaluate(struct pktap_softc *, struct ifnet *); 146void pktap_bpf_tap(struct ifnet *, protocol_family_t , struct mbuf *, 147 u_int32_t , u_int32_t , int ); 148errno_t pktap_tap_callback(ifnet_t , u_int32_t , bpf_tap_mode ); 149 150static void 151pktap_hexdump(int mask, void *addr, size_t len) 152{ 153 unsigned char *buf = addr; 154 size_t i; 155 156 if (!(pktap_log & mask)) 157 return; 158 159 for (i = 0; i < len; i++) { 160 unsigned char h = (buf[i] & 0xf0) >> 4; 161 unsigned char l = buf[i] & 0x0f; 162 163 if (i != 0) { 164 if (i % 32 == 0) 165 printf("\n"); 166 else if (i % 4 == 0) 167 printf(" "); 168 } 169 printf("%c%c", 170 h < 10 ? h + '0' : h - 10 + 'a', 171 l < 10 ? l + '0' : l - 10 + 'a'); 172 } 173 if (i % 32 != 0) 174 printf("\n"); 175 176 return; 177} 178 179__private_extern__ void 180pktap_init(void) 181{ 182 int error = 0; 183 lck_grp_attr_t *lck_grp_attr = NULL; 184 185 /* Make sure we're called only once */ 186 VERIFY(pktap_inited == 0); 187 188 pktap_inited = 1; 189 190 lck_grp_attr = lck_grp_attr_alloc_init(); 191 pktap_lck_grp = lck_grp_alloc_init("pktap", lck_grp_attr); 192 pktap_lck_attr = lck_attr_alloc_init(); 193#if PKTAP_DEBUG 194 lck_attr_setdebug(pktap_lck_attr); 195#endif /* PKTAP_DEBUG */ 196 lck_rw_init(pktap_lck_rw, pktap_lck_grp, pktap_lck_attr); 197 lck_grp_attr_free(lck_grp_attr); 198 199 LIST_INIT(&pktap_list); 200 201 error = if_clone_attach(&pktap_cloner); 202 if (error != 0) 203 panic("%s: if_clone_attach() failed, error %d\n", __func__, error); 204} 205 206__private_extern__ int 207pktap_clone_create(struct if_clone *ifc, u_int32_t unit, __unused void *params) 208{ 209 int error = 0; 210 struct pktap_softc *pktap = NULL; 211 struct ifnet_init_params if_init; 212 213 PKTAP_LOG(PKTP_LOG_FUNC, "unit %u\n", unit); 214 215 pktap = _MALLOC(sizeof(struct pktap_softc), M_DEVBUF, M_WAITOK | M_ZERO); 216 if (pktap == NULL) { 217 printf("%s: _MALLOC failed\n", __func__); 218 error = ENOMEM; 219 goto done; 220 } 221 pktap->pktp_unit = unit; 222 223 /* 224 * By default accept packet from physical interfaces 225 */ 226 pktap->pktp_filters[0].filter_op = PKTAP_FILTER_OP_PASS; 227 pktap->pktp_filters[0].filter_param = PKTAP_FILTER_PARAM_IF_TYPE; 228 pktap->pktp_filters[0].filter_param_if_type = IFT_ETHER; 229 230 pktap->pktp_filters[1].filter_op = PKTAP_FILTER_OP_PASS; 231 pktap->pktp_filters[1].filter_param = PKTAP_FILTER_PARAM_IF_TYPE; 232 pktap->pktp_filters[1].filter_param_if_type = IFT_IEEE1394; 233 /* 234 * We do not use a set_bpf_tap() function as we rather rely on the more 235 * accurate callback passed to bpf_attach() 236 */ 237 bzero(&if_init, sizeof(struct ifnet_init_params)); 238 if_init.name = ifc->ifc_name; 239 if_init.unit = unit; 240 if_init.type = IFT_PKTAP; 241 if_init.family = IFNET_FAMILY_LOOPBACK; 242 if_init.output = pktap_if_output; 243 if_init.demux = pktap_demux; 244 if_init.add_proto = pktap_add_proto; 245 if_init.del_proto = pktap_del_proto; 246 if_init.softc = pktap; 247 if_init.ioctl = pktap_ioctl; 248 if_init.detach = pktap_detach; 249 250 error = ifnet_allocate(&if_init, &pktap->pktp_ifp); 251 if (error != 0) { 252 printf("%s: ifnet_allocate failed, error %d\n", __func__, error); 253 goto done; 254 } 255 256 ifnet_set_flags(pktap->pktp_ifp, IFF_UP, IFF_UP); 257 258 error = ifnet_attach(pktap->pktp_ifp, NULL); 259 if (error != 0) { 260 printf("%s: ifnet_attach failed - error %d\n", __func__, error); 261 ifnet_release(pktap->pktp_ifp); 262 goto done; 263 } 264 265 /* Attach DLT_PKTAP as the default DLT */ 266 bpf_attach(pktap->pktp_ifp, DLT_PKTAP, sizeof(struct pktap_header), NULL, 267 pktap_tap_callback); 268 bpf_attach(pktap->pktp_ifp, DLT_RAW, 0, NULL, pktap_tap_callback); 269 270 /* Take a reference and add to the global list */ 271 ifnet_reference(pktap->pktp_ifp); 272 lck_rw_lock_exclusive(pktap_lck_rw); 273 LIST_INSERT_HEAD(&pktap_list, pktap, pktp_link); 274 lck_rw_done(pktap_lck_rw); 275done: 276 if (error != 0) { 277 if (pktap != NULL) 278 _FREE(pktap, M_DEVBUF); 279 } 280 return (error); 281} 282 283__private_extern__ int 284pktap_clone_destroy(struct ifnet *ifp) 285{ 286 int error = 0; 287 288 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname); 289 290 (void) ifnet_detach(ifp); 291 292 return (error); 293} 294 295/* 296 * This function is called whenever a DLT is set on the interface: 297 * - When interface is attached to a BPF device via BIOCSETIF for the default DLT 298 * - Whenever a new DLT is selected via BIOCSDLT 299 * - When the interface is detached from a BPF device (direction is zero) 300 */ 301__private_extern__ errno_t 302pktap_tap_callback(ifnet_t ifp, u_int32_t dlt, bpf_tap_mode direction) 303{ 304 struct pktap_softc *pktap; 305 306 pktap = ifp->if_softc; 307 if (pktap == NULL) { 308 printf("%s: if_softc is NULL for ifp %s\n", __func__, 309 ifp->if_xname); 310 goto done; 311 } 312 switch (dlt) { 313 case DLT_RAW: 314 if (direction == 0) { 315 if (pktap->pktp_dlt_raw_count > 0) { 316 pktap->pktp_dlt_raw_count--; 317 OSAddAtomic(-1, &pktap_total_tap_count); 318 319 } 320 } else { 321 pktap->pktp_dlt_raw_count++; 322 OSAddAtomic(1, &pktap_total_tap_count); 323 } 324 break; 325 case DLT_PKTAP: 326 if (direction == 0) { 327 if (pktap->pktp_dlt_pkttap_count > 0) { 328 pktap->pktp_dlt_pkttap_count--; 329 OSAddAtomic(-1, &pktap_total_tap_count); 330 } 331 } else { 332 pktap->pktp_dlt_pkttap_count++; 333 OSAddAtomic(1, &pktap_total_tap_count); 334 } 335 break; 336 } 337done: 338 /* 339 * Attachements count must be positive and we're in trouble 340 * if we have more that 2**31 attachements 341 */ 342 VERIFY(pktap_total_tap_count >= 0); 343 344 return (0); 345} 346 347__private_extern__ errno_t 348pktap_if_output(ifnet_t ifp, mbuf_t m) 349{ 350 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname); 351 mbuf_freem(m); 352 return (ENOTSUP); 353} 354 355__private_extern__ errno_t 356pktap_demux(ifnet_t ifp, __unused mbuf_t m, __unused char *header, 357 __unused protocol_family_t *ppf) 358{ 359 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname); 360 return (ENOTSUP); 361} 362 363__private_extern__ errno_t 364pktap_add_proto(__unused ifnet_t ifp, protocol_family_t pf, 365 __unused const struct ifnet_demux_desc *dmx, __unused u_int32_t cnt) 366{ 367 PKTAP_LOG(PKTP_LOG_FUNC, "%s pf %u\n", ifp->if_xname, pf); 368 return (0); 369} 370 371__private_extern__ errno_t 372pktap_del_proto(__unused ifnet_t ifp, __unused protocol_family_t pf) 373{ 374 PKTAP_LOG(PKTP_LOG_FUNC, "%s pf %u\n", ifp->if_xname, pf); 375 return (0); 376} 377 378__private_extern__ errno_t 379pktap_getdrvspec(ifnet_t ifp, struct ifdrv64 *ifd) 380{ 381 errno_t error = 0; 382 struct pktap_softc *pktap; 383 int i; 384 385 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname); 386 387 pktap = ifp->if_softc; 388 if (pktap == NULL) { 389 error = ENOENT; 390 printf("%s: pktap NULL - error %d\n", __func__, error); 391 goto done; 392 } 393 394 switch (ifd->ifd_cmd) { 395 case PKTP_CMD_FILTER_GET: { 396 struct x_pktap_filter x_filters[PKTAP_MAX_FILTERS]; 397 398 bzero(&x_filters, sizeof(x_filters)); 399 400 if (ifd->ifd_len < PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)) { 401 printf("%s: PKTP_CMD_FILTER_GET ifd_len %llu too small - error %d\n", 402 __func__, ifd->ifd_len, error); 403 error = EINVAL; 404 break; 405 } 406 for (i = 0; i < PKTAP_MAX_FILTERS; i++) { 407 struct pktap_filter *pktap_filter = pktap->pktp_filters + i; 408 struct x_pktap_filter *x_filter = x_filters + i; 409 410 x_filter->filter_op = pktap_filter->filter_op; 411 x_filter->filter_param = pktap_filter->filter_param; 412 413 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) 414 x_filter->filter_param_if_type = pktap_filter->filter_param_if_type; 415 else if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) 416 strlcpy(x_filter->filter_param_if_name, 417 pktap_filter->filter_param_if_name, 418 sizeof(x_filter->filter_param_if_name)); 419 } 420 error = copyout(x_filters, ifd->ifd_data, 421 PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)); 422 if (error) { 423 printf("%s: PKTP_CMD_FILTER_GET copyout - error %d\n", __func__, error); 424 goto done; 425 } 426 break; 427 } 428 case PKTP_CMD_TAP_COUNT: { 429 uint32_t tap_count = pktap->pktp_dlt_raw_count + pktap->pktp_dlt_pkttap_count; 430 431 if (ifd->ifd_len < sizeof(tap_count)) { 432 printf("%s: PKTP_CMD_TAP_COUNT ifd_len %llu too small - error %d\n", 433 __func__, ifd->ifd_len, error); 434 error = EINVAL; 435 break; 436 } 437 error = copyout(&tap_count, ifd->ifd_data, sizeof(tap_count)); 438 if (error) { 439 printf("%s: PKTP_CMD_TAP_COUNT copyout - error %d\n", __func__, error); 440 goto done; 441 } 442 break; 443 } 444 default: 445 error = EINVAL; 446 break; 447 } 448 449done: 450 return (error); 451} 452 453__private_extern__ errno_t 454pktap_setdrvspec(ifnet_t ifp, struct ifdrv64 *ifd) 455{ 456 errno_t error = 0; 457 struct pktap_softc *pktap; 458 459 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname); 460 461 pktap = ifp->if_softc; 462 if (pktap == NULL) { 463 error = ENOENT; 464 printf("%s: pktap NULL - error %d\n", __func__, error); 465 goto done; 466 } 467 468 switch (ifd->ifd_cmd) { 469 case PKTP_CMD_FILTER_SET: { 470 struct x_pktap_filter user_filters[PKTAP_MAX_FILTERS]; 471 int i; 472 int got_op_none = 0; 473 474 if (ifd->ifd_len != PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)) { 475 printf("%s: PKTP_CMD_FILTER_SET bad ifd_len %llu - error %d\n", 476 __func__, ifd->ifd_len, error); 477 error = EINVAL; 478 break; 479 } 480 error = copyin(ifd->ifd_data, &user_filters, ifd->ifd_len); 481 if (error) { 482 printf("%s: copyin - error %d\n", __func__, error); 483 goto done; 484 } 485 /* 486 * Validate user provided parameters 487 */ 488 for (i = 0; i < PKTAP_MAX_FILTERS; i++) { 489 struct x_pktap_filter *x_filter = user_filters + i; 490 491 switch (x_filter->filter_op) { 492 case PKTAP_FILTER_OP_NONE: 493 /* Following entries must be PKTAP_FILTER_OP_NONE */ 494 got_op_none = 1; 495 break; 496 case PKTAP_FILTER_OP_PASS: 497 case PKTAP_FILTER_OP_SKIP: 498 /* Invalid after PKTAP_FILTER_OP_NONE */ 499 if (got_op_none) { 500 error = EINVAL; 501 break; 502 } 503 break; 504 default: 505 error = EINVAL; 506 break; 507 } 508 if (error != 0) 509 break; 510 511 switch (x_filter->filter_param) { 512 case PKTAP_FILTER_OP_NONE: 513 if (x_filter->filter_op != PKTAP_FILTER_OP_NONE) { 514 error = EINVAL; 515 break; 516 } 517 break; 518 519 /* 520 * Do not allow to tap a pktap from a pktap 521 */ 522 case PKTAP_FILTER_PARAM_IF_TYPE: 523 if (x_filter->filter_param_if_type == IFT_PKTAP || 524 x_filter->filter_param_if_type > 0xff) { 525 error = EINVAL; 526 break; 527 } 528 break; 529 530 case PKTAP_FILTER_PARAM_IF_NAME: 531 if (x_filter->filter_param_if_name == 0 || 532 strncmp(x_filter->filter_param_if_name, PKTAP_IFNAME, 533 strlen(PKTAP_IFNAME)) == 0) { 534 error = EINVAL; 535 break; 536 } 537 break; 538 539 default: 540 error = EINVAL; 541 break; 542 } 543 if (error != 0) 544 break; 545 } 546 if (error != 0) 547 break; 548 for (i = 0; i < PKTAP_MAX_FILTERS; i++) { 549 struct pktap_filter *pktap_filter = pktap->pktp_filters + i; 550 struct x_pktap_filter *x_filter = user_filters + i; 551 552 pktap_filter->filter_op = x_filter->filter_op; 553 pktap_filter->filter_param = x_filter->filter_param; 554 555 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) 556 pktap_filter->filter_param_if_type = x_filter->filter_param_if_type; 557 else if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) { 558 size_t len; 559 560 strlcpy(pktap_filter->filter_param_if_name, 561 x_filter->filter_param_if_name, 562 sizeof(pktap_filter->filter_param_if_name)); 563 /* 564 * If name does not end with a number then it's a "wildcard" match 565 * where we compare the prefix of the interface name 566 */ 567 len = strlen(pktap_filter->filter_param_if_name); 568 if (pktap_filter->filter_param_if_name[len] < '0' || 569 pktap_filter->filter_param_if_name[len] > '9') 570 pktap_filter->filter_ifname_prefix_len = len; 571 } 572 } 573 break; 574 } 575 default: 576 error = EINVAL; 577 break; 578 } 579 580done: 581 return (error); 582} 583 584__private_extern__ errno_t 585pktap_ioctl(ifnet_t ifp, unsigned long cmd, void *data) 586{ 587 errno_t error = 0; 588 589 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname); 590 591 if ((cmd & IOC_IN)) { 592 error = kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER); 593 if (error) { 594 PKTAP_LOG(PKTP_LOG_ERROR, 595 "%s: kauth_authorize_generic(KAUTH_GENERIC_ISSUSER) - error %d\n", 596 __func__, error); 597 goto done; 598 } 599 } 600 601 switch (cmd) { 602 case SIOCGDRVSPEC32: { 603 struct ifdrv64 ifd; 604 struct ifdrv32 *ifd32 = (struct ifdrv32 *)data; 605 606 memcpy(ifd.ifd_name, ifd32->ifd_name, sizeof(ifd.ifd_name)); 607 ifd.ifd_cmd = ifd32->ifd_cmd; 608 ifd.ifd_len = ifd32->ifd_len; 609 ifd.ifd_data = ifd32->ifd_data; 610 611 error = pktap_getdrvspec(ifp, &ifd); 612 613 break; 614 } 615 case SIOCGDRVSPEC64: { 616 struct ifdrv64 *ifd64 = (struct ifdrv64 *)data; 617 618 error = pktap_getdrvspec(ifp, ifd64); 619 620 break; 621 } 622 case SIOCSDRVSPEC32: { 623 struct ifdrv64 ifd; 624 struct ifdrv32 *ifd32 = (struct ifdrv32 *)data; 625 626 memcpy(ifd.ifd_name, ifd32->ifd_name, sizeof(ifd.ifd_name)); 627 ifd.ifd_cmd = ifd32->ifd_cmd; 628 ifd.ifd_len = ifd32->ifd_len; 629 ifd.ifd_data = ifd32->ifd_data; 630 631 error = pktap_setdrvspec(ifp, &ifd); 632 break; 633 } 634 case SIOCSDRVSPEC64: { 635 struct ifdrv64 *ifd64 = (struct ifdrv64 *)data; 636 637 error = pktap_setdrvspec(ifp, ifd64); 638 639 break; 640 } 641 default: 642 error = ENOTSUP; 643 break; 644 } 645done: 646 return (error); 647} 648 649__private_extern__ void 650pktap_detach(ifnet_t ifp) 651{ 652 struct pktap_softc *pktap; 653 654 PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname); 655 656 lck_rw_lock_exclusive(pktap_lck_rw); 657 658 pktap = ifp->if_softc; 659 ifp->if_softc = NULL; 660 LIST_REMOVE(pktap, pktp_link); 661 662 lck_rw_done(pktap_lck_rw); 663 664 /* Drop reference as it's no more on the global list */ 665 ifnet_release(ifp); 666 667 _FREE(pktap, M_DEVBUF); 668 669 /* This is for the reference taken by ifnet_attach() */ 670 (void) ifnet_release(ifp); 671} 672 673__private_extern__ int 674pktap_filter_evaluate(struct pktap_softc *pktap, struct ifnet *ifp) 675{ 676 int i; 677 int result = PKTAP_FILTER_SKIP; /* Need positive matching rule to pass */ 678 int match = 0; 679 680 for (i = 0; i < PKTAP_MAX_FILTERS; i++) { 681 struct pktap_filter *pktap_filter = pktap->pktp_filters + i; 682 size_t len = pktap_filter->filter_ifname_prefix_len != 0 ? 683 pktap_filter->filter_ifname_prefix_len : PKTAP_IFXNAMESIZE; 684 685 switch (pktap_filter->filter_op) { 686 case PKTAP_FILTER_OP_NONE: 687 match = 1; 688 break; 689 690 case PKTAP_FILTER_OP_PASS: 691 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) { 692 if (pktap_filter->filter_param_if_type == 0 || 693 ifp->if_type == pktap_filter->filter_param_if_type) { 694 result = PKTAP_FILTER_OK; 695 match = 1; 696 PKTAP_LOG(PKTP_LOG_FILTER, "pass %s match type %u\n", 697 ifp->if_xname, pktap_filter->filter_param_if_type); 698 break; 699 } 700 } 701 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) { 702 if (strncmp(ifp->if_xname, pktap_filter->filter_param_if_name, 703 len) == 0) { 704 result = PKTAP_FILTER_OK; 705 match = 1; 706 PKTAP_LOG(PKTP_LOG_FILTER, "pass %s match name %s\n", 707 ifp->if_xname, pktap_filter->filter_param_if_name); 708 break; 709 } 710 } 711 break; 712 713 case PKTAP_FILTER_OP_SKIP: 714 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) { 715 if (pktap_filter->filter_param_if_type == 0 || 716 ifp->if_type == pktap_filter->filter_param_if_type) { 717 result = PKTAP_FILTER_SKIP; 718 match = 1; 719 PKTAP_LOG(PKTP_LOG_FILTER, "skip %s match type %u\n", 720 ifp->if_xname, pktap_filter->filter_param_if_type); 721 break; 722 } 723 } 724 if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) { 725 if (strncmp(ifp->if_xname, pktap_filter->filter_param_if_name, 726 len) == 0) { 727 result = PKTAP_FILTER_SKIP; 728 match = 1; 729 PKTAP_LOG(PKTP_LOG_FILTER, "skip %s match name %s\n", 730 ifp->if_xname, pktap_filter->filter_param_if_name); 731 break; 732 } 733 } 734 break; 735 } 736 if (match) 737 break; 738 } 739 740 if (match == 0) { 741 PKTAP_LOG(PKTP_LOG_FILTER, "%s no match\n", 742 ifp->if_xname); 743 } 744 return (result); 745} 746 747__private_extern__ void 748pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto, 749 struct mbuf *m, u_int32_t pre, int outgoing, struct ifnet *ifp) 750{ 751 int found = 0; 752 struct so_procinfo soprocinfo; 753 754 /* 755 * Getting the pid and procname is expensive 756 * For outgoing, do the lookup only if there's an 757 * associated socket as indicated by the flowhash 758 */ 759 if (outgoing != 0 && (m->m_pkthdr.pkt_flags & 760 (PKTF_FLOW_ID|PKTF_FLOW_LOCALSRC)) == (PKTF_FLOW_ID|PKTF_FLOW_LOCALSRC) && 761 m->m_pkthdr.pkt_flowsrc == FLOWSRC_INPCB) { 762 if (m->m_pkthdr.pkt_flags & PKTF_FLOW_RAWSOCK) 763 found = inp_findinpcb_procinfo(&ripcbinfo, m->m_pkthdr.pkt_flowid, &soprocinfo); 764 else if (m->m_pkthdr.pkt_proto == IPPROTO_TCP) 765 found = inp_findinpcb_procinfo(&tcbinfo, m->m_pkthdr.pkt_flowid, &soprocinfo); 766 else if (m->m_pkthdr.pkt_proto == IPPROTO_UDP) 767 found = inp_findinpcb_procinfo(&udbinfo, m->m_pkthdr.pkt_flowid, &soprocinfo); 768 } else if (outgoing == 0) { 769 struct inpcb *inp = NULL; 770 771 if (proto == PF_INET) { 772 struct ip ip; 773 errno_t error; 774 size_t hlen; 775 struct in_addr faddr, laddr; 776 u_short fport, lport; 777 struct inpcbinfo *pcbinfo = NULL; 778 int wildcard = 0; 779 780 error = mbuf_copydata(m, pre, sizeof(struct ip), &ip); 781 if (error != 0) { 782 PKTAP_LOG(PKTP_LOG_ERROR, "mbuf_copydata tcp v4 failed for %s\n", 783 hdr->pth_ifname); 784 goto done; 785 } 786 hlen = IP_VHL_HL(ip.ip_vhl) << 2; 787 788 faddr = ip.ip_src; 789 laddr = ip.ip_dst; 790 791 if (ip.ip_p == IPPROTO_TCP) { 792 struct tcphdr th; 793 794 error = mbuf_copydata(m, pre + hlen, 795 sizeof(struct tcphdr), &th); 796 if (error != 0) 797 goto done; 798 799 fport = th.th_sport; 800 lport = th.th_dport; 801 802 pcbinfo = &tcbinfo; 803 } else if (ip.ip_p == IPPROTO_UDP) { 804 struct udphdr uh; 805 806 error = mbuf_copydata(m, pre + hlen, 807 sizeof(struct udphdr), &uh); 808 if (error != 0) { 809 PKTAP_LOG(PKTP_LOG_ERROR, "mbuf_copydata udp v4 failed for %s\n", 810 hdr->pth_ifname); 811 goto done; 812 } 813 fport = uh.uh_sport; 814 lport = uh.uh_dport; 815 816 pcbinfo = &udbinfo; 817 wildcard = 1; 818 } 819 if (pcbinfo != NULL) { 820 inp = in_pcblookup_hash(pcbinfo, faddr, fport, 821 laddr, lport, wildcard, outgoing ? NULL : ifp); 822 823 if (inp == NULL && hdr->pth_iftype != IFT_LOOP) 824 PKTAP_LOG(PKTP_LOG_NOPCB, "in_pcblookup_hash no pcb %s\n", 825 hdr->pth_ifname); 826 } else { 827 PKTAP_LOG(PKTP_LOG_NOPCB, "unknown ip_p %u on %s\n", 828 ip.ip_p, 829 hdr->pth_ifname); 830 pktap_hexdump(PKTP_LOG_NOPCB, &ip, sizeof(struct ip)); 831 } 832 } else if (proto == PF_INET6) { 833 struct ip6_hdr ip6; 834 errno_t error; 835 struct in6_addr *faddr; 836 struct in6_addr *laddr; 837 u_short fport, lport; 838 struct inpcbinfo *pcbinfo = NULL; 839 int wildcard = 0; 840 841 error = mbuf_copydata(m, pre, sizeof(struct ip6_hdr), &ip6); 842 if (error != 0) 843 goto done; 844 845 faddr = &ip6.ip6_src; 846 laddr = &ip6.ip6_dst; 847 848 if (ip6.ip6_nxt == IPPROTO_TCP) { 849 struct tcphdr th; 850 851 error = mbuf_copydata(m, pre + sizeof(struct ip6_hdr), 852 sizeof(struct tcphdr), &th); 853 if (error != 0) { 854 PKTAP_LOG(PKTP_LOG_ERROR, "mbuf_copydata tcp v6 failed for %s\n", 855 hdr->pth_ifname); 856 goto done; 857 } 858 859 fport = th.th_sport; 860 lport = th.th_dport; 861 862 pcbinfo = &tcbinfo; 863 } else if (ip6.ip6_nxt == IPPROTO_UDP) { 864 struct udphdr uh; 865 866 error = mbuf_copydata(m, pre + sizeof(struct ip6_hdr), 867 sizeof(struct udphdr), &uh); 868 if (error != 0) { 869 PKTAP_LOG(PKTP_LOG_ERROR, "mbuf_copydata udp v6 failed for %s\n", 870 hdr->pth_ifname); 871 goto done; 872 } 873 874 fport = uh.uh_sport; 875 lport = uh.uh_dport; 876 877 pcbinfo = &udbinfo; 878 wildcard = 1; 879 } 880 if (pcbinfo != NULL) { 881 inp = in6_pcblookup_hash(pcbinfo, faddr, fport, 882 laddr, lport, wildcard, outgoing ? NULL : ifp); 883 884 if (inp == NULL && hdr->pth_iftype != IFT_LOOP) 885 PKTAP_LOG(PKTP_LOG_NOPCB, "in6_pcblookup_hash no pcb %s\n", 886 hdr->pth_ifname); 887 } else { 888 PKTAP_LOG(PKTP_LOG_NOPCB, "unknown ip6.ip6_nxt %u on %s\n", 889 ip6.ip6_nxt, 890 hdr->pth_ifname); 891 pktap_hexdump(PKTP_LOG_NOPCB, &ip6, sizeof(struct ip6_hdr)); 892 } 893 } 894 if (inp != NULL) { 895 if (inp->inp_state != INPCB_STATE_DEAD && inp->inp_socket != NULL) { 896 found = 1; 897 inp_get_soprocinfo(inp, &soprocinfo); 898 } 899 in_pcb_checkstate(inp, WNT_RELEASE, 0); 900 } 901 } 902 /* 903 * -1 means PID not found 904 */ 905 hdr->pth_pid = -1; 906 hdr->pth_epid = -1; 907 if (found != 0) { 908 hdr->pth_pid = soprocinfo.spi_pid; 909 if (soprocinfo.spi_pid == 0) 910 strlcpy(hdr->pth_comm, "mach_kernel", sizeof(hdr->pth_comm)); 911 else 912 proc_name(soprocinfo.spi_pid, hdr->pth_comm, MAXCOMLEN); 913 914 /* 915 * When not delegated, the effective pid is the same as the real pid 916 */ 917 if (soprocinfo.spi_epid != soprocinfo.spi_pid) { 918 hdr->pth_flags |= PTH_FLAG_PROC_DELEGATED; 919 hdr->pth_epid = soprocinfo.spi_epid; 920 if (soprocinfo.spi_epid == 0) 921 strlcpy(hdr->pth_ecomm, "mach_kernel", sizeof(hdr->pth_ecomm)); 922 else 923 proc_name(soprocinfo.spi_epid, hdr->pth_ecomm, MAXCOMLEN); 924 } 925 } 926done: 927 return; 928} 929 930__private_extern__ void 931pktap_bpf_tap(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m, 932 u_int32_t pre, u_int32_t post, int outgoing) 933{ 934 struct pktap_softc *pktap; 935 void (*bpf_tap_func)(ifnet_t , u_int32_t , mbuf_t , void * , size_t ) = 936 outgoing ? bpf_tap_out : bpf_tap_in; 937 938 lck_rw_lock_shared(pktap_lck_rw); 939 940 /* 941 * No need to take the ifnet_lock as the struct ifnet field if_bpf is 942 * protected by the BPF subsystem 943 */ 944 LIST_FOREACH(pktap, &pktap_list, pktp_link) { 945 int filter_result; 946 947 filter_result = pktap_filter_evaluate(pktap, ifp); 948 if (filter_result == PKTAP_FILTER_SKIP) 949 continue; 950 951 if (pktap->pktp_dlt_raw_count > 0) { 952 /* We accept only IPv4 and IPv6 packets for the raw DLT */ 953 if ((proto == AF_INET ||proto == AF_INET6) && 954 !(m->m_pkthdr.pkt_flags & PKTF_INET_RESOLVE)) { 955 /* 956 * We can play just with the length of the first mbuf in the 957 * chain because bpf_tap_imp() disregard the packet length 958 * of the mbuf packet header. 959 */ 960 if (mbuf_setdata(m, m->m_data + pre, m->m_len - pre) == 0) { 961 bpf_tap_func(pktap->pktp_ifp, DLT_RAW, m, NULL, 0); 962 mbuf_setdata(m, m->m_data - pre, m->m_len + pre); 963 } 964 } 965 } 966 967 if (pktap->pktp_dlt_pkttap_count > 0) { 968 struct { 969 struct pktap_header hdr; 970 u_int32_t proto; 971 } hdr_buffer; 972 struct pktap_header *hdr = &hdr_buffer.hdr; 973 size_t hdr_size = sizeof(struct pktap_header); 974 int unknown_if_type = 0; 975 size_t data_adjust = 0; 976 u_int32_t pre_adjust = 0; 977 978 /* Verify the structure is packed */ 979 _CASSERT(sizeof(hdr_buffer) == sizeof(struct pktap_header) + sizeof(u_int32_t)); 980 981 bzero(&hdr_buffer, sizeof(hdr_buffer)); 982 hdr->pth_length = sizeof(struct pktap_header); 983 hdr->pth_type_next = PTH_TYPE_PACKET; 984 985 /* 986 * Set DLT of packet based on interface type 987 */ 988 switch (ifp->if_type) { 989 case IFT_LOOP: 990 case IFT_GIF: 991 case IFT_STF: 992 case IFT_CELLULAR: 993 /* 994 * Packets from pdp interfaces have no loopback 995 * header that contain the protocol number. 996 * As BPF just concatenate the header and the 997 * packet content in a single buffer, 998 * stash the protocol after the pktap header 999 * and adjust the size of the header accordingly 1000 */ 1001 hdr->pth_dlt = DLT_NULL; 1002 if (pre == 0) { 1003 hdr_buffer.proto = proto; 1004 hdr_size = sizeof(hdr_buffer); 1005 pre_adjust = sizeof(hdr_buffer.proto); 1006 } 1007 break; 1008 case IFT_ETHER: 1009 case IFT_BRIDGE: 1010 case IFT_L2VLAN: 1011 case IFT_IEEE8023ADLAG: 1012 hdr->pth_dlt = DLT_EN10MB; 1013 break; 1014 case IFT_PPP: 1015 hdr->pth_dlt = DLT_PPP; 1016 break; 1017 case IFT_IEEE1394: 1018 hdr->pth_dlt = DLT_APPLE_IP_OVER_IEEE1394; 1019 break; 1020 case IFT_OTHER: 1021 if (strncmp(ifp->if_name, "utun", strlen("utun")) == 0) { 1022 /* 1023 * For utun: 1024 * - incoming packets do not have the prefix set to four 1025 * - some packets are as small as two bytes! 1026 */ 1027 if (m_pktlen(m) < 4) 1028 goto done; 1029 if (proto != AF_INET && proto != AF_INET6) 1030 goto done; 1031 if (proto == AF_INET && (size_t) m_pktlen(m) - 4 < sizeof(struct ip)) 1032 goto done; 1033 if (proto == AF_INET6 && (size_t) m_pktlen(m) - 4 < sizeof(struct ip6_hdr)) 1034 goto done; 1035 /* 1036 * Skip the protocol in the mbuf as it's in network order 1037 */ 1038 pre = 4; 1039 data_adjust = 4; 1040 hdr->pth_dlt = DLT_NULL; 1041 hdr_buffer.proto = proto; 1042 hdr_size = sizeof(hdr_buffer); 1043 break; 1044 } 1045 default: 1046 if (pre == 0) 1047 hdr->pth_dlt = DLT_RAW; 1048 else 1049 unknown_if_type = 1; 1050 break; 1051 } 1052 if (unknown_if_type) { 1053 PKTAP_LOG(PKTP_LOG_FUNC, "unknown if_type %u for %s\n", 1054 ifp->if_type,ifp->if_xname); 1055 pktap_count_unknown_if_type += 1; 1056 } else { 1057 snprintf(hdr->pth_ifname, sizeof(hdr->pth_ifname), "%s", 1058 ifp->if_xname); 1059 hdr->pth_flags |= outgoing ? PTH_FLAG_DIR_OUT : PTH_FLAG_DIR_IN; 1060 hdr->pth_protocol_family = proto; 1061 hdr->pth_frame_pre_length = pre + pre_adjust; 1062 hdr->pth_frame_post_length = post; 1063 hdr->pth_iftype = ifp->if_type; 1064 hdr->pth_ifunit = ifp->if_unit; 1065 1066 pktap_fill_proc_info(hdr, proto, m, pre, outgoing, ifp); 1067 1068 hdr->pth_svc = so_svc2tc(m->m_pkthdr.pkt_svc); 1069 1070 if (data_adjust == 0) { 1071 bpf_tap_func(pktap->pktp_ifp, DLT_PKTAP, m, hdr, hdr_size); 1072 } else { 1073 /* 1074 * We can play just with the length of the first mbuf in the 1075 * chain because bpf_tap_imp() disregard the packet length 1076 * of the mbuf packet header. 1077 */ 1078 if (mbuf_setdata(m, m->m_data + data_adjust, m->m_len - data_adjust) == 0) { 1079 bpf_tap_func(pktap->pktp_ifp, DLT_PKTAP, m, hdr, hdr_size); 1080 mbuf_setdata(m, m->m_data - data_adjust, m->m_len + data_adjust); 1081 } 1082 } 1083 } 1084 } 1085 } 1086done: 1087 lck_rw_done(pktap_lck_rw); 1088} 1089 1090__private_extern__ void 1091pktap_input(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m, 1092 char *frame_header) 1093{ 1094 char *hdr = (char *)mbuf_data(m); 1095 char *start = (char *)mbuf_datastart(m); 1096 1097 /* Fast path */ 1098 if (pktap_total_tap_count == 0) 1099 return; 1100 1101 /* Make sure the frame header is fully contained in the mbuf */ 1102 if (frame_header != NULL && frame_header >= start && frame_header <= hdr) { 1103 size_t o_len = m->m_len; 1104 u_int32_t pre = hdr - frame_header; 1105 1106 if (mbuf_setdata(m, frame_header, o_len + pre) == 0) { 1107 PKTAP_LOG(PKTP_LOG_INPUT, "ifp %s proto %u pre %u post %u\n", 1108 ifp->if_xname, proto, pre, 0); 1109 1110 pktap_bpf_tap(ifp, proto, m, pre, 0, 0); 1111 mbuf_setdata(m, hdr, o_len); 1112 } 1113 } else { 1114 PKTAP_LOG(PKTP_LOG_INPUT, "ifp %s proto %u pre %u post %u\n", 1115 ifp->if_xname, proto, 0, 0); 1116 1117 pktap_bpf_tap(ifp, proto, m, 0, 0, 0); 1118 } 1119} 1120 1121__private_extern__ void 1122pktap_output(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m, 1123 u_int32_t pre, u_int32_t post) 1124{ 1125 /* Fast path */ 1126 if (pktap_total_tap_count == 0) 1127 return; 1128 1129 PKTAP_LOG(PKTP_LOG_OUTPUT, "ifp %s proto %u pre %u post %u\n", 1130 ifp->if_xname, proto, pre, post); 1131 1132 pktap_bpf_tap(ifp, proto, m, pre, post, 1); 1133} 1134