pf_ioctl.c revision 232292
1/* $OpenBSD: pf_ioctl.c,v 1.213 2009/02/15 21:46:12 mbalmer Exp $ */ 2 3/* 4 * Copyright (c) 2001 Daniel Hartmeier 5 * Copyright (c) 2002,2003 Henning Brauer 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * - Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * - Redistributions in binary form must reproduce the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer in the documentation and/or other materials provided 17 * with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 * 32 * Effort sponsored in part by the Defense Advanced Research Projects 33 * Agency (DARPA) and Air Force Research Laboratory, Air Force 34 * Materiel Command, USAF, under agreement number F30602-01-2-0537. 35 * 36 */ 37 38#ifdef __FreeBSD__ 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD: stable/9/sys/contrib/pf/net/pf_ioctl.c 232292 2012-02-29 09:47:26Z bz $"); 41 42#include "opt_inet.h" 43#include "opt_inet6.h" 44#include "opt_bpf.h" 45#include "opt_pf.h" 46 47#define NPFSYNC 1 48 49#ifdef DEV_PFLOG 50#define NPFLOG DEV_PFLOG 51#else 52#define NPFLOG 0 53#endif 54 55#else /* !__FreeBSD__ */ 56#include "pfsync.h" 57#include "pflog.h" 58#endif /* __FreeBSD__ */ 59 60#include <sys/param.h> 61#include <sys/systm.h> 62#include <sys/mbuf.h> 63#include <sys/filio.h> 64#include <sys/fcntl.h> 65#include <sys/socket.h> 66#include <sys/socketvar.h> 67#include <sys/kernel.h> 68#include <sys/time.h> 69#ifdef __FreeBSD__ 70#include <sys/ucred.h> 71#include <sys/jail.h> 72#include <sys/module.h> 73#include <sys/conf.h> 74#include <sys/proc.h> 75#include <sys/sysctl.h> 76#else 77#include <sys/timeout.h> 78#include <sys/pool.h> 79#endif 80#include <sys/proc.h> 81#include <sys/malloc.h> 82#include <sys/kthread.h> 83#ifndef __FreeBSD__ 84#include <sys/rwlock.h> 85#include <uvm/uvm_extern.h> 86#endif 87 88#include <net/if.h> 89#include <net/if_types.h> 90#ifdef __FreeBSD__ 91#include <net/vnet.h> 92#endif 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#ifdef __FreeBSD__ 103#include <sys/md5.h> 104#else 105#include <dev/rndvar.h> 106#include <crypto/md5.h> 107#endif 108#include <net/pfvar.h> 109 110#include <net/if_pfsync.h> 111 112#if NPFLOG > 0 113#include <net/if_pflog.h> 114#endif /* NPFLOG > 0 */ 115 116#ifdef INET6 117#include <netinet/ip6.h> 118#include <netinet/in_pcb.h> 119#endif /* INET6 */ 120 121#ifdef ALTQ 122#include <altq/altq.h> 123#endif 124 125#ifdef __FreeBSD__ 126#include <sys/limits.h> 127#include <sys/lock.h> 128#include <sys/mutex.h> 129#include <net/pfil.h> 130#endif /* __FreeBSD__ */ 131 132#ifdef __FreeBSD__ 133void init_zone_var(void); 134void cleanup_pf_zone(void); 135int pfattach(void); 136#else 137void pfattach(int); 138void pf_thread_create(void *); 139int pfopen(dev_t, int, int, struct proc *); 140int pfclose(dev_t, int, int, struct proc *); 141#endif 142struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t, 143 u_int8_t, u_int8_t, u_int8_t); 144 145void pf_mv_pool(struct pf_palist *, struct pf_palist *); 146void pf_empty_pool(struct pf_palist *); 147#ifdef __FreeBSD__ 148int pfioctl(struct cdev *, u_long, caddr_t, int, struct thread *); 149#else 150int pfioctl(dev_t, u_long, caddr_t, int, struct proc *); 151#endif 152#ifdef ALTQ 153int pf_begin_altq(u_int32_t *); 154int pf_rollback_altq(u_int32_t); 155int pf_commit_altq(u_int32_t); 156int pf_enable_altq(struct pf_altq *); 157int pf_disable_altq(struct pf_altq *); 158#endif /* ALTQ */ 159int pf_begin_rules(u_int32_t *, int, const char *); 160int pf_rollback_rules(u_int32_t, int, char *); 161int pf_setup_pfsync_matching(struct pf_ruleset *); 162void pf_hash_rule(MD5_CTX *, struct pf_rule *); 163void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *); 164int pf_commit_rules(u_int32_t, int, char *); 165int pf_addr_setup(struct pf_ruleset *, 166 struct pf_addr_wrap *, sa_family_t); 167void pf_addr_copyout(struct pf_addr_wrap *); 168 169#define TAGID_MAX 50000 170 171#ifdef __FreeBSD__ 172VNET_DEFINE(struct pf_rule, pf_default_rule); 173VNET_DEFINE(struct sx, pf_consistency_lock); 174 175#ifdef ALTQ 176static VNET_DEFINE(int, pf_altq_running); 177#define V_pf_altq_running VNET(pf_altq_running) 178#endif 179 180TAILQ_HEAD(pf_tags, pf_tagname); 181 182#define V_pf_tags VNET(pf_tags) 183VNET_DEFINE(struct pf_tags, pf_tags); 184#define V_pf_qids VNET(pf_qids) 185VNET_DEFINE(struct pf_tags, pf_qids); 186 187#else /* !__FreeBSD__ */ 188struct pf_rule pf_default_rule; 189struct rwlock pf_consistency_lock = RWLOCK_INITIALIZER("pfcnslk"); 190#ifdef ALTQ 191static int pf_altq_running; 192#endif 193 194TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags), 195 pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids); 196#endif /* __FreeBSD__ */ 197 198#if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE) 199#error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE 200#endif 201 202u_int16_t tagname2tag(struct pf_tags *, char *); 203void tag2tagname(struct pf_tags *, u_int16_t, char *); 204void tag_unref(struct pf_tags *, u_int16_t); 205int pf_rtlabel_add(struct pf_addr_wrap *); 206void pf_rtlabel_remove(struct pf_addr_wrap *); 207void pf_rtlabel_copyout(struct pf_addr_wrap *); 208 209#ifdef __FreeBSD__ 210#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x 211#else 212#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x 213#endif 214 215#ifdef __FreeBSD__ 216struct cdev *pf_dev; 217 218/* 219 * XXX - These are new and need to be checked when moveing to a new version 220 */ 221static void pf_clear_states(void); 222static int pf_clear_tables(void); 223static void pf_clear_srcnodes(void); 224/* 225 * XXX - These are new and need to be checked when moveing to a new version 226 */ 227 228/* 229 * Wrapper functions for pfil(9) hooks 230 */ 231#ifdef INET 232static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, 233 int dir, struct inpcb *inp); 234static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, 235 int dir, struct inpcb *inp); 236#endif 237#ifdef INET6 238static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, 239 int dir, struct inpcb *inp); 240static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, 241 int dir, struct inpcb *inp); 242#endif 243 244static int hook_pf(void); 245static int dehook_pf(void); 246static int shutdown_pf(void); 247static int pf_load(void); 248static int pf_unload(void); 249 250static struct cdevsw pf_cdevsw = { 251 .d_ioctl = pfioctl, 252 .d_name = PF_NAME, 253 .d_version = D_VERSION, 254}; 255 256static volatile VNET_DEFINE(int, pf_pfil_hooked); 257#define V_pf_pfil_hooked VNET(pf_pfil_hooked) 258VNET_DEFINE(int, pf_end_threads); 259struct mtx pf_task_mtx; 260 261/* pfsync */ 262pfsync_state_import_t *pfsync_state_import_ptr = NULL; 263pfsync_insert_state_t *pfsync_insert_state_ptr = NULL; 264pfsync_update_state_t *pfsync_update_state_ptr = NULL; 265pfsync_delete_state_t *pfsync_delete_state_ptr = NULL; 266pfsync_clear_states_t *pfsync_clear_states_ptr = NULL; 267pfsync_state_in_use_t *pfsync_state_in_use_ptr = NULL; 268pfsync_defer_t *pfsync_defer_ptr = NULL; 269pfsync_up_t *pfsync_up_ptr = NULL; 270/* pflow */ 271export_pflow_t *export_pflow_ptr = NULL; 272/* pflog */ 273pflog_packet_t *pflog_packet_ptr = NULL; 274 275VNET_DEFINE(int, debug_pfugidhack); 276SYSCTL_VNET_INT(_debug, OID_AUTO, pfugidhack, CTLFLAG_RW, 277 &VNET_NAME(debug_pfugidhack), 0, 278 "Enable/disable pf user/group rules mpsafe hack"); 279 280static void 281init_pf_mutex(void) 282{ 283 284 mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF); 285} 286 287static void 288destroy_pf_mutex(void) 289{ 290 291 mtx_destroy(&pf_task_mtx); 292} 293void 294init_zone_var(void) 295{ 296 V_pf_src_tree_pl = V_pf_rule_pl = NULL; 297 V_pf_state_pl = V_pf_state_key_pl = V_pf_state_item_pl = NULL; 298 V_pf_altq_pl = V_pf_pooladdr_pl = NULL; 299 V_pf_frent_pl = V_pf_frag_pl = V_pf_cache_pl = V_pf_cent_pl = NULL; 300 V_pf_state_scrub_pl = NULL; 301 V_pfr_ktable_pl = V_pfr_kentry_pl = NULL; 302} 303 304void 305cleanup_pf_zone(void) 306{ 307 UMA_DESTROY(V_pf_src_tree_pl); 308 UMA_DESTROY(V_pf_rule_pl); 309 UMA_DESTROY(V_pf_state_pl); 310 UMA_DESTROY(V_pf_state_key_pl); 311 UMA_DESTROY(V_pf_state_item_pl); 312 UMA_DESTROY(V_pf_altq_pl); 313 UMA_DESTROY(V_pf_pooladdr_pl); 314 UMA_DESTROY(V_pf_frent_pl); 315 UMA_DESTROY(V_pf_frag_pl); 316 UMA_DESTROY(V_pf_cache_pl); 317 UMA_DESTROY(V_pf_cent_pl); 318 UMA_DESTROY(V_pfr_ktable_pl); 319 UMA_DESTROY(V_pfr_kentry_pl); 320 UMA_DESTROY(V_pf_state_scrub_pl); 321 UMA_DESTROY(V_pfi_addr_pl); 322} 323 324int 325pfattach(void) 326{ 327 u_int32_t *my_timeout = V_pf_default_rule.timeout; 328 int error = 1; 329 330 do { 331 UMA_CREATE(V_pf_src_tree_pl, struct pf_src_node, "pfsrctrpl"); 332 UMA_CREATE(V_pf_rule_pl, struct pf_rule, "pfrulepl"); 333 UMA_CREATE(V_pf_state_pl, struct pf_state, "pfstatepl"); 334 UMA_CREATE(V_pf_state_key_pl, struct pf_state, "pfstatekeypl"); 335 UMA_CREATE(V_pf_state_item_pl, struct pf_state, "pfstateitempl"); 336 UMA_CREATE(V_pf_altq_pl, struct pf_altq, "pfaltqpl"); 337 UMA_CREATE(V_pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl"); 338 UMA_CREATE(V_pfr_ktable_pl, struct pfr_ktable, "pfrktable"); 339 UMA_CREATE(V_pfr_kentry_pl, struct pfr_kentry, "pfrkentry"); 340 UMA_CREATE(V_pf_frent_pl, struct pf_frent, "pffrent"); 341 UMA_CREATE(V_pf_frag_pl, struct pf_fragment, "pffrag"); 342 UMA_CREATE(V_pf_cache_pl, struct pf_fragment, "pffrcache"); 343 UMA_CREATE(V_pf_cent_pl, struct pf_frcache, "pffrcent"); 344 UMA_CREATE(V_pf_state_scrub_pl, struct pf_state_scrub, 345 "pfstatescrub"); 346 UMA_CREATE(V_pfi_addr_pl, struct pfi_dynaddr, "pfiaddrpl"); 347 error = 0; 348 } while(0); 349 if (error) { 350 cleanup_pf_zone(); 351 return (error); 352 } 353 pfr_initialize(); 354 pfi_initialize(); 355 if ( (error = pf_osfp_initialize()) ) { 356 cleanup_pf_zone(); 357 pf_osfp_cleanup(); 358 return (error); 359 } 360 361 V_pf_pool_limits[PF_LIMIT_STATES].pp = V_pf_state_pl; 362 V_pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT; 363 V_pf_pool_limits[PF_LIMIT_SRC_NODES].pp = V_pf_src_tree_pl; 364 V_pf_pool_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT; 365 V_pf_pool_limits[PF_LIMIT_FRAGS].pp = V_pf_frent_pl; 366 V_pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT; 367 V_pf_pool_limits[PF_LIMIT_TABLES].pp = V_pfr_ktable_pl; 368 V_pf_pool_limits[PF_LIMIT_TABLES].limit = PFR_KTABLE_HIWAT; 369 V_pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].pp = V_pfr_kentry_pl; 370 V_pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT; 371 uma_zone_set_max(V_pf_pool_limits[PF_LIMIT_STATES].pp, 372 V_pf_pool_limits[PF_LIMIT_STATES].limit); 373 374 RB_INIT(&V_tree_src_tracking); 375 RB_INIT(&V_pf_anchors); 376 pf_init_ruleset(&pf_main_ruleset); 377 378 TAILQ_INIT(&V_pf_altqs[0]); 379 TAILQ_INIT(&V_pf_altqs[1]); 380 TAILQ_INIT(&V_pf_pabuf); 381 V_pf_altqs_active = &V_pf_altqs[0]; 382 V_pf_altqs_inactive = &V_pf_altqs[1]; 383 TAILQ_INIT(&V_state_list); 384 385 /* default rule should never be garbage collected */ 386 V_pf_default_rule.entries.tqe_prev = &V_pf_default_rule.entries.tqe_next; 387 V_pf_default_rule.action = PF_PASS; 388 V_pf_default_rule.nr = -1; 389 V_pf_default_rule.rtableid = -1; 390 391 /* initialize default timeouts */ 392 my_timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; 393 my_timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; 394 my_timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; 395 my_timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; 396 my_timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; 397 my_timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; 398 my_timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; 399 my_timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; 400 my_timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; 401 my_timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; 402 my_timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; 403 my_timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; 404 my_timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; 405 my_timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; 406 my_timeout[PFTM_FRAG] = PFTM_FRAG_VAL; 407 my_timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; 408 my_timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; 409 my_timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; 410 my_timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; 411 my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; 412 413 pf_normalize_init(); 414 415 bzero(&V_pf_status, sizeof(V_pf_status)); 416 V_pf_status.debug = PF_DEBUG_URGENT; 417 418 V_pf_pfil_hooked = 0; 419 420 /* XXX do our best to avoid a conflict */ 421 V_pf_status.hostid = arc4random(); 422 423 if (kproc_create(pf_purge_thread, curvnet, NULL, 0, 0, "pfpurge")) 424 return (ENXIO); 425 426 m_addr_chg_pf_p = pf_pkt_addr_changed; 427 428 return (error); 429} 430#else /* !__FreeBSD__ */ 431 432void 433pfattach(int num) 434{ 435 u_int32_t *timeout = pf_default_rule.timeout; 436 437 pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl", 438 &pool_allocator_nointr); 439 pool_init(&pf_src_tree_pl, sizeof(struct pf_src_node), 0, 0, 0, 440 "pfsrctrpl", NULL); 441 pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", 442 NULL); 443 pool_init(&pf_state_key_pl, sizeof(struct pf_state_key), 0, 0, 0, 444 "pfstatekeypl", NULL); 445 pool_init(&pf_state_item_pl, sizeof(struct pf_state_item), 0, 0, 0, 446 "pfstateitempl", NULL); 447 pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", 448 &pool_allocator_nointr); 449 pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, 450 "pfpooladdrpl", &pool_allocator_nointr); 451 pfr_initialize(); 452 pfi_initialize(); 453 pf_osfp_initialize(); 454 455 pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp, 456 pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0); 457 458 if (physmem <= atop(100*1024*1024)) 459 pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = 460 PFR_KENTRY_HIWAT_SMALL; 461 462 RB_INIT(&tree_src_tracking); 463 RB_INIT(&pf_anchors); 464 pf_init_ruleset(&pf_main_ruleset); 465 TAILQ_INIT(&pf_altqs[0]); 466 TAILQ_INIT(&pf_altqs[1]); 467 TAILQ_INIT(&pf_pabuf); 468 pf_altqs_active = &pf_altqs[0]; 469 pf_altqs_inactive = &pf_altqs[1]; 470 TAILQ_INIT(&state_list); 471 472 /* default rule should never be garbage collected */ 473 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; 474 pf_default_rule.action = PF_PASS; 475 pf_default_rule.nr = -1; 476 pf_default_rule.rtableid = -1; 477 478 /* initialize default timeouts */ 479 timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; 480 timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; 481 timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; 482 timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; 483 timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; 484 timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; 485 timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; 486 timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; 487 timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; 488 timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; 489 timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; 490 timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; 491 timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; 492 timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; 493 timeout[PFTM_FRAG] = PFTM_FRAG_VAL; 494 timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; 495 timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; 496 timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; 497 timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; 498 timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; 499 500 pf_normalize_init(); 501 bzero(&pf_status, sizeof(pf_status)); 502 pf_status.debug = PF_DEBUG_URGENT; 503 504 /* XXX do our best to avoid a conflict */ 505 pf_status.hostid = arc4random(); 506 507 /* require process context to purge states, so perform in a thread */ 508 kthread_create_deferred(pf_thread_create, NULL); 509} 510 511void 512pf_thread_create(void *v) 513{ 514 if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge")) 515 panic("pfpurge thread"); 516} 517 518int 519pfopen(dev_t dev, int flags, int fmt, struct proc *p) 520{ 521 if (minor(dev) >= 1) 522 return (ENXIO); 523 return (0); 524} 525 526int 527pfclose(dev_t dev, int flags, int fmt, struct proc *p) 528{ 529 if (minor(dev) >= 1) 530 return (ENXIO); 531 return (0); 532} 533#endif 534 535struct pf_pool * 536pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action, 537 u_int32_t rule_number, u_int8_t r_last, u_int8_t active, 538 u_int8_t check_ticket) 539{ 540 struct pf_ruleset *ruleset; 541 struct pf_rule *rule; 542 int rs_num; 543 544 ruleset = pf_find_ruleset(anchor); 545 if (ruleset == NULL) 546 return (NULL); 547 rs_num = pf_get_ruleset_number(rule_action); 548 if (rs_num >= PF_RULESET_MAX) 549 return (NULL); 550 if (active) { 551 if (check_ticket && ticket != 552 ruleset->rules[rs_num].active.ticket) 553 return (NULL); 554 if (r_last) 555 rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 556 pf_rulequeue); 557 else 558 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 559 } else { 560 if (check_ticket && ticket != 561 ruleset->rules[rs_num].inactive.ticket) 562 return (NULL); 563 if (r_last) 564 rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 565 pf_rulequeue); 566 else 567 rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr); 568 } 569 if (!r_last) { 570 while ((rule != NULL) && (rule->nr != rule_number)) 571 rule = TAILQ_NEXT(rule, entries); 572 } 573 if (rule == NULL) 574 return (NULL); 575 576 return (&rule->rpool); 577} 578 579void 580pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb) 581{ 582 struct pf_pooladdr *mv_pool_pa; 583 584 while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) { 585 TAILQ_REMOVE(poola, mv_pool_pa, entries); 586 TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries); 587 } 588} 589 590void 591pf_empty_pool(struct pf_palist *poola) 592{ 593 struct pf_pooladdr *empty_pool_pa; 594 595 while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) { 596 pfi_dynaddr_remove(&empty_pool_pa->addr); 597 pf_tbladdr_remove(&empty_pool_pa->addr); 598 pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE); 599 TAILQ_REMOVE(poola, empty_pool_pa, entries); 600#ifdef __FreeBSD__ 601 pool_put(&V_pf_pooladdr_pl, empty_pool_pa); 602#else 603 pool_put(&pf_pooladdr_pl, empty_pool_pa); 604#endif 605 } 606} 607 608void 609pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) 610{ 611 if (rulequeue != NULL) { 612 if (rule->states_cur <= 0) { 613 /* 614 * XXX - we need to remove the table *before* detaching 615 * the rule to make sure the table code does not delete 616 * the anchor under our feet. 617 */ 618 pf_tbladdr_remove(&rule->src.addr); 619 pf_tbladdr_remove(&rule->dst.addr); 620 if (rule->overload_tbl) 621 pfr_detach_table(rule->overload_tbl); 622 } 623 TAILQ_REMOVE(rulequeue, rule, entries); 624 rule->entries.tqe_prev = NULL; 625 rule->nr = -1; 626 } 627 628 if (rule->states_cur > 0 || rule->src_nodes > 0 || 629 rule->entries.tqe_prev != NULL) 630 return; 631 pf_tag_unref(rule->tag); 632 pf_tag_unref(rule->match_tag); 633#ifdef ALTQ 634 if (rule->pqid != rule->qid) 635 pf_qid_unref(rule->pqid); 636 pf_qid_unref(rule->qid); 637#endif 638 pf_rtlabel_remove(&rule->src.addr); 639 pf_rtlabel_remove(&rule->dst.addr); 640 pfi_dynaddr_remove(&rule->src.addr); 641 pfi_dynaddr_remove(&rule->dst.addr); 642 if (rulequeue == NULL) { 643 pf_tbladdr_remove(&rule->src.addr); 644 pf_tbladdr_remove(&rule->dst.addr); 645 if (rule->overload_tbl) 646 pfr_detach_table(rule->overload_tbl); 647 } 648 pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE); 649 pf_anchor_remove(rule); 650 pf_empty_pool(&rule->rpool.list); 651#ifdef __FreeBSD__ 652 pool_put(&V_pf_rule_pl, rule); 653#else 654 pool_put(&pf_rule_pl, rule); 655#endif 656} 657 658u_int16_t 659tagname2tag(struct pf_tags *head, char *tagname) 660{ 661 struct pf_tagname *tag, *p = NULL; 662 u_int16_t new_tagid = 1; 663 664 TAILQ_FOREACH(tag, head, entries) 665 if (strcmp(tagname, tag->name) == 0) { 666 tag->ref++; 667 return (tag->tag); 668 } 669 670 /* 671 * to avoid fragmentation, we do a linear search from the beginning 672 * and take the first free slot we find. if there is none or the list 673 * is empty, append a new entry at the end. 674 */ 675 676 /* new entry */ 677 if (!TAILQ_EMPTY(head)) 678 for (p = TAILQ_FIRST(head); p != NULL && 679 p->tag == new_tagid; p = TAILQ_NEXT(p, entries)) 680 new_tagid = p->tag + 1; 681 682 if (new_tagid > TAGID_MAX) 683 return (0); 684 685 /* allocate and fill new struct pf_tagname */ 686 tag = malloc(sizeof(*tag), M_TEMP, M_NOWAIT|M_ZERO); 687 if (tag == NULL) 688 return (0); 689 strlcpy(tag->name, tagname, sizeof(tag->name)); 690 tag->tag = new_tagid; 691 tag->ref++; 692 693 if (p != NULL) /* insert new entry before p */ 694 TAILQ_INSERT_BEFORE(p, tag, entries); 695 else /* either list empty or no free slot in between */ 696 TAILQ_INSERT_TAIL(head, tag, entries); 697 698 return (tag->tag); 699} 700 701void 702tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p) 703{ 704 struct pf_tagname *tag; 705 706 TAILQ_FOREACH(tag, head, entries) 707 if (tag->tag == tagid) { 708 strlcpy(p, tag->name, PF_TAG_NAME_SIZE); 709 return; 710 } 711} 712 713void 714tag_unref(struct pf_tags *head, u_int16_t tag) 715{ 716 struct pf_tagname *p, *next; 717 718 if (tag == 0) 719 return; 720 721 for (p = TAILQ_FIRST(head); p != NULL; p = next) { 722 next = TAILQ_NEXT(p, entries); 723 if (tag == p->tag) { 724 if (--p->ref == 0) { 725 TAILQ_REMOVE(head, p, entries); 726 free(p, M_TEMP); 727 } 728 break; 729 } 730 } 731} 732 733u_int16_t 734pf_tagname2tag(char *tagname) 735{ 736#ifdef __FreeBSD__ 737 return (tagname2tag(&V_pf_tags, tagname)); 738#else 739 return (tagname2tag(&pf_tags, tagname)); 740#endif 741} 742 743void 744pf_tag2tagname(u_int16_t tagid, char *p) 745{ 746#ifdef __FreeBSD__ 747 tag2tagname(&V_pf_tags, tagid, p); 748#else 749 tag2tagname(&pf_tags, tagid, p); 750#endif 751} 752 753void 754pf_tag_ref(u_int16_t tag) 755{ 756 struct pf_tagname *t; 757 758#ifdef __FreeBSD__ 759 TAILQ_FOREACH(t, &V_pf_tags, entries) 760#else 761 TAILQ_FOREACH(t, &pf_tags, entries) 762#endif 763 if (t->tag == tag) 764 break; 765 if (t != NULL) 766 t->ref++; 767} 768 769void 770pf_tag_unref(u_int16_t tag) 771{ 772#ifdef __FreeBSD__ 773 tag_unref(&V_pf_tags, tag); 774#else 775 tag_unref(&pf_tags, tag); 776#endif 777} 778 779int 780pf_rtlabel_add(struct pf_addr_wrap *a) 781{ 782#ifdef __FreeBSD__ 783 /* XXX_IMPORT: later */ 784 return (0); 785#else 786 if (a->type == PF_ADDR_RTLABEL && 787 (a->v.rtlabel = rtlabel_name2id(a->v.rtlabelname)) == 0) 788 return (-1); 789 return (0); 790#endif 791} 792 793void 794pf_rtlabel_remove(struct pf_addr_wrap *a) 795{ 796#ifdef __FreeBSD__ 797 /* XXX_IMPORT: later */ 798#else 799 if (a->type == PF_ADDR_RTLABEL) 800 rtlabel_unref(a->v.rtlabel); 801#endif 802} 803 804void 805pf_rtlabel_copyout(struct pf_addr_wrap *a) 806{ 807#ifdef __FreeBSD__ 808 /* XXX_IMPORT: later */ 809 if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) 810 strlcpy(a->v.rtlabelname, "?", sizeof(a->v.rtlabelname)); 811#else 812 const char *name; 813 814 if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) { 815 if ((name = rtlabel_id2name(a->v.rtlabel)) == NULL) 816 strlcpy(a->v.rtlabelname, "?", 817 sizeof(a->v.rtlabelname)); 818 else 819 strlcpy(a->v.rtlabelname, name, 820 sizeof(a->v.rtlabelname)); 821 } 822#endif 823} 824 825#ifdef ALTQ 826u_int32_t 827pf_qname2qid(char *qname) 828{ 829#ifdef __FreeBSD__ 830 return ((u_int32_t)tagname2tag(&V_pf_qids, qname)); 831#else 832 return ((u_int32_t)tagname2tag(&pf_qids, qname)); 833#endif 834} 835 836void 837pf_qid2qname(u_int32_t qid, char *p) 838{ 839#ifdef __FreeBSD__ 840 tag2tagname(&V_pf_qids, (u_int16_t)qid, p); 841#else 842 tag2tagname(&pf_qids, (u_int16_t)qid, p); 843#endif 844} 845 846void 847pf_qid_unref(u_int32_t qid) 848{ 849#ifdef __FreeBSD__ 850 tag_unref(&V_pf_qids, (u_int16_t)qid); 851#else 852 tag_unref(&pf_qids, (u_int16_t)qid); 853#endif 854} 855 856int 857pf_begin_altq(u_int32_t *ticket) 858{ 859 struct pf_altq *altq; 860 int error = 0; 861 862 /* Purge the old altq list */ 863#ifdef __FreeBSD__ 864 while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) { 865 TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries); 866 if (altq->qname[0] == 0 && 867 (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 868#else 869 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 870 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 871 if (altq->qname[0] == 0) { 872#endif 873 /* detach and destroy the discipline */ 874 error = altq_remove(altq); 875 } else 876 pf_qid_unref(altq->qid); 877#ifdef __FreeBSD__ 878 pool_put(&V_pf_altq_pl, altq); 879#else 880 pool_put(&pf_altq_pl, altq); 881#endif 882 } 883 if (error) 884 return (error); 885#ifdef __FreeBSD__ 886 *ticket = ++V_ticket_altqs_inactive; 887 V_altqs_inactive_open = 1; 888#else 889 *ticket = ++ticket_altqs_inactive; 890 altqs_inactive_open = 1; 891#endif 892 return (0); 893} 894 895int 896pf_rollback_altq(u_int32_t ticket) 897{ 898 struct pf_altq *altq; 899 int error = 0; 900 901#ifdef __FreeBSD__ 902 if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive) 903 return (0); 904 /* Purge the old altq list */ 905 while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) { 906 TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries); 907 if (altq->qname[0] == 0 && 908 (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 909#else 910 if (!altqs_inactive_open || ticket != ticket_altqs_inactive) 911 return (0); 912 /* Purge the old altq list */ 913 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 914 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 915 if (altq->qname[0] == 0) { 916#endif 917 /* detach and destroy the discipline */ 918 error = altq_remove(altq); 919 } else 920 pf_qid_unref(altq->qid); 921#ifdef __FreeBSD__ 922 pool_put(&V_pf_altq_pl, altq); 923#else 924 pool_put(&pf_altq_pl, altq); 925#endif 926 } 927#ifdef __FreeBSD__ 928 V_altqs_inactive_open = 0; 929#else 930 altqs_inactive_open = 0; 931#endif 932 return (error); 933} 934 935int 936pf_commit_altq(u_int32_t ticket) 937{ 938 struct pf_altqqueue *old_altqs; 939 struct pf_altq *altq; 940 int s, err, error = 0; 941 942#ifdef __FreeBSD__ 943 if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive) 944#else 945 if (!altqs_inactive_open || ticket != ticket_altqs_inactive) 946#endif 947 return (EBUSY); 948 949 /* swap altqs, keep the old. */ 950 s = splsoftnet(); 951#ifdef __FreeBSD__ 952 old_altqs = V_pf_altqs_active; 953 V_pf_altqs_active = V_pf_altqs_inactive; 954 V_pf_altqs_inactive = old_altqs; 955 V_ticket_altqs_active = V_ticket_altqs_inactive; 956#else 957 old_altqs = pf_altqs_active; 958 pf_altqs_active = pf_altqs_inactive; 959 pf_altqs_inactive = old_altqs; 960 ticket_altqs_active = ticket_altqs_inactive; 961#endif 962 963 /* Attach new disciplines */ 964#ifdef __FreeBSD__ 965 TAILQ_FOREACH(altq, V_pf_altqs_active, entries) { 966 if (altq->qname[0] == 0 && 967 (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 968#else 969 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 970 if (altq->qname[0] == 0) { 971#endif 972 /* attach the discipline */ 973 error = altq_pfattach(altq); 974#ifdef __FreeBSD__ 975 if (error == 0 && V_pf_altq_running) 976#else 977 if (error == 0 && pf_altq_running) 978#endif 979 error = pf_enable_altq(altq); 980 if (error != 0) { 981 splx(s); 982 return (error); 983 } 984 } 985 } 986 987 /* Purge the old altq list */ 988#ifdef __FreeBSD__ 989 while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) { 990 TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries); 991 if (altq->qname[0] == 0 && 992 (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 993#else 994 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 995 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 996 if (altq->qname[0] == 0) { 997#endif 998 /* detach and destroy the discipline */ 999#ifdef __FreeBSD__ 1000 if (V_pf_altq_running) 1001#else 1002 if (pf_altq_running) 1003#endif 1004 error = pf_disable_altq(altq); 1005 err = altq_pfdetach(altq); 1006 if (err != 0 && error == 0) 1007 error = err; 1008 err = altq_remove(altq); 1009 if (err != 0 && error == 0) 1010 error = err; 1011 } else 1012 pf_qid_unref(altq->qid); 1013#ifdef __FreeBSD__ 1014 pool_put(&V_pf_altq_pl, altq); 1015#else 1016 pool_put(&pf_altq_pl, altq); 1017#endif 1018 } 1019 splx(s); 1020 1021#ifdef __FreeBSD__ 1022 V_altqs_inactive_open = 0; 1023#else 1024 altqs_inactive_open = 0; 1025#endif 1026 return (error); 1027} 1028 1029int 1030pf_enable_altq(struct pf_altq *altq) 1031{ 1032 struct ifnet *ifp; 1033 struct tb_profile tb; 1034 int s, error = 0; 1035 1036 if ((ifp = ifunit(altq->ifname)) == NULL) 1037 return (EINVAL); 1038 1039 if (ifp->if_snd.altq_type != ALTQT_NONE) 1040 error = altq_enable(&ifp->if_snd); 1041 1042 /* set tokenbucket regulator */ 1043 if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { 1044 tb.rate = altq->ifbandwidth; 1045 tb.depth = altq->tbrsize; 1046 s = splnet(); 1047#ifdef __FreeBSD__ 1048 PF_UNLOCK(); 1049#endif 1050 error = tbr_set(&ifp->if_snd, &tb); 1051#ifdef __FreeBSD__ 1052 PF_LOCK(); 1053#endif 1054 splx(s); 1055 } 1056 1057 return (error); 1058} 1059 1060int 1061pf_disable_altq(struct pf_altq *altq) 1062{ 1063 struct ifnet *ifp; 1064 struct tb_profile tb; 1065 int s, error; 1066 1067 if ((ifp = ifunit(altq->ifname)) == NULL) 1068 return (EINVAL); 1069 1070 /* 1071 * when the discipline is no longer referenced, it was overridden 1072 * by a new one. if so, just return. 1073 */ 1074 if (altq->altq_disc != ifp->if_snd.altq_disc) 1075 return (0); 1076 1077 error = altq_disable(&ifp->if_snd); 1078 1079 if (error == 0) { 1080 /* clear tokenbucket regulator */ 1081 tb.rate = 0; 1082 s = splnet(); 1083#ifdef __FreeBSD__ 1084 PF_UNLOCK(); 1085#endif 1086 error = tbr_set(&ifp->if_snd, &tb); 1087#ifdef __FreeBSD__ 1088 PF_LOCK(); 1089#endif 1090 splx(s); 1091 } 1092 1093 return (error); 1094} 1095 1096#ifdef __FreeBSD__ 1097void 1098pf_altq_ifnet_event(struct ifnet *ifp, int remove) 1099{ 1100 struct ifnet *ifp1; 1101 struct pf_altq *a1, *a2, *a3; 1102 u_int32_t ticket; 1103 int error = 0; 1104 1105 /* Interrupt userland queue modifications */ 1106#ifdef __FreeBSD__ 1107 if (V_altqs_inactive_open) 1108 pf_rollback_altq(V_ticket_altqs_inactive); 1109#else 1110 if (altqs_inactive_open) 1111 pf_rollback_altq(ticket_altqs_inactive); 1112#endif 1113 1114 /* Start new altq ruleset */ 1115 if (pf_begin_altq(&ticket)) 1116 return; 1117 1118 /* Copy the current active set */ 1119#ifdef __FreeBSD__ 1120 TAILQ_FOREACH(a1, V_pf_altqs_active, entries) { 1121 a2 = pool_get(&V_pf_altq_pl, PR_NOWAIT); 1122#else 1123 TAILQ_FOREACH(a1, pf_altqs_active, entries) { 1124 a2 = pool_get(&pf_altq_pl, PR_NOWAIT); 1125#endif 1126 if (a2 == NULL) { 1127 error = ENOMEM; 1128 break; 1129 } 1130 bcopy(a1, a2, sizeof(struct pf_altq)); 1131 1132 if (a2->qname[0] != 0) { 1133 if ((a2->qid = pf_qname2qid(a2->qname)) == 0) { 1134 error = EBUSY; 1135#ifdef __FreeBSD__ 1136 pool_put(&V_pf_altq_pl, a2); 1137#else 1138 pool_put(&pf_altq_pl, a2); 1139#endif 1140 break; 1141 } 1142 a2->altq_disc = NULL; 1143#ifdef __FreeBSD__ 1144 TAILQ_FOREACH(a3, V_pf_altqs_inactive, entries) { 1145#else 1146 TAILQ_FOREACH(a3, pf_altqs_inactive, entries) { 1147#endif 1148 if (strncmp(a3->ifname, a2->ifname, 1149 IFNAMSIZ) == 0 && a3->qname[0] == 0) { 1150 a2->altq_disc = a3->altq_disc; 1151 break; 1152 } 1153 } 1154 } 1155 /* Deactivate the interface in question */ 1156 a2->local_flags &= ~PFALTQ_FLAG_IF_REMOVED; 1157 if ((ifp1 = ifunit(a2->ifname)) == NULL || 1158 (remove && ifp1 == ifp)) { 1159 a2->local_flags |= PFALTQ_FLAG_IF_REMOVED; 1160 } else { 1161 PF_UNLOCK(); 1162 error = altq_add(a2); 1163 PF_LOCK(); 1164 1165#ifdef __FreeBSD__ 1166 if (ticket != V_ticket_altqs_inactive) 1167#else 1168 if (ticket != ticket_altqs_inactive) 1169#endif 1170 error = EBUSY; 1171 1172 if (error) { 1173#ifdef __FreeBSD__ 1174 pool_put(&V_pf_altq_pl, a2); 1175#else 1176 pool_put(&pf_altq_pl, a2); 1177#endif 1178 break; 1179 } 1180 } 1181 1182#ifdef __FreeBSD__ 1183 TAILQ_INSERT_TAIL(V_pf_altqs_inactive, a2, entries); 1184#else 1185 TAILQ_INSERT_TAIL(pf_altqs_inactive, a2, entries); 1186#endif 1187 } 1188 1189 if (error != 0) 1190 pf_rollback_altq(ticket); 1191 else 1192 pf_commit_altq(ticket); 1193 } 1194#endif 1195#endif /* ALTQ */ 1196 1197int 1198pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor) 1199{ 1200 struct pf_ruleset *rs; 1201 struct pf_rule *rule; 1202 1203 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 1204 return (EINVAL); 1205 rs = pf_find_or_create_ruleset(anchor); 1206 if (rs == NULL) 1207 return (EINVAL); 1208 while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) { 1209 pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); 1210 rs->rules[rs_num].inactive.rcount--; 1211 } 1212 *ticket = ++rs->rules[rs_num].inactive.ticket; 1213 rs->rules[rs_num].inactive.open = 1; 1214 return (0); 1215} 1216 1217int 1218pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor) 1219{ 1220 struct pf_ruleset *rs; 1221 struct pf_rule *rule; 1222 1223 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 1224 return (EINVAL); 1225 rs = pf_find_ruleset(anchor); 1226 if (rs == NULL || !rs->rules[rs_num].inactive.open || 1227 rs->rules[rs_num].inactive.ticket != ticket) 1228 return (0); 1229 while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) { 1230 pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); 1231 rs->rules[rs_num].inactive.rcount--; 1232 } 1233 rs->rules[rs_num].inactive.open = 0; 1234 return (0); 1235} 1236 1237#define PF_MD5_UPD(st, elm) \ 1238 MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm)) 1239 1240#define PF_MD5_UPD_STR(st, elm) \ 1241 MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm)) 1242 1243#define PF_MD5_UPD_HTONL(st, elm, stor) do { \ 1244 (stor) = htonl((st)->elm); \ 1245 MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\ 1246} while (0) 1247 1248#define PF_MD5_UPD_HTONS(st, elm, stor) do { \ 1249 (stor) = htons((st)->elm); \ 1250 MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\ 1251} while (0) 1252 1253void 1254pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr) 1255{ 1256 PF_MD5_UPD(pfr, addr.type); 1257 switch (pfr->addr.type) { 1258 case PF_ADDR_DYNIFTL: 1259 PF_MD5_UPD(pfr, addr.v.ifname); 1260 PF_MD5_UPD(pfr, addr.iflags); 1261 break; 1262 case PF_ADDR_TABLE: 1263 PF_MD5_UPD(pfr, addr.v.tblname); 1264 break; 1265 case PF_ADDR_ADDRMASK: 1266 /* XXX ignore af? */ 1267 PF_MD5_UPD(pfr, addr.v.a.addr.addr32); 1268 PF_MD5_UPD(pfr, addr.v.a.mask.addr32); 1269 break; 1270 case PF_ADDR_RTLABEL: 1271 PF_MD5_UPD(pfr, addr.v.rtlabelname); 1272 break; 1273 } 1274 1275 PF_MD5_UPD(pfr, port[0]); 1276 PF_MD5_UPD(pfr, port[1]); 1277 PF_MD5_UPD(pfr, neg); 1278 PF_MD5_UPD(pfr, port_op); 1279} 1280 1281void 1282pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule) 1283{ 1284 u_int16_t x; 1285 u_int32_t y; 1286 1287 pf_hash_rule_addr(ctx, &rule->src); 1288 pf_hash_rule_addr(ctx, &rule->dst); 1289 PF_MD5_UPD_STR(rule, label); 1290 PF_MD5_UPD_STR(rule, ifname); 1291 PF_MD5_UPD_STR(rule, match_tagname); 1292 PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */ 1293 PF_MD5_UPD_HTONL(rule, os_fingerprint, y); 1294 PF_MD5_UPD_HTONL(rule, prob, y); 1295 PF_MD5_UPD_HTONL(rule, uid.uid[0], y); 1296 PF_MD5_UPD_HTONL(rule, uid.uid[1], y); 1297 PF_MD5_UPD(rule, uid.op); 1298 PF_MD5_UPD_HTONL(rule, gid.gid[0], y); 1299 PF_MD5_UPD_HTONL(rule, gid.gid[1], y); 1300 PF_MD5_UPD(rule, gid.op); 1301 PF_MD5_UPD_HTONL(rule, rule_flag, y); 1302 PF_MD5_UPD(rule, action); 1303 PF_MD5_UPD(rule, direction); 1304 PF_MD5_UPD(rule, af); 1305 PF_MD5_UPD(rule, quick); 1306 PF_MD5_UPD(rule, ifnot); 1307 PF_MD5_UPD(rule, match_tag_not); 1308 PF_MD5_UPD(rule, natpass); 1309 PF_MD5_UPD(rule, keep_state); 1310 PF_MD5_UPD(rule, proto); 1311 PF_MD5_UPD(rule, type); 1312 PF_MD5_UPD(rule, code); 1313 PF_MD5_UPD(rule, flags); 1314 PF_MD5_UPD(rule, flagset); 1315 PF_MD5_UPD(rule, allow_opts); 1316 PF_MD5_UPD(rule, rt); 1317 PF_MD5_UPD(rule, tos); 1318} 1319 1320int 1321pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) 1322{ 1323 struct pf_ruleset *rs; 1324 struct pf_rule *rule, **old_array; 1325 struct pf_rulequeue *old_rules; 1326 int s, error; 1327 u_int32_t old_rcount; 1328 1329 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 1330 return (EINVAL); 1331 rs = pf_find_ruleset(anchor); 1332 if (rs == NULL || !rs->rules[rs_num].inactive.open || 1333 ticket != rs->rules[rs_num].inactive.ticket) 1334 return (EBUSY); 1335 1336 /* Calculate checksum for the main ruleset */ 1337 if (rs == &pf_main_ruleset) { 1338 error = pf_setup_pfsync_matching(rs); 1339 if (error != 0) 1340 return (error); 1341 } 1342 1343 /* Swap rules, keep the old. */ 1344 s = splsoftnet(); 1345 old_rules = rs->rules[rs_num].active.ptr; 1346 old_rcount = rs->rules[rs_num].active.rcount; 1347 old_array = rs->rules[rs_num].active.ptr_array; 1348 1349 rs->rules[rs_num].active.ptr = 1350 rs->rules[rs_num].inactive.ptr; 1351 rs->rules[rs_num].active.ptr_array = 1352 rs->rules[rs_num].inactive.ptr_array; 1353 rs->rules[rs_num].active.rcount = 1354 rs->rules[rs_num].inactive.rcount; 1355 rs->rules[rs_num].inactive.ptr = old_rules; 1356 rs->rules[rs_num].inactive.ptr_array = old_array; 1357 rs->rules[rs_num].inactive.rcount = old_rcount; 1358 1359 rs->rules[rs_num].active.ticket = 1360 rs->rules[rs_num].inactive.ticket; 1361 pf_calc_skip_steps(rs->rules[rs_num].active.ptr); 1362 1363 1364 /* Purge the old rule list. */ 1365 while ((rule = TAILQ_FIRST(old_rules)) != NULL) 1366 pf_rm_rule(old_rules, rule); 1367 if (rs->rules[rs_num].inactive.ptr_array) 1368 free(rs->rules[rs_num].inactive.ptr_array, M_TEMP); 1369 rs->rules[rs_num].inactive.ptr_array = NULL; 1370 rs->rules[rs_num].inactive.rcount = 0; 1371 rs->rules[rs_num].inactive.open = 0; 1372 pf_remove_if_empty_ruleset(rs); 1373 splx(s); 1374 return (0); 1375} 1376 1377int 1378pf_setup_pfsync_matching(struct pf_ruleset *rs) 1379{ 1380 MD5_CTX ctx; 1381 struct pf_rule *rule; 1382 int rs_cnt; 1383 u_int8_t digest[PF_MD5_DIGEST_LENGTH]; 1384 1385 MD5Init(&ctx); 1386 for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) { 1387 /* XXX PF_RULESET_SCRUB as well? */ 1388 if (rs_cnt == PF_RULESET_SCRUB) 1389 continue; 1390 1391 if (rs->rules[rs_cnt].inactive.ptr_array) 1392 free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP); 1393 rs->rules[rs_cnt].inactive.ptr_array = NULL; 1394 1395 if (rs->rules[rs_cnt].inactive.rcount) { 1396 rs->rules[rs_cnt].inactive.ptr_array = 1397 malloc(sizeof(caddr_t) * 1398 rs->rules[rs_cnt].inactive.rcount, 1399 M_TEMP, M_NOWAIT); 1400 1401 if (!rs->rules[rs_cnt].inactive.ptr_array) 1402 return (ENOMEM); 1403 } 1404 1405 TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr, 1406 entries) { 1407 pf_hash_rule(&ctx, rule); 1408 (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule; 1409 } 1410 } 1411 1412 MD5Final(digest, &ctx); 1413#ifdef __FreeBSD__ 1414 memcpy(V_pf_status.pf_chksum, digest, sizeof(V_pf_status.pf_chksum)); 1415#else 1416 memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum)); 1417#endif 1418 return (0); 1419} 1420 1421int 1422pf_addr_setup(struct pf_ruleset *ruleset, struct pf_addr_wrap *addr, 1423 sa_family_t af) 1424{ 1425 if (pfi_dynaddr_setup(addr, af) || 1426 pf_tbladdr_setup(ruleset, addr)) 1427 return (EINVAL); 1428 1429 return (0); 1430} 1431 1432void 1433pf_addr_copyout(struct pf_addr_wrap *addr) 1434{ 1435 pfi_dynaddr_copyout(addr); 1436 pf_tbladdr_copyout(addr); 1437 pf_rtlabel_copyout(addr); 1438} 1439 1440int 1441#ifdef __FreeBSD__ 1442pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 1443#else 1444pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 1445#endif 1446{ 1447 struct pf_pooladdr *pa = NULL; 1448 struct pf_pool *pool = NULL; 1449#ifndef __FreeBSD__ 1450 int s; 1451#endif 1452 int error = 0; 1453 1454 CURVNET_SET(TD_TO_VNET(td)); 1455 1456 /* XXX keep in sync with switch() below */ 1457#ifdef __FreeBSD__ 1458 if (securelevel_gt(td->td_ucred, 2)) 1459#else 1460 if (securelevel > 1) 1461#endif 1462 switch (cmd) { 1463 case DIOCGETRULES: 1464 case DIOCGETRULE: 1465 case DIOCGETADDRS: 1466 case DIOCGETADDR: 1467 case DIOCGETSTATE: 1468 case DIOCSETSTATUSIF: 1469 case DIOCGETSTATUS: 1470 case DIOCCLRSTATUS: 1471 case DIOCNATLOOK: 1472 case DIOCSETDEBUG: 1473 case DIOCGETSTATES: 1474 case DIOCGETTIMEOUT: 1475 case DIOCCLRRULECTRS: 1476 case DIOCGETLIMIT: 1477 case DIOCGETALTQS: 1478 case DIOCGETALTQ: 1479 case DIOCGETQSTATS: 1480 case DIOCGETRULESETS: 1481 case DIOCGETRULESET: 1482 case DIOCRGETTABLES: 1483 case DIOCRGETTSTATS: 1484 case DIOCRCLRTSTATS: 1485 case DIOCRCLRADDRS: 1486 case DIOCRADDADDRS: 1487 case DIOCRDELADDRS: 1488 case DIOCRSETADDRS: 1489 case DIOCRGETADDRS: 1490 case DIOCRGETASTATS: 1491 case DIOCRCLRASTATS: 1492 case DIOCRTSTADDRS: 1493 case DIOCOSFPGET: 1494 case DIOCGETSRCNODES: 1495 case DIOCCLRSRCNODES: 1496 case DIOCIGETIFACES: 1497#ifdef __FreeBSD__ 1498 case DIOCGIFSPEED: 1499#endif 1500 case DIOCSETIFFLAG: 1501 case DIOCCLRIFFLAG: 1502 break; 1503 case DIOCRCLRTABLES: 1504 case DIOCRADDTABLES: 1505 case DIOCRDELTABLES: 1506 case DIOCRSETTFLAGS: 1507 if (((struct pfioc_table *)addr)->pfrio_flags & 1508 PFR_FLAG_DUMMY) 1509 break; /* dummy operation ok */ 1510 return (EPERM); 1511 default: 1512 return (EPERM); 1513 } 1514 1515 if (!(flags & FWRITE)) 1516 switch (cmd) { 1517 case DIOCGETRULES: 1518 case DIOCGETADDRS: 1519 case DIOCGETADDR: 1520 case DIOCGETSTATE: 1521 case DIOCGETSTATUS: 1522 case DIOCGETSTATES: 1523 case DIOCGETTIMEOUT: 1524 case DIOCGETLIMIT: 1525 case DIOCGETALTQS: 1526 case DIOCGETALTQ: 1527 case DIOCGETQSTATS: 1528 case DIOCGETRULESETS: 1529 case DIOCGETRULESET: 1530 case DIOCNATLOOK: 1531 case DIOCRGETTABLES: 1532 case DIOCRGETTSTATS: 1533 case DIOCRGETADDRS: 1534 case DIOCRGETASTATS: 1535 case DIOCRTSTADDRS: 1536 case DIOCOSFPGET: 1537 case DIOCGETSRCNODES: 1538 case DIOCIGETIFACES: 1539#ifdef __FreeBSD__ 1540 case DIOCGIFSPEED: 1541#endif 1542 break; 1543 case DIOCRCLRTABLES: 1544 case DIOCRADDTABLES: 1545 case DIOCRDELTABLES: 1546 case DIOCRCLRTSTATS: 1547 case DIOCRCLRADDRS: 1548 case DIOCRADDADDRS: 1549 case DIOCRDELADDRS: 1550 case DIOCRSETADDRS: 1551 case DIOCRSETTFLAGS: 1552 if (((struct pfioc_table *)addr)->pfrio_flags & 1553 PFR_FLAG_DUMMY) { 1554 flags |= FWRITE; /* need write lock for dummy */ 1555 break; /* dummy operation ok */ 1556 } 1557 return (EACCES); 1558 case DIOCGETRULE: 1559 if (((struct pfioc_rule *)addr)->action == 1560 PF_GET_CLR_CNTR) 1561 return (EACCES); 1562 break; 1563 default: 1564 return (EACCES); 1565 } 1566 1567 if (flags & FWRITE) 1568#ifdef __FreeBSD__ 1569 sx_xlock(&V_pf_consistency_lock); 1570 else 1571 sx_slock(&V_pf_consistency_lock); 1572#else 1573 rw_enter_write(&pf_consistency_lock); 1574 else 1575 rw_enter_read(&pf_consistency_lock); 1576#endif 1577 1578#ifdef __FreeBSD__ 1579 PF_LOCK(); 1580#else 1581 s = splsoftnet(); 1582#endif 1583 switch (cmd) { 1584 1585 case DIOCSTART: 1586#ifdef __FreeBSD__ 1587 if (V_pf_status.running) 1588#else 1589 if (pf_status.running) 1590#endif 1591 error = EEXIST; 1592 else { 1593#ifdef __FreeBSD__ 1594 PF_UNLOCK(); 1595 error = hook_pf(); 1596 PF_LOCK(); 1597 if (error) { 1598 DPFPRINTF(PF_DEBUG_MISC, 1599 ("pf: pfil registeration fail\n")); 1600 break; 1601 } 1602 V_pf_status.running = 1; 1603 V_pf_status.since = time_second; 1604 1605 if (V_pf_status.stateid == 0) { 1606 V_pf_status.stateid = time_second; 1607 V_pf_status.stateid = V_pf_status.stateid << 32; 1608 } 1609#else 1610 pf_status.running = 1; 1611 pf_status.since = time_second; 1612 1613 if (pf_status.stateid == 0) { 1614 pf_status.stateid = time_second; 1615 pf_status.stateid = pf_status.stateid << 32; 1616 } 1617#endif 1618 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); 1619 } 1620 break; 1621 1622 case DIOCSTOP: 1623#ifdef __FreeBSD__ 1624 if (!V_pf_status.running) 1625 error = ENOENT; 1626 else { 1627 V_pf_status.running = 0; 1628 PF_UNLOCK(); 1629 error = dehook_pf(); 1630 PF_LOCK(); 1631 if (error) { 1632 V_pf_status.running = 1; 1633 DPFPRINTF(PF_DEBUG_MISC, 1634 ("pf: pfil unregisteration failed\n")); 1635 } 1636 V_pf_status.since = time_second; 1637#else 1638 if (!pf_status.running) 1639 error = ENOENT; 1640 else { 1641 pf_status.running = 0; 1642 pf_status.since = time_second; 1643#endif 1644 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); 1645 } 1646 break; 1647 1648 case DIOCADDRULE: { 1649 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1650 struct pf_ruleset *ruleset; 1651 struct pf_rule *rule, *tail; 1652 struct pf_pooladdr *pa; 1653 int rs_num; 1654 1655 pr->anchor[sizeof(pr->anchor) - 1] = 0; 1656 ruleset = pf_find_ruleset(pr->anchor); 1657 if (ruleset == NULL) { 1658 error = EINVAL; 1659 break; 1660 } 1661 rs_num = pf_get_ruleset_number(pr->rule.action); 1662 if (rs_num >= PF_RULESET_MAX) { 1663 error = EINVAL; 1664 break; 1665 } 1666 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1667 error = EINVAL; 1668 break; 1669 } 1670 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { 1671#ifdef __FreeBSD__ 1672 DPFPRINTF(PF_DEBUG_MISC, 1673 ("ticket: %d != [%d]%d\n", pr->ticket, rs_num, 1674 ruleset->rules[rs_num].inactive.ticket)); 1675#endif 1676 error = EBUSY; 1677 break; 1678 } 1679#ifdef __FreeBSD__ 1680 if (pr->pool_ticket != V_ticket_pabuf) { 1681 DPFPRINTF(PF_DEBUG_MISC, 1682 ("pool_ticket: %d != %d\n", pr->pool_ticket, 1683 V_ticket_pabuf)); 1684#else 1685 if (pr->pool_ticket != ticket_pabuf) { 1686#endif 1687 error = EBUSY; 1688 break; 1689 } 1690#ifdef __FreeBSD__ 1691 rule = pool_get(&V_pf_rule_pl, PR_NOWAIT); 1692#else 1693 rule = pool_get(&pf_rule_pl, PR_WAITOK|PR_LIMITFAIL); 1694#endif 1695 if (rule == NULL) { 1696 error = ENOMEM; 1697 break; 1698 } 1699 bcopy(&pr->rule, rule, sizeof(struct pf_rule)); 1700#ifdef __FreeBSD__ 1701 rule->cuid = td->td_ucred->cr_ruid; 1702 rule->cpid = td->td_proc ? td->td_proc->p_pid : 0; 1703#else 1704 rule->cuid = p->p_cred->p_ruid; 1705 rule->cpid = p->p_pid; 1706#endif 1707 rule->anchor = NULL; 1708 rule->kif = NULL; 1709 TAILQ_INIT(&rule->rpool.list); 1710 /* initialize refcounting */ 1711 rule->states_cur = 0; 1712 rule->src_nodes = 0; 1713 rule->entries.tqe_prev = NULL; 1714#ifndef INET 1715 if (rule->af == AF_INET) { 1716#ifdef __FreeBSD__ 1717 pool_put(&V_pf_rule_pl, rule); 1718#else 1719 pool_put(&pf_rule_pl, rule); 1720#endif 1721 error = EAFNOSUPPORT; 1722 break; 1723 } 1724#endif /* INET */ 1725#ifndef INET6 1726 if (rule->af == AF_INET6) { 1727#ifdef __FreeBSD__ 1728 pool_put(&V_pf_rule_pl, rule); 1729#else 1730 pool_put(&pf_rule_pl, rule); 1731#endif 1732 error = EAFNOSUPPORT; 1733 break; 1734 } 1735#endif /* INET6 */ 1736 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 1737 pf_rulequeue); 1738 if (tail) 1739 rule->nr = tail->nr + 1; 1740 else 1741 rule->nr = 0; 1742 if (rule->ifname[0]) { 1743 rule->kif = pfi_kif_get(rule->ifname); 1744 if (rule->kif == NULL) { 1745#ifdef __FreeBSD__ 1746 pool_put(&V_pf_rule_pl, rule); 1747#else 1748 pool_put(&pf_rule_pl, rule); 1749#endif 1750 error = EINVAL; 1751 break; 1752 } 1753 pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE); 1754 } 1755 1756#ifdef __FreeBSD__ /* ROUTING */ 1757 if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs) 1758#else 1759 if (rule->rtableid > 0 && !rtable_exists(rule->rtableid)) 1760#endif 1761 error = EBUSY; 1762 1763#ifdef ALTQ 1764 /* set queue IDs */ 1765 if (rule->qname[0] != 0) { 1766 if ((rule->qid = pf_qname2qid(rule->qname)) == 0) 1767 error = EBUSY; 1768 else if (rule->pqname[0] != 0) { 1769 if ((rule->pqid = 1770 pf_qname2qid(rule->pqname)) == 0) 1771 error = EBUSY; 1772 } else 1773 rule->pqid = rule->qid; 1774 } 1775#endif 1776 if (rule->tagname[0]) 1777 if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) 1778 error = EBUSY; 1779 if (rule->match_tagname[0]) 1780 if ((rule->match_tag = 1781 pf_tagname2tag(rule->match_tagname)) == 0) 1782 error = EBUSY; 1783 if (rule->rt && !rule->direction) 1784 error = EINVAL; 1785#if NPFLOG > 0 1786 if (!rule->log) 1787 rule->logif = 0; 1788 if (rule->logif >= PFLOGIFS_MAX) 1789 error = EINVAL; 1790#endif 1791 if (pf_rtlabel_add(&rule->src.addr) || 1792 pf_rtlabel_add(&rule->dst.addr)) 1793 error = EBUSY; 1794 if (pf_addr_setup(ruleset, &rule->src.addr, rule->af)) 1795 error = EINVAL; 1796 if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af)) 1797 error = EINVAL; 1798 if (pf_anchor_setup(rule, ruleset, pr->anchor_call)) 1799 error = EINVAL; 1800#ifdef __FreeBSD__ 1801 TAILQ_FOREACH(pa, &V_pf_pabuf, entries) 1802#else 1803 TAILQ_FOREACH(pa, &pf_pabuf, entries) 1804#endif 1805 if (pf_tbladdr_setup(ruleset, &pa->addr)) 1806 error = EINVAL; 1807 1808 if (rule->overload_tblname[0]) { 1809 if ((rule->overload_tbl = pfr_attach_table(ruleset, 1810 rule->overload_tblname, 0)) == NULL) 1811 error = EINVAL; 1812 else 1813 rule->overload_tbl->pfrkt_flags |= 1814 PFR_TFLAG_ACTIVE; 1815 } 1816 1817#ifdef __FreeBSD__ 1818 pf_mv_pool(&V_pf_pabuf, &rule->rpool.list); 1819#else 1820 pf_mv_pool(&pf_pabuf, &rule->rpool.list); 1821#endif 1822 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || 1823 (rule->action == PF_BINAT)) && rule->anchor == NULL) || 1824 (rule->rt > PF_FASTROUTE)) && 1825 (TAILQ_FIRST(&rule->rpool.list) == NULL)) 1826 error = EINVAL; 1827 1828 if (error) { 1829 pf_rm_rule(NULL, rule); 1830 break; 1831 } 1832 1833#ifdef __FreeBSD__ 1834 if (!V_debug_pfugidhack && (rule->uid.op || rule->gid.op || 1835 rule->log & PF_LOG_SOCKET_LOOKUP)) { 1836 DPFPRINTF(PF_DEBUG_MISC, 1837 ("pf: debug.pfugidhack enabled\n")); 1838 V_debug_pfugidhack = 1; 1839 } 1840#endif 1841 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list); 1842 rule->evaluations = rule->packets[0] = rule->packets[1] = 1843 rule->bytes[0] = rule->bytes[1] = 0; 1844 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, 1845 rule, entries); 1846 ruleset->rules[rs_num].inactive.rcount++; 1847 break; 1848 } 1849 1850 case DIOCGETRULES: { 1851 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1852 struct pf_ruleset *ruleset; 1853 struct pf_rule *tail; 1854 int rs_num; 1855 1856 pr->anchor[sizeof(pr->anchor) - 1] = 0; 1857 ruleset = pf_find_ruleset(pr->anchor); 1858 if (ruleset == NULL) { 1859 error = EINVAL; 1860 break; 1861 } 1862 rs_num = pf_get_ruleset_number(pr->rule.action); 1863 if (rs_num >= PF_RULESET_MAX) { 1864 error = EINVAL; 1865 break; 1866 } 1867 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 1868 pf_rulequeue); 1869 if (tail) 1870 pr->nr = tail->nr + 1; 1871 else 1872 pr->nr = 0; 1873 pr->ticket = ruleset->rules[rs_num].active.ticket; 1874 break; 1875 } 1876 1877 case DIOCGETRULE: { 1878 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1879 struct pf_ruleset *ruleset; 1880 struct pf_rule *rule; 1881 int rs_num, i; 1882 1883 pr->anchor[sizeof(pr->anchor) - 1] = 0; 1884 ruleset = pf_find_ruleset(pr->anchor); 1885 if (ruleset == NULL) { 1886 error = EINVAL; 1887 break; 1888 } 1889 rs_num = pf_get_ruleset_number(pr->rule.action); 1890 if (rs_num >= PF_RULESET_MAX) { 1891 error = EINVAL; 1892 break; 1893 } 1894 if (pr->ticket != ruleset->rules[rs_num].active.ticket) { 1895 error = EBUSY; 1896 break; 1897 } 1898 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 1899 while ((rule != NULL) && (rule->nr != pr->nr)) 1900 rule = TAILQ_NEXT(rule, entries); 1901 if (rule == NULL) { 1902 error = EBUSY; 1903 break; 1904 } 1905 bcopy(rule, &pr->rule, sizeof(struct pf_rule)); 1906 if (pf_anchor_copyout(ruleset, rule, pr)) { 1907 error = EBUSY; 1908 break; 1909 } 1910 pf_addr_copyout(&pr->rule.src.addr); 1911 pf_addr_copyout(&pr->rule.dst.addr); 1912 for (i = 0; i < PF_SKIP_COUNT; ++i) 1913 if (rule->skip[i].ptr == NULL) 1914 pr->rule.skip[i].nr = -1; 1915 else 1916 pr->rule.skip[i].nr = 1917 rule->skip[i].ptr->nr; 1918 1919 if (pr->action == PF_GET_CLR_CNTR) { 1920 rule->evaluations = 0; 1921 rule->packets[0] = rule->packets[1] = 0; 1922 rule->bytes[0] = rule->bytes[1] = 0; 1923 rule->states_tot = 0; 1924 } 1925 break; 1926 } 1927 1928 case DIOCCHANGERULE: { 1929 struct pfioc_rule *pcr = (struct pfioc_rule *)addr; 1930 struct pf_ruleset *ruleset; 1931 struct pf_rule *oldrule = NULL, *newrule = NULL; 1932 u_int32_t nr = 0; 1933 int rs_num; 1934 1935 if (!(pcr->action == PF_CHANGE_REMOVE || 1936 pcr->action == PF_CHANGE_GET_TICKET) && 1937#ifdef __FreeBSD__ 1938 pcr->pool_ticket != V_ticket_pabuf) { 1939#else 1940 pcr->pool_ticket != ticket_pabuf) { 1941#endif 1942 error = EBUSY; 1943 break; 1944 } 1945 1946 if (pcr->action < PF_CHANGE_ADD_HEAD || 1947 pcr->action > PF_CHANGE_GET_TICKET) { 1948 error = EINVAL; 1949 break; 1950 } 1951 ruleset = pf_find_ruleset(pcr->anchor); 1952 if (ruleset == NULL) { 1953 error = EINVAL; 1954 break; 1955 } 1956 rs_num = pf_get_ruleset_number(pcr->rule.action); 1957 if (rs_num >= PF_RULESET_MAX) { 1958 error = EINVAL; 1959 break; 1960 } 1961 1962 if (pcr->action == PF_CHANGE_GET_TICKET) { 1963 pcr->ticket = ++ruleset->rules[rs_num].active.ticket; 1964 break; 1965 } else { 1966 if (pcr->ticket != 1967 ruleset->rules[rs_num].active.ticket) { 1968 error = EINVAL; 1969 break; 1970 } 1971 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1972 error = EINVAL; 1973 break; 1974 } 1975 } 1976 1977 if (pcr->action != PF_CHANGE_REMOVE) { 1978#ifdef __FreeBSD__ 1979 newrule = pool_get(&V_pf_rule_pl, PR_NOWAIT); 1980#else 1981 newrule = pool_get(&pf_rule_pl, PR_WAITOK|PR_LIMITFAIL); 1982#endif 1983 if (newrule == NULL) { 1984 error = ENOMEM; 1985 break; 1986 } 1987 bcopy(&pcr->rule, newrule, sizeof(struct pf_rule)); 1988#ifdef __FreeBSD__ 1989 newrule->cuid = td->td_ucred->cr_ruid; 1990 newrule->cpid = td->td_proc ? td->td_proc->p_pid : 0; 1991#else 1992 newrule->cuid = p->p_cred->p_ruid; 1993 newrule->cpid = p->p_pid; 1994#endif 1995 TAILQ_INIT(&newrule->rpool.list); 1996 /* initialize refcounting */ 1997 newrule->states_cur = 0; 1998 newrule->entries.tqe_prev = NULL; 1999#ifndef INET 2000 if (newrule->af == AF_INET) { 2001#ifdef __FreeBSD__ 2002 pool_put(&V_pf_rule_pl, newrule); 2003#else 2004 pool_put(&pf_rule_pl, newrule); 2005#endif 2006 error = EAFNOSUPPORT; 2007 break; 2008 } 2009#endif /* INET */ 2010#ifndef INET6 2011 if (newrule->af == AF_INET6) { 2012#ifdef __FreeBSD__ 2013 pool_put(&V_pf_rule_pl, newrule); 2014#else 2015 pool_put(&pf_rule_pl, newrule); 2016#endif 2017 error = EAFNOSUPPORT; 2018 break; 2019 } 2020#endif /* INET6 */ 2021 if (newrule->ifname[0]) { 2022 newrule->kif = pfi_kif_get(newrule->ifname); 2023 if (newrule->kif == NULL) { 2024#ifdef __FreeBSD__ 2025 pool_put(&V_pf_rule_pl, newrule); 2026#else 2027 pool_put(&pf_rule_pl, newrule); 2028#endif 2029 error = EINVAL; 2030 break; 2031 } 2032 pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE); 2033 } else 2034 newrule->kif = NULL; 2035 2036 if (newrule->rtableid > 0 && 2037#ifdef __FreeBSD__ /* ROUTING */ 2038 newrule->rtableid >= rt_numfibs) 2039#else 2040 !rtable_exists(newrule->rtableid)) 2041#endif 2042 error = EBUSY; 2043 2044#ifdef ALTQ 2045 /* set queue IDs */ 2046 if (newrule->qname[0] != 0) { 2047 if ((newrule->qid = 2048 pf_qname2qid(newrule->qname)) == 0) 2049 error = EBUSY; 2050 else if (newrule->pqname[0] != 0) { 2051 if ((newrule->pqid = 2052 pf_qname2qid(newrule->pqname)) == 0) 2053 error = EBUSY; 2054 } else 2055 newrule->pqid = newrule->qid; 2056 } 2057#endif /* ALTQ */ 2058 if (newrule->tagname[0]) 2059 if ((newrule->tag = 2060 pf_tagname2tag(newrule->tagname)) == 0) 2061 error = EBUSY; 2062 if (newrule->match_tagname[0]) 2063 if ((newrule->match_tag = pf_tagname2tag( 2064 newrule->match_tagname)) == 0) 2065 error = EBUSY; 2066 if (newrule->rt && !newrule->direction) 2067 error = EINVAL; 2068#if NPFLOG > 0 2069 if (!newrule->log) 2070 newrule->logif = 0; 2071 if (newrule->logif >= PFLOGIFS_MAX) 2072 error = EINVAL; 2073#endif 2074 if (pf_rtlabel_add(&newrule->src.addr) || 2075 pf_rtlabel_add(&newrule->dst.addr)) 2076 error = EBUSY; 2077 if (pf_addr_setup(ruleset, &newrule->src.addr, newrule->af)) 2078 error = EINVAL; 2079 if (pf_addr_setup(ruleset, &newrule->dst.addr, newrule->af)) 2080 error = EINVAL; 2081 if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call)) 2082 error = EINVAL; 2083#ifdef __FreeBSD__ 2084 TAILQ_FOREACH(pa, &V_pf_pabuf, entries) 2085#else 2086 TAILQ_FOREACH(pa, &pf_pabuf, entries) 2087#endif 2088 if (pf_tbladdr_setup(ruleset, &pa->addr)) 2089 error = EINVAL; 2090 2091 if (newrule->overload_tblname[0]) { 2092 if ((newrule->overload_tbl = pfr_attach_table( 2093 ruleset, newrule->overload_tblname, 0)) == 2094 NULL) 2095 error = EINVAL; 2096 else 2097 newrule->overload_tbl->pfrkt_flags |= 2098 PFR_TFLAG_ACTIVE; 2099 } 2100 2101#ifdef __FreeBSD__ 2102 pf_mv_pool(&V_pf_pabuf, &newrule->rpool.list); 2103#else 2104 pf_mv_pool(&pf_pabuf, &newrule->rpool.list); 2105#endif 2106 if (((((newrule->action == PF_NAT) || 2107 (newrule->action == PF_RDR) || 2108 (newrule->action == PF_BINAT) || 2109 (newrule->rt > PF_FASTROUTE)) && 2110 !newrule->anchor)) && 2111 (TAILQ_FIRST(&newrule->rpool.list) == NULL)) 2112 error = EINVAL; 2113 2114 if (error) { 2115 pf_rm_rule(NULL, newrule); 2116 break; 2117 } 2118 2119#ifdef __FreeBSD__ 2120 if (!V_debug_pfugidhack && (newrule->uid.op || 2121 newrule->gid.op || 2122 newrule->log & PF_LOG_SOCKET_LOOKUP)) { 2123 DPFPRINTF(PF_DEBUG_MISC, 2124 ("pf: debug.pfugidhack enabled\n")); 2125 V_debug_pfugidhack = 1; 2126 } 2127#endif 2128 2129 newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list); 2130 newrule->evaluations = 0; 2131 newrule->packets[0] = newrule->packets[1] = 0; 2132 newrule->bytes[0] = newrule->bytes[1] = 0; 2133 } 2134#ifdef __FreeBSD__ 2135 pf_empty_pool(&V_pf_pabuf); 2136#else 2137 pf_empty_pool(&pf_pabuf); 2138#endif 2139 2140 if (pcr->action == PF_CHANGE_ADD_HEAD) 2141 oldrule = TAILQ_FIRST( 2142 ruleset->rules[rs_num].active.ptr); 2143 else if (pcr->action == PF_CHANGE_ADD_TAIL) 2144 oldrule = TAILQ_LAST( 2145 ruleset->rules[rs_num].active.ptr, pf_rulequeue); 2146 else { 2147 oldrule = TAILQ_FIRST( 2148 ruleset->rules[rs_num].active.ptr); 2149 while ((oldrule != NULL) && (oldrule->nr != pcr->nr)) 2150 oldrule = TAILQ_NEXT(oldrule, entries); 2151 if (oldrule == NULL) { 2152 if (newrule != NULL) 2153 pf_rm_rule(NULL, newrule); 2154 error = EINVAL; 2155 break; 2156 } 2157 } 2158 2159 if (pcr->action == PF_CHANGE_REMOVE) { 2160 pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule); 2161 ruleset->rules[rs_num].active.rcount--; 2162 } else { 2163 if (oldrule == NULL) 2164 TAILQ_INSERT_TAIL( 2165 ruleset->rules[rs_num].active.ptr, 2166 newrule, entries); 2167 else if (pcr->action == PF_CHANGE_ADD_HEAD || 2168 pcr->action == PF_CHANGE_ADD_BEFORE) 2169 TAILQ_INSERT_BEFORE(oldrule, newrule, entries); 2170 else 2171 TAILQ_INSERT_AFTER( 2172 ruleset->rules[rs_num].active.ptr, 2173 oldrule, newrule, entries); 2174 ruleset->rules[rs_num].active.rcount++; 2175 } 2176 2177 nr = 0; 2178 TAILQ_FOREACH(oldrule, 2179 ruleset->rules[rs_num].active.ptr, entries) 2180 oldrule->nr = nr++; 2181 2182 ruleset->rules[rs_num].active.ticket++; 2183 2184 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); 2185 pf_remove_if_empty_ruleset(ruleset); 2186 2187 break; 2188 } 2189 2190 case DIOCCLRSTATES: { 2191 struct pf_state *s, *nexts; 2192 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 2193 u_int killed = 0; 2194 2195#ifdef __FreeBSD__ 2196 for (s = RB_MIN(pf_state_tree_id, &V_tree_id); s; s = nexts) { 2197 nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, s); 2198#else 2199 for (s = RB_MIN(pf_state_tree_id, &tree_id); s; s = nexts) { 2200 nexts = RB_NEXT(pf_state_tree_id, &tree_id, s); 2201#endif 2202 2203 if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, 2204 s->kif->pfik_name)) { 2205#if NPFSYNC > 0 2206 /* don't send out individual delete messages */ 2207 SET(s->state_flags, PFSTATE_NOSYNC); 2208#endif 2209 pf_unlink_state(s); 2210 killed++; 2211 } 2212 } 2213 psk->psk_killed = killed; 2214#if NPFSYNC > 0 2215#ifdef __FreeBSD__ 2216 if (pfsync_clear_states_ptr != NULL) 2217 pfsync_clear_states_ptr(V_pf_status.hostid, psk->psk_ifname); 2218#else 2219 pfsync_clear_states(pf_status.hostid, psk->psk_ifname); 2220#endif 2221#endif 2222 break; 2223 } 2224 2225 case DIOCKILLSTATES: { 2226 struct pf_state *s, *nexts; 2227 struct pf_state_key *sk; 2228 struct pf_addr *srcaddr, *dstaddr; 2229 u_int16_t srcport, dstport; 2230 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 2231 u_int killed = 0; 2232 2233 if (psk->psk_pfcmp.id) { 2234 if (psk->psk_pfcmp.creatorid == 0) 2235#ifdef __FreeBSD__ 2236 psk->psk_pfcmp.creatorid = V_pf_status.hostid; 2237#else 2238 psk->psk_pfcmp.creatorid = pf_status.hostid; 2239#endif 2240 if ((s = pf_find_state_byid(&psk->psk_pfcmp))) { 2241 pf_unlink_state(s); 2242 psk->psk_killed = 1; 2243 } 2244 break; 2245 } 2246 2247#ifdef __FreeBSD__ 2248 for (s = RB_MIN(pf_state_tree_id, &V_tree_id); s; 2249 s = nexts) { 2250 nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, s); 2251#else 2252 for (s = RB_MIN(pf_state_tree_id, &tree_id); s; 2253 s = nexts) { 2254 nexts = RB_NEXT(pf_state_tree_id, &tree_id, s); 2255#endif 2256 sk = s->key[PF_SK_WIRE]; 2257 2258 if (s->direction == PF_OUT) { 2259 srcaddr = &sk->addr[1]; 2260 dstaddr = &sk->addr[0]; 2261 srcport = sk->port[0]; 2262 dstport = sk->port[0]; 2263 } else { 2264 srcaddr = &sk->addr[0]; 2265 dstaddr = &sk->addr[1]; 2266 srcport = sk->port[0]; 2267 dstport = sk->port[0]; 2268 } 2269 if ((!psk->psk_af || sk->af == psk->psk_af) 2270 && (!psk->psk_proto || psk->psk_proto == 2271 sk->proto) && 2272 PF_MATCHA(psk->psk_src.neg, 2273 &psk->psk_src.addr.v.a.addr, 2274 &psk->psk_src.addr.v.a.mask, 2275 srcaddr, sk->af) && 2276 PF_MATCHA(psk->psk_dst.neg, 2277 &psk->psk_dst.addr.v.a.addr, 2278 &psk->psk_dst.addr.v.a.mask, 2279 dstaddr, sk->af) && 2280 (psk->psk_src.port_op == 0 || 2281 pf_match_port(psk->psk_src.port_op, 2282 psk->psk_src.port[0], psk->psk_src.port[1], 2283 srcport)) && 2284 (psk->psk_dst.port_op == 0 || 2285 pf_match_port(psk->psk_dst.port_op, 2286 psk->psk_dst.port[0], psk->psk_dst.port[1], 2287 dstport)) && 2288 (!psk->psk_label[0] || (s->rule.ptr->label[0] && 2289 !strcmp(psk->psk_label, s->rule.ptr->label))) && 2290 (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, 2291 s->kif->pfik_name))) { 2292 pf_unlink_state(s); 2293 killed++; 2294 } 2295 } 2296 psk->psk_killed = killed; 2297 break; 2298 } 2299 2300 case DIOCADDSTATE: { 2301 struct pfioc_state *ps = (struct pfioc_state *)addr; 2302 struct pfsync_state *sp = &ps->state; 2303 2304 if (sp->timeout >= PFTM_MAX && 2305 sp->timeout != PFTM_UNTIL_PACKET) { 2306 error = EINVAL; 2307 break; 2308 } 2309#ifdef __FreeBSD__ 2310 if (pfsync_state_import_ptr != NULL) 2311 error = pfsync_state_import_ptr(sp, PFSYNC_SI_IOCTL); 2312#else 2313 error = pfsync_state_import(sp, PFSYNC_SI_IOCTL); 2314#endif 2315 break; 2316 } 2317 2318 case DIOCGETSTATE: { 2319 struct pfioc_state *ps = (struct pfioc_state *)addr; 2320 struct pf_state *s; 2321 struct pf_state_cmp id_key; 2322 2323 bcopy(ps->state.id, &id_key.id, sizeof(id_key.id)); 2324 id_key.creatorid = ps->state.creatorid; 2325 2326 s = pf_find_state_byid(&id_key); 2327 if (s == NULL) { 2328 error = ENOENT; 2329 break; 2330 } 2331 2332 pfsync_state_export(&ps->state, s); 2333 break; 2334 } 2335 2336 case DIOCGETSTATES: { 2337 struct pfioc_states *ps = (struct pfioc_states *)addr; 2338 struct pf_state *state; 2339 struct pfsync_state *p, *pstore; 2340 u_int32_t nr = 0; 2341 2342 if (ps->ps_len == 0) { 2343#ifdef __FreeBSD__ 2344 nr = V_pf_status.states; 2345#else 2346 nr = pf_status.states; 2347#endif 2348 ps->ps_len = sizeof(struct pfsync_state) * nr; 2349 break; 2350 } 2351 2352#ifdef __FreeBSD__ 2353 PF_UNLOCK(); 2354#endif 2355 pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK); 2356#ifdef __FreeBSD__ 2357 PF_LOCK(); 2358#endif 2359 2360 p = ps->ps_states; 2361 2362#ifdef __FreeBSD__ 2363 state = TAILQ_FIRST(&V_state_list); 2364#else 2365 state = TAILQ_FIRST(&state_list); 2366#endif 2367 while (state) { 2368 if (state->timeout != PFTM_UNLINKED) { 2369 if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len) 2370 break; 2371 pfsync_state_export(pstore, state); 2372#ifdef __FreeBSD__ 2373 PF_COPYOUT(pstore, p, sizeof(*p), error); 2374#else 2375 error = copyout(pstore, p, sizeof(*p)); 2376#endif 2377 if (error) { 2378 free(pstore, M_TEMP); 2379 goto fail; 2380 } 2381 p++; 2382 nr++; 2383 } 2384 state = TAILQ_NEXT(state, entry_list); 2385 } 2386 2387 ps->ps_len = sizeof(struct pfsync_state) * nr; 2388 2389 free(pstore, M_TEMP); 2390 break; 2391 } 2392 2393 case DIOCGETSTATUS: { 2394 struct pf_status *s = (struct pf_status *)addr; 2395#ifdef __FreeBSD__ 2396 bcopy(&V_pf_status, s, sizeof(struct pf_status)); 2397#else 2398 bcopy(&pf_status, s, sizeof(struct pf_status)); 2399#endif 2400 pfi_update_status(s->ifname, s); 2401 break; 2402 } 2403 2404 case DIOCSETSTATUSIF: { 2405 struct pfioc_if *pi = (struct pfioc_if *)addr; 2406 2407 if (pi->ifname[0] == 0) { 2408#ifdef __FreeBSD__ 2409 bzero(V_pf_status.ifname, IFNAMSIZ); 2410#else 2411 bzero(pf_status.ifname, IFNAMSIZ); 2412#endif 2413 break; 2414 } 2415#ifdef __FreeBSD__ 2416 strlcpy(V_pf_status.ifname, pi->ifname, IFNAMSIZ); 2417#else 2418 strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ); 2419#endif 2420 break; 2421 } 2422 2423 case DIOCCLRSTATUS: { 2424#ifdef __FreeBSD__ 2425 bzero(V_pf_status.counters, sizeof(V_pf_status.counters)); 2426 bzero(V_pf_status.fcounters, sizeof(V_pf_status.fcounters)); 2427 bzero(V_pf_status.scounters, sizeof(V_pf_status.scounters)); 2428 V_pf_status.since = time_second; 2429 if (*V_pf_status.ifname) 2430 pfi_update_status(V_pf_status.ifname, NULL); 2431#else 2432 bzero(pf_status.counters, sizeof(pf_status.counters)); 2433 bzero(pf_status.fcounters, sizeof(pf_status.fcounters)); 2434 bzero(pf_status.scounters, sizeof(pf_status.scounters)); 2435 pf_status.since = time_second; 2436 if (*pf_status.ifname) 2437 pfi_update_status(pf_status.ifname, NULL); 2438#endif 2439 break; 2440 } 2441 2442 case DIOCNATLOOK: { 2443 struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; 2444 struct pf_state_key *sk; 2445 struct pf_state *state; 2446 struct pf_state_key_cmp key; 2447 int m = 0, direction = pnl->direction; 2448 int sidx, didx; 2449 2450 /* NATLOOK src and dst are reversed, so reverse sidx/didx */ 2451 sidx = (direction == PF_IN) ? 1 : 0; 2452 didx = (direction == PF_IN) ? 0 : 1; 2453 2454 if (!pnl->proto || 2455 PF_AZERO(&pnl->saddr, pnl->af) || 2456 PF_AZERO(&pnl->daddr, pnl->af) || 2457 ((pnl->proto == IPPROTO_TCP || 2458 pnl->proto == IPPROTO_UDP) && 2459 (!pnl->dport || !pnl->sport))) 2460 error = EINVAL; 2461 else { 2462 key.af = pnl->af; 2463 key.proto = pnl->proto; 2464 PF_ACPY(&key.addr[sidx], &pnl->saddr, pnl->af); 2465 key.port[sidx] = pnl->sport; 2466 PF_ACPY(&key.addr[didx], &pnl->daddr, pnl->af); 2467 key.port[didx] = pnl->dport; 2468 2469 state = pf_find_state_all(&key, direction, &m); 2470 2471 if (m > 1) 2472 error = E2BIG; /* more than one state */ 2473 else if (state != NULL) { 2474 sk = state->key[sidx]; 2475 PF_ACPY(&pnl->rsaddr, &sk->addr[sidx], sk->af); 2476 pnl->rsport = sk->port[sidx]; 2477 PF_ACPY(&pnl->rdaddr, &sk->addr[didx], sk->af); 2478 pnl->rdport = sk->port[didx]; 2479 } else 2480 error = ENOENT; 2481 } 2482 break; 2483 } 2484 2485 case DIOCSETTIMEOUT: { 2486 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 2487 int old; 2488 2489 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX || 2490 pt->seconds < 0) { 2491 error = EINVAL; 2492 goto fail; 2493 } 2494#ifdef __FreeBSD__ 2495 old = V_pf_default_rule.timeout[pt->timeout]; 2496#else 2497 old = pf_default_rule.timeout[pt->timeout]; 2498#endif 2499 if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0) 2500 pt->seconds = 1; 2501#ifdef __FreeBSD__ 2502 V_pf_default_rule.timeout[pt->timeout] = pt->seconds; 2503#else 2504 pf_default_rule.timeout[pt->timeout] = pt->seconds; 2505#endif 2506 if (pt->timeout == PFTM_INTERVAL && pt->seconds < old) 2507 wakeup(pf_purge_thread); 2508 pt->seconds = old; 2509 break; 2510 } 2511 2512 case DIOCGETTIMEOUT: { 2513 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 2514 2515 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) { 2516 error = EINVAL; 2517 goto fail; 2518 } 2519#ifdef __FreeBSD__ 2520 pt->seconds = V_pf_default_rule.timeout[pt->timeout]; 2521#else 2522 pt->seconds = pf_default_rule.timeout[pt->timeout]; 2523#endif 2524 break; 2525 } 2526 2527 case DIOCGETLIMIT: { 2528 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 2529 2530 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { 2531 error = EINVAL; 2532 goto fail; 2533 } 2534#ifdef __FreeBSD__ 2535 pl->limit = V_pf_pool_limits[pl->index].limit; 2536#else 2537 pl->limit = pf_pool_limits[pl->index].limit; 2538#endif 2539 break; 2540 } 2541 2542 case DIOCSETLIMIT: { 2543 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 2544 int old_limit; 2545 2546 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX || 2547#ifdef __FreeBSD__ 2548 V_pf_pool_limits[pl->index].pp == NULL) { 2549#else 2550 pf_pool_limits[pl->index].pp == NULL) { 2551#endif 2552 error = EINVAL; 2553 goto fail; 2554 } 2555#ifdef __FreeBSD__ 2556 uma_zone_set_max(V_pf_pool_limits[pl->index].pp, pl->limit); 2557 old_limit = V_pf_pool_limits[pl->index].limit; 2558 V_pf_pool_limits[pl->index].limit = pl->limit; 2559 pl->limit = old_limit; 2560#else 2561 if (pool_sethardlimit(pf_pool_limits[pl->index].pp, 2562 pl->limit, NULL, 0) != 0) { 2563 error = EBUSY; 2564 goto fail; 2565 } 2566 old_limit = pf_pool_limits[pl->index].limit; 2567 pf_pool_limits[pl->index].limit = pl->limit; 2568 pl->limit = old_limit; 2569#endif 2570 break; 2571 } 2572 2573 case DIOCSETDEBUG: { 2574 u_int32_t *level = (u_int32_t *)addr; 2575 2576#ifdef __FreeBSD__ 2577 V_pf_status.debug = *level; 2578#else 2579 pf_status.debug = *level; 2580#endif 2581 break; 2582 } 2583 2584 case DIOCCLRRULECTRS: { 2585 /* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */ 2586 struct pf_ruleset *ruleset = &pf_main_ruleset; 2587 struct pf_rule *rule; 2588 2589 TAILQ_FOREACH(rule, 2590 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) { 2591 rule->evaluations = 0; 2592 rule->packets[0] = rule->packets[1] = 0; 2593 rule->bytes[0] = rule->bytes[1] = 0; 2594 } 2595 break; 2596 } 2597 2598#ifdef __FreeBSD__ 2599 case DIOCGIFSPEED: { 2600 struct pf_ifspeed *psp = (struct pf_ifspeed *)addr; 2601 struct pf_ifspeed ps; 2602 struct ifnet *ifp; 2603 2604 if (psp->ifname[0] != 0) { 2605 /* Can we completely trust user-land? */ 2606 strlcpy(ps.ifname, psp->ifname, IFNAMSIZ); 2607 ifp = ifunit(ps.ifname); 2608 if (ifp != NULL) 2609 psp->baudrate = ifp->if_baudrate; 2610 else 2611 error = EINVAL; 2612 } else 2613 error = EINVAL; 2614 break; 2615 } 2616#endif /* __FreeBSD__ */ 2617 2618#ifdef ALTQ 2619 case DIOCSTARTALTQ: { 2620 struct pf_altq *altq; 2621 2622 /* enable all altq interfaces on active list */ 2623#ifdef __FreeBSD__ 2624 TAILQ_FOREACH(altq, V_pf_altqs_active, entries) { 2625 if (altq->qname[0] == 0 && (altq->local_flags & 2626 PFALTQ_FLAG_IF_REMOVED) == 0) { 2627#else 2628 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 2629 if (altq->qname[0] == 0) { 2630#endif 2631 error = pf_enable_altq(altq); 2632 if (error != 0) 2633 break; 2634 } 2635 } 2636 if (error == 0) 2637#ifdef __FreeBSD__ 2638 V_pf_altq_running = 1; 2639#else 2640 pf_altq_running = 1; 2641#endif 2642 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n")); 2643 break; 2644 } 2645 2646 case DIOCSTOPALTQ: { 2647 struct pf_altq *altq; 2648 2649 /* disable all altq interfaces on active list */ 2650#ifdef __FreeBSD__ 2651 TAILQ_FOREACH(altq, V_pf_altqs_active, entries) { 2652 if (altq->qname[0] == 0 && (altq->local_flags & 2653 PFALTQ_FLAG_IF_REMOVED) == 0) { 2654#else 2655 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 2656 if (altq->qname[0] == 0) { 2657#endif 2658 error = pf_disable_altq(altq); 2659 if (error != 0) 2660 break; 2661 } 2662 } 2663 if (error == 0) 2664#ifdef __FreeBSD__ 2665 V_pf_altq_running = 0; 2666#else 2667 pf_altq_running = 0; 2668#endif 2669 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n")); 2670 break; 2671 } 2672 2673 case DIOCADDALTQ: { 2674 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2675 struct pf_altq *altq, *a; 2676 2677#ifdef __FreeBSD__ 2678 if (pa->ticket != V_ticket_altqs_inactive) { 2679#else 2680 if (pa->ticket != ticket_altqs_inactive) { 2681#endif 2682 error = EBUSY; 2683 break; 2684 } 2685#ifdef __FreeBSD__ 2686 altq = pool_get(&V_pf_altq_pl, PR_NOWAIT); 2687#else 2688 altq = pool_get(&pf_altq_pl, PR_WAITOK|PR_LIMITFAIL); 2689#endif 2690 if (altq == NULL) { 2691 error = ENOMEM; 2692 break; 2693 } 2694 bcopy(&pa->altq, altq, sizeof(struct pf_altq)); 2695#ifdef __FreeBSD__ 2696 altq->local_flags = 0; 2697#endif 2698 2699 /* 2700 * if this is for a queue, find the discipline and 2701 * copy the necessary fields 2702 */ 2703 if (altq->qname[0] != 0) { 2704 if ((altq->qid = pf_qname2qid(altq->qname)) == 0) { 2705 error = EBUSY; 2706#ifdef __FreeBSD__ 2707 pool_put(&V_pf_altq_pl, altq); 2708#else 2709 pool_put(&pf_altq_pl, altq); 2710#endif 2711 break; 2712 } 2713 altq->altq_disc = NULL; 2714#ifdef __FreeBSD__ 2715 TAILQ_FOREACH(a, V_pf_altqs_inactive, entries) { 2716#else 2717 TAILQ_FOREACH(a, pf_altqs_inactive, entries) { 2718#endif 2719 if (strncmp(a->ifname, altq->ifname, 2720 IFNAMSIZ) == 0 && a->qname[0] == 0) { 2721 altq->altq_disc = a->altq_disc; 2722 break; 2723 } 2724 } 2725 } 2726 2727#ifdef __FreeBSD__ 2728 struct ifnet *ifp; 2729 2730 if ((ifp = ifunit(altq->ifname)) == NULL) { 2731 altq->local_flags |= PFALTQ_FLAG_IF_REMOVED; 2732 } else { 2733 PF_UNLOCK(); 2734#endif 2735 error = altq_add(altq); 2736#ifdef __FreeBSD__ 2737 PF_LOCK(); 2738 } 2739#endif 2740 if (error) { 2741#ifdef __FreeBSD__ 2742 pool_put(&V_pf_altq_pl, altq); 2743#else 2744 pool_put(&pf_altq_pl, altq); 2745#endif 2746 break; 2747 } 2748 2749#ifdef __FreeBSD__ 2750 TAILQ_INSERT_TAIL(V_pf_altqs_inactive, altq, entries); 2751#else 2752 TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries); 2753#endif 2754 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 2755 break; 2756 } 2757 2758 case DIOCGETALTQS: { 2759 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2760 struct pf_altq *altq; 2761 2762 pa->nr = 0; 2763#ifdef __FreeBSD__ 2764 TAILQ_FOREACH(altq, V_pf_altqs_active, entries) 2765 pa->nr++; 2766 pa->ticket = V_ticket_altqs_active; 2767#else 2768 TAILQ_FOREACH(altq, pf_altqs_active, entries) 2769 pa->nr++; 2770 pa->ticket = ticket_altqs_active; 2771#endif 2772 break; 2773 } 2774 2775 case DIOCGETALTQ: { 2776 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2777 struct pf_altq *altq; 2778 u_int32_t nr; 2779 2780#ifdef __FreeBSD__ 2781 if (pa->ticket != V_ticket_altqs_active) { 2782#else 2783 if (pa->ticket != ticket_altqs_active) { 2784#endif 2785 error = EBUSY; 2786 break; 2787 } 2788 nr = 0; 2789#ifdef __FreeBSD__ 2790 altq = TAILQ_FIRST(V_pf_altqs_active); 2791#else 2792 altq = TAILQ_FIRST(pf_altqs_active); 2793#endif 2794 while ((altq != NULL) && (nr < pa->nr)) { 2795 altq = TAILQ_NEXT(altq, entries); 2796 nr++; 2797 } 2798 if (altq == NULL) { 2799 error = EBUSY; 2800 break; 2801 } 2802 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 2803 break; 2804 } 2805 2806 case DIOCCHANGEALTQ: 2807 /* CHANGEALTQ not supported yet! */ 2808 error = ENODEV; 2809 break; 2810 2811 case DIOCGETQSTATS: { 2812 struct pfioc_qstats *pq = (struct pfioc_qstats *)addr; 2813 struct pf_altq *altq; 2814 u_int32_t nr; 2815 int nbytes; 2816 2817#ifdef __FreeBSD__ 2818 if (pq->ticket != V_ticket_altqs_active) { 2819#else 2820 if (pq->ticket != ticket_altqs_active) { 2821#endif 2822 error = EBUSY; 2823 break; 2824 } 2825 nbytes = pq->nbytes; 2826 nr = 0; 2827#ifdef __FreeBSD__ 2828 altq = TAILQ_FIRST(V_pf_altqs_active); 2829#else 2830 altq = TAILQ_FIRST(pf_altqs_active); 2831#endif 2832 while ((altq != NULL) && (nr < pq->nr)) { 2833 altq = TAILQ_NEXT(altq, entries); 2834 nr++; 2835 } 2836 if (altq == NULL) { 2837 error = EBUSY; 2838 break; 2839 } 2840 2841#ifdef __FreeBSD__ 2842 if ((altq->local_flags & PFALTQ_FLAG_IF_REMOVED) != 0) { 2843 error = ENXIO; 2844 break; 2845 } 2846 PF_UNLOCK(); 2847#endif 2848 error = altq_getqstats(altq, pq->buf, &nbytes); 2849#ifdef __FreeBSD__ 2850 PF_LOCK(); 2851#endif 2852 if (error == 0) { 2853 pq->scheduler = altq->scheduler; 2854 pq->nbytes = nbytes; 2855 } 2856 break; 2857 } 2858#endif /* ALTQ */ 2859 2860 case DIOCBEGINADDRS: { 2861 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2862 2863#ifdef __FreeBSD__ 2864 pf_empty_pool(&V_pf_pabuf); 2865 pp->ticket = ++V_ticket_pabuf; 2866#else 2867 pf_empty_pool(&pf_pabuf); 2868 pp->ticket = ++ticket_pabuf; 2869#endif 2870 break; 2871 } 2872 2873 case DIOCADDADDR: { 2874 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2875 2876#ifdef __FreeBSD__ 2877 if (pp->ticket != V_ticket_pabuf) { 2878#else 2879 if (pp->ticket != ticket_pabuf) { 2880#endif 2881 error = EBUSY; 2882 break; 2883 } 2884#ifndef INET 2885 if (pp->af == AF_INET) { 2886 error = EAFNOSUPPORT; 2887 break; 2888 } 2889#endif /* INET */ 2890#ifndef INET6 2891 if (pp->af == AF_INET6) { 2892 error = EAFNOSUPPORT; 2893 break; 2894 } 2895#endif /* INET6 */ 2896 if (pp->addr.addr.type != PF_ADDR_ADDRMASK && 2897 pp->addr.addr.type != PF_ADDR_DYNIFTL && 2898 pp->addr.addr.type != PF_ADDR_TABLE) { 2899 error = EINVAL; 2900 break; 2901 } 2902#ifdef __FreeBSD__ 2903 pa = pool_get(&V_pf_pooladdr_pl, PR_NOWAIT); 2904#else 2905 pa = pool_get(&pf_pooladdr_pl, PR_WAITOK|PR_LIMITFAIL); 2906#endif 2907 if (pa == NULL) { 2908 error = ENOMEM; 2909 break; 2910 } 2911 bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr)); 2912 if (pa->ifname[0]) { 2913 pa->kif = pfi_kif_get(pa->ifname); 2914 if (pa->kif == NULL) { 2915#ifdef __FreeBSD__ 2916 pool_put(&V_pf_pooladdr_pl, pa); 2917#else 2918 pool_put(&pf_pooladdr_pl, pa); 2919#endif 2920 error = EINVAL; 2921 break; 2922 } 2923 pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE); 2924 } 2925 if (pfi_dynaddr_setup(&pa->addr, pp->af)) { 2926 pfi_dynaddr_remove(&pa->addr); 2927 pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE); 2928#ifdef __FreeBSD__ 2929 pool_put(&V_pf_pooladdr_pl, pa); 2930#else 2931 pool_put(&pf_pooladdr_pl, pa); 2932#endif 2933 error = EINVAL; 2934 break; 2935 } 2936#ifdef __FreeBSD__ 2937 TAILQ_INSERT_TAIL(&V_pf_pabuf, pa, entries); 2938#else 2939 TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries); 2940#endif 2941 break; 2942 } 2943 2944 case DIOCGETADDRS: { 2945 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2946 2947 pp->nr = 0; 2948 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, 2949 pp->r_num, 0, 1, 0); 2950 if (pool == NULL) { 2951 error = EBUSY; 2952 break; 2953 } 2954 TAILQ_FOREACH(pa, &pool->list, entries) 2955 pp->nr++; 2956 break; 2957 } 2958 2959 case DIOCGETADDR: { 2960 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2961 u_int32_t nr = 0; 2962 2963 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, 2964 pp->r_num, 0, 1, 1); 2965 if (pool == NULL) { 2966 error = EBUSY; 2967 break; 2968 } 2969 pa = TAILQ_FIRST(&pool->list); 2970 while ((pa != NULL) && (nr < pp->nr)) { 2971 pa = TAILQ_NEXT(pa, entries); 2972 nr++; 2973 } 2974 if (pa == NULL) { 2975 error = EBUSY; 2976 break; 2977 } 2978 bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr)); 2979 pf_addr_copyout(&pp->addr.addr); 2980 break; 2981 } 2982 2983 case DIOCCHANGEADDR: { 2984 struct pfioc_pooladdr *pca = (struct pfioc_pooladdr *)addr; 2985 struct pf_pooladdr *oldpa = NULL, *newpa = NULL; 2986 struct pf_ruleset *ruleset; 2987 2988 if (pca->action < PF_CHANGE_ADD_HEAD || 2989 pca->action > PF_CHANGE_REMOVE) { 2990 error = EINVAL; 2991 break; 2992 } 2993 if (pca->addr.addr.type != PF_ADDR_ADDRMASK && 2994 pca->addr.addr.type != PF_ADDR_DYNIFTL && 2995 pca->addr.addr.type != PF_ADDR_TABLE) { 2996 error = EINVAL; 2997 break; 2998 } 2999 3000 ruleset = pf_find_ruleset(pca->anchor); 3001 if (ruleset == NULL) { 3002 error = EBUSY; 3003 break; 3004 } 3005 pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action, 3006 pca->r_num, pca->r_last, 1, 1); 3007 if (pool == NULL) { 3008 error = EBUSY; 3009 break; 3010 } 3011 if (pca->action != PF_CHANGE_REMOVE) { 3012#ifdef __FreeBSD__ 3013 newpa = pool_get(&V_pf_pooladdr_pl, 3014 PR_NOWAIT); 3015#else 3016 newpa = pool_get(&pf_pooladdr_pl, 3017 PR_WAITOK|PR_LIMITFAIL); 3018#endif 3019 if (newpa == NULL) { 3020 error = ENOMEM; 3021 break; 3022 } 3023 bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr)); 3024#ifndef INET 3025 if (pca->af == AF_INET) { 3026#ifdef __FreeBSD__ 3027 pool_put(&V_pf_pooladdr_pl, newpa); 3028#else 3029 pool_put(&pf_pooladdr_pl, newpa); 3030#endif 3031 error = EAFNOSUPPORT; 3032 break; 3033 } 3034#endif /* INET */ 3035#ifndef INET6 3036 if (pca->af == AF_INET6) { 3037#ifdef __FreeBSD__ 3038 pool_put(&V_pf_pooladdr_pl, newpa); 3039#else 3040 pool_put(&pf_pooladdr_pl, newpa); 3041#endif 3042 error = EAFNOSUPPORT; 3043 break; 3044 } 3045#endif /* INET6 */ 3046 if (newpa->ifname[0]) { 3047 newpa->kif = pfi_kif_get(newpa->ifname); 3048 if (newpa->kif == NULL) { 3049#ifdef __FreeBSD__ 3050 pool_put(&V_pf_pooladdr_pl, newpa); 3051#else 3052 pool_put(&pf_pooladdr_pl, newpa); 3053#endif 3054 error = EINVAL; 3055 break; 3056 } 3057 pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE); 3058 } else 3059 newpa->kif = NULL; 3060 if (pfi_dynaddr_setup(&newpa->addr, pca->af) || 3061 pf_tbladdr_setup(ruleset, &newpa->addr)) { 3062 pfi_dynaddr_remove(&newpa->addr); 3063 pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE); 3064#ifdef __FreeBSD__ 3065 pool_put(&V_pf_pooladdr_pl, newpa); 3066#else 3067 pool_put(&pf_pooladdr_pl, newpa); 3068#endif 3069 error = EINVAL; 3070 break; 3071 } 3072 } 3073 3074 if (pca->action == PF_CHANGE_ADD_HEAD) 3075 oldpa = TAILQ_FIRST(&pool->list); 3076 else if (pca->action == PF_CHANGE_ADD_TAIL) 3077 oldpa = TAILQ_LAST(&pool->list, pf_palist); 3078 else { 3079 int i = 0; 3080 3081 oldpa = TAILQ_FIRST(&pool->list); 3082 while ((oldpa != NULL) && (i < pca->nr)) { 3083 oldpa = TAILQ_NEXT(oldpa, entries); 3084 i++; 3085 } 3086 if (oldpa == NULL) { 3087 error = EINVAL; 3088 break; 3089 } 3090 } 3091 3092 if (pca->action == PF_CHANGE_REMOVE) { 3093 TAILQ_REMOVE(&pool->list, oldpa, entries); 3094 pfi_dynaddr_remove(&oldpa->addr); 3095 pf_tbladdr_remove(&oldpa->addr); 3096 pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE); 3097#ifdef __FreeBSD__ 3098 pool_put(&V_pf_pooladdr_pl, oldpa); 3099#else 3100 pool_put(&pf_pooladdr_pl, oldpa); 3101#endif 3102 } else { 3103 if (oldpa == NULL) 3104 TAILQ_INSERT_TAIL(&pool->list, newpa, entries); 3105 else if (pca->action == PF_CHANGE_ADD_HEAD || 3106 pca->action == PF_CHANGE_ADD_BEFORE) 3107 TAILQ_INSERT_BEFORE(oldpa, newpa, entries); 3108 else 3109 TAILQ_INSERT_AFTER(&pool->list, oldpa, 3110 newpa, entries); 3111 } 3112 3113 pool->cur = TAILQ_FIRST(&pool->list); 3114 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, 3115 pca->af); 3116 break; 3117 } 3118 3119 case DIOCGETRULESETS: { 3120 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 3121 struct pf_ruleset *ruleset; 3122 struct pf_anchor *anchor; 3123 3124 pr->path[sizeof(pr->path) - 1] = 0; 3125 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) { 3126 error = EINVAL; 3127 break; 3128 } 3129 pr->nr = 0; 3130 if (ruleset->anchor == NULL) { 3131 /* XXX kludge for pf_main_ruleset */ 3132#ifdef __FreeBSD__ 3133 RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors) 3134#else 3135 RB_FOREACH(anchor, pf_anchor_global, &pf_anchors) 3136#endif 3137 if (anchor->parent == NULL) 3138 pr->nr++; 3139 } else { 3140 RB_FOREACH(anchor, pf_anchor_node, 3141 &ruleset->anchor->children) 3142 pr->nr++; 3143 } 3144 break; 3145 } 3146 3147 case DIOCGETRULESET: { 3148 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 3149 struct pf_ruleset *ruleset; 3150 struct pf_anchor *anchor; 3151 u_int32_t nr = 0; 3152 3153 pr->path[sizeof(pr->path) - 1] = 0; 3154 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) { 3155 error = EINVAL; 3156 break; 3157 } 3158 pr->name[0] = 0; 3159 if (ruleset->anchor == NULL) { 3160 /* XXX kludge for pf_main_ruleset */ 3161#ifdef __FreeBSD__ 3162 RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors) 3163#else 3164 RB_FOREACH(anchor, pf_anchor_global, &pf_anchors) 3165#endif 3166 if (anchor->parent == NULL && nr++ == pr->nr) { 3167 strlcpy(pr->name, anchor->name, 3168 sizeof(pr->name)); 3169 break; 3170 } 3171 } else { 3172 RB_FOREACH(anchor, pf_anchor_node, 3173 &ruleset->anchor->children) 3174 if (nr++ == pr->nr) { 3175 strlcpy(pr->name, anchor->name, 3176 sizeof(pr->name)); 3177 break; 3178 } 3179 } 3180 if (!pr->name[0]) 3181 error = EBUSY; 3182 break; 3183 } 3184 3185 case DIOCRCLRTABLES: { 3186 struct pfioc_table *io = (struct pfioc_table *)addr; 3187 3188 if (io->pfrio_esize != 0) { 3189 error = ENODEV; 3190 break; 3191 } 3192 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, 3193 io->pfrio_flags | PFR_FLAG_USERIOCTL); 3194 break; 3195 } 3196 3197 case DIOCRADDTABLES: { 3198 struct pfioc_table *io = (struct pfioc_table *)addr; 3199 3200 if (io->pfrio_esize != sizeof(struct pfr_table)) { 3201 error = ENODEV; 3202 break; 3203 } 3204 error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size, 3205 &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3206 break; 3207 } 3208 3209 case DIOCRDELTABLES: { 3210 struct pfioc_table *io = (struct pfioc_table *)addr; 3211 3212 if (io->pfrio_esize != sizeof(struct pfr_table)) { 3213 error = ENODEV; 3214 break; 3215 } 3216 error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size, 3217 &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3218 break; 3219 } 3220 3221 case DIOCRGETTABLES: { 3222 struct pfioc_table *io = (struct pfioc_table *)addr; 3223 3224 if (io->pfrio_esize != sizeof(struct pfr_table)) { 3225 error = ENODEV; 3226 break; 3227 } 3228 error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer, 3229 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3230 break; 3231 } 3232 3233 case DIOCRGETTSTATS: { 3234 struct pfioc_table *io = (struct pfioc_table *)addr; 3235 3236 if (io->pfrio_esize != sizeof(struct pfr_tstats)) { 3237 error = ENODEV; 3238 break; 3239 } 3240 error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer, 3241 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3242 break; 3243 } 3244 3245 case DIOCRCLRTSTATS: { 3246 struct pfioc_table *io = (struct pfioc_table *)addr; 3247 3248 if (io->pfrio_esize != sizeof(struct pfr_table)) { 3249 error = ENODEV; 3250 break; 3251 } 3252 error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size, 3253 &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3254 break; 3255 } 3256 3257 case DIOCRSETTFLAGS: { 3258 struct pfioc_table *io = (struct pfioc_table *)addr; 3259 3260 if (io->pfrio_esize != sizeof(struct pfr_table)) { 3261 error = ENODEV; 3262 break; 3263 } 3264 error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size, 3265 io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange, 3266 &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3267 break; 3268 } 3269 3270 case DIOCRCLRADDRS: { 3271 struct pfioc_table *io = (struct pfioc_table *)addr; 3272 3273 if (io->pfrio_esize != 0) { 3274 error = ENODEV; 3275 break; 3276 } 3277 error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel, 3278 io->pfrio_flags | PFR_FLAG_USERIOCTL); 3279 break; 3280 } 3281 3282 case DIOCRADDADDRS: { 3283 struct pfioc_table *io = (struct pfioc_table *)addr; 3284 3285 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3286 error = ENODEV; 3287 break; 3288 } 3289 error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer, 3290 io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags | 3291 PFR_FLAG_USERIOCTL); 3292 break; 3293 } 3294 3295 case DIOCRDELADDRS: { 3296 struct pfioc_table *io = (struct pfioc_table *)addr; 3297 3298 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3299 error = ENODEV; 3300 break; 3301 } 3302 error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer, 3303 io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags | 3304 PFR_FLAG_USERIOCTL); 3305 break; 3306 } 3307 3308 case DIOCRSETADDRS: { 3309 struct pfioc_table *io = (struct pfioc_table *)addr; 3310 3311 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3312 error = ENODEV; 3313 break; 3314 } 3315 error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer, 3316 io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd, 3317 &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags | 3318 PFR_FLAG_USERIOCTL, 0); 3319 break; 3320 } 3321 3322 case DIOCRGETADDRS: { 3323 struct pfioc_table *io = (struct pfioc_table *)addr; 3324 3325 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3326 error = ENODEV; 3327 break; 3328 } 3329 error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer, 3330 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3331 break; 3332 } 3333 3334 case DIOCRGETASTATS: { 3335 struct pfioc_table *io = (struct pfioc_table *)addr; 3336 3337 if (io->pfrio_esize != sizeof(struct pfr_astats)) { 3338 error = ENODEV; 3339 break; 3340 } 3341 error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer, 3342 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3343 break; 3344 } 3345 3346 case DIOCRCLRASTATS: { 3347 struct pfioc_table *io = (struct pfioc_table *)addr; 3348 3349 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3350 error = ENODEV; 3351 break; 3352 } 3353 error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer, 3354 io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags | 3355 PFR_FLAG_USERIOCTL); 3356 break; 3357 } 3358 3359 case DIOCRTSTADDRS: { 3360 struct pfioc_table *io = (struct pfioc_table *)addr; 3361 3362 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3363 error = ENODEV; 3364 break; 3365 } 3366 error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer, 3367 io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags | 3368 PFR_FLAG_USERIOCTL); 3369 break; 3370 } 3371 3372 case DIOCRINADEFINE: { 3373 struct pfioc_table *io = (struct pfioc_table *)addr; 3374 3375 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3376 error = ENODEV; 3377 break; 3378 } 3379 error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer, 3380 io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr, 3381 io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3382 break; 3383 } 3384 3385 case DIOCOSFPADD: { 3386 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 3387 error = pf_osfp_add(io); 3388 break; 3389 } 3390 3391 case DIOCOSFPGET: { 3392 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 3393 error = pf_osfp_get(io); 3394 break; 3395 } 3396 3397 case DIOCXBEGIN: { 3398 struct pfioc_trans *io = (struct pfioc_trans *)addr; 3399 struct pfioc_trans_e *ioe; 3400 struct pfr_table *table; 3401 int i; 3402 3403 if (io->esize != sizeof(*ioe)) { 3404 error = ENODEV; 3405 goto fail; 3406 } 3407#ifdef __FreeBSD__ 3408 PF_UNLOCK(); 3409#endif 3410 ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK); 3411 table = malloc(sizeof(*table), M_TEMP, M_WAITOK); 3412#ifdef __FreeBSD__ 3413 PF_LOCK(); 3414#endif 3415 for (i = 0; i < io->size; i++) { 3416#ifdef __FreeBSD__ 3417 PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); 3418 if (error) { 3419#else 3420 if (copyin(io->array+i, ioe, sizeof(*ioe))) { 3421#endif 3422 free(table, M_TEMP); 3423 free(ioe, M_TEMP); 3424 error = EFAULT; 3425 goto fail; 3426 } 3427 switch (ioe->rs_num) { 3428#ifdef ALTQ 3429 case PF_RULESET_ALTQ: 3430 if (ioe->anchor[0]) { 3431 free(table, M_TEMP); 3432 free(ioe, M_TEMP); 3433 error = EINVAL; 3434 goto fail; 3435 } 3436 if ((error = pf_begin_altq(&ioe->ticket))) { 3437 free(table, M_TEMP); 3438 free(ioe, M_TEMP); 3439 goto fail; 3440 } 3441 break; 3442#endif /* ALTQ */ 3443 case PF_RULESET_TABLE: 3444 bzero(table, sizeof(*table)); 3445 strlcpy(table->pfrt_anchor, ioe->anchor, 3446 sizeof(table->pfrt_anchor)); 3447 if ((error = pfr_ina_begin(table, 3448 &ioe->ticket, NULL, 0))) { 3449 free(table, M_TEMP); 3450 free(ioe, M_TEMP); 3451 goto fail; 3452 } 3453 break; 3454 default: 3455 if ((error = pf_begin_rules(&ioe->ticket, 3456 ioe->rs_num, ioe->anchor))) { 3457 free(table, M_TEMP); 3458 free(ioe, M_TEMP); 3459 goto fail; 3460 } 3461 break; 3462 } 3463#ifdef __FreeBSD__ 3464 PF_COPYOUT(ioe, io->array+i, sizeof(io->array[i]), 3465 error); 3466 if (error) { 3467#else 3468 if (copyout(ioe, io->array+i, sizeof(io->array[i]))) { 3469#endif 3470 free(table, M_TEMP); 3471 free(ioe, M_TEMP); 3472 error = EFAULT; 3473 goto fail; 3474 } 3475 } 3476 free(table, M_TEMP); 3477 free(ioe, M_TEMP); 3478 break; 3479 } 3480 3481 case DIOCXROLLBACK: { 3482 struct pfioc_trans *io = (struct pfioc_trans *)addr; 3483 struct pfioc_trans_e *ioe; 3484 struct pfr_table *table; 3485 int i; 3486 3487 if (io->esize != sizeof(*ioe)) { 3488 error = ENODEV; 3489 goto fail; 3490 } 3491#ifdef __FreeBSD__ 3492 PF_UNLOCK(); 3493#endif 3494 ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK); 3495 table = malloc(sizeof(*table), M_TEMP, M_WAITOK); 3496#ifdef __FreeBSD__ 3497 PF_LOCK(); 3498#endif 3499 for (i = 0; i < io->size; i++) { 3500#ifdef __FreeBSD__ 3501 PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); 3502 if (error) { 3503#else 3504 if (copyin(io->array+i, ioe, sizeof(*ioe))) { 3505#endif 3506 free(table, M_TEMP); 3507 free(ioe, M_TEMP); 3508 error = EFAULT; 3509 goto fail; 3510 } 3511 switch (ioe->rs_num) { 3512#ifdef ALTQ 3513 case PF_RULESET_ALTQ: 3514 if (ioe->anchor[0]) { 3515 free(table, M_TEMP); 3516 free(ioe, M_TEMP); 3517 error = EINVAL; 3518 goto fail; 3519 } 3520 if ((error = pf_rollback_altq(ioe->ticket))) { 3521 free(table, M_TEMP); 3522 free(ioe, M_TEMP); 3523 goto fail; /* really bad */ 3524 } 3525 break; 3526#endif /* ALTQ */ 3527 case PF_RULESET_TABLE: 3528 bzero(table, sizeof(*table)); 3529 strlcpy(table->pfrt_anchor, ioe->anchor, 3530 sizeof(table->pfrt_anchor)); 3531 if ((error = pfr_ina_rollback(table, 3532 ioe->ticket, NULL, 0))) { 3533 free(table, M_TEMP); 3534 free(ioe, M_TEMP); 3535 goto fail; /* really bad */ 3536 } 3537 break; 3538 default: 3539 if ((error = pf_rollback_rules(ioe->ticket, 3540 ioe->rs_num, ioe->anchor))) { 3541 free(table, M_TEMP); 3542 free(ioe, M_TEMP); 3543 goto fail; /* really bad */ 3544 } 3545 break; 3546 } 3547 } 3548 free(table, M_TEMP); 3549 free(ioe, M_TEMP); 3550 break; 3551 } 3552 3553 case DIOCXCOMMIT: { 3554 struct pfioc_trans *io = (struct pfioc_trans *)addr; 3555 struct pfioc_trans_e *ioe; 3556 struct pfr_table *table; 3557 struct pf_ruleset *rs; 3558 int i; 3559 3560 if (io->esize != sizeof(*ioe)) { 3561 error = ENODEV; 3562 goto fail; 3563 } 3564#ifdef __FreeBSD__ 3565 PF_UNLOCK(); 3566#endif 3567 ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK); 3568 table = malloc(sizeof(*table), M_TEMP, M_WAITOK); 3569#ifdef __FreeBSD__ 3570 PF_LOCK(); 3571#endif 3572 /* first makes sure everything will succeed */ 3573 for (i = 0; i < io->size; i++) { 3574#ifdef __FreeBSD__ 3575 PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); 3576 if (error) { 3577#else 3578 if (copyin(io->array+i, ioe, sizeof(*ioe))) { 3579#endif 3580 free(table, M_TEMP); 3581 free(ioe, M_TEMP); 3582 error = EFAULT; 3583 goto fail; 3584 } 3585 switch (ioe->rs_num) { 3586#ifdef ALTQ 3587 case PF_RULESET_ALTQ: 3588 if (ioe->anchor[0]) { 3589 free(table, M_TEMP); 3590 free(ioe, M_TEMP); 3591 error = EINVAL; 3592 goto fail; 3593 } 3594#ifdef __FreeBSD__ 3595 if (!V_altqs_inactive_open || ioe->ticket != 3596 V_ticket_altqs_inactive) { 3597#else 3598 if (!altqs_inactive_open || ioe->ticket != 3599 ticket_altqs_inactive) { 3600#endif 3601 free(table, M_TEMP); 3602 free(ioe, M_TEMP); 3603 error = EBUSY; 3604 goto fail; 3605 } 3606 break; 3607#endif /* ALTQ */ 3608 case PF_RULESET_TABLE: 3609 rs = pf_find_ruleset(ioe->anchor); 3610 if (rs == NULL || !rs->topen || ioe->ticket != 3611 rs->tticket) { 3612 free(table, M_TEMP); 3613 free(ioe, M_TEMP); 3614 error = EBUSY; 3615 goto fail; 3616 } 3617 break; 3618 default: 3619 if (ioe->rs_num < 0 || ioe->rs_num >= 3620 PF_RULESET_MAX) { 3621 free(table, M_TEMP); 3622 free(ioe, M_TEMP); 3623 error = EINVAL; 3624 goto fail; 3625 } 3626 rs = pf_find_ruleset(ioe->anchor); 3627 if (rs == NULL || 3628 !rs->rules[ioe->rs_num].inactive.open || 3629 rs->rules[ioe->rs_num].inactive.ticket != 3630 ioe->ticket) { 3631 free(table, M_TEMP); 3632 free(ioe, M_TEMP); 3633 error = EBUSY; 3634 goto fail; 3635 } 3636 break; 3637 } 3638 } 3639 /* now do the commit - no errors should happen here */ 3640 for (i = 0; i < io->size; i++) { 3641#ifdef __FreeBSD__ 3642 PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); 3643 if (error) { 3644#else 3645 if (copyin(io->array+i, ioe, sizeof(*ioe))) { 3646#endif 3647 free(table, M_TEMP); 3648 free(ioe, M_TEMP); 3649 error = EFAULT; 3650 goto fail; 3651 } 3652 switch (ioe->rs_num) { 3653#ifdef ALTQ 3654 case PF_RULESET_ALTQ: 3655 if ((error = pf_commit_altq(ioe->ticket))) { 3656 free(table, M_TEMP); 3657 free(ioe, M_TEMP); 3658 goto fail; /* really bad */ 3659 } 3660 break; 3661#endif /* ALTQ */ 3662 case PF_RULESET_TABLE: 3663 bzero(table, sizeof(*table)); 3664 strlcpy(table->pfrt_anchor, ioe->anchor, 3665 sizeof(table->pfrt_anchor)); 3666 if ((error = pfr_ina_commit(table, ioe->ticket, 3667 NULL, NULL, 0))) { 3668 free(table, M_TEMP); 3669 free(ioe, M_TEMP); 3670 goto fail; /* really bad */ 3671 } 3672 break; 3673 default: 3674 if ((error = pf_commit_rules(ioe->ticket, 3675 ioe->rs_num, ioe->anchor))) { 3676 free(table, M_TEMP); 3677 free(ioe, M_TEMP); 3678 goto fail; /* really bad */ 3679 } 3680 break; 3681 } 3682 } 3683 free(table, M_TEMP); 3684 free(ioe, M_TEMP); 3685 break; 3686 } 3687 3688 case DIOCGETSRCNODES: { 3689 struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr; 3690 struct pf_src_node *n, *p, *pstore; 3691 u_int32_t nr = 0; 3692 int space = psn->psn_len; 3693 3694 if (space == 0) { 3695#ifdef __FreeBSD__ 3696 RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) 3697#else 3698 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) 3699#endif 3700 nr++; 3701 psn->psn_len = sizeof(struct pf_src_node) * nr; 3702 break; 3703 } 3704 3705#ifdef __FreeBSD__ 3706 PF_UNLOCK(); 3707#endif 3708 pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK); 3709#ifdef __FreeBSD__ 3710 PF_LOCK(); 3711#endif 3712 p = psn->psn_src_nodes; 3713#ifdef __FreeBSD__ 3714 RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) { 3715#else 3716 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { 3717#endif 3718 int secs = time_second, diff; 3719 3720 if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len) 3721 break; 3722 3723 bcopy(n, pstore, sizeof(*pstore)); 3724 if (n->rule.ptr != NULL) 3725 pstore->rule.nr = n->rule.ptr->nr; 3726 pstore->creation = secs - pstore->creation; 3727 if (pstore->expire > secs) 3728 pstore->expire -= secs; 3729 else 3730 pstore->expire = 0; 3731 3732 /* adjust the connection rate estimate */ 3733 diff = secs - n->conn_rate.last; 3734 if (diff >= n->conn_rate.seconds) 3735 pstore->conn_rate.count = 0; 3736 else 3737 pstore->conn_rate.count -= 3738 n->conn_rate.count * diff / 3739 n->conn_rate.seconds; 3740 3741#ifdef __FreeBSD__ 3742 PF_COPYOUT(pstore, p, sizeof(*p), error); 3743#else 3744 error = copyout(pstore, p, sizeof(*p)); 3745#endif 3746 if (error) { 3747 free(pstore, M_TEMP); 3748 goto fail; 3749 } 3750 p++; 3751 nr++; 3752 } 3753 psn->psn_len = sizeof(struct pf_src_node) * nr; 3754 3755 free(pstore, M_TEMP); 3756 break; 3757 } 3758 3759 case DIOCCLRSRCNODES: { 3760 struct pf_src_node *n; 3761 struct pf_state *state; 3762 3763#ifdef __FreeBSD__ 3764 RB_FOREACH(state, pf_state_tree_id, &V_tree_id) { 3765#else 3766 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 3767#endif 3768 state->src_node = NULL; 3769 state->nat_src_node = NULL; 3770 } 3771#ifdef __FreeBSD__ 3772 RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) { 3773#else 3774 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { 3775#endif 3776 n->expire = 1; 3777 n->states = 0; 3778 } 3779 pf_purge_expired_src_nodes(1); 3780#ifdef __FreeBSD__ 3781 V_pf_status.src_nodes = 0; 3782#else 3783 pf_status.src_nodes = 0; 3784#endif 3785 break; 3786 } 3787 3788 case DIOCKILLSRCNODES: { 3789 struct pf_src_node *sn; 3790 struct pf_state *s; 3791 struct pfioc_src_node_kill *psnk = 3792 (struct pfioc_src_node_kill *)addr; 3793 u_int killed = 0; 3794 3795#ifdef __FreeBSD__ 3796 RB_FOREACH(sn, pf_src_tree, &V_tree_src_tracking) { 3797#else 3798 RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) { 3799#endif 3800 if (PF_MATCHA(psnk->psnk_src.neg, 3801 &psnk->psnk_src.addr.v.a.addr, 3802 &psnk->psnk_src.addr.v.a.mask, 3803 &sn->addr, sn->af) && 3804 PF_MATCHA(psnk->psnk_dst.neg, 3805 &psnk->psnk_dst.addr.v.a.addr, 3806 &psnk->psnk_dst.addr.v.a.mask, 3807 &sn->raddr, sn->af)) { 3808 /* Handle state to src_node linkage */ 3809 if (sn->states != 0) { 3810 RB_FOREACH(s, pf_state_tree_id, 3811#ifdef __FreeBSD__ 3812 &V_tree_id) { 3813#else 3814 &tree_id) { 3815#endif 3816 if (s->src_node == sn) 3817 s->src_node = NULL; 3818 if (s->nat_src_node == sn) 3819 s->nat_src_node = NULL; 3820 } 3821 sn->states = 0; 3822 } 3823 sn->expire = 1; 3824 killed++; 3825 } 3826 } 3827 3828 if (killed > 0) 3829 pf_purge_expired_src_nodes(1); 3830 3831 psnk->psnk_killed = killed; 3832 break; 3833 } 3834 3835 case DIOCSETHOSTID: { 3836 u_int32_t *hostid = (u_int32_t *)addr; 3837 3838#ifdef __FreeBSD__ 3839 if (*hostid == 0) 3840 V_pf_status.hostid = arc4random(); 3841 else 3842 V_pf_status.hostid = *hostid; 3843#else 3844 if (*hostid == 0) 3845 pf_status.hostid = arc4random(); 3846 else 3847 pf_status.hostid = *hostid; 3848#endif 3849 break; 3850 } 3851 3852 case DIOCOSFPFLUSH: 3853 pf_osfp_flush(); 3854 break; 3855 3856 case DIOCIGETIFACES: { 3857 struct pfioc_iface *io = (struct pfioc_iface *)addr; 3858 3859 if (io->pfiio_esize != sizeof(struct pfi_kif)) { 3860 error = ENODEV; 3861 break; 3862 } 3863 error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer, 3864 &io->pfiio_size); 3865 break; 3866 } 3867 3868 case DIOCSETIFFLAG: { 3869 struct pfioc_iface *io = (struct pfioc_iface *)addr; 3870 3871 error = pfi_set_flags(io->pfiio_name, io->pfiio_flags); 3872 break; 3873 } 3874 3875 case DIOCCLRIFFLAG: { 3876 struct pfioc_iface *io = (struct pfioc_iface *)addr; 3877 3878 error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags); 3879 break; 3880 } 3881 3882 default: 3883 error = ENODEV; 3884 break; 3885 } 3886fail: 3887#ifdef __FreeBSD__ 3888 PF_UNLOCK(); 3889 3890 if (flags & FWRITE) 3891 sx_xunlock(&V_pf_consistency_lock); 3892 else 3893 sx_sunlock(&V_pf_consistency_lock); 3894#else 3895 splx(s); 3896 if (flags & FWRITE) 3897 rw_exit_write(&pf_consistency_lock); 3898 else 3899 rw_exit_read(&pf_consistency_lock); 3900#endif 3901 3902 CURVNET_RESTORE(); 3903 3904 return (error); 3905} 3906 3907#ifdef __FreeBSD__ 3908void 3909pfsync_state_export(struct pfsync_state *sp, struct pf_state *st) 3910{ 3911 bzero(sp, sizeof(struct pfsync_state)); 3912 3913 /* copy from state key */ 3914 sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0]; 3915 sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1]; 3916 sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0]; 3917 sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1]; 3918 sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0]; 3919 sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1]; 3920 sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; 3921 sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; 3922 sp->proto = st->key[PF_SK_WIRE]->proto; 3923 sp->af = st->key[PF_SK_WIRE]->af; 3924 3925 /* copy from state */ 3926 strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); 3927 bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 3928 sp->creation = htonl(time_second - st->creation); 3929 sp->expire = pf_state_expires(st); 3930 if (sp->expire <= time_second) 3931 sp->expire = htonl(0); 3932 else 3933 sp->expire = htonl(sp->expire - time_second); 3934 3935 sp->direction = st->direction; 3936 sp->log = st->log; 3937 sp->timeout = st->timeout; 3938 sp->state_flags = st->state_flags; 3939 if (st->src_node) 3940 sp->sync_flags |= PFSYNC_FLAG_SRCNODE; 3941 if (st->nat_src_node) 3942 sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; 3943 3944 bcopy(&st->id, &sp->id, sizeof(sp->id)); 3945 sp->creatorid = st->creatorid; 3946 pf_state_peer_hton(&st->src, &sp->src); 3947 pf_state_peer_hton(&st->dst, &sp->dst); 3948 3949 if (st->rule.ptr == NULL) 3950 sp->rule = htonl(-1); 3951 else 3952 sp->rule = htonl(st->rule.ptr->nr); 3953 if (st->anchor.ptr == NULL) 3954 sp->anchor = htonl(-1); 3955 else 3956 sp->anchor = htonl(st->anchor.ptr->nr); 3957 if (st->nat_rule.ptr == NULL) 3958 sp->nat_rule = htonl(-1); 3959 else 3960 sp->nat_rule = htonl(st->nat_rule.ptr->nr); 3961 3962 pf_state_counter_hton(st->packets[0], sp->packets[0]); 3963 pf_state_counter_hton(st->packets[1], sp->packets[1]); 3964 pf_state_counter_hton(st->bytes[0], sp->bytes[0]); 3965 pf_state_counter_hton(st->bytes[1], sp->bytes[1]); 3966 3967} 3968 3969/* 3970 * XXX - Check for version missmatch!!! 3971 */ 3972static void 3973pf_clear_states(void) 3974{ 3975 struct pf_state *state; 3976 3977#ifdef __FreeBSD__ 3978 RB_FOREACH(state, pf_state_tree_id, &V_tree_id) { 3979#else 3980 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 3981#endif 3982 state->timeout = PFTM_PURGE; 3983#if NPFSYNC 3984 /* don't send out individual delete messages */ 3985 state->sync_state = PFSTATE_NOSYNC; 3986#endif 3987 pf_unlink_state(state); 3988 } 3989 3990#if 0 /* NPFSYNC */ 3991/* 3992 * XXX This is called on module unload, we do not want to sync that over? */ 3993 */ 3994 pfsync_clear_states(V_pf_status.hostid, psk->psk_ifname); 3995#endif 3996} 3997 3998static int 3999pf_clear_tables(void) 4000{ 4001 struct pfioc_table io; 4002 int error; 4003 4004 bzero(&io, sizeof(io)); 4005 4006 error = pfr_clr_tables(&io.pfrio_table, &io.pfrio_ndel, 4007 io.pfrio_flags); 4008 4009 return (error); 4010} 4011 4012static void 4013pf_clear_srcnodes(void) 4014{ 4015 struct pf_src_node *n; 4016 struct pf_state *state; 4017 4018#ifdef __FreeBSD__ 4019 RB_FOREACH(state, pf_state_tree_id, &V_tree_id) { 4020#else 4021 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 4022#endif 4023 state->src_node = NULL; 4024 state->nat_src_node = NULL; 4025 } 4026#ifdef __FreeBSD__ 4027 RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) { 4028#else 4029 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { 4030#endif 4031 n->expire = 1; 4032 n->states = 0; 4033 } 4034} 4035/* 4036 * XXX - Check for version missmatch!!! 4037 */ 4038 4039/* 4040 * Duplicate pfctl -Fa operation to get rid of as much as we can. 4041 */ 4042static int 4043shutdown_pf(void) 4044{ 4045 int error = 0; 4046 u_int32_t t[5]; 4047 char nn = '\0'; 4048 4049 V_pf_status.running = 0; 4050 do { 4051 if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn)) 4052 != 0) { 4053 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: SCRUB\n")); 4054 break; 4055 } 4056 if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn)) 4057 != 0) { 4058 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: FILTER\n")); 4059 break; /* XXX: rollback? */ 4060 } 4061 if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn)) 4062 != 0) { 4063 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: NAT\n")); 4064 break; /* XXX: rollback? */ 4065 } 4066 if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn)) 4067 != 0) { 4068 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: BINAT\n")); 4069 break; /* XXX: rollback? */ 4070 } 4071 if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn)) 4072 != 0) { 4073 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: RDR\n")); 4074 break; /* XXX: rollback? */ 4075 } 4076 4077 /* XXX: these should always succeed here */ 4078 pf_commit_rules(t[0], PF_RULESET_SCRUB, &nn); 4079 pf_commit_rules(t[1], PF_RULESET_FILTER, &nn); 4080 pf_commit_rules(t[2], PF_RULESET_NAT, &nn); 4081 pf_commit_rules(t[3], PF_RULESET_BINAT, &nn); 4082 pf_commit_rules(t[4], PF_RULESET_RDR, &nn); 4083 4084 if ((error = pf_clear_tables()) != 0) 4085 break; 4086 4087 #ifdef ALTQ 4088 if ((error = pf_begin_altq(&t[0])) != 0) { 4089 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n")); 4090 break; 4091 } 4092 pf_commit_altq(t[0]); 4093 #endif 4094 4095 pf_clear_states(); 4096 4097 pf_clear_srcnodes(); 4098 4099 /* status does not use malloced mem so no need to cleanup */ 4100 /* fingerprints and interfaces have thier own cleanup code */ 4101 } while(0); 4102 4103 return (error); 4104} 4105 4106#ifdef INET 4107static int 4108pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 4109 struct inpcb *inp) 4110{ 4111 /* 4112 * XXX Wed Jul 9 22:03:16 2003 UTC 4113 * OpenBSD has changed its byte ordering convention on ip_len/ip_off 4114 * in network stack. OpenBSD's network stack have converted 4115 * ip_len/ip_off to host byte order frist as FreeBSD. 4116 * Now this is not true anymore , so we should convert back to network 4117 * byte order. 4118 */ 4119 struct ip *h = NULL; 4120 int chk; 4121 4122 if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) { 4123 /* if m_pkthdr.len is less than ip header, pf will handle. */ 4124 h = mtod(*m, struct ip *); 4125 HTONS(h->ip_len); 4126 HTONS(h->ip_off); 4127 } 4128 CURVNET_SET(ifp->if_vnet); 4129 chk = pf_test(PF_IN, ifp, m, NULL, inp); 4130 CURVNET_RESTORE(); 4131 if (chk && *m) { 4132 m_freem(*m); 4133 *m = NULL; 4134 } 4135 if (*m != NULL) { 4136 /* pf_test can change ip header location */ 4137 h = mtod(*m, struct ip *); 4138 NTOHS(h->ip_len); 4139 NTOHS(h->ip_off); 4140 } 4141 return chk; 4142} 4143 4144static int 4145pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 4146 struct inpcb *inp) 4147{ 4148 /* 4149 * XXX Wed Jul 9 22:03:16 2003 UTC 4150 * OpenBSD has changed its byte ordering convention on ip_len/ip_off 4151 * in network stack. OpenBSD's network stack have converted 4152 * ip_len/ip_off to host byte order frist as FreeBSD. 4153 * Now this is not true anymore , so we should convert back to network 4154 * byte order. 4155 */ 4156 struct ip *h = NULL; 4157 int chk; 4158 4159 /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */ 4160 if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 4161 in_delayed_cksum(*m); 4162 (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 4163 } 4164 if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) { 4165 /* if m_pkthdr.len is less than ip header, pf will handle. */ 4166 h = mtod(*m, struct ip *); 4167 HTONS(h->ip_len); 4168 HTONS(h->ip_off); 4169 } 4170 CURVNET_SET(ifp->if_vnet); 4171 chk = pf_test(PF_OUT, ifp, m, NULL, inp); 4172 CURVNET_RESTORE(); 4173 if (chk && *m) { 4174 m_freem(*m); 4175 *m = NULL; 4176 } 4177 if (*m != NULL) { 4178 /* pf_test can change ip header location */ 4179 h = mtod(*m, struct ip *); 4180 NTOHS(h->ip_len); 4181 NTOHS(h->ip_off); 4182 } 4183 return chk; 4184} 4185#endif 4186 4187#ifdef INET6 4188static int 4189pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 4190 struct inpcb *inp) 4191{ 4192 4193 /* 4194 * IPv6 is not affected by ip_len/ip_off byte order changes. 4195 */ 4196 int chk; 4197 4198 /* 4199 * In case of loopback traffic IPv6 uses the real interface in 4200 * order to support scoped addresses. In order to support stateful 4201 * filtering we have change this to lo0 as it is the case in IPv4. 4202 */ 4203 CURVNET_SET(ifp->if_vnet); 4204 chk = pf_test6(PF_IN, (*m)->m_flags & M_LOOP ? V_loif : ifp, m, 4205 NULL, inp); 4206 CURVNET_RESTORE(); 4207 if (chk && *m) { 4208 m_freem(*m); 4209 *m = NULL; 4210 } 4211 return chk; 4212} 4213 4214static int 4215pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 4216 struct inpcb *inp) 4217{ 4218 /* 4219 * IPv6 does not affected ip_len/ip_off byte order changes. 4220 */ 4221 int chk; 4222 4223 /* We need a proper CSUM before we start (s. OpenBSD ip_output) */ 4224 if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 4225#ifdef INET 4226 /* XXX-BZ copy&paste error from r126261? */ 4227 in_delayed_cksum(*m); 4228#endif 4229 (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 4230 } 4231 CURVNET_SET(ifp->if_vnet); 4232 chk = pf_test6(PF_OUT, ifp, m, NULL, inp); 4233 CURVNET_RESTORE(); 4234 if (chk && *m) { 4235 m_freem(*m); 4236 *m = NULL; 4237 } 4238 return chk; 4239} 4240#endif /* INET6 */ 4241 4242static int 4243hook_pf(void) 4244{ 4245#ifdef INET 4246 struct pfil_head *pfh_inet; 4247#endif 4248#ifdef INET6 4249 struct pfil_head *pfh_inet6; 4250#endif 4251 4252 PF_UNLOCK_ASSERT(); 4253 4254 if (V_pf_pfil_hooked) 4255 return (0); 4256 4257#ifdef INET 4258 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 4259 if (pfh_inet == NULL) 4260 return (ESRCH); /* XXX */ 4261 pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); 4262 pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); 4263#endif 4264#ifdef INET6 4265 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 4266 if (pfh_inet6 == NULL) { 4267#ifdef INET 4268 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, 4269 pfh_inet); 4270 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 4271 pfh_inet); 4272#endif 4273 return (ESRCH); /* XXX */ 4274 } 4275 pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); 4276 pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); 4277#endif 4278 4279 V_pf_pfil_hooked = 1; 4280 return (0); 4281} 4282 4283static int 4284dehook_pf(void) 4285{ 4286#ifdef INET 4287 struct pfil_head *pfh_inet; 4288#endif 4289#ifdef INET6 4290 struct pfil_head *pfh_inet6; 4291#endif 4292 4293 PF_UNLOCK_ASSERT(); 4294 4295 if (V_pf_pfil_hooked == 0) 4296 return (0); 4297 4298#ifdef INET 4299 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 4300 if (pfh_inet == NULL) 4301 return (ESRCH); /* XXX */ 4302 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, 4303 pfh_inet); 4304 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 4305 pfh_inet); 4306#endif 4307#ifdef INET6 4308 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 4309 if (pfh_inet6 == NULL) 4310 return (ESRCH); /* XXX */ 4311 pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, 4312 pfh_inet6); 4313 pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, 4314 pfh_inet6); 4315#endif 4316 4317 V_pf_pfil_hooked = 0; 4318 return (0); 4319} 4320 4321static int 4322pf_load(void) 4323{ 4324 VNET_ITERATOR_DECL(vnet_iter); 4325 4326 VNET_LIST_RLOCK(); 4327 VNET_FOREACH(vnet_iter) { 4328 CURVNET_SET(vnet_iter); 4329 V_pf_pfil_hooked = 0; 4330 V_pf_end_threads = 0; 4331 V_debug_pfugidhack = 0; 4332 TAILQ_INIT(&V_pf_tags); 4333 TAILQ_INIT(&V_pf_qids); 4334 CURVNET_RESTORE(); 4335 } 4336 VNET_LIST_RUNLOCK(); 4337 4338 init_pf_mutex(); 4339 pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME); 4340 init_zone_var(); 4341 sx_init(&V_pf_consistency_lock, "pf_statetbl_lock"); 4342 if (pfattach() < 0) 4343 return (ENOMEM); 4344 4345 return (0); 4346} 4347 4348static int 4349pf_unload(void) 4350{ 4351 int error = 0; 4352 4353 PF_LOCK(); 4354 V_pf_status.running = 0; 4355 PF_UNLOCK(); 4356 m_addr_chg_pf_p = NULL; 4357 error = dehook_pf(); 4358 if (error) { 4359 /* 4360 * Should not happen! 4361 * XXX Due to error code ESRCH, kldunload will show 4362 * a message like 'No such process'. 4363 */ 4364 printf("%s : pfil unregisteration fail\n", __FUNCTION__); 4365 return error; 4366 } 4367 PF_LOCK(); 4368 shutdown_pf(); 4369 V_pf_end_threads = 1; 4370 while (V_pf_end_threads < 2) { 4371 wakeup_one(pf_purge_thread); 4372 msleep(pf_purge_thread, &pf_task_mtx, 0, "pftmo", hz); 4373 } 4374 pfi_cleanup(); 4375 pf_osfp_flush(); 4376 pf_osfp_cleanup(); 4377 cleanup_pf_zone(); 4378 PF_UNLOCK(); 4379 destroy_dev(pf_dev); 4380 destroy_pf_mutex(); 4381 sx_destroy(&V_pf_consistency_lock); 4382 return error; 4383} 4384 4385static int 4386pf_modevent(module_t mod, int type, void *data) 4387{ 4388 int error = 0; 4389 4390 switch(type) { 4391 case MOD_LOAD: 4392 error = pf_load(); 4393 break; 4394 case MOD_QUIESCE: 4395 /* 4396 * Module should not be unloaded due to race conditions. 4397 */ 4398 error = EPERM; 4399 break; 4400 case MOD_UNLOAD: 4401 error = pf_unload(); 4402 break; 4403 default: 4404 error = EINVAL; 4405 break; 4406 } 4407 return error; 4408} 4409 4410static moduledata_t pf_mod = { 4411 "pf", 4412 pf_modevent, 4413 0 4414}; 4415 4416DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_FIRST); 4417MODULE_VERSION(pf, PF_MODVER); 4418#endif /* __FreeBSD__ */ 4419