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