1/*- 2 * Copyright (c) 2010-2012 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This material is based upon work partially supported by The 6 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30/* 31 * NPF logging extension. 32 */ 33 34#ifdef _KERNEL 35#include <sys/cdefs.h> 36__KERNEL_RCSID(0, "$NetBSD: npf_ext_log.c,v 1.17 2020/05/30 14:16:56 rmind Exp $"); 37 38#include <sys/types.h> 39#include <sys/module.h> 40 41#include <sys/conf.h> 42#include <sys/kmem.h> 43#include <sys/mbuf.h> 44#include <sys/mutex.h> 45#include <sys/queue.h> 46 47#include <net/if.h> 48#include <net/if_types.h> 49#include <net/bpf.h> 50#endif 51 52#include "npf_impl.h" 53#include "if_npflog.h" 54 55NPF_EXT_MODULE(npf_ext_log, ""); 56 57#define NPFEXT_LOG_VER 1 58 59static void * npf_ext_log_id; 60 61typedef struct { 62 unsigned int if_idx; 63} npf_ext_log_t; 64 65static int 66npf_log_ctor(npf_rproc_t *rp, const nvlist_t *params) 67{ 68 npf_ext_log_t *meta; 69 70 meta = kmem_zalloc(sizeof(npf_ext_log_t), KM_SLEEP); 71 meta->if_idx = dnvlist_get_number(params, "log-interface", 0); 72 npf_rproc_assign(rp, meta); 73 return 0; 74} 75 76static void 77npf_log_dtor(npf_rproc_t *rp, void *meta) 78{ 79 kmem_free(meta, sizeof(npf_ext_log_t)); 80} 81 82static bool 83npf_log(npf_cache_t *npc, void *meta, const npf_match_info_t *mi, int *decision) 84{ 85 struct mbuf *m = nbuf_head_mbuf(npc->npc_nbuf); 86 const npf_ext_log_t *log = meta; 87 struct psref psref; 88 ifnet_t *ifp; 89 struct npfloghdr hdr; 90 91 memset(&hdr, 0, sizeof(hdr)); 92 /* Set the address family. */ 93 if (npf_iscached(npc, NPC_IP4)) { 94 hdr.af = AF_INET; 95 } else if (npf_iscached(npc, NPC_IP6)) { 96 hdr.af = AF_INET6; 97 } else { 98 hdr.af = AF_UNSPEC; 99 } 100 101 hdr.length = NPFLOG_REAL_HDRLEN; 102 hdr.action = *decision == NPF_DECISION_PASS ? 103 0 /* pass */ : 1 /* block */; 104 hdr.reason = 0; /* match */ 105 106 struct nbuf *nb = npc->npc_nbuf; 107 npf_ifmap_copyname(npc->npc_ctx, nb ? nb->nb_ifid : 0, 108 hdr.ifname, sizeof(hdr.ifname)); 109 110 hdr.rulenr = htonl((uint32_t)mi->mi_rid); 111 hdr.subrulenr = htonl((uint32_t)(mi->mi_rid >> 32)); 112 strlcpy(hdr.ruleset, "rules", sizeof(hdr.ruleset)); 113 114 hdr.uid = UID_MAX; 115 hdr.pid = (pid_t)-1; 116 hdr.rule_uid = UID_MAX; 117 hdr.rule_pid = (pid_t)-1; 118 119 switch (mi->mi_di) { 120 default: 121 case PFIL_IN|PFIL_OUT: 122 hdr.dir = 0; 123 break; 124 case PFIL_IN: 125 hdr.dir = 1; 126 break; 127 case PFIL_OUT: 128 hdr.dir = 2; 129 break; 130 } 131 132 KERNEL_LOCK(1, NULL); 133 134 /* Find a pseudo-interface to log. */ 135 ifp = if_get_byindex(log->if_idx, &psref); 136 if (ifp == NULL) { 137 /* No interface. */ 138 KERNEL_UNLOCK_ONE(NULL); 139 return true; 140 } 141 142 if_statadd2(ifp, if_opackets, 1, if_obytes, m->m_pkthdr.len); 143 if (ifp->if_bpf) { 144 /* Pass through BPF. */ 145 bpf_mtap2(ifp->if_bpf, &hdr, NPFLOG_HDRLEN, m, BPF_D_OUT); 146 } 147 if_put(ifp, &psref); 148 149 KERNEL_UNLOCK_ONE(NULL); 150 151 return true; 152} 153 154__dso_public int 155npf_ext_log_init(npf_t *npf) 156{ 157 static const npf_ext_ops_t npf_log_ops = { 158 .version = NPFEXT_LOG_VER, 159 .ctx = NULL, 160 .ctor = npf_log_ctor, 161 .dtor = npf_log_dtor, 162 .proc = npf_log 163 }; 164 npf_ext_log_id = npf_ext_register(npf, "log", &npf_log_ops); 165 return npf_ext_log_id ? 0 : EEXIST; 166} 167 168__dso_public int 169npf_ext_log_fini(npf_t *npf) 170{ 171 return npf_ext_unregister(npf, npf_ext_log_id); 172} 173 174#ifdef _KERNEL 175static int 176npf_ext_log_modcmd(modcmd_t cmd, void *arg) 177{ 178 npf_t *npf = npf_getkernctx(); 179 180 switch (cmd) { 181 case MODULE_CMD_INIT: 182 return npf_ext_log_init(npf); 183 case MODULE_CMD_FINI: 184 return npf_ext_log_fini(npf); 185 break; 186 case MODULE_CMD_AUTOUNLOAD: 187 return npf_autounload_p() ? 0 : EBUSY; 188 default: 189 return ENOTTY; 190 } 191 return 0; 192} 193#endif 194