/*- * Copyright (c) 2010-2012 The NetBSD Foundation, Inc. * All rights reserved. * * This material is based upon work partially supported by The * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * NPF logging extension. */ #ifdef _KERNEL #include __KERNEL_RCSID(0, "$NetBSD: npf_ext_log.c,v 1.17 2020/05/30 14:16:56 rmind Exp $"); #include #include #include #include #include #include #include #include #include #include #endif #include "npf_impl.h" #include "if_npflog.h" NPF_EXT_MODULE(npf_ext_log, ""); #define NPFEXT_LOG_VER 1 static void * npf_ext_log_id; typedef struct { unsigned int if_idx; } npf_ext_log_t; static int npf_log_ctor(npf_rproc_t *rp, const nvlist_t *params) { npf_ext_log_t *meta; meta = kmem_zalloc(sizeof(npf_ext_log_t), KM_SLEEP); meta->if_idx = dnvlist_get_number(params, "log-interface", 0); npf_rproc_assign(rp, meta); return 0; } static void npf_log_dtor(npf_rproc_t *rp, void *meta) { kmem_free(meta, sizeof(npf_ext_log_t)); } static bool npf_log(npf_cache_t *npc, void *meta, const npf_match_info_t *mi, int *decision) { struct mbuf *m = nbuf_head_mbuf(npc->npc_nbuf); const npf_ext_log_t *log = meta; struct psref psref; ifnet_t *ifp; struct npfloghdr hdr; memset(&hdr, 0, sizeof(hdr)); /* Set the address family. */ if (npf_iscached(npc, NPC_IP4)) { hdr.af = AF_INET; } else if (npf_iscached(npc, NPC_IP6)) { hdr.af = AF_INET6; } else { hdr.af = AF_UNSPEC; } hdr.length = NPFLOG_REAL_HDRLEN; hdr.action = *decision == NPF_DECISION_PASS ? 0 /* pass */ : 1 /* block */; hdr.reason = 0; /* match */ struct nbuf *nb = npc->npc_nbuf; npf_ifmap_copyname(npc->npc_ctx, nb ? nb->nb_ifid : 0, hdr.ifname, sizeof(hdr.ifname)); hdr.rulenr = htonl((uint32_t)mi->mi_rid); hdr.subrulenr = htonl((uint32_t)(mi->mi_rid >> 32)); strlcpy(hdr.ruleset, "rules", sizeof(hdr.ruleset)); hdr.uid = UID_MAX; hdr.pid = (pid_t)-1; hdr.rule_uid = UID_MAX; hdr.rule_pid = (pid_t)-1; switch (mi->mi_di) { default: case PFIL_IN|PFIL_OUT: hdr.dir = 0; break; case PFIL_IN: hdr.dir = 1; break; case PFIL_OUT: hdr.dir = 2; break; } KERNEL_LOCK(1, NULL); /* Find a pseudo-interface to log. */ ifp = if_get_byindex(log->if_idx, &psref); if (ifp == NULL) { /* No interface. */ KERNEL_UNLOCK_ONE(NULL); return true; } if_statadd2(ifp, if_opackets, 1, if_obytes, m->m_pkthdr.len); if (ifp->if_bpf) { /* Pass through BPF. */ bpf_mtap2(ifp->if_bpf, &hdr, NPFLOG_HDRLEN, m, BPF_D_OUT); } if_put(ifp, &psref); KERNEL_UNLOCK_ONE(NULL); return true; } __dso_public int npf_ext_log_init(npf_t *npf) { static const npf_ext_ops_t npf_log_ops = { .version = NPFEXT_LOG_VER, .ctx = NULL, .ctor = npf_log_ctor, .dtor = npf_log_dtor, .proc = npf_log }; npf_ext_log_id = npf_ext_register(npf, "log", &npf_log_ops); return npf_ext_log_id ? 0 : EEXIST; } __dso_public int npf_ext_log_fini(npf_t *npf) { return npf_ext_unregister(npf, npf_ext_log_id); } #ifdef _KERNEL static int npf_ext_log_modcmd(modcmd_t cmd, void *arg) { npf_t *npf = npf_getkernctx(); switch (cmd) { case MODULE_CMD_INIT: return npf_ext_log_init(npf); case MODULE_CMD_FINI: return npf_ext_log_fini(npf); break; case MODULE_CMD_AUTOUNLOAD: return npf_autounload_p() ? 0 : EBUSY; default: return ENOTTY; } return 0; } #endif