pf_ioctl.c revision 187688
1/* $OpenBSD: pf_ioctl.c,v 1.175 2007/02/26 22:47:43 deraadt Exp $ */ 2 3/* 4 * Copyright (c) 2001 Daniel Hartmeier 5 * Copyright (c) 2002,2003 Henning Brauer 6 * All rights reserved. 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 * 12 * - Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * - Redistributions in binary form must reproduce the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer in the documentation and/or other materials provided 17 * with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 * 32 * Effort sponsored in part by the Defense Advanced Research Projects 33 * Agency (DARPA) and Air Force Research Laboratory, Air Force 34 * Materiel Command, USAF, under agreement number F30602-01-2-0537. 35 * 36 */ 37 38#ifdef __FreeBSD__ 39#include "opt_inet.h" 40#include "opt_inet6.h" 41 42#include <sys/cdefs.h> 43__FBSDID("$FreeBSD: head/sys/contrib/pf/net/pf_ioctl.c 187688 2009-01-25 14:39:15Z ed $"); 44#endif 45 46#ifdef __FreeBSD__ 47#include "opt_bpf.h" 48#include "opt_pf.h" 49 50#ifdef DEV_BPF 51#define NBPFILTER DEV_BPF 52#else 53#define NBPFILTER 0 54#endif 55 56#ifdef DEV_PFLOG 57#define NPFLOG DEV_PFLOG 58#else 59#define NPFLOG 0 60#endif 61 62#ifdef DEV_PFSYNC 63#define NPFSYNC DEV_PFSYNC 64#else 65#define NPFSYNC 0 66#endif 67 68#else 69#include "bpfilter.h" 70#include "pflog.h" 71#include "pfsync.h" 72#endif 73 74#include <sys/param.h> 75#include <sys/systm.h> 76#include <sys/mbuf.h> 77#include <sys/filio.h> 78#include <sys/fcntl.h> 79#include <sys/socket.h> 80#include <sys/socketvar.h> 81#include <sys/kernel.h> 82#include <sys/time.h> 83#include <sys/malloc.h> 84#ifdef __FreeBSD__ 85#include <sys/module.h> 86#include <sys/conf.h> 87#include <sys/proc.h> 88#include <sys/sysctl.h> 89#include <sys/vimage.h> 90#else 91#include <sys/timeout.h> 92#include <sys/pool.h> 93#endif 94#include <sys/proc.h> 95#include <sys/malloc.h> 96#include <sys/kthread.h> 97#ifndef __FreeBSD__ 98#include <sys/rwlock.h> 99#include <uvm/uvm_extern.h> 100#endif 101 102#include <net/if.h> 103#include <net/if_types.h> 104#include <net/route.h> 105#ifdef __FreeBSD__ 106#include <net/vnet.h> 107#endif 108 109#include <netinet/in.h> 110#include <netinet/in_var.h> 111#include <netinet/in_systm.h> 112#include <netinet/ip.h> 113#include <netinet/ip_var.h> 114#include <netinet/ip_icmp.h> 115 116#ifdef __FreeBSD__ 117#include <sys/md5.h> 118#else 119#include <dev/rndvar.h> 120#include <crypto/md5.h> 121#endif 122#include <net/pfvar.h> 123 124#if NPFSYNC > 0 125#include <net/if_pfsync.h> 126#endif /* NPFSYNC > 0 */ 127 128#include <net/if_pflog.h> 129 130#ifdef INET6 131#include <netinet/ip6.h> 132#include <netinet/in_pcb.h> 133#endif /* INET6 */ 134 135#ifdef ALTQ 136#include <altq/altq.h> 137#endif 138 139#ifdef __FreeBSD__ 140#include <sys/limits.h> 141#include <sys/lock.h> 142#include <sys/mutex.h> 143#include <net/pfil.h> 144#endif /* __FreeBSD__ */ 145 146#ifdef __FreeBSD__ 147void init_zone_var(void); 148void cleanup_pf_zone(void); 149int pfattach(void); 150#else 151void pfattach(int); 152void pf_thread_create(void *); 153int pfopen(dev_t, int, int, struct proc *); 154int pfclose(dev_t, int, int, struct proc *); 155#endif 156struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t, 157 u_int8_t, u_int8_t, u_int8_t); 158 159void pf_mv_pool(struct pf_palist *, struct pf_palist *); 160void pf_empty_pool(struct pf_palist *); 161#ifdef __FreeBSD__ 162int pfioctl(struct cdev *, u_long, caddr_t, int, struct thread *); 163#else 164int pfioctl(struct cdev *, u_long, caddr_t, int, struct proc *); 165#endif 166#ifdef ALTQ 167int pf_begin_altq(u_int32_t *); 168int pf_rollback_altq(u_int32_t); 169int pf_commit_altq(u_int32_t); 170int pf_enable_altq(struct pf_altq *); 171int pf_disable_altq(struct pf_altq *); 172#endif /* ALTQ */ 173int pf_begin_rules(u_int32_t *, int, const char *); 174int pf_rollback_rules(u_int32_t, int, char *); 175int pf_setup_pfsync_matching(struct pf_ruleset *); 176void pf_hash_rule(MD5_CTX *, struct pf_rule *); 177void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *); 178int pf_commit_rules(u_int32_t, int, char *); 179 180struct pf_rule pf_default_rule; 181#ifdef __FreeBSD__ 182struct sx pf_consistency_lock; 183SX_SYSINIT(pf_consistency_lock, &pf_consistency_lock, "pf_statetbl_lock"); 184#else 185struct rwlock pf_consistency_lock = RWLOCK_INITIALIZER; 186#endif 187#ifdef ALTQ 188static int pf_altq_running; 189#endif 190 191#define TAGID_MAX 50000 192TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags), 193 pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids); 194 195#if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE) 196#error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE 197#endif 198u_int16_t tagname2tag(struct pf_tags *, char *); 199void tag2tagname(struct pf_tags *, u_int16_t, char *); 200void tag_unref(struct pf_tags *, u_int16_t); 201int pf_rtlabel_add(struct pf_addr_wrap *); 202void pf_rtlabel_remove(struct pf_addr_wrap *); 203void pf_rtlabel_copyout(struct pf_addr_wrap *); 204 205#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x 206 207 208#ifdef __FreeBSD__ 209static struct cdev *pf_dev; 210 211/* 212 * XXX - These are new and need to be checked when moveing to a new version 213 */ 214static void pf_clear_states(void); 215static int pf_clear_tables(void); 216static void pf_clear_srcnodes(void); 217/* 218 * XXX - These are new and need to be checked when moveing to a new version 219 */ 220 221/* 222 * Wrapper functions for pfil(9) hooks 223 */ 224static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, 225 int dir, struct inpcb *inp); 226static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, 227 int dir, struct inpcb *inp); 228#ifdef INET6 229static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, 230 int dir, struct inpcb *inp); 231static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, 232 int dir, struct inpcb *inp); 233#endif 234 235static int hook_pf(void); 236static int dehook_pf(void); 237static int shutdown_pf(void); 238static int pf_load(void); 239static int pf_unload(void); 240 241static struct cdevsw pf_cdevsw = { 242 .d_ioctl = pfioctl, 243 .d_name = PF_NAME, 244 .d_version = D_VERSION, 245}; 246 247static volatile int pf_pfil_hooked = 0; 248int pf_end_threads = 0; 249struct mtx pf_task_mtx; 250pflog_packet_t *pflog_packet_ptr = NULL; 251 252int debug_pfugidhack = 0; 253SYSCTL_INT(_debug, OID_AUTO, pfugidhack, CTLFLAG_RW, &debug_pfugidhack, 0, 254 "Enable/disable pf user/group rules mpsafe hack"); 255 256void 257init_pf_mutex(void) 258{ 259 mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF); 260} 261 262void 263destroy_pf_mutex(void) 264{ 265 mtx_destroy(&pf_task_mtx); 266} 267 268void 269init_zone_var(void) 270{ 271 pf_src_tree_pl = pf_rule_pl = NULL; 272 pf_state_pl = pf_altq_pl = pf_pooladdr_pl = NULL; 273 pf_frent_pl = pf_frag_pl = pf_cache_pl = pf_cent_pl = NULL; 274 pf_state_scrub_pl = NULL; 275 pfr_ktable_pl = pfr_kentry_pl = NULL; 276} 277 278void 279cleanup_pf_zone(void) 280{ 281 UMA_DESTROY(pf_src_tree_pl); 282 UMA_DESTROY(pf_rule_pl); 283 UMA_DESTROY(pf_state_pl); 284 UMA_DESTROY(pf_altq_pl); 285 UMA_DESTROY(pf_pooladdr_pl); 286 UMA_DESTROY(pf_frent_pl); 287 UMA_DESTROY(pf_frag_pl); 288 UMA_DESTROY(pf_cache_pl); 289 UMA_DESTROY(pf_cent_pl); 290 UMA_DESTROY(pfr_ktable_pl); 291 UMA_DESTROY(pfr_kentry_pl2); 292 UMA_DESTROY(pfr_kentry_pl); 293 UMA_DESTROY(pf_state_scrub_pl); 294 UMA_DESTROY(pfi_addr_pl); 295} 296 297int 298pfattach(void) 299{ 300 u_int32_t *my_timeout = pf_default_rule.timeout; 301 int error = 1; 302 303 do { 304 UMA_CREATE(pf_src_tree_pl,struct pf_src_node, "pfsrctrpl"); 305 UMA_CREATE(pf_rule_pl, struct pf_rule, "pfrulepl"); 306 UMA_CREATE(pf_state_pl, struct pf_state, "pfstatepl"); 307 UMA_CREATE(pf_altq_pl, struct pf_altq, "pfaltqpl"); 308 UMA_CREATE(pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl"); 309 UMA_CREATE(pfr_ktable_pl, struct pfr_ktable, "pfrktable"); 310 UMA_CREATE(pfr_kentry_pl, struct pfr_kentry, "pfrkentry"); 311 UMA_CREATE(pfr_kentry_pl2, struct pfr_kentry, "pfrkentry2"); 312 UMA_CREATE(pf_frent_pl, struct pf_frent, "pffrent"); 313 UMA_CREATE(pf_frag_pl, struct pf_fragment, "pffrag"); 314 UMA_CREATE(pf_cache_pl, struct pf_fragment, "pffrcache"); 315 UMA_CREATE(pf_cent_pl, struct pf_frcache, "pffrcent"); 316 UMA_CREATE(pf_state_scrub_pl, struct pf_state_scrub, 317 "pfstatescrub"); 318 UMA_CREATE(pfi_addr_pl, struct pfi_dynaddr, "pfiaddrpl"); 319 error = 0; 320 } while(0); 321 if (error) { 322 cleanup_pf_zone(); 323 return (error); 324 } 325 pfr_initialize(); 326 pfi_initialize(); 327 if ( (error = pf_osfp_initialize()) ) { 328 cleanup_pf_zone(); 329 pf_osfp_cleanup(); 330 return (error); 331 } 332 333 pf_pool_limits[PF_LIMIT_STATES].pp = pf_state_pl; 334 pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT; 335 pf_pool_limits[PF_LIMIT_SRC_NODES].pp = pf_src_tree_pl; 336 pf_pool_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT; 337 pf_pool_limits[PF_LIMIT_FRAGS].pp = pf_frent_pl; 338 pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT; 339 pf_pool_limits[PF_LIMIT_TABLES].pp = pfr_ktable_pl; 340 pf_pool_limits[PF_LIMIT_TABLES].limit = PFR_KTABLE_HIWAT; 341 pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].pp = pfr_kentry_pl; 342 pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT; 343 uma_zone_set_max(pf_pool_limits[PF_LIMIT_STATES].pp, 344 pf_pool_limits[PF_LIMIT_STATES].limit); 345 346 RB_INIT(&tree_src_tracking); 347 RB_INIT(&pf_anchors); 348 pf_init_ruleset(&pf_main_ruleset); 349 TAILQ_INIT(&pf_altqs[0]); 350 TAILQ_INIT(&pf_altqs[1]); 351 TAILQ_INIT(&pf_pabuf); 352 pf_altqs_active = &pf_altqs[0]; 353 pf_altqs_inactive = &pf_altqs[1]; 354 TAILQ_INIT(&state_list); 355 356 /* default rule should never be garbage collected */ 357 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; 358 pf_default_rule.action = PF_PASS; 359 pf_default_rule.nr = -1; 360 pf_default_rule.rtableid = -1; 361 362 /* initialize default timeouts */ 363 my_timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; 364 my_timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; 365 my_timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; 366 my_timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; 367 my_timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; 368 my_timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; 369 my_timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; 370 my_timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; 371 my_timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; 372 my_timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; 373 my_timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; 374 my_timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; 375 my_timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; 376 my_timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; 377 my_timeout[PFTM_FRAG] = PFTM_FRAG_VAL; 378 my_timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; 379 my_timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; 380 my_timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; 381 my_timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; 382 my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; 383 384 pf_normalize_init(); 385 bzero(&pf_status, sizeof(pf_status)); 386 pf_status.debug = PF_DEBUG_URGENT; 387 388 pf_pfil_hooked = 0; 389 390 /* XXX do our best to avoid a conflict */ 391 pf_status.hostid = arc4random(); 392 393 if (kproc_create(pf_purge_thread, NULL, NULL, 0, 0, "pfpurge")) 394 return (ENXIO); 395 396 return (error); 397} 398#else /* !__FreeBSD__ */ 399void 400pfattach(int num) 401{ 402 u_int32_t *timeout = pf_default_rule.timeout; 403 404 pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl", 405 &pool_allocator_nointr); 406 pool_init(&pf_src_tree_pl, sizeof(struct pf_src_node), 0, 0, 0, 407 "pfsrctrpl", NULL); 408 pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", 409 NULL); 410 pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", 411 &pool_allocator_nointr); 412 pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, 413 "pfpooladdrpl", &pool_allocator_nointr); 414 pfr_initialize(); 415 pfi_initialize(); 416 pf_osfp_initialize(); 417 418 pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp, 419 pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0); 420 421 if (ctob(physmem) <= 100*1024*1024) 422 pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = 423 PFR_KENTRY_HIWAT_SMALL; 424 425 RB_INIT(&tree_src_tracking); 426 RB_INIT(&pf_anchors); 427 pf_init_ruleset(&pf_main_ruleset); 428 TAILQ_INIT(&pf_altqs[0]); 429 TAILQ_INIT(&pf_altqs[1]); 430 TAILQ_INIT(&pf_pabuf); 431 pf_altqs_active = &pf_altqs[0]; 432 pf_altqs_inactive = &pf_altqs[1]; 433 TAILQ_INIT(&state_list); 434 435 /* default rule should never be garbage collected */ 436 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; 437 pf_default_rule.action = PF_PASS; 438 pf_default_rule.nr = -1; 439 pf_default_rule.rtableid = -1; 440 441 /* initialize default timeouts */ 442 timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; 443 timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; 444 timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; 445 timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; 446 timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; 447 timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; 448 timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; 449 timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; 450 timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; 451 timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; 452 timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; 453 timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; 454 timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; 455 timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; 456 timeout[PFTM_FRAG] = PFTM_FRAG_VAL; 457 timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; 458 timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; 459 timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; 460 timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; 461 timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; 462 463 pf_normalize_init(); 464 bzero(&pf_status, sizeof(pf_status)); 465 pf_status.debug = PF_DEBUG_URGENT; 466 467 /* XXX do our best to avoid a conflict */ 468 pf_status.hostid = arc4random(); 469 470 /* require process context to purge states, so perform in a thread */ 471 kproc_create_deferred(pf_thread_create, NULL); 472} 473 474void 475pf_thread_create(void *v) 476{ 477 if (kproc_create(pf_purge_thread, NULL, NULL, "pfpurge")) 478 panic("pfpurge thread"); 479} 480#endif /* __FreeBSD__ */ 481 482struct pf_pool * 483pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action, 484 u_int32_t rule_number, u_int8_t r_last, u_int8_t active, 485 u_int8_t check_ticket) 486{ 487 struct pf_ruleset *ruleset; 488 struct pf_rule *rule; 489 int rs_num; 490 491 ruleset = pf_find_ruleset(anchor); 492 if (ruleset == NULL) 493 return (NULL); 494 rs_num = pf_get_ruleset_number(rule_action); 495 if (rs_num >= PF_RULESET_MAX) 496 return (NULL); 497 if (active) { 498 if (check_ticket && ticket != 499 ruleset->rules[rs_num].active.ticket) 500 return (NULL); 501 if (r_last) 502 rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 503 pf_rulequeue); 504 else 505 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 506 } else { 507 if (check_ticket && ticket != 508 ruleset->rules[rs_num].inactive.ticket) 509 return (NULL); 510 if (r_last) 511 rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 512 pf_rulequeue); 513 else 514 rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr); 515 } 516 if (!r_last) { 517 while ((rule != NULL) && (rule->nr != rule_number)) 518 rule = TAILQ_NEXT(rule, entries); 519 } 520 if (rule == NULL) 521 return (NULL); 522 523 return (&rule->rpool); 524} 525 526void 527pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb) 528{ 529 struct pf_pooladdr *mv_pool_pa; 530 531 while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) { 532 TAILQ_REMOVE(poola, mv_pool_pa, entries); 533 TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries); 534 } 535} 536 537void 538pf_empty_pool(struct pf_palist *poola) 539{ 540 struct pf_pooladdr *empty_pool_pa; 541 542 while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) { 543 pfi_dynaddr_remove(&empty_pool_pa->addr); 544 pf_tbladdr_remove(&empty_pool_pa->addr); 545 pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE); 546 TAILQ_REMOVE(poola, empty_pool_pa, entries); 547 pool_put(&pf_pooladdr_pl, empty_pool_pa); 548 } 549} 550 551void 552pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) 553{ 554 if (rulequeue != NULL) { 555 if (rule->states <= 0) { 556 /* 557 * XXX - we need to remove the table *before* detaching 558 * the rule to make sure the table code does not delete 559 * the anchor under our feet. 560 */ 561 pf_tbladdr_remove(&rule->src.addr); 562 pf_tbladdr_remove(&rule->dst.addr); 563 if (rule->overload_tbl) 564 pfr_detach_table(rule->overload_tbl); 565 } 566 TAILQ_REMOVE(rulequeue, rule, entries); 567 rule->entries.tqe_prev = NULL; 568 rule->nr = -1; 569 } 570 571 if (rule->states > 0 || rule->src_nodes > 0 || 572 rule->entries.tqe_prev != NULL) 573 return; 574 pf_tag_unref(rule->tag); 575 pf_tag_unref(rule->match_tag); 576#ifdef ALTQ 577 if (rule->pqid != rule->qid) 578 pf_qid_unref(rule->pqid); 579 pf_qid_unref(rule->qid); 580#endif 581 pf_rtlabel_remove(&rule->src.addr); 582 pf_rtlabel_remove(&rule->dst.addr); 583 pfi_dynaddr_remove(&rule->src.addr); 584 pfi_dynaddr_remove(&rule->dst.addr); 585 if (rulequeue == NULL) { 586 pf_tbladdr_remove(&rule->src.addr); 587 pf_tbladdr_remove(&rule->dst.addr); 588 if (rule->overload_tbl) 589 pfr_detach_table(rule->overload_tbl); 590 } 591 pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE); 592 pf_anchor_remove(rule); 593 pf_empty_pool(&rule->rpool.list); 594 pool_put(&pf_rule_pl, rule); 595} 596 597u_int16_t 598tagname2tag(struct pf_tags *head, char *tagname) 599{ 600 struct pf_tagname *tag, *p = NULL; 601 u_int16_t new_tagid = 1; 602 603 TAILQ_FOREACH(tag, head, entries) 604 if (strcmp(tagname, tag->name) == 0) { 605 tag->ref++; 606 return (tag->tag); 607 } 608 609 /* 610 * to avoid fragmentation, we do a linear search from the beginning 611 * and take the first free slot we find. if there is none or the list 612 * is empty, append a new entry at the end. 613 */ 614 615 /* new entry */ 616 if (!TAILQ_EMPTY(head)) 617 for (p = TAILQ_FIRST(head); p != NULL && 618 p->tag == new_tagid; p = TAILQ_NEXT(p, entries)) 619 new_tagid = p->tag + 1; 620 621 if (new_tagid > TAGID_MAX) 622 return (0); 623 624 /* allocate and fill new struct pf_tagname */ 625 tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname), 626 M_TEMP, M_NOWAIT); 627 if (tag == NULL) 628 return (0); 629 bzero(tag, sizeof(struct pf_tagname)); 630 strlcpy(tag->name, tagname, sizeof(tag->name)); 631 tag->tag = new_tagid; 632 tag->ref++; 633 634 if (p != NULL) /* insert new entry before p */ 635 TAILQ_INSERT_BEFORE(p, tag, entries); 636 else /* either list empty or no free slot in between */ 637 TAILQ_INSERT_TAIL(head, tag, entries); 638 639 return (tag->tag); 640} 641 642void 643tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p) 644{ 645 struct pf_tagname *tag; 646 647 TAILQ_FOREACH(tag, head, entries) 648 if (tag->tag == tagid) { 649 strlcpy(p, tag->name, PF_TAG_NAME_SIZE); 650 return; 651 } 652} 653 654void 655tag_unref(struct pf_tags *head, u_int16_t tag) 656{ 657 struct pf_tagname *p, *next; 658 659 if (tag == 0) 660 return; 661 662 for (p = TAILQ_FIRST(head); p != NULL; p = next) { 663 next = TAILQ_NEXT(p, entries); 664 if (tag == p->tag) { 665 if (--p->ref == 0) { 666 TAILQ_REMOVE(head, p, entries); 667 free(p, M_TEMP); 668 } 669 break; 670 } 671 } 672} 673 674u_int16_t 675pf_tagname2tag(char *tagname) 676{ 677 return (tagname2tag(&pf_tags, tagname)); 678} 679 680void 681pf_tag2tagname(u_int16_t tagid, char *p) 682{ 683 tag2tagname(&pf_tags, tagid, p); 684} 685 686void 687pf_tag_ref(u_int16_t tag) 688{ 689 struct pf_tagname *t; 690 691 TAILQ_FOREACH(t, &pf_tags, entries) 692 if (t->tag == tag) 693 break; 694 if (t != NULL) 695 t->ref++; 696} 697 698void 699pf_tag_unref(u_int16_t tag) 700{ 701 tag_unref(&pf_tags, tag); 702} 703 704int 705pf_rtlabel_add(struct pf_addr_wrap *a) 706{ 707#ifdef __FreeBSD__ 708 /* XXX_IMPORT: later */ 709 return (0); 710#else 711 if (a->type == PF_ADDR_RTLABEL && 712 (a->v.rtlabel = rtlabel_name2id(a->v.rtlabelname)) == 0) 713 return (-1); 714 return (0); 715#endif 716} 717 718void 719pf_rtlabel_remove(struct pf_addr_wrap *a) 720{ 721#ifdef __FreeBSD__ 722 /* XXX_IMPORT: later */ 723#else 724 if (a->type == PF_ADDR_RTLABEL) 725 rtlabel_unref(a->v.rtlabel); 726#endif 727} 728 729void 730pf_rtlabel_copyout(struct pf_addr_wrap *a) 731{ 732#ifdef __FreeBSD__ 733 /* XXX_IMPORT: later */ 734 if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) 735 strlcpy(a->v.rtlabelname, "?", sizeof(a->v.rtlabelname)); 736#else 737 const char *name; 738 739 if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) { 740 if ((name = rtlabel_id2name(a->v.rtlabel)) == NULL) 741 strlcpy(a->v.rtlabelname, "?", 742 sizeof(a->v.rtlabelname)); 743 else 744 strlcpy(a->v.rtlabelname, name, 745 sizeof(a->v.rtlabelname)); 746 } 747#endif 748} 749 750#ifdef ALTQ 751u_int32_t 752pf_qname2qid(char *qname) 753{ 754 return ((u_int32_t)tagname2tag(&pf_qids, qname)); 755} 756 757void 758pf_qid2qname(u_int32_t qid, char *p) 759{ 760 tag2tagname(&pf_qids, (u_int16_t)qid, p); 761} 762 763void 764pf_qid_unref(u_int32_t qid) 765{ 766 tag_unref(&pf_qids, (u_int16_t)qid); 767} 768 769int 770pf_begin_altq(u_int32_t *ticket) 771{ 772 struct pf_altq *altq; 773 int error = 0; 774 775 /* Purge the old altq list */ 776 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 777 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 778#ifdef __FreeBSD__ 779 if (altq->qname[0] == 0 && 780 (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 781#else 782 if (altq->qname[0] == 0) { 783#endif 784 /* detach and destroy the discipline */ 785 error = altq_remove(altq); 786 } else 787 pf_qid_unref(altq->qid); 788 pool_put(&pf_altq_pl, altq); 789 } 790 if (error) 791 return (error); 792 *ticket = ++ticket_altqs_inactive; 793 altqs_inactive_open = 1; 794 return (0); 795} 796 797int 798pf_rollback_altq(u_int32_t ticket) 799{ 800 struct pf_altq *altq; 801 int error = 0; 802 803 if (!altqs_inactive_open || ticket != ticket_altqs_inactive) 804 return (0); 805 /* Purge the old altq list */ 806 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 807 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 808#ifdef __FreeBSD__ 809 if (altq->qname[0] == 0 && 810 (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 811#else 812 if (altq->qname[0] == 0) { 813#endif 814 /* detach and destroy the discipline */ 815 error = altq_remove(altq); 816 } else 817 pf_qid_unref(altq->qid); 818 pool_put(&pf_altq_pl, altq); 819 } 820 altqs_inactive_open = 0; 821 return (error); 822} 823 824int 825pf_commit_altq(u_int32_t ticket) 826{ 827 struct pf_altqqueue *old_altqs; 828 struct pf_altq *altq; 829 int s, err, error = 0; 830 831 if (!altqs_inactive_open || ticket != ticket_altqs_inactive) 832 return (EBUSY); 833 834 /* swap altqs, keep the old. */ 835 s = splsoftnet(); 836 old_altqs = pf_altqs_active; 837 pf_altqs_active = pf_altqs_inactive; 838 pf_altqs_inactive = old_altqs; 839 ticket_altqs_active = ticket_altqs_inactive; 840 841 /* Attach new disciplines */ 842 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 843#ifdef __FreeBSD__ 844 if (altq->qname[0] == 0 && 845 (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 846#else 847 if (altq->qname[0] == 0) { 848#endif 849 /* attach the discipline */ 850 error = altq_pfattach(altq); 851 if (error == 0 && pf_altq_running) 852 error = pf_enable_altq(altq); 853 if (error != 0) { 854 splx(s); 855 return (error); 856 } 857 } 858 } 859 860 /* Purge the old altq list */ 861 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 862 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 863#ifdef __FreeBSD__ 864 if (altq->qname[0] == 0 && 865 (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 866#else 867 if (altq->qname[0] == 0) { 868#endif 869 /* detach and destroy the discipline */ 870 if (pf_altq_running) 871 error = pf_disable_altq(altq); 872 err = altq_pfdetach(altq); 873 if (err != 0 && error == 0) 874 error = err; 875 err = altq_remove(altq); 876 if (err != 0 && error == 0) 877 error = err; 878 } else 879 pf_qid_unref(altq->qid); 880 pool_put(&pf_altq_pl, altq); 881 } 882 splx(s); 883 884 altqs_inactive_open = 0; 885 return (error); 886} 887 888int 889pf_enable_altq(struct pf_altq *altq) 890{ 891 struct ifnet *ifp; 892 struct tb_profile tb; 893 int s, error = 0; 894 895 if ((ifp = ifunit(altq->ifname)) == NULL) 896 return (EINVAL); 897 898 if (ifp->if_snd.altq_type != ALTQT_NONE) 899 error = altq_enable(&ifp->if_snd); 900 901 /* set tokenbucket regulator */ 902 if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { 903 tb.rate = altq->ifbandwidth; 904 tb.depth = altq->tbrsize; 905 s = splnet(); 906#ifdef __FreeBSD__ 907 PF_UNLOCK(); 908#endif 909 error = tbr_set(&ifp->if_snd, &tb); 910#ifdef __FreeBSD__ 911 PF_LOCK(); 912#endif 913 splx(s); 914 } 915 916 return (error); 917} 918 919int 920pf_disable_altq(struct pf_altq *altq) 921{ 922 struct ifnet *ifp; 923 struct tb_profile tb; 924 int s, error; 925 926 if ((ifp = ifunit(altq->ifname)) == NULL) 927 return (EINVAL); 928 929 /* 930 * when the discipline is no longer referenced, it was overridden 931 * by a new one. if so, just return. 932 */ 933 if (altq->altq_disc != ifp->if_snd.altq_disc) 934 return (0); 935 936 error = altq_disable(&ifp->if_snd); 937 938 if (error == 0) { 939 /* clear tokenbucket regulator */ 940 tb.rate = 0; 941 s = splnet(); 942#ifdef __FreeBSD__ 943 PF_UNLOCK(); 944#endif 945 error = tbr_set(&ifp->if_snd, &tb); 946#ifdef __FreeBSD__ 947 PF_LOCK(); 948#endif 949 splx(s); 950 } 951 952 return (error); 953} 954 955#ifdef __FreeBSD__ 956void 957pf_altq_ifnet_event(struct ifnet *ifp, int remove) 958{ 959 struct ifnet *ifp1; 960 struct pf_altq *a1, *a2, *a3; 961 u_int32_t ticket; 962 int error = 0; 963 964 /* Interrupt userland queue modifications */ 965 if (altqs_inactive_open) 966 pf_rollback_altq(ticket_altqs_inactive); 967 968 /* Start new altq ruleset */ 969 if (pf_begin_altq(&ticket)) 970 return; 971 972 /* Copy the current active set */ 973 TAILQ_FOREACH(a1, pf_altqs_active, entries) { 974 a2 = pool_get(&pf_altq_pl, PR_NOWAIT); 975 if (a2 == NULL) { 976 error = ENOMEM; 977 break; 978 } 979 bcopy(a1, a2, sizeof(struct pf_altq)); 980 981 if (a2->qname[0] != 0) { 982 if ((a2->qid = pf_qname2qid(a2->qname)) == 0) { 983 error = EBUSY; 984 pool_put(&pf_altq_pl, a2); 985 break; 986 } 987 a2->altq_disc = NULL; 988 TAILQ_FOREACH(a3, pf_altqs_inactive, entries) { 989 if (strncmp(a3->ifname, a2->ifname, 990 IFNAMSIZ) == 0 && a3->qname[0] == 0) { 991 a2->altq_disc = a3->altq_disc; 992 break; 993 } 994 } 995 } 996 /* Deactivate the interface in question */ 997 a2->local_flags &= ~PFALTQ_FLAG_IF_REMOVED; 998 if ((ifp1 = ifunit(a2->ifname)) == NULL || 999 (remove && ifp1 == ifp)) { 1000 a2->local_flags |= PFALTQ_FLAG_IF_REMOVED; 1001 } else { 1002 PF_UNLOCK(); 1003 error = altq_add(a2); 1004 PF_LOCK(); 1005 1006 if (ticket != ticket_altqs_inactive) 1007 error = EBUSY; 1008 1009 if (error) { 1010 pool_put(&pf_altq_pl, a2); 1011 break; 1012 } 1013 } 1014 1015 TAILQ_INSERT_TAIL(pf_altqs_inactive, a2, entries); 1016 } 1017 1018 if (error != 0) 1019 pf_rollback_altq(ticket); 1020 else 1021 pf_commit_altq(ticket); 1022} 1023#endif 1024#endif /* ALTQ */ 1025 1026int 1027pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor) 1028{ 1029 struct pf_ruleset *rs; 1030 struct pf_rule *rule; 1031 1032 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 1033 return (EINVAL); 1034 rs = pf_find_or_create_ruleset(anchor); 1035 if (rs == NULL) 1036 return (EINVAL); 1037 while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) { 1038 pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); 1039 rs->rules[rs_num].inactive.rcount--; 1040 } 1041 *ticket = ++rs->rules[rs_num].inactive.ticket; 1042 rs->rules[rs_num].inactive.open = 1; 1043 return (0); 1044} 1045 1046int 1047pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor) 1048{ 1049 struct pf_ruleset *rs; 1050 struct pf_rule *rule; 1051 1052 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 1053 return (EINVAL); 1054 rs = pf_find_ruleset(anchor); 1055 if (rs == NULL || !rs->rules[rs_num].inactive.open || 1056 rs->rules[rs_num].inactive.ticket != ticket) 1057 return (0); 1058 while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) { 1059 pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); 1060 rs->rules[rs_num].inactive.rcount--; 1061 } 1062 rs->rules[rs_num].inactive.open = 0; 1063 return (0); 1064} 1065 1066#define PF_MD5_UPD(st, elm) \ 1067 MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm)) 1068 1069#define PF_MD5_UPD_STR(st, elm) \ 1070 MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm)) 1071 1072#define PF_MD5_UPD_HTONL(st, elm, stor) do { \ 1073 (stor) = htonl((st)->elm); \ 1074 MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\ 1075} while (0) 1076 1077#define PF_MD5_UPD_HTONS(st, elm, stor) do { \ 1078 (stor) = htons((st)->elm); \ 1079 MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\ 1080} while (0) 1081 1082void 1083pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr) 1084{ 1085 PF_MD5_UPD(pfr, addr.type); 1086 switch (pfr->addr.type) { 1087 case PF_ADDR_DYNIFTL: 1088 PF_MD5_UPD(pfr, addr.v.ifname); 1089 PF_MD5_UPD(pfr, addr.iflags); 1090 break; 1091 case PF_ADDR_TABLE: 1092 PF_MD5_UPD(pfr, addr.v.tblname); 1093 break; 1094 case PF_ADDR_ADDRMASK: 1095 /* XXX ignore af? */ 1096 PF_MD5_UPD(pfr, addr.v.a.addr.addr32); 1097 PF_MD5_UPD(pfr, addr.v.a.mask.addr32); 1098 break; 1099 case PF_ADDR_RTLABEL: 1100 PF_MD5_UPD(pfr, addr.v.rtlabelname); 1101 break; 1102 } 1103 1104 PF_MD5_UPD(pfr, port[0]); 1105 PF_MD5_UPD(pfr, port[1]); 1106 PF_MD5_UPD(pfr, neg); 1107 PF_MD5_UPD(pfr, port_op); 1108} 1109 1110void 1111pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule) 1112{ 1113 u_int16_t x; 1114 u_int32_t y; 1115 1116 pf_hash_rule_addr(ctx, &rule->src); 1117 pf_hash_rule_addr(ctx, &rule->dst); 1118 PF_MD5_UPD_STR(rule, label); 1119 PF_MD5_UPD_STR(rule, ifname); 1120 PF_MD5_UPD_STR(rule, match_tagname); 1121 PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */ 1122 PF_MD5_UPD_HTONL(rule, os_fingerprint, y); 1123 PF_MD5_UPD_HTONL(rule, prob, y); 1124 PF_MD5_UPD_HTONL(rule, uid.uid[0], y); 1125 PF_MD5_UPD_HTONL(rule, uid.uid[1], y); 1126 PF_MD5_UPD(rule, uid.op); 1127 PF_MD5_UPD_HTONL(rule, gid.gid[0], y); 1128 PF_MD5_UPD_HTONL(rule, gid.gid[1], y); 1129 PF_MD5_UPD(rule, gid.op); 1130 PF_MD5_UPD_HTONL(rule, rule_flag, y); 1131 PF_MD5_UPD(rule, action); 1132 PF_MD5_UPD(rule, direction); 1133 PF_MD5_UPD(rule, af); 1134 PF_MD5_UPD(rule, quick); 1135 PF_MD5_UPD(rule, ifnot); 1136 PF_MD5_UPD(rule, match_tag_not); 1137 PF_MD5_UPD(rule, natpass); 1138 PF_MD5_UPD(rule, keep_state); 1139 PF_MD5_UPD(rule, proto); 1140 PF_MD5_UPD(rule, type); 1141 PF_MD5_UPD(rule, code); 1142 PF_MD5_UPD(rule, flags); 1143 PF_MD5_UPD(rule, flagset); 1144 PF_MD5_UPD(rule, allow_opts); 1145 PF_MD5_UPD(rule, rt); 1146 PF_MD5_UPD(rule, tos); 1147} 1148 1149int 1150pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) 1151{ 1152 struct pf_ruleset *rs; 1153 struct pf_rule *rule, **old_array; 1154 struct pf_rulequeue *old_rules; 1155 int s, error; 1156 u_int32_t old_rcount; 1157 1158 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 1159 return (EINVAL); 1160 rs = pf_find_ruleset(anchor); 1161 if (rs == NULL || !rs->rules[rs_num].inactive.open || 1162 ticket != rs->rules[rs_num].inactive.ticket) 1163 return (EBUSY); 1164 1165 /* Calculate checksum for the main ruleset */ 1166 if (rs == &pf_main_ruleset) { 1167 error = pf_setup_pfsync_matching(rs); 1168 if (error != 0) 1169 return (error); 1170 } 1171 1172 /* Swap rules, keep the old. */ 1173 s = splsoftnet(); 1174 old_rules = rs->rules[rs_num].active.ptr; 1175 old_rcount = rs->rules[rs_num].active.rcount; 1176 old_array = rs->rules[rs_num].active.ptr_array; 1177 1178 rs->rules[rs_num].active.ptr = 1179 rs->rules[rs_num].inactive.ptr; 1180 rs->rules[rs_num].active.ptr_array = 1181 rs->rules[rs_num].inactive.ptr_array; 1182 rs->rules[rs_num].active.rcount = 1183 rs->rules[rs_num].inactive.rcount; 1184 rs->rules[rs_num].inactive.ptr = old_rules; 1185 rs->rules[rs_num].inactive.ptr_array = old_array; 1186 rs->rules[rs_num].inactive.rcount = old_rcount; 1187 1188 rs->rules[rs_num].active.ticket = 1189 rs->rules[rs_num].inactive.ticket; 1190 pf_calc_skip_steps(rs->rules[rs_num].active.ptr); 1191 1192 1193 /* Purge the old rule list. */ 1194 while ((rule = TAILQ_FIRST(old_rules)) != NULL) 1195 pf_rm_rule(old_rules, rule); 1196 if (rs->rules[rs_num].inactive.ptr_array) 1197 free(rs->rules[rs_num].inactive.ptr_array, M_TEMP); 1198 rs->rules[rs_num].inactive.ptr_array = NULL; 1199 rs->rules[rs_num].inactive.rcount = 0; 1200 rs->rules[rs_num].inactive.open = 0; 1201 pf_remove_if_empty_ruleset(rs); 1202 splx(s); 1203 return (0); 1204} 1205 1206int 1207pf_setup_pfsync_matching(struct pf_ruleset *rs) 1208{ 1209 MD5_CTX ctx; 1210 struct pf_rule *rule; 1211 int rs_cnt; 1212 u_int8_t digest[PF_MD5_DIGEST_LENGTH]; 1213 1214 MD5Init(&ctx); 1215 for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) { 1216 /* XXX PF_RULESET_SCRUB as well? */ 1217 if (rs_cnt == PF_RULESET_SCRUB) 1218 continue; 1219 1220 if (rs->rules[rs_cnt].inactive.ptr_array) 1221 free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP); 1222 rs->rules[rs_cnt].inactive.ptr_array = NULL; 1223 1224 if (rs->rules[rs_cnt].inactive.rcount) { 1225 rs->rules[rs_cnt].inactive.ptr_array = 1226 malloc(sizeof(caddr_t) * 1227 rs->rules[rs_cnt].inactive.rcount, 1228 M_TEMP, M_NOWAIT); 1229 1230 if (!rs->rules[rs_cnt].inactive.ptr_array) 1231 return (ENOMEM); 1232 } 1233 1234 TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr, 1235 entries) { 1236 pf_hash_rule(&ctx, rule); 1237 (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule; 1238 } 1239 } 1240 1241 MD5Final(digest, &ctx); 1242 memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum)); 1243 return (0); 1244} 1245 1246int 1247#ifdef __FreeBSD__ 1248pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 1249#else 1250pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 1251#endif 1252{ 1253 struct pf_pooladdr *pa = NULL; 1254 struct pf_pool *pool = NULL; 1255#ifndef __FreeBSD__ 1256 int s; 1257#endif 1258 int error = 0; 1259 1260 /* XXX keep in sync with switch() below */ 1261#ifdef __FreeBSD__ 1262 if (securelevel_gt(td->td_ucred, 2)) 1263#else 1264 if (securelevel > 1) 1265#endif 1266 switch (cmd) { 1267 case DIOCGETRULES: 1268 case DIOCGETRULE: 1269 case DIOCGETADDRS: 1270 case DIOCGETADDR: 1271 case DIOCGETSTATE: 1272 case DIOCSETSTATUSIF: 1273 case DIOCGETSTATUS: 1274 case DIOCCLRSTATUS: 1275 case DIOCNATLOOK: 1276 case DIOCSETDEBUG: 1277 case DIOCGETSTATES: 1278 case DIOCGETTIMEOUT: 1279 case DIOCCLRRULECTRS: 1280 case DIOCGETLIMIT: 1281 case DIOCGETALTQS: 1282 case DIOCGETALTQ: 1283 case DIOCGETQSTATS: 1284 case DIOCGETRULESETS: 1285 case DIOCGETRULESET: 1286 case DIOCRGETTABLES: 1287 case DIOCRGETTSTATS: 1288 case DIOCRCLRTSTATS: 1289 case DIOCRCLRADDRS: 1290 case DIOCRADDADDRS: 1291 case DIOCRDELADDRS: 1292 case DIOCRSETADDRS: 1293 case DIOCRGETADDRS: 1294 case DIOCRGETASTATS: 1295 case DIOCRCLRASTATS: 1296 case DIOCRTSTADDRS: 1297 case DIOCOSFPGET: 1298 case DIOCGETSRCNODES: 1299 case DIOCCLRSRCNODES: 1300 case DIOCIGETIFACES: 1301#ifdef __FreeBSD__ 1302 case DIOCGIFSPEED: 1303#endif 1304 case DIOCSETIFFLAG: 1305 case DIOCCLRIFFLAG: 1306 break; 1307 case DIOCRCLRTABLES: 1308 case DIOCRADDTABLES: 1309 case DIOCRDELTABLES: 1310 case DIOCRSETTFLAGS: 1311 if (((struct pfioc_table *)addr)->pfrio_flags & 1312 PFR_FLAG_DUMMY) 1313 break; /* dummy operation ok */ 1314 return (EPERM); 1315 default: 1316 return (EPERM); 1317 } 1318 1319 if (!(flags & FWRITE)) 1320 switch (cmd) { 1321 case DIOCGETRULES: 1322 case DIOCGETADDRS: 1323 case DIOCGETADDR: 1324 case DIOCGETSTATE: 1325 case DIOCGETSTATUS: 1326 case DIOCGETSTATES: 1327 case DIOCGETTIMEOUT: 1328 case DIOCGETLIMIT: 1329 case DIOCGETALTQS: 1330 case DIOCGETALTQ: 1331 case DIOCGETQSTATS: 1332 case DIOCGETRULESETS: 1333 case DIOCGETRULESET: 1334 case DIOCNATLOOK: 1335 case DIOCRGETTABLES: 1336 case DIOCRGETTSTATS: 1337 case DIOCRGETADDRS: 1338 case DIOCRGETASTATS: 1339 case DIOCRTSTADDRS: 1340 case DIOCOSFPGET: 1341 case DIOCGETSRCNODES: 1342 case DIOCIGETIFACES: 1343#ifdef __FreeBSD__ 1344 case DIOCGIFSPEED: 1345#endif 1346 break; 1347 case DIOCRCLRTABLES: 1348 case DIOCRADDTABLES: 1349 case DIOCRDELTABLES: 1350 case DIOCRCLRTSTATS: 1351 case DIOCRCLRADDRS: 1352 case DIOCRADDADDRS: 1353 case DIOCRDELADDRS: 1354 case DIOCRSETADDRS: 1355 case DIOCRSETTFLAGS: 1356 if (((struct pfioc_table *)addr)->pfrio_flags & 1357 PFR_FLAG_DUMMY) { 1358 flags |= FWRITE; /* need write lock for dummy */ 1359 break; /* dummy operation ok */ 1360 } 1361 return (EACCES); 1362 case DIOCGETRULE: 1363 if (((struct pfioc_rule *)addr)->action == PF_GET_CLR_CNTR) 1364 return (EACCES); 1365 break; 1366 default: 1367 return (EACCES); 1368 } 1369 1370 if (flags & FWRITE) 1371#ifdef __FreeBSD__ 1372 sx_xlock(&pf_consistency_lock); 1373 else 1374 sx_slock(&pf_consistency_lock); 1375#else 1376 rw_enter_write(&pf_consistency_lock); 1377 else 1378 rw_enter_read(&pf_consistency_lock); 1379#endif 1380 1381#ifdef __FreeBSD__ 1382 PF_LOCK(); 1383#else 1384 s = splsoftnet(); 1385#endif 1386 switch (cmd) { 1387 1388 case DIOCSTART: 1389 if (pf_status.running) 1390 error = EEXIST; 1391 else { 1392#ifdef __FreeBSD__ 1393 PF_UNLOCK(); 1394 error = hook_pf(); 1395 PF_LOCK(); 1396 if (error) { 1397 DPFPRINTF(PF_DEBUG_MISC, 1398 ("pf: pfil registeration fail\n")); 1399 break; 1400 } 1401#endif 1402 pf_status.running = 1; 1403 pf_status.since = time_second; 1404 if (pf_status.stateid == 0) { 1405 pf_status.stateid = time_second; 1406 pf_status.stateid = pf_status.stateid << 32; 1407 } 1408 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); 1409 } 1410 break; 1411 1412 case DIOCSTOP: 1413 if (!pf_status.running) 1414 error = ENOENT; 1415 else { 1416 pf_status.running = 0; 1417#ifdef __FreeBSD__ 1418 PF_UNLOCK(); 1419 error = dehook_pf(); 1420 PF_LOCK(); 1421 if (error) { 1422 pf_status.running = 1; 1423 DPFPRINTF(PF_DEBUG_MISC, 1424 ("pf: pfil unregisteration failed\n")); 1425 } 1426#endif 1427 pf_status.since = time_second; 1428 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); 1429 } 1430 break; 1431 1432 case DIOCADDRULE: { 1433 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1434 struct pf_ruleset *ruleset; 1435 struct pf_rule *rule, *tail; 1436 struct pf_pooladdr *pa; 1437 int rs_num; 1438 1439 pr->anchor[sizeof(pr->anchor) - 1] = 0; 1440 ruleset = pf_find_ruleset(pr->anchor); 1441 if (ruleset == NULL) { 1442 error = EINVAL; 1443 break; 1444 } 1445 rs_num = pf_get_ruleset_number(pr->rule.action); 1446 if (rs_num >= PF_RULESET_MAX) { 1447 error = EINVAL; 1448 break; 1449 } 1450 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1451 error = EINVAL; 1452 break; 1453 } 1454 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { 1455#ifdef __FreeBSD__ 1456 DPFPRINTF(PF_DEBUG_MISC, 1457 ("ticket: %d != [%d]%d\n", pr->ticket, rs_num, 1458 ruleset->rules[rs_num].inactive.ticket)); 1459#endif 1460 error = EBUSY; 1461 break; 1462 } 1463 if (pr->pool_ticket != ticket_pabuf) { 1464#ifdef __FreeBSD__ 1465 DPFPRINTF(PF_DEBUG_MISC, 1466 ("pool_ticket: %d != %d\n", pr->pool_ticket, 1467 ticket_pabuf)); 1468#endif 1469 error = EBUSY; 1470 break; 1471 } 1472 rule = pool_get(&pf_rule_pl, PR_NOWAIT); 1473 if (rule == NULL) { 1474 error = ENOMEM; 1475 break; 1476 } 1477 bcopy(&pr->rule, rule, sizeof(struct pf_rule)); 1478#ifdef __FreeBSD__ 1479 rule->cuid = td->td_ucred->cr_ruid; 1480 rule->cpid = td->td_proc ? td->td_proc->p_pid : 0; 1481#else 1482 rule->cuid = p->p_cred->p_ruid; 1483 rule->cpid = p->p_pid; 1484#endif 1485 rule->anchor = NULL; 1486 rule->kif = NULL; 1487 TAILQ_INIT(&rule->rpool.list); 1488 /* initialize refcounting */ 1489 rule->states = 0; 1490 rule->src_nodes = 0; 1491 rule->entries.tqe_prev = NULL; 1492#ifndef INET 1493 if (rule->af == AF_INET) { 1494 pool_put(&pf_rule_pl, rule); 1495 error = EAFNOSUPPORT; 1496 break; 1497 } 1498#endif /* INET */ 1499#ifndef INET6 1500 if (rule->af == AF_INET6) { 1501 pool_put(&pf_rule_pl, rule); 1502 error = EAFNOSUPPORT; 1503 break; 1504 } 1505#endif /* INET6 */ 1506 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 1507 pf_rulequeue); 1508 if (tail) 1509 rule->nr = tail->nr + 1; 1510 else 1511 rule->nr = 0; 1512 if (rule->ifname[0]) { 1513 rule->kif = pfi_kif_get(rule->ifname); 1514 if (rule->kif == NULL) { 1515 pool_put(&pf_rule_pl, rule); 1516 error = EINVAL; 1517 break; 1518 } 1519 pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE); 1520 } 1521 1522#ifdef __FreeBSD__ /* ROUTING */ 1523 if (rule->rtableid > 0 && rule->rtableid > rt_numfibs) 1524#else 1525 if (rule->rtableid > 0 && !rtable_exists(rule->rtableid)) 1526#endif 1527 error = EBUSY; 1528 1529#ifdef ALTQ 1530 /* set queue IDs */ 1531 if (rule->qname[0] != 0) { 1532 if ((rule->qid = pf_qname2qid(rule->qname)) == 0) 1533 error = EBUSY; 1534 else if (rule->pqname[0] != 0) { 1535 if ((rule->pqid = 1536 pf_qname2qid(rule->pqname)) == 0) 1537 error = EBUSY; 1538 } else 1539 rule->pqid = rule->qid; 1540 } 1541#endif 1542 if (rule->tagname[0]) 1543 if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) 1544 error = EBUSY; 1545 if (rule->match_tagname[0]) 1546 if ((rule->match_tag = 1547 pf_tagname2tag(rule->match_tagname)) == 0) 1548 error = EBUSY; 1549 if (rule->rt && !rule->direction) 1550 error = EINVAL; 1551#if NPFLOG > 0 1552#ifdef __FreeBSD__ 1553 if (!rule->log) 1554 rule->logif = 0; 1555#endif 1556 if (rule->logif >= PFLOGIFS_MAX) 1557 error = EINVAL; 1558#endif 1559 if (pf_rtlabel_add(&rule->src.addr) || 1560 pf_rtlabel_add(&rule->dst.addr)) 1561 error = EBUSY; 1562 if (pfi_dynaddr_setup(&rule->src.addr, rule->af)) 1563 error = EINVAL; 1564 if (pfi_dynaddr_setup(&rule->dst.addr, rule->af)) 1565 error = EINVAL; 1566 if (pf_tbladdr_setup(ruleset, &rule->src.addr)) 1567 error = EINVAL; 1568 if (pf_tbladdr_setup(ruleset, &rule->dst.addr)) 1569 error = EINVAL; 1570 if (pf_anchor_setup(rule, ruleset, pr->anchor_call)) 1571 error = EINVAL; 1572 TAILQ_FOREACH(pa, &pf_pabuf, entries) 1573 if (pf_tbladdr_setup(ruleset, &pa->addr)) 1574 error = EINVAL; 1575 1576 if (rule->overload_tblname[0]) { 1577 if ((rule->overload_tbl = pfr_attach_table(ruleset, 1578 rule->overload_tblname)) == NULL) 1579 error = EINVAL; 1580 else 1581 rule->overload_tbl->pfrkt_flags |= 1582 PFR_TFLAG_ACTIVE; 1583 } 1584 1585 pf_mv_pool(&pf_pabuf, &rule->rpool.list); 1586 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || 1587 (rule->action == PF_BINAT)) && rule->anchor == NULL) || 1588 (rule->rt > PF_FASTROUTE)) && 1589 (TAILQ_FIRST(&rule->rpool.list) == NULL)) 1590 error = EINVAL; 1591 1592 if (error) { 1593 pf_rm_rule(NULL, rule); 1594 break; 1595 } 1596 1597#ifdef __FreeBSD__ 1598 if (!debug_pfugidhack && (rule->uid.op || rule->gid.op || 1599 rule->log & PF_LOG_SOCKET_LOOKUP)) { 1600 DPFPRINTF(PF_DEBUG_MISC, 1601 ("pf: debug.pfugidhack enabled\n")); 1602 debug_pfugidhack = 1; 1603 } 1604#endif 1605 1606 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list); 1607 rule->evaluations = rule->packets[0] = rule->packets[1] = 1608 rule->bytes[0] = rule->bytes[1] = 0; 1609 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, 1610 rule, entries); 1611 ruleset->rules[rs_num].inactive.rcount++; 1612 break; 1613 } 1614 1615 case DIOCGETRULES: { 1616 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1617 struct pf_ruleset *ruleset; 1618 struct pf_rule *tail; 1619 int rs_num; 1620 1621 pr->anchor[sizeof(pr->anchor) - 1] = 0; 1622 ruleset = pf_find_ruleset(pr->anchor); 1623 if (ruleset == NULL) { 1624 error = EINVAL; 1625 break; 1626 } 1627 rs_num = pf_get_ruleset_number(pr->rule.action); 1628 if (rs_num >= PF_RULESET_MAX) { 1629 error = EINVAL; 1630 break; 1631 } 1632 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 1633 pf_rulequeue); 1634 if (tail) 1635 pr->nr = tail->nr + 1; 1636 else 1637 pr->nr = 0; 1638 pr->ticket = ruleset->rules[rs_num].active.ticket; 1639 break; 1640 } 1641 1642 case DIOCGETRULE: { 1643 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1644 struct pf_ruleset *ruleset; 1645 struct pf_rule *rule; 1646 int rs_num, i; 1647 1648 pr->anchor[sizeof(pr->anchor) - 1] = 0; 1649 ruleset = pf_find_ruleset(pr->anchor); 1650 if (ruleset == NULL) { 1651 error = EINVAL; 1652 break; 1653 } 1654 rs_num = pf_get_ruleset_number(pr->rule.action); 1655 if (rs_num >= PF_RULESET_MAX) { 1656 error = EINVAL; 1657 break; 1658 } 1659 if (pr->ticket != ruleset->rules[rs_num].active.ticket) { 1660 error = EBUSY; 1661 break; 1662 } 1663 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 1664 while ((rule != NULL) && (rule->nr != pr->nr)) 1665 rule = TAILQ_NEXT(rule, entries); 1666 if (rule == NULL) { 1667 error = EBUSY; 1668 break; 1669 } 1670 bcopy(rule, &pr->rule, sizeof(struct pf_rule)); 1671 if (pf_anchor_copyout(ruleset, rule, pr)) { 1672 error = EBUSY; 1673 break; 1674 } 1675 pfi_dynaddr_copyout(&pr->rule.src.addr); 1676 pfi_dynaddr_copyout(&pr->rule.dst.addr); 1677 pf_tbladdr_copyout(&pr->rule.src.addr); 1678 pf_tbladdr_copyout(&pr->rule.dst.addr); 1679 pf_rtlabel_copyout(&pr->rule.src.addr); 1680 pf_rtlabel_copyout(&pr->rule.dst.addr); 1681 for (i = 0; i < PF_SKIP_COUNT; ++i) 1682 if (rule->skip[i].ptr == NULL) 1683 pr->rule.skip[i].nr = -1; 1684 else 1685 pr->rule.skip[i].nr = 1686 rule->skip[i].ptr->nr; 1687 1688 if (pr->action == PF_GET_CLR_CNTR) { 1689 rule->evaluations = 0; 1690 rule->packets[0] = rule->packets[1] = 0; 1691 rule->bytes[0] = rule->bytes[1] = 0; 1692 } 1693 break; 1694 } 1695 1696 case DIOCCHANGERULE: { 1697 struct pfioc_rule *pcr = (struct pfioc_rule *)addr; 1698 struct pf_ruleset *ruleset; 1699 struct pf_rule *oldrule = NULL, *newrule = NULL; 1700 u_int32_t nr = 0; 1701 int rs_num; 1702 1703 if (!(pcr->action == PF_CHANGE_REMOVE || 1704 pcr->action == PF_CHANGE_GET_TICKET) && 1705 pcr->pool_ticket != ticket_pabuf) { 1706 error = EBUSY; 1707 break; 1708 } 1709 1710 if (pcr->action < PF_CHANGE_ADD_HEAD || 1711 pcr->action > PF_CHANGE_GET_TICKET) { 1712 error = EINVAL; 1713 break; 1714 } 1715 ruleset = pf_find_ruleset(pcr->anchor); 1716 if (ruleset == NULL) { 1717 error = EINVAL; 1718 break; 1719 } 1720 rs_num = pf_get_ruleset_number(pcr->rule.action); 1721 if (rs_num >= PF_RULESET_MAX) { 1722 error = EINVAL; 1723 break; 1724 } 1725 1726 if (pcr->action == PF_CHANGE_GET_TICKET) { 1727 pcr->ticket = ++ruleset->rules[rs_num].active.ticket; 1728 break; 1729 } else { 1730 if (pcr->ticket != 1731 ruleset->rules[rs_num].active.ticket) { 1732 error = EINVAL; 1733 break; 1734 } 1735 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1736 error = EINVAL; 1737 break; 1738 } 1739 } 1740 1741 if (pcr->action != PF_CHANGE_REMOVE) { 1742 newrule = pool_get(&pf_rule_pl, PR_NOWAIT); 1743 if (newrule == NULL) { 1744 error = ENOMEM; 1745 break; 1746 } 1747 bcopy(&pcr->rule, newrule, sizeof(struct pf_rule)); 1748#ifdef __FreeBSD__ 1749 newrule->cuid = td->td_ucred->cr_ruid; 1750 newrule->cpid = td->td_proc ? td->td_proc->p_pid : 0; 1751#else 1752 newrule->cuid = p->p_cred->p_ruid; 1753 newrule->cpid = p->p_pid; 1754#endif 1755 TAILQ_INIT(&newrule->rpool.list); 1756 /* initialize refcounting */ 1757 newrule->states = 0; 1758 newrule->entries.tqe_prev = NULL; 1759#ifndef INET 1760 if (newrule->af == AF_INET) { 1761 pool_put(&pf_rule_pl, newrule); 1762 error = EAFNOSUPPORT; 1763 break; 1764 } 1765#endif /* INET */ 1766#ifndef INET6 1767 if (newrule->af == AF_INET6) { 1768 pool_put(&pf_rule_pl, newrule); 1769 error = EAFNOSUPPORT; 1770 break; 1771 } 1772#endif /* INET6 */ 1773 if (newrule->ifname[0]) { 1774 newrule->kif = pfi_kif_get(newrule->ifname); 1775 if (newrule->kif == NULL) { 1776 pool_put(&pf_rule_pl, newrule); 1777 error = EINVAL; 1778 break; 1779 } 1780 pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE); 1781 } else 1782 newrule->kif = NULL; 1783 1784 if (newrule->rtableid > 0 && 1785#ifdef __FreeBSD__ /* ROUTING */ 1786 newrule->rtableid > rt_numfibs) 1787#else 1788 !rtable_exists(newrule->rtableid)) 1789#endif 1790 error = EBUSY; 1791 1792#ifdef ALTQ 1793 /* set queue IDs */ 1794 if (newrule->qname[0] != 0) { 1795 if ((newrule->qid = 1796 pf_qname2qid(newrule->qname)) == 0) 1797 error = EBUSY; 1798 else if (newrule->pqname[0] != 0) { 1799 if ((newrule->pqid = 1800 pf_qname2qid(newrule->pqname)) == 0) 1801 error = EBUSY; 1802 } else 1803 newrule->pqid = newrule->qid; 1804 } 1805#endif /* ALTQ */ 1806 if (newrule->tagname[0]) 1807 if ((newrule->tag = 1808 pf_tagname2tag(newrule->tagname)) == 0) 1809 error = EBUSY; 1810 if (newrule->match_tagname[0]) 1811 if ((newrule->match_tag = pf_tagname2tag( 1812 newrule->match_tagname)) == 0) 1813 error = EBUSY; 1814 if (newrule->rt && !newrule->direction) 1815 error = EINVAL; 1816#ifdef __FreeBSD__ 1817#if NPFLOG > 0 1818 if (!newrule->log) 1819 newrule->logif = 0; 1820 if (newrule->logif >= PFLOGIFS_MAX) 1821 error = EINVAL; 1822#endif 1823#endif 1824 if (pf_rtlabel_add(&newrule->src.addr) || 1825 pf_rtlabel_add(&newrule->dst.addr)) 1826 error = EBUSY; 1827 if (pfi_dynaddr_setup(&newrule->src.addr, newrule->af)) 1828 error = EINVAL; 1829 if (pfi_dynaddr_setup(&newrule->dst.addr, newrule->af)) 1830 error = EINVAL; 1831 if (pf_tbladdr_setup(ruleset, &newrule->src.addr)) 1832 error = EINVAL; 1833 if (pf_tbladdr_setup(ruleset, &newrule->dst.addr)) 1834 error = EINVAL; 1835 if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call)) 1836 error = EINVAL; 1837 TAILQ_FOREACH(pa, &pf_pabuf, entries) 1838 if (pf_tbladdr_setup(ruleset, &pa->addr)) 1839 error = EINVAL; 1840 1841 if (newrule->overload_tblname[0]) { 1842 if ((newrule->overload_tbl = pfr_attach_table( 1843 ruleset, newrule->overload_tblname)) == 1844 NULL) 1845 error = EINVAL; 1846 else 1847 newrule->overload_tbl->pfrkt_flags |= 1848 PFR_TFLAG_ACTIVE; 1849 } 1850 1851 pf_mv_pool(&pf_pabuf, &newrule->rpool.list); 1852 if (((((newrule->action == PF_NAT) || 1853 (newrule->action == PF_RDR) || 1854 (newrule->action == PF_BINAT) || 1855 (newrule->rt > PF_FASTROUTE)) && 1856 !newrule->anchor)) && 1857 (TAILQ_FIRST(&newrule->rpool.list) == NULL)) 1858 error = EINVAL; 1859 1860 if (error) { 1861 pf_rm_rule(NULL, newrule); 1862 break; 1863 } 1864 1865#ifdef __FreeBSD__ 1866 if (!debug_pfugidhack && (newrule->uid.op || 1867 newrule->gid.op || 1868 newrule->log & PF_LOG_SOCKET_LOOKUP)) { 1869 DPFPRINTF(PF_DEBUG_MISC, 1870 ("pf: debug.pfugidhack enabled\n")); 1871 debug_pfugidhack = 1; 1872 } 1873#endif 1874 1875 newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list); 1876 newrule->evaluations = 0; 1877 newrule->packets[0] = newrule->packets[1] = 0; 1878 newrule->bytes[0] = newrule->bytes[1] = 0; 1879 } 1880 pf_empty_pool(&pf_pabuf); 1881 1882 if (pcr->action == PF_CHANGE_ADD_HEAD) 1883 oldrule = TAILQ_FIRST( 1884 ruleset->rules[rs_num].active.ptr); 1885 else if (pcr->action == PF_CHANGE_ADD_TAIL) 1886 oldrule = TAILQ_LAST( 1887 ruleset->rules[rs_num].active.ptr, pf_rulequeue); 1888 else { 1889 oldrule = TAILQ_FIRST( 1890 ruleset->rules[rs_num].active.ptr); 1891 while ((oldrule != NULL) && (oldrule->nr != pcr->nr)) 1892 oldrule = TAILQ_NEXT(oldrule, entries); 1893 if (oldrule == NULL) { 1894 if (newrule != NULL) 1895 pf_rm_rule(NULL, newrule); 1896 error = EINVAL; 1897 break; 1898 } 1899 } 1900 1901 if (pcr->action == PF_CHANGE_REMOVE) { 1902 pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule); 1903 ruleset->rules[rs_num].active.rcount--; 1904 } else { 1905 if (oldrule == NULL) 1906 TAILQ_INSERT_TAIL( 1907 ruleset->rules[rs_num].active.ptr, 1908 newrule, entries); 1909 else if (pcr->action == PF_CHANGE_ADD_HEAD || 1910 pcr->action == PF_CHANGE_ADD_BEFORE) 1911 TAILQ_INSERT_BEFORE(oldrule, newrule, entries); 1912 else 1913 TAILQ_INSERT_AFTER( 1914 ruleset->rules[rs_num].active.ptr, 1915 oldrule, newrule, entries); 1916 ruleset->rules[rs_num].active.rcount++; 1917 } 1918 1919 nr = 0; 1920 TAILQ_FOREACH(oldrule, 1921 ruleset->rules[rs_num].active.ptr, entries) 1922 oldrule->nr = nr++; 1923 1924 ruleset->rules[rs_num].active.ticket++; 1925 1926 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); 1927 pf_remove_if_empty_ruleset(ruleset); 1928 1929 break; 1930 } 1931 1932 case DIOCCLRSTATES: { 1933 struct pf_state *state, *nexts; 1934 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 1935 int killed = 0; 1936 1937 for (state = RB_MIN(pf_state_tree_id, &tree_id); state; 1938 state = nexts) { 1939 nexts = RB_NEXT(pf_state_tree_id, &tree_id, state); 1940 1941 if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, 1942 state->u.s.kif->pfik_name)) { 1943#if NPFSYNC 1944 /* don't send out individual delete messages */ 1945 state->sync_flags = PFSTATE_NOSYNC; 1946#endif 1947 pf_unlink_state(state); 1948 killed++; 1949 } 1950 } 1951 psk->psk_af = killed; 1952#if NPFSYNC 1953 pfsync_clear_states(pf_status.hostid, psk->psk_ifname); 1954#endif 1955 break; 1956 } 1957 1958 case DIOCKILLSTATES: { 1959 struct pf_state *state, *nexts; 1960 struct pf_state_host *src, *dst; 1961 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 1962 int killed = 0; 1963 1964 for (state = RB_MIN(pf_state_tree_id, &tree_id); state; 1965 state = nexts) { 1966 nexts = RB_NEXT(pf_state_tree_id, &tree_id, state); 1967 1968 if (state->direction == PF_OUT) { 1969 src = &state->lan; 1970 dst = &state->ext; 1971 } else { 1972 src = &state->ext; 1973 dst = &state->lan; 1974 } 1975 if ((!psk->psk_af || state->af == psk->psk_af) 1976 && (!psk->psk_proto || psk->psk_proto == 1977 state->proto) && 1978 PF_MATCHA(psk->psk_src.neg, 1979 &psk->psk_src.addr.v.a.addr, 1980 &psk->psk_src.addr.v.a.mask, 1981 &src->addr, state->af) && 1982 PF_MATCHA(psk->psk_dst.neg, 1983 &psk->psk_dst.addr.v.a.addr, 1984 &psk->psk_dst.addr.v.a.mask, 1985 &dst->addr, state->af) && 1986 (psk->psk_src.port_op == 0 || 1987 pf_match_port(psk->psk_src.port_op, 1988 psk->psk_src.port[0], psk->psk_src.port[1], 1989 src->port)) && 1990 (psk->psk_dst.port_op == 0 || 1991 pf_match_port(psk->psk_dst.port_op, 1992 psk->psk_dst.port[0], psk->psk_dst.port[1], 1993 dst->port)) && 1994 (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, 1995 state->u.s.kif->pfik_name))) { 1996#if NPFSYNC > 0 1997 /* send immediate delete of state */ 1998 pfsync_delete_state(state); 1999 state->sync_flags |= PFSTATE_NOSYNC; 2000#endif 2001 pf_unlink_state(state); 2002 killed++; 2003 } 2004 } 2005 psk->psk_af = killed; 2006 break; 2007 } 2008 2009 case DIOCADDSTATE: { 2010 struct pfioc_state *ps = (struct pfioc_state *)addr; 2011 struct pf_state *state; 2012 struct pfi_kif *kif; 2013 2014 if (ps->state.timeout >= PFTM_MAX && 2015 ps->state.timeout != PFTM_UNTIL_PACKET) { 2016 error = EINVAL; 2017 break; 2018 } 2019 state = pool_get(&pf_state_pl, PR_NOWAIT); 2020 if (state == NULL) { 2021 error = ENOMEM; 2022 break; 2023 } 2024 kif = pfi_kif_get(ps->state.u.ifname); 2025 if (kif == NULL) { 2026 pool_put(&pf_state_pl, state); 2027 error = ENOENT; 2028 break; 2029 } 2030 bcopy(&ps->state, state, sizeof(struct pf_state)); 2031 bzero(&state->u, sizeof(state->u)); 2032 state->rule.ptr = &pf_default_rule; 2033 state->nat_rule.ptr = NULL; 2034 state->anchor.ptr = NULL; 2035 state->rt_kif = NULL; 2036 state->creation = time_second; 2037 state->pfsync_time = 0; 2038 state->packets[0] = state->packets[1] = 0; 2039 state->bytes[0] = state->bytes[1] = 0; 2040 2041 if (pf_insert_state(kif, state)) { 2042 pfi_kif_unref(kif, PFI_KIF_REF_NONE); 2043 pool_put(&pf_state_pl, state); 2044 error = ENOMEM; 2045 } 2046 break; 2047 } 2048 2049 case DIOCGETSTATE: { 2050 struct pfioc_state *ps = (struct pfioc_state *)addr; 2051 struct pf_state *state; 2052 u_int32_t nr; 2053 int secs; 2054 2055 nr = 0; 2056 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 2057 if (nr >= ps->nr) 2058 break; 2059 nr++; 2060 } 2061 if (state == NULL) { 2062 error = EBUSY; 2063 break; 2064 } 2065 secs = time_second; 2066 bcopy(state, &ps->state, sizeof(ps->state)); 2067 strlcpy(ps->state.u.ifname, state->u.s.kif->pfik_name, 2068 sizeof(ps->state.u.ifname)); 2069 ps->state.rule.nr = state->rule.ptr->nr; 2070 ps->state.nat_rule.nr = (state->nat_rule.ptr == NULL) ? 2071 -1 : state->nat_rule.ptr->nr; 2072 ps->state.anchor.nr = (state->anchor.ptr == NULL) ? 2073 -1 : state->anchor.ptr->nr; 2074 ps->state.creation = secs - ps->state.creation; 2075 ps->state.expire = pf_state_expires(state); 2076 if (ps->state.expire > secs) 2077 ps->state.expire -= secs; 2078 else 2079 ps->state.expire = 0; 2080 break; 2081 } 2082 2083 case DIOCGETSTATES: { 2084 struct pfioc_states *ps = (struct pfioc_states *)addr; 2085 struct pf_state *state; 2086 struct pf_state *p, *pstore; 2087 u_int32_t nr = 0; 2088 int space = ps->ps_len; 2089 2090 if (space == 0) { 2091 nr = pf_status.states; 2092 ps->ps_len = sizeof(struct pf_state) * nr; 2093 break; 2094 } 2095 2096#ifdef __FreeBSD__ 2097 PF_UNLOCK(); 2098#endif 2099 pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK); 2100#ifdef __FreeBSD__ 2101 PF_LOCK(); 2102#endif 2103 2104 p = ps->ps_states; 2105 2106 state = TAILQ_FIRST(&state_list); 2107 while (state) { 2108 if (state->timeout != PFTM_UNLINKED) { 2109 int secs = time_second; 2110 2111 if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len) 2112 break; 2113 2114 bcopy(state, pstore, sizeof(*pstore)); 2115 strlcpy(pstore->u.ifname, 2116 state->u.s.kif->pfik_name, 2117 sizeof(pstore->u.ifname)); 2118 pstore->rule.nr = state->rule.ptr->nr; 2119 pstore->nat_rule.nr = (state->nat_rule.ptr == 2120 NULL) ? -1 : state->nat_rule.ptr->nr; 2121 pstore->anchor.nr = (state->anchor.ptr == 2122 NULL) ? -1 : state->anchor.ptr->nr; 2123 pstore->creation = secs - pstore->creation; 2124 pstore->expire = pf_state_expires(state); 2125 if (pstore->expire > secs) 2126 pstore->expire -= secs; 2127 else 2128 pstore->expire = 0; 2129#ifdef __FreeBSD__ 2130 PF_COPYOUT(pstore, p, sizeof(*p), error); 2131#else 2132 error = copyout(pstore, p, sizeof(*p)); 2133#endif 2134 if (error) { 2135 free(pstore, M_TEMP); 2136 goto fail; 2137 } 2138 p++; 2139 nr++; 2140 } 2141 state = TAILQ_NEXT(state, u.s.entry_list); 2142 } 2143 2144 ps->ps_len = sizeof(struct pf_state) * nr; 2145 2146 free(pstore, M_TEMP); 2147 break; 2148 } 2149 2150 case DIOCGETSTATUS: { 2151 struct pf_status *s = (struct pf_status *)addr; 2152 bcopy(&pf_status, s, sizeof(struct pf_status)); 2153 pfi_fill_oldstatus(s); 2154 break; 2155 } 2156 2157 case DIOCSETSTATUSIF: { 2158 struct pfioc_if *pi = (struct pfioc_if *)addr; 2159 2160 if (pi->ifname[0] == 0) { 2161 bzero(pf_status.ifname, IFNAMSIZ); 2162 break; 2163 } 2164 if (ifunit(pi->ifname) == NULL) { 2165 error = EINVAL; 2166 break; 2167 } 2168 strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ); 2169 break; 2170 } 2171 2172 case DIOCCLRSTATUS: { 2173 bzero(pf_status.counters, sizeof(pf_status.counters)); 2174 bzero(pf_status.fcounters, sizeof(pf_status.fcounters)); 2175 bzero(pf_status.scounters, sizeof(pf_status.scounters)); 2176 pf_status.since = time_second; 2177 if (*pf_status.ifname) 2178 pfi_clr_istats(pf_status.ifname); 2179 break; 2180 } 2181 2182 case DIOCNATLOOK: { 2183 struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; 2184 struct pf_state *state; 2185 struct pf_state_cmp key; 2186 int m = 0, direction = pnl->direction; 2187 2188 key.af = pnl->af; 2189 key.proto = pnl->proto; 2190 2191 if (!pnl->proto || 2192 PF_AZERO(&pnl->saddr, pnl->af) || 2193 PF_AZERO(&pnl->daddr, pnl->af) || 2194 ((pnl->proto == IPPROTO_TCP || 2195 pnl->proto == IPPROTO_UDP) && 2196 (!pnl->dport || !pnl->sport))) 2197 error = EINVAL; 2198 else { 2199 /* 2200 * userland gives us source and dest of connection, 2201 * reverse the lookup so we ask for what happens with 2202 * the return traffic, enabling us to find it in the 2203 * state tree. 2204 */ 2205 if (direction == PF_IN) { 2206 PF_ACPY(&key.ext.addr, &pnl->daddr, pnl->af); 2207 key.ext.port = pnl->dport; 2208 PF_ACPY(&key.gwy.addr, &pnl->saddr, pnl->af); 2209 key.gwy.port = pnl->sport; 2210 state = pf_find_state_all(&key, PF_EXT_GWY, &m); 2211 } else { 2212 PF_ACPY(&key.lan.addr, &pnl->daddr, pnl->af); 2213 key.lan.port = pnl->dport; 2214 PF_ACPY(&key.ext.addr, &pnl->saddr, pnl->af); 2215 key.ext.port = pnl->sport; 2216 state = pf_find_state_all(&key, PF_LAN_EXT, &m); 2217 } 2218 if (m > 1) 2219 error = E2BIG; /* more than one state */ 2220 else if (state != NULL) { 2221 if (direction == PF_IN) { 2222 PF_ACPY(&pnl->rsaddr, &state->lan.addr, 2223 state->af); 2224 pnl->rsport = state->lan.port; 2225 PF_ACPY(&pnl->rdaddr, &pnl->daddr, 2226 pnl->af); 2227 pnl->rdport = pnl->dport; 2228 } else { 2229 PF_ACPY(&pnl->rdaddr, &state->gwy.addr, 2230 state->af); 2231 pnl->rdport = state->gwy.port; 2232 PF_ACPY(&pnl->rsaddr, &pnl->saddr, 2233 pnl->af); 2234 pnl->rsport = pnl->sport; 2235 } 2236 } else 2237 error = ENOENT; 2238 } 2239 break; 2240 } 2241 2242 case DIOCSETTIMEOUT: { 2243 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 2244 int old; 2245 2246 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX || 2247 pt->seconds < 0) { 2248 error = EINVAL; 2249 goto fail; 2250 } 2251 old = pf_default_rule.timeout[pt->timeout]; 2252 if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0) 2253 pt->seconds = 1; 2254 pf_default_rule.timeout[pt->timeout] = pt->seconds; 2255 if (pt->timeout == PFTM_INTERVAL && pt->seconds < old) 2256 wakeup(pf_purge_thread); 2257 pt->seconds = old; 2258 break; 2259 } 2260 2261 case DIOCGETTIMEOUT: { 2262 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 2263 2264 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) { 2265 error = EINVAL; 2266 goto fail; 2267 } 2268 pt->seconds = pf_default_rule.timeout[pt->timeout]; 2269 break; 2270 } 2271 2272 case DIOCGETLIMIT: { 2273 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 2274 2275 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { 2276 error = EINVAL; 2277 goto fail; 2278 } 2279 pl->limit = pf_pool_limits[pl->index].limit; 2280 break; 2281 } 2282 2283 case DIOCSETLIMIT: { 2284 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 2285 int old_limit; 2286 2287 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX || 2288 pf_pool_limits[pl->index].pp == NULL) { 2289 error = EINVAL; 2290 goto fail; 2291 } 2292#ifdef __FreeBSD__ 2293 uma_zone_set_max(pf_pool_limits[pl->index].pp, pl->limit); 2294#else 2295 if (pool_sethardlimit(pf_pool_limits[pl->index].pp, 2296 pl->limit, NULL, 0) != 0) { 2297 error = EBUSY; 2298 goto fail; 2299 } 2300#endif 2301 old_limit = pf_pool_limits[pl->index].limit; 2302 pf_pool_limits[pl->index].limit = pl->limit; 2303 pl->limit = old_limit; 2304 break; 2305 } 2306 2307 case DIOCSETDEBUG: { 2308 u_int32_t *level = (u_int32_t *)addr; 2309 2310 pf_status.debug = *level; 2311 break; 2312 } 2313 2314 case DIOCCLRRULECTRS: { 2315 /* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */ 2316 struct pf_ruleset *ruleset = &pf_main_ruleset; 2317 struct pf_rule *rule; 2318 2319 TAILQ_FOREACH(rule, 2320 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) { 2321 rule->evaluations = 0; 2322 rule->packets[0] = rule->packets[1] = 0; 2323 rule->bytes[0] = rule->bytes[1] = 0; 2324 } 2325 break; 2326 } 2327 2328#ifdef __FreeBSD__ 2329 case DIOCGIFSPEED: { 2330 struct pf_ifspeed *psp = (struct pf_ifspeed *)addr; 2331 struct pf_ifspeed ps; 2332 struct ifnet *ifp; 2333 2334 if (psp->ifname[0] != 0) { 2335 /* Can we completely trust user-land? */ 2336 strlcpy(ps.ifname, psp->ifname, IFNAMSIZ); 2337 ifp = ifunit(ps.ifname); 2338 if (ifp != NULL) 2339 psp->baudrate = ifp->if_baudrate; 2340 else 2341 error = EINVAL; 2342 } else 2343 error = EINVAL; 2344 break; 2345 } 2346#endif /* __FreeBSD__ */ 2347 2348#ifdef ALTQ 2349 case DIOCSTARTALTQ: { 2350 struct pf_altq *altq; 2351 2352 /* enable all altq interfaces on active list */ 2353 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 2354#ifdef __FreeBSD__ 2355 if (altq->qname[0] == 0 && (altq->local_flags & 2356 PFALTQ_FLAG_IF_REMOVED) == 0) { 2357#else 2358 if (altq->qname[0] == 0) { 2359#endif 2360 error = pf_enable_altq(altq); 2361 if (error != 0) 2362 break; 2363 } 2364 } 2365 if (error == 0) 2366 pf_altq_running = 1; 2367 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n")); 2368 break; 2369 } 2370 2371 case DIOCSTOPALTQ: { 2372 struct pf_altq *altq; 2373 2374 /* disable all altq interfaces on active list */ 2375 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 2376#ifdef __FreeBSD__ 2377 if (altq->qname[0] == 0 && (altq->local_flags & 2378 PFALTQ_FLAG_IF_REMOVED) == 0) { 2379#else 2380 if (altq->qname[0] == 0) { 2381#endif 2382 error = pf_disable_altq(altq); 2383 if (error != 0) 2384 break; 2385 } 2386 } 2387 if (error == 0) 2388 pf_altq_running = 0; 2389 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n")); 2390 break; 2391 } 2392 2393 case DIOCADDALTQ: { 2394 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2395 struct pf_altq *altq, *a; 2396 2397 if (pa->ticket != ticket_altqs_inactive) { 2398 error = EBUSY; 2399 break; 2400 } 2401 altq = pool_get(&pf_altq_pl, PR_NOWAIT); 2402 if (altq == NULL) { 2403 error = ENOMEM; 2404 break; 2405 } 2406 bcopy(&pa->altq, altq, sizeof(struct pf_altq)); 2407#ifdef __FreeBSD__ 2408 altq->local_flags = 0; 2409#endif 2410 2411 /* 2412 * if this is for a queue, find the discipline and 2413 * copy the necessary fields 2414 */ 2415 if (altq->qname[0] != 0) { 2416 if ((altq->qid = pf_qname2qid(altq->qname)) == 0) { 2417 error = EBUSY; 2418 pool_put(&pf_altq_pl, altq); 2419 break; 2420 } 2421 altq->altq_disc = NULL; 2422 TAILQ_FOREACH(a, pf_altqs_inactive, entries) { 2423 if (strncmp(a->ifname, altq->ifname, 2424 IFNAMSIZ) == 0 && a->qname[0] == 0) { 2425 altq->altq_disc = a->altq_disc; 2426 break; 2427 } 2428 } 2429 } 2430 2431#ifdef __FreeBSD__ 2432 struct ifnet *ifp; 2433 2434 if ((ifp = ifunit(altq->ifname)) == NULL) { 2435 altq->local_flags |= PFALTQ_FLAG_IF_REMOVED; 2436 } else { 2437 PF_UNLOCK(); 2438#endif 2439 error = altq_add(altq); 2440#ifdef __FreeBSD__ 2441 PF_LOCK(); 2442 } 2443#endif 2444 if (error) { 2445 pool_put(&pf_altq_pl, altq); 2446 break; 2447 } 2448 2449 TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries); 2450 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 2451 break; 2452 } 2453 2454 case DIOCGETALTQS: { 2455 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2456 struct pf_altq *altq; 2457 2458 pa->nr = 0; 2459 TAILQ_FOREACH(altq, pf_altqs_active, entries) 2460 pa->nr++; 2461 pa->ticket = ticket_altqs_active; 2462 break; 2463 } 2464 2465 case DIOCGETALTQ: { 2466 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2467 struct pf_altq *altq; 2468 u_int32_t nr; 2469 2470 if (pa->ticket != ticket_altqs_active) { 2471 error = EBUSY; 2472 break; 2473 } 2474 nr = 0; 2475 altq = TAILQ_FIRST(pf_altqs_active); 2476 while ((altq != NULL) && (nr < pa->nr)) { 2477 altq = TAILQ_NEXT(altq, entries); 2478 nr++; 2479 } 2480 if (altq == NULL) { 2481 error = EBUSY; 2482 break; 2483 } 2484 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 2485 break; 2486 } 2487 2488 case DIOCCHANGEALTQ: 2489 /* CHANGEALTQ not supported yet! */ 2490 error = ENODEV; 2491 break; 2492 2493 case DIOCGETQSTATS: { 2494 struct pfioc_qstats *pq = (struct pfioc_qstats *)addr; 2495 struct pf_altq *altq; 2496 u_int32_t nr; 2497 int nbytes; 2498 2499 if (pq->ticket != ticket_altqs_active) { 2500 error = EBUSY; 2501 break; 2502 } 2503 nbytes = pq->nbytes; 2504 nr = 0; 2505 altq = TAILQ_FIRST(pf_altqs_active); 2506 while ((altq != NULL) && (nr < pq->nr)) { 2507 altq = TAILQ_NEXT(altq, entries); 2508 nr++; 2509 } 2510 if (altq == NULL) { 2511 error = EBUSY; 2512 break; 2513 } 2514#ifdef __FreeBSD__ 2515 if ((altq->local_flags & PFALTQ_FLAG_IF_REMOVED) != 0) { 2516 error = ENXIO; 2517 break; 2518 } 2519 PF_UNLOCK(); 2520#endif 2521 error = altq_getqstats(altq, pq->buf, &nbytes); 2522#ifdef __FreeBSD__ 2523 PF_LOCK(); 2524#endif 2525 if (error == 0) { 2526 pq->scheduler = altq->scheduler; 2527 pq->nbytes = nbytes; 2528 } 2529 break; 2530 } 2531#endif /* ALTQ */ 2532 2533 case DIOCBEGINADDRS: { 2534 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2535 2536 pf_empty_pool(&pf_pabuf); 2537 pp->ticket = ++ticket_pabuf; 2538 break; 2539 } 2540 2541 case DIOCADDADDR: { 2542 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2543 2544 if (pp->ticket != ticket_pabuf) { 2545 error = EBUSY; 2546 break; 2547 } 2548#ifndef INET 2549 if (pp->af == AF_INET) { 2550 error = EAFNOSUPPORT; 2551 break; 2552 } 2553#endif /* INET */ 2554#ifndef INET6 2555 if (pp->af == AF_INET6) { 2556 error = EAFNOSUPPORT; 2557 break; 2558 } 2559#endif /* INET6 */ 2560 if (pp->addr.addr.type != PF_ADDR_ADDRMASK && 2561 pp->addr.addr.type != PF_ADDR_DYNIFTL && 2562 pp->addr.addr.type != PF_ADDR_TABLE) { 2563 error = EINVAL; 2564 break; 2565 } 2566 pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT); 2567 if (pa == NULL) { 2568 error = ENOMEM; 2569 break; 2570 } 2571 bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr)); 2572 if (pa->ifname[0]) { 2573 pa->kif = pfi_kif_get(pa->ifname); 2574 if (pa->kif == NULL) { 2575 pool_put(&pf_pooladdr_pl, pa); 2576 error = EINVAL; 2577 break; 2578 } 2579 pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE); 2580 } 2581 if (pfi_dynaddr_setup(&pa->addr, pp->af)) { 2582 pfi_dynaddr_remove(&pa->addr); 2583 pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE); 2584 pool_put(&pf_pooladdr_pl, pa); 2585 error = EINVAL; 2586 break; 2587 } 2588 TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries); 2589 break; 2590 } 2591 2592 case DIOCGETADDRS: { 2593 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2594 2595 pp->nr = 0; 2596 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, 2597 pp->r_num, 0, 1, 0); 2598 if (pool == NULL) { 2599 error = EBUSY; 2600 break; 2601 } 2602 TAILQ_FOREACH(pa, &pool->list, entries) 2603 pp->nr++; 2604 break; 2605 } 2606 2607 case DIOCGETADDR: { 2608 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2609 u_int32_t nr = 0; 2610 2611 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, 2612 pp->r_num, 0, 1, 1); 2613 if (pool == NULL) { 2614 error = EBUSY; 2615 break; 2616 } 2617 pa = TAILQ_FIRST(&pool->list); 2618 while ((pa != NULL) && (nr < pp->nr)) { 2619 pa = TAILQ_NEXT(pa, entries); 2620 nr++; 2621 } 2622 if (pa == NULL) { 2623 error = EBUSY; 2624 break; 2625 } 2626 bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr)); 2627 pfi_dynaddr_copyout(&pp->addr.addr); 2628 pf_tbladdr_copyout(&pp->addr.addr); 2629 pf_rtlabel_copyout(&pp->addr.addr); 2630 break; 2631 } 2632 2633 case DIOCCHANGEADDR: { 2634 struct pfioc_pooladdr *pca = (struct pfioc_pooladdr *)addr; 2635 struct pf_pooladdr *oldpa = NULL, *newpa = NULL; 2636 struct pf_ruleset *ruleset; 2637 2638 if (pca->action < PF_CHANGE_ADD_HEAD || 2639 pca->action > PF_CHANGE_REMOVE) { 2640 error = EINVAL; 2641 break; 2642 } 2643 if (pca->addr.addr.type != PF_ADDR_ADDRMASK && 2644 pca->addr.addr.type != PF_ADDR_DYNIFTL && 2645 pca->addr.addr.type != PF_ADDR_TABLE) { 2646 error = EINVAL; 2647 break; 2648 } 2649 2650 ruleset = pf_find_ruleset(pca->anchor); 2651 if (ruleset == NULL) { 2652 error = EBUSY; 2653 break; 2654 } 2655 pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action, 2656 pca->r_num, pca->r_last, 1, 1); 2657 if (pool == NULL) { 2658 error = EBUSY; 2659 break; 2660 } 2661 if (pca->action != PF_CHANGE_REMOVE) { 2662 newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT); 2663 if (newpa == NULL) { 2664 error = ENOMEM; 2665 break; 2666 } 2667 bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr)); 2668#ifndef INET 2669 if (pca->af == AF_INET) { 2670 pool_put(&pf_pooladdr_pl, newpa); 2671 error = EAFNOSUPPORT; 2672 break; 2673 } 2674#endif /* INET */ 2675#ifndef INET6 2676 if (pca->af == AF_INET6) { 2677 pool_put(&pf_pooladdr_pl, newpa); 2678 error = EAFNOSUPPORT; 2679 break; 2680 } 2681#endif /* INET6 */ 2682 if (newpa->ifname[0]) { 2683 newpa->kif = pfi_kif_get(newpa->ifname); 2684 if (newpa->kif == NULL) { 2685 pool_put(&pf_pooladdr_pl, newpa); 2686 error = EINVAL; 2687 break; 2688 } 2689 pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE); 2690 } else 2691 newpa->kif = NULL; 2692 if (pfi_dynaddr_setup(&newpa->addr, pca->af) || 2693 pf_tbladdr_setup(ruleset, &newpa->addr)) { 2694 pfi_dynaddr_remove(&newpa->addr); 2695 pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE); 2696 pool_put(&pf_pooladdr_pl, newpa); 2697 error = EINVAL; 2698 break; 2699 } 2700 } 2701 2702 if (pca->action == PF_CHANGE_ADD_HEAD) 2703 oldpa = TAILQ_FIRST(&pool->list); 2704 else if (pca->action == PF_CHANGE_ADD_TAIL) 2705 oldpa = TAILQ_LAST(&pool->list, pf_palist); 2706 else { 2707 int i = 0; 2708 2709 oldpa = TAILQ_FIRST(&pool->list); 2710 while ((oldpa != NULL) && (i < pca->nr)) { 2711 oldpa = TAILQ_NEXT(oldpa, entries); 2712 i++; 2713 } 2714 if (oldpa == NULL) { 2715 error = EINVAL; 2716 break; 2717 } 2718 } 2719 2720 if (pca->action == PF_CHANGE_REMOVE) { 2721 TAILQ_REMOVE(&pool->list, oldpa, entries); 2722 pfi_dynaddr_remove(&oldpa->addr); 2723 pf_tbladdr_remove(&oldpa->addr); 2724 pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE); 2725 pool_put(&pf_pooladdr_pl, oldpa); 2726 } else { 2727 if (oldpa == NULL) 2728 TAILQ_INSERT_TAIL(&pool->list, newpa, entries); 2729 else if (pca->action == PF_CHANGE_ADD_HEAD || 2730 pca->action == PF_CHANGE_ADD_BEFORE) 2731 TAILQ_INSERT_BEFORE(oldpa, newpa, entries); 2732 else 2733 TAILQ_INSERT_AFTER(&pool->list, oldpa, 2734 newpa, entries); 2735 } 2736 2737 pool->cur = TAILQ_FIRST(&pool->list); 2738 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, 2739 pca->af); 2740 break; 2741 } 2742 2743 case DIOCGETRULESETS: { 2744 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 2745 struct pf_ruleset *ruleset; 2746 struct pf_anchor *anchor; 2747 2748 pr->path[sizeof(pr->path) - 1] = 0; 2749 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) { 2750 error = EINVAL; 2751 break; 2752 } 2753 pr->nr = 0; 2754 if (ruleset->anchor == NULL) { 2755 /* XXX kludge for pf_main_ruleset */ 2756 RB_FOREACH(anchor, pf_anchor_global, &pf_anchors) 2757 if (anchor->parent == NULL) 2758 pr->nr++; 2759 } else { 2760 RB_FOREACH(anchor, pf_anchor_node, 2761 &ruleset->anchor->children) 2762 pr->nr++; 2763 } 2764 break; 2765 } 2766 2767 case DIOCGETRULESET: { 2768 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 2769 struct pf_ruleset *ruleset; 2770 struct pf_anchor *anchor; 2771 u_int32_t nr = 0; 2772 2773 pr->path[sizeof(pr->path) - 1] = 0; 2774 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) { 2775 error = EINVAL; 2776 break; 2777 } 2778 pr->name[0] = 0; 2779 if (ruleset->anchor == NULL) { 2780 /* XXX kludge for pf_main_ruleset */ 2781 RB_FOREACH(anchor, pf_anchor_global, &pf_anchors) 2782 if (anchor->parent == NULL && nr++ == pr->nr) { 2783 strlcpy(pr->name, anchor->name, 2784 sizeof(pr->name)); 2785 break; 2786 } 2787 } else { 2788 RB_FOREACH(anchor, pf_anchor_node, 2789 &ruleset->anchor->children) 2790 if (nr++ == pr->nr) { 2791 strlcpy(pr->name, anchor->name, 2792 sizeof(pr->name)); 2793 break; 2794 } 2795 } 2796 if (!pr->name[0]) 2797 error = EBUSY; 2798 break; 2799 } 2800 2801 case DIOCRCLRTABLES: { 2802 struct pfioc_table *io = (struct pfioc_table *)addr; 2803 2804 if (io->pfrio_esize != 0) { 2805 error = ENODEV; 2806 break; 2807 } 2808 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, 2809 io->pfrio_flags | PFR_FLAG_USERIOCTL); 2810 break; 2811 } 2812 2813 case DIOCRADDTABLES: { 2814 struct pfioc_table *io = (struct pfioc_table *)addr; 2815 2816 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2817 error = ENODEV; 2818 break; 2819 } 2820 error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size, 2821 &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2822 break; 2823 } 2824 2825 case DIOCRDELTABLES: { 2826 struct pfioc_table *io = (struct pfioc_table *)addr; 2827 2828 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2829 error = ENODEV; 2830 break; 2831 } 2832 error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size, 2833 &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2834 break; 2835 } 2836 2837 case DIOCRGETTABLES: { 2838 struct pfioc_table *io = (struct pfioc_table *)addr; 2839 2840 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2841 error = ENODEV; 2842 break; 2843 } 2844 error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer, 2845 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2846 break; 2847 } 2848 2849 case DIOCRGETTSTATS: { 2850 struct pfioc_table *io = (struct pfioc_table *)addr; 2851 2852 if (io->pfrio_esize != sizeof(struct pfr_tstats)) { 2853 error = ENODEV; 2854 break; 2855 } 2856 error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer, 2857 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2858 break; 2859 } 2860 2861 case DIOCRCLRTSTATS: { 2862 struct pfioc_table *io = (struct pfioc_table *)addr; 2863 2864 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2865 error = ENODEV; 2866 break; 2867 } 2868 error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size, 2869 &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2870 break; 2871 } 2872 2873 case DIOCRSETTFLAGS: { 2874 struct pfioc_table *io = (struct pfioc_table *)addr; 2875 2876 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2877 error = ENODEV; 2878 break; 2879 } 2880 error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size, 2881 io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange, 2882 &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2883 break; 2884 } 2885 2886 case DIOCRCLRADDRS: { 2887 struct pfioc_table *io = (struct pfioc_table *)addr; 2888 2889 if (io->pfrio_esize != 0) { 2890 error = ENODEV; 2891 break; 2892 } 2893 error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel, 2894 io->pfrio_flags | PFR_FLAG_USERIOCTL); 2895 break; 2896 } 2897 2898 case DIOCRADDADDRS: { 2899 struct pfioc_table *io = (struct pfioc_table *)addr; 2900 2901 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2902 error = ENODEV; 2903 break; 2904 } 2905 error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer, 2906 io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags | 2907 PFR_FLAG_USERIOCTL); 2908 break; 2909 } 2910 2911 case DIOCRDELADDRS: { 2912 struct pfioc_table *io = (struct pfioc_table *)addr; 2913 2914 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2915 error = ENODEV; 2916 break; 2917 } 2918 error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer, 2919 io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags | 2920 PFR_FLAG_USERIOCTL); 2921 break; 2922 } 2923 2924 case DIOCRSETADDRS: { 2925 struct pfioc_table *io = (struct pfioc_table *)addr; 2926 2927 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2928 error = ENODEV; 2929 break; 2930 } 2931 error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer, 2932 io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd, 2933 &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags | 2934 PFR_FLAG_USERIOCTL, 0); 2935 break; 2936 } 2937 2938 case DIOCRGETADDRS: { 2939 struct pfioc_table *io = (struct pfioc_table *)addr; 2940 2941 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2942 error = ENODEV; 2943 break; 2944 } 2945 error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer, 2946 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2947 break; 2948 } 2949 2950 case DIOCRGETASTATS: { 2951 struct pfioc_table *io = (struct pfioc_table *)addr; 2952 2953 if (io->pfrio_esize != sizeof(struct pfr_astats)) { 2954 error = ENODEV; 2955 break; 2956 } 2957 error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer, 2958 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2959 break; 2960 } 2961 2962 case DIOCRCLRASTATS: { 2963 struct pfioc_table *io = (struct pfioc_table *)addr; 2964 2965 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2966 error = ENODEV; 2967 break; 2968 } 2969 error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer, 2970 io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags | 2971 PFR_FLAG_USERIOCTL); 2972 break; 2973 } 2974 2975 case DIOCRTSTADDRS: { 2976 struct pfioc_table *io = (struct pfioc_table *)addr; 2977 2978 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2979 error = ENODEV; 2980 break; 2981 } 2982 error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer, 2983 io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags | 2984 PFR_FLAG_USERIOCTL); 2985 break; 2986 } 2987 2988 case DIOCRINADEFINE: { 2989 struct pfioc_table *io = (struct pfioc_table *)addr; 2990 2991 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2992 error = ENODEV; 2993 break; 2994 } 2995 error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer, 2996 io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr, 2997 io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2998 break; 2999 } 3000 3001 case DIOCOSFPADD: { 3002 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 3003 error = pf_osfp_add(io); 3004 break; 3005 } 3006 3007 case DIOCOSFPGET: { 3008 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 3009 error = pf_osfp_get(io); 3010 break; 3011 } 3012 3013 case DIOCXBEGIN: { 3014 struct pfioc_trans *io = (struct pfioc_trans *)addr; 3015 struct pfioc_trans_e *ioe; 3016 struct pfr_table *table; 3017 int i; 3018 3019 if (io->esize != sizeof(*ioe)) { 3020 error = ENODEV; 3021 goto fail; 3022 } 3023#ifdef __FreeBSD__ 3024 PF_UNLOCK(); 3025#endif 3026 ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe), 3027 M_TEMP, M_WAITOK); 3028 table = (struct pfr_table *)malloc(sizeof(*table), 3029 M_TEMP, M_WAITOK); 3030#ifdef __FreeBSD__ 3031 PF_LOCK(); 3032#endif 3033 for (i = 0; i < io->size; i++) { 3034#ifdef __FreeBSD__ 3035 PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); 3036 if (error) { 3037#else 3038 if (copyin(io->array+i, ioe, sizeof(*ioe))) { 3039#endif 3040 free(table, M_TEMP); 3041 free(ioe, M_TEMP); 3042 error = EFAULT; 3043 goto fail; 3044 } 3045 switch (ioe->rs_num) { 3046#ifdef ALTQ 3047 case PF_RULESET_ALTQ: 3048 if (ioe->anchor[0]) { 3049 free(table, M_TEMP); 3050 free(ioe, M_TEMP); 3051 error = EINVAL; 3052 goto fail; 3053 } 3054 if ((error = pf_begin_altq(&ioe->ticket))) { 3055 free(table, M_TEMP); 3056 free(ioe, M_TEMP); 3057 goto fail; 3058 } 3059 break; 3060#endif /* ALTQ */ 3061 case PF_RULESET_TABLE: 3062 bzero(table, sizeof(*table)); 3063 strlcpy(table->pfrt_anchor, ioe->anchor, 3064 sizeof(table->pfrt_anchor)); 3065 if ((error = pfr_ina_begin(table, 3066 &ioe->ticket, NULL, 0))) { 3067 free(table, M_TEMP); 3068 free(ioe, M_TEMP); 3069 goto fail; 3070 } 3071 break; 3072 default: 3073 if ((error = pf_begin_rules(&ioe->ticket, 3074 ioe->rs_num, ioe->anchor))) { 3075 free(table, M_TEMP); 3076 free(ioe, M_TEMP); 3077 goto fail; 3078 } 3079 break; 3080 } 3081#ifdef __FreeBSD__ 3082 PF_COPYOUT(ioe, io->array+i, sizeof(io->array[i]), 3083 error); 3084 if (error) { 3085#else 3086 if (copyout(ioe, io->array+i, sizeof(io->array[i]))) { 3087#endif 3088 free(table, M_TEMP); 3089 free(ioe, M_TEMP); 3090 error = EFAULT; 3091 goto fail; 3092 } 3093 } 3094 free(table, M_TEMP); 3095 free(ioe, M_TEMP); 3096 break; 3097 } 3098 3099 case DIOCXROLLBACK: { 3100 struct pfioc_trans *io = (struct pfioc_trans *)addr; 3101 struct pfioc_trans_e *ioe; 3102 struct pfr_table *table; 3103 int i; 3104 3105 if (io->esize != sizeof(*ioe)) { 3106 error = ENODEV; 3107 goto fail; 3108 } 3109#ifdef __FreeBSD__ 3110 PF_UNLOCK(); 3111#endif 3112 ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe), 3113 M_TEMP, M_WAITOK); 3114 table = (struct pfr_table *)malloc(sizeof(*table), 3115 M_TEMP, M_WAITOK); 3116#ifdef __FreeBSD__ 3117 PF_LOCK(); 3118#endif 3119 for (i = 0; i < io->size; i++) { 3120#ifdef __FreeBSD__ 3121 PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); 3122 if (error) { 3123#else 3124 if (copyin(io->array+i, ioe, sizeof(*ioe))) { 3125#endif 3126 free(table, M_TEMP); 3127 free(ioe, M_TEMP); 3128 error = EFAULT; 3129 goto fail; 3130 } 3131 switch (ioe->rs_num) { 3132#ifdef ALTQ 3133 case PF_RULESET_ALTQ: 3134 if (ioe->anchor[0]) { 3135 free(table, M_TEMP); 3136 free(ioe, M_TEMP); 3137 error = EINVAL; 3138 goto fail; 3139 } 3140 if ((error = pf_rollback_altq(ioe->ticket))) { 3141 free(table, M_TEMP); 3142 free(ioe, M_TEMP); 3143 goto fail; /* really bad */ 3144 } 3145 break; 3146#endif /* ALTQ */ 3147 case PF_RULESET_TABLE: 3148 bzero(table, sizeof(*table)); 3149 strlcpy(table->pfrt_anchor, ioe->anchor, 3150 sizeof(table->pfrt_anchor)); 3151 if ((error = pfr_ina_rollback(table, 3152 ioe->ticket, NULL, 0))) { 3153 free(table, M_TEMP); 3154 free(ioe, M_TEMP); 3155 goto fail; /* really bad */ 3156 } 3157 break; 3158 default: 3159 if ((error = pf_rollback_rules(ioe->ticket, 3160 ioe->rs_num, ioe->anchor))) { 3161 free(table, M_TEMP); 3162 free(ioe, M_TEMP); 3163 goto fail; /* really bad */ 3164 } 3165 break; 3166 } 3167 } 3168 free(table, M_TEMP); 3169 free(ioe, M_TEMP); 3170 break; 3171 } 3172 3173 case DIOCXCOMMIT: { 3174 struct pfioc_trans *io = (struct pfioc_trans *)addr; 3175 struct pfioc_trans_e *ioe; 3176 struct pfr_table *table; 3177 struct pf_ruleset *rs; 3178 int i; 3179 3180 if (io->esize != sizeof(*ioe)) { 3181 error = ENODEV; 3182 goto fail; 3183 } 3184#ifdef __FreeBSD__ 3185 PF_UNLOCK(); 3186#endif 3187 ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe), 3188 M_TEMP, M_WAITOK); 3189 table = (struct pfr_table *)malloc(sizeof(*table), 3190 M_TEMP, M_WAITOK); 3191#ifdef __FreeBSD__ 3192 PF_LOCK(); 3193#endif 3194 /* first makes sure everything will succeed */ 3195 for (i = 0; i < io->size; i++) { 3196#ifdef __FreeBSD__ 3197 PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); 3198 if (error) { 3199#else 3200 if (copyin(io->array+i, ioe, sizeof(*ioe))) { 3201#endif 3202 free(table, M_TEMP); 3203 free(ioe, M_TEMP); 3204 error = EFAULT; 3205 goto fail; 3206 } 3207 switch (ioe->rs_num) { 3208#ifdef ALTQ 3209 case PF_RULESET_ALTQ: 3210 if (ioe->anchor[0]) { 3211 free(table, M_TEMP); 3212 free(ioe, M_TEMP); 3213 error = EINVAL; 3214 goto fail; 3215 } 3216 if (!altqs_inactive_open || ioe->ticket != 3217 ticket_altqs_inactive) { 3218 free(table, M_TEMP); 3219 free(ioe, M_TEMP); 3220 error = EBUSY; 3221 goto fail; 3222 } 3223 break; 3224#endif /* ALTQ */ 3225 case PF_RULESET_TABLE: 3226 rs = pf_find_ruleset(ioe->anchor); 3227 if (rs == NULL || !rs->topen || ioe->ticket != 3228 rs->tticket) { 3229 free(table, M_TEMP); 3230 free(ioe, M_TEMP); 3231 error = EBUSY; 3232 goto fail; 3233 } 3234 break; 3235 default: 3236 if (ioe->rs_num < 0 || ioe->rs_num >= 3237 PF_RULESET_MAX) { 3238 free(table, M_TEMP); 3239 free(ioe, M_TEMP); 3240 error = EINVAL; 3241 goto fail; 3242 } 3243 rs = pf_find_ruleset(ioe->anchor); 3244 if (rs == NULL || 3245 !rs->rules[ioe->rs_num].inactive.open || 3246 rs->rules[ioe->rs_num].inactive.ticket != 3247 ioe->ticket) { 3248 free(table, M_TEMP); 3249 free(ioe, M_TEMP); 3250 error = EBUSY; 3251 goto fail; 3252 } 3253 break; 3254 } 3255 } 3256 /* now do the commit - no errors should happen here */ 3257 for (i = 0; i < io->size; i++) { 3258#ifdef __FreeBSD__ 3259 PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); 3260 if (error) { 3261#else 3262 if (copyin(io->array+i, ioe, sizeof(*ioe))) { 3263#endif 3264 free(table, M_TEMP); 3265 free(ioe, M_TEMP); 3266 error = EFAULT; 3267 goto fail; 3268 } 3269 switch (ioe->rs_num) { 3270#ifdef ALTQ 3271 case PF_RULESET_ALTQ: 3272 if ((error = pf_commit_altq(ioe->ticket))) { 3273 free(table, M_TEMP); 3274 free(ioe, M_TEMP); 3275 goto fail; /* really bad */ 3276 } 3277 break; 3278#endif /* ALTQ */ 3279 case PF_RULESET_TABLE: 3280 bzero(table, sizeof(*table)); 3281 strlcpy(table->pfrt_anchor, ioe->anchor, 3282 sizeof(table->pfrt_anchor)); 3283 if ((error = pfr_ina_commit(table, ioe->ticket, 3284 NULL, NULL, 0))) { 3285 free(table, M_TEMP); 3286 free(ioe, M_TEMP); 3287 goto fail; /* really bad */ 3288 } 3289 break; 3290 default: 3291 if ((error = pf_commit_rules(ioe->ticket, 3292 ioe->rs_num, ioe->anchor))) { 3293 free(table, M_TEMP); 3294 free(ioe, M_TEMP); 3295 goto fail; /* really bad */ 3296 } 3297 break; 3298 } 3299 } 3300 free(table, M_TEMP); 3301 free(ioe, M_TEMP); 3302 break; 3303 } 3304 3305 case DIOCGETSRCNODES: { 3306 struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr; 3307 struct pf_src_node *n, *p, *pstore; 3308 u_int32_t nr = 0; 3309 int space = psn->psn_len; 3310 3311 if (space == 0) { 3312 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) 3313 nr++; 3314 psn->psn_len = sizeof(struct pf_src_node) * nr; 3315 break; 3316 } 3317 3318#ifdef __FreeBSD__ 3319 PF_UNLOCK(); 3320#endif 3321 pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK); 3322#ifdef __FreeBSD__ 3323 PF_LOCK(); 3324#endif 3325 3326 p = psn->psn_src_nodes; 3327 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { 3328 int secs = time_second, diff; 3329 3330 if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len) 3331 break; 3332 3333 bcopy(n, pstore, sizeof(*pstore)); 3334 if (n->rule.ptr != NULL) 3335 pstore->rule.nr = n->rule.ptr->nr; 3336 pstore->creation = secs - pstore->creation; 3337 if (pstore->expire > secs) 3338 pstore->expire -= secs; 3339 else 3340 pstore->expire = 0; 3341 3342 /* adjust the connection rate estimate */ 3343 diff = secs - n->conn_rate.last; 3344 if (diff >= n->conn_rate.seconds) 3345 pstore->conn_rate.count = 0; 3346 else 3347 pstore->conn_rate.count -= 3348 n->conn_rate.count * diff / 3349 n->conn_rate.seconds; 3350 3351#ifdef __FreeBSD__ 3352 PF_COPYOUT(pstore, p, sizeof(*p), error); 3353#else 3354 error = copyout(pstore, p, sizeof(*p)); 3355#endif 3356 if (error) { 3357 free(pstore, M_TEMP); 3358 goto fail; 3359 } 3360 p++; 3361 nr++; 3362 } 3363 psn->psn_len = sizeof(struct pf_src_node) * nr; 3364 3365 free(pstore, M_TEMP); 3366 break; 3367 } 3368 3369 case DIOCCLRSRCNODES: { 3370 struct pf_src_node *n; 3371 struct pf_state *state; 3372 3373 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 3374 state->src_node = NULL; 3375 state->nat_src_node = NULL; 3376 } 3377 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { 3378 n->expire = 1; 3379 n->states = 0; 3380 } 3381 pf_purge_expired_src_nodes(1); 3382 pf_status.src_nodes = 0; 3383 break; 3384 } 3385 3386 case DIOCKILLSRCNODES: { 3387 struct pf_src_node *sn; 3388 struct pf_state *s; 3389 struct pfioc_src_node_kill *psnk = \ 3390 (struct pfioc_src_node_kill *) addr; 3391 int killed = 0; 3392 3393 RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) { 3394 if (PF_MATCHA(psnk->psnk_src.neg, \ 3395 &psnk->psnk_src.addr.v.a.addr, \ 3396 &psnk->psnk_src.addr.v.a.mask, \ 3397 &sn->addr, sn->af) && 3398 PF_MATCHA(psnk->psnk_dst.neg, \ 3399 &psnk->psnk_dst.addr.v.a.addr, \ 3400 &psnk->psnk_dst.addr.v.a.mask, \ 3401 &sn->raddr, sn->af)) { 3402 /* Handle state to src_node linkage */ 3403 if (sn->states != 0) { 3404 RB_FOREACH(s, pf_state_tree_id, 3405 &tree_id) { 3406 if (s->src_node == sn) 3407 s->src_node = NULL; 3408 if (s->nat_src_node == sn) 3409 s->nat_src_node = NULL; 3410 } 3411 sn->states = 0; 3412 } 3413 sn->expire = 1; 3414 killed++; 3415 } 3416 } 3417 3418 if (killed > 0) 3419 pf_purge_expired_src_nodes(1); 3420 3421 psnk->psnk_af = killed; 3422 break; 3423 } 3424 3425 case DIOCSETHOSTID: { 3426 u_int32_t *hostid = (u_int32_t *)addr; 3427 3428 if (*hostid == 0) 3429 pf_status.hostid = arc4random(); 3430 else 3431 pf_status.hostid = *hostid; 3432 break; 3433 } 3434 3435 case DIOCOSFPFLUSH: 3436 pf_osfp_flush(); 3437 break; 3438 3439 case DIOCIGETIFACES: { 3440 struct pfioc_iface *io = (struct pfioc_iface *)addr; 3441 3442 if (io->pfiio_esize != sizeof(struct pfi_kif)) { 3443 error = ENODEV; 3444 break; 3445 } 3446 error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer, 3447 &io->pfiio_size); 3448 break; 3449 } 3450 3451 case DIOCSETIFFLAG: { 3452 struct pfioc_iface *io = (struct pfioc_iface *)addr; 3453 3454 error = pfi_set_flags(io->pfiio_name, io->pfiio_flags); 3455 break; 3456 } 3457 3458 case DIOCCLRIFFLAG: { 3459 struct pfioc_iface *io = (struct pfioc_iface *)addr; 3460 3461 error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags); 3462 break; 3463 } 3464 3465 default: 3466 error = ENODEV; 3467 break; 3468 } 3469fail: 3470#ifdef __FreeBSD__ 3471 PF_UNLOCK(); 3472 3473 if (flags & FWRITE) 3474 sx_xunlock(&pf_consistency_lock); 3475 else 3476 sx_sunlock(&pf_consistency_lock); 3477#else 3478 splx(s); 3479 /* XXX: Lock order? */ 3480 if (flags & FWRITE) 3481 rw_exit_write(&pf_consistency_lock); 3482 else 3483 rw_exit_read(&pf_consistency_lock); 3484#endif 3485 return (error); 3486} 3487 3488#ifdef __FreeBSD__ 3489/* 3490 * XXX - Check for version missmatch!!! 3491 */ 3492static void 3493pf_clear_states(void) 3494{ 3495 struct pf_state *state; 3496 3497 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 3498 state->timeout = PFTM_PURGE; 3499#if NPFSYNC 3500 /* don't send out individual delete messages */ 3501 state->sync_flags = PFSTATE_NOSYNC; 3502#endif 3503 pf_unlink_state(state); 3504 } 3505 3506#if 0 /* NPFSYNC */ 3507/* 3508 * XXX This is called on module unload, we do not want to sync that over? */ 3509 */ 3510 pfsync_clear_states(pf_status.hostid, psk->psk_ifname); 3511#endif 3512} 3513 3514static int 3515pf_clear_tables(void) 3516{ 3517 struct pfioc_table io; 3518 int error; 3519 3520 bzero(&io, sizeof(io)); 3521 3522 error = pfr_clr_tables(&io.pfrio_table, &io.pfrio_ndel, 3523 io.pfrio_flags); 3524 3525 return (error); 3526} 3527 3528static void 3529pf_clear_srcnodes(void) 3530{ 3531 struct pf_src_node *n; 3532 struct pf_state *state; 3533 3534 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 3535 state->src_node = NULL; 3536 state->nat_src_node = NULL; 3537 } 3538 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { 3539 n->expire = 1; 3540 n->states = 0; 3541 } 3542} 3543/* 3544 * XXX - Check for version missmatch!!! 3545 */ 3546 3547/* 3548 * Duplicate pfctl -Fa operation to get rid of as much as we can. 3549 */ 3550static int 3551shutdown_pf(void) 3552{ 3553 int error = 0; 3554 u_int32_t t[5]; 3555 char nn = '\0'; 3556 3557 pf_status.running = 0; 3558 do { 3559 if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn)) 3560 != 0) { 3561 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: SCRUB\n")); 3562 break; 3563 } 3564 if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn)) 3565 != 0) { 3566 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: FILTER\n")); 3567 break; /* XXX: rollback? */ 3568 } 3569 if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn)) 3570 != 0) { 3571 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: NAT\n")); 3572 break; /* XXX: rollback? */ 3573 } 3574 if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn)) 3575 != 0) { 3576 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: BINAT\n")); 3577 break; /* XXX: rollback? */ 3578 } 3579 if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn)) 3580 != 0) { 3581 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: RDR\n")); 3582 break; /* XXX: rollback? */ 3583 } 3584 3585 /* XXX: these should always succeed here */ 3586 pf_commit_rules(t[0], PF_RULESET_SCRUB, &nn); 3587 pf_commit_rules(t[1], PF_RULESET_FILTER, &nn); 3588 pf_commit_rules(t[2], PF_RULESET_NAT, &nn); 3589 pf_commit_rules(t[3], PF_RULESET_BINAT, &nn); 3590 pf_commit_rules(t[4], PF_RULESET_RDR, &nn); 3591 3592 if ((error = pf_clear_tables()) != 0) 3593 break; 3594 3595#ifdef ALTQ 3596 if ((error = pf_begin_altq(&t[0])) != 0) { 3597 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n")); 3598 break; 3599 } 3600 pf_commit_altq(t[0]); 3601#endif 3602 3603 pf_clear_states(); 3604 3605 pf_clear_srcnodes(); 3606 3607 /* status does not use malloced mem so no need to cleanup */ 3608 /* fingerprints and interfaces have thier own cleanup code */ 3609 } while(0); 3610 3611 return (error); 3612} 3613 3614static int 3615pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 3616 struct inpcb *inp) 3617{ 3618 /* 3619 * XXX Wed Jul 9 22:03:16 2003 UTC 3620 * OpenBSD has changed its byte ordering convention on ip_len/ip_off 3621 * in network stack. OpenBSD's network stack have converted 3622 * ip_len/ip_off to host byte order frist as FreeBSD. 3623 * Now this is not true anymore , so we should convert back to network 3624 * byte order. 3625 */ 3626 struct ip *h = NULL; 3627 int chk; 3628 3629 if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) { 3630 /* if m_pkthdr.len is less than ip header, pf will handle. */ 3631 h = mtod(*m, struct ip *); 3632 HTONS(h->ip_len); 3633 HTONS(h->ip_off); 3634 } 3635 chk = pf_test(PF_IN, ifp, m, NULL, inp); 3636 if (chk && *m) { 3637 m_freem(*m); 3638 *m = NULL; 3639 } 3640 if (*m != NULL) { 3641 /* pf_test can change ip header location */ 3642 h = mtod(*m, struct ip *); 3643 NTOHS(h->ip_len); 3644 NTOHS(h->ip_off); 3645 } 3646 return chk; 3647} 3648 3649static int 3650pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 3651 struct inpcb *inp) 3652{ 3653 /* 3654 * XXX Wed Jul 9 22:03:16 2003 UTC 3655 * OpenBSD has changed its byte ordering convention on ip_len/ip_off 3656 * in network stack. OpenBSD's network stack have converted 3657 * ip_len/ip_off to host byte order frist as FreeBSD. 3658 * Now this is not true anymore , so we should convert back to network 3659 * byte order. 3660 */ 3661 struct ip *h = NULL; 3662 int chk; 3663 3664 /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */ 3665 if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 3666 in_delayed_cksum(*m); 3667 (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 3668 } 3669 if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) { 3670 /* if m_pkthdr.len is less than ip header, pf will handle. */ 3671 h = mtod(*m, struct ip *); 3672 HTONS(h->ip_len); 3673 HTONS(h->ip_off); 3674 } 3675 chk = pf_test(PF_OUT, ifp, m, NULL, inp); 3676 if (chk && *m) { 3677 m_freem(*m); 3678 *m = NULL; 3679 } 3680 if (*m != NULL) { 3681 /* pf_test can change ip header location */ 3682 h = mtod(*m, struct ip *); 3683 NTOHS(h->ip_len); 3684 NTOHS(h->ip_off); 3685 } 3686 return chk; 3687} 3688 3689#ifdef INET6 3690static int 3691pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 3692 struct inpcb *inp) 3693{ 3694 INIT_VNET_NET(curvnet); 3695 3696 /* 3697 * IPv6 is not affected by ip_len/ip_off byte order changes. 3698 */ 3699 int chk; 3700 3701 /* 3702 * In case of loopback traffic IPv6 uses the real interface in 3703 * order to support scoped addresses. In order to support stateful 3704 * filtering we have change this to lo0 as it is the case in IPv4. 3705 */ 3706 chk = pf_test6(PF_IN, (*m)->m_flags & M_LOOP ? &V_loif[0] : ifp, m, 3707 NULL, inp); 3708 if (chk && *m) { 3709 m_freem(*m); 3710 *m = NULL; 3711 } 3712 return chk; 3713} 3714 3715static int 3716pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 3717 struct inpcb *inp) 3718{ 3719 /* 3720 * IPv6 does not affected ip_len/ip_off byte order changes. 3721 */ 3722 int chk; 3723 3724 /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */ 3725 if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 3726 in_delayed_cksum(*m); 3727 (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 3728 } 3729 chk = pf_test6(PF_OUT, ifp, m, NULL, inp); 3730 if (chk && *m) { 3731 m_freem(*m); 3732 *m = NULL; 3733 } 3734 return chk; 3735} 3736#endif /* INET6 */ 3737 3738static int 3739hook_pf(void) 3740{ 3741 struct pfil_head *pfh_inet; 3742#ifdef INET6 3743 struct pfil_head *pfh_inet6; 3744#endif 3745 3746 PF_ASSERT(MA_NOTOWNED); 3747 3748 if (pf_pfil_hooked) 3749 return (0); 3750 3751 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 3752 if (pfh_inet == NULL) 3753 return (ESRCH); /* XXX */ 3754 pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); 3755 pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); 3756#ifdef INET6 3757 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 3758 if (pfh_inet6 == NULL) { 3759 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, 3760 pfh_inet); 3761 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 3762 pfh_inet); 3763 return (ESRCH); /* XXX */ 3764 } 3765 pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); 3766 pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); 3767#endif 3768 3769 pf_pfil_hooked = 1; 3770 return (0); 3771} 3772 3773static int 3774dehook_pf(void) 3775{ 3776 struct pfil_head *pfh_inet; 3777#ifdef INET6 3778 struct pfil_head *pfh_inet6; 3779#endif 3780 3781 PF_ASSERT(MA_NOTOWNED); 3782 3783 if (pf_pfil_hooked == 0) 3784 return (0); 3785 3786 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 3787 if (pfh_inet == NULL) 3788 return (ESRCH); /* XXX */ 3789 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, 3790 pfh_inet); 3791 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 3792 pfh_inet); 3793#ifdef INET6 3794 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 3795 if (pfh_inet6 == NULL) 3796 return (ESRCH); /* XXX */ 3797 pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, 3798 pfh_inet6); 3799 pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, 3800 pfh_inet6); 3801#endif 3802 3803 pf_pfil_hooked = 0; 3804 return (0); 3805} 3806 3807static int 3808pf_load(void) 3809{ 3810 init_zone_var(); 3811 init_pf_mutex(); 3812 pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME); 3813 if (pfattach() < 0) { 3814 destroy_dev(pf_dev); 3815 destroy_pf_mutex(); 3816 return (ENOMEM); 3817 } 3818 return (0); 3819} 3820 3821static int 3822pf_unload(void) 3823{ 3824 int error = 0; 3825 3826 PF_LOCK(); 3827 pf_status.running = 0; 3828 PF_UNLOCK(); 3829 error = dehook_pf(); 3830 if (error) { 3831 /* 3832 * Should not happen! 3833 * XXX Due to error code ESRCH, kldunload will show 3834 * a message like 'No such process'. 3835 */ 3836 printf("%s : pfil unregisteration fail\n", __FUNCTION__); 3837 return error; 3838 } 3839 PF_LOCK(); 3840 shutdown_pf(); 3841 pf_end_threads = 1; 3842 while (pf_end_threads < 2) { 3843 wakeup_one(pf_purge_thread); 3844 msleep(pf_purge_thread, &pf_task_mtx, 0, "pftmo", hz); 3845 } 3846 pfi_cleanup(); 3847 pf_osfp_flush(); 3848 pf_osfp_cleanup(); 3849 cleanup_pf_zone(); 3850 PF_UNLOCK(); 3851 destroy_dev(pf_dev); 3852 destroy_pf_mutex(); 3853 return error; 3854} 3855 3856static int 3857pf_modevent(module_t mod, int type, void *data) 3858{ 3859 int error = 0; 3860 3861 switch(type) { 3862 case MOD_LOAD: 3863 error = pf_load(); 3864 break; 3865 3866 case MOD_UNLOAD: 3867 error = pf_unload(); 3868 break; 3869 default: 3870 error = EINVAL; 3871 break; 3872 } 3873 return error; 3874} 3875 3876static moduledata_t pf_mod = { 3877 "pf", 3878 pf_modevent, 3879 0 3880}; 3881 3882DECLARE_MODULE(pf, pf_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST); 3883MODULE_VERSION(pf, PF_MODVER); 3884#endif /* __FreeBSD__ */ 3885