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