1 /* $NetBSD: npf.c,v 1.31 2015/10/29 15:19:43 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2009-2013 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This material is based upon work partially supported by The 8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * NPF main: dynamic load/initialisation and unload routines. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.31 2015/10/29 15:19:43 christos Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/types.h> 41 42 #include <sys/atomic.h> 43 #include <sys/conf.h> 44 #include <sys/kauth.h> 45 #include <sys/kmem.h> 46 #include <sys/lwp.h> 47 #include <sys/module.h> 48 #include <sys/percpu.h> 49 #include <sys/rwlock.h> 50 #include <sys/socketvar.h> 51 #include <sys/sysctl.h> 52 #include <sys/uio.h> 53 54 #include "npf_impl.h" 55 #include "npf_conn.h" 56 57 #ifndef _MODULE 58 #include "opt_modular.h" 59 #endif 60 61 #include "ioconf.h" 62 63 /* 64 * Module and device structures. 65 */ 66 #ifndef _MODULE 67 /* 68 * Modular kernels load drivers too early, and we need percpu to be inited 69 * So we make this misc; a better way would be to have early boot and late 70 * boot drivers. 71 */ 72 MODULE(MODULE_CLASS_MISC, npf, NULL); 73 #else 74 /* This module autoloads via /dev/npf so it needs to be a driver */ 75 MODULE(MODULE_CLASS_DRIVER, npf, NULL); 76 #endif 77 78 static int npf_fini(void); 79 static int npf_dev_open(dev_t, int, int, lwp_t *); 80 static int npf_dev_close(dev_t, int, int, lwp_t *); 81 static int npf_dev_ioctl(dev_t, u_long, void *, int, lwp_t *); 82 static int npf_dev_poll(dev_t, int, lwp_t *); 83 static int npf_dev_read(dev_t, struct uio *, int); 84 85 static int npfctl_stats(void *); 86 87 static percpu_t * npf_stats_percpu __read_mostly; 88 static struct sysctllog * npf_sysctl __read_mostly; 89 90 const struct cdevsw npf_cdevsw = { 91 .d_open = npf_dev_open, 92 .d_close = npf_dev_close, 93 .d_read = npf_dev_read, 94 .d_write = nowrite, 95 .d_ioctl = npf_dev_ioctl, 96 .d_stop = nostop, 97 .d_tty = notty, 98 .d_poll = npf_dev_poll, 99 .d_mmap = nommap, 100 .d_kqfilter = nokqfilter, 101 .d_discard = nodiscard, 102 .d_flag = D_OTHER | D_MPSAFE 103 }; 104 105 static int 106 npf_init(void) 107 { 108 KASSERT(npf_stats_percpu == NULL); 109 110 npf_stats_percpu = percpu_alloc(NPF_STATS_SIZE); 111 npf_sysctl = NULL; 112 113 npf_bpf_sysinit(); 114 npf_worker_sysinit(); 115 npf_tableset_sysinit(); 116 npf_conn_sysinit(); 117 npf_nat_sysinit(); 118 npf_alg_sysinit(); 119 npf_ext_sysinit(); 120 121 /* Load empty configuration. */ 122 npf_pfil_register(true); 123 npf_config_init(); 124 125 #ifdef _MODULE 126 devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; 127 128 /* Attach /dev/npf device. */ 129 int error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor); 130 if (error) { 131 /* It will call devsw_detach(), which is safe. */ 132 (void)npf_fini(); 133 } 134 return error; 135 #else 136 return 0; 137 #endif 138 } 139 140 static int 141 npf_fini(void) 142 { 143 /* At first, detach device and remove pfil hooks. */ 144 #ifdef _MODULE 145 devsw_detach(NULL, &npf_cdevsw); 146 #endif 147 npf_pfil_unregister(true); 148 npf_config_fini(); 149 150 /* Finally, safe to destroy the subsystems. */ 151 npf_ext_sysfini(); 152 npf_alg_sysfini(); 153 npf_nat_sysfini(); 154 npf_conn_sysfini(); 155 npf_tableset_sysfini(); 156 npf_bpf_sysfini(); 157 158 /* Note: worker is the last. */ 159 npf_worker_sysfini(); 160 161 if (npf_sysctl) { 162 sysctl_teardown(&npf_sysctl); 163 } 164 percpu_free(npf_stats_percpu, NPF_STATS_SIZE); 165 166 return 0; 167 } 168 169 /* 170 * Module interface. 171 */ 172 static int 173 npf_modcmd(modcmd_t cmd, void *arg) 174 { 175 176 switch (cmd) { 177 case MODULE_CMD_INIT: 178 return npf_init(); 179 case MODULE_CMD_FINI: 180 return npf_fini(); 181 case MODULE_CMD_AUTOUNLOAD: 182 if (npf_autounload_p()) { 183 return EBUSY; 184 } 185 break; 186 default: 187 return ENOTTY; 188 } 189 return 0; 190 } 191 192 void 193 npfattach(int nunits) 194 { 195 /* Nothing */ 196 } 197 198 static int 199 npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l) 200 { 201 202 /* Available only for super-user. */ 203 if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 204 KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 205 return EPERM; 206 } 207 return 0; 208 } 209 210 static int 211 npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l) 212 { 213 214 return 0; 215 } 216 217 static int 218 npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 219 { 220 int error; 221 222 /* Available only for super-user. */ 223 if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 224 KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 225 return EPERM; 226 } 227 228 switch (cmd) { 229 case IOC_NPF_TABLE: 230 error = npfctl_table(data); 231 break; 232 case IOC_NPF_RULE: 233 error = npfctl_rule(cmd, data); 234 break; 235 case IOC_NPF_STATS: 236 error = npfctl_stats(data); 237 break; 238 case IOC_NPF_SAVE: 239 error = npfctl_save(cmd, data); 240 break; 241 case IOC_NPF_SWITCH: 242 error = npfctl_switch(data); 243 break; 244 case IOC_NPF_LOAD: 245 error = npfctl_load(cmd, data); 246 break; 247 case IOC_NPF_VERSION: 248 *(int *)data = NPF_VERSION; 249 error = 0; 250 break; 251 default: 252 error = ENOTTY; 253 break; 254 } 255 return error; 256 } 257 258 static int 259 npf_dev_poll(dev_t dev, int events, lwp_t *l) 260 { 261 262 return ENOTSUP; 263 } 264 265 static int 266 npf_dev_read(dev_t dev, struct uio *uio, int flag) 267 { 268 269 return ENOTSUP; 270 } 271 272 bool 273 npf_autounload_p(void) 274 { 275 return !npf_pfil_registered_p() && npf_default_pass(); 276 } 277 278 /* 279 * NPF statistics interface. 280 */ 281 282 void 283 npf_stats_inc(npf_stats_t st) 284 { 285 uint64_t *stats = percpu_getref(npf_stats_percpu); 286 stats[st]++; 287 percpu_putref(npf_stats_percpu); 288 } 289 290 void 291 npf_stats_dec(npf_stats_t st) 292 { 293 uint64_t *stats = percpu_getref(npf_stats_percpu); 294 stats[st]--; 295 percpu_putref(npf_stats_percpu); 296 } 297 298 static void 299 npf_stats_collect(void *mem, void *arg, struct cpu_info *ci) 300 { 301 uint64_t *percpu_stats = mem, *full_stats = arg; 302 int i; 303 304 for (i = 0; i < NPF_STATS_COUNT; i++) { 305 full_stats[i] += percpu_stats[i]; 306 } 307 } 308 309 /* 310 * npfctl_stats: export collected statistics. 311 */ 312 static int 313 npfctl_stats(void *data) 314 { 315 uint64_t *fullst, *uptr = *(uint64_t **)data; 316 int error; 317 318 fullst = kmem_zalloc(NPF_STATS_SIZE, KM_SLEEP); 319 percpu_foreach(npf_stats_percpu, npf_stats_collect, fullst); 320 error = copyout(fullst, uptr, NPF_STATS_SIZE); 321 kmem_free(fullst, NPF_STATS_SIZE); 322 return error; 323 } 324