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