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