pf_ioctl.c revision 128846
1/* $FreeBSD: head/sys/contrib/pf/net/pf_ioctl.c 128846 2004-05-02 20:47:24Z dhartmei $ */ 2/* $OpenBSD: pf_ioctl.c,v 1.81.2.2 2004/04/30 23:28:58 brad Exp $ */ 3 4/* 5 * Copyright (c) 2001 Daniel Hartmeier 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#endif 42 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/mbuf.h> 46#include <sys/filio.h> 47#include <sys/fcntl.h> 48#include <sys/socket.h> 49#include <sys/socketvar.h> 50#include <sys/kernel.h> 51#include <sys/time.h> 52#include <sys/malloc.h> 53#ifdef __FreeBSD__ 54#include <sys/conf.h> 55#else 56#include <sys/timeout.h> 57#include <sys/pool.h> 58#endif 59 60#include <net/if.h> 61#include <net/if_types.h> 62#include <net/route.h> 63 64#include <netinet/in.h> 65#include <netinet/in_var.h> 66#include <netinet/in_systm.h> 67#include <netinet/ip.h> 68#include <netinet/ip_var.h> 69#include <netinet/ip_icmp.h> 70 71#include <net/pfvar.h> 72 73#ifdef INET6 74#include <netinet/ip6.h> 75#include <netinet/in_pcb.h> 76#if defined(__FreeBSD__) && (__FreeBSD_version < 501108) 77#include <netinet6/ip6protosw.h> 78#endif 79#endif /* INET6 */ 80 81#ifdef ALTQ 82#include <altq/altq.h> 83#endif 84 85#ifdef __FreeBSD__ 86#if (__FreeBSD_version >= 500112) 87#include <sys/limits.h> 88#else 89#include <machine/limits.h> 90#endif 91#include <sys/lock.h> 92#include <sys/mutex.h> 93#if __FreeBSD_version < 501108 94#include <sys/protosw.h> 95#endif 96#include <net/pfil.h> 97#endif /* __FreeBSD__ */ 98 99#ifdef __FreeBSD__ 100void init_zone_var(void); 101void cleanup_pf_zone(void); 102int pfattach(void); 103#else 104void pfattach(int); 105int pfopen(dev_t, int, int, struct proc *); 106int pfclose(dev_t, int, int, struct proc *); 107#endif 108struct pf_pool *pf_get_pool(char *, char *, u_int32_t, 109 u_int8_t, u_int32_t, u_int8_t, u_int8_t, u_int8_t); 110int pf_get_ruleset_number(u_int8_t); 111void pf_init_ruleset(struct pf_ruleset *); 112void pf_mv_pool(struct pf_palist *, struct pf_palist *); 113void pf_empty_pool(struct pf_palist *); 114#ifdef __FreeBSD__ 115int pfioctl(dev_t, u_long, caddr_t, int, struct thread *); 116#else 117int pfioctl(dev_t, u_long, caddr_t, int, struct proc *); 118#endif 119 120#ifdef __FreeBSD__ 121extern struct callout pf_expire_to; 122#if __FreeBSD_version < 501108 123extern struct protosw inetsw[]; 124#endif 125#else 126extern struct timeout pf_expire_to; 127#endif 128 129struct pf_rule pf_default_rule; 130 131#define TAGID_MAX 50000 132TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags); 133 134#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x 135 136 137#ifdef __FreeBSD__ 138static dev_t pf_dev; 139 140/* 141 * XXX - These are new and need to be checked when moveing to a new version 142 */ 143static int pf_beginrules(void *addr); 144static int pf_commitrules(void *addr); 145#ifdef ALTQ 146static int pf_beginaltqs(void *addr); 147static int pf_commitaltqs(void *addr); 148static int pf_stopaltq(void); 149#endif 150static void pf_clearstates(void); 151static int pf_clear_tables(void *addr); 152/* 153 * XXX - These are new and need to be checked when moveing to a new version 154 */ 155 156#if (__FreeBSD_version < 501108) 157static int pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir, 158 struct mbuf **m); 159static int pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir, 160 struct mbuf **m); 161#ifdef INET6 162static int pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir, 163 struct mbuf **m); 164static int pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir, 165 struct mbuf **m); 166#endif 167#else /* (__FreeBSD_version >= 501108) */ 168static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, 169 int dir); 170static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, 171 int dir); 172#ifdef INET6 173static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, 174 int dir); 175static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, 176 int dir); 177#endif 178#endif /* (__FreeBSD_version >= 501108) */ 179static int hook_pf(void); 180static int dehook_pf(void); 181static int shutdown_pf(void); 182static int pf_load(void); 183static int pf_unload(void); 184 185 186 187static struct cdevsw pf_cdevsw = { 188#if (__FreeBSD_version < 500105) 189 /* open */ noopen, 190 /* close */ noclose, 191 /* read */ noread, 192 /* write */ nowrite, 193 /* ioctl */ pfioctl, 194 /* poll */ nopoll, 195 /* mmap */ nommap, 196 /* strategy */ nostrategy, 197 /* name */ PF_NAME, 198 /* maj */ PF_CDEV_MAJOR, 199 /* dump */ nodump, 200 /* psize */ nopsize, 201 /* flags */ 0, 202 /* kqfilter */ nokqfilter, 203#elif (__FreeBSD_version < 501110) 204 .d_open = noopen, 205 .d_close = noclose, 206 .d_read = noread, 207 .d_write = nowrite, 208 .d_ioctl = pfioctl, 209 .d_poll = nopoll, 210 .d_mmap = nommap, 211 .d_strategy = nostrategy, 212 .d_name = PF_NAME, 213 .d_maj = MAJOR_AUTO, /* PF_CDEV_MAJOR */ 214 .d_dump = nodump, 215 .d_flags = 0, 216 .d_kqfilter = nokqfilter, 217#else 218 .d_ioctl = pfioctl, 219 .d_name = PF_NAME, 220 .d_version = D_VERSION, 221#endif 222}; 223 224static volatile int pf_pfil_hooked = 0; 225struct mtx pf_task_mtx; 226 227void 228init_pf_mutex(void) 229{ 230 mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF); 231/* 232 * pf_altq_mtx is initialized at altq_subr.c. 233 * 234 * #if defined(ALTQ) && !defined(ALTQ3_COMPAT) 235 * mtx_init(&pf_altq_mtx, "pf altq mtx", NULL, MTX_DEF); 236 * #endif 237 */ 238} 239 240void 241destroy_pf_mutex(void) 242{ 243 mtx_destroy(&pf_task_mtx); 244/* 245 * pf_altq_mtx is initialized at altq_subr.c. 246 * 247 * #if defined(ALTQ) && !defined(ALTQ3_COMPAT) 248 * mtx_destroy(&pf_altq_mtx); 249 * #endif 250 */ 251} 252 253void 254init_zone_var(void) 255{ 256 pf_tree_pl = pf_rule_pl = pf_addr_pl = NULL; 257 pf_state_pl = pf_altq_pl = pf_pooladdr_pl = NULL; 258 pf_frent_pl = pf_frag_pl = pf_cache_pl = pf_cent_pl = NULL; 259 pf_state_scrub_pl = NULL; 260 pfr_ktable_pl = pfr_kentry_pl = NULL; 261} 262 263void 264cleanup_pf_zone(void) 265{ 266 UMA_DESTROY(pf_tree_pl); 267 UMA_DESTROY(pf_rule_pl); 268 UMA_DESTROY(pf_addr_pl); 269 UMA_DESTROY(pf_state_pl); 270 UMA_DESTROY(pf_altq_pl); 271 UMA_DESTROY(pf_pooladdr_pl); 272 UMA_DESTROY(pf_frent_pl); 273 UMA_DESTROY(pf_frag_pl); 274 UMA_DESTROY(pf_cache_pl); 275 UMA_DESTROY(pf_cent_pl); 276 UMA_DESTROY(pfr_ktable_pl); 277 UMA_DESTROY(pfr_kentry_pl); 278 UMA_DESTROY(pf_state_scrub_pl); 279} 280 281int 282pfattach(void) 283{ 284 u_int32_t *my_timeout = pf_default_rule.timeout; 285 int error = 1; 286 287 do { 288 UMA_CREATE(pf_tree_pl, struct pf_tree_node, "pftrpl"); 289 UMA_CREATE(pf_rule_pl, struct pf_rule, "pfrulepl"); 290 UMA_CREATE(pf_addr_pl, struct pf_addr_dyn, "pfaddrpl"); 291 UMA_CREATE(pf_state_pl, struct pf_state, "pfstatepl"); 292 UMA_CREATE(pf_altq_pl, struct pf_altq, "pfaltqpl"); 293 UMA_CREATE(pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl"); 294 UMA_CREATE(pfr_ktable_pl, struct pfr_ktable, "pfrktable"); 295 UMA_CREATE(pfr_kentry_pl, struct pfr_kentry, "pfrkentry"); 296 UMA_CREATE(pf_frent_pl, struct pf_frent, "pffrent"); 297 UMA_CREATE(pf_frag_pl, struct pf_fragment, "pffrag"); 298 UMA_CREATE(pf_cache_pl, struct pf_fragment, "pffrcache"); 299 UMA_CREATE(pf_cent_pl, struct pf_frcache, "pffrcent"); 300 UMA_CREATE(pf_state_scrub_pl, struct pf_state_scrub, 301 "pfstatescrub"); 302 error = 0; 303 } while(0); 304 if (error) { 305 cleanup_pf_zone(); 306 return (error); 307 } 308 pfr_initialize(); 309 if ( (error = pf_osfp_initialize()) ) { 310 cleanup_pf_zone(); 311 pf_osfp_cleanup(); 312 return (error); 313 } 314 315 pf_pool_limits[PF_LIMIT_STATES].pp = pf_state_pl; 316 pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT; 317 pf_pool_limits[PF_LIMIT_FRAGS].pp = pf_frent_pl; 318 pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT; 319 uma_zone_set_max(pf_pool_limits[PF_LIMIT_STATES].pp, 320 pf_pool_limits[PF_LIMIT_STATES].limit); 321 322 RB_INIT(&tree_lan_ext); 323 RB_INIT(&tree_ext_gwy); 324 TAILQ_INIT(&pf_anchors); 325 pf_init_ruleset(&pf_main_ruleset); 326 TAILQ_INIT(&pf_altqs[0]); 327 TAILQ_INIT(&pf_altqs[1]); 328 TAILQ_INIT(&pf_pabuf); 329 pf_altqs_active = &pf_altqs[0]; 330 pf_altqs_inactive = &pf_altqs[1]; 331 332 /* default rule should never be garbage collected */ 333 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; 334 pf_default_rule.action = PF_PASS; 335 pf_default_rule.nr = -1; 336 337 /* initialize default timeouts */ 338 my_timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */ 339 my_timeout[PFTM_TCP_OPENING] = 30; /* No response yet */ 340 my_timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */ 341 my_timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */ 342 my_timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */ 343 my_timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */ 344 my_timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */ 345 my_timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */ 346 my_timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */ 347 my_timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */ 348 my_timeout[PFTM_ICMP_ERROR_REPLY] = 10; /* Got error response */ 349 my_timeout[PFTM_OTHER_FIRST_PACKET] = 60; /* First packet */ 350 my_timeout[PFTM_OTHER_SINGLE] = 30; /* Unidirectional */ 351 my_timeout[PFTM_OTHER_MULTIPLE] = 60; /* Bidirectional */ 352 my_timeout[PFTM_FRAG] = 30; /* Fragment expire */ 353 my_timeout[PFTM_INTERVAL] = 10; /* Expire interval */ 354 355 /* 356 * XXX 357 * The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE 358 * if Gaint lock is removed from the network stack. 359 */ 360 callout_init(&pf_expire_to, 0); 361 callout_reset(&pf_expire_to, my_timeout[PFTM_INTERVAL] * hz, 362 pf_purge_timeout, &pf_expire_to); 363 364 pf_normalize_init(); 365 pf_status.debug = PF_DEBUG_URGENT; 366 pf_pfil_hooked = 0; 367 return (error); 368} 369#else /* !__FreeBSD__ */ 370void 371pfattach(int num) 372{ 373 u_int32_t *timeout = pf_default_rule.timeout; 374 375 pool_init(&pf_tree_pl, sizeof(struct pf_tree_node), 0, 0, 0, "pftrpl", 376 NULL); 377 pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl", 378 &pool_allocator_nointr); 379 pool_init(&pf_addr_pl, sizeof(struct pf_addr_dyn), 0, 0, 0, "pfaddrpl", 380 &pool_allocator_nointr); 381 pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", 382 NULL); 383 pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", 384 NULL); 385 pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, 386 "pfpooladdrpl", NULL); 387 pfr_initialize(); 388 pf_osfp_initialize(); 389 390 pool_sethardlimit(&pf_state_pl, pf_pool_limits[PF_LIMIT_STATES].limit, 391 NULL, 0); 392 393 RB_INIT(&tree_lan_ext); 394 RB_INIT(&tree_ext_gwy); 395 TAILQ_INIT(&pf_anchors); 396 pf_init_ruleset(&pf_main_ruleset); 397 TAILQ_INIT(&pf_altqs[0]); 398 TAILQ_INIT(&pf_altqs[1]); 399 TAILQ_INIT(&pf_pabuf); 400 pf_altqs_active = &pf_altqs[0]; 401 pf_altqs_inactive = &pf_altqs[1]; 402 403 /* default rule should never be garbage collected */ 404 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; 405 pf_default_rule.action = PF_PASS; 406 pf_default_rule.nr = -1; 407 408 /* initialize default timeouts */ 409 timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */ 410 timeout[PFTM_TCP_OPENING] = 30; /* No response yet */ 411 timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */ 412 timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */ 413 timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */ 414 timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */ 415 timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */ 416 timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */ 417 timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */ 418 timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */ 419 timeout[PFTM_ICMP_ERROR_REPLY] = 10; /* Got error response */ 420 timeout[PFTM_OTHER_FIRST_PACKET] = 60; /* First packet */ 421 timeout[PFTM_OTHER_SINGLE] = 30; /* Unidirectional */ 422 timeout[PFTM_OTHER_MULTIPLE] = 60; /* Bidirectional */ 423 timeout[PFTM_FRAG] = 30; /* Fragment expire */ 424 timeout[PFTM_INTERVAL] = 10; /* Expire interval */ 425 426 timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to); 427 timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz); 428 429 pf_normalize_init(); 430 pf_status.debug = PF_DEBUG_URGENT; 431} 432 433int 434pfopen(dev_t dev, int flags, int fmt, struct proc *p) 435{ 436 if (minor(dev) >= 1) 437 return (ENXIO); 438 return (0); 439} 440 441int 442pfclose(dev_t dev, int flags, int fmt, struct proc *p) 443{ 444 if (minor(dev) >= 1) 445 return (ENXIO); 446 return (0); 447} 448#endif /* __FreeBSD__ */ 449 450struct pf_pool * 451pf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket, 452 u_int8_t rule_action, u_int32_t rule_number, u_int8_t r_last, 453 u_int8_t active, u_int8_t check_ticket) 454{ 455 struct pf_ruleset *ruleset; 456 struct pf_rule *rule; 457 int rs_num; 458 459 ruleset = pf_find_ruleset(anchorname, rulesetname); 460 if (ruleset == NULL) 461 return (NULL); 462 rs_num = pf_get_ruleset_number(rule_action); 463 if (rs_num >= PF_RULESET_MAX) 464 return (NULL); 465 if (active) { 466 if (check_ticket && ticket != 467 ruleset->rules[rs_num].active.ticket) 468 return (NULL); 469 if (r_last) 470 rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 471 pf_rulequeue); 472 else 473 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 474 } else { 475 if (check_ticket && ticket != 476 ruleset->rules[rs_num].inactive.ticket) 477 return (NULL); 478 if (r_last) 479 rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 480 pf_rulequeue); 481 else 482 rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr); 483 } 484 if (!r_last) { 485 while ((rule != NULL) && (rule->nr != rule_number)) 486 rule = TAILQ_NEXT(rule, entries); 487 } 488 if (rule == NULL) 489 return (NULL); 490 491 return (&rule->rpool); 492} 493 494int 495pf_get_ruleset_number(u_int8_t action) 496{ 497 switch (action) { 498 case PF_SCRUB: 499 return (PF_RULESET_SCRUB); 500 break; 501 case PF_PASS: 502 case PF_DROP: 503 return (PF_RULESET_FILTER); 504 break; 505 case PF_NAT: 506 case PF_NONAT: 507 return (PF_RULESET_NAT); 508 break; 509 case PF_BINAT: 510 case PF_NOBINAT: 511 return (PF_RULESET_BINAT); 512 break; 513 case PF_RDR: 514 case PF_NORDR: 515 return (PF_RULESET_RDR); 516 break; 517 default: 518 return (PF_RULESET_MAX); 519 break; 520 } 521} 522 523void 524pf_init_ruleset(struct pf_ruleset *ruleset) 525{ 526 int i; 527 528 memset(ruleset, 0, sizeof(struct pf_ruleset)); 529 for (i = 0; i < PF_RULESET_MAX; i++) { 530 TAILQ_INIT(&ruleset->rules[i].queues[0]); 531 TAILQ_INIT(&ruleset->rules[i].queues[1]); 532 ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0]; 533 ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1]; 534 } 535} 536 537struct pf_anchor * 538pf_find_anchor(const char *anchorname) 539{ 540 struct pf_anchor *anchor; 541 int n = -1; 542 543 anchor = TAILQ_FIRST(&pf_anchors); 544 while (anchor != NULL && (n = strcmp(anchor->name, anchorname)) < 0) 545 anchor = TAILQ_NEXT(anchor, entries); 546 if (n == 0) 547 return (anchor); 548 else 549 return (NULL); 550} 551 552struct pf_ruleset * 553pf_find_ruleset(char *anchorname, char *rulesetname) 554{ 555 struct pf_anchor *anchor; 556 struct pf_ruleset *ruleset; 557 558 if (!anchorname[0] && !rulesetname[0]) 559 return (&pf_main_ruleset); 560 if (!anchorname[0] || !rulesetname[0]) 561 return (NULL); 562 anchorname[PF_ANCHOR_NAME_SIZE-1] = 0; 563 rulesetname[PF_RULESET_NAME_SIZE-1] = 0; 564 anchor = pf_find_anchor(anchorname); 565 if (anchor == NULL) 566 return (NULL); 567 ruleset = TAILQ_FIRST(&anchor->rulesets); 568 while (ruleset != NULL && strcmp(ruleset->name, rulesetname) < 0) 569 ruleset = TAILQ_NEXT(ruleset, entries); 570 if (ruleset != NULL && !strcmp(ruleset->name, rulesetname)) 571 return (ruleset); 572 else 573 return (NULL); 574} 575 576struct pf_ruleset * 577pf_find_or_create_ruleset(char *anchorname, char *rulesetname) 578{ 579 struct pf_anchor *anchor, *a; 580 struct pf_ruleset *ruleset, *r; 581 582 if (!anchorname[0] && !rulesetname[0]) 583 return (&pf_main_ruleset); 584 if (!anchorname[0] || !rulesetname[0]) 585 return (NULL); 586 anchorname[PF_ANCHOR_NAME_SIZE-1] = 0; 587 rulesetname[PF_RULESET_NAME_SIZE-1] = 0; 588 a = TAILQ_FIRST(&pf_anchors); 589 while (a != NULL && strcmp(a->name, anchorname) < 0) 590 a = TAILQ_NEXT(a, entries); 591 if (a != NULL && !strcmp(a->name, anchorname)) 592 anchor = a; 593 else { 594 anchor = (struct pf_anchor *)malloc(sizeof(struct pf_anchor), 595 M_TEMP, M_NOWAIT); 596 if (anchor == NULL) 597 return (NULL); 598 memset(anchor, 0, sizeof(struct pf_anchor)); 599 bcopy(anchorname, anchor->name, sizeof(anchor->name)); 600 TAILQ_INIT(&anchor->rulesets); 601 if (a != NULL) 602 TAILQ_INSERT_BEFORE(a, anchor, entries); 603 else 604 TAILQ_INSERT_TAIL(&pf_anchors, anchor, entries); 605 } 606 r = TAILQ_FIRST(&anchor->rulesets); 607 while (r != NULL && strcmp(r->name, rulesetname) < 0) 608 r = TAILQ_NEXT(r, entries); 609 if (r != NULL && !strcmp(r->name, rulesetname)) 610 return (r); 611 ruleset = (struct pf_ruleset *)malloc(sizeof(struct pf_ruleset), 612 M_TEMP, M_NOWAIT); 613 if (ruleset != NULL) { 614 pf_init_ruleset(ruleset); 615 bcopy(rulesetname, ruleset->name, sizeof(ruleset->name)); 616 ruleset->anchor = anchor; 617 if (r != NULL) 618 TAILQ_INSERT_BEFORE(r, ruleset, entries); 619 else 620 TAILQ_INSERT_TAIL(&anchor->rulesets, ruleset, entries); 621 } 622 return (ruleset); 623} 624 625void 626pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset) 627{ 628 struct pf_anchor *anchor; 629 int i; 630 631 if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 || 632 ruleset->topen) 633 return; 634 for (i = 0; i < PF_RULESET_MAX; ++i) 635 if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) || 636 !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr)) 637 return; 638 639 anchor = ruleset->anchor; 640 TAILQ_REMOVE(&anchor->rulesets, ruleset, entries); 641 free(ruleset, M_TEMP); 642 643 if (TAILQ_EMPTY(&anchor->rulesets)) { 644 TAILQ_REMOVE(&pf_anchors, anchor, entries); 645 free(anchor, M_TEMP); 646 pf_update_anchor_rules(); 647 } 648} 649 650void 651pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb) 652{ 653 struct pf_pooladdr *mv_pool_pa; 654 655 while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) { 656 TAILQ_REMOVE(poola, mv_pool_pa, entries); 657 TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries); 658 } 659} 660 661void 662pf_empty_pool(struct pf_palist *poola) 663{ 664 struct pf_pooladdr *empty_pool_pa; 665 666 while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) { 667 pf_dynaddr_remove(&empty_pool_pa->addr); 668 pf_tbladdr_remove(&empty_pool_pa->addr); 669 TAILQ_REMOVE(poola, empty_pool_pa, entries); 670 pool_put(&pf_pooladdr_pl, empty_pool_pa); 671 } 672} 673 674void 675pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) 676{ 677 if (rulequeue != NULL) { 678 if (rule->states <= 0) { 679 /* 680 * XXX - we need to remove the table *before* detaching 681 * the rule to make sure the table code does not delete 682 * the anchor under our feet. 683 */ 684 pf_tbladdr_remove(&rule->src.addr); 685 pf_tbladdr_remove(&rule->dst.addr); 686 } 687 TAILQ_REMOVE(rulequeue, rule, entries); 688 rule->entries.tqe_prev = NULL; 689 rule->nr = -1; 690 } 691 if (rule->states > 0 || rule->entries.tqe_prev != NULL) 692 return; 693 pf_tag_unref(rule->tag); 694 pf_tag_unref(rule->match_tag); 695 pf_dynaddr_remove(&rule->src.addr); 696 pf_dynaddr_remove(&rule->dst.addr); 697 if (rulequeue == NULL) { 698 pf_tbladdr_remove(&rule->src.addr); 699 pf_tbladdr_remove(&rule->dst.addr); 700 } 701 pf_empty_pool(&rule->rpool.list); 702 pool_put(&pf_rule_pl, rule); 703} 704 705u_int16_t 706pf_tagname2tag(char *tagname) 707{ 708 struct pf_tagname *tag, *p = NULL; 709 u_int16_t new_tagid = 1; 710 711 TAILQ_FOREACH(tag, &pf_tags, entries) 712 if (strcmp(tagname, tag->name) == 0) { 713 tag->ref++; 714 return (tag->tag); 715 } 716 717 /* 718 * to avoid fragmentation, we do a linear search from the beginning 719 * and take the first free slot we find. if there is none or the list 720 * is empty, append a new entry at the end. 721 */ 722 723 /* new entry */ 724 if (!TAILQ_EMPTY(&pf_tags)) 725 for (p = TAILQ_FIRST(&pf_tags); p != NULL && 726 p->tag == new_tagid; p = TAILQ_NEXT(p, entries)) 727 new_tagid = p->tag + 1; 728 729 if (new_tagid > TAGID_MAX) 730 return (0); 731 732 /* allocate and fill new struct pf_tagname */ 733 tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname), 734 M_TEMP, M_NOWAIT); 735 if (tag == NULL) 736 return (0); 737 bzero(tag, sizeof(struct pf_tagname)); 738 strlcpy(tag->name, tagname, sizeof(tag->name)); 739 tag->tag = new_tagid; 740 tag->ref++; 741 742 if (p != NULL) /* insert new entry before p */ 743 TAILQ_INSERT_BEFORE(p, tag, entries); 744 else /* either list empty or no free slot in between */ 745 TAILQ_INSERT_TAIL(&pf_tags, tag, entries); 746 747 return (tag->tag); 748} 749 750void 751pf_tag2tagname(u_int16_t tagid, char *p) 752{ 753 struct pf_tagname *tag; 754 755 TAILQ_FOREACH(tag, &pf_tags, entries) 756 if (tag->tag == tagid) { 757 strlcpy(p, tag->name, PF_TAG_NAME_SIZE); 758 return; 759 } 760} 761 762void 763pf_tag_unref(u_int16_t tag) 764{ 765 struct pf_tagname *p, *next; 766 767 if (tag == 0) 768 return; 769 770 for (p = TAILQ_FIRST(&pf_tags); p != NULL; p = next) { 771 next = TAILQ_NEXT(p, entries); 772 if (tag == p->tag) { 773 if (--p->ref == 0) { 774 TAILQ_REMOVE(&pf_tags, p, entries); 775 free(p, M_TEMP); 776 } 777 break; 778 } 779 } 780} 781 782#ifdef __FreeBSD__ 783int 784pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 785#else 786int 787pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 788#endif 789{ 790 struct pf_pooladdr *pa = NULL; 791 struct pf_pool *pool = NULL; 792 int s; 793 int error = 0; 794 795 /* XXX keep in sync with switch() below */ 796 if (securelevel > 1) 797 switch (cmd) { 798 case DIOCGETRULES: 799 case DIOCGETRULE: 800 case DIOCGETADDRS: 801 case DIOCGETADDR: 802 case DIOCGETSTATE: 803 case DIOCSETSTATUSIF: 804 case DIOCGETSTATUS: 805 case DIOCCLRSTATUS: 806 case DIOCNATLOOK: 807 case DIOCSETDEBUG: 808 case DIOCGETSTATES: 809 case DIOCGETTIMEOUT: 810 case DIOCCLRRULECTRS: 811 case DIOCGETLIMIT: 812 case DIOCGETALTQS: 813 case DIOCGETALTQ: 814 case DIOCGETQSTATS: 815 case DIOCGETANCHORS: 816 case DIOCGETANCHOR: 817 case DIOCGETRULESETS: 818 case DIOCGETRULESET: 819 case DIOCRGETTABLES: 820 case DIOCRGETTSTATS: 821 case DIOCRCLRTSTATS: 822 case DIOCRCLRADDRS: 823 case DIOCRADDADDRS: 824 case DIOCRDELADDRS: 825 case DIOCRSETADDRS: 826 case DIOCRGETADDRS: 827 case DIOCRGETASTATS: 828 case DIOCRCLRASTATS: 829 case DIOCRTSTADDRS: 830 case DIOCOSFPGET: 831#ifdef __FreeBSD__ 832 case DIOCGIFSPEED: 833#endif 834 break; 835 default: 836 return (EPERM); 837 } 838 839 if (!(flags & FWRITE)) 840 switch (cmd) { 841 case DIOCGETRULES: 842 case DIOCGETRULE: 843 case DIOCGETADDRS: 844 case DIOCGETADDR: 845 case DIOCGETSTATE: 846 case DIOCGETSTATUS: 847 case DIOCGETSTATES: 848 case DIOCGETTIMEOUT: 849 case DIOCGETLIMIT: 850 case DIOCGETALTQS: 851 case DIOCGETALTQ: 852 case DIOCGETQSTATS: 853 case DIOCGETANCHORS: 854 case DIOCGETANCHOR: 855 case DIOCGETRULESETS: 856 case DIOCGETRULESET: 857 case DIOCRGETTABLES: 858 case DIOCRGETTSTATS: 859 case DIOCRGETADDRS: 860 case DIOCRGETASTATS: 861 case DIOCRTSTADDRS: 862 case DIOCOSFPGET: 863#ifdef __FreeBSD__ 864 case DIOCGIFSPEED: 865#endif 866 break; 867 default: 868 return (EACCES); 869 } 870 871#ifdef __FreeBSD__ 872 PF_LOCK(); 873#endif 874 875 switch (cmd) { 876 877 case DIOCSTART: 878 if (pf_status.running) 879 error = EEXIST; 880 else { 881 u_int32_t states = pf_status.states; 882#ifdef __FreeBSD__ 883 PF_UNLOCK(); 884 error = hook_pf(); 885 PF_LOCK(); 886 if (error) { 887 DPFPRINTF(PF_DEBUG_MISC, 888 ("pf: pfil registeration fail\n")); 889 break; 890 } 891#endif 892 bzero(&pf_status, sizeof(struct pf_status)); 893 pf_status.running = 1; 894 pf_status.states = states; 895#ifdef __FreeBSD__ 896 pf_status.since = time_second; 897#else 898 pf_status.since = time.tv_sec; 899#endif 900 if (status_ifp != NULL) 901#if defined(__FreeBSD__) && (__FreeBSD_version < 501113) 902 snprintf(pf_status.ifname, IFNAMSIZ, "%s%d", 903 status_ifp->if_name, status_ifp->if_unit); 904#else 905 strlcpy(pf_status.ifname, 906 status_ifp->if_xname, IFNAMSIZ); 907#endif 908 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); 909 } 910 break; 911 912 case DIOCSTOP: 913 if (!pf_status.running) 914 error = ENOENT; 915 else { 916 pf_status.running = 0; 917#ifdef __FreeBSD__ 918 PF_UNLOCK(); 919 error = dehook_pf(); 920 PF_LOCK(); 921 if (error) { 922 pf_status.running = 1; 923 DPFPRINTF(PF_DEBUG_MISC, 924 ("pf: pfil unregisteration failed\n")); 925 } 926#endif 927 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); 928 } 929 break; 930 931 case DIOCBEGINRULES: { 932 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 933 struct pf_ruleset *ruleset; 934 struct pf_rule *rule; 935 int rs_num; 936 937 ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset); 938 if (ruleset == NULL) { 939 error = EINVAL; 940 break; 941 } 942 rs_num = pf_get_ruleset_number(pr->rule.action); 943 if (rs_num >= PF_RULESET_MAX) { 944 error = EINVAL; 945 break; 946 } 947 while ((rule = 948 TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL) 949 pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule); 950 pr->ticket = ++ruleset->rules[rs_num].inactive.ticket; 951 break; 952 } 953 954 case DIOCADDRULE: { 955 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 956 struct pf_ruleset *ruleset; 957 struct pf_rule *rule, *tail; 958 struct pf_pooladdr *pa; 959 int rs_num; 960 961 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 962 if (ruleset == NULL) { 963 error = EINVAL; 964 break; 965 } 966 rs_num = pf_get_ruleset_number(pr->rule.action); 967 if (rs_num >= PF_RULESET_MAX) { 968 error = EINVAL; 969 break; 970 } 971 if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) { 972 error = EINVAL; 973 break; 974 } 975 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 976 error = EINVAL; 977 break; 978 } 979 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { 980 error = EBUSY; 981 break; 982 } 983 if (pr->pool_ticket != ticket_pabuf) { 984 error = EBUSY; 985 break; 986 } 987 rule = pool_get(&pf_rule_pl, PR_NOWAIT); 988 if (rule == NULL) { 989 error = ENOMEM; 990 break; 991 } 992 bcopy(&pr->rule, rule, sizeof(struct pf_rule)); 993 rule->anchor = NULL; 994 rule->ifp = NULL; 995 TAILQ_INIT(&rule->rpool.list); 996 /* initialize refcounting */ 997 rule->states = 0; 998 rule->entries.tqe_prev = NULL; 999#ifndef INET 1000 if (rule->af == AF_INET) { 1001 pool_put(&pf_rule_pl, rule); 1002 error = EAFNOSUPPORT; 1003 break; 1004 } 1005#endif /* INET */ 1006#ifndef INET6 1007 if (rule->af == AF_INET6) { 1008 pool_put(&pf_rule_pl, rule); 1009 error = EAFNOSUPPORT; 1010 break; 1011 } 1012#endif /* INET6 */ 1013 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 1014 pf_rulequeue); 1015 if (tail) 1016 rule->nr = tail->nr + 1; 1017 else 1018 rule->nr = 0; 1019 if (rule->ifname[0]) { 1020 rule->ifp = ifunit(rule->ifname); 1021 if (rule->ifp == NULL) { 1022 pool_put(&pf_rule_pl, rule); 1023 error = EINVAL; 1024 break; 1025 } 1026 } 1027 1028 if (rule->tagname[0]) 1029 if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) 1030 error = EBUSY; 1031 if (rule->match_tagname[0]) 1032 if ((rule->match_tag = 1033 pf_tagname2tag(rule->match_tagname)) == 0) 1034 error = EBUSY; 1035 if (rule->rt && !rule->direction) 1036 error = EINVAL; 1037 if (pf_dynaddr_setup(&rule->src.addr, rule->af)) 1038 error = EINVAL; 1039 if (pf_dynaddr_setup(&rule->dst.addr, rule->af)) 1040 error = EINVAL; 1041 if (pf_tbladdr_setup(ruleset, &rule->src.addr)) 1042 error = EINVAL; 1043 if (pf_tbladdr_setup(ruleset, &rule->dst.addr)) 1044 error = EINVAL; 1045 TAILQ_FOREACH(pa, &pf_pabuf, entries) 1046 if (pf_tbladdr_setup(ruleset, &pa->addr)) 1047 error = EINVAL; 1048 1049 pf_mv_pool(&pf_pabuf, &rule->rpool.list); 1050 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || 1051 (rule->action == PF_BINAT)) && !rule->anchorname[0]) || 1052 (rule->rt > PF_FASTROUTE)) && 1053 (TAILQ_FIRST(&rule->rpool.list) == NULL)) 1054 error = EINVAL; 1055 1056 if (error) { 1057 pf_rm_rule(NULL, rule); 1058 break; 1059 } 1060 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list); 1061 rule->evaluations = rule->packets = rule->bytes = 0; 1062 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, 1063 rule, entries); 1064 break; 1065 } 1066 1067 case DIOCCOMMITRULES: { 1068 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1069 struct pf_ruleset *ruleset; 1070 struct pf_rulequeue *old_rules; 1071 struct pf_rule *rule; 1072 int rs_num; 1073 1074 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 1075 if (ruleset == NULL) { 1076 error = EINVAL; 1077 break; 1078 } 1079 rs_num = pf_get_ruleset_number(pr->rule.action); 1080 if (rs_num >= PF_RULESET_MAX) { 1081 error = EINVAL; 1082 break; 1083 } 1084 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { 1085 error = EBUSY; 1086 break; 1087 } 1088 1089#ifdef ALTQ 1090 /* set queue IDs */ 1091 if (rs_num == PF_RULESET_FILTER) 1092 pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr); 1093#endif 1094 1095 /* Swap rules, keep the old. */ 1096 s = splsoftnet(); 1097 old_rules = ruleset->rules[rs_num].active.ptr; 1098 ruleset->rules[rs_num].active.ptr = 1099 ruleset->rules[rs_num].inactive.ptr; 1100 ruleset->rules[rs_num].inactive.ptr = old_rules; 1101 ruleset->rules[rs_num].active.ticket = 1102 ruleset->rules[rs_num].inactive.ticket; 1103 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); 1104 1105 /* Purge the old rule list. */ 1106 while ((rule = TAILQ_FIRST(old_rules)) != NULL) 1107 pf_rm_rule(old_rules, rule); 1108 pf_remove_if_empty_ruleset(ruleset); 1109 pf_update_anchor_rules(); 1110 splx(s); 1111 break; 1112 } 1113 1114 case DIOCGETRULES: { 1115 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1116 struct pf_ruleset *ruleset; 1117 struct pf_rule *tail; 1118 int rs_num; 1119 1120 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 1121 if (ruleset == NULL) { 1122 error = EINVAL; 1123 break; 1124 } 1125 rs_num = pf_get_ruleset_number(pr->rule.action); 1126 if (rs_num >= PF_RULESET_MAX) { 1127 error = EINVAL; 1128 break; 1129 } 1130 s = splsoftnet(); 1131 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 1132 pf_rulequeue); 1133 if (tail) 1134 pr->nr = tail->nr + 1; 1135 else 1136 pr->nr = 0; 1137 pr->ticket = ruleset->rules[rs_num].active.ticket; 1138 splx(s); 1139 break; 1140 } 1141 1142 case DIOCGETRULE: { 1143 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1144 struct pf_ruleset *ruleset; 1145 struct pf_rule *rule; 1146 int rs_num, i; 1147 1148 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 1149 if (ruleset == NULL) { 1150 error = EINVAL; 1151 break; 1152 } 1153 rs_num = pf_get_ruleset_number(pr->rule.action); 1154 if (rs_num >= PF_RULESET_MAX) { 1155 error = EINVAL; 1156 break; 1157 } 1158 if (pr->ticket != ruleset->rules[rs_num].active.ticket) { 1159 error = EBUSY; 1160 break; 1161 } 1162 s = splsoftnet(); 1163 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 1164 while ((rule != NULL) && (rule->nr != pr->nr)) 1165 rule = TAILQ_NEXT(rule, entries); 1166 if (rule == NULL) { 1167 error = EBUSY; 1168 splx(s); 1169 break; 1170 } 1171 bcopy(rule, &pr->rule, sizeof(struct pf_rule)); 1172 pf_dynaddr_copyout(&pr->rule.src.addr); 1173 pf_dynaddr_copyout(&pr->rule.dst.addr); 1174 pf_tbladdr_copyout(&pr->rule.src.addr); 1175 pf_tbladdr_copyout(&pr->rule.dst.addr); 1176 for (i = 0; i < PF_SKIP_COUNT; ++i) 1177 if (rule->skip[i].ptr == NULL) 1178 pr->rule.skip[i].nr = -1; 1179 else 1180 pr->rule.skip[i].nr = 1181 rule->skip[i].ptr->nr; 1182 splx(s); 1183 break; 1184 } 1185 1186 case DIOCCHANGERULE: { 1187 struct pfioc_rule *pcr = (struct pfioc_rule *)addr; 1188 struct pf_ruleset *ruleset; 1189 struct pf_rule *oldrule = NULL, *newrule = NULL; 1190 u_int32_t nr = 0; 1191 int rs_num; 1192 1193 if (!(pcr->action == PF_CHANGE_REMOVE || 1194 pcr->action == PF_CHANGE_GET_TICKET) && 1195 pcr->pool_ticket != ticket_pabuf) { 1196 error = EBUSY; 1197 break; 1198 } 1199 1200 if (pcr->action < PF_CHANGE_ADD_HEAD || 1201 pcr->action > PF_CHANGE_GET_TICKET) { 1202 error = EINVAL; 1203 break; 1204 } 1205 ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset); 1206 if (ruleset == NULL) { 1207 error = EINVAL; 1208 break; 1209 } 1210 rs_num = pf_get_ruleset_number(pcr->rule.action); 1211 if (rs_num >= PF_RULESET_MAX) { 1212 error = EINVAL; 1213 break; 1214 } 1215 1216 if (pcr->action == PF_CHANGE_GET_TICKET) { 1217 pcr->ticket = ++ruleset->rules[rs_num].active.ticket; 1218 break; 1219 } else { 1220 if (pcr->ticket != 1221 ruleset->rules[rs_num].active.ticket) { 1222 error = EINVAL; 1223 break; 1224 } 1225 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1226 error = EINVAL; 1227 break; 1228 } 1229 } 1230 1231 if (pcr->action != PF_CHANGE_REMOVE) { 1232 newrule = pool_get(&pf_rule_pl, PR_NOWAIT); 1233 if (newrule == NULL) { 1234 error = ENOMEM; 1235 break; 1236 } 1237 bcopy(&pcr->rule, newrule, sizeof(struct pf_rule)); 1238 TAILQ_INIT(&newrule->rpool.list); 1239 /* initialize refcounting */ 1240 newrule->states = 0; 1241 newrule->entries.tqe_prev = NULL; 1242#ifndef INET 1243 if (newrule->af == AF_INET) { 1244 pool_put(&pf_rule_pl, newrule); 1245 error = EAFNOSUPPORT; 1246 break; 1247 } 1248#endif /* INET */ 1249#ifndef INET6 1250 if (newrule->af == AF_INET6) { 1251 pool_put(&pf_rule_pl, newrule); 1252 error = EAFNOSUPPORT; 1253 break; 1254 } 1255#endif /* INET6 */ 1256 if (newrule->ifname[0]) { 1257 newrule->ifp = ifunit(newrule->ifname); 1258 if (newrule->ifp == NULL) { 1259 pool_put(&pf_rule_pl, newrule); 1260 error = EINVAL; 1261 break; 1262 } 1263 } else 1264 newrule->ifp = NULL; 1265 1266#ifdef ALTQ 1267 /* set queue IDs */ 1268 if (newrule->qname[0] != 0) { 1269 newrule->qid = pf_qname_to_qid(newrule->qname); 1270 if (newrule->pqname[0] != 0) 1271 newrule->pqid = 1272 pf_qname_to_qid(newrule->pqname); 1273 else 1274 newrule->pqid = newrule->qid; 1275 } 1276#endif 1277 if (newrule->tagname[0]) 1278 if ((newrule->tag = 1279 pf_tagname2tag(newrule->tagname)) == 0) 1280 error = EBUSY; 1281 if (newrule->match_tagname[0]) 1282 if ((newrule->match_tag = pf_tagname2tag( 1283 newrule->match_tagname)) == 0) 1284 error = EBUSY; 1285 1286 if (newrule->rt && !newrule->direction) 1287 error = EINVAL; 1288 if (pf_dynaddr_setup(&newrule->src.addr, newrule->af)) 1289 error = EINVAL; 1290 if (pf_dynaddr_setup(&newrule->dst.addr, newrule->af)) 1291 error = EINVAL; 1292 if (pf_tbladdr_setup(ruleset, &newrule->src.addr)) 1293 error = EINVAL; 1294 if (pf_tbladdr_setup(ruleset, &newrule->dst.addr)) 1295 error = EINVAL; 1296 1297 pf_mv_pool(&pf_pabuf, &newrule->rpool.list); 1298 if (((((newrule->action == PF_NAT) || 1299 (newrule->action == PF_RDR) || 1300 (newrule->action == PF_BINAT) || 1301 (newrule->rt > PF_FASTROUTE)) && 1302 !newrule->anchorname[0])) && 1303 (TAILQ_FIRST(&newrule->rpool.list) == NULL)) 1304 error = EINVAL; 1305 1306 if (error) { 1307 pf_rm_rule(NULL, newrule); 1308 break; 1309 } 1310 newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list); 1311 newrule->evaluations = newrule->packets = 0; 1312 newrule->bytes = 0; 1313 } 1314 pf_empty_pool(&pf_pabuf); 1315 1316 s = splsoftnet(); 1317 1318 if (pcr->action == PF_CHANGE_ADD_HEAD) 1319 oldrule = TAILQ_FIRST( 1320 ruleset->rules[rs_num].active.ptr); 1321 else if (pcr->action == PF_CHANGE_ADD_TAIL) 1322 oldrule = TAILQ_LAST( 1323 ruleset->rules[rs_num].active.ptr, pf_rulequeue); 1324 else { 1325 oldrule = TAILQ_FIRST( 1326 ruleset->rules[rs_num].active.ptr); 1327 while ((oldrule != NULL) && (oldrule->nr != pcr->nr)) 1328 oldrule = TAILQ_NEXT(oldrule, entries); 1329 if (oldrule == NULL) { 1330 pf_rm_rule(NULL, newrule); 1331 error = EINVAL; 1332 splx(s); 1333 break; 1334 } 1335 } 1336 1337 if (pcr->action == PF_CHANGE_REMOVE) 1338 pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule); 1339 else { 1340 if (oldrule == NULL) 1341 TAILQ_INSERT_TAIL( 1342 ruleset->rules[rs_num].active.ptr, 1343 newrule, entries); 1344 else if (pcr->action == PF_CHANGE_ADD_HEAD || 1345 pcr->action == PF_CHANGE_ADD_BEFORE) 1346 TAILQ_INSERT_BEFORE(oldrule, newrule, entries); 1347 else 1348 TAILQ_INSERT_AFTER( 1349 ruleset->rules[rs_num].active.ptr, 1350 oldrule, newrule, entries); 1351 } 1352 1353 nr = 0; 1354 TAILQ_FOREACH(oldrule, 1355 ruleset->rules[rs_num].active.ptr, entries) 1356 oldrule->nr = nr++; 1357 1358 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); 1359 pf_remove_if_empty_ruleset(ruleset); 1360 pf_update_anchor_rules(); 1361 1362 ruleset->rules[rs_num].active.ticket++; 1363 splx(s); 1364 break; 1365 } 1366 1367 case DIOCCLRSTATES: { 1368 struct pf_tree_node *n; 1369 1370 s = splsoftnet(); 1371 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) 1372 n->state->timeout = PFTM_PURGE; 1373 pf_purge_expired_states(); 1374 pf_status.states = 0; 1375 splx(s); 1376 break; 1377 } 1378 1379 case DIOCKILLSTATES: { 1380 struct pf_tree_node *n; 1381 struct pf_state *st; 1382 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 1383 int killed = 0; 1384 1385 s = splsoftnet(); 1386 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) { 1387 st = n->state; 1388 if ((!psk->psk_af || st->af == psk->psk_af) && 1389 (!psk->psk_proto || psk->psk_proto == st->proto) && 1390 PF_MATCHA(psk->psk_src.not, 1391 &psk->psk_src.addr.v.a.addr, 1392 &psk->psk_src.addr.v.a.mask, &st->lan.addr, 1393 st->af) && 1394 PF_MATCHA(psk->psk_dst.not, 1395 &psk->psk_dst.addr.v.a.addr, 1396 &psk->psk_dst.addr.v.a.mask, &st->ext.addr, 1397 st->af) && 1398 (psk->psk_src.port_op == 0 || 1399 pf_match_port(psk->psk_src.port_op, 1400 psk->psk_src.port[0], psk->psk_src.port[1], 1401 st->lan.port)) && 1402 (psk->psk_dst.port_op == 0 || 1403 pf_match_port(psk->psk_dst.port_op, 1404 psk->psk_dst.port[0], psk->psk_dst.port[1], 1405 st->ext.port))) { 1406 st->timeout = PFTM_PURGE; 1407 killed++; 1408 } 1409 } 1410 pf_purge_expired_states(); 1411 splx(s); 1412 psk->psk_af = killed; 1413 break; 1414 } 1415 1416 case DIOCADDSTATE: { 1417 struct pfioc_state *ps = (struct pfioc_state *)addr; 1418 struct pf_state *state; 1419 1420 if (ps->state.timeout >= PFTM_MAX && 1421 ps->state.timeout != PFTM_UNTIL_PACKET) { 1422 error = EINVAL; 1423 break; 1424 } 1425 state = pool_get(&pf_state_pl, PR_NOWAIT); 1426 if (state == NULL) { 1427 error = ENOMEM; 1428 break; 1429 } 1430 s = splsoftnet(); 1431 bcopy(&ps->state, state, sizeof(struct pf_state)); 1432 state->rule.ptr = NULL; 1433 state->nat_rule.ptr = NULL; 1434 state->anchor.ptr = NULL; 1435 state->rt_ifp = NULL; 1436#ifdef __FreeBSD__ 1437 state->creation = time_second; 1438#else 1439 state->creation = time.tv_sec; 1440#endif 1441 state->packets[0] = state->packets[1] = 0; 1442 state->bytes[0] = state->bytes[1] = 0; 1443 if (pf_insert_state(state)) { 1444 pool_put(&pf_state_pl, state); 1445 error = ENOMEM; 1446 } 1447 splx(s); 1448 break; 1449 } 1450 1451 case DIOCGETSTATE: { 1452 struct pfioc_state *ps = (struct pfioc_state *)addr; 1453 struct pf_tree_node *n; 1454 u_int32_t nr; 1455 1456 nr = 0; 1457 s = splsoftnet(); 1458 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) { 1459 if (nr >= ps->nr) 1460 break; 1461 nr++; 1462 } 1463 if (n == NULL) { 1464 error = EBUSY; 1465 splx(s); 1466 break; 1467 } 1468 bcopy(n->state, &ps->state, sizeof(struct pf_state)); 1469 ps->state.rule.nr = n->state->rule.ptr->nr; 1470 ps->state.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ? 1471 -1 : n->state->nat_rule.ptr->nr; 1472 ps->state.anchor.nr = (n->state->anchor.ptr == NULL) ? 1473 -1 : n->state->anchor.ptr->nr; 1474 splx(s); 1475 ps->state.expire = pf_state_expires(n->state); 1476#ifdef __FreeBSD__ 1477 if (ps->state.expire > time_second) 1478 ps->state.expire -= time_second; 1479#else 1480 if (ps->state.expire > time.tv_sec) 1481 ps->state.expire -= time.tv_sec; 1482#endif 1483 else 1484 ps->state.expire = 0; 1485 break; 1486 } 1487 1488 case DIOCGETSTATES: { 1489 struct pfioc_states *ps = (struct pfioc_states *)addr; 1490 struct pf_tree_node *n; 1491 struct pf_state *p, pstore; 1492 u_int32_t nr = 0; 1493 int space = ps->ps_len; 1494 1495 if (space == 0) { 1496 s = splsoftnet(); 1497 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) 1498 nr++; 1499 splx(s); 1500 ps->ps_len = sizeof(struct pf_state) * nr; 1501#ifdef __FreeBSD__ 1502 PF_UNLOCK(); 1503#endif 1504 return (0); 1505 } 1506 1507 s = splsoftnet(); 1508 p = ps->ps_states; 1509 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) { 1510#ifdef __FreeBSD__ 1511 int secs = time_second; 1512#else 1513 int secs = time.tv_sec; 1514#endif 1515 1516 if ((nr + 1) * sizeof(*p) > (unsigned)ps->ps_len) 1517 break; 1518 1519 bcopy(n->state, &pstore, sizeof(pstore)); 1520 pstore.rule.nr = n->state->rule.ptr->nr; 1521 pstore.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ? 1522 -1 : n->state->nat_rule.ptr->nr; 1523 pstore.anchor.nr = (n->state->anchor.ptr == NULL) ? 1524 -1 : n->state->anchor.ptr->nr; 1525 pstore.creation = secs - pstore.creation; 1526 pstore.expire = pf_state_expires(n->state); 1527 if (pstore.expire > secs) 1528 pstore.expire -= secs; 1529 else 1530 pstore.expire = 0; 1531#ifdef __FreeBSD__ 1532 PF_COPYOUT(&pstore, p, sizeof(*p), error); 1533#else 1534 error = copyout(&pstore, p, sizeof(*p)); 1535#endif 1536 if (error) { 1537 splx(s); 1538 goto fail; 1539 } 1540 p++; 1541 nr++; 1542 } 1543 ps->ps_len = sizeof(struct pf_state) * nr; 1544 splx(s); 1545 break; 1546 } 1547 1548 case DIOCGETSTATUS: { 1549 struct pf_status *s = (struct pf_status *)addr; 1550 bcopy(&pf_status, s, sizeof(struct pf_status)); 1551 break; 1552 } 1553 1554 case DIOCSETSTATUSIF: { 1555 struct pfioc_if *pi = (struct pfioc_if *)addr; 1556 struct ifnet *ifp; 1557 1558 if (pi->ifname[0] == 0) { 1559 status_ifp = NULL; 1560 bzero(pf_status.ifname, IFNAMSIZ); 1561 break; 1562 } 1563 if ((ifp = ifunit(pi->ifname)) == NULL) { 1564 error = EINVAL; 1565 break; 1566 } else if (ifp == status_ifp) 1567 break; 1568 status_ifp = ifp; 1569 /* fallthrough into DIOCCLRSTATUS */ 1570 } 1571 1572 case DIOCCLRSTATUS: { 1573 u_int32_t running = pf_status.running; 1574 u_int32_t states = pf_status.states; 1575 u_int32_t since = pf_status.since; 1576 u_int32_t debug = pf_status.debug; 1577 1578 bzero(&pf_status, sizeof(struct pf_status)); 1579 pf_status.running = running; 1580 pf_status.states = states; 1581 pf_status.since = since; 1582 pf_status.debug = debug; 1583 if (status_ifp != NULL) 1584#if defined(__FreeBSD__) && (__FreeBSD_version < 501113) 1585 snprintf(pf_status.ifname, IFNAMSIZ, "%s%d", 1586 status_ifp->if_name, status_ifp->if_unit); 1587#else 1588 strlcpy(pf_status.ifname, 1589 status_ifp->if_xname, IFNAMSIZ); 1590#endif 1591 break; 1592 } 1593 1594 case DIOCNATLOOK: { 1595 struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; 1596 struct pf_state *st; 1597 struct pf_tree_node key; 1598 int direction = pnl->direction; 1599 1600 key.af = pnl->af; 1601 key.proto = pnl->proto; 1602 1603 /* 1604 * userland gives us source and dest of connection, reverse 1605 * the lookup so we ask for what happens with the return 1606 * traffic, enabling us to find it in the state tree. 1607 */ 1608 PF_ACPY(&key.addr[1], &pnl->saddr, pnl->af); 1609 key.port[1] = pnl->sport; 1610 PF_ACPY(&key.addr[0], &pnl->daddr, pnl->af); 1611 key.port[0] = pnl->dport; 1612 1613 if (!pnl->proto || 1614 PF_AZERO(&pnl->saddr, pnl->af) || 1615 PF_AZERO(&pnl->daddr, pnl->af) || 1616 !pnl->dport || !pnl->sport) 1617 error = EINVAL; 1618 else { 1619 s = splsoftnet(); 1620 if (direction == PF_IN) 1621 st = pf_find_state(&tree_ext_gwy, &key); 1622 else 1623 st = pf_find_state(&tree_lan_ext, &key); 1624 if (st != NULL) { 1625 if (direction == PF_IN) { 1626 PF_ACPY(&pnl->rsaddr, &st->lan.addr, 1627 st->af); 1628 pnl->rsport = st->lan.port; 1629 PF_ACPY(&pnl->rdaddr, &pnl->daddr, 1630 pnl->af); 1631 pnl->rdport = pnl->dport; 1632 } else { 1633 PF_ACPY(&pnl->rdaddr, &st->gwy.addr, 1634 st->af); 1635 pnl->rdport = st->gwy.port; 1636 PF_ACPY(&pnl->rsaddr, &pnl->saddr, 1637 pnl->af); 1638 pnl->rsport = pnl->sport; 1639 } 1640 } else 1641 error = ENOENT; 1642 splx(s); 1643 } 1644 break; 1645 } 1646 1647 case DIOCSETTIMEOUT: { 1648 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 1649 int old; 1650 1651 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX || 1652 pt->seconds < 0) { 1653 error = EINVAL; 1654 goto fail; 1655 } 1656 old = pf_default_rule.timeout[pt->timeout]; 1657 pf_default_rule.timeout[pt->timeout] = pt->seconds; 1658 pt->seconds = old; 1659 break; 1660 } 1661 1662 case DIOCGETTIMEOUT: { 1663 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 1664 1665 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) { 1666 error = EINVAL; 1667 goto fail; 1668 } 1669 pt->seconds = pf_default_rule.timeout[pt->timeout]; 1670 break; 1671 } 1672 1673 case DIOCGETLIMIT: { 1674 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 1675 1676 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { 1677 error = EINVAL; 1678 goto fail; 1679 } 1680 pl->limit = pf_pool_limits[pl->index].limit; 1681 break; 1682 } 1683 1684 case DIOCSETLIMIT: { 1685 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 1686 int old_limit; 1687 1688 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { 1689 error = EINVAL; 1690 goto fail; 1691 } 1692#ifdef __FreeBSD__ 1693 uma_zone_set_max(pf_pool_limits[pl->index].pp, pl->limit); 1694#else 1695 if (pool_sethardlimit(pf_pool_limits[pl->index].pp, 1696 pl->limit, NULL, 0) != 0) { 1697 error = EBUSY; 1698 goto fail; 1699 } 1700#endif 1701 old_limit = pf_pool_limits[pl->index].limit; 1702 pf_pool_limits[pl->index].limit = pl->limit; 1703 pl->limit = old_limit; 1704 break; 1705 } 1706 1707 case DIOCSETDEBUG: { 1708 u_int32_t *level = (u_int32_t *)addr; 1709 1710 pf_status.debug = *level; 1711 break; 1712 } 1713 1714 case DIOCCLRRULECTRS: { 1715 struct pf_ruleset *ruleset = &pf_main_ruleset; 1716 struct pf_rule *rule; 1717 1718 s = splsoftnet(); 1719 TAILQ_FOREACH(rule, 1720 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) 1721 rule->evaluations = rule->packets = 1722 rule->bytes = 0; 1723 splx(s); 1724 break; 1725 } 1726 1727#ifdef __FreeBSD__ 1728 case DIOCGIFSPEED: { 1729 struct pf_ifspeed *psp = (struct pf_ifspeed *)addr; 1730 struct pf_ifspeed ps; 1731 struct ifnet *ifp; 1732 1733 if (psp->ifname[0] != 0) { 1734 /* Can we completely trust user-land? */ 1735 strlcpy(ps.ifname, psp->ifname, IFNAMSIZ); 1736 ifp = ifunit(ps.ifname); 1737 if (ifp ) 1738 psp->baudrate = ifp->if_baudrate; 1739 else 1740 error = EINVAL; 1741 } else 1742 error = EINVAL; 1743 break; 1744 } 1745#endif /* __FreeBSD__ */ 1746 1747#ifdef ALTQ 1748 case DIOCSTARTALTQ: { 1749 struct pf_altq *altq; 1750 struct ifnet *ifp; 1751 struct tb_profile tb; 1752 1753 /* enable all altq interfaces on active list */ 1754 s = splsoftnet(); 1755 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 1756 if (altq->qname[0] == 0) { 1757 if ((ifp = ifunit(altq->ifname)) == NULL) { 1758 error = EINVAL; 1759 break; 1760 } 1761 if (ifp->if_snd.altq_type != ALTQT_NONE) 1762 error = altq_enable(&ifp->if_snd); 1763 if (error != 0) 1764 break; 1765 /* set tokenbucket regulator */ 1766 tb.rate = altq->ifbandwidth; 1767 tb.depth = altq->tbrsize; 1768 error = tbr_set(&ifp->if_snd, &tb); 1769 if (error != 0) 1770 break; 1771 } 1772 } 1773#ifdef __FreeBSD__ 1774 if (error == 0) { 1775 mtx_lock(&pf_altq_mtx); 1776 pfaltq_running = 1; 1777 mtx_unlock(&pf_altq_mtx); 1778 } 1779#else 1780 if (error == 0) 1781 pfaltq_running = 1; 1782#endif 1783 splx(s); 1784 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n")); 1785 break; 1786 } 1787 1788 case DIOCSTOPALTQ: { 1789 struct pf_altq *altq; 1790 struct ifnet *ifp; 1791 struct tb_profile tb; 1792 int err; 1793 1794 /* disable all altq interfaces on active list */ 1795 s = splsoftnet(); 1796 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 1797 if (altq->qname[0] == 0) { 1798 if ((ifp = ifunit(altq->ifname)) == NULL) { 1799 error = EINVAL; 1800 break; 1801 } 1802 if (ifp->if_snd.altq_type != ALTQT_NONE) { 1803 err = altq_disable(&ifp->if_snd); 1804 if (err != 0 && error == 0) 1805 error = err; 1806 } 1807 /* clear tokenbucket regulator */ 1808 tb.rate = 0; 1809 err = tbr_set(&ifp->if_snd, &tb); 1810 if (err != 0 && error == 0) 1811 error = err; 1812 } 1813 } 1814#ifdef __FreeBSD__ 1815 if (error == 0) { 1816 mtx_lock(&pf_altq_mtx); 1817 pfaltq_running = 0; 1818 mtx_unlock(&pf_altq_mtx); 1819 } 1820#else 1821 if (error == 0) 1822 pfaltq_running = 0; 1823#endif 1824 splx(s); 1825 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n")); 1826 break; 1827 } 1828 1829 case DIOCBEGINALTQS: { 1830 u_int32_t *ticket = (u_int32_t *)addr; 1831 struct pf_altq *altq; 1832 1833 /* Purge the old altq list */ 1834 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 1835 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 1836 if (altq->qname[0] == 0) { 1837 /* detach and destroy the discipline */ 1838#ifdef __FreeBSD__ 1839 PF_UNLOCK(); 1840#endif 1841 error = altq_remove(altq); 1842#ifdef __FreeBSD__ 1843 PF_LOCK(); 1844#endif 1845 } 1846 pool_put(&pf_altq_pl, altq); 1847 } 1848 *ticket = ++ticket_altqs_inactive; 1849 break; 1850 } 1851 1852 case DIOCADDALTQ: { 1853 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 1854 struct pf_altq *altq, *a; 1855 1856 if (pa->ticket != ticket_altqs_inactive) { 1857 error = EBUSY; 1858 break; 1859 } 1860 altq = pool_get(&pf_altq_pl, PR_NOWAIT); 1861 if (altq == NULL) { 1862 error = ENOMEM; 1863 break; 1864 } 1865 bcopy(&pa->altq, altq, sizeof(struct pf_altq)); 1866 1867 /* 1868 * if this is for a queue, find the discipline and 1869 * copy the necessary fields 1870 */ 1871 if (altq->qname[0] != 0) { 1872 TAILQ_FOREACH(a, pf_altqs_inactive, entries) { 1873 if (strncmp(a->ifname, altq->ifname, 1874 IFNAMSIZ) == 0 && a->qname[0] == 0) { 1875 altq->altq_disc = a->altq_disc; 1876 break; 1877 } 1878 } 1879 } 1880 1881#ifdef __FreeBSD__ 1882 PF_UNLOCK(); 1883#endif 1884 error = altq_add(altq); 1885#ifdef __FreeBSD__ 1886 PF_LOCK(); 1887#endif 1888 if (error) { 1889 pool_put(&pf_altq_pl, altq); 1890 break; 1891 } 1892 1893 TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries); 1894 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 1895 break; 1896 } 1897 1898 case DIOCCOMMITALTQS: { 1899 u_int32_t *ticket = (u_int32_t *)addr; 1900 struct pf_altqqueue *old_altqs; 1901 struct pf_altq *altq; 1902 struct pf_anchor *anchor; 1903 struct pf_ruleset *ruleset; 1904 int err; 1905 1906 if (*ticket != ticket_altqs_inactive) { 1907 error = EBUSY; 1908 break; 1909 } 1910 1911 /* Swap altqs, keep the old. */ 1912 s = splsoftnet(); 1913 old_altqs = pf_altqs_active; 1914 pf_altqs_active = pf_altqs_inactive; 1915 pf_altqs_inactive = old_altqs; 1916 ticket_altqs_active = ticket_altqs_inactive; 1917 1918 /* Attach new disciplines */ 1919 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 1920 if (altq->qname[0] == 0) { 1921 /* attach the discipline */ 1922#ifdef __FreeBSD__ 1923 PF_UNLOCK(); 1924#endif 1925 error = altq_pfattach(altq); 1926#ifdef __FreeBSD__ 1927 PF_LOCK(); 1928#endif 1929 if (error) { 1930 splx(s); 1931 goto fail; 1932 } 1933 } 1934 } 1935 1936 /* Purge the old altq list */ 1937 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 1938 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 1939 if (altq->qname[0] == 0) { 1940 /* detach and destroy the discipline */ 1941#ifdef __FreeBSD__ 1942 PF_UNLOCK(); 1943#endif 1944 err = altq_pfdetach(altq); 1945 if (err != 0 && error == 0) 1946 error = err; 1947 err = altq_remove(altq); 1948 if (err != 0 && error == 0) 1949 error = err; 1950#ifdef __FreeBSD__ 1951 PF_LOCK(); 1952#endif 1953 } 1954 pool_put(&pf_altq_pl, altq); 1955 } 1956 splx(s); 1957 1958 /* update queue IDs */ 1959 pf_rule_set_qid( 1960 pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); 1961 TAILQ_FOREACH(anchor, &pf_anchors, entries) { 1962 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) { 1963 pf_rule_set_qid( 1964 ruleset->rules[PF_RULESET_FILTER].active.ptr 1965 ); 1966 } 1967 } 1968 break; 1969 } 1970 1971 case DIOCGETALTQS: { 1972 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 1973 struct pf_altq *altq; 1974 1975 pa->nr = 0; 1976 s = splsoftnet(); 1977 TAILQ_FOREACH(altq, pf_altqs_active, entries) 1978 pa->nr++; 1979 pa->ticket = ticket_altqs_active; 1980 splx(s); 1981 break; 1982 } 1983 1984 case DIOCGETALTQ: { 1985 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 1986 struct pf_altq *altq; 1987 u_int32_t nr; 1988 1989 if (pa->ticket != ticket_altqs_active) { 1990 error = EBUSY; 1991 break; 1992 } 1993 nr = 0; 1994 s = splsoftnet(); 1995 altq = TAILQ_FIRST(pf_altqs_active); 1996 while ((altq != NULL) && (nr < pa->nr)) { 1997 altq = TAILQ_NEXT(altq, entries); 1998 nr++; 1999 } 2000 if (altq == NULL) { 2001 error = EBUSY; 2002 splx(s); 2003 break; 2004 } 2005 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 2006 splx(s); 2007 break; 2008 } 2009 2010 case DIOCCHANGEALTQ: 2011 /* CHANGEALTQ not supported yet! */ 2012 error = ENODEV; 2013 break; 2014 2015 case DIOCGETQSTATS: { 2016 struct pfioc_qstats *pq = (struct pfioc_qstats *)addr; 2017 struct pf_altq *altq; 2018 u_int32_t nr; 2019 int nbytes; 2020 2021 if (pq->ticket != ticket_altqs_active) { 2022 error = EBUSY; 2023 break; 2024 } 2025 nbytes = pq->nbytes; 2026 nr = 0; 2027 s = splsoftnet(); 2028 altq = TAILQ_FIRST(pf_altqs_active); 2029 while ((altq != NULL) && (nr < pq->nr)) { 2030 altq = TAILQ_NEXT(altq, entries); 2031 nr++; 2032 } 2033 if (altq == NULL) { 2034 error = EBUSY; 2035 splx(s); 2036 break; 2037 } 2038#ifdef __FreeBSD__ 2039 PF_UNLOCK(); 2040#endif 2041 error = altq_getqstats(altq, pq->buf, &nbytes); 2042#ifdef __FreeBSD__ 2043 PF_LOCK(); 2044#endif 2045 splx(s); 2046 if (error == 0) { 2047 pq->scheduler = altq->scheduler; 2048 pq->nbytes = nbytes; 2049 } 2050 break; 2051 } 2052#endif /* ALTQ */ 2053 2054 case DIOCBEGINADDRS: { 2055 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2056 2057 pf_empty_pool(&pf_pabuf); 2058 pp->ticket = ++ticket_pabuf; 2059 break; 2060 } 2061 2062 case DIOCADDADDR: { 2063 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2064 2065#ifndef INET 2066 if (pp->af == AF_INET) { 2067 error = EAFNOSUPPORT; 2068 break; 2069 } 2070#endif /* INET */ 2071#ifndef INET6 2072 if (pp->af == AF_INET6) { 2073 error = EAFNOSUPPORT; 2074 break; 2075 } 2076#endif /* INET6 */ 2077 if (pp->addr.addr.type != PF_ADDR_ADDRMASK && 2078 pp->addr.addr.type != PF_ADDR_DYNIFTL && 2079 pp->addr.addr.type != PF_ADDR_TABLE) { 2080 error = EINVAL; 2081 break; 2082 } 2083 pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT); 2084 if (pa == NULL) { 2085 error = ENOMEM; 2086 break; 2087 } 2088 bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr)); 2089 if (pa->ifname[0]) { 2090 pa->ifp = ifunit(pa->ifname); 2091 if (pa->ifp == NULL) { 2092 pool_put(&pf_pooladdr_pl, pa); 2093 error = EINVAL; 2094 break; 2095 } 2096 } 2097 if (pf_dynaddr_setup(&pa->addr, pp->af)) { 2098 pf_dynaddr_remove(&pa->addr); 2099 pool_put(&pf_pooladdr_pl, pa); 2100 error = EINVAL; 2101 break; 2102 } 2103 TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries); 2104 break; 2105 } 2106 2107 case DIOCGETADDRS: { 2108 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2109 2110 pp->nr = 0; 2111 s = splsoftnet(); 2112 pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket, 2113 pp->r_action, pp->r_num, 0, 1, 0); 2114 if (pool == NULL) { 2115 error = EBUSY; 2116 splx(s); 2117 break; 2118 } 2119 TAILQ_FOREACH(pa, &pool->list, entries) 2120 pp->nr++; 2121 splx(s); 2122 break; 2123 } 2124 2125 case DIOCGETADDR: { 2126 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2127 u_int32_t nr = 0; 2128 2129 s = splsoftnet(); 2130 pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket, 2131 pp->r_action, pp->r_num, 0, 1, 1); 2132 if (pool == NULL) { 2133 error = EBUSY; 2134 splx(s); 2135 break; 2136 } 2137 pa = TAILQ_FIRST(&pool->list); 2138 while ((pa != NULL) && (nr < pp->nr)) { 2139 pa = TAILQ_NEXT(pa, entries); 2140 nr++; 2141 } 2142 if (pa == NULL) { 2143 error = EBUSY; 2144 splx(s); 2145 break; 2146 } 2147 bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr)); 2148 pf_dynaddr_copyout(&pp->addr.addr); 2149 pf_tbladdr_copyout(&pp->addr.addr); 2150 splx(s); 2151 break; 2152 } 2153 2154 case DIOCCHANGEADDR: { 2155 struct pfioc_pooladdr *pca = (struct pfioc_pooladdr *)addr; 2156 struct pf_pooladdr *oldpa = NULL, *newpa = NULL; 2157 struct pf_ruleset *ruleset; 2158 2159 if (pca->action < PF_CHANGE_ADD_HEAD || 2160 pca->action > PF_CHANGE_REMOVE) { 2161 error = EINVAL; 2162 break; 2163 } 2164 if (pca->addr.addr.type != PF_ADDR_ADDRMASK && 2165 pca->addr.addr.type != PF_ADDR_DYNIFTL && 2166 pca->addr.addr.type != PF_ADDR_TABLE) { 2167 error = EINVAL; 2168 break; 2169 } 2170 2171 ruleset = pf_find_ruleset(pca->anchor, pca->ruleset); 2172 if (ruleset == NULL) { 2173 error = EBUSY; 2174 break; 2175 } 2176 pool = pf_get_pool(pca->anchor, pca->ruleset, pca->ticket, 2177 pca->r_action, pca->r_num, pca->r_last, 1, 1); 2178 if (pool == NULL) { 2179 error = EBUSY; 2180 break; 2181 } 2182 if (pca->action != PF_CHANGE_REMOVE) { 2183 newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT); 2184 if (newpa == NULL) { 2185 error = ENOMEM; 2186 break; 2187 } 2188 bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr)); 2189#ifndef INET 2190 if (pca->af == AF_INET) { 2191 pool_put(&pf_pooladdr_pl, newpa); 2192 error = EAFNOSUPPORT; 2193 break; 2194 } 2195#endif /* INET */ 2196#ifndef INET6 2197 if (pca->af == AF_INET6) { 2198 pool_put(&pf_pooladdr_pl, newpa); 2199 error = EAFNOSUPPORT; 2200 break; 2201 } 2202#endif /* INET6 */ 2203 if (newpa->ifname[0]) { 2204 newpa->ifp = ifunit(newpa->ifname); 2205 if (newpa->ifp == NULL) { 2206 pool_put(&pf_pooladdr_pl, newpa); 2207 error = EINVAL; 2208 break; 2209 } 2210 } else 2211 newpa->ifp = NULL; 2212 if (pf_dynaddr_setup(&newpa->addr, pca->af) || 2213 pf_tbladdr_setup(ruleset, &newpa->addr)) { 2214 pf_dynaddr_remove(&newpa->addr); 2215 pool_put(&pf_pooladdr_pl, newpa); 2216 error = EINVAL; 2217 break; 2218 } 2219 } 2220 2221 s = splsoftnet(); 2222 2223 if (pca->action == PF_CHANGE_ADD_HEAD) 2224 oldpa = TAILQ_FIRST(&pool->list); 2225 else if (pca->action == PF_CHANGE_ADD_TAIL) 2226 oldpa = TAILQ_LAST(&pool->list, pf_palist); 2227 else { 2228 int i = 0; 2229 2230 oldpa = TAILQ_FIRST(&pool->list); 2231 while ((oldpa != NULL) && (i < pca->nr)) { 2232 oldpa = TAILQ_NEXT(oldpa, entries); 2233 i++; 2234 } 2235 if (oldpa == NULL) { 2236 error = EINVAL; 2237 splx(s); 2238 break; 2239 } 2240 } 2241 2242 if (pca->action == PF_CHANGE_REMOVE) { 2243 TAILQ_REMOVE(&pool->list, oldpa, entries); 2244 pf_dynaddr_remove(&oldpa->addr); 2245 pf_tbladdr_remove(&oldpa->addr); 2246 pool_put(&pf_pooladdr_pl, oldpa); 2247 } else { 2248 if (oldpa == NULL) 2249 TAILQ_INSERT_TAIL(&pool->list, newpa, entries); 2250 else if (pca->action == PF_CHANGE_ADD_HEAD || 2251 pca->action == PF_CHANGE_ADD_BEFORE) 2252 TAILQ_INSERT_BEFORE(oldpa, newpa, entries); 2253 else 2254 TAILQ_INSERT_AFTER(&pool->list, oldpa, 2255 newpa, entries); 2256 } 2257 2258 pool->cur = TAILQ_FIRST(&pool->list); 2259 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, 2260 pca->af); 2261 splx(s); 2262 break; 2263 } 2264 2265 case DIOCGETANCHORS: { 2266 struct pfioc_anchor *pa = (struct pfioc_anchor *)addr; 2267 struct pf_anchor *anchor; 2268 2269 pa->nr = 0; 2270 TAILQ_FOREACH(anchor, &pf_anchors, entries) 2271 pa->nr++; 2272 break; 2273 } 2274 2275 case DIOCGETANCHOR: { 2276 struct pfioc_anchor *pa = (struct pfioc_anchor *)addr; 2277 struct pf_anchor *anchor; 2278 u_int32_t nr = 0; 2279 2280 anchor = TAILQ_FIRST(&pf_anchors); 2281 while (anchor != NULL && nr < pa->nr) { 2282 anchor = TAILQ_NEXT(anchor, entries); 2283 nr++; 2284 } 2285 if (anchor == NULL) 2286 error = EBUSY; 2287 else 2288 bcopy(anchor->name, pa->name, sizeof(pa->name)); 2289 break; 2290 } 2291 2292 case DIOCGETRULESETS: { 2293 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 2294 struct pf_anchor *anchor; 2295 struct pf_ruleset *ruleset; 2296 2297 pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0; 2298 if ((anchor = pf_find_anchor(pr->anchor)) == NULL) { 2299 error = EINVAL; 2300 break; 2301 } 2302 pr->nr = 0; 2303 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) 2304 pr->nr++; 2305 break; 2306 } 2307 2308 case DIOCGETRULESET: { 2309 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 2310 struct pf_anchor *anchor; 2311 struct pf_ruleset *ruleset; 2312 u_int32_t nr = 0; 2313 2314 if ((anchor = pf_find_anchor(pr->anchor)) == NULL) { 2315 error = EINVAL; 2316 break; 2317 } 2318 ruleset = TAILQ_FIRST(&anchor->rulesets); 2319 while (ruleset != NULL && nr < pr->nr) { 2320 ruleset = TAILQ_NEXT(ruleset, entries); 2321 nr++; 2322 } 2323 if (ruleset == NULL) 2324 error = EBUSY; 2325 else 2326 bcopy(ruleset->name, pr->name, sizeof(pr->name)); 2327 break; 2328 } 2329 2330 case DIOCRCLRTABLES: { 2331 struct pfioc_table *io = (struct pfioc_table *)addr; 2332 2333 if (io->pfrio_esize != 0) { 2334 error = ENODEV; 2335 break; 2336 } 2337 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, 2338 io->pfrio_flags); 2339 break; 2340 } 2341 2342 case DIOCRADDTABLES: { 2343 struct pfioc_table *io = (struct pfioc_table *)addr; 2344 2345 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2346 error = ENODEV; 2347 break; 2348 } 2349 error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size, 2350 &io->pfrio_nadd, io->pfrio_flags); 2351 break; 2352 } 2353 2354 case DIOCRDELTABLES: { 2355 struct pfioc_table *io = (struct pfioc_table *)addr; 2356 2357 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2358 error = ENODEV; 2359 break; 2360 } 2361 error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size, 2362 &io->pfrio_ndel, io->pfrio_flags); 2363 break; 2364 } 2365 2366 case DIOCRGETTABLES: { 2367 struct pfioc_table *io = (struct pfioc_table *)addr; 2368 2369 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2370 error = ENODEV; 2371 break; 2372 } 2373 error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer, 2374 &io->pfrio_size, io->pfrio_flags); 2375 break; 2376 } 2377 2378 case DIOCRGETTSTATS: { 2379 struct pfioc_table *io = (struct pfioc_table *)addr; 2380 2381 if (io->pfrio_esize != sizeof(struct pfr_tstats)) { 2382 error = ENODEV; 2383 break; 2384 } 2385 error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer, 2386 &io->pfrio_size, io->pfrio_flags); 2387 break; 2388 } 2389 2390 case DIOCRCLRTSTATS: { 2391 struct pfioc_table *io = (struct pfioc_table *)addr; 2392 2393 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2394 error = ENODEV; 2395 break; 2396 } 2397 error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size, 2398 &io->pfrio_nzero, io->pfrio_flags); 2399 break; 2400 } 2401 2402 case DIOCRSETTFLAGS: { 2403 struct pfioc_table *io = (struct pfioc_table *)addr; 2404 2405 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2406 error = ENODEV; 2407 break; 2408 } 2409 error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size, 2410 io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange, 2411 &io->pfrio_ndel, io->pfrio_flags); 2412 break; 2413 } 2414 2415 case DIOCRCLRADDRS: { 2416 struct pfioc_table *io = (struct pfioc_table *)addr; 2417 2418 if (io->pfrio_esize != 0) { 2419 error = ENODEV; 2420 break; 2421 } 2422 error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel, 2423 io->pfrio_flags); 2424 break; 2425 } 2426 2427 case DIOCRADDADDRS: { 2428 struct pfioc_table *io = (struct pfioc_table *)addr; 2429 2430 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2431 error = ENODEV; 2432 break; 2433 } 2434 error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer, 2435 io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags); 2436 break; 2437 } 2438 2439 case DIOCRDELADDRS: { 2440 struct pfioc_table *io = (struct pfioc_table *)addr; 2441 2442 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2443 error = ENODEV; 2444 break; 2445 } 2446 error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer, 2447 io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags); 2448 break; 2449 } 2450 2451 case DIOCRSETADDRS: { 2452 struct pfioc_table *io = (struct pfioc_table *)addr; 2453 2454 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2455 error = ENODEV; 2456 break; 2457 } 2458 error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer, 2459 io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd, 2460 &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags); 2461 break; 2462 } 2463 2464 case DIOCRGETADDRS: { 2465 struct pfioc_table *io = (struct pfioc_table *)addr; 2466 2467 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2468 error = ENODEV; 2469 break; 2470 } 2471 error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer, 2472 &io->pfrio_size, io->pfrio_flags); 2473 break; 2474 } 2475 2476 case DIOCRGETASTATS: { 2477 struct pfioc_table *io = (struct pfioc_table *)addr; 2478 2479 if (io->pfrio_esize != sizeof(struct pfr_astats)) { 2480 error = ENODEV; 2481 break; 2482 } 2483 error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer, 2484 &io->pfrio_size, io->pfrio_flags); 2485 break; 2486 } 2487 2488 case DIOCRCLRASTATS: { 2489 struct pfioc_table *io = (struct pfioc_table *)addr; 2490 2491 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2492 error = ENODEV; 2493 break; 2494 } 2495 error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer, 2496 io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags); 2497 break; 2498 } 2499 2500 case DIOCRTSTADDRS: { 2501 struct pfioc_table *io = (struct pfioc_table *)addr; 2502 2503 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2504 error = ENODEV; 2505 break; 2506 } 2507 error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer, 2508 io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags); 2509 break; 2510 } 2511 2512 case DIOCRINABEGIN: { 2513 struct pfioc_table *io = (struct pfioc_table *)addr; 2514 2515 if (io->pfrio_esize != 0) { 2516 error = ENODEV; 2517 break; 2518 } 2519 error = pfr_ina_begin(&io->pfrio_table, &io->pfrio_ticket, 2520 &io->pfrio_ndel, io->pfrio_flags); 2521 break; 2522 } 2523 2524 case DIOCRINACOMMIT: { 2525 struct pfioc_table *io = (struct pfioc_table *)addr; 2526 2527 if (io->pfrio_esize != 0) { 2528 error = ENODEV; 2529 break; 2530 } 2531 error = pfr_ina_commit(&io->pfrio_table, io->pfrio_ticket, 2532 &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags); 2533 break; 2534 } 2535 2536 case DIOCRINADEFINE: { 2537 struct pfioc_table *io = (struct pfioc_table *)addr; 2538 2539 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2540 error = ENODEV; 2541 break; 2542 } 2543 error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer, 2544 io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr, 2545 io->pfrio_ticket, io->pfrio_flags); 2546 break; 2547 } 2548 2549 case DIOCOSFPFLUSH: 2550 s = splsoftnet(); 2551 pf_osfp_flush(); 2552 splx(s); 2553 break; 2554 2555 case DIOCOSFPADD: { 2556 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 2557 s = splsoftnet(); 2558 error = pf_osfp_add(io); 2559 splx(s); 2560 break; 2561 } 2562 2563 case DIOCOSFPGET: { 2564 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 2565 s = splsoftnet(); 2566 error = pf_osfp_get(io); 2567 splx(s); 2568 break; 2569 } 2570 2571 default: 2572 error = ENODEV; 2573 break; 2574 } 2575fail: 2576#ifdef __FreeBSD__ 2577 PF_UNLOCK(); 2578#endif 2579 return (error); 2580} 2581 2582#ifdef __FreeBSD__ 2583/* 2584 * XXX - Check for version missmatch!!! 2585 */ 2586static int 2587pf_beginrules(void *addr) 2588{ 2589 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 2590 struct pf_ruleset *ruleset; 2591 struct pf_rule *rule; 2592 int rs_num; 2593 int error = 0; 2594 2595 do { 2596 ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset); 2597 if (ruleset == NULL) { 2598 error = EINVAL; 2599 break; 2600 } 2601 rs_num = pf_get_ruleset_number(pr->rule.action); 2602 if (rs_num >= PF_RULESET_MAX) { 2603 error = EINVAL; 2604 break; 2605 } 2606 while ((rule = 2607 TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL) 2608 pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule); 2609 pr->ticket = ++ruleset->rules[rs_num].inactive.ticket; 2610 } while(0); 2611 2612 return (error); 2613} 2614 2615static int 2616pf_commitrules(void *addr) 2617{ 2618 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 2619 struct pf_ruleset *ruleset; 2620 struct pf_rulequeue *old_rules; 2621 struct pf_rule *rule; 2622 int rs_num, s; 2623 int error = 0; 2624 2625 do { 2626 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 2627 if (ruleset == NULL) { 2628 error = EINVAL; 2629 break; 2630 } 2631 rs_num = pf_get_ruleset_number(pr->rule.action); 2632 if (rs_num >= PF_RULESET_MAX) { 2633 error = EINVAL; 2634 break; 2635 } 2636 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { 2637 error = EBUSY; 2638 break; 2639 } 2640 2641#ifdef ALTQ 2642 /* set queue IDs */ 2643 if (rs_num == PF_RULESET_FILTER) 2644 pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr); 2645#endif 2646 2647 /* Swap rules, keep the old. */ 2648 s = splsoftnet(); 2649 old_rules = ruleset->rules[rs_num].active.ptr; 2650 ruleset->rules[rs_num].active.ptr = 2651 ruleset->rules[rs_num].inactive.ptr; 2652 ruleset->rules[rs_num].inactive.ptr = old_rules; 2653 ruleset->rules[rs_num].active.ticket = 2654 ruleset->rules[rs_num].inactive.ticket; 2655 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); 2656 2657 /* Purge the old rule list. */ 2658 while ((rule = TAILQ_FIRST(old_rules)) != NULL) 2659 pf_rm_rule(old_rules, rule); 2660 pf_remove_if_empty_ruleset(ruleset); 2661 pf_update_anchor_rules(); 2662 splx(s); 2663 } while (0); 2664 2665 return (error); 2666} 2667 2668#ifdef ALTQ 2669static int 2670pf_beginaltqs(void *addr) 2671{ 2672 u_int32_t *ticket = (u_int32_t *)addr; 2673 struct pf_altq *altq; 2674 int error = 0; 2675 2676 /* Purge the old altq list */ 2677 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 2678 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 2679 if (altq->qname[0] == 0) { 2680#ifdef __FreeBSD__ 2681 PF_UNLOCK(); 2682#endif 2683 /* detach and destroy the discipline */ 2684 error = altq_remove(altq); 2685#ifdef __FreeBSD__ 2686 PF_LOCK(); 2687#endif 2688 } 2689 uma_zfree(pf_altq_pl, altq); 2690 } 2691 *ticket = ++ticket_altqs_inactive; 2692 2693 return (error); 2694} 2695 2696static int 2697pf_commitaltqs(void *addr) 2698{ 2699 u_int32_t *ticket = (u_int32_t *)addr; 2700 struct pf_altqqueue *old_altqs; 2701 struct pf_altq *altq; 2702 struct pf_anchor *anchor; 2703 struct pf_ruleset *ruleset; 2704 int err; 2705 int s; 2706 int error = 0; 2707 2708 do { 2709 if (*ticket != ticket_altqs_inactive) { 2710 error = EBUSY; 2711 break; 2712 } 2713 2714 /* Swap altqs, keep the old. */ 2715 s = splsoftnet(); 2716 old_altqs = pf_altqs_active; 2717 pf_altqs_active = pf_altqs_inactive; 2718 pf_altqs_inactive = old_altqs; 2719 ticket_altqs_active = ticket_altqs_inactive; 2720 2721 /* Attach new disciplines */ 2722 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 2723 if (altq->qname[0] == 0) { 2724 /* attach the discipline */ 2725#ifdef __FreeBSD__ 2726 PF_UNLOCK(); 2727#endif 2728 error = altq_pfattach(altq); 2729#ifdef __FreeBSD__ 2730 PF_LOCK(); 2731#endif 2732 if (error) { 2733 splx(s); 2734 goto altq_fail; 2735 } 2736 } 2737 } 2738 2739 /* Purge the old altq list */ 2740 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 2741 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 2742 if (altq->qname[0] == 0) { 2743 /* detach and destroy the discipline */ 2744#ifdef __FreeBSD__ 2745 PF_UNLOCK(); 2746#endif 2747 err = altq_pfdetach(altq); 2748 if (err != 0 && error == 0) 2749 error = err; 2750 err = altq_remove(altq); 2751 if (err != 0 && error == 0) 2752 error = err; 2753#ifdef __FreeBSD__ 2754 PF_LOCK(); 2755#endif 2756 } 2757 uma_zfree(pf_altq_pl, altq); 2758 } 2759 splx(s); 2760 2761 /* update queue IDs */ 2762 pf_rule_set_qid( 2763 pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); 2764 TAILQ_FOREACH(anchor, &pf_anchors, entries) { 2765 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) { 2766 pf_rule_set_qid( 2767 ruleset->rules[PF_RULESET_FILTER].active.ptr 2768 ); 2769 } 2770 } 2771 } while (0); 2772 2773altq_fail: 2774 2775 return (error); 2776} 2777 2778static int 2779pf_stopaltq(void) 2780{ 2781 struct pf_altq *altq; 2782 struct ifnet *ifp; 2783 struct tb_profile tb; 2784 int err; 2785 int s; 2786 int error = 0; 2787 2788 do { 2789 /* disable all altq interfaces on active list */ 2790 s = splsoftnet(); 2791 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 2792 if (altq->qname[0] == 0) { 2793 if ((ifp = ifunit(altq->ifname)) == NULL) { 2794 error = EINVAL; 2795 break; 2796 } 2797 if (ifp->if_snd.altq_type != ALTQT_NONE) { 2798 err = altq_disable(&ifp->if_snd); 2799 if (err != 0 && error == 0) 2800 error = err; 2801 } 2802 /* clear tokenbucket regulator */ 2803 tb.rate = 0; 2804 err = tbr_set(&ifp->if_snd, &tb); 2805 if (err != 0 && error == 0) 2806 error = err; 2807 } 2808 } 2809#ifdef __FreeBSD__ 2810 if (error == 0) { 2811 mtx_lock(&pf_altq_mtx); 2812 pfaltq_running = 0; 2813 mtx_unlock(&pf_altq_mtx); 2814 } 2815#else 2816 if (error == 0) 2817 pfaltq_running = 0; 2818#endif 2819 splx(s); 2820 } while (0); 2821 2822 return (error); 2823} 2824#endif 2825 2826static void 2827pf_clearstates(void) 2828{ 2829 struct pf_tree_node *n; 2830 int s; 2831 2832 s = splsoftnet(); 2833 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) 2834 n->state->timeout = PFTM_PURGE; 2835 pf_purge_expired_states(); 2836 pf_status.states = 0; 2837 splx(s); 2838} 2839 2840static int 2841pf_clear_tables(void *addr) 2842{ 2843 struct pfioc_table *io = (struct pfioc_table *)addr; 2844 int error; 2845 2846 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, 2847 io->pfrio_flags); 2848 2849 return (error); 2850} 2851 2852static int 2853shutdown_pf(void) 2854{ 2855 struct pfioc_rule pr; 2856#ifdef ALTQ 2857 struct pfioc_altq pa; 2858#endif 2859 struct pfioc_table io; 2860 int error = 0; 2861 2862 callout_stop(&pf_expire_to); 2863 2864 PF_LOCK(); 2865 pf_status.running = 0; 2866 do { 2867#ifdef ALTQ 2868 if ((error = pf_stopaltq())) { 2869 DPFPRINTF(PF_DEBUG_MISC, 2870 ("ALTQ: stop(%i)\n", error)); 2871 break; 2872 } 2873#endif 2874 bzero(&pr, sizeof(pr)); 2875 pr.rule.action = PF_SCRUB; 2876 if ((error = pf_beginrules(&pr))) { 2877 DPFPRINTF(PF_DEBUG_MISC, 2878 ("PF_SCRUB: begin(%i)\n", error)); 2879 break; 2880 } 2881 if ((error = pf_commitrules(&pr))) { 2882 DPFPRINTF(PF_DEBUG_MISC, 2883 ("PF_SCRUB: commit(%i)\n", error)); 2884 break; 2885 } 2886 2887 pr.rule.action = PF_PASS; 2888 if ((error = pf_beginrules(&pr))) { 2889 DPFPRINTF(PF_DEBUG_MISC, 2890 ("PF_PASS: begin(%i)\n", error)); 2891 break; 2892 } 2893 if ((error = pf_commitrules(&pr))) { 2894 DPFPRINTF(PF_DEBUG_MISC, 2895 ("PF_PASS: commit(%i)\n", error)); 2896 break; 2897 } 2898 2899/* 2900 * XXX not sure, but can't hurt: 2901 */ 2902 bzero(&pr, sizeof(pr)); 2903 pr.rule.action = PF_NAT; 2904 if ((error = pf_beginrules(&pr))) { 2905 DPFPRINTF(PF_DEBUG_MISC, 2906 ("PF_NAT: begin(%i)\n", error)); 2907 break; 2908 } 2909 if ((error = pf_commitrules(&pr))) { 2910 DPFPRINTF(PF_DEBUG_MISC, 2911 ("PF_NAT: commit(%i)\n", error)); 2912 break; 2913 } 2914 2915 pr.rule.action = PF_BINAT; 2916 if ((error = pf_beginrules(&pr))) { 2917 DPFPRINTF(PF_DEBUG_MISC, 2918 ("PF_BINAT: begin(%i)\n", error)); 2919 break; 2920 } 2921 if ((error = pf_commitrules(&pr))) { 2922 DPFPRINTF(PF_DEBUG_MISC, 2923 ("PF_BINAT: begin(%i)\n", error)); 2924 break; 2925 } 2926 2927 pr.rule.action = PF_RDR; 2928 if ((error = pf_beginrules(&pr))) { 2929 DPFPRINTF(PF_DEBUG_MISC, 2930 ("PF_RDR: begin(%i)\n", error)); 2931 break; 2932 } 2933 if ((error = pf_commitrules(&pr))) { 2934 DPFPRINTF(PF_DEBUG_MISC, 2935 ("PF_RDR: commit(%i)\n", error)); 2936 break; 2937 } 2938 2939#ifdef ALTQ 2940 bzero(&pa, sizeof(pa)); 2941 if ((error = pf_beginaltqs(&pa))) { 2942 DPFPRINTF(PF_DEBUG_MISC, 2943 ("ALTQ: begin(%i)\n", error)); 2944 break; 2945 } 2946 if ((error = pf_commitaltqs(&pa))) { 2947 DPFPRINTF(PF_DEBUG_MISC, 2948 ("ALTQ: commit(%i)\n", error)); 2949 break; 2950 } 2951#endif 2952 pf_clearstates(); 2953 2954 bzero(&io, sizeof(io)); 2955 if ((error = pf_clear_tables(&io))) { 2956 DPFPRINTF(PF_DEBUG_MISC, 2957 ("TABLES: clear(%i)\n", error)); 2958 break; 2959 } 2960 pf_osfp_flush(); 2961 } while(0); 2962 2963 PF_UNLOCK(); 2964 return (error); 2965} 2966 2967static int 2968#if (__FreeBSD_version < 501108) 2969pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m) 2970#else 2971pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) 2972#endif 2973{ 2974 /* 2975 * XXX Wed Jul 9 22:03:16 2003 UTC 2976 * OpenBSD has changed its byte ordering convention on ip_len/ip_off 2977 * in network stack. OpenBSD's network stack have converted 2978 * ip_len/ip_off to host byte order frist as FreeBSD. 2979 * Now this is not true anymore , so we should convert back to network 2980 * byte order. 2981 */ 2982 struct ip *h = NULL; 2983 int chk; 2984 2985 if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) { 2986 /* if m_pkthdr.len is less than ip header, pf will handle. */ 2987 h = mtod(*m, struct ip *); 2988 HTONS(h->ip_len); 2989 HTONS(h->ip_off); 2990 } 2991 chk = pf_test(PF_IN, ifp, m); 2992 if (chk && *m) { 2993 m_freem(*m); 2994 *m = NULL; 2995 } 2996 if (*m != NULL) { 2997 /* pf_test can change ip header location */ 2998 h = mtod(*m, struct ip *); 2999 NTOHS(h->ip_len); 3000 NTOHS(h->ip_off); 3001 } 3002 return chk; 3003} 3004 3005static int 3006#if (__FreeBSD_version < 501108) 3007pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m) 3008#else 3009pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) 3010#endif 3011{ 3012 /* 3013 * XXX Wed Jul 9 22:03:16 2003 UTC 3014 * OpenBSD has changed its byte ordering convention on ip_len/ip_off 3015 * in network stack. OpenBSD's network stack have converted 3016 * ip_len/ip_off to host byte order frist as FreeBSD. 3017 * Now this is not true anymore , so we should convert back to network 3018 * byte order. 3019 */ 3020 struct ip *h = NULL; 3021 int chk; 3022 3023 /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */ 3024 if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 3025 in_delayed_cksum(*m); 3026 (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 3027 } 3028 if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) { 3029 /* if m_pkthdr.len is less than ip header, pf will handle. */ 3030 h = mtod(*m, struct ip *); 3031 HTONS(h->ip_len); 3032 HTONS(h->ip_off); 3033 } 3034 chk = pf_test(PF_OUT, ifp, m); 3035 if (chk && *m) { 3036 m_freem(*m); 3037 *m = NULL; 3038 } 3039 if (*m != NULL) { 3040 /* pf_test can change ip header location */ 3041 h = mtod(*m, struct ip *); 3042 NTOHS(h->ip_len); 3043 NTOHS(h->ip_off); 3044 } 3045 return chk; 3046} 3047 3048#ifdef INET6 3049static int 3050#if (__FreeBSD_version < 501108) 3051pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m) 3052#else 3053pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) 3054#endif 3055{ 3056 /* 3057 * IPv6 does not affected ip_len/ip_off byte order changes. 3058 */ 3059 int chk; 3060 3061 chk = pf_test6(PF_IN, ifp, m); 3062 if (chk && *m) { 3063 m_freem(*m); 3064 *m = NULL; 3065 } 3066 return chk; 3067} 3068 3069static int 3070#if (__FreeBSD_version < 501108) 3071pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m) 3072#else 3073pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) 3074#endif 3075{ 3076 /* 3077 * IPv6 does not affected ip_len/ip_off byte order changes. 3078 */ 3079 int chk; 3080 3081 /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */ 3082 if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 3083 in_delayed_cksum(*m); 3084 (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 3085 } 3086 chk = pf_test6(PF_OUT, ifp, m); 3087 if (chk && *m) { 3088 m_freem(*m); 3089 *m = NULL; 3090 } 3091 return chk; 3092} 3093#endif /* INET6 */ 3094 3095static int 3096hook_pf(void) 3097{ 3098#if (__FreeBSD_version >= 501108) 3099 struct pfil_head *pfh_inet; 3100#ifdef INET6 3101 struct pfil_head *pfh_inet6; 3102#endif 3103#endif 3104 3105 PF_ASSERT(MA_NOTOWNED); 3106 3107 if (pf_pfil_hooked) 3108 return (0); 3109 3110#if (__FreeBSD_version < 501108) 3111 /* 3112 * XXX 3113 * There is no easy way to get pfil header pointer with address 3114 * family such as AF_INET, AF_INET6. 3115 * Needs direct variable reference. 3116 */ 3117 3118 pfil_add_hook(pf_check_in, PFIL_IN, 3119 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 3120 pfil_add_hook(pf_check_out, PFIL_OUT, 3121 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 3122#ifdef INET6 3123 pfil_add_hook(pf_check6_in, PFIL_IN, 3124 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 3125 pfil_add_hook(pf_check6_out, PFIL_OUT, 3126 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 3127#endif 3128#else /* __FreeBSD_version >= 501108 */ 3129 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 3130 if (pfh_inet == NULL) 3131 return (ESRCH); /* XXX */ 3132 pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); 3133 pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); 3134#ifdef INET6 3135 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 3136 if (pfh_inet6 == NULL) { 3137 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, 3138 pfh_inet); 3139 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 3140 pfh_inet); 3141 return (ESRCH); /* XXX */ 3142 } 3143 pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); 3144 pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); 3145#endif 3146#endif /* __FreeBSD_version >= 501108 */ 3147 3148 pf_pfil_hooked = 1; 3149 return (0); 3150} 3151 3152static int 3153dehook_pf(void) 3154{ 3155#if (__FreeBSD_version >= 501108) 3156 struct pfil_head *pfh_inet; 3157#ifdef INET6 3158 struct pfil_head *pfh_inet6; 3159#endif 3160#endif 3161 3162 PF_ASSERT(MA_NOTOWNED); 3163 3164 if (pf_pfil_hooked == 0) 3165 return (0); 3166 3167#if (__FreeBSD_version < 501108) 3168 pfil_remove_hook(pf_check_in, PFIL_IN, 3169 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 3170 pfil_remove_hook(pf_check_out, PFIL_OUT, 3171 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 3172#ifdef INET6 3173 pfil_remove_hook(pf_check6_in, PFIL_IN, 3174 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 3175 pfil_remove_hook(pf_check6_out, PFIL_OUT, 3176 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 3177#endif 3178#else /* __FreeBSD_version >= 501108 */ 3179 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 3180 if (pfh_inet == NULL) 3181 return (ESRCH); /* XXX */ 3182 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, 3183 pfh_inet); 3184 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 3185 pfh_inet); 3186#ifdef INET6 3187 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 3188 if (pfh_inet6 == NULL) 3189 return (ESRCH); /* XXX */ 3190 pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, 3191 pfh_inet6); 3192 pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, 3193 pfh_inet6); 3194#endif 3195#endif /* __FreeBSD_version >= 501108 */ 3196 3197 pf_pfil_hooked = 0; 3198 return (0); 3199} 3200 3201static int 3202pf_load(void) 3203{ 3204 init_zone_var(); 3205 init_pf_mutex(); 3206 pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME); 3207 if (pfattach() < 0) { 3208 destroy_dev(pf_dev); 3209 destroy_pf_mutex(); 3210 return (ENOMEM); 3211 } 3212#ifdef ALTQ 3213 mtx_lock(&pf_altq_mtx); 3214 ++pfaltq_ref; 3215 mtx_unlock(&pf_altq_mtx); 3216#endif 3217 return (0); 3218} 3219 3220static int 3221pf_unload(void) 3222{ 3223 int error = 0; 3224 3225 PF_LOCK(); 3226 pf_status.running = 0; 3227 PF_UNLOCK(); 3228 error = dehook_pf(); 3229 if (error) { 3230 /* 3231 * Should not happen! 3232 * XXX Due to error code ESRCH, kldunload will show 3233 * a message like 'No such process'. 3234 */ 3235 printf("%s : pfil unregisteration fail\n", __FUNCTION__); 3236 return error; 3237 } 3238 shutdown_pf(); 3239 cleanup_pf_zone(); 3240 pf_osfp_cleanup(); 3241 destroy_dev(pf_dev); 3242#ifdef ALTQ 3243 mtx_lock(&pf_altq_mtx); 3244 --pfaltq_ref; 3245 mtx_unlock(&pf_altq_mtx); 3246#endif 3247 destroy_pf_mutex(); 3248 return error; 3249} 3250 3251static int 3252pf_modevent(module_t mod, int type, void *data) 3253{ 3254 int error = 0; 3255 3256 switch(type) { 3257 case MOD_LOAD: 3258 error = pf_load(); 3259 break; 3260 3261 case MOD_UNLOAD: 3262 error = pf_unload(); 3263 break; 3264 default: 3265 error = EINVAL; 3266 break; 3267 } 3268 return error; 3269} 3270 3271static moduledata_t pf_mod = { 3272 "pf", 3273 pf_modevent, 3274 0 3275}; 3276 3277DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 3278MODULE_DEPEND(pf, pflog, PFLOG_MINVER, PFLOG_PREFVER, PFLOG_MAXVER); 3279MODULE_DEPEND(pf, pfsync, PFSYNC_MINVER, PFSYNC_PREFVER, PFSYNC_MAXVER); 3280#ifdef ALTQ 3281MODULE_DEPEND(pf, pfaltq, PFALTQ_MINVER, PFALTQ_PREFVER, PFALTQ_MAXVER); 3282#endif 3283MODULE_VERSION(pf, PF_MODVER); 3284#endif /* __FreeBSD__ */ 3285