pf_ioctl.c revision 126812
1189251Ssam/* $FreeBSD: head/sys/contrib/pf/net/pf_ioctl.c 126812 2004-03-10 15:08:21Z mlaier $ */ 2189251Ssam/* $OpenBSD: pf_ioctl.c,v 1.81 2003/08/22 21:50:34 david Exp $ */ 3189251Ssam 4189251Ssam/* 5252726Srpaulo * Copyright (c) 2001 Daniel Hartmeier 6252726Srpaulo * All rights reserved. 7189251Ssam * 8189251Ssam * Redistribution and use in source and binary forms, with or without 9189251Ssam * modification, are permitted provided that the following conditions 10189251Ssam * are met: 11189251Ssam * 12252726Srpaulo * - Redistributions of source code must retain the above copyright 13252726Srpaulo * notice, this list of conditions and the following disclaimer. 14189251Ssam * - Redistributions in binary form must reproduce the above 15252726Srpaulo * copyright notice, this list of conditions and the following 16214734Srpaulo * disclaimer in the documentation and/or other materials provided 17252726Srpaulo * with the distribution. 18189251Ssam * 19214734Srpaulo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20252726Srpaulo * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21252726Srpaulo * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22252726Srpaulo * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23252726Srpaulo * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24252726Srpaulo * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25252726Srpaulo * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26252726Srpaulo * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27252726Srpaulo * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28252726Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29252726Srpaulo * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30252726Srpaulo * POSSIBILITY OF SUCH DAMAGE. 31252726Srpaulo * 32252726Srpaulo * Effort sponsored in part by the Defense Advanced Research Projects 33252726Srpaulo * Agency (DARPA) and Air Force Research Laboratory, Air Force 34252726Srpaulo * Materiel Command, USAF, under agreement number F30602-01-2-0537. 35252726Srpaulo * 36252726Srpaulo */ 37252726Srpaulo 38252726Srpaulo#if defined(__FreeBSD__) 39252726Srpaulo#include "opt_inet.h" 40252726Srpaulo#include "opt_inet6.h" 41252726Srpaulo#endif 42252726Srpaulo 43252726Srpaulo#include <sys/param.h> 44252726Srpaulo#include <sys/systm.h> 45252726Srpaulo#include <sys/mbuf.h> 46252726Srpaulo#include <sys/filio.h> 47252726Srpaulo#include <sys/fcntl.h> 48252726Srpaulo#include <sys/socket.h> 49252726Srpaulo#include <sys/socketvar.h> 50252726Srpaulo#include <sys/kernel.h> 51252726Srpaulo#include <sys/time.h> 52252726Srpaulo#include <sys/malloc.h> 53252726Srpaulo#if defined(__FreeBSD__) 54252726Srpaulo#include <sys/conf.h> 55252726Srpaulo#else 56252726Srpaulo#include <sys/timeout.h> 57252726Srpaulo#include <sys/pool.h> 58252726Srpaulo#endif 59252726Srpaulo 60252726Srpaulo#include <net/if.h> 61252726Srpaulo#include <net/if_types.h> 62252726Srpaulo#include <net/route.h> 63252726Srpaulo 64252726Srpaulo#include <netinet/in.h> 65252726Srpaulo#include <netinet/in_var.h> 66252726Srpaulo#include <netinet/in_systm.h> 67252726Srpaulo#include <netinet/ip.h> 68252726Srpaulo#include <netinet/ip_var.h> 69252726Srpaulo#include <netinet/ip_icmp.h> 70252726Srpaulo 71252726Srpaulo#include <net/pfvar.h> 72252726Srpaulo 73252726Srpaulo#ifdef INET6 74252726Srpaulo#include <netinet/ip6.h> 75252726Srpaulo#include <netinet/in_pcb.h> 76252726Srpaulo#if defined(__FreeBSD__) && (__FreeBSD_version < 501108) 77252726Srpaulo#include <netinet6/ip6protosw.h> 78252726Srpaulo#endif 79252726Srpaulo#endif /* INET6 */ 80252726Srpaulo 81252726Srpaulo#ifdef ALTQ 82252726Srpaulo#include <altq/altq.h> 83252726Srpaulo#endif 84252726Srpaulo 85252726Srpaulo#if defined(__FreeBSD__) 86252726Srpaulo#if (__FreeBSD_version >= 500112) 87252726Srpaulo#include <sys/limits.h> 88252726Srpaulo#else 89252726Srpaulo#include <machine/limits.h> 90252726Srpaulo#endif 91252726Srpaulo#include <sys/lock.h> 92252726Srpaulo#include <sys/mutex.h> 93252726Srpaulo#if __FreeBSD_version < 501108 94252726Srpaulo#include <sys/protosw.h> 95252726Srpaulo#endif 96252726Srpaulo#include <net/pfil.h> 97252726Srpaulo#endif /* __FreeBSD__ */ 98252726Srpaulo 99252726Srpaulo#if defined(__FreeBSD__) 100252726Srpaulovoid init_zone_var(void); 101252726Srpaulovoid cleanup_pf_zone(void); 102252726Srpauloint pfattach(void); 103252726Srpaulo#else 104252726Srpaulovoid pfattach(int); 105252726Srpauloint pfopen(dev_t, int, int, struct proc *); 106252726Srpauloint pfclose(dev_t, int, int, struct proc *); 107252726Srpaulo#endif 108252726Srpaulostruct pf_pool *pf_get_pool(char *, char *, u_int32_t, 109252726Srpaulo u_int8_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t); 110252726Srpauloint pf_get_ruleset_number(u_int8_t); 111252726Srpaulovoid pf_init_ruleset(struct pf_ruleset *); 112252726Srpaulovoid pf_mv_pool(struct pf_palist *, struct pf_palist *); 113252726Srpaulovoid pf_empty_pool(struct pf_palist *); 114252726Srpaulo#if defined(__FreeBSD__) 115252726Srpauloint pfioctl(dev_t, u_long, caddr_t, int, struct thread *); 116252726Srpaulo#else 117252726Srpauloint pfioctl(dev_t, u_long, caddr_t, int, struct proc *); 118252726Srpaulo#endif 119252726Srpaulo 120252726Srpaulo#if defined(__FreeBSD__) 121252726Srpauloextern struct callout pf_expire_to; 122252726Srpaulo#if __FreeBSD_version < 501108 123252726Srpauloextern struct protosw inetsw[]; 124252726Srpaulo#endif 125252726Srpaulo#else 126252726Srpauloextern struct timeout pf_expire_to; 127252726Srpaulo#endif 128252726Srpaulo 129252726Srpaulostruct pf_rule pf_default_rule; 130252726Srpaulo 131252726Srpaulo#define TAGID_MAX 50000 132252726SrpauloTAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags); 133189251Ssam 134189251Ssam#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x 135189251Ssam 136189251Ssam 137189251Ssam#if defined(__FreeBSD__) 138189251Ssamstatic dev_t pf_dev; 139189251Ssam 140189251Ssam/* 141189251Ssam * XXX - These are new and need to be checked when moveing to a new version 142189251Ssam */ 143189251Ssamstatic int pf_beginrules(void *addr); 144189251Ssamstatic int pf_commitrules(void *addr); 145189251Ssam#if defined(ALTQ) 146189251Ssamstatic int pf_beginaltqs(void *addr); 147189251Ssamstatic int pf_commitaltqs(void *addr); 148189251Ssamstatic int pf_stopaltq(void); 149189251Ssam#endif 150189251Ssamstatic void pf_clearstates(void); 151189251Ssamstatic int pf_clear_tables(void *addr); 152189251Ssam/* 153189251Ssam * XXX - These are new and need to be checked when moveing to a new version 154189251Ssam */ 155189251Ssam 156189251Ssam#if (__FreeBSD_version < 501108) 157189251Ssamstatic int pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir, 158189251Ssam struct mbuf **m); 159189251Ssamstatic int pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir, 160189251Ssam struct mbuf **m); 161189251Ssam#if defined(INET6) 162189251Ssamstatic int pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir, 163189251Ssam struct mbuf **m); 164189251Ssamstatic int pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir, 165189251Ssam struct mbuf **m); 166189251Ssam#endif 167189251Ssam#else /* (__FreeBSD_version >= 501108) */ 168189251Ssamstatic int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, 169189251Ssam int dir); 170189251Ssamstatic int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, 171189251Ssam int dir); 172189251Ssam#if defined(INET6) 173189251Ssamstatic int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, 174189251Ssam int dir); 175189251Ssamstatic int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, 176189251Ssam int dir); 177189251Ssam#endif 178189251Ssam#endif /* (__FreeBSD_version >= 501108) */ 179189251Ssamstatic int hook_pf(void); 180189251Ssamstatic int dehook_pf(void); 181189251Ssamstatic int shutdown_pf(void); 182189251Ssamstatic int pf_load(void); 183189251Ssamstatic int pf_unload(void); 184189251Ssam 185189251Ssam 186189251Ssam 187189251Ssamstatic struct cdevsw pf_cdevsw = { 188189251Ssam#if (__FreeBSD_version < 500105) 189189251Ssam /* open */ noopen, 190189251Ssam /* close */ noclose, 191189251Ssam /* read */ noread, 192189251Ssam /* write */ nowrite, 193189251Ssam /* ioctl */ pfioctl, 194189251Ssam /* poll */ nopoll, 195189251Ssam /* mmap */ nommap, 196189251Ssam /* strategy */ nostrategy, 197189251Ssam /* name */ PF_NAME, 198189251Ssam /* maj */ PF_CDEV_MAJOR, 199189251Ssam /* dump */ nodump, 200189251Ssam /* psize */ nopsize, 201189251Ssam /* flags */ 0, 202189251Ssam /* kqfilter */ nokqfilter, 203189251Ssam#elif (__FreeBSD_version < 501110) 204189251Ssam .d_open = noopen, 205189251Ssam .d_close = noclose, 206189251Ssam .d_read = noread, 207189251Ssam .d_write = nowrite, 208189251Ssam .d_ioctl = pfioctl, 209189251Ssam .d_poll = nopoll, 210189251Ssam .d_mmap = nommap, 211189251Ssam .d_strategy = nostrategy, 212189251Ssam .d_name = PF_NAME, 213189251Ssam .d_maj = MAJOR_AUTO, /* PF_CDEV_MAJOR */ 214189251Ssam .d_dump = nodump, 215189251Ssam .d_flags = 0, 216189251Ssam .d_kqfilter = nokqfilter, 217189251Ssam#else 218189251Ssam .d_ioctl = pfioctl, 219189251Ssam .d_name = PF_NAME, 220189251Ssam .d_version = D_VERSION, 221189251Ssam#endif 222189251Ssam}; 223189251Ssam#endif /* __FreeBSD__ */ 224189251Ssam 225189251Ssam#if defined(__FreeBSD__) 226214734Srpaulostatic volatile int pf_pfil_hooked = 0; 227189251Ssamstruct mtx pf_task_mtx; 228189251Ssam 229189251Ssamvoid 230189251Ssaminit_pf_mutex(void) 231189251Ssam{ 232189251Ssam mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF); 233189251Ssam/* 234189251Ssam * pf_altq_mtx is initialized at altq_subr.c. 235189251Ssam * 236189251Ssam * #if defined(ALTQ) && !defined(ALTQ3_COMPAT) 237189251Ssam * mtx_init(&pf_altq_mtx, "pf altq mtx", NULL, MTX_DEF); 238189251Ssam * #endif 239189251Ssam */ 240189251Ssam} 241189251Ssam 242189251Ssamvoid 243189251Ssamdestroy_pf_mutex(void) 244189251Ssam{ 245189251Ssam mtx_destroy(&pf_task_mtx); 246189251Ssam/* 247189251Ssam * pf_altq_mtx is initialized at altq_subr.c. 248189251Ssam * 249189251Ssam * #if defined(ALTQ) && !defined(ALTQ3_COMPAT) 250189251Ssam * mtx_destroy(&pf_altq_mtx); 251189251Ssam * #endif 252189251Ssam */ 253189251Ssam} 254189251Ssam 255189251Ssamvoid 256189251Ssaminit_zone_var(void) 257189251Ssam{ 258189251Ssam pf_tree_pl = pf_rule_pl = pf_addr_pl = NULL; 259189251Ssam pf_state_pl = pf_altq_pl = pf_pooladdr_pl = NULL; 260189251Ssam pf_frent_pl = pf_frag_pl = pf_cache_pl = pf_cent_pl = NULL; 261189251Ssam pf_state_scrub_pl = NULL; 262189251Ssam pfr_ktable_pl = pfr_kentry_pl = NULL; 263189251Ssam} 264189251Ssam 265214734Srpaulovoid 266252726Srpaulocleanup_pf_zone(void) 267252726Srpaulo{ 268252726Srpaulo UMA_DESTROY(pf_tree_pl); 269252726Srpaulo UMA_DESTROY(pf_rule_pl); 270214734Srpaulo UMA_DESTROY(pf_addr_pl); 271214734Srpaulo UMA_DESTROY(pf_state_pl); 272214734Srpaulo UMA_DESTROY(pf_altq_pl); 273214734Srpaulo UMA_DESTROY(pf_pooladdr_pl); 274214734Srpaulo UMA_DESTROY(pf_frent_pl); 275252726Srpaulo UMA_DESTROY(pf_frag_pl); 276214734Srpaulo UMA_DESTROY(pf_cache_pl); 277189251Ssam UMA_DESTROY(pf_cent_pl); 278189251Ssam UMA_DESTROY(pfr_ktable_pl); 279189251Ssam UMA_DESTROY(pfr_kentry_pl); 280189251Ssam UMA_DESTROY(pf_state_scrub_pl); 281189251Ssam} 282189251Ssam#endif /* __FreeBSD__ */ 283189251Ssam 284189251Ssam#if defined(__FreeBSD__) 285189251Ssamint 286189251Ssampfattach(void) 287189251Ssam{ 288189251Ssam u_int32_t *my_timeout = pf_default_rule.timeout; 289189251Ssam int error = 1; 290189251Ssam 291189251Ssam do { 292189251Ssam UMA_CREATE(pf_tree_pl, struct pf_tree_node, "pftrpl"); 293189251Ssam UMA_CREATE(pf_rule_pl, struct pf_rule, "pfrulepl"); 294189251Ssam UMA_CREATE(pf_addr_pl, struct pf_addr_dyn, "pfaddrpl"); 295189251Ssam UMA_CREATE(pf_state_pl, struct pf_state, "pfstatepl"); 296189251Ssam UMA_CREATE(pf_altq_pl, struct pf_altq, "pfaltqpl"); 297189251Ssam UMA_CREATE(pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl"); 298189251Ssam UMA_CREATE(pfr_ktable_pl, struct pfr_ktable, "pfrktable"); 299189251Ssam UMA_CREATE(pfr_kentry_pl, struct pfr_kentry, "pfrkentry"); 300189251Ssam UMA_CREATE(pf_frent_pl, struct pf_frent, "pffrent"); 301189251Ssam UMA_CREATE(pf_frag_pl, struct pf_fragment, "pffrag"); 302189251Ssam UMA_CREATE(pf_cache_pl, struct pf_fragment, "pffrcache"); 303189251Ssam UMA_CREATE(pf_cent_pl, struct pf_frcache, "pffrcent"); 304189251Ssam UMA_CREATE(pf_state_scrub_pl, struct pf_state_scrub, 305189251Ssam "pfstatescrub"); 306189251Ssam error = 0; 307189251Ssam } while(0); 308189251Ssam if (error) { 309189251Ssam cleanup_pf_zone(); 310189251Ssam return (error); 311189251Ssam } 312189251Ssam pfr_initialize(); 313189251Ssam if ( (error = pf_osfp_initialize()) ) { 314189251Ssam cleanup_pf_zone(); 315189251Ssam pf_osfp_cleanup(); 316189251Ssam return (error); 317189251Ssam } 318189251Ssam 319189251Ssam pf_pool_limits[PF_LIMIT_STATES].pp = pf_state_pl; 320189251Ssam pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT; 321189251Ssam pf_pool_limits[PF_LIMIT_FRAGS].pp = pf_frent_pl; 322189251Ssam pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT; 323189251Ssam uma_zone_set_max(pf_pool_limits[PF_LIMIT_STATES].pp, 324189251Ssam pf_pool_limits[PF_LIMIT_STATES].limit); 325189251Ssam 326189251Ssam RB_INIT(&tree_lan_ext); 327189251Ssam RB_INIT(&tree_ext_gwy); 328189251Ssam TAILQ_INIT(&pf_anchors); 329189251Ssam pf_init_ruleset(&pf_main_ruleset); 330189251Ssam TAILQ_INIT(&pf_altqs[0]); 331189251Ssam TAILQ_INIT(&pf_altqs[1]); 332189251Ssam TAILQ_INIT(&pf_pabuf); 333189251Ssam pf_altqs_active = &pf_altqs[0]; 334189251Ssam pf_altqs_inactive = &pf_altqs[1]; 335189251Ssam 336189251Ssam /* default rule should never be garbage collected */ 337189251Ssam pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; 338189251Ssam pf_default_rule.action = PF_PASS; 339189251Ssam pf_default_rule.nr = -1; 340189251Ssam 341189251Ssam /* initialize default timeouts */ 342189251Ssam my_timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */ 343189251Ssam my_timeout[PFTM_TCP_OPENING] = 30; /* No response yet */ 344189251Ssam my_timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */ 345189251Ssam my_timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */ 346189251Ssam my_timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */ 347189251Ssam my_timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */ 348189251Ssam my_timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */ 349189251Ssam my_timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */ 350189251Ssam my_timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */ 351189251Ssam my_timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */ 352189251Ssam my_timeout[PFTM_ICMP_ERROR_REPLY] = 10; /* Got error response */ 353189251Ssam my_timeout[PFTM_OTHER_FIRST_PACKET] = 60; /* First packet */ 354189251Ssam my_timeout[PFTM_OTHER_SINGLE] = 30; /* Unidirectional */ 355189251Ssam my_timeout[PFTM_OTHER_MULTIPLE] = 60; /* Bidirectional */ 356189251Ssam my_timeout[PFTM_FRAG] = 30; /* Fragment expire */ 357189251Ssam my_timeout[PFTM_INTERVAL] = 10; /* Expire interval */ 358189251Ssam 359189251Ssam /* 360189251Ssam * XXX 361189251Ssam * The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE 362189251Ssam * if Gaint lock is removed from the network stack. 363189251Ssam */ 364189251Ssam callout_init(&pf_expire_to, 0); 365189251Ssam callout_reset(&pf_expire_to, my_timeout[PFTM_INTERVAL] * hz, 366189251Ssam pf_purge_timeout, &pf_expire_to); 367189251Ssam 368189251Ssam pf_normalize_init(); 369189251Ssam pf_status.debug = PF_DEBUG_URGENT; 370189251Ssam pf_pfil_hooked = 0; 371189251Ssam return (error); 372189251Ssam} 373189251Ssam#else /* !__FreeBSD__ */ 374189251Ssamvoid 375189251Ssampfattach(int num) 376189251Ssam{ 377189251Ssam u_int32_t *timeout = pf_default_rule.timeout; 378189251Ssam 379189251Ssam pool_init(&pf_tree_pl, sizeof(struct pf_tree_node), 0, 0, 0, "pftrpl", 380189251Ssam NULL); 381189251Ssam pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl", 382189251Ssam &pool_allocator_nointr); 383189251Ssam pool_init(&pf_addr_pl, sizeof(struct pf_addr_dyn), 0, 0, 0, "pfaddrpl", 384189251Ssam &pool_allocator_nointr); 385189251Ssam pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", 386189251Ssam NULL); 387189251Ssam pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", 388189251Ssam NULL); 389189251Ssam pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, 390189251Ssam "pfpooladdrpl", NULL); 391189251Ssam pfr_initialize(); 392189251Ssam pf_osfp_initialize(); 393189251Ssam 394189251Ssam pool_sethardlimit(&pf_state_pl, pf_pool_limits[PF_LIMIT_STATES].limit, 395189251Ssam NULL, 0); 396189251Ssam 397189251Ssam RB_INIT(&tree_lan_ext); 398189251Ssam RB_INIT(&tree_ext_gwy); 399189251Ssam TAILQ_INIT(&pf_anchors); 400189251Ssam pf_init_ruleset(&pf_main_ruleset); 401189251Ssam TAILQ_INIT(&pf_altqs[0]); 402189251Ssam TAILQ_INIT(&pf_altqs[1]); 403189251Ssam TAILQ_INIT(&pf_pabuf); 404189251Ssam pf_altqs_active = &pf_altqs[0]; 405189251Ssam pf_altqs_inactive = &pf_altqs[1]; 406189251Ssam 407189251Ssam /* default rule should never be garbage collected */ 408189251Ssam pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; 409189251Ssam pf_default_rule.action = PF_PASS; 410189251Ssam pf_default_rule.nr = -1; 411189251Ssam 412189251Ssam /* initialize default timeouts */ 413189251Ssam timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */ 414189251Ssam timeout[PFTM_TCP_OPENING] = 30; /* No response yet */ 415189251Ssam timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */ 416189251Ssam timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */ 417189251Ssam timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */ 418189251Ssam timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */ 419189251Ssam timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */ 420189251Ssam timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */ 421189251Ssam timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */ 422189251Ssam timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */ 423189251Ssam timeout[PFTM_ICMP_ERROR_REPLY] = 10; /* Got error response */ 424189251Ssam timeout[PFTM_OTHER_FIRST_PACKET] = 60; /* First packet */ 425189251Ssam timeout[PFTM_OTHER_SINGLE] = 30; /* Unidirectional */ 426189251Ssam timeout[PFTM_OTHER_MULTIPLE] = 60; /* Bidirectional */ 427189251Ssam timeout[PFTM_FRAG] = 30; /* Fragment expire */ 428189251Ssam timeout[PFTM_INTERVAL] = 10; /* Expire interval */ 429189251Ssam 430189251Ssam timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to); 431189251Ssam timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz); 432189251Ssam 433189251Ssam pf_normalize_init(); 434189251Ssam pf_status.debug = PF_DEBUG_URGENT; 435189251Ssam} 436189251Ssam#endif /* __FreeBSD__ */ 437189251Ssam 438189251Ssam#if !defined(__FreeBSD__) 439189251Ssamint 440189251Ssampfopen(dev_t dev, int flags, int fmt, struct proc *p) 441189251Ssam{ 442189251Ssam if (minor(dev) >= 1) 443189251Ssam return (ENXIO); 444189251Ssam return (0); 445189251Ssam} 446189251Ssam#endif 447189251Ssam 448189251Ssam#if !defined(__FreeBSD__) 449189251Ssamint 450189251Ssampfclose(dev_t dev, int flags, int fmt, struct proc *p) 451214734Srpaulo{ 452189251Ssam if (minor(dev) >= 1) 453189251Ssam return (ENXIO); 454189251Ssam return (0); 455189251Ssam} 456189251Ssam#endif 457189251Ssam 458189251Ssamstruct pf_pool * 459189251Ssampf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket, 460189251Ssam u_int8_t rule_action, u_int8_t rule_number, u_int8_t r_last, 461189251Ssam u_int8_t active, u_int8_t check_ticket) 462189251Ssam{ 463189251Ssam struct pf_ruleset *ruleset; 464189251Ssam struct pf_rule *rule; 465189251Ssam int rs_num; 466189251Ssam 467189251Ssam ruleset = pf_find_ruleset(anchorname, rulesetname); 468189251Ssam if (ruleset == NULL) 469189251Ssam return (NULL); 470189251Ssam rs_num = pf_get_ruleset_number(rule_action); 471189251Ssam if (rs_num >= PF_RULESET_MAX) 472189251Ssam return (NULL); 473189251Ssam if (active) { 474189251Ssam if (check_ticket && ticket != 475189251Ssam ruleset->rules[rs_num].active.ticket) 476189251Ssam return (NULL); 477189251Ssam if (r_last) 478189251Ssam rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 479189251Ssam pf_rulequeue); 480189251Ssam else 481189251Ssam rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 482189251Ssam } else { 483189251Ssam if (check_ticket && ticket != 484189251Ssam ruleset->rules[rs_num].inactive.ticket) 485189251Ssam return (NULL); 486189251Ssam if (r_last) 487189251Ssam rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 488189251Ssam pf_rulequeue); 489189251Ssam else 490189251Ssam rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr); 491189251Ssam } 492189251Ssam if (!r_last) { 493189251Ssam while ((rule != NULL) && (rule->nr != rule_number)) 494189251Ssam rule = TAILQ_NEXT(rule, entries); 495189251Ssam } 496189251Ssam if (rule == NULL) 497189251Ssam return (NULL); 498189251Ssam 499189251Ssam return (&rule->rpool); 500189251Ssam} 501189251Ssam 502189251Ssamint 503189251Ssampf_get_ruleset_number(u_int8_t action) 504189251Ssam{ 505189251Ssam switch (action) { 506189251Ssam case PF_SCRUB: 507189251Ssam return (PF_RULESET_SCRUB); 508209158Srpaulo break; 509209158Srpaulo case PF_PASS: 510209158Srpaulo case PF_DROP: 511209158Srpaulo return (PF_RULESET_FILTER); 512209158Srpaulo break; 513209158Srpaulo case PF_NAT: 514209158Srpaulo case PF_NONAT: 515209158Srpaulo return (PF_RULESET_NAT); 516252726Srpaulo break; 517252726Srpaulo case PF_BINAT: 518252726Srpaulo case PF_NOBINAT: 519252726Srpaulo return (PF_RULESET_BINAT); 520252726Srpaulo break; 521252726Srpaulo case PF_RDR: 522252726Srpaulo case PF_NORDR: 523252726Srpaulo return (PF_RULESET_RDR); 524252726Srpaulo break; 525252726Srpaulo default: 526252726Srpaulo return (PF_RULESET_MAX); 527252726Srpaulo break; 528252726Srpaulo } 529252726Srpaulo} 530252726Srpaulo 531252726Srpaulovoid 532252726Srpaulopf_init_ruleset(struct pf_ruleset *ruleset) 533252726Srpaulo{ 534252726Srpaulo int i; 535252726Srpaulo 536252726Srpaulo memset(ruleset, 0, sizeof(struct pf_ruleset)); 537252726Srpaulo for (i = 0; i < PF_RULESET_MAX; i++) { 538252726Srpaulo TAILQ_INIT(&ruleset->rules[i].queues[0]); 539252726Srpaulo TAILQ_INIT(&ruleset->rules[i].queues[1]); 540252726Srpaulo ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0]; 541252726Srpaulo ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1]; 542252726Srpaulo } 543252726Srpaulo} 544252726Srpaulo 545252726Srpaulostruct pf_anchor * 546252726Srpaulopf_find_anchor(const char *anchorname) 547252726Srpaulo{ 548252726Srpaulo struct pf_anchor *anchor; 549252726Srpaulo int n = -1; 550252726Srpaulo 551252726Srpaulo anchor = TAILQ_FIRST(&pf_anchors); 552252726Srpaulo while (anchor != NULL && (n = strcmp(anchor->name, anchorname)) < 0) 553189251Ssam anchor = TAILQ_NEXT(anchor, entries); 554189251Ssam if (n == 0) 555189251Ssam return (anchor); 556189251Ssam else 557189251Ssam return (NULL); 558189251Ssam} 559189251Ssam 560189251Ssamstruct pf_ruleset * 561189251Ssampf_find_ruleset(char *anchorname, char *rulesetname) 562189251Ssam{ 563189251Ssam struct pf_anchor *anchor; 564189251Ssam struct pf_ruleset *ruleset; 565189251Ssam 566189251Ssam if (!anchorname[0] && !rulesetname[0]) 567252726Srpaulo return (&pf_main_ruleset); 568252726Srpaulo if (!anchorname[0] || !rulesetname[0]) 569252726Srpaulo return (NULL); 570189251Ssam anchorname[PF_ANCHOR_NAME_SIZE-1] = 0; 571189251Ssam rulesetname[PF_RULESET_NAME_SIZE-1] = 0; 572189251Ssam anchor = pf_find_anchor(anchorname); 573189251Ssam if (anchor == NULL) 574189251Ssam return (NULL); 575189251Ssam ruleset = TAILQ_FIRST(&anchor->rulesets); 576189251Ssam while (ruleset != NULL && strcmp(ruleset->name, rulesetname) < 0) 577189251Ssam ruleset = TAILQ_NEXT(ruleset, entries); 578189251Ssam if (ruleset != NULL && !strcmp(ruleset->name, rulesetname)) 579189251Ssam return (ruleset); 580189251Ssam else 581189251Ssam return (NULL); 582189251Ssam} 583189251Ssam 584189251Ssamstruct pf_ruleset * 585189251Ssampf_find_or_create_ruleset(char *anchorname, char *rulesetname) 586189251Ssam{ 587252726Srpaulo struct pf_anchor *anchor, *a; 588189251Ssam struct pf_ruleset *ruleset, *r; 589189251Ssam 590189251Ssam if (!anchorname[0] && !rulesetname[0]) 591252726Srpaulo return (&pf_main_ruleset); 592252726Srpaulo if (!anchorname[0] || !rulesetname[0]) 593252726Srpaulo return (NULL); 594252726Srpaulo anchorname[PF_ANCHOR_NAME_SIZE-1] = 0; 595252726Srpaulo rulesetname[PF_RULESET_NAME_SIZE-1] = 0; 596252726Srpaulo a = TAILQ_FIRST(&pf_anchors); 597252726Srpaulo while (a != NULL && strcmp(a->name, anchorname) < 0) 598252726Srpaulo a = TAILQ_NEXT(a, entries); 599252726Srpaulo if (a != NULL && !strcmp(a->name, anchorname)) 600252726Srpaulo anchor = a; 601252726Srpaulo else { 602252726Srpaulo anchor = (struct pf_anchor *)malloc(sizeof(struct pf_anchor), 603252726Srpaulo M_TEMP, M_NOWAIT); 604252726Srpaulo if (anchor == NULL) 605252726Srpaulo return (NULL); 606252726Srpaulo memset(anchor, 0, sizeof(struct pf_anchor)); 607252726Srpaulo bcopy(anchorname, anchor->name, sizeof(anchor->name)); 608252726Srpaulo TAILQ_INIT(&anchor->rulesets); 609189251Ssam if (a != NULL) 610189251Ssam TAILQ_INSERT_BEFORE(a, anchor, entries); 611189251Ssam else 612214734Srpaulo TAILQ_INSERT_TAIL(&pf_anchors, anchor, entries); 613214734Srpaulo } 614214734Srpaulo r = TAILQ_FIRST(&anchor->rulesets); 615214734Srpaulo while (r != NULL && strcmp(r->name, rulesetname) < 0) 616214734Srpaulo r = TAILQ_NEXT(r, entries); 617214734Srpaulo if (r != NULL && !strcmp(r->name, rulesetname)) 618214734Srpaulo return (r); 619214734Srpaulo ruleset = (struct pf_ruleset *)malloc(sizeof(struct pf_ruleset), 620214734Srpaulo M_TEMP, M_NOWAIT); 621214734Srpaulo if (ruleset != NULL) { 622214734Srpaulo pf_init_ruleset(ruleset); 623214734Srpaulo bcopy(rulesetname, ruleset->name, sizeof(ruleset->name)); 624214734Srpaulo ruleset->anchor = anchor; 625214734Srpaulo if (r != NULL) 626214734Srpaulo TAILQ_INSERT_BEFORE(r, ruleset, entries); 627214734Srpaulo else 628214734Srpaulo TAILQ_INSERT_TAIL(&anchor->rulesets, ruleset, entries); 629214734Srpaulo } 630214734Srpaulo return (ruleset); 631189251Ssam} 632189251Ssam 633189251Ssamvoid 634252726Srpaulopf_remove_if_empty_ruleset(struct pf_ruleset *ruleset) 635252726Srpaulo{ 636252726Srpaulo struct pf_anchor *anchor; 637189251Ssam int i; 638189251Ssam 639189251Ssam if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 || 640189251Ssam ruleset->topen) 641189251Ssam return; 642 for (i = 0; i < PF_RULESET_MAX; ++i) 643 if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) || 644 !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr)) 645 return; 646 647 anchor = ruleset->anchor; 648 TAILQ_REMOVE(&anchor->rulesets, ruleset, entries); 649 free(ruleset, M_TEMP); 650 651 if (TAILQ_EMPTY(&anchor->rulesets)) { 652 TAILQ_REMOVE(&pf_anchors, anchor, entries); 653 free(anchor, M_TEMP); 654 } 655} 656 657void 658pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb) 659{ 660 struct pf_pooladdr *mv_pool_pa; 661 662 while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) { 663 TAILQ_REMOVE(poola, mv_pool_pa, entries); 664 TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries); 665 } 666} 667 668void 669pf_empty_pool(struct pf_palist *poola) 670{ 671 struct pf_pooladdr *empty_pool_pa; 672 673 while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) { 674 pf_dynaddr_remove(&empty_pool_pa->addr); 675 pf_tbladdr_remove(&empty_pool_pa->addr); 676 TAILQ_REMOVE(poola, empty_pool_pa, entries); 677 pool_put(&pf_pooladdr_pl, empty_pool_pa); 678 } 679} 680 681void 682pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) 683{ 684 if (rulequeue != NULL) { 685 if (rule->states <= 0) { 686 /* 687 * XXX - we need to remove the table *before* detaching 688 * the rule to make sure the table code does not delete 689 * the anchor under our feet. 690 */ 691 pf_tbladdr_remove(&rule->src.addr); 692 pf_tbladdr_remove(&rule->dst.addr); 693 } 694 TAILQ_REMOVE(rulequeue, rule, entries); 695 rule->entries.tqe_prev = NULL; 696 rule->nr = -1; 697 } 698 if (rule->states > 0 || rule->entries.tqe_prev != NULL) 699 return; 700 pf_tag_unref(rule->tag); 701 pf_tag_unref(rule->match_tag); 702 pf_dynaddr_remove(&rule->src.addr); 703 pf_dynaddr_remove(&rule->dst.addr); 704 if (rulequeue == NULL) { 705 pf_tbladdr_remove(&rule->src.addr); 706 pf_tbladdr_remove(&rule->dst.addr); 707 } 708 pf_empty_pool(&rule->rpool.list); 709 pool_put(&pf_rule_pl, rule); 710} 711 712u_int16_t 713pf_tagname2tag(char *tagname) 714{ 715 struct pf_tagname *tag, *p = NULL; 716 u_int16_t new_tagid = 1; 717 718 TAILQ_FOREACH(tag, &pf_tags, entries) 719 if (strcmp(tagname, tag->name) == 0) { 720 tag->ref++; 721 return (tag->tag); 722 } 723 724 /* 725 * to avoid fragmentation, we do a linear search from the beginning 726 * and take the first free slot we find. if there is none or the list 727 * is empty, append a new entry at the end. 728 */ 729 730 /* new entry */ 731 if (!TAILQ_EMPTY(&pf_tags)) 732 for (p = TAILQ_FIRST(&pf_tags); p != NULL && 733 p->tag == new_tagid; p = TAILQ_NEXT(p, entries)) 734 new_tagid = p->tag + 1; 735 736 if (new_tagid > TAGID_MAX) 737 return (0); 738 739 /* allocate and fill new struct pf_tagname */ 740 tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname), 741 M_TEMP, M_NOWAIT); 742 if (tag == NULL) 743 return (0); 744 bzero(tag, sizeof(struct pf_tagname)); 745 strlcpy(tag->name, tagname, sizeof(tag->name)); 746 tag->tag = new_tagid; 747 tag->ref++; 748 749 if (p != NULL) /* insert new entry before p */ 750 TAILQ_INSERT_BEFORE(p, tag, entries); 751 else /* either list empty or no free slot in between */ 752 TAILQ_INSERT_TAIL(&pf_tags, tag, entries); 753 754 return (tag->tag); 755} 756 757void 758pf_tag2tagname(u_int16_t tagid, char *p) 759{ 760 struct pf_tagname *tag; 761 762 TAILQ_FOREACH(tag, &pf_tags, entries) 763 if (tag->tag == tagid) { 764 strlcpy(p, tag->name, PF_TAG_NAME_SIZE); 765 return; 766 } 767} 768 769void 770pf_tag_unref(u_int16_t tag) 771{ 772 struct pf_tagname *p, *next; 773 774 if (tag == 0) 775 return; 776 777 for (p = TAILQ_FIRST(&pf_tags); p != NULL; p = next) { 778 next = TAILQ_NEXT(p, entries); 779 if (tag == p->tag) { 780 if (--p->ref == 0) { 781 TAILQ_REMOVE(&pf_tags, p, entries); 782 free(p, M_TEMP); 783 } 784 break; 785 } 786 } 787} 788 789#if defined(__FreeBSD__) 790int 791pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 792#else 793int 794pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 795#endif 796{ 797 struct pf_pooladdr *pa = NULL; 798 struct pf_pool *pool = NULL; 799 int s; 800 int error = 0; 801 802 /* XXX keep in sync with switch() below */ 803 if (securelevel > 1) 804 switch (cmd) { 805 case DIOCGETRULES: 806 case DIOCGETRULE: 807 case DIOCGETADDRS: 808 case DIOCGETADDR: 809 case DIOCGETSTATE: 810 case DIOCSETSTATUSIF: 811 case DIOCGETSTATUS: 812 case DIOCCLRSTATUS: 813 case DIOCNATLOOK: 814 case DIOCSETDEBUG: 815 case DIOCGETSTATES: 816 case DIOCGETTIMEOUT: 817 case DIOCCLRRULECTRS: 818 case DIOCGETLIMIT: 819 case DIOCGETALTQS: 820 case DIOCGETALTQ: 821 case DIOCGETQSTATS: 822 case DIOCGETANCHORS: 823 case DIOCGETANCHOR: 824 case DIOCGETRULESETS: 825 case DIOCGETRULESET: 826 case DIOCRGETTABLES: 827 case DIOCRGETTSTATS: 828 case DIOCRCLRTSTATS: 829 case DIOCRCLRADDRS: 830 case DIOCRADDADDRS: 831 case DIOCRDELADDRS: 832 case DIOCRSETADDRS: 833 case DIOCRGETADDRS: 834 case DIOCRGETASTATS: 835 case DIOCRCLRASTATS: 836 case DIOCRTSTADDRS: 837 case DIOCOSFPGET: 838#if defined(__FreeBSD__) 839 case DIOCGIFSPEED: 840#endif 841 break; 842 default: 843 return (EPERM); 844 } 845 846 if (!(flags & FWRITE)) 847 switch (cmd) { 848 case DIOCGETRULES: 849 case DIOCGETRULE: 850 case DIOCGETADDRS: 851 case DIOCGETADDR: 852 case DIOCGETSTATE: 853 case DIOCGETSTATUS: 854 case DIOCGETSTATES: 855 case DIOCGETTIMEOUT: 856 case DIOCGETLIMIT: 857 case DIOCGETALTQS: 858 case DIOCGETALTQ: 859 case DIOCGETQSTATS: 860 case DIOCGETANCHORS: 861 case DIOCGETANCHOR: 862 case DIOCGETRULESETS: 863 case DIOCGETRULESET: 864 case DIOCRGETTABLES: 865 case DIOCRGETTSTATS: 866 case DIOCRGETADDRS: 867 case DIOCRGETASTATS: 868 case DIOCRTSTADDRS: 869 case DIOCOSFPGET: 870#if defined(__FreeBSD__) 871 case DIOCGIFSPEED: 872#endif 873 break; 874 default: 875 return (EACCES); 876 } 877 878#if defined(__FreeBSD__) 879 PF_LOCK(); 880#endif 881 882 switch (cmd) { 883 884 case DIOCSTART: 885 if (pf_status.running) 886 error = EEXIST; 887 else { 888 u_int32_t states = pf_status.states; 889#if defined(__FreeBSD__) 890 PF_UNLOCK(); 891 error = hook_pf(); 892 PF_LOCK(); 893 if (error) { 894 DPFPRINTF(PF_DEBUG_MISC, 895 ("pf: pfil registeration fail\n")); 896 break; 897 } 898#endif 899 bzero(&pf_status, sizeof(struct pf_status)); 900 pf_status.running = 1; 901 pf_status.states = states; 902#if defined(__FreeBSD__) 903 pf_status.since = time_second; 904#else 905 pf_status.since = time.tv_sec; 906#endif 907 if (status_ifp != NULL) 908#if defined(__FreeBSD__) && (__FreeBSD_version < 501113) 909 snprintf(pf_status.ifname, IFNAMSIZ, "%s%d", 910 status_ifp->if_name, status_ifp->if_unit); 911#else 912 strlcpy(pf_status.ifname, 913 status_ifp->if_xname, IFNAMSIZ); 914#endif 915 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); 916 } 917 break; 918 919 case DIOCSTOP: 920 if (!pf_status.running) 921 error = ENOENT; 922 else { 923 pf_status.running = 0; 924#if defined(__FreeBSD__) 925 PF_UNLOCK(); 926 error = dehook_pf(); 927 PF_LOCK(); 928 if (error) { 929 pf_status.running = 1; 930 DPFPRINTF(PF_DEBUG_MISC, 931 ("pf: pfil unregisteration failed\n")); 932 } 933#endif 934 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); 935 } 936 break; 937 938 case DIOCBEGINRULES: { 939 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 940 struct pf_ruleset *ruleset; 941 struct pf_rule *rule; 942 int rs_num; 943 944 ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset); 945 if (ruleset == NULL) { 946 error = EINVAL; 947 break; 948 } 949 rs_num = pf_get_ruleset_number(pr->rule.action); 950 if (rs_num >= PF_RULESET_MAX) { 951 error = EINVAL; 952 break; 953 } 954 while ((rule = 955 TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL) 956 pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule); 957 pr->ticket = ++ruleset->rules[rs_num].inactive.ticket; 958 break; 959 } 960 961 case DIOCADDRULE: { 962 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 963 struct pf_ruleset *ruleset; 964 struct pf_rule *rule, *tail; 965 struct pf_pooladdr *pa; 966 int rs_num; 967 968 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 969 if (ruleset == NULL) { 970 error = EINVAL; 971 break; 972 } 973 rs_num = pf_get_ruleset_number(pr->rule.action); 974 if (rs_num >= PF_RULESET_MAX) { 975 error = EINVAL; 976 break; 977 } 978 if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) { 979 error = EINVAL; 980 break; 981 } 982 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 983 error = EINVAL; 984 break; 985 } 986 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { 987 error = EBUSY; 988 break; 989 } 990 if (pr->pool_ticket != ticket_pabuf) { 991 error = EBUSY; 992 break; 993 } 994 rule = pool_get(&pf_rule_pl, PR_NOWAIT); 995 if (rule == NULL) { 996 error = ENOMEM; 997 break; 998 } 999 bcopy(&pr->rule, rule, sizeof(struct pf_rule)); 1000 rule->anchor = NULL; 1001 rule->ifp = NULL; 1002 TAILQ_INIT(&rule->rpool.list); 1003 /* initialize refcounting */ 1004 rule->states = 0; 1005 rule->entries.tqe_prev = NULL; 1006#ifndef INET 1007 if (rule->af == AF_INET) { 1008 pool_put(&pf_rule_pl, rule); 1009 error = EAFNOSUPPORT; 1010 break; 1011 } 1012#endif /* INET */ 1013#ifndef INET6 1014 if (rule->af == AF_INET6) { 1015 pool_put(&pf_rule_pl, rule); 1016 error = EAFNOSUPPORT; 1017 break; 1018 } 1019#endif /* INET6 */ 1020 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 1021 pf_rulequeue); 1022 if (tail) 1023 rule->nr = tail->nr + 1; 1024 else 1025 rule->nr = 0; 1026 if (rule->ifname[0]) { 1027 rule->ifp = ifunit(rule->ifname); 1028 if (rule->ifp == NULL) { 1029 pool_put(&pf_rule_pl, rule); 1030 error = EINVAL; 1031 break; 1032 } 1033 } 1034 1035 if (rule->tagname[0]) 1036 if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) 1037 error = EBUSY; 1038 if (rule->match_tagname[0]) 1039 if ((rule->match_tag = 1040 pf_tagname2tag(rule->match_tagname)) == 0) 1041 error = EBUSY; 1042 if (rule->rt && !rule->direction) 1043 error = EINVAL; 1044 if (pf_dynaddr_setup(&rule->src.addr, rule->af)) 1045 error = EINVAL; 1046 if (pf_dynaddr_setup(&rule->dst.addr, rule->af)) 1047 error = EINVAL; 1048 if (pf_tbladdr_setup(ruleset, &rule->src.addr)) 1049 error = EINVAL; 1050 if (pf_tbladdr_setup(ruleset, &rule->dst.addr)) 1051 error = EINVAL; 1052 TAILQ_FOREACH(pa, &pf_pabuf, entries) 1053 if (pf_tbladdr_setup(ruleset, &pa->addr)) 1054 error = EINVAL; 1055 1056 pf_mv_pool(&pf_pabuf, &rule->rpool.list); 1057 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || 1058 (rule->action == PF_BINAT)) && !rule->anchorname[0]) || 1059 (rule->rt > PF_FASTROUTE)) && 1060 (TAILQ_FIRST(&rule->rpool.list) == NULL)) 1061 error = EINVAL; 1062 1063 if (error) { 1064 pf_rm_rule(NULL, rule); 1065 break; 1066 } 1067 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list); 1068 rule->evaluations = rule->packets = rule->bytes = 0; 1069 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, 1070 rule, entries); 1071 break; 1072 } 1073 1074 case DIOCCOMMITRULES: { 1075 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1076 struct pf_ruleset *ruleset; 1077 struct pf_rulequeue *old_rules; 1078 struct pf_rule *rule; 1079 int rs_num; 1080 1081 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 1082 if (ruleset == NULL) { 1083 error = EINVAL; 1084 break; 1085 } 1086 rs_num = pf_get_ruleset_number(pr->rule.action); 1087 if (rs_num >= PF_RULESET_MAX) { 1088 error = EINVAL; 1089 break; 1090 } 1091 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { 1092 error = EBUSY; 1093 break; 1094 } 1095 1096#ifdef ALTQ 1097 /* set queue IDs */ 1098 if (rs_num == PF_RULESET_FILTER) 1099 pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr); 1100#endif 1101 1102 /* Swap rules, keep the old. */ 1103 s = splsoftnet(); 1104 old_rules = ruleset->rules[rs_num].active.ptr; 1105 ruleset->rules[rs_num].active.ptr = 1106 ruleset->rules[rs_num].inactive.ptr; 1107 ruleset->rules[rs_num].inactive.ptr = old_rules; 1108 ruleset->rules[rs_num].active.ticket = 1109 ruleset->rules[rs_num].inactive.ticket; 1110 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); 1111 1112 /* Purge the old rule list. */ 1113 while ((rule = TAILQ_FIRST(old_rules)) != NULL) 1114 pf_rm_rule(old_rules, rule); 1115 pf_remove_if_empty_ruleset(ruleset); 1116 pf_update_anchor_rules(); 1117 splx(s); 1118 break; 1119 } 1120 1121 case DIOCGETRULES: { 1122 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1123 struct pf_ruleset *ruleset; 1124 struct pf_rule *tail; 1125 int rs_num; 1126 1127 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 1128 if (ruleset == NULL) { 1129 error = EINVAL; 1130 break; 1131 } 1132 rs_num = pf_get_ruleset_number(pr->rule.action); 1133 if (rs_num >= PF_RULESET_MAX) { 1134 error = EINVAL; 1135 break; 1136 } 1137 s = splsoftnet(); 1138 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 1139 pf_rulequeue); 1140 if (tail) 1141 pr->nr = tail->nr + 1; 1142 else 1143 pr->nr = 0; 1144 pr->ticket = ruleset->rules[rs_num].active.ticket; 1145 splx(s); 1146 break; 1147 } 1148 1149 case DIOCGETRULE: { 1150 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1151 struct pf_ruleset *ruleset; 1152 struct pf_rule *rule; 1153 int rs_num, i; 1154 1155 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 1156 if (ruleset == NULL) { 1157 error = EINVAL; 1158 break; 1159 } 1160 rs_num = pf_get_ruleset_number(pr->rule.action); 1161 if (rs_num >= PF_RULESET_MAX) { 1162 error = EINVAL; 1163 break; 1164 } 1165 if (pr->ticket != ruleset->rules[rs_num].active.ticket) { 1166 error = EBUSY; 1167 break; 1168 } 1169 s = splsoftnet(); 1170 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 1171 while ((rule != NULL) && (rule->nr != pr->nr)) 1172 rule = TAILQ_NEXT(rule, entries); 1173 if (rule == NULL) { 1174 error = EBUSY; 1175 splx(s); 1176 break; 1177 } 1178 bcopy(rule, &pr->rule, sizeof(struct pf_rule)); 1179 pf_dynaddr_copyout(&pr->rule.src.addr); 1180 pf_dynaddr_copyout(&pr->rule.dst.addr); 1181 pf_tbladdr_copyout(&pr->rule.src.addr); 1182 pf_tbladdr_copyout(&pr->rule.dst.addr); 1183 for (i = 0; i < PF_SKIP_COUNT; ++i) 1184 if (rule->skip[i].ptr == NULL) 1185 pr->rule.skip[i].nr = -1; 1186 else 1187 pr->rule.skip[i].nr = 1188 rule->skip[i].ptr->nr; 1189 splx(s); 1190 break; 1191 } 1192 1193 case DIOCCHANGERULE: { 1194 struct pfioc_rule *pcr = (struct pfioc_rule *)addr; 1195 struct pf_ruleset *ruleset; 1196 struct pf_rule *oldrule = NULL, *newrule = NULL; 1197 u_int32_t nr = 0; 1198 int rs_num; 1199 1200 if (!(pcr->action == PF_CHANGE_REMOVE || 1201 pcr->action == PF_CHANGE_GET_TICKET) && 1202 pcr->pool_ticket != ticket_pabuf) { 1203 error = EBUSY; 1204 break; 1205 } 1206 1207 if (pcr->action < PF_CHANGE_ADD_HEAD || 1208 pcr->action > PF_CHANGE_GET_TICKET) { 1209 error = EINVAL; 1210 break; 1211 } 1212 ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset); 1213 if (ruleset == NULL) { 1214 error = EINVAL; 1215 break; 1216 } 1217 rs_num = pf_get_ruleset_number(pcr->rule.action); 1218 if (rs_num >= PF_RULESET_MAX) { 1219 error = EINVAL; 1220 break; 1221 } 1222 1223 if (pcr->action == PF_CHANGE_GET_TICKET) { 1224 pcr->ticket = ++ruleset->rules[rs_num].active.ticket; 1225 break; 1226 } else { 1227 if (pcr->ticket != 1228 ruleset->rules[rs_num].active.ticket) { 1229 error = EINVAL; 1230 break; 1231 } 1232 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1233 error = EINVAL; 1234 break; 1235 } 1236 } 1237 1238 if (pcr->action != PF_CHANGE_REMOVE) { 1239 newrule = pool_get(&pf_rule_pl, PR_NOWAIT); 1240 if (newrule == NULL) { 1241 error = ENOMEM; 1242 break; 1243 } 1244 bcopy(&pcr->rule, newrule, sizeof(struct pf_rule)); 1245 TAILQ_INIT(&newrule->rpool.list); 1246 /* initialize refcounting */ 1247 newrule->states = 0; 1248 newrule->entries.tqe_prev = NULL; 1249#ifndef INET 1250 if (newrule->af == AF_INET) { 1251 pool_put(&pf_rule_pl, newrule); 1252 error = EAFNOSUPPORT; 1253 break; 1254 } 1255#endif /* INET */ 1256#ifndef INET6 1257 if (newrule->af == AF_INET6) { 1258 pool_put(&pf_rule_pl, newrule); 1259 error = EAFNOSUPPORT; 1260 break; 1261 } 1262#endif /* INET6 */ 1263 if (newrule->ifname[0]) { 1264 newrule->ifp = ifunit(newrule->ifname); 1265 if (newrule->ifp == NULL) { 1266 pool_put(&pf_rule_pl, newrule); 1267 error = EINVAL; 1268 break; 1269 } 1270 } else 1271 newrule->ifp = NULL; 1272 1273#ifdef ALTQ 1274 /* set queue IDs */ 1275 if (newrule->qname[0] != 0) { 1276 newrule->qid = pf_qname_to_qid(newrule->qname); 1277 if (newrule->pqname[0] != 0) 1278 newrule->pqid = 1279 pf_qname_to_qid(newrule->pqname); 1280 else 1281 newrule->pqid = newrule->qid; 1282 } 1283#endif 1284 if (newrule->tagname[0]) 1285 if ((newrule->tag = 1286 pf_tagname2tag(newrule->tagname)) == 0) 1287 error = EBUSY; 1288 if (newrule->match_tagname[0]) 1289 if ((newrule->match_tag = pf_tagname2tag( 1290 newrule->match_tagname)) == 0) 1291 error = EBUSY; 1292 1293 if (newrule->rt && !newrule->direction) 1294 error = EINVAL; 1295 if (pf_dynaddr_setup(&newrule->src.addr, newrule->af)) 1296 error = EINVAL; 1297 if (pf_dynaddr_setup(&newrule->dst.addr, newrule->af)) 1298 error = EINVAL; 1299 if (pf_tbladdr_setup(ruleset, &newrule->src.addr)) 1300 error = EINVAL; 1301 if (pf_tbladdr_setup(ruleset, &newrule->dst.addr)) 1302 error = EINVAL; 1303 1304 pf_mv_pool(&pf_pabuf, &newrule->rpool.list); 1305 if (((((newrule->action == PF_NAT) || 1306 (newrule->action == PF_RDR) || 1307 (newrule->action == PF_BINAT) || 1308 (newrule->rt > PF_FASTROUTE)) && 1309 !newrule->anchorname[0])) && 1310 (TAILQ_FIRST(&newrule->rpool.list) == NULL)) 1311 error = EINVAL; 1312 1313 if (error) { 1314 pf_rm_rule(NULL, newrule); 1315 break; 1316 } 1317 newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list); 1318 newrule->evaluations = newrule->packets = 0; 1319 newrule->bytes = 0; 1320 } 1321 pf_empty_pool(&pf_pabuf); 1322 1323 s = splsoftnet(); 1324 1325 if (pcr->action == PF_CHANGE_ADD_HEAD) 1326 oldrule = TAILQ_FIRST( 1327 ruleset->rules[rs_num].active.ptr); 1328 else if (pcr->action == PF_CHANGE_ADD_TAIL) 1329 oldrule = TAILQ_LAST( 1330 ruleset->rules[rs_num].active.ptr, pf_rulequeue); 1331 else { 1332 oldrule = TAILQ_FIRST( 1333 ruleset->rules[rs_num].active.ptr); 1334 while ((oldrule != NULL) && (oldrule->nr != pcr->nr)) 1335 oldrule = TAILQ_NEXT(oldrule, entries); 1336 if (oldrule == NULL) { 1337 pf_rm_rule(NULL, newrule); 1338 error = EINVAL; 1339 splx(s); 1340 break; 1341 } 1342 } 1343 1344 if (pcr->action == PF_CHANGE_REMOVE) 1345 pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule); 1346 else { 1347 if (oldrule == NULL) 1348 TAILQ_INSERT_TAIL( 1349 ruleset->rules[rs_num].active.ptr, 1350 newrule, entries); 1351 else if (pcr->action == PF_CHANGE_ADD_HEAD || 1352 pcr->action == PF_CHANGE_ADD_BEFORE) 1353 TAILQ_INSERT_BEFORE(oldrule, newrule, entries); 1354 else 1355 TAILQ_INSERT_AFTER( 1356 ruleset->rules[rs_num].active.ptr, 1357 oldrule, newrule, entries); 1358 } 1359 1360 nr = 0; 1361 TAILQ_FOREACH(oldrule, 1362 ruleset->rules[rs_num].active.ptr, entries) 1363 oldrule->nr = nr++; 1364 1365 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); 1366 pf_remove_if_empty_ruleset(ruleset); 1367 pf_update_anchor_rules(); 1368 1369 ruleset->rules[rs_num].active.ticket++; 1370 splx(s); 1371 break; 1372 } 1373 1374 case DIOCCLRSTATES: { 1375 struct pf_tree_node *n; 1376 1377 s = splsoftnet(); 1378 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) 1379 n->state->timeout = PFTM_PURGE; 1380 pf_purge_expired_states(); 1381 pf_status.states = 0; 1382 splx(s); 1383 break; 1384 } 1385 1386 case DIOCKILLSTATES: { 1387 struct pf_tree_node *n; 1388 struct pf_state *st; 1389 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 1390 int killed = 0; 1391 1392 s = splsoftnet(); 1393 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) { 1394 st = n->state; 1395 if ((!psk->psk_af || st->af == psk->psk_af) && 1396 (!psk->psk_proto || psk->psk_proto == st->proto) && 1397 PF_MATCHA(psk->psk_src.not, 1398 &psk->psk_src.addr.v.a.addr, 1399 &psk->psk_src.addr.v.a.mask, &st->lan.addr, 1400 st->af) && 1401 PF_MATCHA(psk->psk_dst.not, 1402 &psk->psk_dst.addr.v.a.addr, 1403 &psk->psk_dst.addr.v.a.mask, &st->ext.addr, 1404 st->af) && 1405 (psk->psk_src.port_op == 0 || 1406 pf_match_port(psk->psk_src.port_op, 1407 psk->psk_src.port[0], psk->psk_src.port[1], 1408 st->lan.port)) && 1409 (psk->psk_dst.port_op == 0 || 1410 pf_match_port(psk->psk_dst.port_op, 1411 psk->psk_dst.port[0], psk->psk_dst.port[1], 1412 st->ext.port))) { 1413 st->timeout = PFTM_PURGE; 1414 killed++; 1415 } 1416 } 1417 pf_purge_expired_states(); 1418 splx(s); 1419 psk->psk_af = killed; 1420 break; 1421 } 1422 1423 case DIOCADDSTATE: { 1424 struct pfioc_state *ps = (struct pfioc_state *)addr; 1425 struct pf_state *state; 1426 1427 if (ps->state.timeout >= PFTM_MAX && 1428 ps->state.timeout != PFTM_UNTIL_PACKET) { 1429 error = EINVAL; 1430 break; 1431 } 1432 state = pool_get(&pf_state_pl, PR_NOWAIT); 1433 if (state == NULL) { 1434 error = ENOMEM; 1435 break; 1436 } 1437 s = splsoftnet(); 1438 bcopy(&ps->state, state, sizeof(struct pf_state)); 1439 state->rule.ptr = NULL; 1440 state->nat_rule.ptr = NULL; 1441 state->anchor.ptr = NULL; 1442 state->rt_ifp = NULL; 1443#if defined(__FreeBSD__) 1444 state->creation = time_second; 1445#else 1446 state->creation = time.tv_sec; 1447#endif 1448 state->packets[0] = state->packets[1] = 0; 1449 state->bytes[0] = state->bytes[1] = 0; 1450 if (pf_insert_state(state)) { 1451 pool_put(&pf_state_pl, state); 1452 error = ENOMEM; 1453 } 1454 splx(s); 1455 break; 1456 } 1457 1458 case DIOCGETSTATE: { 1459 struct pfioc_state *ps = (struct pfioc_state *)addr; 1460 struct pf_tree_node *n; 1461 u_int32_t nr; 1462 1463 nr = 0; 1464 s = splsoftnet(); 1465 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) { 1466 if (nr >= ps->nr) 1467 break; 1468 nr++; 1469 } 1470 if (n == NULL) { 1471 error = EBUSY; 1472 splx(s); 1473 break; 1474 } 1475 bcopy(n->state, &ps->state, sizeof(struct pf_state)); 1476 ps->state.rule.nr = n->state->rule.ptr->nr; 1477 ps->state.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ? 1478 -1 : n->state->nat_rule.ptr->nr; 1479 ps->state.anchor.nr = (n->state->anchor.ptr == NULL) ? 1480 -1 : n->state->anchor.ptr->nr; 1481 splx(s); 1482 ps->state.expire = pf_state_expires(n->state); 1483#if defined(__FreeBSD__) 1484 if (ps->state.expire > time_second) 1485 ps->state.expire -= time_second; 1486#else 1487 if (ps->state.expire > time.tv_sec) 1488 ps->state.expire -= time.tv_sec; 1489#endif 1490 else 1491 ps->state.expire = 0; 1492 break; 1493 } 1494 1495 case DIOCGETSTATES: { 1496 struct pfioc_states *ps = (struct pfioc_states *)addr; 1497 struct pf_tree_node *n; 1498 struct pf_state *p, pstore; 1499 u_int32_t nr = 0; 1500 int space = ps->ps_len; 1501 1502 if (space == 0) { 1503 s = splsoftnet(); 1504 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) 1505 nr++; 1506 splx(s); 1507 ps->ps_len = sizeof(struct pf_state) * nr; 1508#if defined(__FreeBSD__) 1509 PF_UNLOCK(); 1510#endif 1511 return (0); 1512 } 1513 1514 s = splsoftnet(); 1515 p = ps->ps_states; 1516 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) { 1517#if defined(__FreeBSD__) 1518 int secs = time_second; 1519#else 1520 int secs = time.tv_sec; 1521#endif 1522 1523 if ((nr + 1) * sizeof(*p) > (unsigned)ps->ps_len) 1524 break; 1525 1526 bcopy(n->state, &pstore, sizeof(pstore)); 1527 pstore.rule.nr = n->state->rule.ptr->nr; 1528 pstore.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ? 1529 -1 : n->state->nat_rule.ptr->nr; 1530 pstore.anchor.nr = (n->state->anchor.ptr == NULL) ? 1531 -1 : n->state->anchor.ptr->nr; 1532 pstore.creation = secs - pstore.creation; 1533 pstore.expire = pf_state_expires(n->state); 1534 if (pstore.expire > secs) 1535 pstore.expire -= secs; 1536 else 1537 pstore.expire = 0; 1538#if defined(__FreeBSD__) 1539 PF_COPYOUT(&pstore, p, sizeof(*p), error); 1540#else 1541 error = copyout(&pstore, p, sizeof(*p)); 1542#endif 1543 if (error) { 1544 splx(s); 1545 goto fail; 1546 } 1547 p++; 1548 nr++; 1549 } 1550 ps->ps_len = sizeof(struct pf_state) * nr; 1551 splx(s); 1552 break; 1553 } 1554 1555 case DIOCGETSTATUS: { 1556 struct pf_status *s = (struct pf_status *)addr; 1557 bcopy(&pf_status, s, sizeof(struct pf_status)); 1558 break; 1559 } 1560 1561 case DIOCSETSTATUSIF: { 1562 struct pfioc_if *pi = (struct pfioc_if *)addr; 1563 struct ifnet *ifp; 1564 1565 if (pi->ifname[0] == 0) { 1566 status_ifp = NULL; 1567 bzero(pf_status.ifname, IFNAMSIZ); 1568 break; 1569 } 1570 if ((ifp = ifunit(pi->ifname)) == NULL) { 1571 error = EINVAL; 1572 break; 1573 } else if (ifp == status_ifp) 1574 break; 1575 status_ifp = ifp; 1576 /* fallthrough into DIOCCLRSTATUS */ 1577 } 1578 1579 case DIOCCLRSTATUS: { 1580 u_int32_t running = pf_status.running; 1581 u_int32_t states = pf_status.states; 1582 u_int32_t since = pf_status.since; 1583 u_int32_t debug = pf_status.debug; 1584 1585 bzero(&pf_status, sizeof(struct pf_status)); 1586 pf_status.running = running; 1587 pf_status.states = states; 1588 pf_status.since = since; 1589 pf_status.debug = debug; 1590 if (status_ifp != NULL) 1591#if defined(__FreeBSD__) && (__FreeBSD_version < 501113) 1592 snprintf(pf_status.ifname, IFNAMSIZ, "%s%d", 1593 status_ifp->if_name, status_ifp->if_unit); 1594#else 1595 strlcpy(pf_status.ifname, 1596 status_ifp->if_xname, IFNAMSIZ); 1597#endif 1598 break; 1599 } 1600 1601 case DIOCNATLOOK: { 1602 struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; 1603 struct pf_state *st; 1604 struct pf_tree_node key; 1605 int direction = pnl->direction; 1606 1607 key.af = pnl->af; 1608 key.proto = pnl->proto; 1609 1610 /* 1611 * userland gives us source and dest of connection, reverse 1612 * the lookup so we ask for what happens with the return 1613 * traffic, enabling us to find it in the state tree. 1614 */ 1615 PF_ACPY(&key.addr[1], &pnl->saddr, pnl->af); 1616 key.port[1] = pnl->sport; 1617 PF_ACPY(&key.addr[0], &pnl->daddr, pnl->af); 1618 key.port[0] = pnl->dport; 1619 1620 if (!pnl->proto || 1621 PF_AZERO(&pnl->saddr, pnl->af) || 1622 PF_AZERO(&pnl->daddr, pnl->af) || 1623 !pnl->dport || !pnl->sport) 1624 error = EINVAL; 1625 else { 1626 s = splsoftnet(); 1627 if (direction == PF_IN) 1628 st = pf_find_state(&tree_ext_gwy, &key); 1629 else 1630 st = pf_find_state(&tree_lan_ext, &key); 1631 if (st != NULL) { 1632 if (direction == PF_IN) { 1633 PF_ACPY(&pnl->rsaddr, &st->lan.addr, 1634 st->af); 1635 pnl->rsport = st->lan.port; 1636 PF_ACPY(&pnl->rdaddr, &pnl->daddr, 1637 pnl->af); 1638 pnl->rdport = pnl->dport; 1639 } else { 1640 PF_ACPY(&pnl->rdaddr, &st->gwy.addr, 1641 st->af); 1642 pnl->rdport = st->gwy.port; 1643 PF_ACPY(&pnl->rsaddr, &pnl->saddr, 1644 pnl->af); 1645 pnl->rsport = pnl->sport; 1646 } 1647 } else 1648 error = ENOENT; 1649 splx(s); 1650 } 1651 break; 1652 } 1653 1654 case DIOCSETTIMEOUT: { 1655 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 1656 int old; 1657 1658 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX || 1659 pt->seconds < 0) { 1660 error = EINVAL; 1661 goto fail; 1662 } 1663 old = pf_default_rule.timeout[pt->timeout]; 1664 pf_default_rule.timeout[pt->timeout] = pt->seconds; 1665 pt->seconds = old; 1666 break; 1667 } 1668 1669 case DIOCGETTIMEOUT: { 1670 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 1671 1672 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) { 1673 error = EINVAL; 1674 goto fail; 1675 } 1676 pt->seconds = pf_default_rule.timeout[pt->timeout]; 1677 break; 1678 } 1679 1680 case DIOCGETLIMIT: { 1681 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 1682 1683 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { 1684 error = EINVAL; 1685 goto fail; 1686 } 1687 pl->limit = pf_pool_limits[pl->index].limit; 1688 break; 1689 } 1690 1691 case DIOCSETLIMIT: { 1692 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 1693 int old_limit; 1694 1695 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { 1696 error = EINVAL; 1697 goto fail; 1698 } 1699#if defined(__FreeBSD__) 1700 uma_zone_set_max(pf_pool_limits[pl->index].pp, pl->limit); 1701#else 1702 if (pool_sethardlimit(pf_pool_limits[pl->index].pp, 1703 pl->limit, NULL, 0) != 0) { 1704 error = EBUSY; 1705 goto fail; 1706 } 1707#endif 1708 old_limit = pf_pool_limits[pl->index].limit; 1709 pf_pool_limits[pl->index].limit = pl->limit; 1710 pl->limit = old_limit; 1711 break; 1712 } 1713 1714 case DIOCSETDEBUG: { 1715 u_int32_t *level = (u_int32_t *)addr; 1716 1717 pf_status.debug = *level; 1718 break; 1719 } 1720 1721 case DIOCCLRRULECTRS: { 1722 struct pf_ruleset *ruleset = &pf_main_ruleset; 1723 struct pf_rule *rule; 1724 1725 s = splsoftnet(); 1726 TAILQ_FOREACH(rule, 1727 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) 1728 rule->evaluations = rule->packets = 1729 rule->bytes = 0; 1730 splx(s); 1731 break; 1732 } 1733 1734#if defined(__FreeBSD__) 1735 case DIOCGIFSPEED: { 1736 struct pf_ifspeed *psp = (struct pf_ifspeed *)addr; 1737 struct pf_ifspeed ps; 1738 struct ifnet *ifp; 1739 1740 if (psp->ifname[0] != 0) { 1741 /* Can we completely trust user-land? */ 1742 strlcpy(ps.ifname, psp->ifname, IFNAMSIZ); 1743 ifp = ifunit(ps.ifname); 1744 if (ifp ) 1745 psp->baudrate = ifp->if_baudrate; 1746 else 1747 error = EINVAL; 1748 } else 1749 error = EINVAL; 1750 break; 1751 } 1752#endif /* __FreeBSD__ */ 1753 1754#ifdef ALTQ 1755 case DIOCSTARTALTQ: { 1756 struct pf_altq *altq; 1757 struct ifnet *ifp; 1758 struct tb_profile tb; 1759 1760 /* enable all altq interfaces on active list */ 1761 s = splsoftnet(); 1762 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 1763 if (altq->qname[0] == 0) { 1764 if ((ifp = ifunit(altq->ifname)) == NULL) { 1765 error = EINVAL; 1766 break; 1767 } 1768 if (ifp->if_snd.altq_type != ALTQT_NONE) 1769 error = altq_enable(&ifp->if_snd); 1770 if (error != 0) 1771 break; 1772 /* set tokenbucket regulator */ 1773 tb.rate = altq->ifbandwidth; 1774 tb.depth = altq->tbrsize; 1775 error = tbr_set(&ifp->if_snd, &tb); 1776 if (error != 0) 1777 break; 1778 } 1779 } 1780#if defined(__FreeBSD__) 1781 if (error == 0) { 1782 mtx_lock(&pf_altq_mtx); 1783 pfaltq_running = 1; 1784 mtx_unlock(&pf_altq_mtx); 1785 } 1786#else 1787 if (error == 0) 1788 pfaltq_running = 1; 1789#endif 1790 splx(s); 1791 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n")); 1792 break; 1793 } 1794 1795 case DIOCSTOPALTQ: { 1796 struct pf_altq *altq; 1797 struct ifnet *ifp; 1798 struct tb_profile tb; 1799 int err; 1800 1801 /* disable all altq interfaces on active list */ 1802 s = splsoftnet(); 1803 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 1804 if (altq->qname[0] == 0) { 1805 if ((ifp = ifunit(altq->ifname)) == NULL) { 1806 error = EINVAL; 1807 break; 1808 } 1809 if (ifp->if_snd.altq_type != ALTQT_NONE) { 1810 err = altq_disable(&ifp->if_snd); 1811 if (err != 0 && error == 0) 1812 error = err; 1813 } 1814 /* clear tokenbucket regulator */ 1815 tb.rate = 0; 1816 err = tbr_set(&ifp->if_snd, &tb); 1817 if (err != 0 && error == 0) 1818 error = err; 1819 } 1820 } 1821#if defined(__FreeBSD__) 1822 if (error == 0) { 1823 mtx_lock(&pf_altq_mtx); 1824 pfaltq_running = 0; 1825 mtx_unlock(&pf_altq_mtx); 1826 } 1827#else 1828 if (error == 0) 1829 pfaltq_running = 0; 1830#endif 1831 splx(s); 1832 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n")); 1833 break; 1834 } 1835 1836 case DIOCBEGINALTQS: { 1837 u_int32_t *ticket = (u_int32_t *)addr; 1838 struct pf_altq *altq; 1839 1840 /* Purge the old altq list */ 1841 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 1842 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 1843 if (altq->qname[0] == 0) { 1844 /* detach and destroy the discipline */ 1845#if defined(__FreeBSD__) 1846 PF_UNLOCK(); 1847#endif 1848 error = altq_remove(altq); 1849#if defined(__FreeBSD__) 1850 PF_LOCK(); 1851#endif 1852 } 1853 pool_put(&pf_altq_pl, altq); 1854 } 1855 *ticket = ++ticket_altqs_inactive; 1856 break; 1857 } 1858 1859 case DIOCADDALTQ: { 1860 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 1861 struct pf_altq *altq, *a; 1862 1863 if (pa->ticket != ticket_altqs_inactive) { 1864 error = EBUSY; 1865 break; 1866 } 1867 altq = pool_get(&pf_altq_pl, PR_NOWAIT); 1868 if (altq == NULL) { 1869 error = ENOMEM; 1870 break; 1871 } 1872 bcopy(&pa->altq, altq, sizeof(struct pf_altq)); 1873 1874 /* 1875 * if this is for a queue, find the discipline and 1876 * copy the necessary fields 1877 */ 1878 if (altq->qname[0] != 0) { 1879 TAILQ_FOREACH(a, pf_altqs_inactive, entries) { 1880 if (strncmp(a->ifname, altq->ifname, 1881 IFNAMSIZ) == 0 && a->qname[0] == 0) { 1882 altq->altq_disc = a->altq_disc; 1883 break; 1884 } 1885 } 1886 } 1887 1888#if defined(__FreeBSD__) 1889 PF_UNLOCK(); 1890#endif 1891 error = altq_add(altq); 1892#if defined(__FreeBSD__) 1893 PF_LOCK(); 1894#endif 1895 if (error) { 1896 pool_put(&pf_altq_pl, altq); 1897 break; 1898 } 1899 1900 TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries); 1901 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 1902 break; 1903 } 1904 1905 case DIOCCOMMITALTQS: { 1906 u_int32_t *ticket = (u_int32_t *)addr; 1907 struct pf_altqqueue *old_altqs; 1908 struct pf_altq *altq; 1909 struct pf_anchor *anchor; 1910 struct pf_ruleset *ruleset; 1911 int err; 1912 1913 if (*ticket != ticket_altqs_inactive) { 1914 error = EBUSY; 1915 break; 1916 } 1917 1918 /* Swap altqs, keep the old. */ 1919 s = splsoftnet(); 1920 old_altqs = pf_altqs_active; 1921 pf_altqs_active = pf_altqs_inactive; 1922 pf_altqs_inactive = old_altqs; 1923 ticket_altqs_active = ticket_altqs_inactive; 1924 1925 /* Attach new disciplines */ 1926 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 1927 if (altq->qname[0] == 0) { 1928 /* attach the discipline */ 1929#if defined(__FreeBSD__) 1930 PF_UNLOCK(); 1931#endif 1932 error = altq_pfattach(altq); 1933#if defined(__FreeBSD__) 1934 PF_LOCK(); 1935#endif 1936 if (error) { 1937 splx(s); 1938 goto fail; 1939 } 1940 } 1941 } 1942 1943 /* Purge the old altq list */ 1944 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 1945 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 1946 if (altq->qname[0] == 0) { 1947 /* detach and destroy the discipline */ 1948#if defined(__FreeBSD__) 1949 PF_UNLOCK(); 1950#endif 1951 err = altq_pfdetach(altq); 1952 if (err != 0 && error == 0) 1953 error = err; 1954 err = altq_remove(altq); 1955 if (err != 0 && error == 0) 1956 error = err; 1957#if defined(__FreeBSD__) 1958 PF_LOCK(); 1959#endif 1960 } 1961 pool_put(&pf_altq_pl, altq); 1962 } 1963 splx(s); 1964 1965 /* update queue IDs */ 1966 pf_rule_set_qid( 1967 pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); 1968 TAILQ_FOREACH(anchor, &pf_anchors, entries) { 1969 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) { 1970 pf_rule_set_qid( 1971 ruleset->rules[PF_RULESET_FILTER].active.ptr 1972 ); 1973 } 1974 } 1975 break; 1976 } 1977 1978 case DIOCGETALTQS: { 1979 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 1980 struct pf_altq *altq; 1981 1982 pa->nr = 0; 1983 s = splsoftnet(); 1984 TAILQ_FOREACH(altq, pf_altqs_active, entries) 1985 pa->nr++; 1986 pa->ticket = ticket_altqs_active; 1987 splx(s); 1988 break; 1989 } 1990 1991 case DIOCGETALTQ: { 1992 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 1993 struct pf_altq *altq; 1994 u_int32_t nr; 1995 1996 if (pa->ticket != ticket_altqs_active) { 1997 error = EBUSY; 1998 break; 1999 } 2000 nr = 0; 2001 s = splsoftnet(); 2002 altq = TAILQ_FIRST(pf_altqs_active); 2003 while ((altq != NULL) && (nr < pa->nr)) { 2004 altq = TAILQ_NEXT(altq, entries); 2005 nr++; 2006 } 2007 if (altq == NULL) { 2008 error = EBUSY; 2009 splx(s); 2010 break; 2011 } 2012 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 2013 splx(s); 2014 break; 2015 } 2016 2017 case DIOCCHANGEALTQ: 2018 /* CHANGEALTQ not supported yet! */ 2019 error = ENODEV; 2020 break; 2021 2022 case DIOCGETQSTATS: { 2023 struct pfioc_qstats *pq = (struct pfioc_qstats *)addr; 2024 struct pf_altq *altq; 2025 u_int32_t nr; 2026 int nbytes; 2027 2028 if (pq->ticket != ticket_altqs_active) { 2029 error = EBUSY; 2030 break; 2031 } 2032 nbytes = pq->nbytes; 2033 nr = 0; 2034 s = splsoftnet(); 2035 altq = TAILQ_FIRST(pf_altqs_active); 2036 while ((altq != NULL) && (nr < pq->nr)) { 2037 altq = TAILQ_NEXT(altq, entries); 2038 nr++; 2039 } 2040 if (altq == NULL) { 2041 error = EBUSY; 2042 splx(s); 2043 break; 2044 } 2045#if defined(__FreeBSD__) 2046 PF_UNLOCK(); 2047#endif 2048 error = altq_getqstats(altq, pq->buf, &nbytes); 2049#if defined(__FreeBSD__) 2050 PF_LOCK(); 2051#endif 2052 splx(s); 2053 if (error == 0) { 2054 pq->scheduler = altq->scheduler; 2055 pq->nbytes = nbytes; 2056 } 2057 break; 2058 } 2059#endif /* ALTQ */ 2060 2061 case DIOCBEGINADDRS: { 2062 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2063 2064 pf_empty_pool(&pf_pabuf); 2065 pp->ticket = ++ticket_pabuf; 2066 break; 2067 } 2068 2069 case DIOCADDADDR: { 2070 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2071 2072#ifndef INET 2073 if (pp->af == AF_INET) { 2074 error = EAFNOSUPPORT; 2075 break; 2076 } 2077#endif /* INET */ 2078#ifndef INET6 2079 if (pp->af == AF_INET6) { 2080 error = EAFNOSUPPORT; 2081 break; 2082 } 2083#endif /* INET6 */ 2084 if (pp->addr.addr.type != PF_ADDR_ADDRMASK && 2085 pp->addr.addr.type != PF_ADDR_DYNIFTL && 2086 pp->addr.addr.type != PF_ADDR_TABLE) { 2087 error = EINVAL; 2088 break; 2089 } 2090 pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT); 2091 if (pa == NULL) { 2092 error = ENOMEM; 2093 break; 2094 } 2095 bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr)); 2096 if (pa->ifname[0]) { 2097 pa->ifp = ifunit(pa->ifname); 2098 if (pa->ifp == NULL) { 2099 pool_put(&pf_pooladdr_pl, pa); 2100 error = EINVAL; 2101 break; 2102 } 2103 } 2104 if (pf_dynaddr_setup(&pa->addr, pp->af)) { 2105 pf_dynaddr_remove(&pa->addr); 2106 pool_put(&pf_pooladdr_pl, pa); 2107 error = EINVAL; 2108 break; 2109 } 2110 TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries); 2111 break; 2112 } 2113 2114 case DIOCGETADDRS: { 2115 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2116 2117 pp->nr = 0; 2118 s = splsoftnet(); 2119 pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket, 2120 pp->r_action, pp->r_num, 0, 1, 0); 2121 if (pool == NULL) { 2122 error = EBUSY; 2123 splx(s); 2124 break; 2125 } 2126 TAILQ_FOREACH(pa, &pool->list, entries) 2127 pp->nr++; 2128 splx(s); 2129 break; 2130 } 2131 2132 case DIOCGETADDR: { 2133 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2134 u_int32_t nr = 0; 2135 2136 s = splsoftnet(); 2137 pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket, 2138 pp->r_action, pp->r_num, 0, 1, 1); 2139 if (pool == NULL) { 2140 error = EBUSY; 2141 splx(s); 2142 break; 2143 } 2144 pa = TAILQ_FIRST(&pool->list); 2145 while ((pa != NULL) && (nr < pp->nr)) { 2146 pa = TAILQ_NEXT(pa, entries); 2147 nr++; 2148 } 2149 if (pa == NULL) { 2150 error = EBUSY; 2151 splx(s); 2152 break; 2153 } 2154 bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr)); 2155 pf_dynaddr_copyout(&pp->addr.addr); 2156 pf_tbladdr_copyout(&pp->addr.addr); 2157 splx(s); 2158 break; 2159 } 2160 2161 case DIOCCHANGEADDR: { 2162 struct pfioc_pooladdr *pca = (struct pfioc_pooladdr *)addr; 2163 struct pf_pooladdr *oldpa = NULL, *newpa = NULL; 2164 struct pf_ruleset *ruleset; 2165 2166 if (pca->action < PF_CHANGE_ADD_HEAD || 2167 pca->action > PF_CHANGE_REMOVE) { 2168 error = EINVAL; 2169 break; 2170 } 2171 if (pca->addr.addr.type != PF_ADDR_ADDRMASK && 2172 pca->addr.addr.type != PF_ADDR_DYNIFTL && 2173 pca->addr.addr.type != PF_ADDR_TABLE) { 2174 error = EINVAL; 2175 break; 2176 } 2177 2178 ruleset = pf_find_ruleset(pca->anchor, pca->ruleset); 2179 if (ruleset == NULL) { 2180 error = EBUSY; 2181 break; 2182 } 2183 pool = pf_get_pool(pca->anchor, pca->ruleset, pca->ticket, 2184 pca->r_action, pca->r_num, pca->r_last, 1, 1); 2185 if (pool == NULL) { 2186 error = EBUSY; 2187 break; 2188 } 2189 if (pca->action != PF_CHANGE_REMOVE) { 2190 newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT); 2191 if (newpa == NULL) { 2192 error = ENOMEM; 2193 break; 2194 } 2195 bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr)); 2196#ifndef INET 2197 if (pca->af == AF_INET) { 2198 pool_put(&pf_pooladdr_pl, newpa); 2199 error = EAFNOSUPPORT; 2200 break; 2201 } 2202#endif /* INET */ 2203#ifndef INET6 2204 if (pca->af == AF_INET6) { 2205 pool_put(&pf_pooladdr_pl, newpa); 2206 error = EAFNOSUPPORT; 2207 break; 2208 } 2209#endif /* INET6 */ 2210 if (newpa->ifname[0]) { 2211 newpa->ifp = ifunit(newpa->ifname); 2212 if (newpa->ifp == NULL) { 2213 pool_put(&pf_pooladdr_pl, newpa); 2214 error = EINVAL; 2215 break; 2216 } 2217 } else 2218 newpa->ifp = NULL; 2219 if (pf_dynaddr_setup(&newpa->addr, pca->af) || 2220 pf_tbladdr_setup(ruleset, &newpa->addr)) { 2221 pf_dynaddr_remove(&newpa->addr); 2222 pool_put(&pf_pooladdr_pl, newpa); 2223 error = EINVAL; 2224 break; 2225 } 2226 } 2227 2228 s = splsoftnet(); 2229 2230 if (pca->action == PF_CHANGE_ADD_HEAD) 2231 oldpa = TAILQ_FIRST(&pool->list); 2232 else if (pca->action == PF_CHANGE_ADD_TAIL) 2233 oldpa = TAILQ_LAST(&pool->list, pf_palist); 2234 else { 2235 int i = 0; 2236 2237 oldpa = TAILQ_FIRST(&pool->list); 2238 while ((oldpa != NULL) && (i < pca->nr)) { 2239 oldpa = TAILQ_NEXT(oldpa, entries); 2240 i++; 2241 } 2242 if (oldpa == NULL) { 2243 error = EINVAL; 2244 splx(s); 2245 break; 2246 } 2247 } 2248 2249 if (pca->action == PF_CHANGE_REMOVE) { 2250 TAILQ_REMOVE(&pool->list, oldpa, entries); 2251 pf_dynaddr_remove(&oldpa->addr); 2252 pf_tbladdr_remove(&oldpa->addr); 2253 pool_put(&pf_pooladdr_pl, oldpa); 2254 } else { 2255 if (oldpa == NULL) 2256 TAILQ_INSERT_TAIL(&pool->list, newpa, entries); 2257 else if (pca->action == PF_CHANGE_ADD_HEAD || 2258 pca->action == PF_CHANGE_ADD_BEFORE) 2259 TAILQ_INSERT_BEFORE(oldpa, newpa, entries); 2260 else 2261 TAILQ_INSERT_AFTER(&pool->list, oldpa, 2262 newpa, entries); 2263 } 2264 2265 pool->cur = TAILQ_FIRST(&pool->list); 2266 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, 2267 pca->af); 2268 splx(s); 2269 break; 2270 } 2271 2272 case DIOCGETANCHORS: { 2273 struct pfioc_anchor *pa = (struct pfioc_anchor *)addr; 2274 struct pf_anchor *anchor; 2275 2276 pa->nr = 0; 2277 TAILQ_FOREACH(anchor, &pf_anchors, entries) 2278 pa->nr++; 2279 break; 2280 } 2281 2282 case DIOCGETANCHOR: { 2283 struct pfioc_anchor *pa = (struct pfioc_anchor *)addr; 2284 struct pf_anchor *anchor; 2285 u_int32_t nr = 0; 2286 2287 anchor = TAILQ_FIRST(&pf_anchors); 2288 while (anchor != NULL && nr < pa->nr) { 2289 anchor = TAILQ_NEXT(anchor, entries); 2290 nr++; 2291 } 2292 if (anchor == NULL) 2293 error = EBUSY; 2294 else 2295 bcopy(anchor->name, pa->name, sizeof(pa->name)); 2296 break; 2297 } 2298 2299 case DIOCGETRULESETS: { 2300 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 2301 struct pf_anchor *anchor; 2302 struct pf_ruleset *ruleset; 2303 2304 pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0; 2305 if ((anchor = pf_find_anchor(pr->anchor)) == NULL) { 2306 error = EINVAL; 2307 break; 2308 } 2309 pr->nr = 0; 2310 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) 2311 pr->nr++; 2312 break; 2313 } 2314 2315 case DIOCGETRULESET: { 2316 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 2317 struct pf_anchor *anchor; 2318 struct pf_ruleset *ruleset; 2319 u_int32_t nr = 0; 2320 2321 if ((anchor = pf_find_anchor(pr->anchor)) == NULL) { 2322 error = EINVAL; 2323 break; 2324 } 2325 ruleset = TAILQ_FIRST(&anchor->rulesets); 2326 while (ruleset != NULL && nr < pr->nr) { 2327 ruleset = TAILQ_NEXT(ruleset, entries); 2328 nr++; 2329 } 2330 if (ruleset == NULL) 2331 error = EBUSY; 2332 else 2333 bcopy(ruleset->name, pr->name, sizeof(pr->name)); 2334 break; 2335 } 2336 2337 case DIOCRCLRTABLES: { 2338 struct pfioc_table *io = (struct pfioc_table *)addr; 2339 2340 if (io->pfrio_esize != 0) { 2341 error = ENODEV; 2342 break; 2343 } 2344 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, 2345 io->pfrio_flags); 2346 break; 2347 } 2348 2349 case DIOCRADDTABLES: { 2350 struct pfioc_table *io = (struct pfioc_table *)addr; 2351 2352 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2353 error = ENODEV; 2354 break; 2355 } 2356 error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size, 2357 &io->pfrio_nadd, io->pfrio_flags); 2358 break; 2359 } 2360 2361 case DIOCRDELTABLES: { 2362 struct pfioc_table *io = (struct pfioc_table *)addr; 2363 2364 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2365 error = ENODEV; 2366 break; 2367 } 2368 error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size, 2369 &io->pfrio_ndel, io->pfrio_flags); 2370 break; 2371 } 2372 2373 case DIOCRGETTABLES: { 2374 struct pfioc_table *io = (struct pfioc_table *)addr; 2375 2376 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2377 error = ENODEV; 2378 break; 2379 } 2380 error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer, 2381 &io->pfrio_size, io->pfrio_flags); 2382 break; 2383 } 2384 2385 case DIOCRGETTSTATS: { 2386 struct pfioc_table *io = (struct pfioc_table *)addr; 2387 2388 if (io->pfrio_esize != sizeof(struct pfr_tstats)) { 2389 error = ENODEV; 2390 break; 2391 } 2392 error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer, 2393 &io->pfrio_size, io->pfrio_flags); 2394 break; 2395 } 2396 2397 case DIOCRCLRTSTATS: { 2398 struct pfioc_table *io = (struct pfioc_table *)addr; 2399 2400 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2401 error = ENODEV; 2402 break; 2403 } 2404 error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size, 2405 &io->pfrio_nzero, io->pfrio_flags); 2406 break; 2407 } 2408 2409 case DIOCRSETTFLAGS: { 2410 struct pfioc_table *io = (struct pfioc_table *)addr; 2411 2412 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2413 error = ENODEV; 2414 break; 2415 } 2416 error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size, 2417 io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange, 2418 &io->pfrio_ndel, io->pfrio_flags); 2419 break; 2420 } 2421 2422 case DIOCRCLRADDRS: { 2423 struct pfioc_table *io = (struct pfioc_table *)addr; 2424 2425 if (io->pfrio_esize != 0) { 2426 error = ENODEV; 2427 break; 2428 } 2429 error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel, 2430 io->pfrio_flags); 2431 break; 2432 } 2433 2434 case DIOCRADDADDRS: { 2435 struct pfioc_table *io = (struct pfioc_table *)addr; 2436 2437 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2438 error = ENODEV; 2439 break; 2440 } 2441 error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer, 2442 io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags); 2443 break; 2444 } 2445 2446 case DIOCRDELADDRS: { 2447 struct pfioc_table *io = (struct pfioc_table *)addr; 2448 2449 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2450 error = ENODEV; 2451 break; 2452 } 2453 error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer, 2454 io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags); 2455 break; 2456 } 2457 2458 case DIOCRSETADDRS: { 2459 struct pfioc_table *io = (struct pfioc_table *)addr; 2460 2461 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2462 error = ENODEV; 2463 break; 2464 } 2465 error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer, 2466 io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd, 2467 &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags); 2468 break; 2469 } 2470 2471 case DIOCRGETADDRS: { 2472 struct pfioc_table *io = (struct pfioc_table *)addr; 2473 2474 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2475 error = ENODEV; 2476 break; 2477 } 2478 error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer, 2479 &io->pfrio_size, io->pfrio_flags); 2480 break; 2481 } 2482 2483 case DIOCRGETASTATS: { 2484 struct pfioc_table *io = (struct pfioc_table *)addr; 2485 2486 if (io->pfrio_esize != sizeof(struct pfr_astats)) { 2487 error = ENODEV; 2488 break; 2489 } 2490 error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer, 2491 &io->pfrio_size, io->pfrio_flags); 2492 break; 2493 } 2494 2495 case DIOCRCLRASTATS: { 2496 struct pfioc_table *io = (struct pfioc_table *)addr; 2497 2498 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2499 error = ENODEV; 2500 break; 2501 } 2502 error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer, 2503 io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags); 2504 break; 2505 } 2506 2507 case DIOCRTSTADDRS: { 2508 struct pfioc_table *io = (struct pfioc_table *)addr; 2509 2510 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2511 error = ENODEV; 2512 break; 2513 } 2514 error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer, 2515 io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags); 2516 break; 2517 } 2518 2519 case DIOCRINABEGIN: { 2520 struct pfioc_table *io = (struct pfioc_table *)addr; 2521 2522 if (io->pfrio_esize != 0) { 2523 error = ENODEV; 2524 break; 2525 } 2526 error = pfr_ina_begin(&io->pfrio_table, &io->pfrio_ticket, 2527 &io->pfrio_ndel, io->pfrio_flags); 2528 break; 2529 } 2530 2531 case DIOCRINACOMMIT: { 2532 struct pfioc_table *io = (struct pfioc_table *)addr; 2533 2534 if (io->pfrio_esize != 0) { 2535 error = ENODEV; 2536 break; 2537 } 2538 error = pfr_ina_commit(&io->pfrio_table, io->pfrio_ticket, 2539 &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags); 2540 break; 2541 } 2542 2543 case DIOCRINADEFINE: { 2544 struct pfioc_table *io = (struct pfioc_table *)addr; 2545 2546 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2547 error = ENODEV; 2548 break; 2549 } 2550 error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer, 2551 io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr, 2552 io->pfrio_ticket, io->pfrio_flags); 2553 break; 2554 } 2555 2556 case DIOCOSFPFLUSH: 2557 s = splsoftnet(); 2558 pf_osfp_flush(); 2559 splx(s); 2560 break; 2561 2562 case DIOCOSFPADD: { 2563 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 2564 s = splsoftnet(); 2565 error = pf_osfp_add(io); 2566 splx(s); 2567 break; 2568 } 2569 2570 case DIOCOSFPGET: { 2571 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 2572 s = splsoftnet(); 2573 error = pf_osfp_get(io); 2574 splx(s); 2575 break; 2576 } 2577 2578 default: 2579 error = ENODEV; 2580 break; 2581 } 2582fail: 2583#if defined(__FreeBSD__) 2584 PF_UNLOCK(); 2585#endif 2586 return (error); 2587} 2588 2589#if defined(__FreeBSD__) 2590/* 2591 * XXX - Check for version missmatch!!! 2592 */ 2593static int 2594pf_beginrules(void *addr) 2595{ 2596 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 2597 struct pf_ruleset *ruleset; 2598 struct pf_rule *rule; 2599 int rs_num; 2600 int error = 0; 2601 2602 do { 2603 ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset); 2604 if (ruleset == NULL) { 2605 error = EINVAL; 2606 break; 2607 } 2608 rs_num = pf_get_ruleset_number(pr->rule.action); 2609 if (rs_num >= PF_RULESET_MAX) { 2610 error = EINVAL; 2611 break; 2612 } 2613 while ((rule = 2614 TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL) 2615 pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule); 2616 pr->ticket = ++ruleset->rules[rs_num].inactive.ticket; 2617 } while(0); 2618 2619 return (error); 2620} 2621 2622static int 2623pf_commitrules(void *addr) 2624{ 2625 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 2626 struct pf_ruleset *ruleset; 2627 struct pf_rulequeue *old_rules; 2628 struct pf_rule *rule; 2629 int rs_num, s; 2630 int error = 0; 2631 2632 do { 2633 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 2634 if (ruleset == NULL) { 2635 error = EINVAL; 2636 break; 2637 } 2638 rs_num = pf_get_ruleset_number(pr->rule.action); 2639 if (rs_num >= PF_RULESET_MAX) { 2640 error = EINVAL; 2641 break; 2642 } 2643 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { 2644 error = EBUSY; 2645 break; 2646 } 2647 2648#ifdef ALTQ 2649 /* set queue IDs */ 2650 if (rs_num == PF_RULESET_FILTER) 2651 pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr); 2652#endif 2653 2654 /* Swap rules, keep the old. */ 2655 s = splsoftnet(); 2656 old_rules = ruleset->rules[rs_num].active.ptr; 2657 ruleset->rules[rs_num].active.ptr = 2658 ruleset->rules[rs_num].inactive.ptr; 2659 ruleset->rules[rs_num].inactive.ptr = old_rules; 2660 ruleset->rules[rs_num].active.ticket = 2661 ruleset->rules[rs_num].inactive.ticket; 2662 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); 2663 2664 /* Purge the old rule list. */ 2665 while ((rule = TAILQ_FIRST(old_rules)) != NULL) 2666 pf_rm_rule(old_rules, rule); 2667 pf_remove_if_empty_ruleset(ruleset); 2668 pf_update_anchor_rules(); 2669 splx(s); 2670 } while (0); 2671 2672 return (error); 2673} 2674 2675#if defined(ALTQ) 2676static int 2677pf_beginaltqs(void *addr) 2678{ 2679 u_int32_t *ticket = (u_int32_t *)addr; 2680 struct pf_altq *altq; 2681 int error = 0; 2682 2683 /* Purge the old altq list */ 2684 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 2685 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 2686 if (altq->qname[0] == 0) { 2687#if defined(__FreeBSD__) 2688 PF_UNLOCK(); 2689#endif 2690 /* detach and destroy the discipline */ 2691 error = altq_remove(altq); 2692#if defined(__FreeBSD__) 2693 PF_LOCK(); 2694#endif 2695 } 2696 uma_zfree(pf_altq_pl, altq); 2697 } 2698 *ticket = ++ticket_altqs_inactive; 2699 2700 return (error); 2701} 2702 2703static int 2704pf_commitaltqs(void *addr) 2705{ 2706 u_int32_t *ticket = (u_int32_t *)addr; 2707 struct pf_altqqueue *old_altqs; 2708 struct pf_altq *altq; 2709 struct pf_anchor *anchor; 2710 struct pf_ruleset *ruleset; 2711 int err; 2712 int s; 2713 int error = 0; 2714 2715 do { 2716 if (*ticket != ticket_altqs_inactive) { 2717 error = EBUSY; 2718 break; 2719 } 2720 2721 /* Swap altqs, keep the old. */ 2722 s = splsoftnet(); 2723 old_altqs = pf_altqs_active; 2724 pf_altqs_active = pf_altqs_inactive; 2725 pf_altqs_inactive = old_altqs; 2726 ticket_altqs_active = ticket_altqs_inactive; 2727 2728 /* Attach new disciplines */ 2729 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 2730 if (altq->qname[0] == 0) { 2731 /* attach the discipline */ 2732#if defined(__FreeBSD__) 2733 PF_UNLOCK(); 2734#endif 2735 error = altq_pfattach(altq); 2736#if defined(__FreeBSD__) 2737 PF_LOCK(); 2738#endif 2739 if (error) { 2740 splx(s); 2741 goto altq_fail; 2742 } 2743 } 2744 } 2745 2746 /* Purge the old altq list */ 2747 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 2748 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 2749 if (altq->qname[0] == 0) { 2750 /* detach and destroy the discipline */ 2751#if defined(__FreeBSD__) 2752 PF_UNLOCK(); 2753#endif 2754 err = altq_pfdetach(altq); 2755 if (err != 0 && error == 0) 2756 error = err; 2757 err = altq_remove(altq); 2758 if (err != 0 && error == 0) 2759 error = err; 2760#if defined(__FreeBSD__) 2761 PF_LOCK(); 2762#endif 2763 } 2764 uma_zfree(pf_altq_pl, altq); 2765 } 2766 splx(s); 2767 2768 /* update queue IDs */ 2769 pf_rule_set_qid( 2770 pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); 2771 TAILQ_FOREACH(anchor, &pf_anchors, entries) { 2772 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) { 2773 pf_rule_set_qid( 2774 ruleset->rules[PF_RULESET_FILTER].active.ptr 2775 ); 2776 } 2777 } 2778 } while (0); 2779 2780altq_fail: 2781 2782 return (error); 2783} 2784 2785static int 2786pf_stopaltq(void) 2787{ 2788 struct pf_altq *altq; 2789 struct ifnet *ifp; 2790 struct tb_profile tb; 2791 int err; 2792 int s; 2793 int error = 0; 2794 2795 do { 2796 /* disable all altq interfaces on active list */ 2797 s = splsoftnet(); 2798 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 2799 if (altq->qname[0] == 0) { 2800 if ((ifp = ifunit(altq->ifname)) == NULL) { 2801 error = EINVAL; 2802 break; 2803 } 2804 if (ifp->if_snd.altq_type != ALTQT_NONE) { 2805 err = altq_disable(&ifp->if_snd); 2806 if (err != 0 && error == 0) 2807 error = err; 2808 } 2809 /* clear tokenbucket regulator */ 2810 tb.rate = 0; 2811 err = tbr_set(&ifp->if_snd, &tb); 2812 if (err != 0 && error == 0) 2813 error = err; 2814 } 2815 } 2816#if defined(__FreeBSD__) 2817 if (error == 0) { 2818 mtx_lock(&pf_altq_mtx); 2819 pfaltq_running = 0; 2820 mtx_unlock(&pf_altq_mtx); 2821 } 2822#else 2823 if (error == 0) 2824 pfaltq_running = 0; 2825#endif 2826 splx(s); 2827 } while (0); 2828 2829 return (error); 2830} 2831#endif 2832 2833static void 2834pf_clearstates(void) 2835{ 2836 struct pf_tree_node *n; 2837 int s; 2838 2839 s = splsoftnet(); 2840 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) 2841 n->state->timeout = PFTM_PURGE; 2842 pf_purge_expired_states(); 2843 pf_status.states = 0; 2844 splx(s); 2845} 2846 2847static int 2848pf_clear_tables(void *addr) 2849{ 2850 struct pfioc_table *io = (struct pfioc_table *)addr; 2851 int error; 2852 2853 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, 2854 io->pfrio_flags); 2855 2856 return (error); 2857} 2858 2859static int 2860shutdown_pf(void) 2861{ 2862 struct pfioc_rule pr; 2863#if defined(ALTQ) 2864 struct pfioc_altq pa; 2865#endif 2866 struct pfioc_table io; 2867 int error = 0; 2868 2869 callout_stop(&pf_expire_to); 2870 2871 PF_LOCK(); 2872 pf_status.running = 0; 2873 do { 2874#if defined(ALTQ) 2875 if ((error = pf_stopaltq())) { 2876 DPFPRINTF(PF_DEBUG_MISC, 2877 ("ALTQ: stop(%i)\n", error)); 2878 break; 2879 } 2880#endif 2881 bzero(&pr, sizeof(pr)); 2882 pr.rule.action = PF_SCRUB; 2883 if ((error = pf_beginrules(&pr))) { 2884 DPFPRINTF(PF_DEBUG_MISC, 2885 ("PF_SCRUB: begin(%i)\n", error)); 2886 break; 2887 } 2888 if ((error = pf_commitrules(&pr))) { 2889 DPFPRINTF(PF_DEBUG_MISC, 2890 ("PF_SCRUB: commit(%i)\n", error)); 2891 break; 2892 } 2893 2894 pr.rule.action = PF_PASS; 2895 if ((error = pf_beginrules(&pr))) { 2896 DPFPRINTF(PF_DEBUG_MISC, 2897 ("PF_PASS: begin(%i)\n", error)); 2898 break; 2899 } 2900 if ((error = pf_commitrules(&pr))) { 2901 DPFPRINTF(PF_DEBUG_MISC, 2902 ("PF_PASS: commit(%i)\n", error)); 2903 break; 2904 } 2905 2906/* 2907 * XXX not sure, but can't hurt: 2908 */ 2909 bzero(&pr, sizeof(pr)); 2910 pr.rule.action = PF_NAT; 2911 if ((error = pf_beginrules(&pr))) { 2912 DPFPRINTF(PF_DEBUG_MISC, 2913 ("PF_NAT: begin(%i)\n", error)); 2914 break; 2915 } 2916 if ((error = pf_commitrules(&pr))) { 2917 DPFPRINTF(PF_DEBUG_MISC, 2918 ("PF_NAT: commit(%i)\n", error)); 2919 break; 2920 } 2921 2922 pr.rule.action = PF_BINAT; 2923 if ((error = pf_beginrules(&pr))) { 2924 DPFPRINTF(PF_DEBUG_MISC, 2925 ("PF_BINAT: begin(%i)\n", error)); 2926 break; 2927 } 2928 if ((error = pf_commitrules(&pr))) { 2929 DPFPRINTF(PF_DEBUG_MISC, 2930 ("PF_BINAT: begin(%i)\n", error)); 2931 break; 2932 } 2933 2934 pr.rule.action = PF_RDR; 2935 if ((error = pf_beginrules(&pr))) { 2936 DPFPRINTF(PF_DEBUG_MISC, 2937 ("PF_RDR: begin(%i)\n", error)); 2938 break; 2939 } 2940 if ((error = pf_commitrules(&pr))) { 2941 DPFPRINTF(PF_DEBUG_MISC, 2942 ("PF_RDR: commit(%i)\n", error)); 2943 break; 2944 } 2945 2946#if defined(ALTQ) 2947 bzero(&pa, sizeof(pa)); 2948 if ((error = pf_beginaltqs(&pa))) { 2949 DPFPRINTF(PF_DEBUG_MISC, 2950 ("ALTQ: begin(%i)\n", error)); 2951 break; 2952 } 2953 if ((error = pf_commitaltqs(&pa))) { 2954 DPFPRINTF(PF_DEBUG_MISC, 2955 ("ALTQ: commit(%i)\n", error)); 2956 break; 2957 } 2958#endif 2959 pf_clearstates(); 2960 2961 bzero(&io, sizeof(io)); 2962 if ((error = pf_clear_tables(&io))) { 2963 DPFPRINTF(PF_DEBUG_MISC, 2964 ("TABLES: clear(%i)\n", error)); 2965 break; 2966 } 2967 pf_osfp_flush(); 2968 } while(0); 2969 2970 PF_UNLOCK(); 2971 return (error); 2972} 2973 2974static int 2975#if (__FreeBSD_version < 501108) 2976pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m) 2977#else 2978pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) 2979#endif 2980{ 2981 /* 2982 * XXX Wed Jul 9 22:03:16 2003 UTC 2983 * OpenBSD has changed its byte ordering convention on ip_len/ip_off 2984 * in network stack. OpenBSD's network stack have converted 2985 * ip_len/ip_off to host byte order frist as FreeBSD. 2986 * Now this is not true anymore , so we should convert back to network 2987 * byte order. 2988 */ 2989 struct ip *h = NULL; 2990 int chk; 2991 2992 if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) { 2993 /* if m_pkthdr.len is less than ip header, pf will handle. */ 2994 h = mtod(*m, struct ip *); 2995 HTONS(h->ip_len); 2996 HTONS(h->ip_off); 2997 } 2998 chk = pf_test(PF_IN, ifp, m); 2999 if (chk && *m) { 3000 m_freem(*m); 3001 *m = NULL; 3002 } 3003 if (*m != NULL) { 3004 /* pf_test can change ip header location */ 3005 h = mtod(*m, struct ip *); 3006 NTOHS(h->ip_len); 3007 NTOHS(h->ip_off); 3008 } 3009 return chk; 3010} 3011 3012static int 3013#if (__FreeBSD_version < 501108) 3014pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m) 3015#else 3016pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) 3017#endif 3018{ 3019 /* 3020 * XXX Wed Jul 9 22:03:16 2003 UTC 3021 * OpenBSD has changed its byte ordering convention on ip_len/ip_off 3022 * in network stack. OpenBSD's network stack have converted 3023 * ip_len/ip_off to host byte order frist as FreeBSD. 3024 * Now this is not true anymore , so we should convert back to network 3025 * byte order. 3026 */ 3027 struct ip *h = NULL; 3028 int chk; 3029 3030 /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */ 3031 if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 3032 in_delayed_cksum(*m); 3033 (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 3034 } 3035 if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) { 3036 /* if m_pkthdr.len is less than ip header, pf will handle. */ 3037 h = mtod(*m, struct ip *); 3038 HTONS(h->ip_len); 3039 HTONS(h->ip_off); 3040 } 3041 chk = pf_test(PF_OUT, ifp, m); 3042 if (chk && *m) { 3043 m_freem(*m); 3044 *m = NULL; 3045 } 3046 if (*m != NULL) { 3047 /* pf_test can change ip header location */ 3048 h = mtod(*m, struct ip *); 3049 NTOHS(h->ip_len); 3050 NTOHS(h->ip_off); 3051 } 3052 return chk; 3053} 3054 3055#ifdef INET6 3056static int 3057#if (__FreeBSD_version < 501108) 3058pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m) 3059#else 3060pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) 3061#endif 3062{ 3063 /* 3064 * IPv6 does not affected ip_len/ip_off byte order changes. 3065 */ 3066 int chk; 3067 3068 chk = pf_test6(PF_IN, ifp, m); 3069 if (chk && *m) { 3070 m_freem(*m); 3071 *m = NULL; 3072 } 3073 return chk; 3074} 3075 3076static int 3077#if (__FreeBSD_version < 501108) 3078pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m) 3079#else 3080pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) 3081#endif 3082{ 3083 /* 3084 * IPv6 does not affected ip_len/ip_off byte order changes. 3085 */ 3086 int chk; 3087 3088 /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */ 3089 if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 3090 in_delayed_cksum(*m); 3091 (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 3092 } 3093 chk = pf_test6(PF_OUT, ifp, m); 3094 if (chk && *m) { 3095 m_freem(*m); 3096 *m = NULL; 3097 } 3098 return chk; 3099} 3100#endif /* INET6 */ 3101 3102static int 3103hook_pf(void) 3104{ 3105#if (__FreeBSD_version >= 501108) 3106 struct pfil_head *pfh_inet; 3107#if defined(INET6) 3108 struct pfil_head *pfh_inet6; 3109#endif 3110#endif 3111 3112 PF_ASSERT(MA_NOTOWNED); 3113 3114 if (pf_pfil_hooked) 3115 return (0); 3116 3117#if (__FreeBSD_version < 501108) 3118 /* 3119 * XXX 3120 * There is no easy way to get pfil header pointer with address 3121 * family such as AF_INET, AF_INET6. 3122 * Needs direct variable reference. 3123 */ 3124 3125 pfil_add_hook(pf_check_in, PFIL_IN, 3126 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 3127 pfil_add_hook(pf_check_out, PFIL_OUT, 3128 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 3129#if defined(INET6) 3130 pfil_add_hook(pf_check6_in, PFIL_IN, 3131 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 3132 pfil_add_hook(pf_check6_out, PFIL_OUT, 3133 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 3134#endif 3135#else /* __FreeBSD_version >= 501108 */ 3136 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 3137 if (pfh_inet == NULL) 3138 return (ESRCH); /* XXX */ 3139 pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); 3140 pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); 3141#if defined(INET6) 3142 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 3143 if (pfh_inet6 == NULL) { 3144 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, 3145 pfh_inet); 3146 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 3147 pfh_inet); 3148 return (ESRCH); /* XXX */ 3149 } 3150 pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); 3151 pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); 3152#endif 3153#endif /* __FreeBSD_version >= 501108 */ 3154 3155 pf_pfil_hooked = 1; 3156 return (0); 3157} 3158 3159static int 3160dehook_pf(void) 3161{ 3162#if (__FreeBSD_version >= 501108) 3163 struct pfil_head *pfh_inet; 3164#if defined(INET6) 3165 struct pfil_head *pfh_inet6; 3166#endif 3167#endif 3168 3169 PF_ASSERT(MA_NOTOWNED); 3170 3171 if (pf_pfil_hooked == 0) 3172 return (0); 3173 3174#if (__FreeBSD_version < 501108) 3175 pfil_remove_hook(pf_check_in, PFIL_IN, 3176 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 3177 pfil_remove_hook(pf_check_out, PFIL_OUT, 3178 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 3179#if defined(INET6) 3180 pfil_remove_hook(pf_check6_in, PFIL_IN, 3181 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 3182 pfil_remove_hook(pf_check6_out, PFIL_OUT, 3183 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 3184#endif 3185#else /* __FreeBSD_version >= 501108 */ 3186 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 3187 if (pfh_inet == NULL) 3188 return (ESRCH); /* XXX */ 3189 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, 3190 pfh_inet); 3191 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 3192 pfh_inet); 3193#if defined(INET6) 3194 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 3195 if (pfh_inet6 == NULL) 3196 return (ESRCH); /* XXX */ 3197 pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, 3198 pfh_inet6); 3199 pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, 3200 pfh_inet6); 3201#endif 3202#endif /* __FreeBSD_version >= 501108 */ 3203 3204 pf_pfil_hooked = 0; 3205 return (0); 3206} 3207 3208static int 3209pf_load(void) 3210{ 3211 init_zone_var(); 3212 init_pf_mutex(); 3213 pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME); 3214 if (pfattach() < 0) { 3215 destroy_dev(pf_dev); 3216 destroy_pf_mutex(); 3217 return (ENOMEM); 3218 } 3219#if defined(ALTQ) 3220 mtx_lock(&pf_altq_mtx); 3221 ++pfaltq_ref; 3222 mtx_unlock(&pf_altq_mtx); 3223#endif 3224 return (0); 3225} 3226 3227static int 3228pf_unload(void) 3229{ 3230 int error = 0; 3231 3232 PF_LOCK(); 3233 pf_status.running = 0; 3234 PF_UNLOCK(); 3235 error = dehook_pf(); 3236 if (error) { 3237 /* 3238 * Should not happen! 3239 * XXX Due to error code ESRCH, kldunload will show 3240 * a message like 'No such process'. 3241 */ 3242 printf("%s : pfil unregisteration fail\n", __FUNCTION__); 3243 return error; 3244 } 3245 shutdown_pf(); 3246 cleanup_pf_zone(); 3247 pf_osfp_cleanup(); 3248 destroy_dev(pf_dev); 3249#if defined(ALTQ) 3250 mtx_lock(&pf_altq_mtx); 3251 --pfaltq_ref; 3252 mtx_unlock(&pf_altq_mtx); 3253#endif 3254 destroy_pf_mutex(); 3255 return error; 3256} 3257 3258static int 3259pf_modevent(module_t mod, int type, void *data) 3260{ 3261 int error = 0; 3262 3263 switch(type) { 3264 case MOD_LOAD: 3265 error = pf_load(); 3266 break; 3267 3268 case MOD_UNLOAD: 3269 error = pf_unload(); 3270 break; 3271 default: 3272 error = EINVAL; 3273 break; 3274 } 3275 return error; 3276} 3277 3278static moduledata_t pf_mod = { 3279 "pf", 3280 pf_modevent, 3281 0 3282}; 3283 3284DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 3285MODULE_DEPEND(pf, pflog, PFLOG_MINVER, PFLOG_PREFVER, PFLOG_MAXVER); 3286MODULE_DEPEND(pf, pfsync, PFSYNC_MINVER, PFSYNC_PREFVER, PFSYNC_MAXVER); 3287#if defined(ALTQ) 3288MODULE_DEPEND(pf, pfaltq, PFALTQ_MINVER, PFALTQ_PREFVER, PFALTQ_MAXVER); 3289#endif 3290MODULE_VERSION(pf, PF_MODVER); 3291#endif /* __FreeBSD__ */ 3292