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