1 /* $NetBSD: npf_os.c,v 1.6 2017/01/27 17:25:34 ryo Exp $ */ 2 3 /*- 4 * Copyright (c) 2009-2016 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 #ifdef _KERNEL 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.6 2017/01/27 17:25:34 ryo Exp $"); 39 40 #ifdef _KERNEL_OPT 41 #include "pf.h" 42 #if NPF > 0 43 #error "NPF and PF are mutually exclusive; please select one" 44 #endif 45 #endif 46 47 #include <sys/param.h> 48 #include <sys/types.h> 49 50 #include <sys/conf.h> 51 #include <sys/kauth.h> 52 #include <sys/kmem.h> 53 #include <sys/lwp.h> 54 #include <sys/module.h> 55 #include <sys/socketvar.h> 56 #include <sys/uio.h> 57 58 #include <netinet/in.h> 59 #include <netinet6/in6_var.h> 60 #endif 61 62 #include "npf_impl.h" 63 #include "npfkern.h" 64 65 #ifdef _KERNEL 66 #ifndef _MODULE 67 #include "opt_modular.h" 68 #include "opt_net_mpsafe.h" 69 #endif 70 #include "ioconf.h" 71 #endif 72 73 /* 74 * Module and device structures. 75 */ 76 #ifndef _MODULE 77 /* 78 * Modular kernels load drivers too early, and we need percpu to be inited 79 * So we make this misc; a better way would be to have early boot and late 80 * boot drivers. 81 */ 82 MODULE(MODULE_CLASS_MISC, npf, NULL); 83 #else 84 /* This module autoloads via /dev/npf so it needs to be a driver */ 85 MODULE(MODULE_CLASS_DRIVER, npf, NULL); 86 #endif 87 88 static int npf_dev_open(dev_t, int, int, lwp_t *); 89 static int npf_dev_close(dev_t, int, int, lwp_t *); 90 static int npf_dev_ioctl(dev_t, u_long, void *, int, lwp_t *); 91 static int npf_dev_poll(dev_t, int, lwp_t *); 92 static int npf_dev_read(dev_t, struct uio *, int); 93 94 const struct cdevsw npf_cdevsw = { 95 .d_open = npf_dev_open, 96 .d_close = npf_dev_close, 97 .d_read = npf_dev_read, 98 .d_write = nowrite, 99 .d_ioctl = npf_dev_ioctl, 100 .d_stop = nostop, 101 .d_tty = notty, 102 .d_poll = npf_dev_poll, 103 .d_mmap = nommap, 104 .d_kqfilter = nokqfilter, 105 .d_discard = nodiscard, 106 .d_flag = D_OTHER | D_MPSAFE 107 }; 108 109 static const char * npf_ifop_getname(ifnet_t *); 110 static ifnet_t * npf_ifop_lookup(const char *); 111 static void npf_ifop_flush(void *); 112 static void * npf_ifop_getmeta(const ifnet_t *); 113 static void npf_ifop_setmeta(ifnet_t *, void *); 114 115 static const unsigned nworkers = 1; 116 117 static bool pfil_registered = false; 118 static pfil_head_t * npf_ph_if = NULL; 119 static pfil_head_t * npf_ph_inet = NULL; 120 static pfil_head_t * npf_ph_inet6 = NULL; 121 122 static const npf_ifops_t kern_ifops = { 123 .getname = npf_ifop_getname, 124 .lookup = npf_ifop_lookup, 125 .flush = npf_ifop_flush, 126 .getmeta = npf_ifop_getmeta, 127 .setmeta = npf_ifop_setmeta, 128 }; 129 130 static int 131 npf_fini(void) 132 { 133 npf_t *npf = npf_getkernctx(); 134 135 /* At first, detach device and remove pfil hooks. */ 136 #ifdef _MODULE 137 devsw_detach(NULL, &npf_cdevsw); 138 #endif 139 npf_pfil_unregister(true); 140 npf_destroy(npf); 141 npf_sysfini(); 142 return 0; 143 } 144 145 static int 146 npf_init(void) 147 { 148 npf_t *npf; 149 int error = 0; 150 151 error = npf_sysinit(nworkers); 152 if (error) 153 return error; 154 npf = npf_create(0, NULL, &kern_ifops); 155 npf_setkernctx(npf); 156 npf_pfil_register(true); 157 158 #ifdef _MODULE 159 devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; 160 161 /* Attach /dev/npf device. */ 162 error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor); 163 if (error) { 164 /* It will call devsw_detach(), which is safe. */ 165 (void)npf_fini(); 166 } 167 #endif 168 return error; 169 } 170 171 172 /* 173 * Module interface. 174 */ 175 static int 176 npf_modcmd(modcmd_t cmd, void *arg) 177 { 178 switch (cmd) { 179 case MODULE_CMD_INIT: 180 return npf_init(); 181 case MODULE_CMD_FINI: 182 return npf_fini(); 183 case MODULE_CMD_AUTOUNLOAD: 184 if (npf_autounload_p()) { 185 return EBUSY; 186 } 187 break; 188 default: 189 return ENOTTY; 190 } 191 return 0; 192 } 193 194 void 195 npfattach(int nunits) 196 { 197 /* Nothing */ 198 } 199 200 static int 201 npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l) 202 { 203 /* Available only for super-user. */ 204 if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 205 KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 206 return EPERM; 207 } 208 return 0; 209 } 210 211 static int 212 npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l) 213 { 214 return 0; 215 } 216 217 static int 218 npf_stats_export(npf_t *npf, void *data) 219 { 220 uint64_t *fullst, *uptr = *(uint64_t **)data; 221 int error; 222 223 fullst = kmem_alloc(NPF_STATS_SIZE, KM_SLEEP); 224 npf_stats(npf, fullst); /* will zero the buffer */ 225 error = copyout(fullst, uptr, NPF_STATS_SIZE); 226 kmem_free(fullst, NPF_STATS_SIZE); 227 return error; 228 } 229 230 static int 231 npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 232 { 233 npf_t *npf = npf_getkernctx(); 234 int error; 235 236 /* Available only for super-user. */ 237 if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 238 KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 239 return EPERM; 240 } 241 242 switch (cmd) { 243 case IOC_NPF_TABLE: 244 error = npfctl_table(npf, data); 245 break; 246 case IOC_NPF_RULE: 247 error = npfctl_rule(npf, cmd, data); 248 break; 249 case IOC_NPF_STATS: 250 error = npf_stats_export(npf, data); 251 break; 252 case IOC_NPF_SAVE: 253 error = npfctl_save(npf, cmd, data); 254 break; 255 case IOC_NPF_SWITCH: 256 error = npfctl_switch(data); 257 break; 258 case IOC_NPF_LOAD: 259 error = npfctl_load(npf, cmd, data); 260 break; 261 case IOC_NPF_CONN_LOOKUP: 262 error = npfctl_conn_lookup(npf, cmd, data); 263 break; 264 case IOC_NPF_VERSION: 265 *(int *)data = NPF_VERSION; 266 error = 0; 267 break; 268 default: 269 error = ENOTTY; 270 break; 271 } 272 return error; 273 } 274 275 static int 276 npf_dev_poll(dev_t dev, int events, lwp_t *l) 277 { 278 return ENOTSUP; 279 } 280 281 static int 282 npf_dev_read(dev_t dev, struct uio *uio, int flag) 283 { 284 return ENOTSUP; 285 } 286 287 bool 288 npf_autounload_p(void) 289 { 290 npf_t *npf = npf_getkernctx(); 291 return !npf_pfil_registered_p() && npf_default_pass(npf); 292 } 293 294 /* 295 * Interface operations. 296 */ 297 298 static const char * 299 npf_ifop_getname(ifnet_t *ifp) 300 { 301 return ifp->if_xname; 302 } 303 304 static ifnet_t * 305 npf_ifop_lookup(const char *name) 306 { 307 return ifunit(name); 308 } 309 310 static void 311 npf_ifop_flush(void *arg) 312 { 313 ifnet_t *ifp; 314 315 KERNEL_LOCK(1, NULL); 316 IFNET_LOCK(); 317 IFNET_WRITER_FOREACH(ifp) { 318 ifp->if_pf_kif = arg; 319 } 320 IFNET_UNLOCK(); 321 KERNEL_UNLOCK_ONE(NULL); 322 } 323 324 static void * 325 npf_ifop_getmeta(const ifnet_t *ifp) 326 { 327 return ifp->if_pf_kif; 328 } 329 330 static void 331 npf_ifop_setmeta(ifnet_t *ifp, void *arg) 332 { 333 ifp->if_pf_kif = arg; 334 } 335 336 #ifdef _KERNEL 337 338 /* 339 * Wrapper of the main packet handler to pass the kernel NPF context. 340 */ 341 static int 342 npfkern_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di) 343 { 344 npf_t *npf = npf_getkernctx(); 345 return npf_packet_handler(npf, mp, ifp, di); 346 } 347 348 /* 349 * npf_ifhook: hook handling interface changes. 350 */ 351 static void 352 npf_ifhook(void *arg, unsigned long cmd, void *arg2) 353 { 354 npf_t *npf = npf_getkernctx(); 355 ifnet_t *ifp = arg2; 356 357 switch (cmd) { 358 case PFIL_IFNET_ATTACH: 359 npf_ifmap_attach(npf, ifp); 360 npf_ifaddr_sync(npf, ifp); 361 break; 362 case PFIL_IFNET_DETACH: 363 npf_ifmap_detach(npf, ifp); 364 npf_ifaddr_flush(npf, ifp); 365 break; 366 } 367 } 368 369 static void 370 npf_ifaddrhook(void *arg, u_long cmd, void *arg2) 371 { 372 npf_t *npf = npf_getkernctx(); 373 struct ifaddr *ifa = arg2; 374 375 switch (cmd) { 376 case SIOCSIFADDR: 377 case SIOCAIFADDR: 378 case SIOCDIFADDR: 379 #ifdef INET6 380 case SIOCSIFADDR_IN6: 381 case SIOCAIFADDR_IN6: 382 case SIOCDIFADDR_IN6: 383 #endif 384 break; 385 default: 386 return; 387 } 388 npf_ifaddr_sync(npf, ifa->ifa_ifp); 389 } 390 391 /* 392 * npf_pfil_register: register pfil(9) hooks. 393 */ 394 int 395 npf_pfil_register(bool init) 396 { 397 npf_t *npf = npf_getkernctx(); 398 int error = 0; 399 400 #ifndef NET_MPSAFE 401 mutex_enter(softnet_lock); 402 KERNEL_LOCK(1, NULL); 403 #endif 404 405 /* Init: interface re-config and attach/detach hook. */ 406 if (!npf_ph_if) { 407 npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0); 408 if (!npf_ph_if) { 409 error = ENOENT; 410 goto out; 411 } 412 413 error = pfil_add_ihook(npf_ifhook, NULL, 414 PFIL_IFNET, npf_ph_if); 415 KASSERT(error == 0); 416 417 error = pfil_add_ihook(npf_ifaddrhook, NULL, 418 PFIL_IFADDR, npf_ph_if); 419 KASSERT(error == 0); 420 } 421 if (init) { 422 goto out; 423 } 424 425 /* Check if pfil hooks are not already registered. */ 426 if (pfil_registered) { 427 error = EEXIST; 428 goto out; 429 } 430 431 /* Capture points of the activity in the IP layer. */ 432 npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET); 433 npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6); 434 if (!npf_ph_inet && !npf_ph_inet6) { 435 error = ENOENT; 436 goto out; 437 } 438 439 /* Packet IN/OUT handlers for IP layer. */ 440 if (npf_ph_inet) { 441 error = pfil_add_hook(npfkern_packet_handler, npf, 442 PFIL_ALL, npf_ph_inet); 443 KASSERT(error == 0); 444 } 445 if (npf_ph_inet6) { 446 error = pfil_add_hook(npfkern_packet_handler, npf, 447 PFIL_ALL, npf_ph_inet6); 448 KASSERT(error == 0); 449 } 450 451 /* 452 * It is necessary to re-sync all/any interface address tables, 453 * since we did not listen for any changes. 454 */ 455 npf_ifaddr_syncall(npf); 456 pfil_registered = true; 457 out: 458 #ifndef NET_MPSAFE 459 KERNEL_UNLOCK_ONE(NULL); 460 mutex_exit(softnet_lock); 461 #endif 462 463 return error; 464 } 465 466 /* 467 * npf_pfil_unregister: unregister pfil(9) hooks. 468 */ 469 void 470 npf_pfil_unregister(bool fini) 471 { 472 npf_t *npf = npf_getkernctx(); 473 474 #ifndef NET_MPSAFE 475 mutex_enter(softnet_lock); 476 KERNEL_LOCK(1, NULL); 477 #endif 478 479 if (fini && npf_ph_if) { 480 (void)pfil_remove_ihook(npf_ifhook, NULL, 481 PFIL_IFNET, npf_ph_if); 482 (void)pfil_remove_ihook(npf_ifaddrhook, NULL, 483 PFIL_IFADDR, npf_ph_if); 484 } 485 if (npf_ph_inet) { 486 (void)pfil_remove_hook(npfkern_packet_handler, npf, 487 PFIL_ALL, npf_ph_inet); 488 } 489 if (npf_ph_inet6) { 490 (void)pfil_remove_hook(npfkern_packet_handler, npf, 491 PFIL_ALL, npf_ph_inet6); 492 } 493 pfil_registered = false; 494 495 #ifndef NET_MPSAFE 496 KERNEL_UNLOCK_ONE(NULL); 497 mutex_exit(softnet_lock); 498 #endif 499 } 500 501 bool 502 npf_pfil_registered_p(void) 503 { 504 return pfil_registered; 505 } 506 #endif 507