1 /* $NetBSD: npf.c,v 1.22 2014/07/25 08:10:40 dholland 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.22 2014/07/25 08:10:40 dholland 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 /* 58 * Module and device structures. 59 */ 60 MODULE(MODULE_CLASS_DRIVER, npf, NULL); 61 62 void npfattach(int); 63 64 static int npf_fini(void); 65 static int npf_dev_open(dev_t, int, int, lwp_t *); 66 static int npf_dev_close(dev_t, int, int, lwp_t *); 67 static int npf_dev_ioctl(dev_t, u_long, void *, int, lwp_t *); 68 static int npf_dev_poll(dev_t, int, lwp_t *); 69 static int npf_dev_read(dev_t, struct uio *, int); 70 71 static int npfctl_stats(void *); 72 73 static percpu_t * npf_stats_percpu __read_mostly; 74 static struct sysctllog * npf_sysctl __read_mostly; 75 76 const struct cdevsw npf_cdevsw = { 77 .d_open = npf_dev_open, 78 .d_close = npf_dev_close, 79 .d_read = npf_dev_read, 80 .d_write = nowrite, 81 .d_ioctl = npf_dev_ioctl, 82 .d_stop = nostop, 83 .d_tty = notty, 84 .d_poll = npf_dev_poll, 85 .d_mmap = nommap, 86 .d_kqfilter = nokqfilter, 87 .d_discard = nodiscard, 88 .d_flag = D_OTHER | D_MPSAFE 89 }; 90 91 static int 92 npf_init(void) 93 { 94 #ifdef _MODULE 95 devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; 96 #endif 97 int error = 0; 98 99 npf_stats_percpu = percpu_alloc(NPF_STATS_SIZE); 100 npf_sysctl = NULL; 101 102 npf_bpf_sysinit(); 103 npf_worker_sysinit(); 104 npf_tableset_sysinit(); 105 npf_conn_sysinit(); 106 npf_nat_sysinit(); 107 npf_alg_sysinit(); 108 npf_ext_sysinit(); 109 110 /* Load empty configuration. */ 111 npf_pfil_register(true); 112 npf_config_init(); 113 114 #ifdef _MODULE 115 /* Attach /dev/npf device. */ 116 error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor); 117 if (error) { 118 /* It will call devsw_detach(), which is safe. */ 119 (void)npf_fini(); 120 } 121 #endif 122 return error; 123 } 124 125 static int 126 npf_fini(void) 127 { 128 /* At first, detach device and remove pfil hooks. */ 129 #ifdef _MODULE 130 devsw_detach(NULL, &npf_cdevsw); 131 #endif 132 npf_pfil_unregister(true); 133 npf_config_fini(); 134 135 /* Finally, safe to destroy the subsystems. */ 136 npf_ext_sysfini(); 137 npf_alg_sysfini(); 138 npf_nat_sysfini(); 139 npf_conn_sysfini(); 140 npf_tableset_sysfini(); 141 npf_bpf_sysfini(); 142 143 /* Note: worker is the last. */ 144 npf_worker_sysfini(); 145 146 if (npf_sysctl) { 147 sysctl_teardown(&npf_sysctl); 148 } 149 percpu_free(npf_stats_percpu, NPF_STATS_SIZE); 150 151 return 0; 152 } 153 154 /* 155 * Module interface. 156 */ 157 static int 158 npf_modcmd(modcmd_t cmd, void *arg) 159 { 160 161 switch (cmd) { 162 case MODULE_CMD_INIT: 163 return npf_init(); 164 case MODULE_CMD_FINI: 165 return npf_fini(); 166 case MODULE_CMD_AUTOUNLOAD: 167 if (npf_autounload_p()) { 168 return EBUSY; 169 } 170 break; 171 default: 172 return ENOTTY; 173 } 174 return 0; 175 } 176 177 void 178 npfattach(int nunits) 179 { 180 181 /* Void. */ 182 } 183 184 static int 185 npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l) 186 { 187 188 /* Available only for super-user. */ 189 if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 190 KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 191 return EPERM; 192 } 193 return 0; 194 } 195 196 static int 197 npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l) 198 { 199 200 return 0; 201 } 202 203 static int 204 npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 205 { 206 int error; 207 208 /* Available only for super-user. */ 209 if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 210 KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 211 return EPERM; 212 } 213 214 switch (cmd) { 215 case IOC_NPF_TABLE: 216 error = npfctl_table(data); 217 break; 218 case IOC_NPF_RULE: 219 error = npfctl_rule(cmd, data); 220 break; 221 case IOC_NPF_STATS: 222 error = npfctl_stats(data); 223 break; 224 case IOC_NPF_SAVE: 225 error = npfctl_save(cmd, data); 226 break; 227 case IOC_NPF_SWITCH: 228 error = npfctl_switch(data); 229 break; 230 case IOC_NPF_LOAD: 231 error = npfctl_load(cmd, data); 232 break; 233 case IOC_NPF_VERSION: 234 *(int *)data = NPF_VERSION; 235 error = 0; 236 break; 237 default: 238 error = ENOTTY; 239 break; 240 } 241 return error; 242 } 243 244 static int 245 npf_dev_poll(dev_t dev, int events, lwp_t *l) 246 { 247 248 return ENOTSUP; 249 } 250 251 static int 252 npf_dev_read(dev_t dev, struct uio *uio, int flag) 253 { 254 255 return ENOTSUP; 256 } 257 258 bool 259 npf_autounload_p(void) 260 { 261 return !npf_pfil_registered_p() && npf_default_pass(); 262 } 263 264 /* 265 * NPF statistics interface. 266 */ 267 268 void 269 npf_stats_inc(npf_stats_t st) 270 { 271 uint64_t *stats = percpu_getref(npf_stats_percpu); 272 stats[st]++; 273 percpu_putref(npf_stats_percpu); 274 } 275 276 void 277 npf_stats_dec(npf_stats_t st) 278 { 279 uint64_t *stats = percpu_getref(npf_stats_percpu); 280 stats[st]--; 281 percpu_putref(npf_stats_percpu); 282 } 283 284 static void 285 npf_stats_collect(void *mem, void *arg, struct cpu_info *ci) 286 { 287 uint64_t *percpu_stats = mem, *full_stats = arg; 288 int i; 289 290 for (i = 0; i < NPF_STATS_COUNT; i++) { 291 full_stats[i] += percpu_stats[i]; 292 } 293 } 294 295 /* 296 * npfctl_stats: export collected statistics. 297 */ 298 static int 299 npfctl_stats(void *data) 300 { 301 uint64_t *fullst, *uptr = *(uint64_t **)data; 302 int error; 303 304 fullst = kmem_zalloc(NPF_STATS_SIZE, KM_SLEEP); 305 percpu_foreach(npf_stats_percpu, npf_stats_collect, fullst); 306 error = copyout(fullst, uptr, NPF_STATS_SIZE); 307 kmem_free(fullst, NPF_STATS_SIZE); 308 return error; 309 } 310