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