1223637Sbz/* $OpenBSD: pf_ioctl.c,v 1.213 2009/02/15 21:46:12 mbalmer Exp $ */ 2126258Smlaier 3126258Smlaier/* 4126258Smlaier * Copyright (c) 2001 Daniel Hartmeier 5130613Smlaier * Copyright (c) 2002,2003 Henning Brauer 6126258Smlaier * All rights reserved. 7126258Smlaier * 8126258Smlaier * Redistribution and use in source and binary forms, with or without 9126258Smlaier * modification, are permitted provided that the following conditions 10126258Smlaier * are met: 11126258Smlaier * 12126258Smlaier * - Redistributions of source code must retain the above copyright 13126258Smlaier * notice, this list of conditions and the following disclaimer. 14126258Smlaier * - Redistributions in binary form must reproduce the above 15126258Smlaier * copyright notice, this list of conditions and the following 16126258Smlaier * disclaimer in the documentation and/or other materials provided 17126258Smlaier * with the distribution. 18126258Smlaier * 19126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20126258Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21126258Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22126258Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23126258Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24126258Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25126258Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26126258Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27126258Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28126258Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29126258Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30126258Smlaier * POSSIBILITY OF SUCH DAMAGE. 31126258Smlaier * 32126258Smlaier * Effort sponsored in part by the Defense Advanced Research Projects 33126258Smlaier * Agency (DARPA) and Air Force Research Laboratory, Air Force 34126258Smlaier * Materiel Command, USAF, under agreement number F30602-01-2-0537. 35126258Smlaier * 36126258Smlaier */ 37126258Smlaier 38127145Smlaier#ifdef __FreeBSD__ 39171168Smlaier#include <sys/cdefs.h> 40171168Smlaier__FBSDID("$FreeBSD$"); 41126261Smlaier 42189106Sbz#include "opt_inet.h" 43189106Sbz#include "opt_inet6.h" 44130613Smlaier#include "opt_bpf.h" 45130613Smlaier#include "opt_pf.h" 46153110Sru 47230868Sglebius#define NPFSYNC 1 48153110Sru 49153110Sru#ifdef DEV_PFLOG 50223637Sbz#define NPFLOG DEV_PFLOG 51153110Sru#else 52223637Sbz#define NPFLOG 0 53153110Sru#endif 54153110Sru 55230868Sglebius#else /* !__FreeBSD__ */ 56223637Sbz#include "pfsync.h" 57130613Smlaier#include "pflog.h" 58230868Sglebius#endif /* __FreeBSD__ */ 59130613Smlaier 60126258Smlaier#include <sys/param.h> 61126258Smlaier#include <sys/systm.h> 62126258Smlaier#include <sys/mbuf.h> 63126258Smlaier#include <sys/filio.h> 64126258Smlaier#include <sys/fcntl.h> 65126258Smlaier#include <sys/socket.h> 66126258Smlaier#include <sys/socketvar.h> 67126258Smlaier#include <sys/kernel.h> 68126258Smlaier#include <sys/time.h> 69127145Smlaier#ifdef __FreeBSD__ 70223637Sbz#include <sys/ucred.h> 71223637Sbz#include <sys/jail.h> 72129907Smlaier#include <sys/module.h> 73126261Smlaier#include <sys/conf.h> 74134166Smlaier#include <sys/proc.h> 75171168Smlaier#include <sys/sysctl.h> 76126261Smlaier#else 77126258Smlaier#include <sys/timeout.h> 78126258Smlaier#include <sys/pool.h> 79126261Smlaier#endif 80171168Smlaier#include <sys/proc.h> 81171168Smlaier#include <sys/malloc.h> 82171168Smlaier#include <sys/kthread.h> 83171168Smlaier#ifndef __FreeBSD__ 84171168Smlaier#include <sys/rwlock.h> 85171168Smlaier#include <uvm/uvm_extern.h> 86171168Smlaier#endif 87126258Smlaier 88126258Smlaier#include <net/if.h> 89126258Smlaier#include <net/if_types.h> 90185571Sbz#ifdef __FreeBSD__ 91185571Sbz#include <net/vnet.h> 92185571Sbz#endif 93223637Sbz#include <net/route.h> 94126258Smlaier 95126258Smlaier#include <netinet/in.h> 96126258Smlaier#include <netinet/in_var.h> 97126258Smlaier#include <netinet/in_systm.h> 98126258Smlaier#include <netinet/ip.h> 99126258Smlaier#include <netinet/ip_var.h> 100126258Smlaier#include <netinet/ip_icmp.h> 101126258Smlaier 102171168Smlaier#ifdef __FreeBSD__ 103171168Smlaier#include <sys/md5.h> 104171168Smlaier#else 105130613Smlaier#include <dev/rndvar.h> 106171168Smlaier#include <crypto/md5.h> 107130613Smlaier#endif 108126258Smlaier#include <net/pfvar.h> 109126258Smlaier 110130613Smlaier#include <net/if_pfsync.h> 111130613Smlaier 112223637Sbz#if NPFLOG > 0 113155337Smlaier#include <net/if_pflog.h> 114223637Sbz#endif /* NPFLOG > 0 */ 115155337Smlaier 116126258Smlaier#ifdef INET6 117126258Smlaier#include <netinet/ip6.h> 118126258Smlaier#include <netinet/in_pcb.h> 119126258Smlaier#endif /* INET6 */ 120126258Smlaier 121126258Smlaier#ifdef ALTQ 122126258Smlaier#include <altq/altq.h> 123126258Smlaier#endif 124126258Smlaier 125127145Smlaier#ifdef __FreeBSD__ 126126261Smlaier#include <sys/limits.h> 127126261Smlaier#include <sys/lock.h> 128126261Smlaier#include <sys/mutex.h> 129126261Smlaier#include <net/pfil.h> 130126261Smlaier#endif /* __FreeBSD__ */ 131126261Smlaier 132127145Smlaier#ifdef __FreeBSD__ 133126261Smlaiervoid init_zone_var(void); 134126261Smlaiervoid cleanup_pf_zone(void); 135126261Smlaierint pfattach(void); 136126261Smlaier#else 137126258Smlaiervoid pfattach(int); 138171168Smlaiervoid pf_thread_create(void *); 139145836Smlaierint pfopen(dev_t, int, int, struct proc *); 140145836Smlaierint pfclose(dev_t, int, int, struct proc *); 141126261Smlaier#endif 142145836Smlaierstruct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t, 143145836Smlaier u_int8_t, u_int8_t, u_int8_t); 144145836Smlaier 145126258Smlaiervoid pf_mv_pool(struct pf_palist *, struct pf_palist *); 146126258Smlaiervoid pf_empty_pool(struct pf_palist *); 147127145Smlaier#ifdef __FreeBSD__ 148130585Sphkint pfioctl(struct cdev *, u_long, caddr_t, int, struct thread *); 149126261Smlaier#else 150223637Sbzint pfioctl(dev_t, u_long, caddr_t, int, struct proc *); 151126261Smlaier#endif 152130613Smlaier#ifdef ALTQ 153130613Smlaierint pf_begin_altq(u_int32_t *); 154130613Smlaierint pf_rollback_altq(u_int32_t); 155130613Smlaierint pf_commit_altq(u_int32_t); 156135352Smlaierint pf_enable_altq(struct pf_altq *); 157135352Smlaierint pf_disable_altq(struct pf_altq *); 158130613Smlaier#endif /* ALTQ */ 159145836Smlaierint pf_begin_rules(u_int32_t *, int, const char *); 160145836Smlaierint pf_rollback_rules(u_int32_t, int, char *); 161171168Smlaierint pf_setup_pfsync_matching(struct pf_ruleset *); 162171168Smlaiervoid pf_hash_rule(MD5_CTX *, struct pf_rule *); 163171168Smlaiervoid pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *); 164145836Smlaierint pf_commit_rules(u_int32_t, int, char *); 165223637Sbzint pf_addr_setup(struct pf_ruleset *, 166223637Sbz struct pf_addr_wrap *, sa_family_t); 167223637Sbzvoid pf_addr_copyout(struct pf_addr_wrap *); 168126258Smlaier 169223637Sbz#define TAGID_MAX 50000 170223637Sbz 171127145Smlaier#ifdef __FreeBSD__ 172223637SbzVNET_DEFINE(struct pf_rule, pf_default_rule); 173223637SbzVNET_DEFINE(struct sx, pf_consistency_lock); 174223637Sbz 175223637Sbz#ifdef ALTQ 176223637Sbzstatic VNET_DEFINE(int, pf_altq_running); 177223637Sbz#define V_pf_altq_running VNET(pf_altq_running) 178126261Smlaier#endif 179223637Sbz 180223637SbzTAILQ_HEAD(pf_tags, pf_tagname); 181223637Sbz 182223637Sbz#define V_pf_tags VNET(pf_tags) 183223637SbzVNET_DEFINE(struct pf_tags, pf_tags); 184223637Sbz#define V_pf_qids VNET(pf_qids) 185223637SbzVNET_DEFINE(struct pf_tags, pf_qids); 186223637Sbz 187223637Sbz#else /* !__FreeBSD__ */ 188223637Sbzstruct pf_rule pf_default_rule; 189223637Sbzstruct rwlock pf_consistency_lock = RWLOCK_INITIALIZER("pfcnslk"); 190135352Smlaier#ifdef ALTQ 191135352Smlaierstatic int pf_altq_running; 192135352Smlaier#endif 193126258Smlaier 194130613SmlaierTAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags), 195130613Smlaier pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids); 196223637Sbz#endif /* __FreeBSD__ */ 197126258Smlaier 198130613Smlaier#if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE) 199130613Smlaier#error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE 200130613Smlaier#endif 201223637Sbz 202171168Smlaieru_int16_t tagname2tag(struct pf_tags *, char *); 203171168Smlaiervoid tag2tagname(struct pf_tags *, u_int16_t, char *); 204171168Smlaiervoid tag_unref(struct pf_tags *, u_int16_t); 205145836Smlaierint pf_rtlabel_add(struct pf_addr_wrap *); 206145836Smlaiervoid pf_rtlabel_remove(struct pf_addr_wrap *); 207145836Smlaiervoid pf_rtlabel_copyout(struct pf_addr_wrap *); 208130613Smlaier 209223637Sbz#ifdef __FreeBSD__ 210223637Sbz#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x 211223637Sbz#else 212126258Smlaier#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x 213223637Sbz#endif 214126258Smlaier 215127145Smlaier#ifdef __FreeBSD__ 216223637Sbzstruct cdev *pf_dev; 217223637Sbz 218126261Smlaier/* 219126261Smlaier * XXX - These are new and need to be checked when moveing to a new version 220126261Smlaier */ 221130613Smlaierstatic void pf_clear_states(void); 222130613Smlaierstatic int pf_clear_tables(void); 223130613Smlaierstatic void pf_clear_srcnodes(void); 224126261Smlaier/* 225126261Smlaier * XXX - These are new and need to be checked when moveing to a new version 226126261Smlaier */ 227126261Smlaier 228130613Smlaier/* 229130613Smlaier * Wrapper functions for pfil(9) hooks 230130613Smlaier */ 231221132Sbz#ifdef INET 232126261Smlaierstatic int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, 233223637Sbz int dir, struct inpcb *inp); 234126261Smlaierstatic int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, 235223637Sbz int dir, struct inpcb *inp); 236221132Sbz#endif 237127145Smlaier#ifdef INET6 238126261Smlaierstatic int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, 239223637Sbz int dir, struct inpcb *inp); 240126261Smlaierstatic int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, 241223637Sbz int dir, struct inpcb *inp); 242126261Smlaier#endif 243223637Sbz 244223637Sbzstatic int hook_pf(void); 245223637Sbzstatic int dehook_pf(void); 246223637Sbzstatic int shutdown_pf(void); 247223637Sbzstatic int pf_load(void); 248223637Sbzstatic int pf_unload(void); 249126261Smlaier 250126261Smlaierstatic struct cdevsw pf_cdevsw = { 251126261Smlaier .d_ioctl = pfioctl, 252126261Smlaier .d_name = PF_NAME, 253126261Smlaier .d_version = D_VERSION, 254126261Smlaier}; 255126261Smlaier 256223637Sbzstatic volatile VNET_DEFINE(int, pf_pfil_hooked); 257223637Sbz#define V_pf_pfil_hooked VNET(pf_pfil_hooked) 258223637SbzVNET_DEFINE(int, pf_end_threads); 259226801Sglebiusstruct mtx pf_task_mtx; 260126261Smlaier 261223637Sbz/* pfsync */ 262223637Sbzpfsync_state_import_t *pfsync_state_import_ptr = NULL; 263223637Sbzpfsync_insert_state_t *pfsync_insert_state_ptr = NULL; 264223637Sbzpfsync_update_state_t *pfsync_update_state_ptr = NULL; 265223637Sbzpfsync_delete_state_t *pfsync_delete_state_ptr = NULL; 266223637Sbzpfsync_clear_states_t *pfsync_clear_states_ptr = NULL; 267223637Sbzpfsync_state_in_use_t *pfsync_state_in_use_ptr = NULL; 268223637Sbzpfsync_defer_t *pfsync_defer_ptr = NULL; 269223637Sbzpfsync_up_t *pfsync_up_ptr = NULL; 270223637Sbz/* pflow */ 271223637Sbzexport_pflow_t *export_pflow_ptr = NULL; 272223637Sbz/* pflog */ 273223637Sbzpflog_packet_t *pflog_packet_ptr = NULL; 274171168Smlaier 275223637SbzVNET_DEFINE(int, debug_pfugidhack); 276223637SbzSYSCTL_VNET_INT(_debug, OID_AUTO, pfugidhack, CTLFLAG_RW, 277223637Sbz &VNET_NAME(debug_pfugidhack), 0, 278223637Sbz "Enable/disable pf user/group rules mpsafe hack"); 279223637Sbz 280226801Sglebiusstatic void 281126261Smlaierinit_pf_mutex(void) 282126261Smlaier{ 283223637Sbz 284226801Sglebius mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF); 285126261Smlaier} 286126261Smlaier 287226801Sglebiusstatic void 288126261Smlaierdestroy_pf_mutex(void) 289126261Smlaier{ 290223637Sbz 291226801Sglebius mtx_destroy(&pf_task_mtx); 292126261Smlaier} 293126261Smlaiervoid 294126261Smlaierinit_zone_var(void) 295126261Smlaier{ 296223637Sbz V_pf_src_tree_pl = V_pf_rule_pl = NULL; 297223637Sbz V_pf_state_pl = V_pf_state_key_pl = V_pf_state_item_pl = NULL; 298223637Sbz V_pf_altq_pl = V_pf_pooladdr_pl = NULL; 299223637Sbz V_pf_frent_pl = V_pf_frag_pl = V_pf_cache_pl = V_pf_cent_pl = NULL; 300223637Sbz V_pf_state_scrub_pl = NULL; 301237776Sglebius V_pfr_ktable_pl = V_pfr_kentry_pl = V_pfr_kcounters_pl = NULL; 302126261Smlaier} 303126261Smlaier 304126261Smlaiervoid 305126261Smlaiercleanup_pf_zone(void) 306126261Smlaier{ 307223637Sbz UMA_DESTROY(V_pf_src_tree_pl); 308223637Sbz UMA_DESTROY(V_pf_rule_pl); 309223637Sbz UMA_DESTROY(V_pf_state_pl); 310223637Sbz UMA_DESTROY(V_pf_state_key_pl); 311223637Sbz UMA_DESTROY(V_pf_state_item_pl); 312223637Sbz UMA_DESTROY(V_pf_altq_pl); 313223637Sbz UMA_DESTROY(V_pf_pooladdr_pl); 314223637Sbz UMA_DESTROY(V_pf_frent_pl); 315223637Sbz UMA_DESTROY(V_pf_frag_pl); 316223637Sbz UMA_DESTROY(V_pf_cache_pl); 317223637Sbz UMA_DESTROY(V_pf_cent_pl); 318223637Sbz UMA_DESTROY(V_pfr_ktable_pl); 319223637Sbz UMA_DESTROY(V_pfr_kentry_pl); 320237776Sglebius UMA_DESTROY(V_pfr_kcounters_pl); 321223637Sbz UMA_DESTROY(V_pf_state_scrub_pl); 322223637Sbz UMA_DESTROY(V_pfi_addr_pl); 323126261Smlaier} 324126261Smlaier 325126261Smlaierint 326126261Smlaierpfattach(void) 327126261Smlaier{ 328223637Sbz u_int32_t *my_timeout = V_pf_default_rule.timeout; 329126261Smlaier int error = 1; 330126261Smlaier 331126261Smlaier do { 332223637Sbz UMA_CREATE(V_pf_src_tree_pl, struct pf_src_node, "pfsrctrpl"); 333223637Sbz UMA_CREATE(V_pf_rule_pl, struct pf_rule, "pfrulepl"); 334223637Sbz UMA_CREATE(V_pf_state_pl, struct pf_state, "pfstatepl"); 335223637Sbz UMA_CREATE(V_pf_state_key_pl, struct pf_state, "pfstatekeypl"); 336223637Sbz UMA_CREATE(V_pf_state_item_pl, struct pf_state, "pfstateitempl"); 337223637Sbz UMA_CREATE(V_pf_altq_pl, struct pf_altq, "pfaltqpl"); 338223637Sbz UMA_CREATE(V_pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl"); 339223637Sbz UMA_CREATE(V_pfr_ktable_pl, struct pfr_ktable, "pfrktable"); 340223637Sbz UMA_CREATE(V_pfr_kentry_pl, struct pfr_kentry, "pfrkentry"); 341237776Sglebius UMA_CREATE(V_pfr_kcounters_pl, struct pfr_kcounters, "pfrkcounters"); 342223637Sbz UMA_CREATE(V_pf_frent_pl, struct pf_frent, "pffrent"); 343223637Sbz UMA_CREATE(V_pf_frag_pl, struct pf_fragment, "pffrag"); 344223637Sbz UMA_CREATE(V_pf_cache_pl, struct pf_fragment, "pffrcache"); 345223637Sbz UMA_CREATE(V_pf_cent_pl, struct pf_frcache, "pffrcent"); 346223637Sbz UMA_CREATE(V_pf_state_scrub_pl, struct pf_state_scrub, 347126261Smlaier "pfstatescrub"); 348223637Sbz UMA_CREATE(V_pfi_addr_pl, struct pfi_dynaddr, "pfiaddrpl"); 349126261Smlaier error = 0; 350126261Smlaier } while(0); 351126261Smlaier if (error) { 352126261Smlaier cleanup_pf_zone(); 353126261Smlaier return (error); 354126261Smlaier } 355126261Smlaier pfr_initialize(); 356130613Smlaier pfi_initialize(); 357126261Smlaier if ( (error = pf_osfp_initialize()) ) { 358126261Smlaier cleanup_pf_zone(); 359126261Smlaier pf_osfp_cleanup(); 360126261Smlaier return (error); 361126261Smlaier } 362126261Smlaier 363223637Sbz V_pf_pool_limits[PF_LIMIT_STATES].pp = V_pf_state_pl; 364223637Sbz V_pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT; 365223637Sbz V_pf_pool_limits[PF_LIMIT_SRC_NODES].pp = V_pf_src_tree_pl; 366223637Sbz V_pf_pool_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT; 367223637Sbz V_pf_pool_limits[PF_LIMIT_FRAGS].pp = V_pf_frent_pl; 368223637Sbz V_pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT; 369223637Sbz V_pf_pool_limits[PF_LIMIT_TABLES].pp = V_pfr_ktable_pl; 370223637Sbz V_pf_pool_limits[PF_LIMIT_TABLES].limit = PFR_KTABLE_HIWAT; 371223637Sbz V_pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].pp = V_pfr_kentry_pl; 372223637Sbz V_pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT; 373223637Sbz uma_zone_set_max(V_pf_pool_limits[PF_LIMIT_STATES].pp, 374223637Sbz V_pf_pool_limits[PF_LIMIT_STATES].limit); 375126261Smlaier 376223637Sbz RB_INIT(&V_tree_src_tracking); 377223637Sbz RB_INIT(&V_pf_anchors); 378130613Smlaier pf_init_ruleset(&pf_main_ruleset); 379126261Smlaier 380223637Sbz TAILQ_INIT(&V_pf_altqs[0]); 381223637Sbz TAILQ_INIT(&V_pf_altqs[1]); 382223637Sbz TAILQ_INIT(&V_pf_pabuf); 383223637Sbz V_pf_altqs_active = &V_pf_altqs[0]; 384223637Sbz V_pf_altqs_inactive = &V_pf_altqs[1]; 385223637Sbz TAILQ_INIT(&V_state_list); 386223637Sbz 387126261Smlaier /* default rule should never be garbage collected */ 388223637Sbz V_pf_default_rule.entries.tqe_prev = &V_pf_default_rule.entries.tqe_next; 389223637Sbz V_pf_default_rule.action = PF_PASS; 390223637Sbz V_pf_default_rule.nr = -1; 391223637Sbz V_pf_default_rule.rtableid = -1; 392126261Smlaier 393126261Smlaier /* initialize default timeouts */ 394145836Smlaier my_timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; 395145836Smlaier my_timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; 396145836Smlaier my_timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; 397145836Smlaier my_timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; 398145836Smlaier my_timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; 399145836Smlaier my_timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; 400145836Smlaier my_timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; 401145836Smlaier my_timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; 402145836Smlaier my_timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; 403145836Smlaier my_timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; 404145836Smlaier my_timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; 405145836Smlaier my_timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; 406145836Smlaier my_timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; 407145836Smlaier my_timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; 408145836Smlaier my_timeout[PFTM_FRAG] = PFTM_FRAG_VAL; 409145836Smlaier my_timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; 410145836Smlaier my_timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; 411145836Smlaier my_timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; 412171168Smlaier my_timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; 413171168Smlaier my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; 414126261Smlaier 415126261Smlaier pf_normalize_init(); 416171168Smlaier 417223637Sbz bzero(&V_pf_status, sizeof(V_pf_status)); 418223637Sbz V_pf_status.debug = PF_DEBUG_URGENT; 419130613Smlaier 420223637Sbz V_pf_pfil_hooked = 0; 421223637Sbz 422130613Smlaier /* XXX do our best to avoid a conflict */ 423223637Sbz V_pf_status.hostid = arc4random(); 424130613Smlaier 425223637Sbz if (kproc_create(pf_purge_thread, curvnet, NULL, 0, 0, "pfpurge")) 426171168Smlaier return (ENXIO); 427171168Smlaier 428223637Sbz m_addr_chg_pf_p = pf_pkt_addr_changed; 429223637Sbz 430126261Smlaier return (error); 431126261Smlaier} 432126261Smlaier#else /* !__FreeBSD__ */ 433223637Sbz 434126261Smlaiervoid 435126258Smlaierpfattach(int num) 436126258Smlaier{ 437126258Smlaier u_int32_t *timeout = pf_default_rule.timeout; 438126258Smlaier 439126258Smlaier pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl", 440126258Smlaier &pool_allocator_nointr); 441130613Smlaier pool_init(&pf_src_tree_pl, sizeof(struct pf_src_node), 0, 0, 0, 442130613Smlaier "pfsrctrpl", NULL); 443126258Smlaier pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", 444126258Smlaier NULL); 445223637Sbz pool_init(&pf_state_key_pl, sizeof(struct pf_state_key), 0, 0, 0, 446223637Sbz "pfstatekeypl", NULL); 447223637Sbz pool_init(&pf_state_item_pl, sizeof(struct pf_state_item), 0, 0, 0, 448223637Sbz "pfstateitempl", NULL); 449126258Smlaier pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", 450145836Smlaier &pool_allocator_nointr); 451126258Smlaier pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, 452145836Smlaier "pfpooladdrpl", &pool_allocator_nointr); 453126258Smlaier pfr_initialize(); 454130613Smlaier pfi_initialize(); 455126258Smlaier pf_osfp_initialize(); 456126258Smlaier 457130613Smlaier pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp, 458130613Smlaier pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0); 459126258Smlaier 460223637Sbz if (physmem <= atop(100*1024*1024)) 461171168Smlaier pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = 462171168Smlaier PFR_KENTRY_HIWAT_SMALL; 463171168Smlaier 464130613Smlaier RB_INIT(&tree_src_tracking); 465145836Smlaier RB_INIT(&pf_anchors); 466126258Smlaier pf_init_ruleset(&pf_main_ruleset); 467126258Smlaier TAILQ_INIT(&pf_altqs[0]); 468126258Smlaier TAILQ_INIT(&pf_altqs[1]); 469126258Smlaier TAILQ_INIT(&pf_pabuf); 470126258Smlaier pf_altqs_active = &pf_altqs[0]; 471126258Smlaier pf_altqs_inactive = &pf_altqs[1]; 472171168Smlaier TAILQ_INIT(&state_list); 473126258Smlaier 474126258Smlaier /* default rule should never be garbage collected */ 475126258Smlaier pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; 476126258Smlaier pf_default_rule.action = PF_PASS; 477126258Smlaier pf_default_rule.nr = -1; 478171168Smlaier pf_default_rule.rtableid = -1; 479126258Smlaier 480126258Smlaier /* initialize default timeouts */ 481145836Smlaier timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; 482145836Smlaier timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; 483145836Smlaier timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; 484145836Smlaier timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; 485145836Smlaier timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; 486145836Smlaier timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; 487145836Smlaier timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; 488145836Smlaier timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; 489145836Smlaier timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; 490145836Smlaier timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; 491145836Smlaier timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; 492145836Smlaier timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; 493145836Smlaier timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; 494145836Smlaier timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; 495145836Smlaier timeout[PFTM_FRAG] = PFTM_FRAG_VAL; 496145836Smlaier timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; 497145836Smlaier timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; 498145836Smlaier timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; 499171168Smlaier timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; 500171168Smlaier timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; 501126258Smlaier 502126258Smlaier pf_normalize_init(); 503130613Smlaier bzero(&pf_status, sizeof(pf_status)); 504126258Smlaier pf_status.debug = PF_DEBUG_URGENT; 505130613Smlaier 506130613Smlaier /* XXX do our best to avoid a conflict */ 507130613Smlaier pf_status.hostid = arc4random(); 508171168Smlaier 509171168Smlaier /* require process context to purge states, so perform in a thread */ 510223637Sbz kthread_create_deferred(pf_thread_create, NULL); 511126258Smlaier} 512126258Smlaier 513171168Smlaiervoid 514171168Smlaierpf_thread_create(void *v) 515171168Smlaier{ 516223637Sbz if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge")) 517171168Smlaier panic("pfpurge thread"); 518171168Smlaier} 519187689Sed 520187689Sedint 521223637Sbzpfopen(dev_t dev, int flags, int fmt, struct proc *p) 522187689Sed{ 523223637Sbz if (minor(dev) >= 1) 524187689Sed return (ENXIO); 525187689Sed return (0); 526187689Sed} 527187689Sed 528187689Sedint 529223637Sbzpfclose(dev_t dev, int flags, int fmt, struct proc *p) 530187689Sed{ 531223637Sbz if (minor(dev) >= 1) 532187689Sed return (ENXIO); 533187689Sed return (0); 534187689Sed} 535223637Sbz#endif 536126258Smlaier 537126258Smlaierstruct pf_pool * 538145836Smlaierpf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action, 539145836Smlaier u_int32_t rule_number, u_int8_t r_last, u_int8_t active, 540145836Smlaier u_int8_t check_ticket) 541126258Smlaier{ 542126258Smlaier struct pf_ruleset *ruleset; 543126258Smlaier struct pf_rule *rule; 544126258Smlaier int rs_num; 545126258Smlaier 546145836Smlaier ruleset = pf_find_ruleset(anchor); 547126258Smlaier if (ruleset == NULL) 548126258Smlaier return (NULL); 549126258Smlaier rs_num = pf_get_ruleset_number(rule_action); 550126258Smlaier if (rs_num >= PF_RULESET_MAX) 551126258Smlaier return (NULL); 552126258Smlaier if (active) { 553126258Smlaier if (check_ticket && ticket != 554126258Smlaier ruleset->rules[rs_num].active.ticket) 555126258Smlaier return (NULL); 556126258Smlaier if (r_last) 557126258Smlaier rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 558126258Smlaier pf_rulequeue); 559126258Smlaier else 560126258Smlaier rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 561126258Smlaier } else { 562126258Smlaier if (check_ticket && ticket != 563126258Smlaier ruleset->rules[rs_num].inactive.ticket) 564126258Smlaier return (NULL); 565126258Smlaier if (r_last) 566126258Smlaier rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 567126258Smlaier pf_rulequeue); 568126258Smlaier else 569126258Smlaier rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr); 570126258Smlaier } 571126258Smlaier if (!r_last) { 572126258Smlaier while ((rule != NULL) && (rule->nr != rule_number)) 573126258Smlaier rule = TAILQ_NEXT(rule, entries); 574126258Smlaier } 575126258Smlaier if (rule == NULL) 576126258Smlaier return (NULL); 577126258Smlaier 578126258Smlaier return (&rule->rpool); 579126258Smlaier} 580126258Smlaier 581126258Smlaiervoid 582126258Smlaierpf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb) 583126258Smlaier{ 584126258Smlaier struct pf_pooladdr *mv_pool_pa; 585126258Smlaier 586126258Smlaier while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) { 587126258Smlaier TAILQ_REMOVE(poola, mv_pool_pa, entries); 588126258Smlaier TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries); 589126258Smlaier } 590126258Smlaier} 591126258Smlaier 592126258Smlaiervoid 593126258Smlaierpf_empty_pool(struct pf_palist *poola) 594126258Smlaier{ 595126258Smlaier struct pf_pooladdr *empty_pool_pa; 596126258Smlaier 597126258Smlaier while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) { 598130613Smlaier pfi_dynaddr_remove(&empty_pool_pa->addr); 599126258Smlaier pf_tbladdr_remove(&empty_pool_pa->addr); 600171168Smlaier pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE); 601126258Smlaier TAILQ_REMOVE(poola, empty_pool_pa, entries); 602223637Sbz#ifdef __FreeBSD__ 603223637Sbz pool_put(&V_pf_pooladdr_pl, empty_pool_pa); 604223637Sbz#else 605126258Smlaier pool_put(&pf_pooladdr_pl, empty_pool_pa); 606223637Sbz#endif 607126258Smlaier } 608126258Smlaier} 609126258Smlaier 610126258Smlaiervoid 611126258Smlaierpf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) 612126258Smlaier{ 613126258Smlaier if (rulequeue != NULL) { 614223637Sbz if (rule->states_cur <= 0) { 615126258Smlaier /* 616126258Smlaier * XXX - we need to remove the table *before* detaching 617126258Smlaier * the rule to make sure the table code does not delete 618126258Smlaier * the anchor under our feet. 619126258Smlaier */ 620126258Smlaier pf_tbladdr_remove(&rule->src.addr); 621126258Smlaier pf_tbladdr_remove(&rule->dst.addr); 622145836Smlaier if (rule->overload_tbl) 623145836Smlaier pfr_detach_table(rule->overload_tbl); 624126258Smlaier } 625126258Smlaier TAILQ_REMOVE(rulequeue, rule, entries); 626126258Smlaier rule->entries.tqe_prev = NULL; 627126258Smlaier rule->nr = -1; 628126258Smlaier } 629130613Smlaier 630223637Sbz if (rule->states_cur > 0 || rule->src_nodes > 0 || 631130613Smlaier rule->entries.tqe_prev != NULL) 632126258Smlaier return; 633126258Smlaier pf_tag_unref(rule->tag); 634126258Smlaier pf_tag_unref(rule->match_tag); 635130613Smlaier#ifdef ALTQ 636130613Smlaier if (rule->pqid != rule->qid) 637130613Smlaier pf_qid_unref(rule->pqid); 638130613Smlaier pf_qid_unref(rule->qid); 639130613Smlaier#endif 640145836Smlaier pf_rtlabel_remove(&rule->src.addr); 641145836Smlaier pf_rtlabel_remove(&rule->dst.addr); 642130613Smlaier pfi_dynaddr_remove(&rule->src.addr); 643130613Smlaier pfi_dynaddr_remove(&rule->dst.addr); 644126258Smlaier if (rulequeue == NULL) { 645126258Smlaier pf_tbladdr_remove(&rule->src.addr); 646126258Smlaier pf_tbladdr_remove(&rule->dst.addr); 647145836Smlaier if (rule->overload_tbl) 648145836Smlaier pfr_detach_table(rule->overload_tbl); 649126258Smlaier } 650171168Smlaier pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE); 651145836Smlaier pf_anchor_remove(rule); 652126258Smlaier pf_empty_pool(&rule->rpool.list); 653223637Sbz#ifdef __FreeBSD__ 654223637Sbz pool_put(&V_pf_rule_pl, rule); 655223637Sbz#else 656126258Smlaier pool_put(&pf_rule_pl, rule); 657223637Sbz#endif 658126258Smlaier} 659126258Smlaier 660171168Smlaieru_int16_t 661130613Smlaiertagname2tag(struct pf_tags *head, char *tagname) 662126258Smlaier{ 663126258Smlaier struct pf_tagname *tag, *p = NULL; 664126258Smlaier u_int16_t new_tagid = 1; 665126258Smlaier 666130613Smlaier TAILQ_FOREACH(tag, head, entries) 667126258Smlaier if (strcmp(tagname, tag->name) == 0) { 668126258Smlaier tag->ref++; 669126258Smlaier return (tag->tag); 670126258Smlaier } 671126258Smlaier 672126258Smlaier /* 673126258Smlaier * to avoid fragmentation, we do a linear search from the beginning 674126258Smlaier * and take the first free slot we find. if there is none or the list 675126258Smlaier * is empty, append a new entry at the end. 676126258Smlaier */ 677126258Smlaier 678126258Smlaier /* new entry */ 679130613Smlaier if (!TAILQ_EMPTY(head)) 680130613Smlaier for (p = TAILQ_FIRST(head); p != NULL && 681126258Smlaier p->tag == new_tagid; p = TAILQ_NEXT(p, entries)) 682126258Smlaier new_tagid = p->tag + 1; 683126258Smlaier 684126258Smlaier if (new_tagid > TAGID_MAX) 685126258Smlaier return (0); 686126258Smlaier 687126258Smlaier /* allocate and fill new struct pf_tagname */ 688223637Sbz tag = malloc(sizeof(*tag), M_TEMP, M_NOWAIT|M_ZERO); 689126258Smlaier if (tag == NULL) 690126258Smlaier return (0); 691126258Smlaier strlcpy(tag->name, tagname, sizeof(tag->name)); 692126258Smlaier tag->tag = new_tagid; 693126258Smlaier tag->ref++; 694126258Smlaier 695126258Smlaier if (p != NULL) /* insert new entry before p */ 696126258Smlaier TAILQ_INSERT_BEFORE(p, tag, entries); 697126258Smlaier else /* either list empty or no free slot in between */ 698130613Smlaier TAILQ_INSERT_TAIL(head, tag, entries); 699126258Smlaier 700126258Smlaier return (tag->tag); 701126258Smlaier} 702126258Smlaier 703171168Smlaiervoid 704130613Smlaiertag2tagname(struct pf_tags *head, u_int16_t tagid, char *p) 705126258Smlaier{ 706126258Smlaier struct pf_tagname *tag; 707126258Smlaier 708130613Smlaier TAILQ_FOREACH(tag, head, entries) 709126258Smlaier if (tag->tag == tagid) { 710126258Smlaier strlcpy(p, tag->name, PF_TAG_NAME_SIZE); 711126258Smlaier return; 712126258Smlaier } 713126258Smlaier} 714126258Smlaier 715171168Smlaiervoid 716130613Smlaiertag_unref(struct pf_tags *head, u_int16_t tag) 717126258Smlaier{ 718126258Smlaier struct pf_tagname *p, *next; 719126258Smlaier 720126258Smlaier if (tag == 0) 721126258Smlaier return; 722126258Smlaier 723130613Smlaier for (p = TAILQ_FIRST(head); p != NULL; p = next) { 724126258Smlaier next = TAILQ_NEXT(p, entries); 725126258Smlaier if (tag == p->tag) { 726126258Smlaier if (--p->ref == 0) { 727130613Smlaier TAILQ_REMOVE(head, p, entries); 728126258Smlaier free(p, M_TEMP); 729126258Smlaier } 730126258Smlaier break; 731126258Smlaier } 732126258Smlaier } 733126258Smlaier} 734126258Smlaier 735130613Smlaieru_int16_t 736130613Smlaierpf_tagname2tag(char *tagname) 737130613Smlaier{ 738223637Sbz#ifdef __FreeBSD__ 739223637Sbz return (tagname2tag(&V_pf_tags, tagname)); 740223637Sbz#else 741130613Smlaier return (tagname2tag(&pf_tags, tagname)); 742223637Sbz#endif 743130613Smlaier} 744130613Smlaier 745130613Smlaiervoid 746130613Smlaierpf_tag2tagname(u_int16_t tagid, char *p) 747130613Smlaier{ 748223637Sbz#ifdef __FreeBSD__ 749223637Sbz tag2tagname(&V_pf_tags, tagid, p); 750223637Sbz#else 751171168Smlaier tag2tagname(&pf_tags, tagid, p); 752223637Sbz#endif 753130613Smlaier} 754130613Smlaier 755130613Smlaiervoid 756145836Smlaierpf_tag_ref(u_int16_t tag) 757145836Smlaier{ 758145836Smlaier struct pf_tagname *t; 759145836Smlaier 760223637Sbz#ifdef __FreeBSD__ 761223637Sbz TAILQ_FOREACH(t, &V_pf_tags, entries) 762223637Sbz#else 763145836Smlaier TAILQ_FOREACH(t, &pf_tags, entries) 764223637Sbz#endif 765145836Smlaier if (t->tag == tag) 766145836Smlaier break; 767145836Smlaier if (t != NULL) 768145836Smlaier t->ref++; 769145836Smlaier} 770145836Smlaier 771145836Smlaiervoid 772130613Smlaierpf_tag_unref(u_int16_t tag) 773130613Smlaier{ 774223637Sbz#ifdef __FreeBSD__ 775223637Sbz tag_unref(&V_pf_tags, tag); 776223637Sbz#else 777171168Smlaier tag_unref(&pf_tags, tag); 778223637Sbz#endif 779130613Smlaier} 780130613Smlaier 781145836Smlaierint 782145836Smlaierpf_rtlabel_add(struct pf_addr_wrap *a) 783145836Smlaier{ 784145836Smlaier#ifdef __FreeBSD__ 785145836Smlaier /* XXX_IMPORT: later */ 786145836Smlaier return (0); 787145836Smlaier#else 788145836Smlaier if (a->type == PF_ADDR_RTLABEL && 789145836Smlaier (a->v.rtlabel = rtlabel_name2id(a->v.rtlabelname)) == 0) 790145836Smlaier return (-1); 791145836Smlaier return (0); 792145836Smlaier#endif 793145836Smlaier} 794145836Smlaier 795145836Smlaiervoid 796145836Smlaierpf_rtlabel_remove(struct pf_addr_wrap *a) 797145836Smlaier{ 798145836Smlaier#ifdef __FreeBSD__ 799145836Smlaier /* XXX_IMPORT: later */ 800145836Smlaier#else 801145836Smlaier if (a->type == PF_ADDR_RTLABEL) 802145836Smlaier rtlabel_unref(a->v.rtlabel); 803145836Smlaier#endif 804145836Smlaier} 805145836Smlaier 806145836Smlaiervoid 807145836Smlaierpf_rtlabel_copyout(struct pf_addr_wrap *a) 808145836Smlaier{ 809145836Smlaier#ifdef __FreeBSD__ 810145836Smlaier /* XXX_IMPORT: later */ 811145836Smlaier if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) 812145836Smlaier strlcpy(a->v.rtlabelname, "?", sizeof(a->v.rtlabelname)); 813145836Smlaier#else 814145836Smlaier const char *name; 815145836Smlaier 816145836Smlaier if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) { 817145836Smlaier if ((name = rtlabel_id2name(a->v.rtlabel)) == NULL) 818145836Smlaier strlcpy(a->v.rtlabelname, "?", 819145836Smlaier sizeof(a->v.rtlabelname)); 820145836Smlaier else 821145836Smlaier strlcpy(a->v.rtlabelname, name, 822145836Smlaier sizeof(a->v.rtlabelname)); 823145836Smlaier } 824145836Smlaier#endif 825145836Smlaier} 826145836Smlaier 827130613Smlaier#ifdef ALTQ 828130613Smlaieru_int32_t 829130613Smlaierpf_qname2qid(char *qname) 830130613Smlaier{ 831223637Sbz#ifdef __FreeBSD__ 832223637Sbz return ((u_int32_t)tagname2tag(&V_pf_qids, qname)); 833223637Sbz#else 834130613Smlaier return ((u_int32_t)tagname2tag(&pf_qids, qname)); 835223637Sbz#endif 836130613Smlaier} 837130613Smlaier 838130613Smlaiervoid 839130613Smlaierpf_qid2qname(u_int32_t qid, char *p) 840130613Smlaier{ 841223637Sbz#ifdef __FreeBSD__ 842223637Sbz tag2tagname(&V_pf_qids, (u_int16_t)qid, p); 843223637Sbz#else 844171168Smlaier tag2tagname(&pf_qids, (u_int16_t)qid, p); 845223637Sbz#endif 846130613Smlaier} 847130613Smlaier 848130613Smlaiervoid 849130613Smlaierpf_qid_unref(u_int32_t qid) 850130613Smlaier{ 851223637Sbz#ifdef __FreeBSD__ 852223637Sbz tag_unref(&V_pf_qids, (u_int16_t)qid); 853223637Sbz#else 854171168Smlaier tag_unref(&pf_qids, (u_int16_t)qid); 855223637Sbz#endif 856130613Smlaier} 857130613Smlaier 858130613Smlaierint 859130613Smlaierpf_begin_altq(u_int32_t *ticket) 860130613Smlaier{ 861130613Smlaier struct pf_altq *altq; 862130613Smlaier int error = 0; 863130613Smlaier 864130613Smlaier /* Purge the old altq list */ 865177700Smlaier#ifdef __FreeBSD__ 866223637Sbz while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) { 867223637Sbz TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries); 868177700Smlaier if (altq->qname[0] == 0 && 869177700Smlaier (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 870177700Smlaier#else 871223637Sbz while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 872223637Sbz TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 873130613Smlaier if (altq->qname[0] == 0) { 874177700Smlaier#endif 875130613Smlaier /* detach and destroy the discipline */ 876130613Smlaier error = altq_remove(altq); 877130613Smlaier } else 878130613Smlaier pf_qid_unref(altq->qid); 879223637Sbz#ifdef __FreeBSD__ 880223637Sbz pool_put(&V_pf_altq_pl, altq); 881223637Sbz#else 882130613Smlaier pool_put(&pf_altq_pl, altq); 883223637Sbz#endif 884130613Smlaier } 885130613Smlaier if (error) 886130613Smlaier return (error); 887223637Sbz#ifdef __FreeBSD__ 888223637Sbz *ticket = ++V_ticket_altqs_inactive; 889223637Sbz V_altqs_inactive_open = 1; 890223637Sbz#else 891130613Smlaier *ticket = ++ticket_altqs_inactive; 892130613Smlaier altqs_inactive_open = 1; 893223637Sbz#endif 894130613Smlaier return (0); 895130613Smlaier} 896130613Smlaier 897130613Smlaierint 898130613Smlaierpf_rollback_altq(u_int32_t ticket) 899130613Smlaier{ 900130613Smlaier struct pf_altq *altq; 901130613Smlaier int error = 0; 902130613Smlaier 903223637Sbz#ifdef __FreeBSD__ 904223637Sbz if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive) 905223637Sbz return (0); 906223637Sbz /* Purge the old altq list */ 907223637Sbz while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) { 908223637Sbz TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries); 909223637Sbz if (altq->qname[0] == 0 && 910223637Sbz (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 911223637Sbz#else 912130613Smlaier if (!altqs_inactive_open || ticket != ticket_altqs_inactive) 913130613Smlaier return (0); 914130613Smlaier /* Purge the old altq list */ 915130613Smlaier while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 916130613Smlaier TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 917130613Smlaier if (altq->qname[0] == 0) { 918177700Smlaier#endif 919130613Smlaier /* detach and destroy the discipline */ 920130613Smlaier error = altq_remove(altq); 921130613Smlaier } else 922130613Smlaier pf_qid_unref(altq->qid); 923223637Sbz#ifdef __FreeBSD__ 924223637Sbz pool_put(&V_pf_altq_pl, altq); 925223637Sbz#else 926130613Smlaier pool_put(&pf_altq_pl, altq); 927223637Sbz#endif 928130613Smlaier } 929223637Sbz#ifdef __FreeBSD__ 930223637Sbz V_altqs_inactive_open = 0; 931223637Sbz#else 932130613Smlaier altqs_inactive_open = 0; 933223637Sbz#endif 934130613Smlaier return (error); 935130613Smlaier} 936130613Smlaier 937130613Smlaierint 938130613Smlaierpf_commit_altq(u_int32_t ticket) 939130613Smlaier{ 940130613Smlaier struct pf_altqqueue *old_altqs; 941130613Smlaier struct pf_altq *altq; 942130613Smlaier int s, err, error = 0; 943130613Smlaier 944223637Sbz#ifdef __FreeBSD__ 945223637Sbz if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive) 946223637Sbz#else 947130613Smlaier if (!altqs_inactive_open || ticket != ticket_altqs_inactive) 948223637Sbz#endif 949130613Smlaier return (EBUSY); 950130613Smlaier 951130613Smlaier /* swap altqs, keep the old. */ 952130613Smlaier s = splsoftnet(); 953223637Sbz#ifdef __FreeBSD__ 954223637Sbz old_altqs = V_pf_altqs_active; 955223637Sbz V_pf_altqs_active = V_pf_altqs_inactive; 956223637Sbz V_pf_altqs_inactive = old_altqs; 957223637Sbz V_ticket_altqs_active = V_ticket_altqs_inactive; 958223637Sbz#else 959130613Smlaier old_altqs = pf_altqs_active; 960130613Smlaier pf_altqs_active = pf_altqs_inactive; 961130613Smlaier pf_altqs_inactive = old_altqs; 962130613Smlaier ticket_altqs_active = ticket_altqs_inactive; 963223637Sbz#endif 964130613Smlaier 965130613Smlaier /* Attach new disciplines */ 966177700Smlaier#ifdef __FreeBSD__ 967223637Sbz TAILQ_FOREACH(altq, V_pf_altqs_active, entries) { 968223637Sbz if (altq->qname[0] == 0 && 969223637Sbz (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 970177700Smlaier#else 971223637Sbz TAILQ_FOREACH(altq, pf_altqs_active, entries) { 972130613Smlaier if (altq->qname[0] == 0) { 973177700Smlaier#endif 974130613Smlaier /* attach the discipline */ 975130613Smlaier error = altq_pfattach(altq); 976223637Sbz#ifdef __FreeBSD__ 977223637Sbz if (error == 0 && V_pf_altq_running) 978223637Sbz#else 979135352Smlaier if (error == 0 && pf_altq_running) 980223637Sbz#endif 981135352Smlaier error = pf_enable_altq(altq); 982135352Smlaier if (error != 0) { 983130613Smlaier splx(s); 984130613Smlaier return (error); 985130613Smlaier } 986130613Smlaier } 987130613Smlaier } 988130613Smlaier 989130613Smlaier /* Purge the old altq list */ 990177700Smlaier#ifdef __FreeBSD__ 991223637Sbz while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) { 992223637Sbz TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries); 993177700Smlaier if (altq->qname[0] == 0 && 994177700Smlaier (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 995177700Smlaier#else 996223637Sbz while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 997223637Sbz TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 998130613Smlaier if (altq->qname[0] == 0) { 999177700Smlaier#endif 1000130613Smlaier /* detach and destroy the discipline */ 1001223637Sbz#ifdef __FreeBSD__ 1002223637Sbz if (V_pf_altq_running) 1003223637Sbz#else 1004135352Smlaier if (pf_altq_running) 1005223637Sbz#endif 1006135352Smlaier error = pf_disable_altq(altq); 1007130613Smlaier err = altq_pfdetach(altq); 1008130613Smlaier if (err != 0 && error == 0) 1009130613Smlaier error = err; 1010130613Smlaier err = altq_remove(altq); 1011130613Smlaier if (err != 0 && error == 0) 1012130613Smlaier error = err; 1013130613Smlaier } else 1014130613Smlaier pf_qid_unref(altq->qid); 1015223637Sbz#ifdef __FreeBSD__ 1016223637Sbz pool_put(&V_pf_altq_pl, altq); 1017223637Sbz#else 1018130613Smlaier pool_put(&pf_altq_pl, altq); 1019223637Sbz#endif 1020130613Smlaier } 1021130613Smlaier splx(s); 1022130613Smlaier 1023223637Sbz#ifdef __FreeBSD__ 1024223637Sbz V_altqs_inactive_open = 0; 1025223637Sbz#else 1026130613Smlaier altqs_inactive_open = 0; 1027223637Sbz#endif 1028130613Smlaier return (error); 1029130613Smlaier} 1030135352Smlaier 1031135352Smlaierint 1032135352Smlaierpf_enable_altq(struct pf_altq *altq) 1033135352Smlaier{ 1034135352Smlaier struct ifnet *ifp; 1035135352Smlaier struct tb_profile tb; 1036135352Smlaier int s, error = 0; 1037135352Smlaier 1038135352Smlaier if ((ifp = ifunit(altq->ifname)) == NULL) 1039135352Smlaier return (EINVAL); 1040135352Smlaier 1041135352Smlaier if (ifp->if_snd.altq_type != ALTQT_NONE) 1042135352Smlaier error = altq_enable(&ifp->if_snd); 1043135352Smlaier 1044135352Smlaier /* set tokenbucket regulator */ 1045135352Smlaier if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { 1046135352Smlaier tb.rate = altq->ifbandwidth; 1047135352Smlaier tb.depth = altq->tbrsize; 1048171168Smlaier s = splnet(); 1049135352Smlaier#ifdef __FreeBSD__ 1050135352Smlaier PF_UNLOCK(); 1051135352Smlaier#endif 1052135352Smlaier error = tbr_set(&ifp->if_snd, &tb); 1053135352Smlaier#ifdef __FreeBSD__ 1054135352Smlaier PF_LOCK(); 1055145836Smlaier#endif 1056135352Smlaier splx(s); 1057135352Smlaier } 1058135352Smlaier 1059135352Smlaier return (error); 1060135352Smlaier} 1061135352Smlaier 1062135352Smlaierint 1063135352Smlaierpf_disable_altq(struct pf_altq *altq) 1064135352Smlaier{ 1065135352Smlaier struct ifnet *ifp; 1066135352Smlaier struct tb_profile tb; 1067135352Smlaier int s, error; 1068135352Smlaier 1069135352Smlaier if ((ifp = ifunit(altq->ifname)) == NULL) 1070135352Smlaier return (EINVAL); 1071135352Smlaier 1072135352Smlaier /* 1073135352Smlaier * when the discipline is no longer referenced, it was overridden 1074135352Smlaier * by a new one. if so, just return. 1075135352Smlaier */ 1076135352Smlaier if (altq->altq_disc != ifp->if_snd.altq_disc) 1077135352Smlaier return (0); 1078135352Smlaier 1079135352Smlaier error = altq_disable(&ifp->if_snd); 1080135352Smlaier 1081135352Smlaier if (error == 0) { 1082135352Smlaier /* clear tokenbucket regulator */ 1083135352Smlaier tb.rate = 0; 1084171168Smlaier s = splnet(); 1085135352Smlaier#ifdef __FreeBSD__ 1086135352Smlaier PF_UNLOCK(); 1087135352Smlaier#endif 1088135352Smlaier error = tbr_set(&ifp->if_snd, &tb); 1089135352Smlaier#ifdef __FreeBSD__ 1090135352Smlaier PF_LOCK(); 1091135352Smlaier#endif 1092135352Smlaier splx(s); 1093135352Smlaier } 1094135352Smlaier 1095135352Smlaier return (error); 1096135352Smlaier} 1097177700Smlaier 1098177700Smlaier#ifdef __FreeBSD__ 1099177700Smlaiervoid 1100177700Smlaierpf_altq_ifnet_event(struct ifnet *ifp, int remove) 1101177700Smlaier{ 1102223637Sbz struct ifnet *ifp1; 1103223637Sbz struct pf_altq *a1, *a2, *a3; 1104223637Sbz u_int32_t ticket; 1105223637Sbz int error = 0; 1106177700Smlaier 1107177700Smlaier /* Interrupt userland queue modifications */ 1108223637Sbz#ifdef __FreeBSD__ 1109223637Sbz if (V_altqs_inactive_open) 1110223637Sbz pf_rollback_altq(V_ticket_altqs_inactive); 1111223637Sbz#else 1112177700Smlaier if (altqs_inactive_open) 1113177700Smlaier pf_rollback_altq(ticket_altqs_inactive); 1114223637Sbz#endif 1115177700Smlaier 1116177700Smlaier /* Start new altq ruleset */ 1117177700Smlaier if (pf_begin_altq(&ticket)) 1118177700Smlaier return; 1119177700Smlaier 1120177700Smlaier /* Copy the current active set */ 1121223637Sbz#ifdef __FreeBSD__ 1122223637Sbz TAILQ_FOREACH(a1, V_pf_altqs_active, entries) { 1123223637Sbz a2 = pool_get(&V_pf_altq_pl, PR_NOWAIT); 1124223637Sbz#else 1125177700Smlaier TAILQ_FOREACH(a1, pf_altqs_active, entries) { 1126177700Smlaier a2 = pool_get(&pf_altq_pl, PR_NOWAIT); 1127223637Sbz#endif 1128177700Smlaier if (a2 == NULL) { 1129177700Smlaier error = ENOMEM; 1130177700Smlaier break; 1131177700Smlaier } 1132177700Smlaier bcopy(a1, a2, sizeof(struct pf_altq)); 1133177700Smlaier 1134177700Smlaier if (a2->qname[0] != 0) { 1135177700Smlaier if ((a2->qid = pf_qname2qid(a2->qname)) == 0) { 1136177700Smlaier error = EBUSY; 1137223637Sbz#ifdef __FreeBSD__ 1138223637Sbz pool_put(&V_pf_altq_pl, a2); 1139223637Sbz#else 1140177700Smlaier pool_put(&pf_altq_pl, a2); 1141223637Sbz#endif 1142177700Smlaier break; 1143177700Smlaier } 1144177700Smlaier a2->altq_disc = NULL; 1145223637Sbz#ifdef __FreeBSD__ 1146223637Sbz TAILQ_FOREACH(a3, V_pf_altqs_inactive, entries) { 1147223637Sbz#else 1148177700Smlaier TAILQ_FOREACH(a3, pf_altqs_inactive, entries) { 1149223637Sbz#endif 1150177700Smlaier if (strncmp(a3->ifname, a2->ifname, 1151177700Smlaier IFNAMSIZ) == 0 && a3->qname[0] == 0) { 1152177700Smlaier a2->altq_disc = a3->altq_disc; 1153177700Smlaier break; 1154177700Smlaier } 1155177700Smlaier } 1156177700Smlaier } 1157177700Smlaier /* Deactivate the interface in question */ 1158177700Smlaier a2->local_flags &= ~PFALTQ_FLAG_IF_REMOVED; 1159177700Smlaier if ((ifp1 = ifunit(a2->ifname)) == NULL || 1160177700Smlaier (remove && ifp1 == ifp)) { 1161177700Smlaier a2->local_flags |= PFALTQ_FLAG_IF_REMOVED; 1162177700Smlaier } else { 1163177700Smlaier PF_UNLOCK(); 1164177700Smlaier error = altq_add(a2); 1165177700Smlaier PF_LOCK(); 1166177700Smlaier 1167223637Sbz#ifdef __FreeBSD__ 1168223637Sbz if (ticket != V_ticket_altqs_inactive) 1169223637Sbz#else 1170177700Smlaier if (ticket != ticket_altqs_inactive) 1171223637Sbz#endif 1172177700Smlaier error = EBUSY; 1173177700Smlaier 1174177700Smlaier if (error) { 1175223637Sbz#ifdef __FreeBSD__ 1176223637Sbz pool_put(&V_pf_altq_pl, a2); 1177223637Sbz#else 1178177700Smlaier pool_put(&pf_altq_pl, a2); 1179223637Sbz#endif 1180177700Smlaier break; 1181177700Smlaier } 1182177700Smlaier } 1183177700Smlaier 1184223637Sbz#ifdef __FreeBSD__ 1185223637Sbz TAILQ_INSERT_TAIL(V_pf_altqs_inactive, a2, entries); 1186223637Sbz#else 1187177700Smlaier TAILQ_INSERT_TAIL(pf_altqs_inactive, a2, entries); 1188223637Sbz#endif 1189177700Smlaier } 1190177700Smlaier 1191177700Smlaier if (error != 0) 1192177700Smlaier pf_rollback_altq(ticket); 1193177700Smlaier else 1194177700Smlaier pf_commit_altq(ticket); 1195223637Sbz } 1196177700Smlaier#endif 1197130613Smlaier#endif /* ALTQ */ 1198130613Smlaier 1199130613Smlaierint 1200145836Smlaierpf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor) 1201130613Smlaier{ 1202130613Smlaier struct pf_ruleset *rs; 1203130613Smlaier struct pf_rule *rule; 1204130613Smlaier 1205130613Smlaier if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 1206130613Smlaier return (EINVAL); 1207145836Smlaier rs = pf_find_or_create_ruleset(anchor); 1208130613Smlaier if (rs == NULL) 1209130613Smlaier return (EINVAL); 1210171168Smlaier while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) { 1211130613Smlaier pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); 1212171168Smlaier rs->rules[rs_num].inactive.rcount--; 1213171168Smlaier } 1214130613Smlaier *ticket = ++rs->rules[rs_num].inactive.ticket; 1215130613Smlaier rs->rules[rs_num].inactive.open = 1; 1216130613Smlaier return (0); 1217130613Smlaier} 1218130613Smlaier 1219130613Smlaierint 1220145836Smlaierpf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor) 1221130613Smlaier{ 1222130613Smlaier struct pf_ruleset *rs; 1223130613Smlaier struct pf_rule *rule; 1224130613Smlaier 1225130613Smlaier if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 1226130613Smlaier return (EINVAL); 1227145836Smlaier rs = pf_find_ruleset(anchor); 1228130613Smlaier if (rs == NULL || !rs->rules[rs_num].inactive.open || 1229130613Smlaier rs->rules[rs_num].inactive.ticket != ticket) 1230130613Smlaier return (0); 1231171168Smlaier while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) { 1232130613Smlaier pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); 1233171168Smlaier rs->rules[rs_num].inactive.rcount--; 1234171168Smlaier } 1235130613Smlaier rs->rules[rs_num].inactive.open = 0; 1236130613Smlaier return (0); 1237130613Smlaier} 1238130613Smlaier 1239171168Smlaier#define PF_MD5_UPD(st, elm) \ 1240171168Smlaier MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm)) 1241171168Smlaier 1242171168Smlaier#define PF_MD5_UPD_STR(st, elm) \ 1243171168Smlaier MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm)) 1244171168Smlaier 1245171168Smlaier#define PF_MD5_UPD_HTONL(st, elm, stor) do { \ 1246171168Smlaier (stor) = htonl((st)->elm); \ 1247171168Smlaier MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\ 1248171168Smlaier} while (0) 1249171168Smlaier 1250171168Smlaier#define PF_MD5_UPD_HTONS(st, elm, stor) do { \ 1251171168Smlaier (stor) = htons((st)->elm); \ 1252171168Smlaier MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\ 1253171168Smlaier} while (0) 1254171168Smlaier 1255171168Smlaiervoid 1256171168Smlaierpf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr) 1257171168Smlaier{ 1258171168Smlaier PF_MD5_UPD(pfr, addr.type); 1259171168Smlaier switch (pfr->addr.type) { 1260171168Smlaier case PF_ADDR_DYNIFTL: 1261171168Smlaier PF_MD5_UPD(pfr, addr.v.ifname); 1262171168Smlaier PF_MD5_UPD(pfr, addr.iflags); 1263171168Smlaier break; 1264171168Smlaier case PF_ADDR_TABLE: 1265171168Smlaier PF_MD5_UPD(pfr, addr.v.tblname); 1266171168Smlaier break; 1267171168Smlaier case PF_ADDR_ADDRMASK: 1268171168Smlaier /* XXX ignore af? */ 1269171168Smlaier PF_MD5_UPD(pfr, addr.v.a.addr.addr32); 1270171168Smlaier PF_MD5_UPD(pfr, addr.v.a.mask.addr32); 1271171168Smlaier break; 1272171168Smlaier case PF_ADDR_RTLABEL: 1273171168Smlaier PF_MD5_UPD(pfr, addr.v.rtlabelname); 1274171168Smlaier break; 1275171168Smlaier } 1276171168Smlaier 1277171168Smlaier PF_MD5_UPD(pfr, port[0]); 1278171168Smlaier PF_MD5_UPD(pfr, port[1]); 1279171168Smlaier PF_MD5_UPD(pfr, neg); 1280171168Smlaier PF_MD5_UPD(pfr, port_op); 1281171168Smlaier} 1282171168Smlaier 1283171168Smlaiervoid 1284171168Smlaierpf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule) 1285171168Smlaier{ 1286171168Smlaier u_int16_t x; 1287171168Smlaier u_int32_t y; 1288171168Smlaier 1289171168Smlaier pf_hash_rule_addr(ctx, &rule->src); 1290171168Smlaier pf_hash_rule_addr(ctx, &rule->dst); 1291171168Smlaier PF_MD5_UPD_STR(rule, label); 1292171168Smlaier PF_MD5_UPD_STR(rule, ifname); 1293171168Smlaier PF_MD5_UPD_STR(rule, match_tagname); 1294171168Smlaier PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */ 1295171168Smlaier PF_MD5_UPD_HTONL(rule, os_fingerprint, y); 1296171168Smlaier PF_MD5_UPD_HTONL(rule, prob, y); 1297171168Smlaier PF_MD5_UPD_HTONL(rule, uid.uid[0], y); 1298171168Smlaier PF_MD5_UPD_HTONL(rule, uid.uid[1], y); 1299171168Smlaier PF_MD5_UPD(rule, uid.op); 1300171168Smlaier PF_MD5_UPD_HTONL(rule, gid.gid[0], y); 1301171168Smlaier PF_MD5_UPD_HTONL(rule, gid.gid[1], y); 1302171168Smlaier PF_MD5_UPD(rule, gid.op); 1303171168Smlaier PF_MD5_UPD_HTONL(rule, rule_flag, y); 1304171168Smlaier PF_MD5_UPD(rule, action); 1305171168Smlaier PF_MD5_UPD(rule, direction); 1306171168Smlaier PF_MD5_UPD(rule, af); 1307171168Smlaier PF_MD5_UPD(rule, quick); 1308171168Smlaier PF_MD5_UPD(rule, ifnot); 1309171168Smlaier PF_MD5_UPD(rule, match_tag_not); 1310171168Smlaier PF_MD5_UPD(rule, natpass); 1311171168Smlaier PF_MD5_UPD(rule, keep_state); 1312171168Smlaier PF_MD5_UPD(rule, proto); 1313171168Smlaier PF_MD5_UPD(rule, type); 1314171168Smlaier PF_MD5_UPD(rule, code); 1315171168Smlaier PF_MD5_UPD(rule, flags); 1316171168Smlaier PF_MD5_UPD(rule, flagset); 1317171168Smlaier PF_MD5_UPD(rule, allow_opts); 1318171168Smlaier PF_MD5_UPD(rule, rt); 1319171168Smlaier PF_MD5_UPD(rule, tos); 1320171168Smlaier} 1321171168Smlaier 1322130613Smlaierint 1323145836Smlaierpf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) 1324130613Smlaier{ 1325130613Smlaier struct pf_ruleset *rs; 1326171168Smlaier struct pf_rule *rule, **old_array; 1327130613Smlaier struct pf_rulequeue *old_rules; 1328171168Smlaier int s, error; 1329171168Smlaier u_int32_t old_rcount; 1330130613Smlaier 1331130613Smlaier if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 1332130613Smlaier return (EINVAL); 1333145836Smlaier rs = pf_find_ruleset(anchor); 1334130613Smlaier if (rs == NULL || !rs->rules[rs_num].inactive.open || 1335130613Smlaier ticket != rs->rules[rs_num].inactive.ticket) 1336130613Smlaier return (EBUSY); 1337130613Smlaier 1338171168Smlaier /* Calculate checksum for the main ruleset */ 1339171168Smlaier if (rs == &pf_main_ruleset) { 1340171168Smlaier error = pf_setup_pfsync_matching(rs); 1341171168Smlaier if (error != 0) 1342171168Smlaier return (error); 1343171168Smlaier } 1344171168Smlaier 1345130613Smlaier /* Swap rules, keep the old. */ 1346130613Smlaier s = splsoftnet(); 1347130613Smlaier old_rules = rs->rules[rs_num].active.ptr; 1348171168Smlaier old_rcount = rs->rules[rs_num].active.rcount; 1349171168Smlaier old_array = rs->rules[rs_num].active.ptr_array; 1350171168Smlaier 1351130613Smlaier rs->rules[rs_num].active.ptr = 1352130613Smlaier rs->rules[rs_num].inactive.ptr; 1353171168Smlaier rs->rules[rs_num].active.ptr_array = 1354171168Smlaier rs->rules[rs_num].inactive.ptr_array; 1355171168Smlaier rs->rules[rs_num].active.rcount = 1356171168Smlaier rs->rules[rs_num].inactive.rcount; 1357130613Smlaier rs->rules[rs_num].inactive.ptr = old_rules; 1358171168Smlaier rs->rules[rs_num].inactive.ptr_array = old_array; 1359171168Smlaier rs->rules[rs_num].inactive.rcount = old_rcount; 1360171168Smlaier 1361130613Smlaier rs->rules[rs_num].active.ticket = 1362130613Smlaier rs->rules[rs_num].inactive.ticket; 1363130613Smlaier pf_calc_skip_steps(rs->rules[rs_num].active.ptr); 1364130613Smlaier 1365171168Smlaier 1366130613Smlaier /* Purge the old rule list. */ 1367130613Smlaier while ((rule = TAILQ_FIRST(old_rules)) != NULL) 1368130613Smlaier pf_rm_rule(old_rules, rule); 1369171168Smlaier if (rs->rules[rs_num].inactive.ptr_array) 1370171168Smlaier free(rs->rules[rs_num].inactive.ptr_array, M_TEMP); 1371171168Smlaier rs->rules[rs_num].inactive.ptr_array = NULL; 1372171168Smlaier rs->rules[rs_num].inactive.rcount = 0; 1373130613Smlaier rs->rules[rs_num].inactive.open = 0; 1374130613Smlaier pf_remove_if_empty_ruleset(rs); 1375130613Smlaier splx(s); 1376130613Smlaier return (0); 1377130613Smlaier} 1378130613Smlaier 1379171168Smlaierint 1380171168Smlaierpf_setup_pfsync_matching(struct pf_ruleset *rs) 1381171168Smlaier{ 1382171168Smlaier MD5_CTX ctx; 1383171168Smlaier struct pf_rule *rule; 1384171168Smlaier int rs_cnt; 1385171168Smlaier u_int8_t digest[PF_MD5_DIGEST_LENGTH]; 1386171168Smlaier 1387171168Smlaier MD5Init(&ctx); 1388171168Smlaier for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) { 1389171168Smlaier /* XXX PF_RULESET_SCRUB as well? */ 1390171168Smlaier if (rs_cnt == PF_RULESET_SCRUB) 1391171168Smlaier continue; 1392171168Smlaier 1393171168Smlaier if (rs->rules[rs_cnt].inactive.ptr_array) 1394171168Smlaier free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP); 1395171168Smlaier rs->rules[rs_cnt].inactive.ptr_array = NULL; 1396171168Smlaier 1397171168Smlaier if (rs->rules[rs_cnt].inactive.rcount) { 1398171168Smlaier rs->rules[rs_cnt].inactive.ptr_array = 1399171168Smlaier malloc(sizeof(caddr_t) * 1400171168Smlaier rs->rules[rs_cnt].inactive.rcount, 1401171168Smlaier M_TEMP, M_NOWAIT); 1402171168Smlaier 1403171168Smlaier if (!rs->rules[rs_cnt].inactive.ptr_array) 1404171168Smlaier return (ENOMEM); 1405171168Smlaier } 1406171168Smlaier 1407171168Smlaier TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr, 1408171168Smlaier entries) { 1409171168Smlaier pf_hash_rule(&ctx, rule); 1410171168Smlaier (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule; 1411171168Smlaier } 1412171168Smlaier } 1413171168Smlaier 1414171168Smlaier MD5Final(digest, &ctx); 1415223637Sbz#ifdef __FreeBSD__ 1416223637Sbz memcpy(V_pf_status.pf_chksum, digest, sizeof(V_pf_status.pf_chksum)); 1417223637Sbz#else 1418171168Smlaier memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum)); 1419223637Sbz#endif 1420171168Smlaier return (0); 1421171168Smlaier} 1422171168Smlaier 1423171168Smlaierint 1424223637Sbzpf_addr_setup(struct pf_ruleset *ruleset, struct pf_addr_wrap *addr, 1425223637Sbz sa_family_t af) 1426223637Sbz{ 1427223637Sbz if (pfi_dynaddr_setup(addr, af) || 1428223637Sbz pf_tbladdr_setup(ruleset, addr)) 1429223637Sbz return (EINVAL); 1430223637Sbz 1431223637Sbz return (0); 1432223637Sbz} 1433223637Sbz 1434223637Sbzvoid 1435223637Sbzpf_addr_copyout(struct pf_addr_wrap *addr) 1436223637Sbz{ 1437223637Sbz pfi_dynaddr_copyout(addr); 1438223637Sbz pf_tbladdr_copyout(addr); 1439223637Sbz pf_rtlabel_copyout(addr); 1440223637Sbz} 1441223637Sbz 1442223637Sbzint 1443127145Smlaier#ifdef __FreeBSD__ 1444130585Sphkpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 1445126261Smlaier#else 1446171168Smlaierpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 1447126261Smlaier#endif 1448126258Smlaier{ 1449126258Smlaier struct pf_pooladdr *pa = NULL; 1450126258Smlaier struct pf_pool *pool = NULL; 1451145836Smlaier#ifndef __FreeBSD__ 1452126258Smlaier int s; 1453145836Smlaier#endif 1454126258Smlaier int error = 0; 1455126258Smlaier 1456223637Sbz CURVNET_SET(TD_TO_VNET(td)); 1457223637Sbz 1458126258Smlaier /* XXX keep in sync with switch() below */ 1459134166Smlaier#ifdef __FreeBSD__ 1460140494Sdhartmei if (securelevel_gt(td->td_ucred, 2)) 1461134166Smlaier#else 1462126258Smlaier if (securelevel > 1) 1463134166Smlaier#endif 1464126258Smlaier switch (cmd) { 1465126258Smlaier case DIOCGETRULES: 1466126258Smlaier case DIOCGETRULE: 1467126258Smlaier case DIOCGETADDRS: 1468126258Smlaier case DIOCGETADDR: 1469126258Smlaier case DIOCGETSTATE: 1470126258Smlaier case DIOCSETSTATUSIF: 1471126258Smlaier case DIOCGETSTATUS: 1472126258Smlaier case DIOCCLRSTATUS: 1473126258Smlaier case DIOCNATLOOK: 1474126258Smlaier case DIOCSETDEBUG: 1475126258Smlaier case DIOCGETSTATES: 1476126258Smlaier case DIOCGETTIMEOUT: 1477126258Smlaier case DIOCCLRRULECTRS: 1478126258Smlaier case DIOCGETLIMIT: 1479126258Smlaier case DIOCGETALTQS: 1480126258Smlaier case DIOCGETALTQ: 1481126258Smlaier case DIOCGETQSTATS: 1482126258Smlaier case DIOCGETRULESETS: 1483126258Smlaier case DIOCGETRULESET: 1484126258Smlaier case DIOCRGETTABLES: 1485126258Smlaier case DIOCRGETTSTATS: 1486126258Smlaier case DIOCRCLRTSTATS: 1487126258Smlaier case DIOCRCLRADDRS: 1488126258Smlaier case DIOCRADDADDRS: 1489126258Smlaier case DIOCRDELADDRS: 1490126258Smlaier case DIOCRSETADDRS: 1491126258Smlaier case DIOCRGETADDRS: 1492126258Smlaier case DIOCRGETASTATS: 1493126258Smlaier case DIOCRCLRASTATS: 1494126258Smlaier case DIOCRTSTADDRS: 1495126258Smlaier case DIOCOSFPGET: 1496130613Smlaier case DIOCGETSRCNODES: 1497130613Smlaier case DIOCCLRSRCNODES: 1498130613Smlaier case DIOCIGETIFACES: 1499127145Smlaier#ifdef __FreeBSD__ 1500126261Smlaier case DIOCGIFSPEED: 1501126261Smlaier#endif 1502145836Smlaier case DIOCSETIFFLAG: 1503145836Smlaier case DIOCCLRIFFLAG: 1504126258Smlaier break; 1505130613Smlaier case DIOCRCLRTABLES: 1506130613Smlaier case DIOCRADDTABLES: 1507130613Smlaier case DIOCRDELTABLES: 1508130613Smlaier case DIOCRSETTFLAGS: 1509130613Smlaier if (((struct pfioc_table *)addr)->pfrio_flags & 1510130613Smlaier PFR_FLAG_DUMMY) 1511130613Smlaier break; /* dummy operation ok */ 1512130613Smlaier return (EPERM); 1513126258Smlaier default: 1514126258Smlaier return (EPERM); 1515126258Smlaier } 1516126258Smlaier 1517126258Smlaier if (!(flags & FWRITE)) 1518126258Smlaier switch (cmd) { 1519126258Smlaier case DIOCGETRULES: 1520126258Smlaier case DIOCGETADDRS: 1521126258Smlaier case DIOCGETADDR: 1522126258Smlaier case DIOCGETSTATE: 1523126258Smlaier case DIOCGETSTATUS: 1524126258Smlaier case DIOCGETSTATES: 1525126258Smlaier case DIOCGETTIMEOUT: 1526126258Smlaier case DIOCGETLIMIT: 1527126258Smlaier case DIOCGETALTQS: 1528126258Smlaier case DIOCGETALTQ: 1529126258Smlaier case DIOCGETQSTATS: 1530126258Smlaier case DIOCGETRULESETS: 1531126258Smlaier case DIOCGETRULESET: 1532171168Smlaier case DIOCNATLOOK: 1533126258Smlaier case DIOCRGETTABLES: 1534126258Smlaier case DIOCRGETTSTATS: 1535126258Smlaier case DIOCRGETADDRS: 1536126258Smlaier case DIOCRGETASTATS: 1537126258Smlaier case DIOCRTSTADDRS: 1538126258Smlaier case DIOCOSFPGET: 1539130613Smlaier case DIOCGETSRCNODES: 1540130613Smlaier case DIOCIGETIFACES: 1541127145Smlaier#ifdef __FreeBSD__ 1542126261Smlaier case DIOCGIFSPEED: 1543126261Smlaier#endif 1544126258Smlaier break; 1545130613Smlaier case DIOCRCLRTABLES: 1546130613Smlaier case DIOCRADDTABLES: 1547130613Smlaier case DIOCRDELTABLES: 1548130613Smlaier case DIOCRCLRTSTATS: 1549130613Smlaier case DIOCRCLRADDRS: 1550130613Smlaier case DIOCRADDADDRS: 1551130613Smlaier case DIOCRDELADDRS: 1552130613Smlaier case DIOCRSETADDRS: 1553130613Smlaier case DIOCRSETTFLAGS: 1554130613Smlaier if (((struct pfioc_table *)addr)->pfrio_flags & 1555171168Smlaier PFR_FLAG_DUMMY) { 1556171168Smlaier flags |= FWRITE; /* need write lock for dummy */ 1557130613Smlaier break; /* dummy operation ok */ 1558171168Smlaier } 1559130613Smlaier return (EACCES); 1560171168Smlaier case DIOCGETRULE: 1561223637Sbz if (((struct pfioc_rule *)addr)->action == 1562223637Sbz PF_GET_CLR_CNTR) 1563171168Smlaier return (EACCES); 1564171168Smlaier break; 1565126258Smlaier default: 1566126258Smlaier return (EACCES); 1567126258Smlaier } 1568126258Smlaier 1569171168Smlaier if (flags & FWRITE) 1570127145Smlaier#ifdef __FreeBSD__ 1571223637Sbz sx_xlock(&V_pf_consistency_lock); 1572171168Smlaier else 1573223637Sbz sx_slock(&V_pf_consistency_lock); 1574171168Smlaier#else 1575171168Smlaier rw_enter_write(&pf_consistency_lock); 1576171168Smlaier else 1577171168Smlaier rw_enter_read(&pf_consistency_lock); 1578171168Smlaier#endif 1579171168Smlaier 1580171168Smlaier#ifdef __FreeBSD__ 1581126261Smlaier PF_LOCK(); 1582145836Smlaier#else 1583145836Smlaier s = splsoftnet(); 1584126261Smlaier#endif 1585126258Smlaier switch (cmd) { 1586126258Smlaier 1587126258Smlaier case DIOCSTART: 1588223637Sbz#ifdef __FreeBSD__ 1589223637Sbz if (V_pf_status.running) 1590223637Sbz#else 1591126258Smlaier if (pf_status.running) 1592223637Sbz#endif 1593126258Smlaier error = EEXIST; 1594126258Smlaier else { 1595127145Smlaier#ifdef __FreeBSD__ 1596126261Smlaier PF_UNLOCK(); 1597126261Smlaier error = hook_pf(); 1598126261Smlaier PF_LOCK(); 1599126261Smlaier if (error) { 1600126261Smlaier DPFPRINTF(PF_DEBUG_MISC, 1601126261Smlaier ("pf: pfil registeration fail\n")); 1602126261Smlaier break; 1603126261Smlaier } 1604223637Sbz V_pf_status.running = 1; 1605223637Sbz V_pf_status.since = time_second; 1606223637Sbz 1607223637Sbz if (V_pf_status.stateid == 0) { 1608223637Sbz V_pf_status.stateid = time_second; 1609223637Sbz V_pf_status.stateid = V_pf_status.stateid << 32; 1610223637Sbz } 1611223637Sbz#else 1612126258Smlaier pf_status.running = 1; 1613126261Smlaier pf_status.since = time_second; 1614223637Sbz 1615130613Smlaier if (pf_status.stateid == 0) { 1616130613Smlaier pf_status.stateid = time_second; 1617130613Smlaier pf_status.stateid = pf_status.stateid << 32; 1618130613Smlaier } 1619223637Sbz#endif 1620126258Smlaier DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); 1621126258Smlaier } 1622126258Smlaier break; 1623126258Smlaier 1624126258Smlaier case DIOCSTOP: 1625223637Sbz#ifdef __FreeBSD__ 1626223637Sbz if (!V_pf_status.running) 1627126258Smlaier error = ENOENT; 1628126258Smlaier else { 1629223637Sbz V_pf_status.running = 0; 1630126261Smlaier PF_UNLOCK(); 1631126261Smlaier error = dehook_pf(); 1632126261Smlaier PF_LOCK(); 1633126261Smlaier if (error) { 1634223637Sbz V_pf_status.running = 1; 1635126261Smlaier DPFPRINTF(PF_DEBUG_MISC, 1636223637Sbz ("pf: pfil unregisteration failed\n")); 1637126261Smlaier } 1638223637Sbz V_pf_status.since = time_second; 1639223637Sbz#else 1640223637Sbz if (!pf_status.running) 1641223637Sbz error = ENOENT; 1642223637Sbz else { 1643223637Sbz pf_status.running = 0; 1644223637Sbz pf_status.since = time_second; 1645145836Smlaier#endif 1646126258Smlaier DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); 1647126258Smlaier } 1648126258Smlaier break; 1649126258Smlaier 1650126258Smlaier case DIOCADDRULE: { 1651126258Smlaier struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1652126258Smlaier struct pf_ruleset *ruleset; 1653126258Smlaier struct pf_rule *rule, *tail; 1654126258Smlaier struct pf_pooladdr *pa; 1655126258Smlaier int rs_num; 1656126258Smlaier 1657145836Smlaier pr->anchor[sizeof(pr->anchor) - 1] = 0; 1658145836Smlaier ruleset = pf_find_ruleset(pr->anchor); 1659126258Smlaier if (ruleset == NULL) { 1660126258Smlaier error = EINVAL; 1661126258Smlaier break; 1662126258Smlaier } 1663126258Smlaier rs_num = pf_get_ruleset_number(pr->rule.action); 1664126258Smlaier if (rs_num >= PF_RULESET_MAX) { 1665126258Smlaier error = EINVAL; 1666126258Smlaier break; 1667126258Smlaier } 1668126258Smlaier if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1669126258Smlaier error = EINVAL; 1670126258Smlaier break; 1671126258Smlaier } 1672126258Smlaier if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { 1673158486Smlaier#ifdef __FreeBSD__ 1674158486Smlaier DPFPRINTF(PF_DEBUG_MISC, 1675158486Smlaier ("ticket: %d != [%d]%d\n", pr->ticket, rs_num, 1676158486Smlaier ruleset->rules[rs_num].inactive.ticket)); 1677158486Smlaier#endif 1678126258Smlaier error = EBUSY; 1679126258Smlaier break; 1680126258Smlaier } 1681158486Smlaier#ifdef __FreeBSD__ 1682223637Sbz if (pr->pool_ticket != V_ticket_pabuf) { 1683158486Smlaier DPFPRINTF(PF_DEBUG_MISC, 1684158486Smlaier ("pool_ticket: %d != %d\n", pr->pool_ticket, 1685223637Sbz V_ticket_pabuf)); 1686223637Sbz#else 1687223637Sbz if (pr->pool_ticket != ticket_pabuf) { 1688158486Smlaier#endif 1689126258Smlaier error = EBUSY; 1690126258Smlaier break; 1691126258Smlaier } 1692223637Sbz#ifdef __FreeBSD__ 1693223637Sbz rule = pool_get(&V_pf_rule_pl, PR_NOWAIT); 1694223637Sbz#else 1695223637Sbz rule = pool_get(&pf_rule_pl, PR_WAITOK|PR_LIMITFAIL); 1696223637Sbz#endif 1697126258Smlaier if (rule == NULL) { 1698126258Smlaier error = ENOMEM; 1699126258Smlaier break; 1700126258Smlaier } 1701126258Smlaier bcopy(&pr->rule, rule, sizeof(struct pf_rule)); 1702171168Smlaier#ifdef __FreeBSD__ 1703171168Smlaier rule->cuid = td->td_ucred->cr_ruid; 1704171168Smlaier rule->cpid = td->td_proc ? td->td_proc->p_pid : 0; 1705171168Smlaier#else 1706171168Smlaier rule->cuid = p->p_cred->p_ruid; 1707171168Smlaier rule->cpid = p->p_pid; 1708171168Smlaier#endif 1709126258Smlaier rule->anchor = NULL; 1710130613Smlaier rule->kif = NULL; 1711126258Smlaier TAILQ_INIT(&rule->rpool.list); 1712126258Smlaier /* initialize refcounting */ 1713223637Sbz rule->states_cur = 0; 1714130613Smlaier rule->src_nodes = 0; 1715126258Smlaier rule->entries.tqe_prev = NULL; 1716126258Smlaier#ifndef INET 1717126258Smlaier if (rule->af == AF_INET) { 1718223637Sbz#ifdef __FreeBSD__ 1719223637Sbz pool_put(&V_pf_rule_pl, rule); 1720223637Sbz#else 1721126258Smlaier pool_put(&pf_rule_pl, rule); 1722223637Sbz#endif 1723126258Smlaier error = EAFNOSUPPORT; 1724126258Smlaier break; 1725126258Smlaier } 1726126258Smlaier#endif /* INET */ 1727126258Smlaier#ifndef INET6 1728126258Smlaier if (rule->af == AF_INET6) { 1729223637Sbz#ifdef __FreeBSD__ 1730223637Sbz pool_put(&V_pf_rule_pl, rule); 1731223637Sbz#else 1732126258Smlaier pool_put(&pf_rule_pl, rule); 1733223637Sbz#endif 1734126258Smlaier error = EAFNOSUPPORT; 1735126258Smlaier break; 1736126258Smlaier } 1737126258Smlaier#endif /* INET6 */ 1738126258Smlaier tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 1739126258Smlaier pf_rulequeue); 1740126258Smlaier if (tail) 1741126258Smlaier rule->nr = tail->nr + 1; 1742126258Smlaier else 1743126258Smlaier rule->nr = 0; 1744126258Smlaier if (rule->ifname[0]) { 1745171168Smlaier rule->kif = pfi_kif_get(rule->ifname); 1746130613Smlaier if (rule->kif == NULL) { 1747223637Sbz#ifdef __FreeBSD__ 1748223637Sbz pool_put(&V_pf_rule_pl, rule); 1749223637Sbz#else 1750126258Smlaier pool_put(&pf_rule_pl, rule); 1751223637Sbz#endif 1752126258Smlaier error = EINVAL; 1753126258Smlaier break; 1754126258Smlaier } 1755171168Smlaier pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE); 1756126258Smlaier } 1757126258Smlaier 1758180788Sjulian#ifdef __FreeBSD__ /* ROUTING */ 1759232292Sbz if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs) 1760171168Smlaier#else 1761171168Smlaier if (rule->rtableid > 0 && !rtable_exists(rule->rtableid)) 1762171168Smlaier#endif 1763171168Smlaier error = EBUSY; 1764171168Smlaier 1765130613Smlaier#ifdef ALTQ 1766130613Smlaier /* set queue IDs */ 1767130613Smlaier if (rule->qname[0] != 0) { 1768130613Smlaier if ((rule->qid = pf_qname2qid(rule->qname)) == 0) 1769130613Smlaier error = EBUSY; 1770130613Smlaier else if (rule->pqname[0] != 0) { 1771130613Smlaier if ((rule->pqid = 1772130613Smlaier pf_qname2qid(rule->pqname)) == 0) 1773130613Smlaier error = EBUSY; 1774130613Smlaier } else 1775130613Smlaier rule->pqid = rule->qid; 1776130613Smlaier } 1777130613Smlaier#endif 1778126258Smlaier if (rule->tagname[0]) 1779126258Smlaier if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) 1780126258Smlaier error = EBUSY; 1781126258Smlaier if (rule->match_tagname[0]) 1782126258Smlaier if ((rule->match_tag = 1783126258Smlaier pf_tagname2tag(rule->match_tagname)) == 0) 1784126258Smlaier error = EBUSY; 1785126258Smlaier if (rule->rt && !rule->direction) 1786126258Smlaier error = EINVAL; 1787171168Smlaier#if NPFLOG > 0 1788171168Smlaier if (!rule->log) 1789171168Smlaier rule->logif = 0; 1790171168Smlaier if (rule->logif >= PFLOGIFS_MAX) 1791171168Smlaier error = EINVAL; 1792171168Smlaier#endif 1793145836Smlaier if (pf_rtlabel_add(&rule->src.addr) || 1794145836Smlaier pf_rtlabel_add(&rule->dst.addr)) 1795145836Smlaier error = EBUSY; 1796223637Sbz if (pf_addr_setup(ruleset, &rule->src.addr, rule->af)) 1797126258Smlaier error = EINVAL; 1798223637Sbz if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af)) 1799126258Smlaier error = EINVAL; 1800145836Smlaier if (pf_anchor_setup(rule, ruleset, pr->anchor_call)) 1801145836Smlaier error = EINVAL; 1802223637Sbz#ifdef __FreeBSD__ 1803223637Sbz TAILQ_FOREACH(pa, &V_pf_pabuf, entries) 1804223637Sbz#else 1805126258Smlaier TAILQ_FOREACH(pa, &pf_pabuf, entries) 1806223637Sbz#endif 1807126258Smlaier if (pf_tbladdr_setup(ruleset, &pa->addr)) 1808126258Smlaier error = EINVAL; 1809126258Smlaier 1810145836Smlaier if (rule->overload_tblname[0]) { 1811145836Smlaier if ((rule->overload_tbl = pfr_attach_table(ruleset, 1812223637Sbz rule->overload_tblname, 0)) == NULL) 1813145836Smlaier error = EINVAL; 1814145836Smlaier else 1815145836Smlaier rule->overload_tbl->pfrkt_flags |= 1816145836Smlaier PFR_TFLAG_ACTIVE; 1817145836Smlaier } 1818145836Smlaier 1819223637Sbz#ifdef __FreeBSD__ 1820223637Sbz pf_mv_pool(&V_pf_pabuf, &rule->rpool.list); 1821223637Sbz#else 1822126258Smlaier pf_mv_pool(&pf_pabuf, &rule->rpool.list); 1823223637Sbz#endif 1824126258Smlaier if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || 1825145836Smlaier (rule->action == PF_BINAT)) && rule->anchor == NULL) || 1826126258Smlaier (rule->rt > PF_FASTROUTE)) && 1827126258Smlaier (TAILQ_FIRST(&rule->rpool.list) == NULL)) 1828126258Smlaier error = EINVAL; 1829126258Smlaier 1830126258Smlaier if (error) { 1831126258Smlaier pf_rm_rule(NULL, rule); 1832126258Smlaier break; 1833126258Smlaier } 1834171168Smlaier 1835171168Smlaier#ifdef __FreeBSD__ 1836223637Sbz if (!V_debug_pfugidhack && (rule->uid.op || rule->gid.op || 1837171168Smlaier rule->log & PF_LOG_SOCKET_LOOKUP)) { 1838171168Smlaier DPFPRINTF(PF_DEBUG_MISC, 1839171168Smlaier ("pf: debug.pfugidhack enabled\n")); 1840223637Sbz V_debug_pfugidhack = 1; 1841171168Smlaier } 1842171168Smlaier#endif 1843126258Smlaier rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list); 1844171168Smlaier rule->evaluations = rule->packets[0] = rule->packets[1] = 1845171168Smlaier rule->bytes[0] = rule->bytes[1] = 0; 1846126258Smlaier TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, 1847126258Smlaier rule, entries); 1848171168Smlaier ruleset->rules[rs_num].inactive.rcount++; 1849126258Smlaier break; 1850126258Smlaier } 1851126258Smlaier 1852126258Smlaier case DIOCGETRULES: { 1853126258Smlaier struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1854126258Smlaier struct pf_ruleset *ruleset; 1855126258Smlaier struct pf_rule *tail; 1856126258Smlaier int rs_num; 1857126258Smlaier 1858145836Smlaier pr->anchor[sizeof(pr->anchor) - 1] = 0; 1859145836Smlaier ruleset = pf_find_ruleset(pr->anchor); 1860126258Smlaier if (ruleset == NULL) { 1861126258Smlaier error = EINVAL; 1862126258Smlaier break; 1863126258Smlaier } 1864126258Smlaier rs_num = pf_get_ruleset_number(pr->rule.action); 1865126258Smlaier if (rs_num >= PF_RULESET_MAX) { 1866126258Smlaier error = EINVAL; 1867126258Smlaier break; 1868126258Smlaier } 1869126258Smlaier tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 1870126258Smlaier pf_rulequeue); 1871126258Smlaier if (tail) 1872126258Smlaier pr->nr = tail->nr + 1; 1873126258Smlaier else 1874126258Smlaier pr->nr = 0; 1875126258Smlaier pr->ticket = ruleset->rules[rs_num].active.ticket; 1876126258Smlaier break; 1877126258Smlaier } 1878126258Smlaier 1879126258Smlaier case DIOCGETRULE: { 1880126258Smlaier struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1881126258Smlaier struct pf_ruleset *ruleset; 1882126258Smlaier struct pf_rule *rule; 1883126258Smlaier int rs_num, i; 1884126258Smlaier 1885145836Smlaier pr->anchor[sizeof(pr->anchor) - 1] = 0; 1886145836Smlaier ruleset = pf_find_ruleset(pr->anchor); 1887126258Smlaier if (ruleset == NULL) { 1888126258Smlaier error = EINVAL; 1889126258Smlaier break; 1890126258Smlaier } 1891126258Smlaier rs_num = pf_get_ruleset_number(pr->rule.action); 1892126258Smlaier if (rs_num >= PF_RULESET_MAX) { 1893126258Smlaier error = EINVAL; 1894126258Smlaier break; 1895126258Smlaier } 1896126258Smlaier if (pr->ticket != ruleset->rules[rs_num].active.ticket) { 1897126258Smlaier error = EBUSY; 1898126258Smlaier break; 1899126258Smlaier } 1900126258Smlaier rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 1901126258Smlaier while ((rule != NULL) && (rule->nr != pr->nr)) 1902126258Smlaier rule = TAILQ_NEXT(rule, entries); 1903126258Smlaier if (rule == NULL) { 1904126258Smlaier error = EBUSY; 1905126258Smlaier break; 1906126258Smlaier } 1907126258Smlaier bcopy(rule, &pr->rule, sizeof(struct pf_rule)); 1908145836Smlaier if (pf_anchor_copyout(ruleset, rule, pr)) { 1909145836Smlaier error = EBUSY; 1910145836Smlaier break; 1911145836Smlaier } 1912223637Sbz pf_addr_copyout(&pr->rule.src.addr); 1913223637Sbz pf_addr_copyout(&pr->rule.dst.addr); 1914126258Smlaier for (i = 0; i < PF_SKIP_COUNT; ++i) 1915126258Smlaier if (rule->skip[i].ptr == NULL) 1916126258Smlaier pr->rule.skip[i].nr = -1; 1917126258Smlaier else 1918126258Smlaier pr->rule.skip[i].nr = 1919126258Smlaier rule->skip[i].ptr->nr; 1920171168Smlaier 1921171168Smlaier if (pr->action == PF_GET_CLR_CNTR) { 1922171168Smlaier rule->evaluations = 0; 1923171168Smlaier rule->packets[0] = rule->packets[1] = 0; 1924171168Smlaier rule->bytes[0] = rule->bytes[1] = 0; 1925223637Sbz rule->states_tot = 0; 1926171168Smlaier } 1927126258Smlaier break; 1928126258Smlaier } 1929126258Smlaier 1930126258Smlaier case DIOCCHANGERULE: { 1931126258Smlaier struct pfioc_rule *pcr = (struct pfioc_rule *)addr; 1932126258Smlaier struct pf_ruleset *ruleset; 1933126258Smlaier struct pf_rule *oldrule = NULL, *newrule = NULL; 1934126258Smlaier u_int32_t nr = 0; 1935126258Smlaier int rs_num; 1936126258Smlaier 1937126258Smlaier if (!(pcr->action == PF_CHANGE_REMOVE || 1938126258Smlaier pcr->action == PF_CHANGE_GET_TICKET) && 1939223637Sbz#ifdef __FreeBSD__ 1940223637Sbz pcr->pool_ticket != V_ticket_pabuf) { 1941223637Sbz#else 1942126258Smlaier pcr->pool_ticket != ticket_pabuf) { 1943223637Sbz#endif 1944126258Smlaier error = EBUSY; 1945126258Smlaier break; 1946126258Smlaier } 1947126258Smlaier 1948126258Smlaier if (pcr->action < PF_CHANGE_ADD_HEAD || 1949126258Smlaier pcr->action > PF_CHANGE_GET_TICKET) { 1950126258Smlaier error = EINVAL; 1951126258Smlaier break; 1952126258Smlaier } 1953145836Smlaier ruleset = pf_find_ruleset(pcr->anchor); 1954126258Smlaier if (ruleset == NULL) { 1955126258Smlaier error = EINVAL; 1956126258Smlaier break; 1957126258Smlaier } 1958126258Smlaier rs_num = pf_get_ruleset_number(pcr->rule.action); 1959126258Smlaier if (rs_num >= PF_RULESET_MAX) { 1960126258Smlaier error = EINVAL; 1961126258Smlaier break; 1962126258Smlaier } 1963126258Smlaier 1964126258Smlaier if (pcr->action == PF_CHANGE_GET_TICKET) { 1965126258Smlaier pcr->ticket = ++ruleset->rules[rs_num].active.ticket; 1966126258Smlaier break; 1967126258Smlaier } else { 1968126258Smlaier if (pcr->ticket != 1969126258Smlaier ruleset->rules[rs_num].active.ticket) { 1970126258Smlaier error = EINVAL; 1971126258Smlaier break; 1972126258Smlaier } 1973126258Smlaier if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1974126258Smlaier error = EINVAL; 1975126258Smlaier break; 1976126258Smlaier } 1977126258Smlaier } 1978126258Smlaier 1979126258Smlaier if (pcr->action != PF_CHANGE_REMOVE) { 1980223637Sbz#ifdef __FreeBSD__ 1981223637Sbz newrule = pool_get(&V_pf_rule_pl, PR_NOWAIT); 1982223637Sbz#else 1983223637Sbz newrule = pool_get(&pf_rule_pl, PR_WAITOK|PR_LIMITFAIL); 1984223637Sbz#endif 1985126258Smlaier if (newrule == NULL) { 1986126258Smlaier error = ENOMEM; 1987126258Smlaier break; 1988126258Smlaier } 1989126258Smlaier bcopy(&pcr->rule, newrule, sizeof(struct pf_rule)); 1990171168Smlaier#ifdef __FreeBSD__ 1991171168Smlaier newrule->cuid = td->td_ucred->cr_ruid; 1992171168Smlaier newrule->cpid = td->td_proc ? td->td_proc->p_pid : 0; 1993171168Smlaier#else 1994171168Smlaier newrule->cuid = p->p_cred->p_ruid; 1995171168Smlaier newrule->cpid = p->p_pid; 1996171168Smlaier#endif 1997126258Smlaier TAILQ_INIT(&newrule->rpool.list); 1998126258Smlaier /* initialize refcounting */ 1999223637Sbz newrule->states_cur = 0; 2000126258Smlaier newrule->entries.tqe_prev = NULL; 2001126258Smlaier#ifndef INET 2002126258Smlaier if (newrule->af == AF_INET) { 2003223637Sbz#ifdef __FreeBSD__ 2004223637Sbz pool_put(&V_pf_rule_pl, newrule); 2005223637Sbz#else 2006126258Smlaier pool_put(&pf_rule_pl, newrule); 2007223637Sbz#endif 2008126258Smlaier error = EAFNOSUPPORT; 2009126258Smlaier break; 2010126258Smlaier } 2011126258Smlaier#endif /* INET */ 2012126258Smlaier#ifndef INET6 2013126258Smlaier if (newrule->af == AF_INET6) { 2014223637Sbz#ifdef __FreeBSD__ 2015223637Sbz pool_put(&V_pf_rule_pl, newrule); 2016223637Sbz#else 2017126258Smlaier pool_put(&pf_rule_pl, newrule); 2018223637Sbz#endif 2019126258Smlaier error = EAFNOSUPPORT; 2020126258Smlaier break; 2021126258Smlaier } 2022126258Smlaier#endif /* INET6 */ 2023126258Smlaier if (newrule->ifname[0]) { 2024171168Smlaier newrule->kif = pfi_kif_get(newrule->ifname); 2025130613Smlaier if (newrule->kif == NULL) { 2026223637Sbz#ifdef __FreeBSD__ 2027223637Sbz pool_put(&V_pf_rule_pl, newrule); 2028223637Sbz#else 2029126258Smlaier pool_put(&pf_rule_pl, newrule); 2030223637Sbz#endif 2031126258Smlaier error = EINVAL; 2032126258Smlaier break; 2033126258Smlaier } 2034171168Smlaier pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE); 2035126258Smlaier } else 2036130613Smlaier newrule->kif = NULL; 2037126258Smlaier 2038171168Smlaier if (newrule->rtableid > 0 && 2039171168Smlaier#ifdef __FreeBSD__ /* ROUTING */ 2040232292Sbz newrule->rtableid >= rt_numfibs) 2041171168Smlaier#else 2042171168Smlaier !rtable_exists(newrule->rtableid)) 2043171168Smlaier#endif 2044171168Smlaier error = EBUSY; 2045171168Smlaier 2046126258Smlaier#ifdef ALTQ 2047126258Smlaier /* set queue IDs */ 2048126258Smlaier if (newrule->qname[0] != 0) { 2049130613Smlaier if ((newrule->qid = 2050130613Smlaier pf_qname2qid(newrule->qname)) == 0) 2051130613Smlaier error = EBUSY; 2052130613Smlaier else if (newrule->pqname[0] != 0) { 2053130613Smlaier if ((newrule->pqid = 2054130613Smlaier pf_qname2qid(newrule->pqname)) == 0) 2055130613Smlaier error = EBUSY; 2056130613Smlaier } else 2057126258Smlaier newrule->pqid = newrule->qid; 2058126258Smlaier } 2059145836Smlaier#endif /* ALTQ */ 2060126258Smlaier if (newrule->tagname[0]) 2061126258Smlaier if ((newrule->tag = 2062126258Smlaier pf_tagname2tag(newrule->tagname)) == 0) 2063126258Smlaier error = EBUSY; 2064126258Smlaier if (newrule->match_tagname[0]) 2065126258Smlaier if ((newrule->match_tag = pf_tagname2tag( 2066126258Smlaier newrule->match_tagname)) == 0) 2067126258Smlaier error = EBUSY; 2068126258Smlaier if (newrule->rt && !newrule->direction) 2069126258Smlaier error = EINVAL; 2070171168Smlaier#if NPFLOG > 0 2071171168Smlaier if (!newrule->log) 2072171168Smlaier newrule->logif = 0; 2073171168Smlaier if (newrule->logif >= PFLOGIFS_MAX) 2074171168Smlaier error = EINVAL; 2075171168Smlaier#endif 2076145836Smlaier if (pf_rtlabel_add(&newrule->src.addr) || 2077145836Smlaier pf_rtlabel_add(&newrule->dst.addr)) 2078145836Smlaier error = EBUSY; 2079223637Sbz if (pf_addr_setup(ruleset, &newrule->src.addr, newrule->af)) 2080126258Smlaier error = EINVAL; 2081223637Sbz if (pf_addr_setup(ruleset, &newrule->dst.addr, newrule->af)) 2082126258Smlaier error = EINVAL; 2083145836Smlaier if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call)) 2084145836Smlaier error = EINVAL; 2085223637Sbz#ifdef __FreeBSD__ 2086223637Sbz TAILQ_FOREACH(pa, &V_pf_pabuf, entries) 2087223637Sbz#else 2088149884Smlaier TAILQ_FOREACH(pa, &pf_pabuf, entries) 2089223637Sbz#endif 2090149884Smlaier if (pf_tbladdr_setup(ruleset, &pa->addr)) 2091149884Smlaier error = EINVAL; 2092126258Smlaier 2093145836Smlaier if (newrule->overload_tblname[0]) { 2094145836Smlaier if ((newrule->overload_tbl = pfr_attach_table( 2095223637Sbz ruleset, newrule->overload_tblname, 0)) == 2096145836Smlaier NULL) 2097145836Smlaier error = EINVAL; 2098145836Smlaier else 2099145836Smlaier newrule->overload_tbl->pfrkt_flags |= 2100145836Smlaier PFR_TFLAG_ACTIVE; 2101145836Smlaier } 2102145836Smlaier 2103223637Sbz#ifdef __FreeBSD__ 2104223637Sbz pf_mv_pool(&V_pf_pabuf, &newrule->rpool.list); 2105223637Sbz#else 2106126258Smlaier pf_mv_pool(&pf_pabuf, &newrule->rpool.list); 2107223637Sbz#endif 2108126258Smlaier if (((((newrule->action == PF_NAT) || 2109126258Smlaier (newrule->action == PF_RDR) || 2110126258Smlaier (newrule->action == PF_BINAT) || 2111126258Smlaier (newrule->rt > PF_FASTROUTE)) && 2112160543Smlaier !newrule->anchor)) && 2113126258Smlaier (TAILQ_FIRST(&newrule->rpool.list) == NULL)) 2114126258Smlaier error = EINVAL; 2115126258Smlaier 2116126258Smlaier if (error) { 2117126258Smlaier pf_rm_rule(NULL, newrule); 2118126258Smlaier break; 2119126258Smlaier } 2120171168Smlaier 2121171168Smlaier#ifdef __FreeBSD__ 2122223637Sbz if (!V_debug_pfugidhack && (newrule->uid.op || 2123171168Smlaier newrule->gid.op || 2124171168Smlaier newrule->log & PF_LOG_SOCKET_LOOKUP)) { 2125171168Smlaier DPFPRINTF(PF_DEBUG_MISC, 2126171168Smlaier ("pf: debug.pfugidhack enabled\n")); 2127223637Sbz V_debug_pfugidhack = 1; 2128171168Smlaier } 2129171168Smlaier#endif 2130171168Smlaier 2131126258Smlaier newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list); 2132171168Smlaier newrule->evaluations = 0; 2133171168Smlaier newrule->packets[0] = newrule->packets[1] = 0; 2134171168Smlaier newrule->bytes[0] = newrule->bytes[1] = 0; 2135126258Smlaier } 2136223637Sbz#ifdef __FreeBSD__ 2137223637Sbz pf_empty_pool(&V_pf_pabuf); 2138223637Sbz#else 2139126258Smlaier pf_empty_pool(&pf_pabuf); 2140223637Sbz#endif 2141126258Smlaier 2142126258Smlaier if (pcr->action == PF_CHANGE_ADD_HEAD) 2143126258Smlaier oldrule = TAILQ_FIRST( 2144126258Smlaier ruleset->rules[rs_num].active.ptr); 2145126258Smlaier else if (pcr->action == PF_CHANGE_ADD_TAIL) 2146126258Smlaier oldrule = TAILQ_LAST( 2147126258Smlaier ruleset->rules[rs_num].active.ptr, pf_rulequeue); 2148126258Smlaier else { 2149126258Smlaier oldrule = TAILQ_FIRST( 2150126258Smlaier ruleset->rules[rs_num].active.ptr); 2151126258Smlaier while ((oldrule != NULL) && (oldrule->nr != pcr->nr)) 2152126258Smlaier oldrule = TAILQ_NEXT(oldrule, entries); 2153126258Smlaier if (oldrule == NULL) { 2154133577Smlaier if (newrule != NULL) 2155133577Smlaier pf_rm_rule(NULL, newrule); 2156126258Smlaier error = EINVAL; 2157126258Smlaier break; 2158126258Smlaier } 2159126258Smlaier } 2160126258Smlaier 2161171168Smlaier if (pcr->action == PF_CHANGE_REMOVE) { 2162126258Smlaier pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule); 2163171168Smlaier ruleset->rules[rs_num].active.rcount--; 2164171168Smlaier } else { 2165126258Smlaier if (oldrule == NULL) 2166126258Smlaier TAILQ_INSERT_TAIL( 2167126258Smlaier ruleset->rules[rs_num].active.ptr, 2168126258Smlaier newrule, entries); 2169126258Smlaier else if (pcr->action == PF_CHANGE_ADD_HEAD || 2170126258Smlaier pcr->action == PF_CHANGE_ADD_BEFORE) 2171126258Smlaier TAILQ_INSERT_BEFORE(oldrule, newrule, entries); 2172126258Smlaier else 2173126258Smlaier TAILQ_INSERT_AFTER( 2174126258Smlaier ruleset->rules[rs_num].active.ptr, 2175126258Smlaier oldrule, newrule, entries); 2176171168Smlaier ruleset->rules[rs_num].active.rcount++; 2177126258Smlaier } 2178126258Smlaier 2179126258Smlaier nr = 0; 2180126258Smlaier TAILQ_FOREACH(oldrule, 2181126258Smlaier ruleset->rules[rs_num].active.ptr, entries) 2182126258Smlaier oldrule->nr = nr++; 2183126258Smlaier 2184145836Smlaier ruleset->rules[rs_num].active.ticket++; 2185145836Smlaier 2186126258Smlaier pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); 2187126258Smlaier pf_remove_if_empty_ruleset(ruleset); 2188126258Smlaier 2189126258Smlaier break; 2190126258Smlaier } 2191126258Smlaier 2192126258Smlaier case DIOCCLRSTATES: { 2193223637Sbz struct pf_state *s, *nexts; 2194130613Smlaier struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 2195223637Sbz u_int killed = 0; 2196126258Smlaier 2197223637Sbz#ifdef __FreeBSD__ 2198223637Sbz for (s = RB_MIN(pf_state_tree_id, &V_tree_id); s; s = nexts) { 2199223637Sbz nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, s); 2200223637Sbz#else 2201223637Sbz for (s = RB_MIN(pf_state_tree_id, &tree_id); s; s = nexts) { 2202223637Sbz nexts = RB_NEXT(pf_state_tree_id, &tree_id, s); 2203223637Sbz#endif 2204171168Smlaier 2205130613Smlaier if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, 2206223637Sbz s->kif->pfik_name)) { 2207223637Sbz#if NPFSYNC > 0 2208130613Smlaier /* don't send out individual delete messages */ 2209223637Sbz SET(s->state_flags, PFSTATE_NOSYNC); 2210130613Smlaier#endif 2211223637Sbz pf_unlink_state(s); 2212130613Smlaier killed++; 2213130613Smlaier } 2214130613Smlaier } 2215223637Sbz psk->psk_killed = killed; 2216223637Sbz#if NPFSYNC > 0 2217223637Sbz#ifdef __FreeBSD__ 2218223637Sbz if (pfsync_clear_states_ptr != NULL) 2219223637Sbz pfsync_clear_states_ptr(V_pf_status.hostid, psk->psk_ifname); 2220223637Sbz#else 2221130613Smlaier pfsync_clear_states(pf_status.hostid, psk->psk_ifname); 2222130613Smlaier#endif 2223223637Sbz#endif 2224126258Smlaier break; 2225126258Smlaier } 2226126258Smlaier 2227126258Smlaier case DIOCKILLSTATES: { 2228223637Sbz struct pf_state *s, *nexts; 2229223637Sbz struct pf_state_key *sk; 2230223637Sbz struct pf_addr *srcaddr, *dstaddr; 2231223637Sbz u_int16_t srcport, dstport; 2232126258Smlaier struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 2233223637Sbz u_int killed = 0; 2234126258Smlaier 2235223637Sbz if (psk->psk_pfcmp.id) { 2236223637Sbz if (psk->psk_pfcmp.creatorid == 0) 2237223637Sbz#ifdef __FreeBSD__ 2238223637Sbz psk->psk_pfcmp.creatorid = V_pf_status.hostid; 2239223637Sbz#else 2240223637Sbz psk->psk_pfcmp.creatorid = pf_status.hostid; 2241223637Sbz#endif 2242223637Sbz if ((s = pf_find_state_byid(&psk->psk_pfcmp))) { 2243223637Sbz pf_unlink_state(s); 2244223637Sbz psk->psk_killed = 1; 2245223637Sbz } 2246223637Sbz break; 2247223637Sbz } 2248171168Smlaier 2249223637Sbz#ifdef __FreeBSD__ 2250223637Sbz for (s = RB_MIN(pf_state_tree_id, &V_tree_id); s; 2251223637Sbz s = nexts) { 2252223637Sbz nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, s); 2253223637Sbz#else 2254223637Sbz for (s = RB_MIN(pf_state_tree_id, &tree_id); s; 2255223637Sbz s = nexts) { 2256223637Sbz nexts = RB_NEXT(pf_state_tree_id, &tree_id, s); 2257223637Sbz#endif 2258223637Sbz sk = s->key[PF_SK_WIRE]; 2259223637Sbz 2260223637Sbz if (s->direction == PF_OUT) { 2261223637Sbz srcaddr = &sk->addr[1]; 2262223637Sbz dstaddr = &sk->addr[0]; 2263223637Sbz srcport = sk->port[0]; 2264223637Sbz dstport = sk->port[0]; 2265171168Smlaier } else { 2266223637Sbz srcaddr = &sk->addr[0]; 2267223637Sbz dstaddr = &sk->addr[1]; 2268223637Sbz srcport = sk->port[0]; 2269223637Sbz dstport = sk->port[0]; 2270171168Smlaier } 2271223637Sbz if ((!psk->psk_af || sk->af == psk->psk_af) 2272130613Smlaier && (!psk->psk_proto || psk->psk_proto == 2273223637Sbz sk->proto) && 2274145836Smlaier PF_MATCHA(psk->psk_src.neg, 2275126258Smlaier &psk->psk_src.addr.v.a.addr, 2276130613Smlaier &psk->psk_src.addr.v.a.mask, 2277223637Sbz srcaddr, sk->af) && 2278145836Smlaier PF_MATCHA(psk->psk_dst.neg, 2279126258Smlaier &psk->psk_dst.addr.v.a.addr, 2280130613Smlaier &psk->psk_dst.addr.v.a.mask, 2281223637Sbz dstaddr, sk->af) && 2282126258Smlaier (psk->psk_src.port_op == 0 || 2283126258Smlaier pf_match_port(psk->psk_src.port_op, 2284126258Smlaier psk->psk_src.port[0], psk->psk_src.port[1], 2285223637Sbz srcport)) && 2286126258Smlaier (psk->psk_dst.port_op == 0 || 2287126258Smlaier pf_match_port(psk->psk_dst.port_op, 2288126258Smlaier psk->psk_dst.port[0], psk->psk_dst.port[1], 2289223637Sbz dstport)) && 2290223637Sbz (!psk->psk_label[0] || (s->rule.ptr->label[0] && 2291223637Sbz !strcmp(psk->psk_label, s->rule.ptr->label))) && 2292130613Smlaier (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, 2293223637Sbz s->kif->pfik_name))) { 2294223637Sbz pf_unlink_state(s); 2295126258Smlaier killed++; 2296126258Smlaier } 2297126258Smlaier } 2298223637Sbz psk->psk_killed = killed; 2299126258Smlaier break; 2300126258Smlaier } 2301126258Smlaier 2302126258Smlaier case DIOCADDSTATE: { 2303126258Smlaier struct pfioc_state *ps = (struct pfioc_state *)addr; 2304223637Sbz struct pfsync_state *sp = &ps->state; 2305126258Smlaier 2306223637Sbz if (sp->timeout >= PFTM_MAX && 2307223637Sbz sp->timeout != PFTM_UNTIL_PACKET) { 2308126258Smlaier error = EINVAL; 2309126258Smlaier break; 2310126258Smlaier } 2311223637Sbz#ifdef __FreeBSD__ 2312223637Sbz if (pfsync_state_import_ptr != NULL) 2313223637Sbz error = pfsync_state_import_ptr(sp, PFSYNC_SI_IOCTL); 2314223637Sbz#else 2315223637Sbz error = pfsync_state_import(sp, PFSYNC_SI_IOCTL); 2316223637Sbz#endif 2317126258Smlaier break; 2318126258Smlaier } 2319126258Smlaier 2320126258Smlaier case DIOCGETSTATE: { 2321126258Smlaier struct pfioc_state *ps = (struct pfioc_state *)addr; 2322223637Sbz struct pf_state *s; 2323223637Sbz struct pf_state_cmp id_key; 2324126258Smlaier 2325223637Sbz bcopy(ps->state.id, &id_key.id, sizeof(id_key.id)); 2326223637Sbz id_key.creatorid = ps->state.creatorid; 2327223637Sbz 2328223637Sbz s = pf_find_state_byid(&id_key); 2329223637Sbz if (s == NULL) { 2330223637Sbz error = ENOENT; 2331126258Smlaier break; 2332126258Smlaier } 2333223637Sbz 2334223637Sbz pfsync_state_export(&ps->state, s); 2335126258Smlaier break; 2336126258Smlaier } 2337126258Smlaier 2338126258Smlaier case DIOCGETSTATES: { 2339126258Smlaier struct pfioc_states *ps = (struct pfioc_states *)addr; 2340130613Smlaier struct pf_state *state; 2341223637Sbz struct pfsync_state *p, *pstore; 2342126258Smlaier u_int32_t nr = 0; 2343126258Smlaier 2344223637Sbz if (ps->ps_len == 0) { 2345223637Sbz#ifdef __FreeBSD__ 2346223637Sbz nr = V_pf_status.states; 2347223637Sbz#else 2348171168Smlaier nr = pf_status.states; 2349223637Sbz#endif 2350223637Sbz ps->ps_len = sizeof(struct pfsync_state) * nr; 2351145836Smlaier break; 2352126258Smlaier } 2353126258Smlaier 2354171168Smlaier#ifdef __FreeBSD__ 2355171168Smlaier PF_UNLOCK(); 2356171168Smlaier#endif 2357171168Smlaier pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK); 2358171168Smlaier#ifdef __FreeBSD__ 2359171168Smlaier PF_LOCK(); 2360171168Smlaier#endif 2361171168Smlaier 2362126258Smlaier p = ps->ps_states; 2363171168Smlaier 2364223637Sbz#ifdef __FreeBSD__ 2365223637Sbz state = TAILQ_FIRST(&V_state_list); 2366223637Sbz#else 2367171168Smlaier state = TAILQ_FIRST(&state_list); 2368223637Sbz#endif 2369171168Smlaier while (state) { 2370171168Smlaier if (state->timeout != PFTM_UNLINKED) { 2371130613Smlaier if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len) 2372130613Smlaier break; 2373223637Sbz pfsync_state_export(pstore, state); 2374127145Smlaier#ifdef __FreeBSD__ 2375171168Smlaier PF_COPYOUT(pstore, p, sizeof(*p), error); 2376126261Smlaier#else 2377171168Smlaier error = copyout(pstore, p, sizeof(*p)); 2378126261Smlaier#endif 2379171168Smlaier if (error) { 2380171168Smlaier free(pstore, M_TEMP); 2381130613Smlaier goto fail; 2382171168Smlaier } 2383130613Smlaier p++; 2384130613Smlaier nr++; 2385126258Smlaier } 2386223637Sbz state = TAILQ_NEXT(state, entry_list); 2387171168Smlaier } 2388171168Smlaier 2389223637Sbz ps->ps_len = sizeof(struct pfsync_state) * nr; 2390171168Smlaier 2391171168Smlaier free(pstore, M_TEMP); 2392126258Smlaier break; 2393126258Smlaier } 2394126258Smlaier 2395126258Smlaier case DIOCGETSTATUS: { 2396126258Smlaier struct pf_status *s = (struct pf_status *)addr; 2397223637Sbz#ifdef __FreeBSD__ 2398223637Sbz bcopy(&V_pf_status, s, sizeof(struct pf_status)); 2399223637Sbz#else 2400126258Smlaier bcopy(&pf_status, s, sizeof(struct pf_status)); 2401223637Sbz#endif 2402223637Sbz pfi_update_status(s->ifname, s); 2403126258Smlaier break; 2404126258Smlaier } 2405126258Smlaier 2406126258Smlaier case DIOCSETSTATUSIF: { 2407126258Smlaier struct pfioc_if *pi = (struct pfioc_if *)addr; 2408126258Smlaier 2409126258Smlaier if (pi->ifname[0] == 0) { 2410223637Sbz#ifdef __FreeBSD__ 2411223637Sbz bzero(V_pf_status.ifname, IFNAMSIZ); 2412223637Sbz#else 2413126258Smlaier bzero(pf_status.ifname, IFNAMSIZ); 2414223637Sbz#endif 2415126258Smlaier break; 2416126258Smlaier } 2417223637Sbz#ifdef __FreeBSD__ 2418223637Sbz strlcpy(V_pf_status.ifname, pi->ifname, IFNAMSIZ); 2419223637Sbz#else 2420130613Smlaier strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ); 2421223637Sbz#endif 2422130613Smlaier break; 2423126258Smlaier } 2424126258Smlaier 2425126258Smlaier case DIOCCLRSTATUS: { 2426223637Sbz#ifdef __FreeBSD__ 2427223637Sbz bzero(V_pf_status.counters, sizeof(V_pf_status.counters)); 2428223637Sbz bzero(V_pf_status.fcounters, sizeof(V_pf_status.fcounters)); 2429223637Sbz bzero(V_pf_status.scounters, sizeof(V_pf_status.scounters)); 2430223637Sbz V_pf_status.since = time_second; 2431223637Sbz if (*V_pf_status.ifname) 2432223637Sbz pfi_update_status(V_pf_status.ifname, NULL); 2433223637Sbz#else 2434130613Smlaier bzero(pf_status.counters, sizeof(pf_status.counters)); 2435130613Smlaier bzero(pf_status.fcounters, sizeof(pf_status.fcounters)); 2436130613Smlaier bzero(pf_status.scounters, sizeof(pf_status.scounters)); 2437171168Smlaier pf_status.since = time_second; 2438130613Smlaier if (*pf_status.ifname) 2439223637Sbz pfi_update_status(pf_status.ifname, NULL); 2440223637Sbz#endif 2441126258Smlaier break; 2442126258Smlaier } 2443126258Smlaier 2444126258Smlaier case DIOCNATLOOK: { 2445126258Smlaier struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; 2446223637Sbz struct pf_state_key *sk; 2447130613Smlaier struct pf_state *state; 2448223637Sbz struct pf_state_key_cmp key; 2449130613Smlaier int m = 0, direction = pnl->direction; 2450223637Sbz int sidx, didx; 2451126258Smlaier 2452223637Sbz /* NATLOOK src and dst are reversed, so reverse sidx/didx */ 2453223637Sbz sidx = (direction == PF_IN) ? 1 : 0; 2454223637Sbz didx = (direction == PF_IN) ? 0 : 1; 2455126258Smlaier 2456126258Smlaier if (!pnl->proto || 2457126258Smlaier PF_AZERO(&pnl->saddr, pnl->af) || 2458126258Smlaier PF_AZERO(&pnl->daddr, pnl->af) || 2459171168Smlaier ((pnl->proto == IPPROTO_TCP || 2460171168Smlaier pnl->proto == IPPROTO_UDP) && 2461171168Smlaier (!pnl->dport || !pnl->sport))) 2462126258Smlaier error = EINVAL; 2463126258Smlaier else { 2464223637Sbz key.af = pnl->af; 2465223637Sbz key.proto = pnl->proto; 2466223637Sbz PF_ACPY(&key.addr[sidx], &pnl->saddr, pnl->af); 2467223637Sbz key.port[sidx] = pnl->sport; 2468223637Sbz PF_ACPY(&key.addr[didx], &pnl->daddr, pnl->af); 2469223637Sbz key.port[didx] = pnl->dport; 2470223637Sbz 2471223637Sbz state = pf_find_state_all(&key, direction, &m); 2472223637Sbz 2473130613Smlaier if (m > 1) 2474130613Smlaier error = E2BIG; /* more than one state */ 2475130613Smlaier else if (state != NULL) { 2476223637Sbz sk = state->key[sidx]; 2477223637Sbz PF_ACPY(&pnl->rsaddr, &sk->addr[sidx], sk->af); 2478223637Sbz pnl->rsport = sk->port[sidx]; 2479223637Sbz PF_ACPY(&pnl->rdaddr, &sk->addr[didx], sk->af); 2480223637Sbz pnl->rdport = sk->port[didx]; 2481126258Smlaier } else 2482126258Smlaier error = ENOENT; 2483126258Smlaier } 2484126258Smlaier break; 2485126258Smlaier } 2486126258Smlaier 2487126258Smlaier case DIOCSETTIMEOUT: { 2488126258Smlaier struct pfioc_tm *pt = (struct pfioc_tm *)addr; 2489126258Smlaier int old; 2490126258Smlaier 2491126258Smlaier if (pt->timeout < 0 || pt->timeout >= PFTM_MAX || 2492126258Smlaier pt->seconds < 0) { 2493126258Smlaier error = EINVAL; 2494126258Smlaier goto fail; 2495126258Smlaier } 2496223637Sbz#ifdef __FreeBSD__ 2497223637Sbz old = V_pf_default_rule.timeout[pt->timeout]; 2498223637Sbz#else 2499126258Smlaier old = pf_default_rule.timeout[pt->timeout]; 2500223637Sbz#endif 2501171168Smlaier if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0) 2502171168Smlaier pt->seconds = 1; 2503223637Sbz#ifdef __FreeBSD__ 2504223637Sbz V_pf_default_rule.timeout[pt->timeout] = pt->seconds; 2505223637Sbz#else 2506126258Smlaier pf_default_rule.timeout[pt->timeout] = pt->seconds; 2507223637Sbz#endif 2508171168Smlaier if (pt->timeout == PFTM_INTERVAL && pt->seconds < old) 2509171168Smlaier wakeup(pf_purge_thread); 2510126258Smlaier pt->seconds = old; 2511126258Smlaier break; 2512126258Smlaier } 2513126258Smlaier 2514126258Smlaier case DIOCGETTIMEOUT: { 2515126258Smlaier struct pfioc_tm *pt = (struct pfioc_tm *)addr; 2516126258Smlaier 2517126258Smlaier if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) { 2518126258Smlaier error = EINVAL; 2519126258Smlaier goto fail; 2520126258Smlaier } 2521223637Sbz#ifdef __FreeBSD__ 2522223637Sbz pt->seconds = V_pf_default_rule.timeout[pt->timeout]; 2523223637Sbz#else 2524126258Smlaier pt->seconds = pf_default_rule.timeout[pt->timeout]; 2525223637Sbz#endif 2526126258Smlaier break; 2527126258Smlaier } 2528126258Smlaier 2529126258Smlaier case DIOCGETLIMIT: { 2530126258Smlaier struct pfioc_limit *pl = (struct pfioc_limit *)addr; 2531126258Smlaier 2532126258Smlaier if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { 2533126258Smlaier error = EINVAL; 2534126258Smlaier goto fail; 2535126258Smlaier } 2536223637Sbz#ifdef __FreeBSD__ 2537223637Sbz pl->limit = V_pf_pool_limits[pl->index].limit; 2538223637Sbz#else 2539126258Smlaier pl->limit = pf_pool_limits[pl->index].limit; 2540223637Sbz#endif 2541126258Smlaier break; 2542126258Smlaier } 2543126258Smlaier 2544126258Smlaier case DIOCSETLIMIT: { 2545126258Smlaier struct pfioc_limit *pl = (struct pfioc_limit *)addr; 2546126258Smlaier int old_limit; 2547126258Smlaier 2548130613Smlaier if (pl->index < 0 || pl->index >= PF_LIMIT_MAX || 2549223637Sbz#ifdef __FreeBSD__ 2550223637Sbz V_pf_pool_limits[pl->index].pp == NULL) { 2551223637Sbz#else 2552130613Smlaier pf_pool_limits[pl->index].pp == NULL) { 2553223637Sbz#endif 2554126258Smlaier error = EINVAL; 2555126258Smlaier goto fail; 2556126258Smlaier } 2557127145Smlaier#ifdef __FreeBSD__ 2558223637Sbz uma_zone_set_max(V_pf_pool_limits[pl->index].pp, pl->limit); 2559223637Sbz old_limit = V_pf_pool_limits[pl->index].limit; 2560223637Sbz V_pf_pool_limits[pl->index].limit = pl->limit; 2561223637Sbz pl->limit = old_limit; 2562126261Smlaier#else 2563126258Smlaier if (pool_sethardlimit(pf_pool_limits[pl->index].pp, 2564126258Smlaier pl->limit, NULL, 0) != 0) { 2565126258Smlaier error = EBUSY; 2566126258Smlaier goto fail; 2567126258Smlaier } 2568126258Smlaier old_limit = pf_pool_limits[pl->index].limit; 2569126258Smlaier pf_pool_limits[pl->index].limit = pl->limit; 2570126258Smlaier pl->limit = old_limit; 2571223637Sbz#endif 2572126258Smlaier break; 2573126258Smlaier } 2574126258Smlaier 2575126258Smlaier case DIOCSETDEBUG: { 2576126258Smlaier u_int32_t *level = (u_int32_t *)addr; 2577126258Smlaier 2578223637Sbz#ifdef __FreeBSD__ 2579223637Sbz V_pf_status.debug = *level; 2580223637Sbz#else 2581126258Smlaier pf_status.debug = *level; 2582223637Sbz#endif 2583126258Smlaier break; 2584126258Smlaier } 2585126258Smlaier 2586126258Smlaier case DIOCCLRRULECTRS: { 2587171168Smlaier /* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */ 2588126258Smlaier struct pf_ruleset *ruleset = &pf_main_ruleset; 2589126258Smlaier struct pf_rule *rule; 2590126258Smlaier 2591126258Smlaier TAILQ_FOREACH(rule, 2592171168Smlaier ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) { 2593171168Smlaier rule->evaluations = 0; 2594171168Smlaier rule->packets[0] = rule->packets[1] = 0; 2595171168Smlaier rule->bytes[0] = rule->bytes[1] = 0; 2596171168Smlaier } 2597126258Smlaier break; 2598126258Smlaier } 2599126258Smlaier 2600127145Smlaier#ifdef __FreeBSD__ 2601126261Smlaier case DIOCGIFSPEED: { 2602126261Smlaier struct pf_ifspeed *psp = (struct pf_ifspeed *)addr; 2603126261Smlaier struct pf_ifspeed ps; 2604126261Smlaier struct ifnet *ifp; 2605126261Smlaier 2606126261Smlaier if (psp->ifname[0] != 0) { 2607126261Smlaier /* Can we completely trust user-land? */ 2608126261Smlaier strlcpy(ps.ifname, psp->ifname, IFNAMSIZ); 2609126261Smlaier ifp = ifunit(ps.ifname); 2610141584Smlaier if (ifp != NULL) 2611126261Smlaier psp->baudrate = ifp->if_baudrate; 2612126261Smlaier else 2613126261Smlaier error = EINVAL; 2614126261Smlaier } else 2615126261Smlaier error = EINVAL; 2616126261Smlaier break; 2617126261Smlaier } 2618126261Smlaier#endif /* __FreeBSD__ */ 2619126261Smlaier 2620126258Smlaier#ifdef ALTQ 2621126258Smlaier case DIOCSTARTALTQ: { 2622126258Smlaier struct pf_altq *altq; 2623126258Smlaier 2624126258Smlaier /* enable all altq interfaces on active list */ 2625177700Smlaier#ifdef __FreeBSD__ 2626223637Sbz TAILQ_FOREACH(altq, V_pf_altqs_active, entries) { 2627177700Smlaier if (altq->qname[0] == 0 && (altq->local_flags & 2628177700Smlaier PFALTQ_FLAG_IF_REMOVED) == 0) { 2629177700Smlaier#else 2630223637Sbz TAILQ_FOREACH(altq, pf_altqs_active, entries) { 2631126258Smlaier if (altq->qname[0] == 0) { 2632177700Smlaier#endif 2633135352Smlaier error = pf_enable_altq(altq); 2634126258Smlaier if (error != 0) 2635126258Smlaier break; 2636126258Smlaier } 2637126258Smlaier } 2638126258Smlaier if (error == 0) 2639223637Sbz#ifdef __FreeBSD__ 2640223637Sbz V_pf_altq_running = 1; 2641223637Sbz#else 2642135352Smlaier pf_altq_running = 1; 2643223637Sbz#endif 2644126258Smlaier DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n")); 2645126258Smlaier break; 2646126258Smlaier } 2647126258Smlaier 2648126258Smlaier case DIOCSTOPALTQ: { 2649126258Smlaier struct pf_altq *altq; 2650126258Smlaier 2651126258Smlaier /* disable all altq interfaces on active list */ 2652177700Smlaier#ifdef __FreeBSD__ 2653223637Sbz TAILQ_FOREACH(altq, V_pf_altqs_active, entries) { 2654177700Smlaier if (altq->qname[0] == 0 && (altq->local_flags & 2655177700Smlaier PFALTQ_FLAG_IF_REMOVED) == 0) { 2656177700Smlaier#else 2657223637Sbz TAILQ_FOREACH(altq, pf_altqs_active, entries) { 2658126258Smlaier if (altq->qname[0] == 0) { 2659177700Smlaier#endif 2660135352Smlaier error = pf_disable_altq(altq); 2661135352Smlaier if (error != 0) 2662126258Smlaier break; 2663126258Smlaier } 2664126258Smlaier } 2665126258Smlaier if (error == 0) 2666223637Sbz#ifdef __FreeBSD__ 2667223637Sbz V_pf_altq_running = 0; 2668223637Sbz#else 2669135352Smlaier pf_altq_running = 0; 2670223637Sbz#endif 2671126258Smlaier DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n")); 2672126258Smlaier break; 2673126258Smlaier } 2674126258Smlaier 2675126258Smlaier case DIOCADDALTQ: { 2676126258Smlaier struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2677126258Smlaier struct pf_altq *altq, *a; 2678126258Smlaier 2679223637Sbz#ifdef __FreeBSD__ 2680223637Sbz if (pa->ticket != V_ticket_altqs_inactive) { 2681223637Sbz#else 2682126258Smlaier if (pa->ticket != ticket_altqs_inactive) { 2683223637Sbz#endif 2684126258Smlaier error = EBUSY; 2685126258Smlaier break; 2686126258Smlaier } 2687223637Sbz#ifdef __FreeBSD__ 2688223637Sbz altq = pool_get(&V_pf_altq_pl, PR_NOWAIT); 2689223637Sbz#else 2690223637Sbz altq = pool_get(&pf_altq_pl, PR_WAITOK|PR_LIMITFAIL); 2691223637Sbz#endif 2692126258Smlaier if (altq == NULL) { 2693126258Smlaier error = ENOMEM; 2694126258Smlaier break; 2695126258Smlaier } 2696126258Smlaier bcopy(&pa->altq, altq, sizeof(struct pf_altq)); 2697177700Smlaier#ifdef __FreeBSD__ 2698177700Smlaier altq->local_flags = 0; 2699177700Smlaier#endif 2700126258Smlaier 2701126258Smlaier /* 2702126258Smlaier * if this is for a queue, find the discipline and 2703126258Smlaier * copy the necessary fields 2704126258Smlaier */ 2705126258Smlaier if (altq->qname[0] != 0) { 2706130613Smlaier if ((altq->qid = pf_qname2qid(altq->qname)) == 0) { 2707130613Smlaier error = EBUSY; 2708223637Sbz#ifdef __FreeBSD__ 2709223637Sbz pool_put(&V_pf_altq_pl, altq); 2710223637Sbz#else 2711130613Smlaier pool_put(&pf_altq_pl, altq); 2712223637Sbz#endif 2713130613Smlaier break; 2714130613Smlaier } 2715177700Smlaier altq->altq_disc = NULL; 2716223637Sbz#ifdef __FreeBSD__ 2717223637Sbz TAILQ_FOREACH(a, V_pf_altqs_inactive, entries) { 2718223637Sbz#else 2719126258Smlaier TAILQ_FOREACH(a, pf_altqs_inactive, entries) { 2720223637Sbz#endif 2721126258Smlaier if (strncmp(a->ifname, altq->ifname, 2722126258Smlaier IFNAMSIZ) == 0 && a->qname[0] == 0) { 2723126258Smlaier altq->altq_disc = a->altq_disc; 2724126258Smlaier break; 2725126258Smlaier } 2726126258Smlaier } 2727126258Smlaier } 2728126258Smlaier 2729127145Smlaier#ifdef __FreeBSD__ 2730177700Smlaier struct ifnet *ifp; 2731177700Smlaier 2732177700Smlaier if ((ifp = ifunit(altq->ifname)) == NULL) { 2733177700Smlaier altq->local_flags |= PFALTQ_FLAG_IF_REMOVED; 2734177700Smlaier } else { 2735177700Smlaier PF_UNLOCK(); 2736223637Sbz#endif 2737126258Smlaier error = altq_add(altq); 2738127145Smlaier#ifdef __FreeBSD__ 2739177700Smlaier PF_LOCK(); 2740177700Smlaier } 2741126261Smlaier#endif 2742126258Smlaier if (error) { 2743223637Sbz#ifdef __FreeBSD__ 2744223637Sbz pool_put(&V_pf_altq_pl, altq); 2745223637Sbz#else 2746126258Smlaier pool_put(&pf_altq_pl, altq); 2747223637Sbz#endif 2748126258Smlaier break; 2749126258Smlaier } 2750126258Smlaier 2751223637Sbz#ifdef __FreeBSD__ 2752223637Sbz TAILQ_INSERT_TAIL(V_pf_altqs_inactive, altq, entries); 2753223637Sbz#else 2754126258Smlaier TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries); 2755223637Sbz#endif 2756126258Smlaier bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 2757126258Smlaier break; 2758126258Smlaier } 2759126258Smlaier 2760126258Smlaier case DIOCGETALTQS: { 2761126258Smlaier struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2762126258Smlaier struct pf_altq *altq; 2763126258Smlaier 2764126258Smlaier pa->nr = 0; 2765223637Sbz#ifdef __FreeBSD__ 2766223637Sbz TAILQ_FOREACH(altq, V_pf_altqs_active, entries) 2767223637Sbz pa->nr++; 2768223637Sbz pa->ticket = V_ticket_altqs_active; 2769223637Sbz#else 2770126258Smlaier TAILQ_FOREACH(altq, pf_altqs_active, entries) 2771126258Smlaier pa->nr++; 2772126258Smlaier pa->ticket = ticket_altqs_active; 2773223637Sbz#endif 2774126258Smlaier break; 2775126258Smlaier } 2776126258Smlaier 2777126258Smlaier case DIOCGETALTQ: { 2778126258Smlaier struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2779126258Smlaier struct pf_altq *altq; 2780126258Smlaier u_int32_t nr; 2781126258Smlaier 2782223637Sbz#ifdef __FreeBSD__ 2783223637Sbz if (pa->ticket != V_ticket_altqs_active) { 2784223637Sbz#else 2785126258Smlaier if (pa->ticket != ticket_altqs_active) { 2786223637Sbz#endif 2787126258Smlaier error = EBUSY; 2788126258Smlaier break; 2789126258Smlaier } 2790126258Smlaier nr = 0; 2791223637Sbz#ifdef __FreeBSD__ 2792223637Sbz altq = TAILQ_FIRST(V_pf_altqs_active); 2793223637Sbz#else 2794126258Smlaier altq = TAILQ_FIRST(pf_altqs_active); 2795223637Sbz#endif 2796126258Smlaier while ((altq != NULL) && (nr < pa->nr)) { 2797126258Smlaier altq = TAILQ_NEXT(altq, entries); 2798126258Smlaier nr++; 2799126258Smlaier } 2800126258Smlaier if (altq == NULL) { 2801126258Smlaier error = EBUSY; 2802126258Smlaier break; 2803126258Smlaier } 2804126258Smlaier bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 2805126258Smlaier break; 2806126258Smlaier } 2807126258Smlaier 2808126258Smlaier case DIOCCHANGEALTQ: 2809126258Smlaier /* CHANGEALTQ not supported yet! */ 2810126258Smlaier error = ENODEV; 2811126258Smlaier break; 2812126258Smlaier 2813126258Smlaier case DIOCGETQSTATS: { 2814126258Smlaier struct pfioc_qstats *pq = (struct pfioc_qstats *)addr; 2815126258Smlaier struct pf_altq *altq; 2816126258Smlaier u_int32_t nr; 2817126258Smlaier int nbytes; 2818126258Smlaier 2819223637Sbz#ifdef __FreeBSD__ 2820223637Sbz if (pq->ticket != V_ticket_altqs_active) { 2821223637Sbz#else 2822126258Smlaier if (pq->ticket != ticket_altqs_active) { 2823223637Sbz#endif 2824126258Smlaier error = EBUSY; 2825126258Smlaier break; 2826126258Smlaier } 2827126258Smlaier nbytes = pq->nbytes; 2828126258Smlaier nr = 0; 2829223637Sbz#ifdef __FreeBSD__ 2830223637Sbz altq = TAILQ_FIRST(V_pf_altqs_active); 2831223637Sbz#else 2832126258Smlaier altq = TAILQ_FIRST(pf_altqs_active); 2833223637Sbz#endif 2834126258Smlaier while ((altq != NULL) && (nr < pq->nr)) { 2835126258Smlaier altq = TAILQ_NEXT(altq, entries); 2836126258Smlaier nr++; 2837126258Smlaier } 2838126258Smlaier if (altq == NULL) { 2839126258Smlaier error = EBUSY; 2840126258Smlaier break; 2841126258Smlaier } 2842223637Sbz 2843127145Smlaier#ifdef __FreeBSD__ 2844177700Smlaier if ((altq->local_flags & PFALTQ_FLAG_IF_REMOVED) != 0) { 2845177700Smlaier error = ENXIO; 2846177700Smlaier break; 2847177700Smlaier } 2848126261Smlaier PF_UNLOCK(); 2849126261Smlaier#endif 2850126258Smlaier error = altq_getqstats(altq, pq->buf, &nbytes); 2851127145Smlaier#ifdef __FreeBSD__ 2852126261Smlaier PF_LOCK(); 2853126261Smlaier#endif 2854126258Smlaier if (error == 0) { 2855126258Smlaier pq->scheduler = altq->scheduler; 2856126258Smlaier pq->nbytes = nbytes; 2857126258Smlaier } 2858126258Smlaier break; 2859126258Smlaier } 2860126258Smlaier#endif /* ALTQ */ 2861126258Smlaier 2862126258Smlaier case DIOCBEGINADDRS: { 2863126258Smlaier struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2864126258Smlaier 2865223637Sbz#ifdef __FreeBSD__ 2866223637Sbz pf_empty_pool(&V_pf_pabuf); 2867223637Sbz pp->ticket = ++V_ticket_pabuf; 2868223637Sbz#else 2869126258Smlaier pf_empty_pool(&pf_pabuf); 2870126258Smlaier pp->ticket = ++ticket_pabuf; 2871223637Sbz#endif 2872126258Smlaier break; 2873126258Smlaier } 2874126258Smlaier 2875126258Smlaier case DIOCADDADDR: { 2876126258Smlaier struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2877126258Smlaier 2878223637Sbz#ifdef __FreeBSD__ 2879223637Sbz if (pp->ticket != V_ticket_pabuf) { 2880223637Sbz#else 2881149884Smlaier if (pp->ticket != ticket_pabuf) { 2882223637Sbz#endif 2883149884Smlaier error = EBUSY; 2884149884Smlaier break; 2885149884Smlaier } 2886126258Smlaier#ifndef INET 2887126258Smlaier if (pp->af == AF_INET) { 2888126258Smlaier error = EAFNOSUPPORT; 2889126258Smlaier break; 2890126258Smlaier } 2891126258Smlaier#endif /* INET */ 2892126258Smlaier#ifndef INET6 2893126258Smlaier if (pp->af == AF_INET6) { 2894126258Smlaier error = EAFNOSUPPORT; 2895126258Smlaier break; 2896126258Smlaier } 2897126258Smlaier#endif /* INET6 */ 2898126258Smlaier if (pp->addr.addr.type != PF_ADDR_ADDRMASK && 2899126258Smlaier pp->addr.addr.type != PF_ADDR_DYNIFTL && 2900126258Smlaier pp->addr.addr.type != PF_ADDR_TABLE) { 2901126258Smlaier error = EINVAL; 2902126258Smlaier break; 2903126258Smlaier } 2904223637Sbz#ifdef __FreeBSD__ 2905223637Sbz pa = pool_get(&V_pf_pooladdr_pl, PR_NOWAIT); 2906223637Sbz#else 2907223637Sbz pa = pool_get(&pf_pooladdr_pl, PR_WAITOK|PR_LIMITFAIL); 2908223637Sbz#endif 2909126258Smlaier if (pa == NULL) { 2910126258Smlaier error = ENOMEM; 2911126258Smlaier break; 2912126258Smlaier } 2913126258Smlaier bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr)); 2914126258Smlaier if (pa->ifname[0]) { 2915171168Smlaier pa->kif = pfi_kif_get(pa->ifname); 2916130613Smlaier if (pa->kif == NULL) { 2917223637Sbz#ifdef __FreeBSD__ 2918223637Sbz pool_put(&V_pf_pooladdr_pl, pa); 2919223637Sbz#else 2920126258Smlaier pool_put(&pf_pooladdr_pl, pa); 2921223637Sbz#endif 2922126258Smlaier error = EINVAL; 2923126258Smlaier break; 2924126258Smlaier } 2925171168Smlaier pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE); 2926126258Smlaier } 2927130613Smlaier if (pfi_dynaddr_setup(&pa->addr, pp->af)) { 2928130613Smlaier pfi_dynaddr_remove(&pa->addr); 2929171168Smlaier pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE); 2930223637Sbz#ifdef __FreeBSD__ 2931223637Sbz pool_put(&V_pf_pooladdr_pl, pa); 2932223637Sbz#else 2933126258Smlaier pool_put(&pf_pooladdr_pl, pa); 2934223637Sbz#endif 2935126258Smlaier error = EINVAL; 2936126258Smlaier break; 2937126258Smlaier } 2938223637Sbz#ifdef __FreeBSD__ 2939223637Sbz TAILQ_INSERT_TAIL(&V_pf_pabuf, pa, entries); 2940223637Sbz#else 2941126258Smlaier TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries); 2942223637Sbz#endif 2943126258Smlaier break; 2944126258Smlaier } 2945126258Smlaier 2946126258Smlaier case DIOCGETADDRS: { 2947126258Smlaier struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2948126258Smlaier 2949126258Smlaier pp->nr = 0; 2950145836Smlaier pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, 2951145836Smlaier pp->r_num, 0, 1, 0); 2952126258Smlaier if (pool == NULL) { 2953126258Smlaier error = EBUSY; 2954126258Smlaier break; 2955126258Smlaier } 2956126258Smlaier TAILQ_FOREACH(pa, &pool->list, entries) 2957126258Smlaier pp->nr++; 2958126258Smlaier break; 2959126258Smlaier } 2960126258Smlaier 2961126258Smlaier case DIOCGETADDR: { 2962126258Smlaier struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2963126258Smlaier u_int32_t nr = 0; 2964126258Smlaier 2965145836Smlaier pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, 2966145836Smlaier pp->r_num, 0, 1, 1); 2967126258Smlaier if (pool == NULL) { 2968126258Smlaier error = EBUSY; 2969126258Smlaier break; 2970126258Smlaier } 2971126258Smlaier pa = TAILQ_FIRST(&pool->list); 2972126258Smlaier while ((pa != NULL) && (nr < pp->nr)) { 2973126258Smlaier pa = TAILQ_NEXT(pa, entries); 2974126258Smlaier nr++; 2975126258Smlaier } 2976126258Smlaier if (pa == NULL) { 2977126258Smlaier error = EBUSY; 2978126258Smlaier break; 2979126258Smlaier } 2980126258Smlaier bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr)); 2981223637Sbz pf_addr_copyout(&pp->addr.addr); 2982126258Smlaier break; 2983126258Smlaier } 2984126258Smlaier 2985126258Smlaier case DIOCCHANGEADDR: { 2986126258Smlaier struct pfioc_pooladdr *pca = (struct pfioc_pooladdr *)addr; 2987126258Smlaier struct pf_pooladdr *oldpa = NULL, *newpa = NULL; 2988126258Smlaier struct pf_ruleset *ruleset; 2989126258Smlaier 2990126258Smlaier if (pca->action < PF_CHANGE_ADD_HEAD || 2991126258Smlaier pca->action > PF_CHANGE_REMOVE) { 2992126258Smlaier error = EINVAL; 2993126258Smlaier break; 2994126258Smlaier } 2995126258Smlaier if (pca->addr.addr.type != PF_ADDR_ADDRMASK && 2996126258Smlaier pca->addr.addr.type != PF_ADDR_DYNIFTL && 2997126258Smlaier pca->addr.addr.type != PF_ADDR_TABLE) { 2998126258Smlaier error = EINVAL; 2999126258Smlaier break; 3000126258Smlaier } 3001126258Smlaier 3002145836Smlaier ruleset = pf_find_ruleset(pca->anchor); 3003126258Smlaier if (ruleset == NULL) { 3004126258Smlaier error = EBUSY; 3005126258Smlaier break; 3006126258Smlaier } 3007145836Smlaier pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action, 3008145836Smlaier pca->r_num, pca->r_last, 1, 1); 3009126258Smlaier if (pool == NULL) { 3010126258Smlaier error = EBUSY; 3011126258Smlaier break; 3012126258Smlaier } 3013126258Smlaier if (pca->action != PF_CHANGE_REMOVE) { 3014223637Sbz#ifdef __FreeBSD__ 3015223637Sbz newpa = pool_get(&V_pf_pooladdr_pl, 3016223637Sbz PR_NOWAIT); 3017223637Sbz#else 3018223637Sbz newpa = pool_get(&pf_pooladdr_pl, 3019223637Sbz PR_WAITOK|PR_LIMITFAIL); 3020223637Sbz#endif 3021126258Smlaier if (newpa == NULL) { 3022126258Smlaier error = ENOMEM; 3023126258Smlaier break; 3024126258Smlaier } 3025126258Smlaier bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr)); 3026126258Smlaier#ifndef INET 3027126258Smlaier if (pca->af == AF_INET) { 3028223637Sbz#ifdef __FreeBSD__ 3029223637Sbz pool_put(&V_pf_pooladdr_pl, newpa); 3030223637Sbz#else 3031126258Smlaier pool_put(&pf_pooladdr_pl, newpa); 3032223637Sbz#endif 3033126258Smlaier error = EAFNOSUPPORT; 3034126258Smlaier break; 3035126258Smlaier } 3036126258Smlaier#endif /* INET */ 3037126258Smlaier#ifndef INET6 3038126258Smlaier if (pca->af == AF_INET6) { 3039223637Sbz#ifdef __FreeBSD__ 3040223637Sbz pool_put(&V_pf_pooladdr_pl, newpa); 3041223637Sbz#else 3042126258Smlaier pool_put(&pf_pooladdr_pl, newpa); 3043223637Sbz#endif 3044126258Smlaier error = EAFNOSUPPORT; 3045126258Smlaier break; 3046126258Smlaier } 3047126258Smlaier#endif /* INET6 */ 3048126258Smlaier if (newpa->ifname[0]) { 3049171168Smlaier newpa->kif = pfi_kif_get(newpa->ifname); 3050130613Smlaier if (newpa->kif == NULL) { 3051223637Sbz#ifdef __FreeBSD__ 3052223637Sbz pool_put(&V_pf_pooladdr_pl, newpa); 3053223637Sbz#else 3054126258Smlaier pool_put(&pf_pooladdr_pl, newpa); 3055223637Sbz#endif 3056126258Smlaier error = EINVAL; 3057126258Smlaier break; 3058126258Smlaier } 3059171168Smlaier pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE); 3060126258Smlaier } else 3061130613Smlaier newpa->kif = NULL; 3062130613Smlaier if (pfi_dynaddr_setup(&newpa->addr, pca->af) || 3063126258Smlaier pf_tbladdr_setup(ruleset, &newpa->addr)) { 3064130613Smlaier pfi_dynaddr_remove(&newpa->addr); 3065171168Smlaier pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE); 3066223637Sbz#ifdef __FreeBSD__ 3067223637Sbz pool_put(&V_pf_pooladdr_pl, newpa); 3068223637Sbz#else 3069126258Smlaier pool_put(&pf_pooladdr_pl, newpa); 3070223637Sbz#endif 3071126258Smlaier error = EINVAL; 3072126258Smlaier break; 3073126258Smlaier } 3074126258Smlaier } 3075126258Smlaier 3076126258Smlaier if (pca->action == PF_CHANGE_ADD_HEAD) 3077126258Smlaier oldpa = TAILQ_FIRST(&pool->list); 3078126258Smlaier else if (pca->action == PF_CHANGE_ADD_TAIL) 3079126258Smlaier oldpa = TAILQ_LAST(&pool->list, pf_palist); 3080126258Smlaier else { 3081126258Smlaier int i = 0; 3082126258Smlaier 3083126258Smlaier oldpa = TAILQ_FIRST(&pool->list); 3084126258Smlaier while ((oldpa != NULL) && (i < pca->nr)) { 3085126258Smlaier oldpa = TAILQ_NEXT(oldpa, entries); 3086126258Smlaier i++; 3087126258Smlaier } 3088126258Smlaier if (oldpa == NULL) { 3089126258Smlaier error = EINVAL; 3090126258Smlaier break; 3091126258Smlaier } 3092126258Smlaier } 3093126258Smlaier 3094126258Smlaier if (pca->action == PF_CHANGE_REMOVE) { 3095126258Smlaier TAILQ_REMOVE(&pool->list, oldpa, entries); 3096130613Smlaier pfi_dynaddr_remove(&oldpa->addr); 3097126258Smlaier pf_tbladdr_remove(&oldpa->addr); 3098171168Smlaier pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE); 3099223637Sbz#ifdef __FreeBSD__ 3100223637Sbz pool_put(&V_pf_pooladdr_pl, oldpa); 3101223637Sbz#else 3102126258Smlaier pool_put(&pf_pooladdr_pl, oldpa); 3103223637Sbz#endif 3104126258Smlaier } else { 3105126258Smlaier if (oldpa == NULL) 3106126258Smlaier TAILQ_INSERT_TAIL(&pool->list, newpa, entries); 3107126258Smlaier else if (pca->action == PF_CHANGE_ADD_HEAD || 3108126258Smlaier pca->action == PF_CHANGE_ADD_BEFORE) 3109126258Smlaier TAILQ_INSERT_BEFORE(oldpa, newpa, entries); 3110126258Smlaier else 3111126258Smlaier TAILQ_INSERT_AFTER(&pool->list, oldpa, 3112126258Smlaier newpa, entries); 3113126258Smlaier } 3114126258Smlaier 3115126258Smlaier pool->cur = TAILQ_FIRST(&pool->list); 3116126258Smlaier PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, 3117126258Smlaier pca->af); 3118126258Smlaier break; 3119126258Smlaier } 3120126258Smlaier 3121126258Smlaier case DIOCGETRULESETS: { 3122126258Smlaier struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 3123145836Smlaier struct pf_ruleset *ruleset; 3124126258Smlaier struct pf_anchor *anchor; 3125126258Smlaier 3126145836Smlaier pr->path[sizeof(pr->path) - 1] = 0; 3127145836Smlaier if ((ruleset = pf_find_ruleset(pr->path)) == NULL) { 3128126258Smlaier error = EINVAL; 3129126258Smlaier break; 3130126258Smlaier } 3131126258Smlaier pr->nr = 0; 3132145836Smlaier if (ruleset->anchor == NULL) { 3133145836Smlaier /* XXX kludge for pf_main_ruleset */ 3134223637Sbz#ifdef __FreeBSD__ 3135223637Sbz RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors) 3136223637Sbz#else 3137145836Smlaier RB_FOREACH(anchor, pf_anchor_global, &pf_anchors) 3138223637Sbz#endif 3139145836Smlaier if (anchor->parent == NULL) 3140145836Smlaier pr->nr++; 3141145836Smlaier } else { 3142145836Smlaier RB_FOREACH(anchor, pf_anchor_node, 3143145836Smlaier &ruleset->anchor->children) 3144145836Smlaier pr->nr++; 3145145836Smlaier } 3146126258Smlaier break; 3147126258Smlaier } 3148126258Smlaier 3149126258Smlaier case DIOCGETRULESET: { 3150126258Smlaier struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 3151145836Smlaier struct pf_ruleset *ruleset; 3152126258Smlaier struct pf_anchor *anchor; 3153126258Smlaier u_int32_t nr = 0; 3154126258Smlaier 3155145836Smlaier pr->path[sizeof(pr->path) - 1] = 0; 3156145836Smlaier if ((ruleset = pf_find_ruleset(pr->path)) == NULL) { 3157126258Smlaier error = EINVAL; 3158126258Smlaier break; 3159126258Smlaier } 3160145836Smlaier pr->name[0] = 0; 3161145836Smlaier if (ruleset->anchor == NULL) { 3162145836Smlaier /* XXX kludge for pf_main_ruleset */ 3163223637Sbz#ifdef __FreeBSD__ 3164223637Sbz RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors) 3165223637Sbz#else 3166145836Smlaier RB_FOREACH(anchor, pf_anchor_global, &pf_anchors) 3167223637Sbz#endif 3168145836Smlaier if (anchor->parent == NULL && nr++ == pr->nr) { 3169145836Smlaier strlcpy(pr->name, anchor->name, 3170145836Smlaier sizeof(pr->name)); 3171145836Smlaier break; 3172145836Smlaier } 3173145836Smlaier } else { 3174145836Smlaier RB_FOREACH(anchor, pf_anchor_node, 3175145836Smlaier &ruleset->anchor->children) 3176145836Smlaier if (nr++ == pr->nr) { 3177145836Smlaier strlcpy(pr->name, anchor->name, 3178145836Smlaier sizeof(pr->name)); 3179145836Smlaier break; 3180145836Smlaier } 3181126258Smlaier } 3182145836Smlaier if (!pr->name[0]) 3183126258Smlaier error = EBUSY; 3184126258Smlaier break; 3185126258Smlaier } 3186126258Smlaier 3187126258Smlaier case DIOCRCLRTABLES: { 3188126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3189126258Smlaier 3190126258Smlaier if (io->pfrio_esize != 0) { 3191126258Smlaier error = ENODEV; 3192126258Smlaier break; 3193126258Smlaier } 3194126258Smlaier error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, 3195130613Smlaier io->pfrio_flags | PFR_FLAG_USERIOCTL); 3196126258Smlaier break; 3197126258Smlaier } 3198126258Smlaier 3199126258Smlaier case DIOCRADDTABLES: { 3200126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3201126258Smlaier 3202126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_table)) { 3203126258Smlaier error = ENODEV; 3204126258Smlaier break; 3205126258Smlaier } 3206126258Smlaier error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size, 3207130613Smlaier &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3208126258Smlaier break; 3209126258Smlaier } 3210126258Smlaier 3211126258Smlaier case DIOCRDELTABLES: { 3212126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3213126258Smlaier 3214126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_table)) { 3215126258Smlaier error = ENODEV; 3216126258Smlaier break; 3217126258Smlaier } 3218126258Smlaier error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size, 3219130613Smlaier &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3220126258Smlaier break; 3221126258Smlaier } 3222126258Smlaier 3223126258Smlaier case DIOCRGETTABLES: { 3224126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3225126258Smlaier 3226126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_table)) { 3227126258Smlaier error = ENODEV; 3228126258Smlaier break; 3229126258Smlaier } 3230126258Smlaier error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer, 3231130613Smlaier &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3232126258Smlaier break; 3233126258Smlaier } 3234126258Smlaier 3235126258Smlaier case DIOCRGETTSTATS: { 3236126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3237126258Smlaier 3238126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_tstats)) { 3239126258Smlaier error = ENODEV; 3240126258Smlaier break; 3241126258Smlaier } 3242126258Smlaier error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer, 3243130613Smlaier &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3244126258Smlaier break; 3245126258Smlaier } 3246126258Smlaier 3247126258Smlaier case DIOCRCLRTSTATS: { 3248126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3249126258Smlaier 3250126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_table)) { 3251126258Smlaier error = ENODEV; 3252126258Smlaier break; 3253126258Smlaier } 3254126258Smlaier error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size, 3255130613Smlaier &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3256126258Smlaier break; 3257126258Smlaier } 3258126258Smlaier 3259126258Smlaier case DIOCRSETTFLAGS: { 3260126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3261126258Smlaier 3262126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_table)) { 3263126258Smlaier error = ENODEV; 3264126258Smlaier break; 3265126258Smlaier } 3266126258Smlaier error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size, 3267126258Smlaier io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange, 3268130613Smlaier &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3269126258Smlaier break; 3270126258Smlaier } 3271126258Smlaier 3272126258Smlaier case DIOCRCLRADDRS: { 3273126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3274126258Smlaier 3275126258Smlaier if (io->pfrio_esize != 0) { 3276126258Smlaier error = ENODEV; 3277126258Smlaier break; 3278126258Smlaier } 3279126258Smlaier error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel, 3280130613Smlaier io->pfrio_flags | PFR_FLAG_USERIOCTL); 3281126258Smlaier break; 3282126258Smlaier } 3283126258Smlaier 3284126258Smlaier case DIOCRADDADDRS: { 3285126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3286126258Smlaier 3287126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3288126258Smlaier error = ENODEV; 3289126258Smlaier break; 3290126258Smlaier } 3291126258Smlaier error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer, 3292130613Smlaier io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags | 3293130613Smlaier PFR_FLAG_USERIOCTL); 3294126258Smlaier break; 3295126258Smlaier } 3296126258Smlaier 3297126258Smlaier case DIOCRDELADDRS: { 3298126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3299126258Smlaier 3300126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3301126258Smlaier error = ENODEV; 3302126258Smlaier break; 3303126258Smlaier } 3304126258Smlaier error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer, 3305130613Smlaier io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags | 3306130613Smlaier PFR_FLAG_USERIOCTL); 3307126258Smlaier break; 3308126258Smlaier } 3309126258Smlaier 3310126258Smlaier case DIOCRSETADDRS: { 3311126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3312126258Smlaier 3313126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3314126258Smlaier error = ENODEV; 3315126258Smlaier break; 3316126258Smlaier } 3317126258Smlaier error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer, 3318126258Smlaier io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd, 3319130613Smlaier &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags | 3320171168Smlaier PFR_FLAG_USERIOCTL, 0); 3321126258Smlaier break; 3322126258Smlaier } 3323126258Smlaier 3324126258Smlaier case DIOCRGETADDRS: { 3325126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3326126258Smlaier 3327126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3328126258Smlaier error = ENODEV; 3329126258Smlaier break; 3330126258Smlaier } 3331126258Smlaier error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer, 3332130613Smlaier &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3333126258Smlaier break; 3334126258Smlaier } 3335126258Smlaier 3336126258Smlaier case DIOCRGETASTATS: { 3337126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3338126258Smlaier 3339126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_astats)) { 3340126258Smlaier error = ENODEV; 3341126258Smlaier break; 3342126258Smlaier } 3343126258Smlaier error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer, 3344130613Smlaier &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3345126258Smlaier break; 3346126258Smlaier } 3347126258Smlaier 3348126258Smlaier case DIOCRCLRASTATS: { 3349126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3350126258Smlaier 3351126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3352126258Smlaier error = ENODEV; 3353126258Smlaier break; 3354126258Smlaier } 3355126258Smlaier error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer, 3356130613Smlaier io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags | 3357130613Smlaier PFR_FLAG_USERIOCTL); 3358126258Smlaier break; 3359126258Smlaier } 3360126258Smlaier 3361126258Smlaier case DIOCRTSTADDRS: { 3362126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3363126258Smlaier 3364126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3365126258Smlaier error = ENODEV; 3366126258Smlaier break; 3367126258Smlaier } 3368126258Smlaier error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer, 3369130613Smlaier io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags | 3370130613Smlaier PFR_FLAG_USERIOCTL); 3371126258Smlaier break; 3372126258Smlaier } 3373126258Smlaier 3374126258Smlaier case DIOCRINADEFINE: { 3375126258Smlaier struct pfioc_table *io = (struct pfioc_table *)addr; 3376126258Smlaier 3377126258Smlaier if (io->pfrio_esize != sizeof(struct pfr_addr)) { 3378126258Smlaier error = ENODEV; 3379126258Smlaier break; 3380126258Smlaier } 3381126258Smlaier error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer, 3382126258Smlaier io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr, 3383130613Smlaier io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL); 3384126258Smlaier break; 3385126258Smlaier } 3386126258Smlaier 3387126258Smlaier case DIOCOSFPADD: { 3388126258Smlaier struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 3389126258Smlaier error = pf_osfp_add(io); 3390126258Smlaier break; 3391126258Smlaier } 3392126258Smlaier 3393126258Smlaier case DIOCOSFPGET: { 3394126258Smlaier struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 3395126258Smlaier error = pf_osfp_get(io); 3396126258Smlaier break; 3397126258Smlaier } 3398126258Smlaier 3399130613Smlaier case DIOCXBEGIN: { 3400171168Smlaier struct pfioc_trans *io = (struct pfioc_trans *)addr; 3401171168Smlaier struct pfioc_trans_e *ioe; 3402171168Smlaier struct pfr_table *table; 3403171168Smlaier int i; 3404130613Smlaier 3405171168Smlaier if (io->esize != sizeof(*ioe)) { 3406130613Smlaier error = ENODEV; 3407130613Smlaier goto fail; 3408130613Smlaier } 3409171168Smlaier#ifdef __FreeBSD__ 3410171168Smlaier PF_UNLOCK(); 3411171168Smlaier#endif 3412223637Sbz ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK); 3413223637Sbz table = malloc(sizeof(*table), M_TEMP, M_WAITOK); 3414171168Smlaier#ifdef __FreeBSD__ 3415171168Smlaier PF_LOCK(); 3416171168Smlaier#endif 3417130613Smlaier for (i = 0; i < io->size; i++) { 3418127145Smlaier#ifdef __FreeBSD__ 3419223637Sbz PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); 3420223637Sbz if (error) { 3421130613Smlaier#else 3422171168Smlaier if (copyin(io->array+i, ioe, sizeof(*ioe))) { 3423126261Smlaier#endif 3424171168Smlaier free(table, M_TEMP); 3425171168Smlaier free(ioe, M_TEMP); 3426130613Smlaier error = EFAULT; 3427130613Smlaier goto fail; 3428130613Smlaier } 3429171168Smlaier switch (ioe->rs_num) { 3430130613Smlaier#ifdef ALTQ 3431130613Smlaier case PF_RULESET_ALTQ: 3432171168Smlaier if (ioe->anchor[0]) { 3433171168Smlaier free(table, M_TEMP); 3434171168Smlaier free(ioe, M_TEMP); 3435130613Smlaier error = EINVAL; 3436130613Smlaier goto fail; 3437130613Smlaier } 3438171168Smlaier if ((error = pf_begin_altq(&ioe->ticket))) { 3439171168Smlaier free(table, M_TEMP); 3440171168Smlaier free(ioe, M_TEMP); 3441130613Smlaier goto fail; 3442171168Smlaier } 3443130613Smlaier break; 3444130613Smlaier#endif /* ALTQ */ 3445130613Smlaier case PF_RULESET_TABLE: 3446171168Smlaier bzero(table, sizeof(*table)); 3447171168Smlaier strlcpy(table->pfrt_anchor, ioe->anchor, 3448171168Smlaier sizeof(table->pfrt_anchor)); 3449171168Smlaier if ((error = pfr_ina_begin(table, 3450171168Smlaier &ioe->ticket, NULL, 0))) { 3451171168Smlaier free(table, M_TEMP); 3452171168Smlaier free(ioe, M_TEMP); 3453130613Smlaier goto fail; 3454171168Smlaier } 3455130613Smlaier break; 3456130613Smlaier default: 3457171168Smlaier if ((error = pf_begin_rules(&ioe->ticket, 3458171168Smlaier ioe->rs_num, ioe->anchor))) { 3459171168Smlaier free(table, M_TEMP); 3460171168Smlaier free(ioe, M_TEMP); 3461130613Smlaier goto fail; 3462171168Smlaier } 3463130613Smlaier break; 3464130613Smlaier } 3465127145Smlaier#ifdef __FreeBSD__ 3466171168Smlaier PF_COPYOUT(ioe, io->array+i, sizeof(io->array[i]), 3467130613Smlaier error); 3468130613Smlaier if (error) { 3469130613Smlaier#else 3470171168Smlaier if (copyout(ioe, io->array+i, sizeof(io->array[i]))) { 3471130613Smlaier#endif 3472171168Smlaier free(table, M_TEMP); 3473171168Smlaier free(ioe, M_TEMP); 3474130613Smlaier error = EFAULT; 3475130613Smlaier goto fail; 3476130613Smlaier } 3477126261Smlaier } 3478171168Smlaier free(table, M_TEMP); 3479171168Smlaier free(ioe, M_TEMP); 3480130613Smlaier break; 3481130613Smlaier } 3482126261Smlaier 3483130613Smlaier case DIOCXROLLBACK: { 3484171168Smlaier struct pfioc_trans *io = (struct pfioc_trans *)addr; 3485171168Smlaier struct pfioc_trans_e *ioe; 3486171168Smlaier struct pfr_table *table; 3487171168Smlaier int i; 3488126261Smlaier 3489171168Smlaier if (io->esize != sizeof(*ioe)) { 3490130613Smlaier error = ENODEV; 3491130613Smlaier goto fail; 3492126261Smlaier } 3493171168Smlaier#ifdef __FreeBSD__ 3494171168Smlaier PF_UNLOCK(); 3495171168Smlaier#endif 3496223637Sbz ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK); 3497223637Sbz table = malloc(sizeof(*table), M_TEMP, M_WAITOK); 3498171168Smlaier#ifdef __FreeBSD__ 3499171168Smlaier PF_LOCK(); 3500171168Smlaier#endif 3501130613Smlaier for (i = 0; i < io->size; i++) { 3502130613Smlaier#ifdef __FreeBSD__ 3503171168Smlaier PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); 3504130613Smlaier if (error) { 3505130613Smlaier#else 3506171168Smlaier if (copyin(io->array+i, ioe, sizeof(*ioe))) { 3507130613Smlaier#endif 3508171168Smlaier free(table, M_TEMP); 3509171168Smlaier free(ioe, M_TEMP); 3510130613Smlaier error = EFAULT; 3511130613Smlaier goto fail; 3512130613Smlaier } 3513171168Smlaier switch (ioe->rs_num) { 3514130613Smlaier#ifdef ALTQ 3515130613Smlaier case PF_RULESET_ALTQ: 3516171168Smlaier if (ioe->anchor[0]) { 3517171168Smlaier free(table, M_TEMP); 3518171168Smlaier free(ioe, M_TEMP); 3519130613Smlaier error = EINVAL; 3520130613Smlaier goto fail; 3521130613Smlaier } 3522171168Smlaier if ((error = pf_rollback_altq(ioe->ticket))) { 3523171168Smlaier free(table, M_TEMP); 3524171168Smlaier free(ioe, M_TEMP); 3525130613Smlaier goto fail; /* really bad */ 3526171168Smlaier } 3527130613Smlaier break; 3528130613Smlaier#endif /* ALTQ */ 3529130613Smlaier case PF_RULESET_TABLE: 3530171168Smlaier bzero(table, sizeof(*table)); 3531171168Smlaier strlcpy(table->pfrt_anchor, ioe->anchor, 3532171168Smlaier sizeof(table->pfrt_anchor)); 3533171168Smlaier if ((error = pfr_ina_rollback(table, 3534171168Smlaier ioe->ticket, NULL, 0))) { 3535171168Smlaier free(table, M_TEMP); 3536171168Smlaier free(ioe, M_TEMP); 3537130613Smlaier goto fail; /* really bad */ 3538171168Smlaier } 3539130613Smlaier break; 3540130613Smlaier default: 3541171168Smlaier if ((error = pf_rollback_rules(ioe->ticket, 3542171168Smlaier ioe->rs_num, ioe->anchor))) { 3543171168Smlaier free(table, M_TEMP); 3544171168Smlaier free(ioe, M_TEMP); 3545130613Smlaier goto fail; /* really bad */ 3546171168Smlaier } 3547130613Smlaier break; 3548130613Smlaier } 3549126261Smlaier } 3550171168Smlaier free(table, M_TEMP); 3551171168Smlaier free(ioe, M_TEMP); 3552130613Smlaier break; 3553130613Smlaier } 3554126261Smlaier 3555130613Smlaier case DIOCXCOMMIT: { 3556171168Smlaier struct pfioc_trans *io = (struct pfioc_trans *)addr; 3557171168Smlaier struct pfioc_trans_e *ioe; 3558171168Smlaier struct pfr_table *table; 3559171168Smlaier struct pf_ruleset *rs; 3560171168Smlaier int i; 3561126261Smlaier 3562171168Smlaier if (io->esize != sizeof(*ioe)) { 3563130613Smlaier error = ENODEV; 3564130613Smlaier goto fail; 3565130613Smlaier } 3566171168Smlaier#ifdef __FreeBSD__ 3567171168Smlaier PF_UNLOCK(); 3568171168Smlaier#endif 3569223637Sbz ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK); 3570223637Sbz table = malloc(sizeof(*table), M_TEMP, M_WAITOK); 3571171168Smlaier#ifdef __FreeBSD__ 3572171168Smlaier PF_LOCK(); 3573171168Smlaier#endif 3574130613Smlaier /* first makes sure everything will succeed */ 3575130613Smlaier for (i = 0; i < io->size; i++) { 3576127145Smlaier#ifdef __FreeBSD__ 3577171168Smlaier PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); 3578130613Smlaier if (error) { 3579130613Smlaier#else 3580171168Smlaier if (copyin(io->array+i, ioe, sizeof(*ioe))) { 3581126261Smlaier#endif 3582171168Smlaier free(table, M_TEMP); 3583171168Smlaier free(ioe, M_TEMP); 3584130613Smlaier error = EFAULT; 3585130613Smlaier goto fail; 3586130613Smlaier } 3587171168Smlaier switch (ioe->rs_num) { 3588130613Smlaier#ifdef ALTQ 3589130613Smlaier case PF_RULESET_ALTQ: 3590171168Smlaier if (ioe->anchor[0]) { 3591171168Smlaier free(table, M_TEMP); 3592171168Smlaier free(ioe, M_TEMP); 3593130613Smlaier error = EINVAL; 3594130613Smlaier goto fail; 3595130613Smlaier } 3596223637Sbz#ifdef __FreeBSD__ 3597223637Sbz if (!V_altqs_inactive_open || ioe->ticket != 3598223637Sbz V_ticket_altqs_inactive) { 3599223637Sbz#else 3600171168Smlaier if (!altqs_inactive_open || ioe->ticket != 3601130613Smlaier ticket_altqs_inactive) { 3602223637Sbz#endif 3603171168Smlaier free(table, M_TEMP); 3604171168Smlaier free(ioe, M_TEMP); 3605130613Smlaier error = EBUSY; 3606130613Smlaier goto fail; 3607130613Smlaier } 3608130613Smlaier break; 3609130613Smlaier#endif /* ALTQ */ 3610130613Smlaier case PF_RULESET_TABLE: 3611171168Smlaier rs = pf_find_ruleset(ioe->anchor); 3612171168Smlaier if (rs == NULL || !rs->topen || ioe->ticket != 3613223637Sbz rs->tticket) { 3614171168Smlaier free(table, M_TEMP); 3615171168Smlaier free(ioe, M_TEMP); 3616130613Smlaier error = EBUSY; 3617130613Smlaier goto fail; 3618130613Smlaier } 3619130613Smlaier break; 3620130613Smlaier default: 3621171168Smlaier if (ioe->rs_num < 0 || ioe->rs_num >= 3622130613Smlaier PF_RULESET_MAX) { 3623171168Smlaier free(table, M_TEMP); 3624171168Smlaier free(ioe, M_TEMP); 3625130613Smlaier error = EINVAL; 3626130613Smlaier goto fail; 3627130613Smlaier } 3628171168Smlaier rs = pf_find_ruleset(ioe->anchor); 3629130613Smlaier if (rs == NULL || 3630171168Smlaier !rs->rules[ioe->rs_num].inactive.open || 3631171168Smlaier rs->rules[ioe->rs_num].inactive.ticket != 3632171168Smlaier ioe->ticket) { 3633171168Smlaier free(table, M_TEMP); 3634171168Smlaier free(ioe, M_TEMP); 3635130613Smlaier error = EBUSY; 3636130613Smlaier goto fail; 3637130613Smlaier } 3638130613Smlaier break; 3639130613Smlaier } 3640130613Smlaier } 3641130613Smlaier /* now do the commit - no errors should happen here */ 3642130613Smlaier for (i = 0; i < io->size; i++) { 3643127145Smlaier#ifdef __FreeBSD__ 3644171168Smlaier PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); 3645130613Smlaier if (error) { 3646130613Smlaier#else 3647171168Smlaier if (copyin(io->array+i, ioe, sizeof(*ioe))) { 3648126261Smlaier#endif 3649171168Smlaier free(table, M_TEMP); 3650171168Smlaier free(ioe, M_TEMP); 3651130613Smlaier error = EFAULT; 3652130613Smlaier goto fail; 3653130613Smlaier } 3654171168Smlaier switch (ioe->rs_num) { 3655130613Smlaier#ifdef ALTQ 3656130613Smlaier case PF_RULESET_ALTQ: 3657171168Smlaier if ((error = pf_commit_altq(ioe->ticket))) { 3658171168Smlaier free(table, M_TEMP); 3659171168Smlaier free(ioe, M_TEMP); 3660130613Smlaier goto fail; /* really bad */ 3661171168Smlaier } 3662130613Smlaier break; 3663130613Smlaier#endif /* ALTQ */ 3664130613Smlaier case PF_RULESET_TABLE: 3665171168Smlaier bzero(table, sizeof(*table)); 3666171168Smlaier strlcpy(table->pfrt_anchor, ioe->anchor, 3667171168Smlaier sizeof(table->pfrt_anchor)); 3668171168Smlaier if ((error = pfr_ina_commit(table, ioe->ticket, 3669171168Smlaier NULL, NULL, 0))) { 3670171168Smlaier free(table, M_TEMP); 3671171168Smlaier free(ioe, M_TEMP); 3672130613Smlaier goto fail; /* really bad */ 3673171168Smlaier } 3674130613Smlaier break; 3675130613Smlaier default: 3676171168Smlaier if ((error = pf_commit_rules(ioe->ticket, 3677171168Smlaier ioe->rs_num, ioe->anchor))) { 3678171168Smlaier free(table, M_TEMP); 3679171168Smlaier free(ioe, M_TEMP); 3680130613Smlaier goto fail; /* really bad */ 3681171168Smlaier } 3682130613Smlaier break; 3683130613Smlaier } 3684126261Smlaier } 3685171168Smlaier free(table, M_TEMP); 3686171168Smlaier free(ioe, M_TEMP); 3687130613Smlaier break; 3688126261Smlaier } 3689126261Smlaier 3690130613Smlaier case DIOCGETSRCNODES: { 3691130613Smlaier struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr; 3692171168Smlaier struct pf_src_node *n, *p, *pstore; 3693130613Smlaier u_int32_t nr = 0; 3694130613Smlaier int space = psn->psn_len; 3695126261Smlaier 3696130613Smlaier if (space == 0) { 3697223637Sbz#ifdef __FreeBSD__ 3698223637Sbz RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) 3699223637Sbz#else 3700130613Smlaier RB_FOREACH(n, pf_src_tree, &tree_src_tracking) 3701223637Sbz#endif 3702130613Smlaier nr++; 3703130613Smlaier psn->psn_len = sizeof(struct pf_src_node) * nr; 3704145836Smlaier break; 3705126261Smlaier } 3706126261Smlaier 3707171168Smlaier#ifdef __FreeBSD__ 3708171168Smlaier PF_UNLOCK(); 3709171168Smlaier#endif 3710171168Smlaier pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK); 3711171168Smlaier#ifdef __FreeBSD__ 3712171168Smlaier PF_LOCK(); 3713171168Smlaier#endif 3714130613Smlaier p = psn->psn_src_nodes; 3715223637Sbz#ifdef __FreeBSD__ 3716223637Sbz RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) { 3717223637Sbz#else 3718130613Smlaier RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { 3719223637Sbz#endif 3720145836Smlaier int secs = time_second, diff; 3721126261Smlaier 3722130613Smlaier if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len) 3723130613Smlaier break; 3724130613Smlaier 3725171168Smlaier bcopy(n, pstore, sizeof(*pstore)); 3726130613Smlaier if (n->rule.ptr != NULL) 3727171168Smlaier pstore->rule.nr = n->rule.ptr->nr; 3728171168Smlaier pstore->creation = secs - pstore->creation; 3729171168Smlaier if (pstore->expire > secs) 3730171168Smlaier pstore->expire -= secs; 3731130613Smlaier else 3732171168Smlaier pstore->expire = 0; 3733145836Smlaier 3734145836Smlaier /* adjust the connection rate estimate */ 3735145836Smlaier diff = secs - n->conn_rate.last; 3736145836Smlaier if (diff >= n->conn_rate.seconds) 3737171168Smlaier pstore->conn_rate.count = 0; 3738145836Smlaier else 3739171168Smlaier pstore->conn_rate.count -= 3740145836Smlaier n->conn_rate.count * diff / 3741145836Smlaier n->conn_rate.seconds; 3742145836Smlaier 3743127145Smlaier#ifdef __FreeBSD__ 3744171168Smlaier PF_COPYOUT(pstore, p, sizeof(*p), error); 3745130613Smlaier#else 3746171168Smlaier error = copyout(pstore, p, sizeof(*p)); 3747126261Smlaier#endif 3748171168Smlaier if (error) { 3749171168Smlaier free(pstore, M_TEMP); 3750130613Smlaier goto fail; 3751171168Smlaier } 3752130613Smlaier p++; 3753130613Smlaier nr++; 3754126261Smlaier } 3755130613Smlaier psn->psn_len = sizeof(struct pf_src_node) * nr; 3756171168Smlaier 3757171168Smlaier free(pstore, M_TEMP); 3758130613Smlaier break; 3759130613Smlaier } 3760126261Smlaier 3761130613Smlaier case DIOCCLRSRCNODES: { 3762130613Smlaier struct pf_src_node *n; 3763130613Smlaier struct pf_state *state; 3764130613Smlaier 3765223637Sbz#ifdef __FreeBSD__ 3766223637Sbz RB_FOREACH(state, pf_state_tree_id, &V_tree_id) { 3767223637Sbz#else 3768130613Smlaier RB_FOREACH(state, pf_state_tree_id, &tree_id) { 3769223637Sbz#endif 3770130613Smlaier state->src_node = NULL; 3771130613Smlaier state->nat_src_node = NULL; 3772126261Smlaier } 3773223637Sbz#ifdef __FreeBSD__ 3774223637Sbz RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) { 3775223637Sbz#else 3776130613Smlaier RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { 3777223637Sbz#endif 3778130613Smlaier n->expire = 1; 3779130613Smlaier n->states = 0; 3780130613Smlaier } 3781171168Smlaier pf_purge_expired_src_nodes(1); 3782223637Sbz#ifdef __FreeBSD__ 3783223637Sbz V_pf_status.src_nodes = 0; 3784223637Sbz#else 3785130613Smlaier pf_status.src_nodes = 0; 3786223637Sbz#endif 3787130613Smlaier break; 3788130613Smlaier } 3789126261Smlaier 3790171168Smlaier case DIOCKILLSRCNODES: { 3791171168Smlaier struct pf_src_node *sn; 3792171168Smlaier struct pf_state *s; 3793223637Sbz struct pfioc_src_node_kill *psnk = 3794223637Sbz (struct pfioc_src_node_kill *)addr; 3795223637Sbz u_int killed = 0; 3796171168Smlaier 3797223637Sbz#ifdef __FreeBSD__ 3798223637Sbz RB_FOREACH(sn, pf_src_tree, &V_tree_src_tracking) { 3799223637Sbz#else 3800171168Smlaier RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) { 3801223637Sbz#endif 3802223637Sbz if (PF_MATCHA(psnk->psnk_src.neg, 3803223637Sbz &psnk->psnk_src.addr.v.a.addr, 3804223637Sbz &psnk->psnk_src.addr.v.a.mask, 3805223637Sbz &sn->addr, sn->af) && 3806223637Sbz PF_MATCHA(psnk->psnk_dst.neg, 3807223637Sbz &psnk->psnk_dst.addr.v.a.addr, 3808223637Sbz &psnk->psnk_dst.addr.v.a.mask, 3809223637Sbz &sn->raddr, sn->af)) { 3810171168Smlaier /* Handle state to src_node linkage */ 3811171168Smlaier if (sn->states != 0) { 3812223637Sbz RB_FOREACH(s, pf_state_tree_id, 3813223637Sbz#ifdef __FreeBSD__ 3814223637Sbz &V_tree_id) { 3815223637Sbz#else 3816171168Smlaier &tree_id) { 3817223637Sbz#endif 3818171168Smlaier if (s->src_node == sn) 3819171168Smlaier s->src_node = NULL; 3820171168Smlaier if (s->nat_src_node == sn) 3821171168Smlaier s->nat_src_node = NULL; 3822171168Smlaier } 3823171168Smlaier sn->states = 0; 3824171168Smlaier } 3825171168Smlaier sn->expire = 1; 3826171168Smlaier killed++; 3827171168Smlaier } 3828171168Smlaier } 3829171168Smlaier 3830171168Smlaier if (killed > 0) 3831171168Smlaier pf_purge_expired_src_nodes(1); 3832171168Smlaier 3833223637Sbz psnk->psnk_killed = killed; 3834171168Smlaier break; 3835171168Smlaier } 3836171168Smlaier 3837130613Smlaier case DIOCSETHOSTID: { 3838130613Smlaier u_int32_t *hostid = (u_int32_t *)addr; 3839126261Smlaier 3840223637Sbz#ifdef __FreeBSD__ 3841145836Smlaier if (*hostid == 0) 3842223637Sbz V_pf_status.hostid = arc4random(); 3843223637Sbz else 3844223637Sbz V_pf_status.hostid = *hostid; 3845223637Sbz#else 3846223637Sbz if (*hostid == 0) 3847145836Smlaier pf_status.hostid = arc4random(); 3848145836Smlaier else 3849145836Smlaier pf_status.hostid = *hostid; 3850223637Sbz#endif 3851130613Smlaier break; 3852130613Smlaier } 3853126261Smlaier 3854130613Smlaier case DIOCOSFPFLUSH: 3855130613Smlaier pf_osfp_flush(); 3856130613Smlaier break; 3857126261Smlaier 3858130613Smlaier case DIOCIGETIFACES: { 3859130613Smlaier struct pfioc_iface *io = (struct pfioc_iface *)addr; 3860130613Smlaier 3861171168Smlaier if (io->pfiio_esize != sizeof(struct pfi_kif)) { 3862130613Smlaier error = ENODEV; 3863130613Smlaier break; 3864130613Smlaier } 3865130613Smlaier error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer, 3866171168Smlaier &io->pfiio_size); 3867130613Smlaier break; 3868130613Smlaier } 3869130613Smlaier 3870145836Smlaier case DIOCSETIFFLAG: { 3871145836Smlaier struct pfioc_iface *io = (struct pfioc_iface *)addr; 3872145836Smlaier 3873145836Smlaier error = pfi_set_flags(io->pfiio_name, io->pfiio_flags); 3874145836Smlaier break; 3875145836Smlaier } 3876145836Smlaier 3877145836Smlaier case DIOCCLRIFFLAG: { 3878145836Smlaier struct pfioc_iface *io = (struct pfioc_iface *)addr; 3879145836Smlaier 3880145836Smlaier error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags); 3881145836Smlaier break; 3882145836Smlaier } 3883145836Smlaier 3884130613Smlaier default: 3885130613Smlaier error = ENODEV; 3886130613Smlaier break; 3887130613Smlaier } 3888130613Smlaierfail: 3889130613Smlaier#ifdef __FreeBSD__ 3890130613Smlaier PF_UNLOCK(); 3891171168Smlaier 3892171168Smlaier if (flags & FWRITE) 3893223637Sbz sx_xunlock(&V_pf_consistency_lock); 3894171168Smlaier else 3895223637Sbz sx_sunlock(&V_pf_consistency_lock); 3896145836Smlaier#else 3897145836Smlaier splx(s); 3898171168Smlaier if (flags & FWRITE) 3899171168Smlaier rw_exit_write(&pf_consistency_lock); 3900171168Smlaier else 3901171168Smlaier rw_exit_read(&pf_consistency_lock); 3902130613Smlaier#endif 3903223637Sbz 3904223637Sbz CURVNET_RESTORE(); 3905223637Sbz 3906126261Smlaier return (error); 3907126261Smlaier} 3908126261Smlaier 3909130613Smlaier#ifdef __FreeBSD__ 3910223637Sbzvoid 3911223637Sbzpfsync_state_export(struct pfsync_state *sp, struct pf_state *st) 3912223637Sbz{ 3913223637Sbz bzero(sp, sizeof(struct pfsync_state)); 3914223637Sbz 3915223637Sbz /* copy from state key */ 3916223637Sbz sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0]; 3917223637Sbz sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1]; 3918223637Sbz sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0]; 3919223637Sbz sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1]; 3920223637Sbz sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0]; 3921223637Sbz sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1]; 3922223637Sbz sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; 3923223637Sbz sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; 3924223637Sbz sp->proto = st->key[PF_SK_WIRE]->proto; 3925223637Sbz sp->af = st->key[PF_SK_WIRE]->af; 3926223637Sbz 3927223637Sbz /* copy from state */ 3928223637Sbz strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); 3929223637Sbz bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 3930223637Sbz sp->creation = htonl(time_second - st->creation); 3931223637Sbz sp->expire = pf_state_expires(st); 3932223637Sbz if (sp->expire <= time_second) 3933223637Sbz sp->expire = htonl(0); 3934223637Sbz else 3935223637Sbz sp->expire = htonl(sp->expire - time_second); 3936223637Sbz 3937223637Sbz sp->direction = st->direction; 3938223637Sbz sp->log = st->log; 3939223637Sbz sp->timeout = st->timeout; 3940223637Sbz sp->state_flags = st->state_flags; 3941223637Sbz if (st->src_node) 3942223637Sbz sp->sync_flags |= PFSYNC_FLAG_SRCNODE; 3943223637Sbz if (st->nat_src_node) 3944223637Sbz sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; 3945223637Sbz 3946223637Sbz bcopy(&st->id, &sp->id, sizeof(sp->id)); 3947223637Sbz sp->creatorid = st->creatorid; 3948223637Sbz pf_state_peer_hton(&st->src, &sp->src); 3949223637Sbz pf_state_peer_hton(&st->dst, &sp->dst); 3950223637Sbz 3951223637Sbz if (st->rule.ptr == NULL) 3952223637Sbz sp->rule = htonl(-1); 3953223637Sbz else 3954223637Sbz sp->rule = htonl(st->rule.ptr->nr); 3955223637Sbz if (st->anchor.ptr == NULL) 3956223637Sbz sp->anchor = htonl(-1); 3957223637Sbz else 3958223637Sbz sp->anchor = htonl(st->anchor.ptr->nr); 3959223637Sbz if (st->nat_rule.ptr == NULL) 3960223637Sbz sp->nat_rule = htonl(-1); 3961223637Sbz else 3962223637Sbz sp->nat_rule = htonl(st->nat_rule.ptr->nr); 3963223637Sbz 3964223637Sbz pf_state_counter_hton(st->packets[0], sp->packets[0]); 3965223637Sbz pf_state_counter_hton(st->packets[1], sp->packets[1]); 3966223637Sbz pf_state_counter_hton(st->bytes[0], sp->bytes[0]); 3967223637Sbz pf_state_counter_hton(st->bytes[1], sp->bytes[1]); 3968223637Sbz 3969223637Sbz} 3970223637Sbz 3971130613Smlaier/* 3972130613Smlaier * XXX - Check for version missmatch!!! 3973130613Smlaier */ 3974126261Smlaierstatic void 3975130613Smlaierpf_clear_states(void) 3976126261Smlaier{ 3977223637Sbz struct pf_state *state; 3978223637Sbz 3979223637Sbz#ifdef __FreeBSD__ 3980223637Sbz RB_FOREACH(state, pf_state_tree_id, &V_tree_id) { 3981223637Sbz#else 3982130613Smlaier RB_FOREACH(state, pf_state_tree_id, &tree_id) { 3983223637Sbz#endif 3984130613Smlaier state->timeout = PFTM_PURGE; 3985130613Smlaier#if NPFSYNC 3986130613Smlaier /* don't send out individual delete messages */ 3987223637Sbz state->sync_state = PFSTATE_NOSYNC; 3988130613Smlaier#endif 3989171168Smlaier pf_unlink_state(state); 3990130613Smlaier } 3991223637Sbz 3992130613Smlaier#if 0 /* NPFSYNC */ 3993130613Smlaier/* 3994130613Smlaier * XXX This is called on module unload, we do not want to sync that over? */ 3995130613Smlaier */ 3996223637Sbz pfsync_clear_states(V_pf_status.hostid, psk->psk_ifname); 3997130613Smlaier#endif 3998126261Smlaier} 3999126261Smlaier 4000126261Smlaierstatic int 4001130613Smlaierpf_clear_tables(void) 4002126261Smlaier{ 4003130613Smlaier struct pfioc_table io; 4004126261Smlaier int error; 4005126261Smlaier 4006130613Smlaier bzero(&io, sizeof(io)); 4007126261Smlaier 4008130613Smlaier error = pfr_clr_tables(&io.pfrio_table, &io.pfrio_ndel, 4009130613Smlaier io.pfrio_flags); 4010130613Smlaier 4011126261Smlaier return (error); 4012126261Smlaier} 4013126261Smlaier 4014130613Smlaierstatic void 4015130613Smlaierpf_clear_srcnodes(void) 4016130613Smlaier{ 4017130613Smlaier struct pf_src_node *n; 4018130613Smlaier struct pf_state *state; 4019130613Smlaier 4020223637Sbz#ifdef __FreeBSD__ 4021223637Sbz RB_FOREACH(state, pf_state_tree_id, &V_tree_id) { 4022223637Sbz#else 4023130613Smlaier RB_FOREACH(state, pf_state_tree_id, &tree_id) { 4024223637Sbz#endif 4025130613Smlaier state->src_node = NULL; 4026130613Smlaier state->nat_src_node = NULL; 4027130613Smlaier } 4028223637Sbz#ifdef __FreeBSD__ 4029223637Sbz RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) { 4030223637Sbz#else 4031130613Smlaier RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { 4032223637Sbz#endif 4033130613Smlaier n->expire = 1; 4034130613Smlaier n->states = 0; 4035130613Smlaier } 4036130613Smlaier} 4037130613Smlaier/* 4038130613Smlaier * XXX - Check for version missmatch!!! 4039130613Smlaier */ 4040130613Smlaier 4041130613Smlaier/* 4042130613Smlaier * Duplicate pfctl -Fa operation to get rid of as much as we can. 4043130613Smlaier */ 4044126261Smlaierstatic int 4045126261Smlaiershutdown_pf(void) 4046126261Smlaier{ 4047126261Smlaier int error = 0; 4048130613Smlaier u_int32_t t[5]; 4049130613Smlaier char nn = '\0'; 4050223637Sbz 4051223637Sbz V_pf_status.running = 0; 4052126261Smlaier do { 4053145836Smlaier if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn)) 4054145836Smlaier != 0) { 4055130613Smlaier DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: SCRUB\n")); 4056126261Smlaier break; 4057126261Smlaier } 4058145836Smlaier if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn)) 4059145836Smlaier != 0) { 4060130613Smlaier DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: FILTER\n")); 4061223637Sbz break; /* XXX: rollback? */ 4062126261Smlaier } 4063145836Smlaier if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn)) 4064130613Smlaier != 0) { 4065130613Smlaier DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: NAT\n")); 4066223637Sbz break; /* XXX: rollback? */ 4067126261Smlaier } 4068145836Smlaier if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn)) 4069130613Smlaier != 0) { 4070130613Smlaier DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: BINAT\n")); 4071223637Sbz break; /* XXX: rollback? */ 4072126261Smlaier } 4073145836Smlaier if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn)) 4074130613Smlaier != 0) { 4075130613Smlaier DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: RDR\n")); 4076223637Sbz break; /* XXX: rollback? */ 4077126261Smlaier } 4078126261Smlaier 4079130613Smlaier /* XXX: these should always succeed here */ 4080145836Smlaier pf_commit_rules(t[0], PF_RULESET_SCRUB, &nn); 4081145836Smlaier pf_commit_rules(t[1], PF_RULESET_FILTER, &nn); 4082145836Smlaier pf_commit_rules(t[2], PF_RULESET_NAT, &nn); 4083145836Smlaier pf_commit_rules(t[3], PF_RULESET_BINAT, &nn); 4084145836Smlaier pf_commit_rules(t[4], PF_RULESET_RDR, &nn); 4085126261Smlaier 4086130613Smlaier if ((error = pf_clear_tables()) != 0) 4087126261Smlaier break; 4088126261Smlaier 4089223637Sbz #ifdef ALTQ 4090130613Smlaier if ((error = pf_begin_altq(&t[0])) != 0) { 4091130613Smlaier DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n")); 4092126261Smlaier break; 4093126261Smlaier } 4094130613Smlaier pf_commit_altq(t[0]); 4095223637Sbz #endif 4096126261Smlaier 4097130613Smlaier pf_clear_states(); 4098130613Smlaier 4099130613Smlaier pf_clear_srcnodes(); 4100130613Smlaier 4101130613Smlaier /* status does not use malloced mem so no need to cleanup */ 4102130613Smlaier /* fingerprints and interfaces have thier own cleanup code */ 4103126261Smlaier } while(0); 4104126261Smlaier 4105223637Sbz return (error); 4106126261Smlaier} 4107126261Smlaier 4108221132Sbz#ifdef INET 4109126261Smlaierstatic int 4110135920Smlaierpf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 4111135920Smlaier struct inpcb *inp) 4112126261Smlaier{ 4113126261Smlaier /* 4114126261Smlaier * XXX Wed Jul 9 22:03:16 2003 UTC 4115126261Smlaier * OpenBSD has changed its byte ordering convention on ip_len/ip_off 4116126261Smlaier * in network stack. OpenBSD's network stack have converted 4117126261Smlaier * ip_len/ip_off to host byte order frist as FreeBSD. 4118126261Smlaier * Now this is not true anymore , so we should convert back to network 4119126261Smlaier * byte order. 4120126261Smlaier */ 4121126261Smlaier struct ip *h = NULL; 4122126261Smlaier int chk; 4123126261Smlaier 4124126261Smlaier if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) { 4125126261Smlaier /* if m_pkthdr.len is less than ip header, pf will handle. */ 4126126261Smlaier h = mtod(*m, struct ip *); 4127223637Sbz HTONS(h->ip_len); 4128223637Sbz HTONS(h->ip_off); 4129126261Smlaier } 4130223637Sbz CURVNET_SET(ifp->if_vnet); 4131145836Smlaier chk = pf_test(PF_IN, ifp, m, NULL, inp); 4132223637Sbz CURVNET_RESTORE(); 4133126261Smlaier if (chk && *m) { 4134126261Smlaier m_freem(*m); 4135126261Smlaier *m = NULL; 4136126261Smlaier } 4137126261Smlaier if (*m != NULL) { 4138126261Smlaier /* pf_test can change ip header location */ 4139126261Smlaier h = mtod(*m, struct ip *); 4140126261Smlaier NTOHS(h->ip_len); 4141126261Smlaier NTOHS(h->ip_off); 4142126261Smlaier } 4143126261Smlaier return chk; 4144126261Smlaier} 4145126261Smlaier 4146126261Smlaierstatic int 4147135920Smlaierpf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 4148135920Smlaier struct inpcb *inp) 4149126261Smlaier{ 4150126261Smlaier /* 4151126261Smlaier * XXX Wed Jul 9 22:03:16 2003 UTC 4152126261Smlaier * OpenBSD has changed its byte ordering convention on ip_len/ip_off 4153126261Smlaier * in network stack. OpenBSD's network stack have converted 4154126261Smlaier * ip_len/ip_off to host byte order frist as FreeBSD. 4155126261Smlaier * Now this is not true anymore , so we should convert back to network 4156126261Smlaier * byte order. 4157126261Smlaier */ 4158126261Smlaier struct ip *h = NULL; 4159126261Smlaier int chk; 4160126261Smlaier 4161126261Smlaier if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) { 4162126261Smlaier /* if m_pkthdr.len is less than ip header, pf will handle. */ 4163126261Smlaier h = mtod(*m, struct ip *); 4164223637Sbz HTONS(h->ip_len); 4165223637Sbz HTONS(h->ip_off); 4166126261Smlaier } 4167223637Sbz CURVNET_SET(ifp->if_vnet); 4168145836Smlaier chk = pf_test(PF_OUT, ifp, m, NULL, inp); 4169223637Sbz CURVNET_RESTORE(); 4170126261Smlaier if (chk && *m) { 4171126261Smlaier m_freem(*m); 4172126261Smlaier *m = NULL; 4173126261Smlaier } 4174126261Smlaier if (*m != NULL) { 4175126261Smlaier /* pf_test can change ip header location */ 4176126261Smlaier h = mtod(*m, struct ip *); 4177126261Smlaier NTOHS(h->ip_len); 4178126261Smlaier NTOHS(h->ip_off); 4179126261Smlaier } 4180126261Smlaier return chk; 4181126261Smlaier} 4182221132Sbz#endif 4183126261Smlaier 4184126261Smlaier#ifdef INET6 4185126261Smlaierstatic int 4186135920Smlaierpf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 4187135920Smlaier struct inpcb *inp) 4188126261Smlaier{ 4189183550Szec 4190126261Smlaier /* 4191162069Smlaier * IPv6 is not affected by ip_len/ip_off byte order changes. 4192126261Smlaier */ 4193126261Smlaier int chk; 4194126261Smlaier 4195162069Smlaier /* 4196162069Smlaier * In case of loopback traffic IPv6 uses the real interface in 4197162069Smlaier * order to support scoped addresses. In order to support stateful 4198162069Smlaier * filtering we have change this to lo0 as it is the case in IPv4. 4199162069Smlaier */ 4200223637Sbz CURVNET_SET(ifp->if_vnet); 4201193274Szec chk = pf_test6(PF_IN, (*m)->m_flags & M_LOOP ? V_loif : ifp, m, 4202162069Smlaier NULL, inp); 4203223637Sbz CURVNET_RESTORE(); 4204126261Smlaier if (chk && *m) { 4205126261Smlaier m_freem(*m); 4206126261Smlaier *m = NULL; 4207126261Smlaier } 4208126261Smlaier return chk; 4209126261Smlaier} 4210126261Smlaier 4211126261Smlaierstatic int 4212135920Smlaierpf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 4213135920Smlaier struct inpcb *inp) 4214126261Smlaier{ 4215126261Smlaier /* 4216126261Smlaier * IPv6 does not affected ip_len/ip_off byte order changes. 4217126261Smlaier */ 4218126261Smlaier int chk; 4219126261Smlaier 4220223637Sbz CURVNET_SET(ifp->if_vnet); 4221145836Smlaier chk = pf_test6(PF_OUT, ifp, m, NULL, inp); 4222223637Sbz CURVNET_RESTORE(); 4223126261Smlaier if (chk && *m) { 4224126261Smlaier m_freem(*m); 4225126261Smlaier *m = NULL; 4226126261Smlaier } 4227126261Smlaier return chk; 4228126261Smlaier} 4229126261Smlaier#endif /* INET6 */ 4230126261Smlaier 4231126261Smlaierstatic int 4232126261Smlaierhook_pf(void) 4233126261Smlaier{ 4234223637Sbz#ifdef INET 4235126261Smlaier struct pfil_head *pfh_inet; 4236223637Sbz#endif 4237127145Smlaier#ifdef INET6 4238126261Smlaier struct pfil_head *pfh_inet6; 4239126261Smlaier#endif 4240223637Sbz 4241226801Sglebius PF_UNLOCK_ASSERT(); 4242126261Smlaier 4243223637Sbz if (V_pf_pfil_hooked) 4244126261Smlaier return (0); 4245223637Sbz 4246223637Sbz#ifdef INET 4247126261Smlaier pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 4248126261Smlaier if (pfh_inet == NULL) 4249126261Smlaier return (ESRCH); /* XXX */ 4250126261Smlaier pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); 4251126261Smlaier pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); 4252221132Sbz#endif 4253127145Smlaier#ifdef INET6 4254126261Smlaier pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 4255126261Smlaier if (pfh_inet6 == NULL) { 4256221132Sbz#ifdef INET 4257126261Smlaier pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, 4258126261Smlaier pfh_inet); 4259126261Smlaier pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 4260126261Smlaier pfh_inet); 4261221132Sbz#endif 4262126261Smlaier return (ESRCH); /* XXX */ 4263126261Smlaier } 4264126261Smlaier pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); 4265126261Smlaier pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); 4266126261Smlaier#endif 4267126261Smlaier 4268223637Sbz V_pf_pfil_hooked = 1; 4269126261Smlaier return (0); 4270126261Smlaier} 4271126261Smlaier 4272126261Smlaierstatic int 4273126261Smlaierdehook_pf(void) 4274126261Smlaier{ 4275223637Sbz#ifdef INET 4276126261Smlaier struct pfil_head *pfh_inet; 4277223637Sbz#endif 4278127145Smlaier#ifdef INET6 4279126261Smlaier struct pfil_head *pfh_inet6; 4280126261Smlaier#endif 4281126261Smlaier 4282226801Sglebius PF_UNLOCK_ASSERT(); 4283126261Smlaier 4284223637Sbz if (V_pf_pfil_hooked == 0) 4285126261Smlaier return (0); 4286126261Smlaier 4287223637Sbz#ifdef INET 4288126261Smlaier pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 4289126261Smlaier if (pfh_inet == NULL) 4290126261Smlaier return (ESRCH); /* XXX */ 4291126261Smlaier pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, 4292126261Smlaier pfh_inet); 4293126261Smlaier pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 4294126261Smlaier pfh_inet); 4295221132Sbz#endif 4296127145Smlaier#ifdef INET6 4297126261Smlaier pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 4298126261Smlaier if (pfh_inet6 == NULL) 4299126261Smlaier return (ESRCH); /* XXX */ 4300126261Smlaier pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, 4301126261Smlaier pfh_inet6); 4302126261Smlaier pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, 4303126261Smlaier pfh_inet6); 4304126261Smlaier#endif 4305126261Smlaier 4306223637Sbz V_pf_pfil_hooked = 0; 4307126261Smlaier return (0); 4308126261Smlaier} 4309126261Smlaier 4310126261Smlaierstatic int 4311230868Sglebiuspf_load(void) 4312223637Sbz{ 4313230868Sglebius VNET_ITERATOR_DECL(vnet_iter); 4314223637Sbz 4315230868Sglebius VNET_LIST_RLOCK(); 4316230868Sglebius VNET_FOREACH(vnet_iter) { 4317230868Sglebius CURVNET_SET(vnet_iter); 4318230868Sglebius V_pf_pfil_hooked = 0; 4319230868Sglebius V_pf_end_threads = 0; 4320230868Sglebius V_debug_pfugidhack = 0; 4321230868Sglebius TAILQ_INIT(&V_pf_tags); 4322230868Sglebius TAILQ_INIT(&V_pf_qids); 4323230868Sglebius CURVNET_RESTORE(); 4324230868Sglebius } 4325230868Sglebius VNET_LIST_RUNLOCK(); 4326223637Sbz 4327230868Sglebius init_pf_mutex(); 4328230868Sglebius pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME); 4329126261Smlaier init_zone_var(); 4330223637Sbz sx_init(&V_pf_consistency_lock, "pf_statetbl_lock"); 4331226801Sglebius if (pfattach() < 0) 4332126261Smlaier return (ENOMEM); 4333223637Sbz 4334126261Smlaier return (0); 4335126261Smlaier} 4336126261Smlaier 4337126261Smlaierstatic int 4338126261Smlaierpf_unload(void) 4339126261Smlaier{ 4340126261Smlaier int error = 0; 4341126261Smlaier 4342126261Smlaier PF_LOCK(); 4343223637Sbz V_pf_status.running = 0; 4344126261Smlaier PF_UNLOCK(); 4345230868Sglebius m_addr_chg_pf_p = NULL; 4346126261Smlaier error = dehook_pf(); 4347126261Smlaier if (error) { 4348126261Smlaier /* 4349126261Smlaier * Should not happen! 4350126261Smlaier * XXX Due to error code ESRCH, kldunload will show 4351126261Smlaier * a message like 'No such process'. 4352126261Smlaier */ 4353126261Smlaier printf("%s : pfil unregisteration fail\n", __FUNCTION__); 4354126261Smlaier return error; 4355126261Smlaier } 4356130613Smlaier PF_LOCK(); 4357126261Smlaier shutdown_pf(); 4358223637Sbz V_pf_end_threads = 1; 4359223637Sbz while (V_pf_end_threads < 2) { 4360171168Smlaier wakeup_one(pf_purge_thread); 4361226801Sglebius msleep(pf_purge_thread, &pf_task_mtx, 0, "pftmo", hz); 4362171168Smlaier } 4363173822Smlaier pfi_cleanup(); 4364130613Smlaier pf_osfp_flush(); 4365130613Smlaier pf_osfp_cleanup(); 4366126261Smlaier cleanup_pf_zone(); 4367130613Smlaier PF_UNLOCK(); 4368230868Sglebius destroy_dev(pf_dev); 4369230868Sglebius destroy_pf_mutex(); 4370223637Sbz sx_destroy(&V_pf_consistency_lock); 4371126261Smlaier return error; 4372126261Smlaier} 4373126261Smlaier 4374126261Smlaierstatic int 4375126261Smlaierpf_modevent(module_t mod, int type, void *data) 4376126261Smlaier{ 4377126261Smlaier int error = 0; 4378126261Smlaier 4379126261Smlaier switch(type) { 4380126261Smlaier case MOD_LOAD: 4381230868Sglebius error = pf_load(); 4382126261Smlaier break; 4383230868Sglebius case MOD_QUIESCE: 4384230868Sglebius /* 4385230868Sglebius * Module should not be unloaded due to race conditions. 4386230868Sglebius */ 4387230868Sglebius error = EPERM; 4388230868Sglebius break; 4389126261Smlaier case MOD_UNLOAD: 4390230868Sglebius error = pf_unload(); 4391126261Smlaier break; 4392126261Smlaier default: 4393126261Smlaier error = EINVAL; 4394126261Smlaier break; 4395126261Smlaier } 4396126261Smlaier return error; 4397126261Smlaier} 4398223637Sbz 4399126261Smlaierstatic moduledata_t pf_mod = { 4400126261Smlaier "pf", 4401126261Smlaier pf_modevent, 4402126261Smlaier 0 4403126261Smlaier}; 4404126261Smlaier 4405226801SglebiusDECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_FIRST); 4406126261SmlaierMODULE_VERSION(pf, PF_MODVER); 4407223637Sbz#endif /* __FreeBSD__ */ 4408