X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/3e170ce000f1506b7b5d2c5c7faec85ceabb573d..refs/heads/master:/bsd/net/pktap.c diff --git a/bsd/net/pktap.c b/bsd/net/pktap.c index e02810ac4..c5d8635b3 100644 --- a/bsd/net/pktap.c +++ b/bsd/net/pktap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Apple Inc. All rights reserved. + * Copyright (c) 2012-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -27,6 +27,7 @@ */ #include +#include #include #include @@ -47,7 +48,7 @@ #include #include #include -#define _IP_VHL +#define _IP_VHL #include #include #include @@ -67,29 +68,29 @@ extern struct inpcbinfo ripcbinfo; struct pktap_softc { - LIST_ENTRY(pktap_softc) pktp_link; - uint32_t pktp_unit; - uint32_t pktp_dlt_raw_count; - uint32_t pktp_dlt_pkttap_count; - struct ifnet *pktp_ifp; - struct pktap_filter pktp_filters[PKTAP_MAX_FILTERS]; + LIST_ENTRY(pktap_softc) pktp_link; + uint32_t pktp_unit; + uint32_t pktp_dlt_raw_count; + uint32_t pktp_dlt_pkttap_count; + struct ifnet *pktp_ifp; + struct pktap_filter pktp_filters[PKTAP_MAX_FILTERS]; }; #ifndef PKTAP_DEBUG -#define PKTAP_DEBUG 1 +#define PKTAP_DEBUG 0 #endif /* PKTAP_DEBUG */ -#define PKTAP_FILTER_OK 0 /* Packet passes filter checks */ -#define PKTAP_FILTER_SKIP 1 /* Do not tap this packet */ +#define PKTAP_FILTER_OK 0 /* Packet passes filter checks */ +#define PKTAP_FILTER_SKIP 1 /* Do not tap this packet */ static int pktap_inited = 0; SYSCTL_DECL(_net_link); SYSCTL_NODE(_net_link, IFT_PKTAP, pktap, - CTLFLAG_RW |CTLFLAG_LOCKED, 0, "pktap virtual interface"); + CTLFLAG_RW | CTLFLAG_LOCKED, 0, "pktap virtual interface"); -static int pktap_total_tap_count = 0; -SYSCTL_INT(_net_link_pktap, OID_AUTO, total_tap_count, +uint32_t pktap_total_tap_count = 0; +SYSCTL_UINT(_net_link_pktap, OID_AUTO, total_tap_count, CTLFLAG_RD | CTLFLAG_LOCKED, &pktap_total_tap_count, 0, ""); static u_int64_t pktap_count_unknown_if_type = 0; @@ -100,18 +101,18 @@ static int pktap_log = 0; SYSCTL_INT(_net_link_pktap, OID_AUTO, log, CTLFLAG_RW | CTLFLAG_LOCKED, &pktap_log, 0, ""); -#define PKTAP_LOG(mask, fmt, ...) \ +#define PKTAP_LOG(mask, fmt, ...) \ do { \ if ((pktap_log & mask)) \ - printf("%s:%d " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + printf("%s:%d " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ } while (false) -#define PKTP_LOG_FUNC 0x01 -#define PKTP_LOG_FILTER 0x02 -#define PKTP_LOG_INPUT 0x04 -#define PKTP_LOG_OUTPUT 0x08 -#define PKTP_LOG_ERROR 0x10 -#define PKTP_LOG_NOPCB 0x20 +#define PKTP_LOG_FUNC 0x01 +#define PKTP_LOG_FILTER 0x02 +#define PKTP_LOG_INPUT 0x04 +#define PKTP_LOG_OUTPUT 0x08 +#define PKTP_LOG_ERROR 0x10 +#define PKTP_LOG_NOPCB 0x20 /* * pktap_lck_rw protects the global list of pktap interfaces @@ -127,17 +128,22 @@ static LIST_HEAD(pktap_list, pktap_softc) pktap_list = int pktap_clone_create(struct if_clone *, u_int32_t, void *); int pktap_clone_destroy(struct ifnet *); +#define PKTAP_MAXUNIT IF_MAXUNIT +#define PKTAP_ZONE_MAX_ELEM MIN(IFNETS_MAX, PKTAP_MAXUNIT) + static struct if_clone pktap_cloner = - IF_CLONE_INITIALIZER(PKTAP_IFNAME, - pktap_clone_create, - pktap_clone_destroy, - 0, - IF_MAXUNIT); + IF_CLONE_INITIALIZER(PKTAP_IFNAME, + pktap_clone_create, + pktap_clone_destroy, + 0, + PKTAP_MAXUNIT, + PKTAP_ZONE_MAX_ELEM, + sizeof(struct pktap_softc)); errno_t pktap_if_output(ifnet_t, mbuf_t); errno_t pktap_demux(ifnet_t, mbuf_t, char *, protocol_family_t *); errno_t pktap_add_proto(ifnet_t, protocol_family_t, - const struct ifnet_demux_desc *, u_int32_t); + const struct ifnet_demux_desc *, u_int32_t); errno_t pktap_del_proto(ifnet_t, protocol_family_t); errno_t pktap_getdrvspec(ifnet_t, struct ifdrv64 *); errno_t pktap_setdrvspec(ifnet_t, struct ifdrv64 *); @@ -154,33 +160,41 @@ pktap_hexdump(int mask, void *addr, size_t len) unsigned char *buf = addr; size_t i; - if (!(pktap_log & mask)) + if (!(pktap_log & mask)) { return; + } for (i = 0; i < len; i++) { unsigned char h = (buf[i] & 0xf0) >> 4; unsigned char l = buf[i] & 0x0f; if (i != 0) { - if (i % 32 == 0) + if (i % 32 == 0) { printf("\n"); - else if (i % 4 == 0) + } else if (i % 4 == 0) { printf(" "); + } } printf("%c%c", - h < 10 ? h + '0' : h - 10 + 'a', - l < 10 ? l + '0' : l - 10 + 'a'); + h < 10 ? h + '0' : h - 10 + 'a', + l < 10 ? l + '0' : l - 10 + 'a'); } - if (i % 32 != 0) + if (i % 32 != 0) { printf("\n"); + } } +#define _CASSERT_OFFFSETOF_FIELD(s1, s2, f) \ + _CASSERT(offsetof(struct s1, f) == offsetof(struct s2, f)) + __private_extern__ void pktap_init(void) { int error = 0; lck_grp_attr_t *lck_grp_attr = NULL; + _CASSERT_OFFFSETOF_FIELD(pktap_header, pktap_v2_hdr, pth_flags); + /* Make sure we're called only once */ VERIFY(pktap_inited == 0); @@ -198,9 +212,10 @@ pktap_init(void) LIST_INIT(&pktap_list); error = if_clone_attach(&pktap_cloner); - if (error != 0) + if (error != 0) { panic("%s: if_clone_attach() failed, error %d\n", __func__, error); + } } __private_extern__ int @@ -208,12 +223,11 @@ pktap_clone_create(struct if_clone *ifc, u_int32_t unit, __unused void *params) { int error = 0; struct pktap_softc *pktap = NULL; - struct ifnet_init_params if_init; + struct ifnet_init_eparams if_init; PKTAP_LOG(PKTP_LOG_FUNC, "unit %u\n", unit); - pktap = _MALLOC(sizeof(struct pktap_softc), M_DEVBUF, - M_WAITOK | M_ZERO); + pktap = if_clone_softc_allocate(&pktap_cloner); if (pktap == NULL) { printf("%s: _MALLOC failed\n", __func__); error = ENOMEM; @@ -228,14 +242,28 @@ pktap_clone_create(struct if_clone *ifc, u_int32_t unit, __unused void *params) pktap->pktp_filters[0].filter_param = PKTAP_FILTER_PARAM_IF_TYPE; pktap->pktp_filters[0].filter_param_if_type = IFT_ETHER; +#if !XNU_TARGET_OS_OSX + pktap->pktp_filters[1].filter_op = PKTAP_FILTER_OP_PASS; + pktap->pktp_filters[1].filter_param = PKTAP_FILTER_PARAM_IF_TYPE; + pktap->pktp_filters[1].filter_param_if_type = IFT_CELLULAR; +#else /* XNU_TARGET_OS_OSX */ pktap->pktp_filters[1].filter_op = PKTAP_FILTER_OP_PASS; pktap->pktp_filters[1].filter_param = PKTAP_FILTER_PARAM_IF_TYPE; pktap->pktp_filters[1].filter_param_if_type = IFT_IEEE1394; +#endif /* XNU_TARGET_OS_OSX */ + + pktap->pktp_filters[2].filter_op = PKTAP_FILTER_OP_PASS; + pktap->pktp_filters[2].filter_param = PKTAP_FILTER_PARAM_IF_TYPE; + pktap->pktp_filters[2].filter_param_if_type = IFT_OTHER; + /* * We do not use a set_bpf_tap() function as we rather rely on the more * accurate callback passed to bpf_attach() */ - bzero(&if_init, sizeof(struct ifnet_init_params)); + bzero(&if_init, sizeof(if_init)); + if_init.ver = IFNET_INIT_CURRENT_VERSION; + if_init.len = sizeof(if_init); + if_init.flags = IFNET_INIT_LEGACY; if_init.name = ifc->ifc_name; if_init.unit = unit; if_init.type = IFT_PKTAP; @@ -248,7 +276,7 @@ pktap_clone_create(struct if_clone *ifc, u_int32_t unit, __unused void *params) if_init.ioctl = pktap_ioctl; if_init.detach = pktap_detach; - error = ifnet_allocate(&if_init, &pktap->pktp_ifp); + error = ifnet_allocate_extended(&if_init, &pktap->pktp_ifp); if (error != 0) { printf("%s: ifnet_allocate failed, error %d\n", __func__, error); @@ -275,11 +303,10 @@ pktap_clone_create(struct if_clone *ifc, u_int32_t unit, __unused void *params) LIST_INSERT_HEAD(&pktap_list, pktap, pktp_link); lck_rw_done(pktap_lck_rw); done: - if (error != 0) { - if (pktap != NULL) - _FREE(pktap, M_DEVBUF); + if (error != 0 && pktap != NULL) { + if_clone_softc_deallocate(&pktap_cloner, pktap); } - return (error); + return error; } __private_extern__ int @@ -291,7 +318,7 @@ pktap_clone_destroy(struct ifnet *ifp) (void) ifnet_detach(ifp); - return (error); + return error; } /* @@ -313,29 +340,28 @@ pktap_tap_callback(ifnet_t ifp, u_int32_t dlt, bpf_tap_mode direction) goto done; } switch (dlt) { - case DLT_RAW: - if (direction == 0) { - if (pktap->pktp_dlt_raw_count > 0) { - pktap->pktp_dlt_raw_count--; - OSAddAtomic(-1, &pktap_total_tap_count); - - } - } else { - pktap->pktp_dlt_raw_count++; - OSAddAtomic(1, &pktap_total_tap_count); + case DLT_RAW: + if (direction == 0) { + if (pktap->pktp_dlt_raw_count > 0) { + pktap->pktp_dlt_raw_count--; + OSAddAtomic(-1, &pktap_total_tap_count); } - break; - case DLT_PKTAP: - if (direction == 0) { - if (pktap->pktp_dlt_pkttap_count > 0) { - pktap->pktp_dlt_pkttap_count--; - OSAddAtomic(-1, &pktap_total_tap_count); - } - } else { - pktap->pktp_dlt_pkttap_count++; - OSAddAtomic(1, &pktap_total_tap_count); + } else { + pktap->pktp_dlt_raw_count++; + OSAddAtomic(1, &pktap_total_tap_count); + } + break; + case DLT_PKTAP: + if (direction == 0) { + if (pktap->pktp_dlt_pkttap_count > 0) { + pktap->pktp_dlt_pkttap_count--; + OSAddAtomic(-1, &pktap_total_tap_count); } - break; + } else { + pktap->pktp_dlt_pkttap_count++; + OSAddAtomic(1, &pktap_total_tap_count); + } + break; } done: /* @@ -344,7 +370,7 @@ done: */ VERIFY(pktap_total_tap_count >= 0); - return (0); + return 0; } __private_extern__ errno_t @@ -352,15 +378,15 @@ pktap_if_output(ifnet_t ifp, mbuf_t m) { PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname); mbuf_freem(m); - return (ENOTSUP); + return ENOTSUP; } __private_extern__ errno_t pktap_demux(ifnet_t ifp, __unused mbuf_t m, __unused char *header, - __unused protocol_family_t *ppf) + __unused protocol_family_t *ppf) { PKTAP_LOG(PKTP_LOG_FUNC, "%s\n", ifp->if_xname); - return (ENOTSUP); + return ENOTSUP; } __private_extern__ errno_t @@ -368,14 +394,14 @@ pktap_add_proto(__unused ifnet_t ifp, protocol_family_t pf, __unused const struct ifnet_demux_desc *dmx, __unused u_int32_t cnt) { PKTAP_LOG(PKTP_LOG_FUNC, "%s pf %u\n", ifp->if_xname, pf); - return (0); + return 0; } __private_extern__ errno_t pktap_del_proto(__unused ifnet_t ifp, __unused protocol_family_t pf) { PKTAP_LOG(PKTP_LOG_FUNC, "%s pf %u\n", ifp->if_xname, pf); - return (0); + return 0; } __private_extern__ errno_t @@ -402,7 +428,7 @@ pktap_getdrvspec(ifnet_t ifp, struct ifdrv64 *ifd) if (ifd->ifd_len < PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)) { printf("%s: PKTP_CMD_FILTER_GET ifd_len %llu too small - error %d\n", - __func__, ifd->ifd_len, error); + __func__, ifd->ifd_len, error); error = EINVAL; break; } @@ -413,15 +439,16 @@ pktap_getdrvspec(ifnet_t ifp, struct ifdrv64 *ifd) x_filter->filter_op = pktap_filter->filter_op; x_filter->filter_param = pktap_filter->filter_param; - if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) + if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) { x_filter->filter_param_if_type = pktap_filter->filter_param_if_type; - else if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) + } else if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) { strlcpy(x_filter->filter_param_if_name, - pktap_filter->filter_param_if_name, - sizeof(x_filter->filter_param_if_name)); + pktap_filter->filter_param_if_name, + sizeof(x_filter->filter_param_if_name)); + } } - error = copyout(x_filters, ifd->ifd_data, - PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)); + error = copyout(x_filters, CAST_USER_ADDR_T(ifd->ifd_data), + PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)); if (error) { printf("%s: PKTP_CMD_FILTER_GET copyout - error %d\n", __func__, error); goto done; @@ -433,11 +460,11 @@ pktap_getdrvspec(ifnet_t ifp, struct ifdrv64 *ifd) if (ifd->ifd_len < sizeof(tap_count)) { printf("%s: PKTP_CMD_TAP_COUNT ifd_len %llu too small - error %d\n", - __func__, ifd->ifd_len, error); + __func__, ifd->ifd_len, error); error = EINVAL; break; } - error = copyout(&tap_count, ifd->ifd_data, sizeof(tap_count)); + error = copyout(&tap_count, CAST_USER_ADDR_T(ifd->ifd_data), sizeof(tap_count)); if (error) { printf("%s: PKTP_CMD_TAP_COUNT copyout - error %d\n", __func__, error); goto done; @@ -450,7 +477,7 @@ pktap_getdrvspec(ifnet_t ifp, struct ifdrv64 *ifd) } done: - return (error); + return error; } __private_extern__ errno_t @@ -476,11 +503,11 @@ pktap_setdrvspec(ifnet_t ifp, struct ifdrv64 *ifd) if (ifd->ifd_len != PKTAP_MAX_FILTERS * sizeof(struct x_pktap_filter)) { printf("%s: PKTP_CMD_FILTER_SET bad ifd_len %llu - error %d\n", - __func__, ifd->ifd_len, error); + __func__, ifd->ifd_len, error); error = EINVAL; break; } - error = copyin(ifd->ifd_data, &user_filters, ifd->ifd_len); + error = copyin(CAST_USER_ADDR_T(ifd->ifd_data), &user_filters, (size_t)ifd->ifd_len); if (error) { printf("%s: copyin - error %d\n", __func__, error); goto done; @@ -492,61 +519,64 @@ pktap_setdrvspec(ifnet_t ifp, struct ifdrv64 *ifd) struct x_pktap_filter *x_filter = user_filters + i; switch (x_filter->filter_op) { - case PKTAP_FILTER_OP_NONE: - /* Following entries must be PKTAP_FILTER_OP_NONE */ - got_op_none = 1; - break; - case PKTAP_FILTER_OP_PASS: - case PKTAP_FILTER_OP_SKIP: - /* Invalid after PKTAP_FILTER_OP_NONE */ - if (got_op_none) { - error = EINVAL; - break; - } - break; - default: + case PKTAP_FILTER_OP_NONE: + /* Following entries must be PKTAP_FILTER_OP_NONE */ + got_op_none = 1; + break; + case PKTAP_FILTER_OP_PASS: + case PKTAP_FILTER_OP_SKIP: + /* Invalid after PKTAP_FILTER_OP_NONE */ + if (got_op_none) { error = EINVAL; break; + } + break; + default: + error = EINVAL; + break; } - if (error != 0) + if (error != 0) { break; + } switch (x_filter->filter_param) { - case PKTAP_FILTER_OP_NONE: - if (x_filter->filter_op != PKTAP_FILTER_OP_NONE) { - error = EINVAL; - break; - } - break; - - /* - * Do not allow to tap a pktap from a pktap - */ - case PKTAP_FILTER_PARAM_IF_TYPE: - if (x_filter->filter_param_if_type == IFT_PKTAP || - x_filter->filter_param_if_type > 0xff) { - error = EINVAL; - break; - } + case PKTAP_FILTER_OP_NONE: + if (x_filter->filter_op != PKTAP_FILTER_OP_NONE) { + error = EINVAL; break; + } + break; - case PKTAP_FILTER_PARAM_IF_NAME: - if (strncmp(x_filter->filter_param_if_name, PKTAP_IFNAME, - strlen(PKTAP_IFNAME)) == 0) { - error = EINVAL; - break; - } + /* + * Do not allow to tap a pktap from a pktap + */ + case PKTAP_FILTER_PARAM_IF_TYPE: + if (x_filter->filter_param_if_type == IFT_PKTAP || + x_filter->filter_param_if_type > 0xff) { + error = EINVAL; break; + } + break; - default: + case PKTAP_FILTER_PARAM_IF_NAME: + if (strncmp(x_filter->filter_param_if_name, PKTAP_IFNAME, + strlen(PKTAP_IFNAME)) == 0) { error = EINVAL; break; + } + break; + + default: + error = EINVAL; + break; } - if (error != 0) + if (error != 0) { break; + } } - if (error != 0) + if (error != 0) { break; + } for (i = 0; i < PKTAP_MAX_FILTERS; i++) { struct pktap_filter *pktap_filter = pktap->pktp_filters + i; struct x_pktap_filter *x_filter = user_filters + i; @@ -554,22 +584,23 @@ pktap_setdrvspec(ifnet_t ifp, struct ifdrv64 *ifd) pktap_filter->filter_op = x_filter->filter_op; pktap_filter->filter_param = x_filter->filter_param; - if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) + if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) { pktap_filter->filter_param_if_type = x_filter->filter_param_if_type; - else if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) { + } else if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) { size_t len; strlcpy(pktap_filter->filter_param_if_name, - x_filter->filter_param_if_name, - sizeof(pktap_filter->filter_param_if_name)); + x_filter->filter_param_if_name, + sizeof(pktap_filter->filter_param_if_name)); /* * If name does not end with a number then it's a "wildcard" match * where we compare the prefix of the interface name */ len = strlen(pktap_filter->filter_param_if_name); if (pktap_filter->filter_param_if_name[len] < '0' || - pktap_filter->filter_param_if_name[len] > '9') + pktap_filter->filter_param_if_name[len] > '9') { pktap_filter->filter_ifname_prefix_len = len; + } } } break; @@ -580,7 +611,7 @@ pktap_setdrvspec(ifnet_t ifp, struct ifdrv64 *ifd) } done: - return (error); + return error; } __private_extern__ errno_t @@ -594,8 +625,8 @@ pktap_ioctl(ifnet_t ifp, unsigned long cmd, void *data) error = kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER); if (error) { PKTAP_LOG(PKTP_LOG_ERROR, - "%s: kauth_authorize_generic(KAUTH_GENERIC_ISSUSER) - error %d\n", - __func__, error); + "%s: kauth_authorize_generic(KAUTH_GENERIC_ISSUSER) - error %d\n", + __func__, error); goto done; } } @@ -645,7 +676,7 @@ pktap_ioctl(ifnet_t ifp, unsigned long cmd, void *data) break; } done: - return (error); + return error; } __private_extern__ void @@ -666,8 +697,7 @@ pktap_detach(ifnet_t ifp) /* Drop reference as it's no more on the global list */ ifnet_release(ifp); - _FREE(pktap, M_DEVBUF); - + if_clone_softc_deallocate(&pktap_cloner, pktap); /* This is for the reference taken by ifnet_attach() */ (void) ifnet_release(ifp); } @@ -682,85 +712,88 @@ pktap_filter_evaluate(struct pktap_softc *pktap, struct ifnet *ifp) for (i = 0; i < PKTAP_MAX_FILTERS; i++) { struct pktap_filter *pktap_filter = pktap->pktp_filters + i; size_t len = pktap_filter->filter_ifname_prefix_len != 0 ? - pktap_filter->filter_ifname_prefix_len : PKTAP_IFXNAMESIZE; + pktap_filter->filter_ifname_prefix_len : PKTAP_IFXNAMESIZE; switch (pktap_filter->filter_op) { - case PKTAP_FILTER_OP_NONE: - match = 1; - break; + case PKTAP_FILTER_OP_NONE: + match = 1; + break; - case PKTAP_FILTER_OP_PASS: - if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) { - if (pktap_filter->filter_param_if_type == 0 || - ifp->if_type == pktap_filter->filter_param_if_type) { - result = PKTAP_FILTER_OK; - match = 1; - PKTAP_LOG(PKTP_LOG_FILTER, "pass %s match type %u\n", - ifp->if_xname, pktap_filter->filter_param_if_type); - break; - } + case PKTAP_FILTER_OP_PASS: + if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) { + if (pktap_filter->filter_param_if_type == 0 || + ifp->if_type == pktap_filter->filter_param_if_type) { + result = PKTAP_FILTER_OK; + match = 1; + PKTAP_LOG(PKTP_LOG_FILTER, "pass %s match type %u\n", + ifp->if_xname, pktap_filter->filter_param_if_type); + break; } - if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) { - if (strncmp(ifp->if_xname, pktap_filter->filter_param_if_name, - len) == 0) { - result = PKTAP_FILTER_OK; - match = 1; - PKTAP_LOG(PKTP_LOG_FILTER, "pass %s match name %s\n", - ifp->if_xname, pktap_filter->filter_param_if_name); - break; - } + } + if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) { + if (strncmp(ifp->if_xname, pktap_filter->filter_param_if_name, + len) == 0) { + result = PKTAP_FILTER_OK; + match = 1; + PKTAP_LOG(PKTP_LOG_FILTER, "pass %s match name %s\n", + ifp->if_xname, pktap_filter->filter_param_if_name); + break; } - break; + } + break; - case PKTAP_FILTER_OP_SKIP: - if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) { - if (pktap_filter->filter_param_if_type == 0 || - ifp->if_type == pktap_filter->filter_param_if_type) { - result = PKTAP_FILTER_SKIP; - match = 1; - PKTAP_LOG(PKTP_LOG_FILTER, "skip %s match type %u\n", - ifp->if_xname, pktap_filter->filter_param_if_type); - break; - } + case PKTAP_FILTER_OP_SKIP: + if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE) { + if (pktap_filter->filter_param_if_type == 0 || + ifp->if_type == pktap_filter->filter_param_if_type) { + result = PKTAP_FILTER_SKIP; + match = 1; + PKTAP_LOG(PKTP_LOG_FILTER, "skip %s match type %u\n", + ifp->if_xname, pktap_filter->filter_param_if_type); + break; } - if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) { - if (strncmp(ifp->if_xname, pktap_filter->filter_param_if_name, - len) == 0) { - result = PKTAP_FILTER_SKIP; - match = 1; - PKTAP_LOG(PKTP_LOG_FILTER, "skip %s match name %s\n", - ifp->if_xname, pktap_filter->filter_param_if_name); - break; - } + } + if (pktap_filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME) { + if (strncmp(ifp->if_xname, pktap_filter->filter_param_if_name, + len) == 0) { + result = PKTAP_FILTER_SKIP; + match = 1; + PKTAP_LOG(PKTP_LOG_FILTER, "skip %s match name %s\n", + ifp->if_xname, pktap_filter->filter_param_if_name); + break; } - break; + } + break; } - if (match) + if (match) { break; + } } if (match == 0) { PKTAP_LOG(PKTP_LOG_FILTER, "%s no match\n", - ifp->if_xname); + ifp->if_xname); } - return (result); + return result; } static void pktap_set_procinfo(struct pktap_header *hdr, struct so_procinfo *soprocinfo) { hdr->pth_pid = soprocinfo->spi_pid; - proc_name(soprocinfo->spi_pid, hdr->pth_comm, MAXCOMLEN); - if (soprocinfo->spi_pid != 0) + if (hdr->pth_comm[0] == 0) { + proc_name(soprocinfo->spi_pid, hdr->pth_comm, MAXCOMLEN); + } + strlcpy(&hdr->pth_comm[0], &soprocinfo->spi_proc_name[0], sizeof(hdr->pth_comm)); + + if (soprocinfo->spi_pid != 0) { uuid_copy(hdr->pth_uuid, soprocinfo->spi_uuid); + } - /* - * When not delegated, the effective pid is the same as the real pid - */ if (soprocinfo->spi_delegated != 0) { hdr->pth_flags |= PTH_FLAG_PROC_DELEGATED; hdr->pth_epid = soprocinfo->spi_epid; - proc_name(soprocinfo->spi_epid, hdr->pth_ecomm, MAXCOMLEN); + strlcpy(&hdr->pth_ecomm[0], &soprocinfo->spi_e_proc_name[0], sizeof(hdr->pth_ecomm)); uuid_copy(hdr->pth_euuid, soprocinfo->spi_euuid); } } @@ -771,35 +804,103 @@ pktap_finalize_proc_info(struct pktap_header *hdr) int found; struct so_procinfo soprocinfo; - if (!(hdr->pth_flags & PTH_FLAG_DELAY_PKTAP)) + if (!(hdr->pth_flags & PTH_FLAG_DELAY_PKTAP)) { return; + } - /* - * Clear the flag as it's internal - */ - hdr->pth_flags &= ~PTH_FLAG_DELAY_PKTAP; - - if (hdr->pth_ipproto == IPPROTO_TCP) + if (hdr->pth_ipproto == IPPROTO_TCP) { found = inp_findinpcb_procinfo(&tcbinfo, hdr->pth_flowid, &soprocinfo); - else if (hdr->pth_ipproto == IPPROTO_UDP) + } else if (hdr->pth_ipproto == IPPROTO_UDP) { found = inp_findinpcb_procinfo(&udbinfo, hdr->pth_flowid, &soprocinfo); - else + } else { found = inp_findinpcb_procinfo(&ripcbinfo, hdr->pth_flowid, &soprocinfo); + } - if (found == 1) + if (found == 1) { pktap_set_procinfo(hdr, &soprocinfo); + } +} + +static void +pktap_v2_set_procinfo(struct pktap_v2_hdr *pktap_v2_hdr, + struct so_procinfo *soprocinfo) +{ + pktap_v2_hdr->pth_pid = soprocinfo->spi_pid; + + if (soprocinfo->spi_pid != 0 && soprocinfo->spi_pid != -1) { + if (pktap_v2_hdr->pth_comm_offset != 0) { + char *ptr = ((char *)pktap_v2_hdr) + + pktap_v2_hdr->pth_comm_offset; + + strlcpy(ptr, &soprocinfo->spi_proc_name[0], PKTAP_MAX_COMM_SIZE); + } + if (pktap_v2_hdr->pth_uuid_offset != 0) { + uuid_t *ptr = (uuid_t *) (((char *)pktap_v2_hdr) + + pktap_v2_hdr->pth_uuid_offset); + + uuid_copy(*ptr, soprocinfo->spi_uuid); + } + } + + if (!(pktap_v2_hdr->pth_flags & PTH_FLAG_PROC_DELEGATED)) { + return; + } + + /* + * The effective UUID may be set independently from the effective pid + */ + if (soprocinfo->spi_delegated != 0) { + pktap_v2_hdr->pth_flags |= PTH_FLAG_PROC_DELEGATED; + pktap_v2_hdr->pth_e_pid = soprocinfo->spi_epid; + + if (soprocinfo->spi_pid != 0 && soprocinfo->spi_pid != -1 && + pktap_v2_hdr->pth_e_comm_offset != 0) { + char *ptr = ((char *)pktap_v2_hdr) + + pktap_v2_hdr->pth_e_comm_offset; + + strlcpy(ptr, &soprocinfo->spi_e_proc_name[0], PKTAP_MAX_COMM_SIZE); + } + if (pktap_v2_hdr->pth_e_uuid_offset != 0) { + uuid_t *ptr = (uuid_t *) (((char *)pktap_v2_hdr) + + pktap_v2_hdr->pth_e_uuid_offset); + + uuid_copy(*ptr, soprocinfo->spi_euuid); + } + } } __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) +pktap_v2_finalize_proc_info(struct pktap_v2_hdr *pktap_v2_hdr) { - int found = 0; + int found; struct so_procinfo soprocinfo; + if (!(pktap_v2_hdr->pth_flags & PTH_FLAG_DELAY_PKTAP)) { + return; + } + + if (pktap_v2_hdr->pth_ipproto == IPPROTO_TCP) { + found = inp_findinpcb_procinfo(&tcbinfo, + pktap_v2_hdr->pth_flowid, &soprocinfo); + } else if (pktap_v2_hdr->pth_ipproto == IPPROTO_UDP) { + found = inp_findinpcb_procinfo(&udbinfo, + pktap_v2_hdr->pth_flowid, &soprocinfo); + } else { + found = inp_findinpcb_procinfo(&ripcbinfo, + pktap_v2_hdr->pth_flowid, &soprocinfo); + } + if (found == 1) { + pktap_v2_set_procinfo(pktap_v2_hdr, &soprocinfo); + } +} + +__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) +{ /* * Getting the pid and procname is expensive * For outgoing, do the lookup only if there's an @@ -807,26 +908,60 @@ pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto, */ if (outgoing != 0 && m->m_pkthdr.pkt_flowsrc == FLOWSRC_INPCB) { /* - * To avoid lock ordering issues we delay the process lookup + * To avoid lock ordering issues we delay the proc UUID lookup * to the BPF read as we cannot * assume the socket lock is unlocked on output */ - found = 0; hdr->pth_flags |= PTH_FLAG_DELAY_PKTAP; + hdr->pth_flags |= PTH_FLAG_SOCKET; hdr->pth_flowid = m->m_pkthdr.pkt_flowid; - if (m->m_pkthdr.pkt_flags & PKTF_FLOW_RAWSOCK) + + if (m->m_pkthdr.pkt_flags & PKTF_FLOW_RAWSOCK) { hdr->pth_ipproto = IPPROTO_RAW; - else + } else { hdr->pth_ipproto = m->m_pkthdr.pkt_proto; + } + + if (hdr->pth_ipproto == IPPROTO_TCP) { + hdr->pth_pid = m->m_pkthdr.tx_tcp_pid; + hdr->pth_epid = m->m_pkthdr.tx_tcp_e_pid; + } else if (hdr->pth_ipproto == IPPROTO_UDP) { + hdr->pth_pid = m->m_pkthdr.tx_udp_pid; + hdr->pth_epid = m->m_pkthdr.tx_udp_e_pid; + } else if (hdr->pth_ipproto == IPPROTO_RAW) { + hdr->pth_pid = m->m_pkthdr.tx_rawip_pid; + hdr->pth_epid = m->m_pkthdr.tx_rawip_e_pid; + } + + if (hdr->pth_pid != 0 && hdr->pth_pid != -1) { + proc_name(hdr->pth_pid, hdr->pth_comm, MAXCOMLEN); + } else { + hdr->pth_pid = -1; + } + + if (hdr->pth_epid != 0 && hdr->pth_epid != -1) { + hdr->pth_flags |= PTH_FLAG_PROC_DELEGATED; + proc_name(hdr->pth_epid, hdr->pth_ecomm, MAXCOMLEN); + } else { + hdr->pth_epid = -1; + } + + if (m->m_pkthdr.pkt_flags & PKTF_NEW_FLOW) { + hdr->pth_flags |= PTH_FLAG_NEW_FLOW; + } } else if (outgoing == 0) { + int found = 0; + struct so_procinfo soprocinfo; struct inpcb *inp = NULL; + memset(&soprocinfo, 0, sizeof(struct so_procinfo)); + if (proto == PF_INET) { struct ip ip; errno_t error; size_t hlen; struct in_addr faddr, laddr; - u_short fport, lport; + u_short fport = 0, lport = 0; struct inpcbinfo *pcbinfo = NULL; int wildcard = 0; @@ -846,9 +981,10 @@ pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto, struct tcphdr th; error = mbuf_copydata(m, pre + hlen, - sizeof(struct tcphdr), &th); - if (error != 0) + sizeof(struct tcphdr), &th); + if (error != 0) { goto done; + } fport = th.th_sport; lport = th.th_dport; @@ -858,7 +994,7 @@ pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto, struct udphdr uh; error = mbuf_copydata(m, pre + hlen, - sizeof(struct udphdr), &uh); + sizeof(struct udphdr), &uh); if (error != 0) { PKTAP_LOG(PKTP_LOG_ERROR, "mbuf_copydata udp v4 failed for %s\n", @@ -873,12 +1009,13 @@ pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto, } if (pcbinfo != NULL) { inp = in_pcblookup_hash(pcbinfo, faddr, fport, - laddr, lport, wildcard, outgoing ? NULL : ifp); + laddr, lport, wildcard, outgoing ? NULL : ifp); - if (inp == NULL && hdr->pth_iftype != IFT_LOOP) + if (inp == NULL && hdr->pth_iftype != IFT_LOOP) { PKTAP_LOG(PKTP_LOG_NOPCB, "in_pcblookup_hash no pcb %s\n", hdr->pth_ifname); + } } else { PKTAP_LOG(PKTP_LOG_NOPCB, "unknown ip_p %u on %s\n", @@ -890,13 +1027,14 @@ pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto, errno_t error; struct in6_addr *faddr; struct in6_addr *laddr; - u_short fport, lport; + u_short fport = 0, lport = 0; struct inpcbinfo *pcbinfo = NULL; int wildcard = 0; error = mbuf_copydata(m, pre, sizeof(struct ip6_hdr), &ip6); - if (error != 0) + if (error != 0) { goto done; + } faddr = &ip6.ip6_src; laddr = &ip6.ip6_dst; @@ -905,7 +1043,7 @@ pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto, struct tcphdr th; error = mbuf_copydata(m, pre + sizeof(struct ip6_hdr), - sizeof(struct tcphdr), &th); + sizeof(struct tcphdr), &th); if (error != 0) { PKTAP_LOG(PKTP_LOG_ERROR, "mbuf_copydata tcp v6 failed for %s\n", @@ -921,7 +1059,7 @@ pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto, struct udphdr uh; error = mbuf_copydata(m, pre + sizeof(struct ip6_hdr), - sizeof(struct udphdr), &uh); + sizeof(struct udphdr), &uh); if (error != 0) { PKTAP_LOG(PKTP_LOG_ERROR, "mbuf_copydata udp v6 failed for %s\n", @@ -937,12 +1075,13 @@ pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto, } if (pcbinfo != NULL) { inp = in6_pcblookup_hash(pcbinfo, faddr, fport, - laddr, lport, wildcard, outgoing ? NULL : ifp); + laddr, lport, wildcard, outgoing ? NULL : ifp); - if (inp == NULL && hdr->pth_iftype != IFT_LOOP) + if (inp == NULL && hdr->pth_iftype != IFT_LOOP) { PKTAP_LOG(PKTP_LOG_NOPCB, "in6_pcblookup_hash no pcb %s\n", hdr->pth_ifname); + } } else { PKTAP_LOG(PKTP_LOG_NOPCB, "unknown ip6.ip6_nxt %u on %s\n", @@ -951,21 +1090,24 @@ pktap_fill_proc_info(struct pktap_header *hdr, protocol_family_t proto, } } if (inp != NULL) { + hdr->pth_flags |= PTH_FLAG_SOCKET; if (inp->inp_state != INPCB_STATE_DEAD && inp->inp_socket != NULL) { found = 1; inp_get_soprocinfo(inp, &soprocinfo); } in_pcb_checkstate(inp, WNT_RELEASE, 0); } - } done: - /* - * -1 means PID not found - */ - hdr->pth_pid = -1; - hdr->pth_epid = -1; - if (found != 0) - pktap_set_procinfo(hdr, &soprocinfo); + /* + * -1 means PID not found + */ + hdr->pth_pid = -1; + hdr->pth_epid = -1; + + if (found != 0) { + pktap_set_procinfo(hdr, &soprocinfo); + } + } } __private_extern__ void @@ -974,7 +1116,14 @@ pktap_bpf_tap(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m, { struct pktap_softc *pktap; void (*bpf_tap_func)(ifnet_t, u_int32_t, mbuf_t, void *, size_t) = - outgoing ? bpf_tap_out : bpf_tap_in; + outgoing ? bpf_tap_out : bpf_tap_in; + + /* + * Skip the coprocessor interface + */ + if (!intcoproc_unrestricted && IFNET_IS_INTCOPROC(ifp)) { + return; + } lck_rw_lock_shared(pktap_lck_rw); @@ -986,19 +1135,20 @@ pktap_bpf_tap(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m, int filter_result; filter_result = pktap_filter_evaluate(pktap, ifp); - if (filter_result == PKTAP_FILTER_SKIP) + if (filter_result == PKTAP_FILTER_SKIP) { continue; + } if (pktap->pktp_dlt_raw_count > 0) { /* We accept only IPv4 and IPv6 packets for the raw DLT */ - if ((proto == AF_INET ||proto == AF_INET6) && - !(m->m_pkthdr.pkt_flags & PKTF_INET_RESOLVE)) { + if ((proto == AF_INET || proto == AF_INET6) && + !(m->m_pkthdr.pkt_flags & PKTF_INET_RESOLVE)) { /* * We can play just with the length of the first mbuf in the * chain because bpf_tap_imp() disregard the packet length * of the mbuf packet header. */ - if (mbuf_setdata(m, m->m_data + pre, m->m_len - pre) == 0) { + if (mbuf_setdata(m, m->m_data + pre, m->m_len - pre) == 0) { bpf_tap_func(pktap->pktp_ifp, DLT_RAW, m, NULL, 0); mbuf_setdata(m, m->m_data - pre, m->m_len + pre); } @@ -1027,68 +1177,85 @@ pktap_bpf_tap(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m, * Set DLT of packet based on interface type */ switch (ifp->if_type) { - case IFT_LOOP: - case IFT_GIF: - case IFT_STF: - case IFT_CELLULAR: + case IFT_LOOP: + case IFT_GIF: + case IFT_STF: + case IFT_CELLULAR: + /* + * Packets from pdp interfaces have no loopback + * header that contain the protocol number. + * As BPF just concatenate the header and the + * packet content in a single buffer, + * stash the protocol after the pktap header + * and adjust the size of the header accordingly + */ + hdr->pth_dlt = DLT_NULL; + if (pre == 0) { + hdr_buffer.proto = proto; + hdr_size = sizeof(hdr_buffer); + pre_adjust = sizeof(hdr_buffer.proto); + } + break; + case IFT_ETHER: + case IFT_BRIDGE: + case IFT_L2VLAN: + case IFT_IEEE8023ADLAG: + hdr->pth_dlt = DLT_EN10MB; + break; + case IFT_PPP: + hdr->pth_dlt = DLT_PPP; + break; + case IFT_IEEE1394: + hdr->pth_dlt = DLT_APPLE_IP_OVER_IEEE1394; + break; + case IFT_OTHER: + if (ifp->if_family == IFNET_FAMILY_IPSEC || + ifp->if_family == IFNET_FAMILY_UTUN) { /* - * Packets from pdp interfaces have no loopback - * header that contain the protocol number. - * As BPF just concatenate the header and the - * packet content in a single buffer, - * stash the protocol after the pktap header - * and adjust the size of the header accordingly + * For utun: + * - incoming packets do not have the prefix set to four + * - some packets are as small as two bytes! */ - hdr->pth_dlt = DLT_NULL; - if (pre == 0) { - hdr_buffer.proto = proto; - hdr_size = sizeof(hdr_buffer); - pre_adjust = sizeof(hdr_buffer.proto); + if (m_pktlen(m) < 4) { + goto done; } - break; - case IFT_ETHER: - case IFT_BRIDGE: - case IFT_L2VLAN: - case IFT_IEEE8023ADLAG: - hdr->pth_dlt = DLT_EN10MB; - break; - case IFT_PPP: - hdr->pth_dlt = DLT_PPP; - break; - case IFT_IEEE1394: - hdr->pth_dlt = DLT_APPLE_IP_OVER_IEEE1394; - break; - case IFT_OTHER: - if (strncmp(ifp->if_name, "utun", strlen("utun")) == 0) { - /* - * For utun: - * - incoming packets do not have the prefix set to four - * - some packets are as small as two bytes! - */ - if (m_pktlen(m) < 4) - goto done; - if (proto != AF_INET && proto != AF_INET6) - goto done; - if (proto == AF_INET && (size_t) m_pktlen(m) - 4 < sizeof(struct ip)) - goto done; - if (proto == AF_INET6 && (size_t) m_pktlen(m) - 4 < sizeof(struct ip6_hdr)) - goto done; + if (proto != AF_INET && proto != AF_INET6) { + goto done; + } + if (proto == AF_INET && (size_t) m_pktlen(m) - 4 < sizeof(struct ip)) { + goto done; + } + if (proto == AF_INET6 && (size_t) m_pktlen(m) - 4 < sizeof(struct ip6_hdr)) { + goto done; + } + + /* + * Handle two cases: + * - The old utun encapsulation with the protocol family in network order + * - A raw IPv4 or IPv6 packet + */ + uint8_t data = *(uint8_t *)mbuf_data(m); + if ((data >> 4) == 4 || (data >> 4) == 6) { + pre = 4; + } else { /* * Skip the protocol in the mbuf as it's in network order */ pre = 4; data_adjust = 4; - hdr->pth_dlt = DLT_NULL; - hdr_buffer.proto = proto; - hdr_size = sizeof(hdr_buffer); - break; } - default: - if (pre == 0) - hdr->pth_dlt = DLT_RAW; - else - unknown_if_type = 1; - break; + } + hdr->pth_dlt = DLT_NULL; + hdr_buffer.proto = proto; + hdr_size = sizeof(hdr_buffer); + break; + default: + if (pre == 0) { + hdr->pth_dlt = DLT_RAW; + } else { + unknown_if_type = 1; + } + break; } if (unknown_if_type) { PKTAP_LOG(PKTP_LOG_FUNC, @@ -1096,8 +1263,8 @@ pktap_bpf_tap(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m, ifp->if_type, ifp->if_xname); pktap_count_unknown_if_type += 1; } else { - snprintf(hdr->pth_ifname, sizeof(hdr->pth_ifname), "%s", - ifp->if_xname); + strlcpy(hdr->pth_ifname, ifp->if_xname, + sizeof(hdr->pth_ifname)); hdr->pth_flags |= outgoing ? PTH_FLAG_DIR_OUT : PTH_FLAG_DIR_IN; hdr->pth_protocol_family = proto; hdr->pth_frame_pre_length = pre + pre_adjust; @@ -1105,6 +1272,13 @@ pktap_bpf_tap(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m, hdr->pth_iftype = ifp->if_type; hdr->pth_ifunit = ifp->if_unit; + if (m->m_pkthdr.pkt_flags & PKTF_KEEPALIVE) { + hdr->pth_flags |= PTH_FLAG_KEEP_ALIVE; + } + if (m->m_pkthdr.pkt_flags & PKTF_TCP_REXMT) { + hdr->pth_flags |= PTH_FLAG_REXMIT; + } + pktap_fill_proc_info(hdr, proto, m, pre, outgoing, ifp); hdr->pth_svc = so_svc2tc(m->m_pkthdr.pkt_svc); @@ -1117,7 +1291,7 @@ pktap_bpf_tap(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m, * chain because bpf_tap_imp() disregard the packet length * of the mbuf packet header. */ - if (mbuf_setdata(m, m->m_data + data_adjust, m->m_len - data_adjust) == 0) { + if (mbuf_setdata(m, m->m_data + data_adjust, m->m_len - data_adjust) == 0) { bpf_tap_func(pktap->pktp_ifp, DLT_PKTAP, m, hdr, hdr_size); mbuf_setdata(m, m->m_data - data_adjust, m->m_len + data_adjust); } @@ -1133,28 +1307,32 @@ __private_extern__ void pktap_input(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m, char *frame_header) { - char *hdr = (char *)mbuf_data(m); - char *start = (char *)mbuf_datastart(m); + char *hdr; + char *start; /* Fast path */ - if (pktap_total_tap_count == 0) + if (pktap_total_tap_count == 0 || + (m->m_pkthdr.pkt_flags & PKTF_SKIP_PKTAP) != 0) { return; + } + hdr = (char *)mbuf_data(m); + start = (char *)mbuf_datastart(m); /* Make sure the frame header is fully contained in the mbuf */ if (frame_header != NULL && frame_header >= start && frame_header <= hdr) { size_t o_len = m->m_len; - u_int32_t pre = hdr - frame_header; + u_int32_t pre = (u_int32_t)(hdr - frame_header); if (mbuf_setdata(m, frame_header, o_len + pre) == 0) { PKTAP_LOG(PKTP_LOG_INPUT, "ifp %s proto %u pre %u post %u\n", - ifp->if_xname, proto, pre, 0); + ifp->if_xname, proto, pre, 0); - pktap_bpf_tap(ifp, proto, m, pre, 0, 0); + pktap_bpf_tap(ifp, proto, m, pre, 0, 0); mbuf_setdata(m, hdr, o_len); } } else { PKTAP_LOG(PKTP_LOG_INPUT, "ifp %s proto %u pre %u post %u\n", - ifp->if_xname, proto, 0, 0); + ifp->if_xname, proto, 0, 0); pktap_bpf_tap(ifp, proto, m, 0, 0, 0); } @@ -1165,11 +1343,173 @@ pktap_output(struct ifnet *ifp, protocol_family_t proto, struct mbuf *m, u_int32_t pre, u_int32_t post) { /* Fast path */ - if (pktap_total_tap_count == 0) + if (pktap_total_tap_count == 0 || + (m->m_pkthdr.pkt_flags & PKTF_SKIP_PKTAP) != 0) { return; + } PKTAP_LOG(PKTP_LOG_OUTPUT, "ifp %s proto %u pre %u post %u\n", - ifp->if_xname, proto, pre, post); + ifp->if_xname, proto, pre, post); pktap_bpf_tap(ifp, proto, m, pre, post, 1); } + + +void +convert_to_pktap_header_to_v2(struct bpf_packet *bpf_pkt, bool truncate) +{ + struct pktap_header *pktap_header; + size_t extra_src_size; + struct pktap_buffer_v2_hdr_extra pktap_buffer_v2_hdr_extra; + struct pktap_v2_hdr_space *pktap_v2_hdr_space; + struct pktap_v2_hdr *pktap_v2_hdr; + uint8_t *ptr; + + pktap_header = (struct pktap_header *)bpf_pkt->bpfp_header; + + if (pktap_header->pth_type_next != PTH_TYPE_PACKET) { + return; + } + + VERIFY(bpf_pkt->bpfp_header_length >= sizeof(struct pktap_header)); + + /* + * extra_src_size is the length of the optional link layer header + */ + extra_src_size = bpf_pkt->bpfp_header_length - + sizeof(struct pktap_header); + + VERIFY(extra_src_size <= sizeof(union pktap_header_extra)); + + pktap_v2_hdr_space = &pktap_buffer_v2_hdr_extra.hdr_space; + pktap_v2_hdr = &pktap_v2_hdr_space->pth_hdr; + ptr = (uint8_t *) (pktap_v2_hdr + 1); + + COPY_PKTAP_COMMON_FIELDS_TO_V2(pktap_v2_hdr, pktap_header); + + /* + * When truncating don't bother with the process UUIDs + */ + if (!truncate) { + if ((pktap_header->pth_flags & PTH_FLAG_DELAY_PKTAP)) { + pktap_v2_hdr->pth_uuid_offset = pktap_v2_hdr->pth_length; + pktap_v2_hdr->pth_length += sizeof(uuid_t); + uuid_clear(*(uuid_t *)ptr); + ptr += sizeof(uuid_t); + VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1)); + } else if (!uuid_is_null(pktap_header->pth_uuid)) { + pktap_v2_hdr->pth_uuid_offset = pktap_v2_hdr->pth_length; + uuid_copy(*(uuid_t *)ptr, pktap_header->pth_uuid); + pktap_v2_hdr->pth_length += sizeof(uuid_t); + ptr += sizeof(uuid_t); + VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1)); + } + + if ((pktap_header->pth_flags & PTH_FLAG_DELAY_PKTAP)) { + if (pktap_header->pth_flags & PTH_FLAG_PROC_DELEGATED) { + pktap_v2_hdr->pth_e_uuid_offset = pktap_v2_hdr->pth_length; + uuid_clear(*(uuid_t *)ptr); + pktap_v2_hdr->pth_length += sizeof(uuid_t); + ptr += sizeof(uuid_t); + VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1)); + } + } else if (!uuid_is_null(pktap_header->pth_euuid)) { + pktap_v2_hdr->pth_e_uuid_offset = pktap_v2_hdr->pth_length; + uuid_copy(*(uuid_t *)ptr, pktap_header->pth_euuid); + pktap_v2_hdr->pth_length += sizeof(uuid_t); + ptr += sizeof(uuid_t); + VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1)); + } + } + + if (pktap_header->pth_ifname[0] != 0) { + size_t strsize; + + pktap_v2_hdr->pth_ifname_offset = pktap_v2_hdr->pth_length; + + /* + * Note: strlcpy() returns the length of the string so we need + * to add one for the end-of-string + */ + strsize = 1 + strlcpy((char *)ptr, pktap_header->pth_ifname, + sizeof(pktap_v2_hdr_space->pth_ifname)); + pktap_v2_hdr->pth_length += strsize; + ptr += strsize; + VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1)); + } + + /* + * Do not waste space with the process name if we do not have a pid + */ + if (pktap_header->pth_pid != 0 && pktap_header->pth_pid != -1) { + if (pktap_header->pth_comm[0] != 0) { + size_t strsize; + + pktap_v2_hdr->pth_comm_offset = pktap_v2_hdr->pth_length; + + strsize = 1 + strlcpy((char *)ptr, pktap_header->pth_comm, + sizeof(pktap_v2_hdr_space->pth_comm)); + pktap_v2_hdr->pth_length += strsize; + ptr += strsize; + VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1)); + } else if ((pktap_header->pth_flags & PTH_FLAG_DELAY_PKTAP)) { + size_t strsize = sizeof(pktap_v2_hdr_space->pth_comm); + + pktap_v2_hdr->pth_comm_offset = pktap_v2_hdr->pth_length; + + *ptr = 0; /* empty string by default */ + pktap_v2_hdr->pth_length += strsize; + ptr += strsize; + VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1)); + } + } + + /* + * Do not waste space with the effective process name if we do not have + * an effective pid or it's the same as the pid + */ + if (pktap_header->pth_epid != 0 && pktap_header->pth_epid != -1 && + pktap_header->pth_epid != pktap_header->pth_pid) { + if (pktap_header->pth_ecomm[0] != 0) { + size_t strsize; + + pktap_v2_hdr->pth_e_comm_offset = pktap_v2_hdr->pth_length; + + strsize = 1 + strlcpy((char *)ptr, pktap_header->pth_ecomm, + sizeof(pktap_v2_hdr_space->pth_e_comm)); + pktap_v2_hdr->pth_length += strsize; + ptr += strsize; + VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1)); + } else if ((pktap_header->pth_flags & PTH_FLAG_DELAY_PKTAP)) { + size_t strsize = sizeof(pktap_v2_hdr_space->pth_e_comm); + + pktap_v2_hdr->pth_e_comm_offset = pktap_v2_hdr->pth_length; + *ptr = 0; /* empty string by default */ + pktap_v2_hdr->pth_length += strsize; + ptr += strsize; + VERIFY((void *)ptr < (void *)(pktap_v2_hdr_space + 1)); + } + } + + if (extra_src_size > 0) { + char *extra_src_ptr = (char *)(pktap_header + 1); + char *extra_dst_ptr = ((char *)pktap_v2_hdr) + + pktap_v2_hdr->pth_length; + + VERIFY(pktap_v2_hdr->pth_length + extra_src_size <= + sizeof(struct pktap_buffer_v2_hdr_extra)); + + memcpy(extra_dst_ptr, extra_src_ptr, extra_src_size); + } + + VERIFY(pktap_v2_hdr->pth_length + extra_src_size <= + bpf_pkt->bpfp_header_length); + + memcpy(bpf_pkt->bpfp_header, pktap_v2_hdr, + pktap_v2_hdr->pth_length + extra_src_size); + + bpf_pkt->bpfp_total_length += pktap_v2_hdr->pth_length - + sizeof(struct pktap_header); + bpf_pkt->bpfp_header_length += pktap_v2_hdr->pth_length - + sizeof(struct pktap_header); +}