pf_ioctl.c revision 261019
1186904Ssam/*- 2186904Ssam * Copyright (c) 2001 Daniel Hartmeier 3186904Ssam * Copyright (c) 2002,2003 Henning Brauer 4186904Ssam * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org> 5186904Ssam * All rights reserved. 6186904Ssam * 7186904Ssam * Redistribution and use in source and binary forms, with or without 8186904Ssam * modification, are permitted provided that the following conditions 9186904Ssam * are met: 10186904Ssam * 11186904Ssam * - Redistributions of source code must retain the above copyright 12186904Ssam * notice, this list of conditions and the following disclaimer. 13186904Ssam * - Redistributions in binary form must reproduce the above 14186904Ssam * copyright notice, this list of conditions and the following 15186904Ssam * disclaimer in the documentation and/or other materials provided 16186904Ssam * with the distribution. 17186904Ssam * 18186904Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19186904Ssam * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20186904Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21186904Ssam * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22186904Ssam * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23186904Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24186904Ssam * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25186904Ssam * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26186904Ssam * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27186904Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28186904Ssam * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29186904Ssam * POSSIBILITY OF SUCH DAMAGE. 30186904Ssam * 31186904Ssam * Effort sponsored in part by the Defense Advanced Research Projects 32186904Ssam * Agency (DARPA) and Air Force Research Laboratory, Air Force 33186904Ssam * Materiel Command, USAF, under agreement number F30602-01-2-0537. 34186904Ssam * 35186904Ssam * $OpenBSD: pf_ioctl.c,v 1.213 2009/02/15 21:46:12 mbalmer Exp $ 36190455Ssam */ 37186904Ssam 38186904Ssam#include <sys/cdefs.h> 39230153Sadrian__FBSDID("$FreeBSD: stable/10/sys/netpfil/pf/pf_ioctl.c 261019 2014-01-22 10:29:15Z glebius $"); 40230153Sadrian 41186904Ssam#include "opt_inet.h" 42186904Ssam#include "opt_inet6.h" 43186904Ssam#include "opt_bpf.h" 44186904Ssam#include "opt_pf.h" 45186904Ssam 46186904Ssam#include <sys/param.h> 47186904Ssam#include <sys/bus.h> 48186904Ssam#include <sys/conf.h> 49186904Ssam#include <sys/endian.h> 50186904Ssam#include <sys/fcntl.h> 51186904Ssam#include <sys/filio.h> 52186904Ssam#include <sys/interrupt.h> 53186904Ssam#include <sys/jail.h> 54186904Ssam#include <sys/kernel.h> 55186904Ssam#include <sys/kthread.h> 56186904Ssam#include <sys/mbuf.h> 57186904Ssam#include <sys/module.h> 58186904Ssam#include <sys/proc.h> 59186904Ssam#include <sys/smp.h> 60186904Ssam#include <sys/socket.h> 61186904Ssam#include <sys/sysctl.h> 62186904Ssam#include <sys/md5.h> 63186904Ssam#include <sys/ucred.h> 64186904Ssam 65186904Ssam#include <net/if.h> 66186904Ssam#include <net/route.h> 67186904Ssam#include <net/pfil.h> 68186904Ssam#include <net/pfvar.h> 69186904Ssam#include <net/if_pfsync.h> 70186904Ssam#include <net/if_pflog.h> 71186904Ssam 72186904Ssam#include <netinet/in.h> 73186904Ssam#include <netinet/ip.h> 74186904Ssam#include <netinet/ip_var.h> 75186904Ssam#include <netinet/ip_icmp.h> 76186904Ssam 77186904Ssam#ifdef INET6 78186904Ssam#include <netinet/ip6.h> 79186904Ssam#endif /* INET6 */ 80186904Ssam 81186904Ssam#ifdef ALTQ 82186904Ssam#include <altq/altq.h> 83191018Ssam#endif 84191018Ssam 85187899Ssamstatic int pfattach(void); 86188782Ssamstatic struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t, 87188782Ssam u_int8_t, u_int8_t, u_int8_t); 88188782Ssam 89188782Ssamstatic void pf_mv_pool(struct pf_palist *, struct pf_palist *); 90188782Ssamstatic void pf_empty_pool(struct pf_palist *); 91188782Ssamstatic int pfioctl(struct cdev *, u_long, caddr_t, int, 92187899Ssam struct thread *); 93187899Ssam#ifdef ALTQ 94187899Ssamstatic int pf_begin_altq(u_int32_t *); 95187899Ssamstatic int pf_rollback_altq(u_int32_t); 96187899Ssamstatic int pf_commit_altq(u_int32_t); 97187899Ssamstatic int pf_enable_altq(struct pf_altq *); 98186904Ssamstatic int pf_disable_altq(struct pf_altq *); 99190455Ssamstatic u_int32_t pf_qname2qid(char *); 100190455Ssamstatic void pf_qid_unref(u_int32_t); 101190455Ssam#endif /* ALTQ */ 102190455Ssamstatic int pf_begin_rules(u_int32_t *, int, const char *); 103190455Ssamstatic int pf_rollback_rules(u_int32_t, int, char *); 104190455Ssamstatic int pf_setup_pfsync_matching(struct pf_ruleset *); 105190455Ssamstatic void pf_hash_rule(MD5_CTX *, struct pf_rule *); 106190455Ssamstatic void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *); 107190455Ssamstatic int pf_commit_rules(u_int32_t, int, char *); 108190455Ssamstatic int pf_addr_setup(struct pf_ruleset *, 109193114Ssam struct pf_addr_wrap *, sa_family_t); 110193114Ssamstatic void pf_addr_copyout(struct pf_addr_wrap *); 111193114Ssam 112193114SsamVNET_DEFINE(struct pf_rule, pf_default_rule); 113193114Ssam 114186904Ssam#ifdef ALTQ 115186904Ssamstatic VNET_DEFINE(int, pf_altq_running); 116186904Ssam#define V_pf_altq_running VNET(pf_altq_running) 117186904Ssam#endif 118192468Ssam 119186904Ssam#define TAGID_MAX 50000 120186904Ssamstruct pf_tagname { 121186904Ssam TAILQ_ENTRY(pf_tagname) entries; 122186904Ssam char name[PF_TAG_NAME_SIZE]; 123192468Ssam uint16_t tag; 124186904Ssam int ref; 125186904Ssam}; 126187899Ssam 127187899SsamTAILQ_HEAD(pf_tags, pf_tagname); 128187899Ssam#define V_pf_tags VNET(pf_tags) 129187899SsamVNET_DEFINE(struct pf_tags, pf_tags); 130187899Ssam#define V_pf_qids VNET(pf_qids) 131187899SsamVNET_DEFINE(struct pf_tags, pf_qids); 132187899Ssamstatic MALLOC_DEFINE(M_PFTAG, "pf_tag", "pf(4) tag names"); 133186904Ssamstatic MALLOC_DEFINE(M_PFALTQ, "pf_altq", "pf(4) altq configuration db"); 134186904Ssamstatic MALLOC_DEFINE(M_PFRULE, "pf_rule", "pf(4) rules"); 135186904Ssam 136186904Ssam#if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE) 137186904Ssam#error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE 138186904Ssam#endif 139186904Ssam 140186904Ssamstatic u_int16_t tagname2tag(struct pf_tags *, char *); 141186904Ssamstatic u_int16_t pf_tagname2tag(char *); 142186904Ssamstatic void tag_unref(struct pf_tags *, u_int16_t); 143186904Ssam 144186904Ssam#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x 145186904Ssam 146186904Ssamstruct cdev *pf_dev; 147186904Ssam 148186904Ssam/* 149186904Ssam * XXX - These are new and need to be checked when moveing to a new version 150186904Ssam */ 151186904Ssamstatic void pf_clear_states(void); 152186904Ssamstatic int pf_clear_tables(void); 153186904Ssamstatic void pf_clear_srcnodes(struct pf_src_node *); 154186904Ssamstatic void pf_kill_srcnodes(struct pfioc_src_node_kill *); 155186904Ssamstatic void pf_tbladdr_copyout(struct pf_addr_wrap *); 156186904Ssam 157186904Ssam/* 158186904Ssam * Wrapper functions for pfil(9) hooks 159186904Ssam */ 160186904Ssam#ifdef INET 161189980Ssamstatic int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, 162186904Ssam int dir, struct inpcb *inp); 163186904Ssamstatic int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, 164186904Ssam int dir, struct inpcb *inp); 165186904Ssam#endif 166186904Ssam#ifdef INET6 167186904Ssamstatic int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, 168187899Ssam int dir, struct inpcb *inp); 169187899Ssamstatic int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, 170187899Ssam int dir, struct inpcb *inp); 171191018Ssam#endif 172191018Ssam 173191018Ssamstatic int hook_pf(void); 174187899Ssamstatic int dehook_pf(void); 175187899Ssamstatic int shutdown_pf(void); 176188782Ssamstatic int pf_load(void); 177188782Ssamstatic int pf_unload(void); 178186904Ssam 179186904Ssamstatic struct cdevsw pf_cdevsw = { 180186904Ssam .d_ioctl = pfioctl, 181186904Ssam .d_name = PF_NAME, 182186904Ssam .d_version = D_VERSION, 183186904Ssam}; 184186904Ssam 185186904Ssamstatic volatile VNET_DEFINE(int, pf_pfil_hooked); 186186904Ssam#define V_pf_pfil_hooked VNET(pf_pfil_hooked) 187186904SsamVNET_DEFINE(int, pf_end_threads); 188186904Ssam 189186904Ssamstruct rwlock pf_rules_lock; 190186904Ssam 191186904Ssam/* pfsync */ 192186904Ssampfsync_state_import_t *pfsync_state_import_ptr = NULL; 193186904Ssampfsync_insert_state_t *pfsync_insert_state_ptr = NULL; 194186904Ssampfsync_update_state_t *pfsync_update_state_ptr = NULL; 195186904Ssampfsync_delete_state_t *pfsync_delete_state_ptr = NULL; 196186904Ssampfsync_clear_states_t *pfsync_clear_states_ptr = NULL; 197193114Ssampfsync_defer_t *pfsync_defer_ptr = NULL; 198193114Ssam/* pflog */ 199193114Ssampflog_packet_t *pflog_packet_ptr = NULL; 200193114Ssam 201186904Ssamstatic int 202186904Ssampfattach(void) 203193114Ssam{ 204186904Ssam u_int32_t *my_timeout = V_pf_default_rule.timeout; 205186904Ssam int error; 206186904Ssam 207186904Ssam pf_initialize(); 208188467Ssam pfr_initialize(); 209188467Ssam pfi_initialize(); 210188467Ssam pf_normalize_init(); 211188467Ssam 212188467Ssam V_pf_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT; 213188467Ssam V_pf_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT; 214188467Ssam 215188467Ssam RB_INIT(&V_pf_anchors); 216188467Ssam pf_init_ruleset(&pf_main_ruleset); 217186904Ssam 218186904Ssam /* default rule should never be garbage collected */ 219186904Ssam V_pf_default_rule.entries.tqe_prev = &V_pf_default_rule.entries.tqe_next; 220186904Ssam#ifdef PF_DEFAULT_TO_DROP 221186904Ssam V_pf_default_rule.action = PF_DROP; 222186904Ssam#else 223186904Ssam V_pf_default_rule.action = PF_PASS; 224188467Ssam#endif 225186904Ssam V_pf_default_rule.nr = -1; 226186904Ssam V_pf_default_rule.rtableid = -1; 227186904Ssam 228188467Ssam /* initialize default timeouts */ 229186904Ssam my_timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; 230186904Ssam my_timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; 231186904Ssam my_timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; 232186904Ssam my_timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; 233186904Ssam my_timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; 234186904Ssam my_timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; 235186904Ssam my_timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; 236186904Ssam my_timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; 237186904Ssam my_timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; 238186904Ssam my_timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; 239186904Ssam my_timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; 240186904Ssam my_timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; 241186904Ssam my_timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; 242186904Ssam my_timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; 243186904Ssam my_timeout[PFTM_FRAG] = PFTM_FRAG_VAL; 244186904Ssam my_timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; 245186904Ssam my_timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; 246188467Ssam my_timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; 247188467Ssam my_timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; 248188467Ssam my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; 249188467Ssam 250186904Ssam bzero(&V_pf_status, sizeof(V_pf_status)); 251186904Ssam V_pf_status.debug = PF_DEBUG_URGENT; 252186904Ssam 253186904Ssam V_pf_pfil_hooked = 0; 254186904Ssam 255186904Ssam /* XXX do our best to avoid a conflict */ 256186904Ssam V_pf_status.hostid = arc4random(); 257186904Ssam 258186904Ssam if ((error = kproc_create(pf_purge_thread, curvnet, NULL, 0, 0, 259186904Ssam "pf purge")) != 0) 260186904Ssam /* XXXGL: leaked all above. */ 261186904Ssam return (error); 262186904Ssam if ((error = swi_add(NULL, "pf send", pf_intr, curvnet, SWI_NET, 263186904Ssam INTR_MPSAFE, &V_pf_swi_cookie)) != 0) 264186904Ssam /* XXXGL: leaked all above. */ 265186904Ssam return (error); 266186904Ssam 267188925Ssam return (0); 268188925Ssam} 269186904Ssam 270186904Ssamstatic struct pf_pool * 271188925Ssampf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action, 272188925Ssam u_int32_t rule_number, u_int8_t r_last, u_int8_t active, 273188925Ssam u_int8_t check_ticket) 274188925Ssam{ 275186904Ssam struct pf_ruleset *ruleset; 276186904Ssam struct pf_rule *rule; 277186904Ssam int rs_num; 278186904Ssam 279186904Ssam ruleset = pf_find_ruleset(anchor); 280186904Ssam if (ruleset == NULL) 281186904Ssam return (NULL); 282186904Ssam rs_num = pf_get_ruleset_number(rule_action); 283186904Ssam if (rs_num >= PF_RULESET_MAX) 284186904Ssam return (NULL); 285186904Ssam if (active) { 286186904Ssam if (check_ticket && ticket != 287186904Ssam ruleset->rules[rs_num].active.ticket) 288186904Ssam return (NULL); 289186904Ssam if (r_last) 290186904Ssam rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 291226296Sadrian pf_rulequeue); 292225913Sadrian else 293186904Ssam rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 294186904Ssam } else { 295186904Ssam if (check_ticket && ticket != 296186904Ssam ruleset->rules[rs_num].inactive.ticket) 297186904Ssam return (NULL); 298186904Ssam if (r_last) 299186904Ssam rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 300186904Ssam pf_rulequeue); 301186904Ssam else 302205140Sweongyo rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr); 303205140Sweongyo } 304186904Ssam if (!r_last) { 305186904Ssam while ((rule != NULL) && (rule->nr != rule_number)) 306186904Ssam rule = TAILQ_NEXT(rule, entries); 307186904Ssam } 308186904Ssam if (rule == NULL) 309186904Ssam return (NULL); 310186904Ssam 311186904Ssam return (&rule->rpool); 312186904Ssam} 313186904Ssam 314186904Ssamstatic void 315186904Ssampf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb) 316186904Ssam{ 317186904Ssam struct pf_pooladdr *mv_pool_pa; 318186904Ssam 319186904Ssam while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) { 320186904Ssam TAILQ_REMOVE(poola, mv_pool_pa, entries); 321186904Ssam TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries); 322186904Ssam } 323192468Ssam} 324186904Ssam 325186904Ssamstatic void 326186904Ssampf_empty_pool(struct pf_palist *poola) 327186904Ssam{ 328186904Ssam struct pf_pooladdr *pa; 329186904Ssam 330186904Ssam while ((pa = TAILQ_FIRST(poola)) != NULL) { 331186904Ssam switch (pa->addr.type) { 332186904Ssam case PF_ADDR_DYNIFTL: 333186904Ssam pfi_dynaddr_remove(pa->addr.p.dyn); 334186904Ssam break; 335186904Ssam case PF_ADDR_TABLE: 336186904Ssam pfr_detach_table(pa->addr.p.tbl); 337186904Ssam break; 338186904Ssam } 339186904Ssam if (pa->kif) 340186904Ssam pfi_kif_unref(pa->kif); 341186904Ssam TAILQ_REMOVE(poola, pa, entries); 342186904Ssam free(pa, M_PFRULE); 343186904Ssam } 344186904Ssam} 345186904Ssam 346186904Ssamstatic void 347186904Ssampf_unlink_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) 348186904Ssam{ 349186904Ssam 350186904Ssam PF_RULES_WASSERT(); 351186904Ssam 352186904Ssam TAILQ_REMOVE(rulequeue, rule, entries); 353186904Ssam 354186904Ssam PF_UNLNKDRULES_LOCK(); 355186904Ssam rule->rule_flag |= PFRULE_REFS; 356186904Ssam TAILQ_INSERT_TAIL(&V_pf_unlinked_rules, rule, entries); 357186904Ssam PF_UNLNKDRULES_UNLOCK(); 358186904Ssam} 359186904Ssam 360186904Ssamvoid 361186904Ssampf_free_rule(struct pf_rule *rule) 362186904Ssam{ 363186904Ssam 364186904Ssam PF_RULES_WASSERT(); 365191016Ssam 366186904Ssam if (rule->tag) 367186904Ssam tag_unref(&V_pf_tags, rule->tag); 368186904Ssam if (rule->match_tag) 369186904Ssam tag_unref(&V_pf_tags, rule->match_tag); 370186904Ssam#ifdef ALTQ 371186904Ssam if (rule->pqid != rule->qid) 372186904Ssam pf_qid_unref(rule->pqid); 373186904Ssam pf_qid_unref(rule->qid); 374186904Ssam#endif 375186904Ssam switch (rule->src.addr.type) { 376186904Ssam case PF_ADDR_DYNIFTL: 377186904Ssam pfi_dynaddr_remove(rule->src.addr.p.dyn); 378186904Ssam break; 379186904Ssam case PF_ADDR_TABLE: 380186904Ssam pfr_detach_table(rule->src.addr.p.tbl); 381186904Ssam break; 382186904Ssam } 383186904Ssam switch (rule->dst.addr.type) { 384186904Ssam case PF_ADDR_DYNIFTL: 385186904Ssam pfi_dynaddr_remove(rule->dst.addr.p.dyn); 386192468Ssam break; 387186904Ssam case PF_ADDR_TABLE: 388186904Ssam pfr_detach_table(rule->dst.addr.p.tbl); 389186904Ssam break; 390186904Ssam } 391186904Ssam if (rule->overload_tbl) 392186904Ssam pfr_detach_table(rule->overload_tbl); 393186904Ssam if (rule->kif) 394192468Ssam pfi_kif_unref(rule->kif); 395186904Ssam pf_anchor_remove(rule); 396186904Ssam pf_empty_pool(&rule->rpool.list); 397186904Ssam free(rule, M_PFRULE); 398186904Ssam} 399186904Ssam 400186904Ssamstatic u_int16_t 401186904Ssamtagname2tag(struct pf_tags *head, char *tagname) 402189980Ssam{ 403186904Ssam struct pf_tagname *tag, *p = NULL; 404186904Ssam u_int16_t new_tagid = 1; 405186904Ssam 406186904Ssam PF_RULES_WASSERT(); 407186904Ssam 408186904Ssam TAILQ_FOREACH(tag, head, entries) 409189980Ssam if (strcmp(tagname, tag->name) == 0) { 410186904Ssam tag->ref++; 411186904Ssam return (tag->tag); 412186904Ssam } 413186904Ssam 414189980Ssam /* 415189980Ssam * to avoid fragmentation, we do a linear search from the beginning 416189980Ssam * and take the first free slot we find. if there is none or the list 417189981Ssam * is empty, append a new entry at the end. 418189981Ssam */ 419189981Ssam 420189980Ssam /* new entry */ 421189980Ssam if (!TAILQ_EMPTY(head)) 422189980Ssam for (p = TAILQ_FIRST(head); p != NULL && 423189980Ssam p->tag == new_tagid; p = TAILQ_NEXT(p, entries)) 424189980Ssam new_tagid = p->tag + 1; 425189980Ssam 426189980Ssam if (new_tagid > TAGID_MAX) 427189981Ssam return (0); 428189981Ssam 429189981Ssam /* allocate and fill new struct pf_tagname */ 430189980Ssam tag = malloc(sizeof(*tag), M_PFTAG, M_NOWAIT|M_ZERO); 431189980Ssam if (tag == NULL) 432189980Ssam return (0); 433189980Ssam strlcpy(tag->name, tagname, sizeof(tag->name)); 434189980Ssam tag->tag = new_tagid; 435189980Ssam tag->ref++; 436189981Ssam 437189981Ssam if (p != NULL) /* insert new entry before p */ 438189981Ssam TAILQ_INSERT_BEFORE(p, tag, entries); 439189980Ssam else /* either list empty or no free slot in between */ 440189980Ssam TAILQ_INSERT_TAIL(head, tag, entries); 441189980Ssam 442189980Ssam return (tag->tag); 443189980Ssam} 444186904Ssam 445186904Ssamstatic void 446186904Ssamtag_unref(struct pf_tags *head, u_int16_t tag) 447186904Ssam{ 448189980Ssam struct pf_tagname *p, *next; 449186904Ssam 450186904Ssam PF_RULES_WASSERT(); 451186904Ssam 452186904Ssam for (p = TAILQ_FIRST(head); p != NULL; p = next) { 453189980Ssam next = TAILQ_NEXT(p, entries); 454189980Ssam if (tag == p->tag) { 455186904Ssam if (--p->ref == 0) { 456186904Ssam TAILQ_REMOVE(head, p, entries); 457186904Ssam free(p, M_PFTAG); 458189980Ssam } 459189980Ssam break; 460189980Ssam } 461189980Ssam } 462189980Ssam} 463189980Ssam 464189980Ssamstatic u_int16_t 465189980Ssampf_tagname2tag(char *tagname) 466189980Ssam{ 467189980Ssam return (tagname2tag(&V_pf_tags, tagname)); 468186904Ssam} 469189980Ssam 470186904Ssam#ifdef ALTQ 471186904Ssamstatic u_int32_t 472186904Ssampf_qname2qid(char *qname) 473186904Ssam{ 474189980Ssam return ((u_int32_t)tagname2tag(&V_pf_qids, qname)); 475189980Ssam} 476189980Ssam 477189980Ssamstatic void 478189980Ssampf_qid_unref(u_int32_t qid) 479189980Ssam{ 480189980Ssam tag_unref(&V_pf_qids, (u_int16_t)qid); 481189980Ssam} 482186904Ssam 483186904Ssamstatic int 484186904Ssampf_begin_altq(u_int32_t *ticket) 485186904Ssam{ 486186904Ssam struct pf_altq *altq; 487189980Ssam int error = 0; 488191017Ssam 489186904Ssam PF_RULES_WASSERT(); 490186904Ssam 491186904Ssam /* Purge the old altq list */ 492186904Ssam while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) { 493186904Ssam TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries); 494186904Ssam if (altq->qname[0] == 0 && 495186904Ssam (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 496186904Ssam /* detach and destroy the discipline */ 497186904Ssam error = altq_remove(altq); 498189980Ssam } else 499186904Ssam pf_qid_unref(altq->qid); 500186904Ssam free(altq, M_PFALTQ); 501186904Ssam } 502186904Ssam if (error) 503186904Ssam return (error); 504186904Ssam *ticket = ++V_ticket_altqs_inactive; 505186904Ssam V_altqs_inactive_open = 1; 506186904Ssam return (0); 507186904Ssam} 508186904Ssam 509186904Ssamstatic int 510186904Ssampf_rollback_altq(u_int32_t ticket) 511186904Ssam{ 512186904Ssam struct pf_altq *altq; 513186904Ssam int error = 0; 514186904Ssam 515186904Ssam PF_RULES_WASSERT(); 516192468Ssam 517192468Ssam if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive) 518186904Ssam return (0); 519186904Ssam /* Purge the old altq list */ 520186904Ssam while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) { 521186904Ssam TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries); 522186904Ssam if (altq->qname[0] == 0 && 523186904Ssam (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 524186904Ssam /* detach and destroy the discipline */ 525186904Ssam error = altq_remove(altq); 526186904Ssam } else 527186904Ssam pf_qid_unref(altq->qid); 528186904Ssam free(altq, M_PFALTQ); 529186904Ssam } 530186904Ssam V_altqs_inactive_open = 0; 531186904Ssam return (error); 532186904Ssam} 533186904Ssam 534189980Ssamstatic int 535186904Ssampf_commit_altq(u_int32_t ticket) 536186904Ssam{ 537189980Ssam struct pf_altqqueue *old_altqs; 538189980Ssam struct pf_altq *altq; 539186904Ssam int err, error = 0; 540186904Ssam 541189980Ssam PF_RULES_WASSERT(); 542189980Ssam 543189980Ssam if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive) 544189980Ssam return (EBUSY); 545189980Ssam 546189980Ssam /* swap altqs, keep the old. */ 547189980Ssam old_altqs = V_pf_altqs_active; 548189980Ssam V_pf_altqs_active = V_pf_altqs_inactive; 549189980Ssam V_pf_altqs_inactive = old_altqs; 550189980Ssam V_ticket_altqs_active = V_ticket_altqs_inactive; 551189980Ssam 552189980Ssam /* Attach new disciplines */ 553186904Ssam TAILQ_FOREACH(altq, V_pf_altqs_active, entries) { 554186904Ssam if (altq->qname[0] == 0 && 555186904Ssam (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 556186904Ssam /* attach the discipline */ 557186904Ssam error = altq_pfattach(altq); 558186904Ssam if (error == 0 && V_pf_altq_running) 559186904Ssam error = pf_enable_altq(altq); 560186904Ssam if (error != 0) 561186904Ssam return (error); 562186904Ssam } 563186904Ssam } 564186904Ssam 565186904Ssam /* Purge the old altq list */ 566186904Ssam while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) { 567186904Ssam TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries); 568186904Ssam if (altq->qname[0] == 0 && 569186904Ssam (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { 570186904Ssam /* detach and destroy the discipline */ 571186904Ssam if (V_pf_altq_running) 572186904Ssam error = pf_disable_altq(altq); 573186904Ssam err = altq_pfdetach(altq); 574186904Ssam if (err != 0 && error == 0) 575186904Ssam error = err; 576186904Ssam err = altq_remove(altq); 577186904Ssam if (err != 0 && error == 0) 578186904Ssam error = err; 579186904Ssam } else 580186904Ssam pf_qid_unref(altq->qid); 581186904Ssam free(altq, M_PFALTQ); 582192468Ssam } 583192468Ssam 584186904Ssam V_altqs_inactive_open = 0; 585192468Ssam return (error); 586186904Ssam} 587186904Ssam 588186904Ssamstatic int 589186904Ssampf_enable_altq(struct pf_altq *altq) 590186904Ssam{ 591192468Ssam struct ifnet *ifp; 592186904Ssam struct tb_profile tb; 593186904Ssam int error = 0; 594186904Ssam 595186904Ssam if ((ifp = ifunit(altq->ifname)) == NULL) 596186904Ssam return (EINVAL); 597186904Ssam 598186904Ssam if (ifp->if_snd.altq_type != ALTQT_NONE) 599186904Ssam error = altq_enable(&ifp->if_snd); 600186904Ssam 601192468Ssam /* set tokenbucket regulator */ 602186904Ssam if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { 603186904Ssam tb.rate = altq->ifbandwidth; 604186904Ssam tb.depth = altq->tbrsize; 605186904Ssam error = tbr_set(&ifp->if_snd, &tb); 606186904Ssam } 607186904Ssam 608186904Ssam return (error); 609186904Ssam} 610186904Ssam 611186904Ssamstatic int 612186904Ssampf_disable_altq(struct pf_altq *altq) 613186904Ssam{ 614186904Ssam struct ifnet *ifp; 615186904Ssam struct tb_profile tb; 616186904Ssam int error; 617186904Ssam 618186904Ssam if ((ifp = ifunit(altq->ifname)) == NULL) 619186904Ssam return (EINVAL); 620186904Ssam 621186904Ssam /* 622186904Ssam * when the discipline is no longer referenced, it was overridden 623186904Ssam * by a new one. if so, just return. 624186904Ssam */ 625186904Ssam if (altq->altq_disc != ifp->if_snd.altq_disc) 626186904Ssam return (0); 627186904Ssam 628186904Ssam error = altq_disable(&ifp->if_snd); 629186904Ssam 630186904Ssam if (error == 0) { 631186904Ssam /* clear tokenbucket regulator */ 632186904Ssam tb.rate = 0; 633186904Ssam error = tbr_set(&ifp->if_snd, &tb); 634186904Ssam } 635186904Ssam 636186904Ssam return (error); 637186904Ssam} 638186904Ssam 639186904Ssamvoid 640186904Ssampf_altq_ifnet_event(struct ifnet *ifp, int remove) 641186904Ssam{ 642186904Ssam struct ifnet *ifp1; 643186904Ssam struct pf_altq *a1, *a2, *a3; 644186904Ssam u_int32_t ticket; 645186904Ssam int error = 0; 646186904Ssam 647186904Ssam /* Interrupt userland queue modifications */ 648186904Ssam if (V_altqs_inactive_open) 649186904Ssam pf_rollback_altq(V_ticket_altqs_inactive); 650186904Ssam 651186904Ssam /* Start new altq ruleset */ 652186904Ssam if (pf_begin_altq(&ticket)) 653186904Ssam return; 654186904Ssam 655186904Ssam /* Copy the current active set */ 656186904Ssam TAILQ_FOREACH(a1, V_pf_altqs_active, entries) { 657186904Ssam a2 = malloc(sizeof(*a2), M_PFALTQ, M_NOWAIT); 658186904Ssam if (a2 == NULL) { 659186904Ssam error = ENOMEM; 660186904Ssam break; 661186904Ssam } 662186904Ssam bcopy(a1, a2, sizeof(struct pf_altq)); 663186904Ssam 664186904Ssam if (a2->qname[0] != 0) { 665186904Ssam if ((a2->qid = pf_qname2qid(a2->qname)) == 0) { 666186904Ssam error = EBUSY; 667186904Ssam free(a2, M_PFALTQ); 668186904Ssam break; 669186904Ssam } 670186904Ssam a2->altq_disc = NULL; 671186904Ssam TAILQ_FOREACH(a3, V_pf_altqs_inactive, entries) { 672186904Ssam if (strncmp(a3->ifname, a2->ifname, 673186904Ssam IFNAMSIZ) == 0 && a3->qname[0] == 0) { 674186904Ssam a2->altq_disc = a3->altq_disc; 675186904Ssam break; 676186904Ssam } 677186904Ssam } 678186904Ssam } 679186904Ssam /* Deactivate the interface in question */ 680186904Ssam a2->local_flags &= ~PFALTQ_FLAG_IF_REMOVED; 681186904Ssam if ((ifp1 = ifunit(a2->ifname)) == NULL || 682186904Ssam (remove && ifp1 == ifp)) { 683189980Ssam a2->local_flags |= PFALTQ_FLAG_IF_REMOVED; 684186904Ssam } else { 685186904Ssam error = altq_add(a2); 686186904Ssam 687186904Ssam if (ticket != V_ticket_altqs_inactive) 688186904Ssam error = EBUSY; 689186904Ssam 690186904Ssam if (error) { 691189980Ssam free(a2, M_PFALTQ); 692189980Ssam break; 693186904Ssam } 694189980Ssam } 695186904Ssam 696189980Ssam TAILQ_INSERT_TAIL(V_pf_altqs_inactive, a2, entries); 697189980Ssam } 698186904Ssam 699186904Ssam if (error != 0) 700186904Ssam pf_rollback_altq(ticket); 701186904Ssam else 702186904Ssam pf_commit_altq(ticket); 703186904Ssam} 704186904Ssam#endif /* ALTQ */ 705186904Ssam 706186904Ssamstatic int 707186904Ssampf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor) 708186904Ssam{ 709186904Ssam struct pf_ruleset *rs; 710186904Ssam struct pf_rule *rule; 711186904Ssam 712186904Ssam PF_RULES_WASSERT(); 713186904Ssam 714186904Ssam if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 715186904Ssam return (EINVAL); 716186904Ssam rs = pf_find_or_create_ruleset(anchor); 717186904Ssam if (rs == NULL) 718186904Ssam return (EINVAL); 719186904Ssam while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) { 720186904Ssam pf_unlink_rule(rs->rules[rs_num].inactive.ptr, rule); 721186904Ssam rs->rules[rs_num].inactive.rcount--; 722186904Ssam } 723186904Ssam *ticket = ++rs->rules[rs_num].inactive.ticket; 724186904Ssam rs->rules[rs_num].inactive.open = 1; 725186904Ssam return (0); 726186904Ssam} 727186904Ssam 728186904Ssamstatic int 729186904Ssampf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor) 730186904Ssam{ 731186904Ssam struct pf_ruleset *rs; 732186904Ssam struct pf_rule *rule; 733186904Ssam 734186904Ssam PF_RULES_WASSERT(); 735186904Ssam 736186904Ssam if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 737186904Ssam return (EINVAL); 738186904Ssam rs = pf_find_ruleset(anchor); 739186904Ssam if (rs == NULL || !rs->rules[rs_num].inactive.open || 740186904Ssam rs->rules[rs_num].inactive.ticket != ticket) 741190384Ssam return (0); 742190384Ssam while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) { 743186904Ssam pf_unlink_rule(rs->rules[rs_num].inactive.ptr, rule); 744186904Ssam rs->rules[rs_num].inactive.rcount--; 745186904Ssam } 746186904Ssam rs->rules[rs_num].inactive.open = 0; 747254506Sadrian return (0); 748186904Ssam} 749186904Ssam 750186904Ssam#define PF_MD5_UPD(st, elm) \ 751186904Ssam MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm)) 752186904Ssam 753186904Ssam#define PF_MD5_UPD_STR(st, elm) \ 754186904Ssam MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm)) 755186904Ssam 756186904Ssam#define PF_MD5_UPD_HTONL(st, elm, stor) do { \ 757186904Ssam (stor) = htonl((st)->elm); \ 758186904Ssam MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\ 759186904Ssam} while (0) 760186904Ssam 761186904Ssam#define PF_MD5_UPD_HTONS(st, elm, stor) do { \ 762186904Ssam (stor) = htons((st)->elm); \ 763190384Ssam MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\ 764186904Ssam} while (0) 765186904Ssam 766186904Ssamstatic void 767190384Ssampf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr) 768186904Ssam{ 769190384Ssam PF_MD5_UPD(pfr, addr.type); 770190384Ssam switch (pfr->addr.type) { 771186904Ssam case PF_ADDR_DYNIFTL: 772186904Ssam PF_MD5_UPD(pfr, addr.v.ifname); 773186904Ssam PF_MD5_UPD(pfr, addr.iflags); 774186904Ssam break; 775254506Sadrian case PF_ADDR_TABLE: 776186904Ssam PF_MD5_UPD(pfr, addr.v.tblname); 777186904Ssam break; 778186904Ssam case PF_ADDR_ADDRMASK: 779186904Ssam /* XXX ignore af? */ 780186904Ssam PF_MD5_UPD(pfr, addr.v.a.addr.addr32); 781186904Ssam PF_MD5_UPD(pfr, addr.v.a.mask.addr32); 782186904Ssam break; 783193114Ssam } 784186904Ssam 785186904Ssam PF_MD5_UPD(pfr, port[0]); 786186904Ssam PF_MD5_UPD(pfr, port[1]); 787189980Ssam PF_MD5_UPD(pfr, neg); 788186904Ssam PF_MD5_UPD(pfr, port_op); 789186904Ssam} 790186904Ssam 791193114Ssamstatic void 792186904Ssampf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule) 793186904Ssam{ 794186904Ssam u_int16_t x; 795186904Ssam u_int32_t y; 796186904Ssam 797186904Ssam pf_hash_rule_addr(ctx, &rule->src); 798186904Ssam pf_hash_rule_addr(ctx, &rule->dst); 799186904Ssam PF_MD5_UPD_STR(rule, label); 800186904Ssam PF_MD5_UPD_STR(rule, ifname); 801189980Ssam PF_MD5_UPD_STR(rule, match_tagname); 802186904Ssam PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */ 803186904Ssam PF_MD5_UPD_HTONL(rule, os_fingerprint, y); 804186904Ssam PF_MD5_UPD_HTONL(rule, prob, y); 805193114Ssam PF_MD5_UPD_HTONL(rule, uid.uid[0], y); 806186904Ssam PF_MD5_UPD_HTONL(rule, uid.uid[1], y); 807186904Ssam PF_MD5_UPD(rule, uid.op); 808186904Ssam PF_MD5_UPD_HTONL(rule, gid.gid[0], y); 809189980Ssam PF_MD5_UPD_HTONL(rule, gid.gid[1], y); 810186904Ssam PF_MD5_UPD(rule, gid.op); 811186904Ssam PF_MD5_UPD_HTONL(rule, rule_flag, y); 812186904Ssam PF_MD5_UPD(rule, action); 813193114Ssam PF_MD5_UPD(rule, direction); 814186904Ssam PF_MD5_UPD(rule, af); 815186904Ssam PF_MD5_UPD(rule, quick); 816186904Ssam PF_MD5_UPD(rule, ifnot); 817190384Ssam PF_MD5_UPD(rule, match_tag_not); 818186904Ssam PF_MD5_UPD(rule, natpass); 819186904Ssam PF_MD5_UPD(rule, keep_state); 820193114Ssam PF_MD5_UPD(rule, proto); 821193114Ssam PF_MD5_UPD(rule, type); 822193114Ssam PF_MD5_UPD(rule, code); 823186904Ssam PF_MD5_UPD(rule, flags); 824190384Ssam PF_MD5_UPD(rule, flagset); 825230153Sadrian PF_MD5_UPD(rule, allow_opts); 826230153Sadrian PF_MD5_UPD(rule, rt); 827 PF_MD5_UPD(rule, tos); 828} 829 830static int 831pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) 832{ 833 struct pf_ruleset *rs; 834 struct pf_rule *rule, **old_array; 835 struct pf_rulequeue *old_rules; 836 int error; 837 u_int32_t old_rcount; 838 839 PF_RULES_WASSERT(); 840 841 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 842 return (EINVAL); 843 rs = pf_find_ruleset(anchor); 844 if (rs == NULL || !rs->rules[rs_num].inactive.open || 845 ticket != rs->rules[rs_num].inactive.ticket) 846 return (EBUSY); 847 848 /* Calculate checksum for the main ruleset */ 849 if (rs == &pf_main_ruleset) { 850 error = pf_setup_pfsync_matching(rs); 851 if (error != 0) 852 return (error); 853 } 854 855 /* Swap rules, keep the old. */ 856 old_rules = rs->rules[rs_num].active.ptr; 857 old_rcount = rs->rules[rs_num].active.rcount; 858 old_array = rs->rules[rs_num].active.ptr_array; 859 860 rs->rules[rs_num].active.ptr = 861 rs->rules[rs_num].inactive.ptr; 862 rs->rules[rs_num].active.ptr_array = 863 rs->rules[rs_num].inactive.ptr_array; 864 rs->rules[rs_num].active.rcount = 865 rs->rules[rs_num].inactive.rcount; 866 rs->rules[rs_num].inactive.ptr = old_rules; 867 rs->rules[rs_num].inactive.ptr_array = old_array; 868 rs->rules[rs_num].inactive.rcount = old_rcount; 869 870 rs->rules[rs_num].active.ticket = 871 rs->rules[rs_num].inactive.ticket; 872 pf_calc_skip_steps(rs->rules[rs_num].active.ptr); 873 874 875 /* Purge the old rule list. */ 876 while ((rule = TAILQ_FIRST(old_rules)) != NULL) 877 pf_unlink_rule(old_rules, rule); 878 if (rs->rules[rs_num].inactive.ptr_array) 879 free(rs->rules[rs_num].inactive.ptr_array, M_TEMP); 880 rs->rules[rs_num].inactive.ptr_array = NULL; 881 rs->rules[rs_num].inactive.rcount = 0; 882 rs->rules[rs_num].inactive.open = 0; 883 pf_remove_if_empty_ruleset(rs); 884 885 return (0); 886} 887 888static int 889pf_setup_pfsync_matching(struct pf_ruleset *rs) 890{ 891 MD5_CTX ctx; 892 struct pf_rule *rule; 893 int rs_cnt; 894 u_int8_t digest[PF_MD5_DIGEST_LENGTH]; 895 896 MD5Init(&ctx); 897 for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) { 898 /* XXX PF_RULESET_SCRUB as well? */ 899 if (rs_cnt == PF_RULESET_SCRUB) 900 continue; 901 902 if (rs->rules[rs_cnt].inactive.ptr_array) 903 free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP); 904 rs->rules[rs_cnt].inactive.ptr_array = NULL; 905 906 if (rs->rules[rs_cnt].inactive.rcount) { 907 rs->rules[rs_cnt].inactive.ptr_array = 908 malloc(sizeof(caddr_t) * 909 rs->rules[rs_cnt].inactive.rcount, 910 M_TEMP, M_NOWAIT); 911 912 if (!rs->rules[rs_cnt].inactive.ptr_array) 913 return (ENOMEM); 914 } 915 916 TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr, 917 entries) { 918 pf_hash_rule(&ctx, rule); 919 (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule; 920 } 921 } 922 923 MD5Final(digest, &ctx); 924 memcpy(V_pf_status.pf_chksum, digest, sizeof(V_pf_status.pf_chksum)); 925 return (0); 926} 927 928static int 929pf_addr_setup(struct pf_ruleset *ruleset, struct pf_addr_wrap *addr, 930 sa_family_t af) 931{ 932 int error = 0; 933 934 switch (addr->type) { 935 case PF_ADDR_TABLE: 936 addr->p.tbl = pfr_attach_table(ruleset, addr->v.tblname); 937 if (addr->p.tbl == NULL) 938 error = ENOMEM; 939 break; 940 case PF_ADDR_DYNIFTL: 941 error = pfi_dynaddr_setup(addr, af); 942 break; 943 } 944 945 return (error); 946} 947 948static void 949pf_addr_copyout(struct pf_addr_wrap *addr) 950{ 951 952 switch (addr->type) { 953 case PF_ADDR_DYNIFTL: 954 pfi_dynaddr_copyout(addr); 955 break; 956 case PF_ADDR_TABLE: 957 pf_tbladdr_copyout(addr); 958 break; 959 } 960} 961 962static int 963pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 964{ 965 int error = 0; 966 967 /* XXX keep in sync with switch() below */ 968 if (securelevel_gt(td->td_ucred, 2)) 969 switch (cmd) { 970 case DIOCGETRULES: 971 case DIOCGETRULE: 972 case DIOCGETADDRS: 973 case DIOCGETADDR: 974 case DIOCGETSTATE: 975 case DIOCSETSTATUSIF: 976 case DIOCGETSTATUS: 977 case DIOCCLRSTATUS: 978 case DIOCNATLOOK: 979 case DIOCSETDEBUG: 980 case DIOCGETSTATES: 981 case DIOCGETTIMEOUT: 982 case DIOCCLRRULECTRS: 983 case DIOCGETLIMIT: 984 case DIOCGETALTQS: 985 case DIOCGETALTQ: 986 case DIOCGETQSTATS: 987 case DIOCGETRULESETS: 988 case DIOCGETRULESET: 989 case DIOCRGETTABLES: 990 case DIOCRGETTSTATS: 991 case DIOCRCLRTSTATS: 992 case DIOCRCLRADDRS: 993 case DIOCRADDADDRS: 994 case DIOCRDELADDRS: 995 case DIOCRSETADDRS: 996 case DIOCRGETADDRS: 997 case DIOCRGETASTATS: 998 case DIOCRCLRASTATS: 999 case DIOCRTSTADDRS: 1000 case DIOCOSFPGET: 1001 case DIOCGETSRCNODES: 1002 case DIOCCLRSRCNODES: 1003 case DIOCIGETIFACES: 1004 case DIOCGIFSPEED: 1005 case DIOCSETIFFLAG: 1006 case DIOCCLRIFFLAG: 1007 break; 1008 case DIOCRCLRTABLES: 1009 case DIOCRADDTABLES: 1010 case DIOCRDELTABLES: 1011 case DIOCRSETTFLAGS: 1012 if (((struct pfioc_table *)addr)->pfrio_flags & 1013 PFR_FLAG_DUMMY) 1014 break; /* dummy operation ok */ 1015 return (EPERM); 1016 default: 1017 return (EPERM); 1018 } 1019 1020 if (!(flags & FWRITE)) 1021 switch (cmd) { 1022 case DIOCGETRULES: 1023 case DIOCGETADDRS: 1024 case DIOCGETADDR: 1025 case DIOCGETSTATE: 1026 case DIOCGETSTATUS: 1027 case DIOCGETSTATES: 1028 case DIOCGETTIMEOUT: 1029 case DIOCGETLIMIT: 1030 case DIOCGETALTQS: 1031 case DIOCGETALTQ: 1032 case DIOCGETQSTATS: 1033 case DIOCGETRULESETS: 1034 case DIOCGETRULESET: 1035 case DIOCNATLOOK: 1036 case DIOCRGETTABLES: 1037 case DIOCRGETTSTATS: 1038 case DIOCRGETADDRS: 1039 case DIOCRGETASTATS: 1040 case DIOCRTSTADDRS: 1041 case DIOCOSFPGET: 1042 case DIOCGETSRCNODES: 1043 case DIOCIGETIFACES: 1044 case DIOCGIFSPEED: 1045 break; 1046 case DIOCRCLRTABLES: 1047 case DIOCRADDTABLES: 1048 case DIOCRDELTABLES: 1049 case DIOCRCLRTSTATS: 1050 case DIOCRCLRADDRS: 1051 case DIOCRADDADDRS: 1052 case DIOCRDELADDRS: 1053 case DIOCRSETADDRS: 1054 case DIOCRSETTFLAGS: 1055 if (((struct pfioc_table *)addr)->pfrio_flags & 1056 PFR_FLAG_DUMMY) { 1057 flags |= FWRITE; /* need write lock for dummy */ 1058 break; /* dummy operation ok */ 1059 } 1060 return (EACCES); 1061 case DIOCGETRULE: 1062 if (((struct pfioc_rule *)addr)->action == 1063 PF_GET_CLR_CNTR) 1064 return (EACCES); 1065 break; 1066 default: 1067 return (EACCES); 1068 } 1069 1070 CURVNET_SET(TD_TO_VNET(td)); 1071 1072 switch (cmd) { 1073 case DIOCSTART: 1074 PF_RULES_WLOCK(); 1075 if (V_pf_status.running) 1076 error = EEXIST; 1077 else { 1078 int cpu; 1079 1080 PF_RULES_WUNLOCK(); 1081 error = hook_pf(); 1082 if (error) { 1083 DPFPRINTF(PF_DEBUG_MISC, 1084 ("pf: pfil registration failed\n")); 1085 break; 1086 } 1087 PF_RULES_WLOCK(); 1088 V_pf_status.running = 1; 1089 V_pf_status.since = time_second; 1090 1091 CPU_FOREACH(cpu) 1092 V_pf_stateid[cpu] = time_second; 1093 1094 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); 1095 } 1096 PF_RULES_WUNLOCK(); 1097 break; 1098 1099 case DIOCSTOP: 1100 PF_RULES_WLOCK(); 1101 if (!V_pf_status.running) 1102 error = ENOENT; 1103 else { 1104 V_pf_status.running = 0; 1105 PF_RULES_WUNLOCK(); 1106 error = dehook_pf(); 1107 if (error) { 1108 V_pf_status.running = 1; 1109 DPFPRINTF(PF_DEBUG_MISC, 1110 ("pf: pfil unregistration failed\n")); 1111 } 1112 PF_RULES_WLOCK(); 1113 V_pf_status.since = time_second; 1114 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); 1115 } 1116 PF_RULES_WUNLOCK(); 1117 break; 1118 1119 case DIOCADDRULE: { 1120 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1121 struct pf_ruleset *ruleset; 1122 struct pf_rule *rule, *tail; 1123 struct pf_pooladdr *pa; 1124 struct pfi_kif *kif = NULL; 1125 int rs_num; 1126 1127 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1128 error = EINVAL; 1129 break; 1130 } 1131#ifndef INET 1132 if (pr->rule.af == AF_INET) { 1133 error = EAFNOSUPPORT; 1134 break; 1135 } 1136#endif /* INET */ 1137#ifndef INET6 1138 if (pr->rule.af == AF_INET6) { 1139 error = EAFNOSUPPORT; 1140 break; 1141 } 1142#endif /* INET6 */ 1143 1144 rule = malloc(sizeof(*rule), M_PFRULE, M_WAITOK); 1145 bcopy(&pr->rule, rule, sizeof(struct pf_rule)); 1146 if (rule->ifname[0]) 1147 kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); 1148 rule->cuid = td->td_ucred->cr_ruid; 1149 rule->cpid = td->td_proc ? td->td_proc->p_pid : 0; 1150 TAILQ_INIT(&rule->rpool.list); 1151 1152#define ERROUT(x) { error = (x); goto DIOCADDRULE_error; } 1153 1154 PF_RULES_WLOCK(); 1155 pr->anchor[sizeof(pr->anchor) - 1] = 0; 1156 ruleset = pf_find_ruleset(pr->anchor); 1157 if (ruleset == NULL) 1158 ERROUT(EINVAL); 1159 rs_num = pf_get_ruleset_number(pr->rule.action); 1160 if (rs_num >= PF_RULESET_MAX) 1161 ERROUT(EINVAL); 1162 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { 1163 DPFPRINTF(PF_DEBUG_MISC, 1164 ("ticket: %d != [%d]%d\n", pr->ticket, rs_num, 1165 ruleset->rules[rs_num].inactive.ticket)); 1166 ERROUT(EBUSY); 1167 } 1168 if (pr->pool_ticket != V_ticket_pabuf) { 1169 DPFPRINTF(PF_DEBUG_MISC, 1170 ("pool_ticket: %d != %d\n", pr->pool_ticket, 1171 V_ticket_pabuf)); 1172 ERROUT(EBUSY); 1173 } 1174 1175 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 1176 pf_rulequeue); 1177 if (tail) 1178 rule->nr = tail->nr + 1; 1179 else 1180 rule->nr = 0; 1181 if (rule->ifname[0]) { 1182 rule->kif = pfi_kif_attach(kif, rule->ifname); 1183 pfi_kif_ref(rule->kif); 1184 } else 1185 rule->kif = NULL; 1186 1187 if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs) 1188 error = EBUSY; 1189 1190#ifdef ALTQ 1191 /* set queue IDs */ 1192 if (rule->qname[0] != 0) { 1193 if ((rule->qid = pf_qname2qid(rule->qname)) == 0) 1194 error = EBUSY; 1195 else if (rule->pqname[0] != 0) { 1196 if ((rule->pqid = 1197 pf_qname2qid(rule->pqname)) == 0) 1198 error = EBUSY; 1199 } else 1200 rule->pqid = rule->qid; 1201 } 1202#endif 1203 if (rule->tagname[0]) 1204 if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) 1205 error = EBUSY; 1206 if (rule->match_tagname[0]) 1207 if ((rule->match_tag = 1208 pf_tagname2tag(rule->match_tagname)) == 0) 1209 error = EBUSY; 1210 if (rule->rt && !rule->direction) 1211 error = EINVAL; 1212 if (!rule->log) 1213 rule->logif = 0; 1214 if (rule->logif >= PFLOGIFS_MAX) 1215 error = EINVAL; 1216 if (pf_addr_setup(ruleset, &rule->src.addr, rule->af)) 1217 error = ENOMEM; 1218 if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af)) 1219 error = ENOMEM; 1220 if (pf_anchor_setup(rule, ruleset, pr->anchor_call)) 1221 error = EINVAL; 1222 TAILQ_FOREACH(pa, &V_pf_pabuf, entries) 1223 if (pa->addr.type == PF_ADDR_TABLE) { 1224 pa->addr.p.tbl = pfr_attach_table(ruleset, 1225 pa->addr.v.tblname); 1226 if (pa->addr.p.tbl == NULL) 1227 error = ENOMEM; 1228 } 1229 1230 if (rule->overload_tblname[0]) { 1231 if ((rule->overload_tbl = pfr_attach_table(ruleset, 1232 rule->overload_tblname)) == NULL) 1233 error = EINVAL; 1234 else 1235 rule->overload_tbl->pfrkt_flags |= 1236 PFR_TFLAG_ACTIVE; 1237 } 1238 1239 pf_mv_pool(&V_pf_pabuf, &rule->rpool.list); 1240 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || 1241 (rule->action == PF_BINAT)) && rule->anchor == NULL) || 1242 (rule->rt > PF_FASTROUTE)) && 1243 (TAILQ_FIRST(&rule->rpool.list) == NULL)) 1244 error = EINVAL; 1245 1246 if (error) { 1247 pf_free_rule(rule); 1248 PF_RULES_WUNLOCK(); 1249 break; 1250 } 1251 1252 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list); 1253 rule->evaluations = rule->packets[0] = rule->packets[1] = 1254 rule->bytes[0] = rule->bytes[1] = 0; 1255 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, 1256 rule, entries); 1257 ruleset->rules[rs_num].inactive.rcount++; 1258 PF_RULES_WUNLOCK(); 1259 break; 1260 1261#undef ERROUT 1262DIOCADDRULE_error: 1263 PF_RULES_WUNLOCK(); 1264 free(rule, M_PFRULE); 1265 if (kif) 1266 free(kif, PFI_MTYPE); 1267 break; 1268 } 1269 1270 case DIOCGETRULES: { 1271 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1272 struct pf_ruleset *ruleset; 1273 struct pf_rule *tail; 1274 int rs_num; 1275 1276 PF_RULES_WLOCK(); 1277 pr->anchor[sizeof(pr->anchor) - 1] = 0; 1278 ruleset = pf_find_ruleset(pr->anchor); 1279 if (ruleset == NULL) { 1280 PF_RULES_WUNLOCK(); 1281 error = EINVAL; 1282 break; 1283 } 1284 rs_num = pf_get_ruleset_number(pr->rule.action); 1285 if (rs_num >= PF_RULESET_MAX) { 1286 PF_RULES_WUNLOCK(); 1287 error = EINVAL; 1288 break; 1289 } 1290 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 1291 pf_rulequeue); 1292 if (tail) 1293 pr->nr = tail->nr + 1; 1294 else 1295 pr->nr = 0; 1296 pr->ticket = ruleset->rules[rs_num].active.ticket; 1297 PF_RULES_WUNLOCK(); 1298 break; 1299 } 1300 1301 case DIOCGETRULE: { 1302 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1303 struct pf_ruleset *ruleset; 1304 struct pf_rule *rule; 1305 int rs_num, i; 1306 1307 PF_RULES_WLOCK(); 1308 pr->anchor[sizeof(pr->anchor) - 1] = 0; 1309 ruleset = pf_find_ruleset(pr->anchor); 1310 if (ruleset == NULL) { 1311 PF_RULES_WUNLOCK(); 1312 error = EINVAL; 1313 break; 1314 } 1315 rs_num = pf_get_ruleset_number(pr->rule.action); 1316 if (rs_num >= PF_RULESET_MAX) { 1317 PF_RULES_WUNLOCK(); 1318 error = EINVAL; 1319 break; 1320 } 1321 if (pr->ticket != ruleset->rules[rs_num].active.ticket) { 1322 PF_RULES_WUNLOCK(); 1323 error = EBUSY; 1324 break; 1325 } 1326 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 1327 while ((rule != NULL) && (rule->nr != pr->nr)) 1328 rule = TAILQ_NEXT(rule, entries); 1329 if (rule == NULL) { 1330 PF_RULES_WUNLOCK(); 1331 error = EBUSY; 1332 break; 1333 } 1334 bcopy(rule, &pr->rule, sizeof(struct pf_rule)); 1335 if (pf_anchor_copyout(ruleset, rule, pr)) { 1336 PF_RULES_WUNLOCK(); 1337 error = EBUSY; 1338 break; 1339 } 1340 pf_addr_copyout(&pr->rule.src.addr); 1341 pf_addr_copyout(&pr->rule.dst.addr); 1342 for (i = 0; i < PF_SKIP_COUNT; ++i) 1343 if (rule->skip[i].ptr == NULL) 1344 pr->rule.skip[i].nr = -1; 1345 else 1346 pr->rule.skip[i].nr = 1347 rule->skip[i].ptr->nr; 1348 1349 if (pr->action == PF_GET_CLR_CNTR) { 1350 rule->evaluations = 0; 1351 rule->packets[0] = rule->packets[1] = 0; 1352 rule->bytes[0] = rule->bytes[1] = 0; 1353 rule->states_tot = 0; 1354 } 1355 PF_RULES_WUNLOCK(); 1356 break; 1357 } 1358 1359 case DIOCCHANGERULE: { 1360 struct pfioc_rule *pcr = (struct pfioc_rule *)addr; 1361 struct pf_ruleset *ruleset; 1362 struct pf_rule *oldrule = NULL, *newrule = NULL; 1363 struct pfi_kif *kif = NULL; 1364 struct pf_pooladdr *pa; 1365 u_int32_t nr = 0; 1366 int rs_num; 1367 1368 if (pcr->action < PF_CHANGE_ADD_HEAD || 1369 pcr->action > PF_CHANGE_GET_TICKET) { 1370 error = EINVAL; 1371 break; 1372 } 1373 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1374 error = EINVAL; 1375 break; 1376 } 1377 1378 if (pcr->action != PF_CHANGE_REMOVE) { 1379#ifndef INET 1380 if (pcr->rule.af == AF_INET) { 1381 error = EAFNOSUPPORT; 1382 break; 1383 } 1384#endif /* INET */ 1385#ifndef INET6 1386 if (pcr->rule.af == AF_INET6) { 1387 error = EAFNOSUPPORT; 1388 break; 1389 } 1390#endif /* INET6 */ 1391 newrule = malloc(sizeof(*newrule), M_PFRULE, M_WAITOK); 1392 bcopy(&pcr->rule, newrule, sizeof(struct pf_rule)); 1393 newrule->cuid = td->td_ucred->cr_ruid; 1394 newrule->cpid = td->td_proc ? td->td_proc->p_pid : 0; 1395 TAILQ_INIT(&newrule->rpool.list); 1396 /* Initialize refcounting. */ 1397 newrule->states_cur = 0; 1398 newrule->entries.tqe_prev = NULL; 1399 1400 if (newrule->ifname[0]) 1401 kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); 1402 } 1403 1404#define ERROUT(x) { error = (x); goto DIOCCHANGERULE_error; } 1405 1406 PF_RULES_WLOCK(); 1407 if (!(pcr->action == PF_CHANGE_REMOVE || 1408 pcr->action == PF_CHANGE_GET_TICKET) && 1409 pcr->pool_ticket != V_ticket_pabuf) 1410 ERROUT(EBUSY); 1411 1412 ruleset = pf_find_ruleset(pcr->anchor); 1413 if (ruleset == NULL) 1414 ERROUT(EINVAL); 1415 1416 rs_num = pf_get_ruleset_number(pcr->rule.action); 1417 if (rs_num >= PF_RULESET_MAX) 1418 ERROUT(EINVAL); 1419 1420 if (pcr->action == PF_CHANGE_GET_TICKET) { 1421 pcr->ticket = ++ruleset->rules[rs_num].active.ticket; 1422 ERROUT(0); 1423 } else if (pcr->ticket != 1424 ruleset->rules[rs_num].active.ticket) 1425 ERROUT(EINVAL); 1426 1427 if (pcr->action != PF_CHANGE_REMOVE) { 1428 if (newrule->ifname[0]) { 1429 newrule->kif = pfi_kif_attach(kif, 1430 newrule->ifname); 1431 pfi_kif_ref(newrule->kif); 1432 } else 1433 newrule->kif = NULL; 1434 1435 if (newrule->rtableid > 0 && 1436 newrule->rtableid >= rt_numfibs) 1437 error = EBUSY; 1438 1439#ifdef ALTQ 1440 /* set queue IDs */ 1441 if (newrule->qname[0] != 0) { 1442 if ((newrule->qid = 1443 pf_qname2qid(newrule->qname)) == 0) 1444 error = EBUSY; 1445 else if (newrule->pqname[0] != 0) { 1446 if ((newrule->pqid = 1447 pf_qname2qid(newrule->pqname)) == 0) 1448 error = EBUSY; 1449 } else 1450 newrule->pqid = newrule->qid; 1451 } 1452#endif /* ALTQ */ 1453 if (newrule->tagname[0]) 1454 if ((newrule->tag = 1455 pf_tagname2tag(newrule->tagname)) == 0) 1456 error = EBUSY; 1457 if (newrule->match_tagname[0]) 1458 if ((newrule->match_tag = pf_tagname2tag( 1459 newrule->match_tagname)) == 0) 1460 error = EBUSY; 1461 if (newrule->rt && !newrule->direction) 1462 error = EINVAL; 1463 if (!newrule->log) 1464 newrule->logif = 0; 1465 if (newrule->logif >= PFLOGIFS_MAX) 1466 error = EINVAL; 1467 if (pf_addr_setup(ruleset, &newrule->src.addr, newrule->af)) 1468 error = ENOMEM; 1469 if (pf_addr_setup(ruleset, &newrule->dst.addr, newrule->af)) 1470 error = ENOMEM; 1471 if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call)) 1472 error = EINVAL; 1473 TAILQ_FOREACH(pa, &V_pf_pabuf, entries) 1474 if (pa->addr.type == PF_ADDR_TABLE) { 1475 pa->addr.p.tbl = 1476 pfr_attach_table(ruleset, 1477 pa->addr.v.tblname); 1478 if (pa->addr.p.tbl == NULL) 1479 error = ENOMEM; 1480 } 1481 1482 if (newrule->overload_tblname[0]) { 1483 if ((newrule->overload_tbl = pfr_attach_table( 1484 ruleset, newrule->overload_tblname)) == 1485 NULL) 1486 error = EINVAL; 1487 else 1488 newrule->overload_tbl->pfrkt_flags |= 1489 PFR_TFLAG_ACTIVE; 1490 } 1491 1492 pf_mv_pool(&V_pf_pabuf, &newrule->rpool.list); 1493 if (((((newrule->action == PF_NAT) || 1494 (newrule->action == PF_RDR) || 1495 (newrule->action == PF_BINAT) || 1496 (newrule->rt > PF_FASTROUTE)) && 1497 !newrule->anchor)) && 1498 (TAILQ_FIRST(&newrule->rpool.list) == NULL)) 1499 error = EINVAL; 1500 1501 if (error) { 1502 pf_free_rule(newrule); 1503 PF_RULES_WUNLOCK(); 1504 break; 1505 } 1506 1507 newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list); 1508 newrule->evaluations = 0; 1509 newrule->packets[0] = newrule->packets[1] = 0; 1510 newrule->bytes[0] = newrule->bytes[1] = 0; 1511 } 1512 pf_empty_pool(&V_pf_pabuf); 1513 1514 if (pcr->action == PF_CHANGE_ADD_HEAD) 1515 oldrule = TAILQ_FIRST( 1516 ruleset->rules[rs_num].active.ptr); 1517 else if (pcr->action == PF_CHANGE_ADD_TAIL) 1518 oldrule = TAILQ_LAST( 1519 ruleset->rules[rs_num].active.ptr, pf_rulequeue); 1520 else { 1521 oldrule = TAILQ_FIRST( 1522 ruleset->rules[rs_num].active.ptr); 1523 while ((oldrule != NULL) && (oldrule->nr != pcr->nr)) 1524 oldrule = TAILQ_NEXT(oldrule, entries); 1525 if (oldrule == NULL) { 1526 if (newrule != NULL) 1527 pf_free_rule(newrule); 1528 PF_RULES_WUNLOCK(); 1529 error = EINVAL; 1530 break; 1531 } 1532 } 1533 1534 if (pcr->action == PF_CHANGE_REMOVE) { 1535 pf_unlink_rule(ruleset->rules[rs_num].active.ptr, 1536 oldrule); 1537 ruleset->rules[rs_num].active.rcount--; 1538 } else { 1539 if (oldrule == NULL) 1540 TAILQ_INSERT_TAIL( 1541 ruleset->rules[rs_num].active.ptr, 1542 newrule, entries); 1543 else if (pcr->action == PF_CHANGE_ADD_HEAD || 1544 pcr->action == PF_CHANGE_ADD_BEFORE) 1545 TAILQ_INSERT_BEFORE(oldrule, newrule, entries); 1546 else 1547 TAILQ_INSERT_AFTER( 1548 ruleset->rules[rs_num].active.ptr, 1549 oldrule, newrule, entries); 1550 ruleset->rules[rs_num].active.rcount++; 1551 } 1552 1553 nr = 0; 1554 TAILQ_FOREACH(oldrule, 1555 ruleset->rules[rs_num].active.ptr, entries) 1556 oldrule->nr = nr++; 1557 1558 ruleset->rules[rs_num].active.ticket++; 1559 1560 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); 1561 pf_remove_if_empty_ruleset(ruleset); 1562 1563 PF_RULES_WUNLOCK(); 1564 break; 1565 1566#undef ERROUT 1567DIOCCHANGERULE_error: 1568 PF_RULES_WUNLOCK(); 1569 if (newrule != NULL) 1570 free(newrule, M_PFRULE); 1571 if (kif != NULL) 1572 free(kif, PFI_MTYPE); 1573 break; 1574 } 1575 1576 case DIOCCLRSTATES: { 1577 struct pf_state *s; 1578 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 1579 u_int i, killed = 0; 1580 1581 for (i = 0; i <= V_pf_hashmask; i++) { 1582 struct pf_idhash *ih = &V_pf_idhash[i]; 1583 1584relock_DIOCCLRSTATES: 1585 PF_HASHROW_LOCK(ih); 1586 LIST_FOREACH(s, &ih->states, entry) 1587 if (!psk->psk_ifname[0] || 1588 !strcmp(psk->psk_ifname, 1589 s->kif->pfik_name)) { 1590 /* 1591 * Don't send out individual 1592 * delete messages. 1593 */ 1594 s->state_flags |= PFSTATE_NOSYNC; 1595 pf_unlink_state(s, PF_ENTER_LOCKED); 1596 killed++; 1597 goto relock_DIOCCLRSTATES; 1598 } 1599 PF_HASHROW_UNLOCK(ih); 1600 } 1601 psk->psk_killed = killed; 1602 if (pfsync_clear_states_ptr != NULL) 1603 pfsync_clear_states_ptr(V_pf_status.hostid, psk->psk_ifname); 1604 break; 1605 } 1606 1607 case DIOCKILLSTATES: { 1608 struct pf_state *s; 1609 struct pf_state_key *sk; 1610 struct pf_addr *srcaddr, *dstaddr; 1611 u_int16_t srcport, dstport; 1612 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 1613 u_int i, killed = 0; 1614 1615 if (psk->psk_pfcmp.id) { 1616 if (psk->psk_pfcmp.creatorid == 0) 1617 psk->psk_pfcmp.creatorid = V_pf_status.hostid; 1618 if ((s = pf_find_state_byid(psk->psk_pfcmp.id, 1619 psk->psk_pfcmp.creatorid))) { 1620 pf_unlink_state(s, PF_ENTER_LOCKED); 1621 psk->psk_killed = 1; 1622 } 1623 break; 1624 } 1625 1626 for (i = 0; i <= V_pf_hashmask; i++) { 1627 struct pf_idhash *ih = &V_pf_idhash[i]; 1628 1629relock_DIOCKILLSTATES: 1630 PF_HASHROW_LOCK(ih); 1631 LIST_FOREACH(s, &ih->states, entry) { 1632 sk = s->key[PF_SK_WIRE]; 1633 if (s->direction == PF_OUT) { 1634 srcaddr = &sk->addr[1]; 1635 dstaddr = &sk->addr[0]; 1636 srcport = sk->port[0]; 1637 dstport = sk->port[0]; 1638 } else { 1639 srcaddr = &sk->addr[0]; 1640 dstaddr = &sk->addr[1]; 1641 srcport = sk->port[0]; 1642 dstport = sk->port[0]; 1643 } 1644 1645 if ((!psk->psk_af || sk->af == psk->psk_af) 1646 && (!psk->psk_proto || psk->psk_proto == 1647 sk->proto) && 1648 PF_MATCHA(psk->psk_src.neg, 1649 &psk->psk_src.addr.v.a.addr, 1650 &psk->psk_src.addr.v.a.mask, 1651 srcaddr, sk->af) && 1652 PF_MATCHA(psk->psk_dst.neg, 1653 &psk->psk_dst.addr.v.a.addr, 1654 &psk->psk_dst.addr.v.a.mask, 1655 dstaddr, sk->af) && 1656 (psk->psk_src.port_op == 0 || 1657 pf_match_port(psk->psk_src.port_op, 1658 psk->psk_src.port[0], psk->psk_src.port[1], 1659 srcport)) && 1660 (psk->psk_dst.port_op == 0 || 1661 pf_match_port(psk->psk_dst.port_op, 1662 psk->psk_dst.port[0], psk->psk_dst.port[1], 1663 dstport)) && 1664 (!psk->psk_label[0] || 1665 (s->rule.ptr->label[0] && 1666 !strcmp(psk->psk_label, 1667 s->rule.ptr->label))) && 1668 (!psk->psk_ifname[0] || 1669 !strcmp(psk->psk_ifname, 1670 s->kif->pfik_name))) { 1671 pf_unlink_state(s, PF_ENTER_LOCKED); 1672 killed++; 1673 goto relock_DIOCKILLSTATES; 1674 } 1675 } 1676 PF_HASHROW_UNLOCK(ih); 1677 } 1678 psk->psk_killed = killed; 1679 break; 1680 } 1681 1682 case DIOCADDSTATE: { 1683 struct pfioc_state *ps = (struct pfioc_state *)addr; 1684 struct pfsync_state *sp = &ps->state; 1685 1686 if (sp->timeout >= PFTM_MAX) { 1687 error = EINVAL; 1688 break; 1689 } 1690 if (pfsync_state_import_ptr != NULL) { 1691 PF_RULES_RLOCK(); 1692 error = pfsync_state_import_ptr(sp, PFSYNC_SI_IOCTL); 1693 PF_RULES_RUNLOCK(); 1694 } else 1695 error = EOPNOTSUPP; 1696 break; 1697 } 1698 1699 case DIOCGETSTATE: { 1700 struct pfioc_state *ps = (struct pfioc_state *)addr; 1701 struct pf_state *s; 1702 1703 s = pf_find_state_byid(ps->state.id, ps->state.creatorid); 1704 if (s == NULL) { 1705 error = ENOENT; 1706 break; 1707 } 1708 1709 pfsync_state_export(&ps->state, s); 1710 PF_STATE_UNLOCK(s); 1711 break; 1712 } 1713 1714 case DIOCGETSTATES: { 1715 struct pfioc_states *ps = (struct pfioc_states *)addr; 1716 struct pf_state *s; 1717 struct pfsync_state *pstore, *p; 1718 int i, nr; 1719 1720 if (ps->ps_len == 0) { 1721 nr = uma_zone_get_cur(V_pf_state_z); 1722 ps->ps_len = sizeof(struct pfsync_state) * nr; 1723 break; 1724 } 1725 1726 p = pstore = malloc(ps->ps_len, M_TEMP, M_WAITOK); 1727 nr = 0; 1728 1729 for (i = 0; i <= V_pf_hashmask; i++) { 1730 struct pf_idhash *ih = &V_pf_idhash[i]; 1731 1732 PF_HASHROW_LOCK(ih); 1733 LIST_FOREACH(s, &ih->states, entry) { 1734 1735 if (s->timeout == PFTM_UNLINKED) 1736 continue; 1737 1738 if ((nr+1) * sizeof(*p) > ps->ps_len) { 1739 PF_HASHROW_UNLOCK(ih); 1740 goto DIOCGETSTATES_full; 1741 } 1742 pfsync_state_export(p, s); 1743 p++; 1744 nr++; 1745 } 1746 PF_HASHROW_UNLOCK(ih); 1747 } 1748DIOCGETSTATES_full: 1749 error = copyout(pstore, ps->ps_states, 1750 sizeof(struct pfsync_state) * nr); 1751 if (error) { 1752 free(pstore, M_TEMP); 1753 break; 1754 } 1755 ps->ps_len = sizeof(struct pfsync_state) * nr; 1756 free(pstore, M_TEMP); 1757 1758 break; 1759 } 1760 1761 case DIOCGETSTATUS: { 1762 struct pf_status *s = (struct pf_status *)addr; 1763 PF_RULES_RLOCK(); 1764 bcopy(&V_pf_status, s, sizeof(struct pf_status)); 1765 pfi_update_status(s->ifname, s); 1766 PF_RULES_RUNLOCK(); 1767 break; 1768 } 1769 1770 case DIOCSETSTATUSIF: { 1771 struct pfioc_if *pi = (struct pfioc_if *)addr; 1772 1773 if (pi->ifname[0] == 0) { 1774 bzero(V_pf_status.ifname, IFNAMSIZ); 1775 break; 1776 } 1777 PF_RULES_WLOCK(); 1778 strlcpy(V_pf_status.ifname, pi->ifname, IFNAMSIZ); 1779 PF_RULES_WUNLOCK(); 1780 break; 1781 } 1782 1783 case DIOCCLRSTATUS: { 1784 PF_RULES_WLOCK(); 1785 bzero(V_pf_status.counters, sizeof(V_pf_status.counters)); 1786 bzero(V_pf_status.fcounters, sizeof(V_pf_status.fcounters)); 1787 bzero(V_pf_status.scounters, sizeof(V_pf_status.scounters)); 1788 V_pf_status.since = time_second; 1789 if (*V_pf_status.ifname) 1790 pfi_update_status(V_pf_status.ifname, NULL); 1791 PF_RULES_WUNLOCK(); 1792 break; 1793 } 1794 1795 case DIOCNATLOOK: { 1796 struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; 1797 struct pf_state_key *sk; 1798 struct pf_state *state; 1799 struct pf_state_key_cmp key; 1800 int m = 0, direction = pnl->direction; 1801 int sidx, didx; 1802 1803 /* NATLOOK src and dst are reversed, so reverse sidx/didx */ 1804 sidx = (direction == PF_IN) ? 1 : 0; 1805 didx = (direction == PF_IN) ? 0 : 1; 1806 1807 if (!pnl->proto || 1808 PF_AZERO(&pnl->saddr, pnl->af) || 1809 PF_AZERO(&pnl->daddr, pnl->af) || 1810 ((pnl->proto == IPPROTO_TCP || 1811 pnl->proto == IPPROTO_UDP) && 1812 (!pnl->dport || !pnl->sport))) 1813 error = EINVAL; 1814 else { 1815 bzero(&key, sizeof(key)); 1816 key.af = pnl->af; 1817 key.proto = pnl->proto; 1818 PF_ACPY(&key.addr[sidx], &pnl->saddr, pnl->af); 1819 key.port[sidx] = pnl->sport; 1820 PF_ACPY(&key.addr[didx], &pnl->daddr, pnl->af); 1821 key.port[didx] = pnl->dport; 1822 1823 state = pf_find_state_all(&key, direction, &m); 1824 1825 if (m > 1) 1826 error = E2BIG; /* more than one state */ 1827 else if (state != NULL) { 1828 /* XXXGL: not locked read */ 1829 sk = state->key[sidx]; 1830 PF_ACPY(&pnl->rsaddr, &sk->addr[sidx], sk->af); 1831 pnl->rsport = sk->port[sidx]; 1832 PF_ACPY(&pnl->rdaddr, &sk->addr[didx], sk->af); 1833 pnl->rdport = sk->port[didx]; 1834 } else 1835 error = ENOENT; 1836 } 1837 break; 1838 } 1839 1840 case DIOCSETTIMEOUT: { 1841 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 1842 int old; 1843 1844 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX || 1845 pt->seconds < 0) { 1846 error = EINVAL; 1847 break; 1848 } 1849 PF_RULES_WLOCK(); 1850 old = V_pf_default_rule.timeout[pt->timeout]; 1851 if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0) 1852 pt->seconds = 1; 1853 V_pf_default_rule.timeout[pt->timeout] = pt->seconds; 1854 if (pt->timeout == PFTM_INTERVAL && pt->seconds < old) 1855 wakeup(pf_purge_thread); 1856 pt->seconds = old; 1857 PF_RULES_WUNLOCK(); 1858 break; 1859 } 1860 1861 case DIOCGETTIMEOUT: { 1862 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 1863 1864 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) { 1865 error = EINVAL; 1866 break; 1867 } 1868 PF_RULES_RLOCK(); 1869 pt->seconds = V_pf_default_rule.timeout[pt->timeout]; 1870 PF_RULES_RUNLOCK(); 1871 break; 1872 } 1873 1874 case DIOCGETLIMIT: { 1875 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 1876 1877 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { 1878 error = EINVAL; 1879 break; 1880 } 1881 PF_RULES_RLOCK(); 1882 pl->limit = V_pf_limits[pl->index].limit; 1883 PF_RULES_RUNLOCK(); 1884 break; 1885 } 1886 1887 case DIOCSETLIMIT: { 1888 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 1889 int old_limit; 1890 1891 PF_RULES_WLOCK(); 1892 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX || 1893 V_pf_limits[pl->index].zone == NULL) { 1894 PF_RULES_WUNLOCK(); 1895 error = EINVAL; 1896 break; 1897 } 1898 uma_zone_set_max(V_pf_limits[pl->index].zone, pl->limit); 1899 old_limit = V_pf_limits[pl->index].limit; 1900 V_pf_limits[pl->index].limit = pl->limit; 1901 pl->limit = old_limit; 1902 PF_RULES_WUNLOCK(); 1903 break; 1904 } 1905 1906 case DIOCSETDEBUG: { 1907 u_int32_t *level = (u_int32_t *)addr; 1908 1909 PF_RULES_WLOCK(); 1910 V_pf_status.debug = *level; 1911 PF_RULES_WUNLOCK(); 1912 break; 1913 } 1914 1915 case DIOCCLRRULECTRS: { 1916 /* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */ 1917 struct pf_ruleset *ruleset = &pf_main_ruleset; 1918 struct pf_rule *rule; 1919 1920 PF_RULES_WLOCK(); 1921 TAILQ_FOREACH(rule, 1922 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) { 1923 rule->evaluations = 0; 1924 rule->packets[0] = rule->packets[1] = 0; 1925 rule->bytes[0] = rule->bytes[1] = 0; 1926 } 1927 PF_RULES_WUNLOCK(); 1928 break; 1929 } 1930 1931 case DIOCGIFSPEED: { 1932 struct pf_ifspeed *psp = (struct pf_ifspeed *)addr; 1933 struct pf_ifspeed ps; 1934 struct ifnet *ifp; 1935 1936 if (psp->ifname[0] != 0) { 1937 /* Can we completely trust user-land? */ 1938 strlcpy(ps.ifname, psp->ifname, IFNAMSIZ); 1939 ifp = ifunit(ps.ifname); 1940 if (ifp != NULL) 1941 psp->baudrate = ifp->if_baudrate; 1942 else 1943 error = EINVAL; 1944 } else 1945 error = EINVAL; 1946 break; 1947 } 1948 1949#ifdef ALTQ 1950 case DIOCSTARTALTQ: { 1951 struct pf_altq *altq; 1952 1953 PF_RULES_WLOCK(); 1954 /* enable all altq interfaces on active list */ 1955 TAILQ_FOREACH(altq, V_pf_altqs_active, entries) { 1956 if (altq->qname[0] == 0 && (altq->local_flags & 1957 PFALTQ_FLAG_IF_REMOVED) == 0) { 1958 error = pf_enable_altq(altq); 1959 if (error != 0) 1960 break; 1961 } 1962 } 1963 if (error == 0) 1964 V_pf_altq_running = 1; 1965 PF_RULES_WUNLOCK(); 1966 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n")); 1967 break; 1968 } 1969 1970 case DIOCSTOPALTQ: { 1971 struct pf_altq *altq; 1972 1973 PF_RULES_WLOCK(); 1974 /* disable all altq interfaces on active list */ 1975 TAILQ_FOREACH(altq, V_pf_altqs_active, entries) { 1976 if (altq->qname[0] == 0 && (altq->local_flags & 1977 PFALTQ_FLAG_IF_REMOVED) == 0) { 1978 error = pf_disable_altq(altq); 1979 if (error != 0) 1980 break; 1981 } 1982 } 1983 if (error == 0) 1984 V_pf_altq_running = 0; 1985 PF_RULES_WUNLOCK(); 1986 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n")); 1987 break; 1988 } 1989 1990 case DIOCADDALTQ: { 1991 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 1992 struct pf_altq *altq, *a; 1993 struct ifnet *ifp; 1994 1995 altq = malloc(sizeof(*altq), M_PFALTQ, M_WAITOK); 1996 bcopy(&pa->altq, altq, sizeof(struct pf_altq)); 1997 altq->local_flags = 0; 1998 1999 PF_RULES_WLOCK(); 2000 if (pa->ticket != V_ticket_altqs_inactive) { 2001 PF_RULES_WUNLOCK(); 2002 free(altq, M_PFALTQ); 2003 error = EBUSY; 2004 break; 2005 } 2006 2007 /* 2008 * if this is for a queue, find the discipline and 2009 * copy the necessary fields 2010 */ 2011 if (altq->qname[0] != 0) { 2012 if ((altq->qid = pf_qname2qid(altq->qname)) == 0) { 2013 PF_RULES_WUNLOCK(); 2014 error = EBUSY; 2015 free(altq, M_PFALTQ); 2016 break; 2017 } 2018 altq->altq_disc = NULL; 2019 TAILQ_FOREACH(a, V_pf_altqs_inactive, entries) { 2020 if (strncmp(a->ifname, altq->ifname, 2021 IFNAMSIZ) == 0 && a->qname[0] == 0) { 2022 altq->altq_disc = a->altq_disc; 2023 break; 2024 } 2025 } 2026 } 2027 2028 if ((ifp = ifunit(altq->ifname)) == NULL) 2029 altq->local_flags |= PFALTQ_FLAG_IF_REMOVED; 2030 else 2031 error = altq_add(altq); 2032 2033 if (error) { 2034 PF_RULES_WUNLOCK(); 2035 free(altq, M_PFALTQ); 2036 break; 2037 } 2038 2039 TAILQ_INSERT_TAIL(V_pf_altqs_inactive, altq, entries); 2040 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 2041 PF_RULES_WUNLOCK(); 2042 break; 2043 } 2044 2045 case DIOCGETALTQS: { 2046 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2047 struct pf_altq *altq; 2048 2049 PF_RULES_RLOCK(); 2050 pa->nr = 0; 2051 TAILQ_FOREACH(altq, V_pf_altqs_active, entries) 2052 pa->nr++; 2053 pa->ticket = V_ticket_altqs_active; 2054 PF_RULES_RUNLOCK(); 2055 break; 2056 } 2057 2058 case DIOCGETALTQ: { 2059 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2060 struct pf_altq *altq; 2061 u_int32_t nr; 2062 2063 PF_RULES_RLOCK(); 2064 if (pa->ticket != V_ticket_altqs_active) { 2065 PF_RULES_RUNLOCK(); 2066 error = EBUSY; 2067 break; 2068 } 2069 nr = 0; 2070 altq = TAILQ_FIRST(V_pf_altqs_active); 2071 while ((altq != NULL) && (nr < pa->nr)) { 2072 altq = TAILQ_NEXT(altq, entries); 2073 nr++; 2074 } 2075 if (altq == NULL) { 2076 PF_RULES_RUNLOCK(); 2077 error = EBUSY; 2078 break; 2079 } 2080 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 2081 PF_RULES_RUNLOCK(); 2082 break; 2083 } 2084 2085 case DIOCCHANGEALTQ: 2086 /* CHANGEALTQ not supported yet! */ 2087 error = ENODEV; 2088 break; 2089 2090 case DIOCGETQSTATS: { 2091 struct pfioc_qstats *pq = (struct pfioc_qstats *)addr; 2092 struct pf_altq *altq; 2093 u_int32_t nr; 2094 int nbytes; 2095 2096 PF_RULES_RLOCK(); 2097 if (pq->ticket != V_ticket_altqs_active) { 2098 PF_RULES_RUNLOCK(); 2099 error = EBUSY; 2100 break; 2101 } 2102 nbytes = pq->nbytes; 2103 nr = 0; 2104 altq = TAILQ_FIRST(V_pf_altqs_active); 2105 while ((altq != NULL) && (nr < pq->nr)) { 2106 altq = TAILQ_NEXT(altq, entries); 2107 nr++; 2108 } 2109 if (altq == NULL) { 2110 PF_RULES_RUNLOCK(); 2111 error = EBUSY; 2112 break; 2113 } 2114 2115 if ((altq->local_flags & PFALTQ_FLAG_IF_REMOVED) != 0) { 2116 PF_RULES_RUNLOCK(); 2117 error = ENXIO; 2118 break; 2119 } 2120 PF_RULES_RUNLOCK(); 2121 error = altq_getqstats(altq, pq->buf, &nbytes); 2122 if (error == 0) { 2123 pq->scheduler = altq->scheduler; 2124 pq->nbytes = nbytes; 2125 } 2126 break; 2127 } 2128#endif /* ALTQ */ 2129 2130 case DIOCBEGINADDRS: { 2131 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2132 2133 PF_RULES_WLOCK(); 2134 pf_empty_pool(&V_pf_pabuf); 2135 pp->ticket = ++V_ticket_pabuf; 2136 PF_RULES_WUNLOCK(); 2137 break; 2138 } 2139 2140 case DIOCADDADDR: { 2141 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2142 struct pf_pooladdr *pa; 2143 struct pfi_kif *kif = NULL; 2144 2145#ifndef INET 2146 if (pp->af == AF_INET) { 2147 error = EAFNOSUPPORT; 2148 break; 2149 } 2150#endif /* INET */ 2151#ifndef INET6 2152 if (pp->af == AF_INET6) { 2153 error = EAFNOSUPPORT; 2154 break; 2155 } 2156#endif /* INET6 */ 2157 if (pp->addr.addr.type != PF_ADDR_ADDRMASK && 2158 pp->addr.addr.type != PF_ADDR_DYNIFTL && 2159 pp->addr.addr.type != PF_ADDR_TABLE) { 2160 error = EINVAL; 2161 break; 2162 } 2163 pa = malloc(sizeof(*pa), M_PFRULE, M_WAITOK); 2164 bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr)); 2165 if (pa->ifname[0]) 2166 kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); 2167 PF_RULES_WLOCK(); 2168 if (pp->ticket != V_ticket_pabuf) { 2169 PF_RULES_WUNLOCK(); 2170 if (pa->ifname[0]) 2171 free(kif, PFI_MTYPE); 2172 free(pa, M_PFRULE); 2173 error = EBUSY; 2174 break; 2175 } 2176 if (pa->ifname[0]) { 2177 pa->kif = pfi_kif_attach(kif, pa->ifname); 2178 pfi_kif_ref(pa->kif); 2179 } else 2180 pa->kif = NULL; 2181 if (pa->addr.type == PF_ADDR_DYNIFTL && ((error = 2182 pfi_dynaddr_setup(&pa->addr, pp->af)) != 0)) { 2183 if (pa->ifname[0]) 2184 pfi_kif_unref(pa->kif); 2185 PF_RULES_WUNLOCK(); 2186 free(pa, M_PFRULE); 2187 break; 2188 } 2189 TAILQ_INSERT_TAIL(&V_pf_pabuf, pa, entries); 2190 PF_RULES_WUNLOCK(); 2191 break; 2192 } 2193 2194 case DIOCGETADDRS: { 2195 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2196 struct pf_pool *pool; 2197 struct pf_pooladdr *pa; 2198 2199 PF_RULES_RLOCK(); 2200 pp->nr = 0; 2201 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, 2202 pp->r_num, 0, 1, 0); 2203 if (pool == NULL) { 2204 PF_RULES_RUNLOCK(); 2205 error = EBUSY; 2206 break; 2207 } 2208 TAILQ_FOREACH(pa, &pool->list, entries) 2209 pp->nr++; 2210 PF_RULES_RUNLOCK(); 2211 break; 2212 } 2213 2214 case DIOCGETADDR: { 2215 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2216 struct pf_pool *pool; 2217 struct pf_pooladdr *pa; 2218 u_int32_t nr = 0; 2219 2220 PF_RULES_RLOCK(); 2221 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, 2222 pp->r_num, 0, 1, 1); 2223 if (pool == NULL) { 2224 PF_RULES_RUNLOCK(); 2225 error = EBUSY; 2226 break; 2227 } 2228 pa = TAILQ_FIRST(&pool->list); 2229 while ((pa != NULL) && (nr < pp->nr)) { 2230 pa = TAILQ_NEXT(pa, entries); 2231 nr++; 2232 } 2233 if (pa == NULL) { 2234 PF_RULES_RUNLOCK(); 2235 error = EBUSY; 2236 break; 2237 } 2238 bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr)); 2239 pf_addr_copyout(&pp->addr.addr); 2240 PF_RULES_RUNLOCK(); 2241 break; 2242 } 2243 2244 case DIOCCHANGEADDR: { 2245 struct pfioc_pooladdr *pca = (struct pfioc_pooladdr *)addr; 2246 struct pf_pool *pool; 2247 struct pf_pooladdr *oldpa = NULL, *newpa = NULL; 2248 struct pf_ruleset *ruleset; 2249 struct pfi_kif *kif = NULL; 2250 2251 if (pca->action < PF_CHANGE_ADD_HEAD || 2252 pca->action > PF_CHANGE_REMOVE) { 2253 error = EINVAL; 2254 break; 2255 } 2256 if (pca->addr.addr.type != PF_ADDR_ADDRMASK && 2257 pca->addr.addr.type != PF_ADDR_DYNIFTL && 2258 pca->addr.addr.type != PF_ADDR_TABLE) { 2259 error = EINVAL; 2260 break; 2261 } 2262 2263 if (pca->action != PF_CHANGE_REMOVE) { 2264#ifndef INET 2265 if (pca->af == AF_INET) { 2266 error = EAFNOSUPPORT; 2267 break; 2268 } 2269#endif /* INET */ 2270#ifndef INET6 2271 if (pca->af == AF_INET6) { 2272 error = EAFNOSUPPORT; 2273 break; 2274 } 2275#endif /* INET6 */ 2276 newpa = malloc(sizeof(*newpa), M_PFRULE, M_WAITOK); 2277 bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr)); 2278 if (newpa->ifname[0]) 2279 kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); 2280 } 2281 2282#define ERROUT(x) { error = (x); goto DIOCCHANGEADDR_error; } 2283 PF_RULES_WLOCK(); 2284 ruleset = pf_find_ruleset(pca->anchor); 2285 if (ruleset == NULL) 2286 ERROUT(EBUSY); 2287 2288 pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action, 2289 pca->r_num, pca->r_last, 1, 1); 2290 if (pool == NULL) 2291 ERROUT(EBUSY); 2292 2293 if (pca->action != PF_CHANGE_REMOVE) { 2294 if (newpa->ifname[0]) { 2295 newpa->kif = pfi_kif_attach(kif, newpa->ifname); 2296 pfi_kif_ref(newpa->kif); 2297 } else 2298 newpa->kif = NULL; 2299 2300 switch (newpa->addr.type) { 2301 case PF_ADDR_DYNIFTL: 2302 error = pfi_dynaddr_setup(&newpa->addr, 2303 pca->af); 2304 break; 2305 case PF_ADDR_TABLE: 2306 newpa->addr.p.tbl = pfr_attach_table(ruleset, 2307 newpa->addr.v.tblname); 2308 if (newpa->addr.p.tbl == NULL) 2309 error = ENOMEM; 2310 break; 2311 } 2312 if (error) { 2313 if (newpa->kif) 2314 pfi_kif_unref(newpa->kif); 2315 PF_RULES_WUNLOCK(); 2316 free(newpa, M_PFRULE); 2317 break; 2318 } 2319 } 2320 2321 if (pca->action == PF_CHANGE_ADD_HEAD) 2322 oldpa = TAILQ_FIRST(&pool->list); 2323 else if (pca->action == PF_CHANGE_ADD_TAIL) 2324 oldpa = TAILQ_LAST(&pool->list, pf_palist); 2325 else { 2326 int i = 0; 2327 2328 oldpa = TAILQ_FIRST(&pool->list); 2329 while ((oldpa != NULL) && (i < pca->nr)) { 2330 oldpa = TAILQ_NEXT(oldpa, entries); 2331 i++; 2332 } 2333 if (oldpa == NULL) { 2334 PF_RULES_WUNLOCK(); 2335 error = EINVAL; 2336 break; 2337 } 2338 } 2339 2340 if (pca->action == PF_CHANGE_REMOVE) { 2341 TAILQ_REMOVE(&pool->list, oldpa, entries); 2342 switch (oldpa->addr.type) { 2343 case PF_ADDR_DYNIFTL: 2344 pfi_dynaddr_remove(oldpa->addr.p.dyn); 2345 break; 2346 case PF_ADDR_TABLE: 2347 pfr_detach_table(oldpa->addr.p.tbl); 2348 break; 2349 } 2350 if (oldpa->kif) 2351 pfi_kif_unref(oldpa->kif); 2352 free(oldpa, M_PFRULE); 2353 } else { 2354 if (oldpa == NULL) 2355 TAILQ_INSERT_TAIL(&pool->list, newpa, entries); 2356 else if (pca->action == PF_CHANGE_ADD_HEAD || 2357 pca->action == PF_CHANGE_ADD_BEFORE) 2358 TAILQ_INSERT_BEFORE(oldpa, newpa, entries); 2359 else 2360 TAILQ_INSERT_AFTER(&pool->list, oldpa, 2361 newpa, entries); 2362 } 2363 2364 pool->cur = TAILQ_FIRST(&pool->list); 2365 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, 2366 pca->af); 2367 PF_RULES_WUNLOCK(); 2368 break; 2369 2370#undef ERROUT 2371DIOCCHANGEADDR_error: 2372 PF_RULES_WUNLOCK(); 2373 if (newpa != NULL) 2374 free(newpa, M_PFRULE); 2375 if (kif != NULL) 2376 free(kif, PFI_MTYPE); 2377 break; 2378 } 2379 2380 case DIOCGETRULESETS: { 2381 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 2382 struct pf_ruleset *ruleset; 2383 struct pf_anchor *anchor; 2384 2385 PF_RULES_RLOCK(); 2386 pr->path[sizeof(pr->path) - 1] = 0; 2387 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) { 2388 PF_RULES_RUNLOCK(); 2389 error = ENOENT; 2390 break; 2391 } 2392 pr->nr = 0; 2393 if (ruleset->anchor == NULL) { 2394 /* XXX kludge for pf_main_ruleset */ 2395 RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors) 2396 if (anchor->parent == NULL) 2397 pr->nr++; 2398 } else { 2399 RB_FOREACH(anchor, pf_anchor_node, 2400 &ruleset->anchor->children) 2401 pr->nr++; 2402 } 2403 PF_RULES_RUNLOCK(); 2404 break; 2405 } 2406 2407 case DIOCGETRULESET: { 2408 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 2409 struct pf_ruleset *ruleset; 2410 struct pf_anchor *anchor; 2411 u_int32_t nr = 0; 2412 2413 PF_RULES_RLOCK(); 2414 pr->path[sizeof(pr->path) - 1] = 0; 2415 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) { 2416 PF_RULES_RUNLOCK(); 2417 error = ENOENT; 2418 break; 2419 } 2420 pr->name[0] = 0; 2421 if (ruleset->anchor == NULL) { 2422 /* XXX kludge for pf_main_ruleset */ 2423 RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors) 2424 if (anchor->parent == NULL && nr++ == pr->nr) { 2425 strlcpy(pr->name, anchor->name, 2426 sizeof(pr->name)); 2427 break; 2428 } 2429 } else { 2430 RB_FOREACH(anchor, pf_anchor_node, 2431 &ruleset->anchor->children) 2432 if (nr++ == pr->nr) { 2433 strlcpy(pr->name, anchor->name, 2434 sizeof(pr->name)); 2435 break; 2436 } 2437 } 2438 if (!pr->name[0]) 2439 error = EBUSY; 2440 PF_RULES_RUNLOCK(); 2441 break; 2442 } 2443 2444 case DIOCRCLRTABLES: { 2445 struct pfioc_table *io = (struct pfioc_table *)addr; 2446 2447 if (io->pfrio_esize != 0) { 2448 error = ENODEV; 2449 break; 2450 } 2451 PF_RULES_WLOCK(); 2452 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, 2453 io->pfrio_flags | PFR_FLAG_USERIOCTL); 2454 PF_RULES_WUNLOCK(); 2455 break; 2456 } 2457 2458 case DIOCRADDTABLES: { 2459 struct pfioc_table *io = (struct pfioc_table *)addr; 2460 struct pfr_table *pfrts; 2461 size_t totlen; 2462 2463 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2464 error = ENODEV; 2465 break; 2466 } 2467 totlen = io->pfrio_size * sizeof(struct pfr_table); 2468 pfrts = malloc(totlen, M_TEMP, M_WAITOK); 2469 error = copyin(io->pfrio_buffer, pfrts, totlen); 2470 if (error) { 2471 free(pfrts, M_TEMP); 2472 break; 2473 } 2474 PF_RULES_WLOCK(); 2475 error = pfr_add_tables(pfrts, io->pfrio_size, 2476 &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2477 PF_RULES_WUNLOCK(); 2478 free(pfrts, M_TEMP); 2479 break; 2480 } 2481 2482 case DIOCRDELTABLES: { 2483 struct pfioc_table *io = (struct pfioc_table *)addr; 2484 struct pfr_table *pfrts; 2485 size_t totlen; 2486 2487 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2488 error = ENODEV; 2489 break; 2490 } 2491 totlen = io->pfrio_size * sizeof(struct pfr_table); 2492 pfrts = malloc(totlen, M_TEMP, M_WAITOK); 2493 error = copyin(io->pfrio_buffer, pfrts, totlen); 2494 if (error) { 2495 free(pfrts, M_TEMP); 2496 break; 2497 } 2498 PF_RULES_WLOCK(); 2499 error = pfr_del_tables(pfrts, io->pfrio_size, 2500 &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2501 PF_RULES_WUNLOCK(); 2502 free(pfrts, M_TEMP); 2503 break; 2504 } 2505 2506 case DIOCRGETTABLES: { 2507 struct pfioc_table *io = (struct pfioc_table *)addr; 2508 struct pfr_table *pfrts; 2509 size_t totlen; 2510 2511 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2512 error = ENODEV; 2513 break; 2514 } 2515 totlen = io->pfrio_size * sizeof(struct pfr_table); 2516 pfrts = malloc(totlen, M_TEMP, M_WAITOK); 2517 PF_RULES_RLOCK(); 2518 error = pfr_get_tables(&io->pfrio_table, pfrts, 2519 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2520 PF_RULES_RUNLOCK(); 2521 if (error == 0) 2522 error = copyout(pfrts, io->pfrio_buffer, totlen); 2523 free(pfrts, M_TEMP); 2524 break; 2525 } 2526 2527 case DIOCRGETTSTATS: { 2528 struct pfioc_table *io = (struct pfioc_table *)addr; 2529 struct pfr_tstats *pfrtstats; 2530 size_t totlen; 2531 2532 if (io->pfrio_esize != sizeof(struct pfr_tstats)) { 2533 error = ENODEV; 2534 break; 2535 } 2536 totlen = io->pfrio_size * sizeof(struct pfr_tstats); 2537 pfrtstats = malloc(totlen, M_TEMP, M_WAITOK); 2538 PF_RULES_WLOCK(); 2539 error = pfr_get_tstats(&io->pfrio_table, pfrtstats, 2540 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2541 PF_RULES_WUNLOCK(); 2542 if (error == 0) 2543 error = copyout(pfrtstats, io->pfrio_buffer, totlen); 2544 free(pfrtstats, M_TEMP); 2545 break; 2546 } 2547 2548 case DIOCRCLRTSTATS: { 2549 struct pfioc_table *io = (struct pfioc_table *)addr; 2550 struct pfr_table *pfrts; 2551 size_t totlen; 2552 2553 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2554 error = ENODEV; 2555 break; 2556 } 2557 totlen = io->pfrio_size * sizeof(struct pfr_table); 2558 pfrts = malloc(totlen, M_TEMP, M_WAITOK); 2559 error = copyin(io->pfrio_buffer, pfrts, totlen); 2560 if (error) { 2561 free(pfrts, M_TEMP); 2562 break; 2563 } 2564 PF_RULES_WLOCK(); 2565 error = pfr_clr_tstats(pfrts, io->pfrio_size, 2566 &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2567 PF_RULES_WUNLOCK(); 2568 free(pfrts, M_TEMP); 2569 break; 2570 } 2571 2572 case DIOCRSETTFLAGS: { 2573 struct pfioc_table *io = (struct pfioc_table *)addr; 2574 struct pfr_table *pfrts; 2575 size_t totlen; 2576 2577 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2578 error = ENODEV; 2579 break; 2580 } 2581 totlen = io->pfrio_size * sizeof(struct pfr_table); 2582 pfrts = malloc(totlen, M_TEMP, M_WAITOK); 2583 error = copyin(io->pfrio_buffer, pfrts, totlen); 2584 if (error) { 2585 free(pfrts, M_TEMP); 2586 break; 2587 } 2588 PF_RULES_WLOCK(); 2589 error = pfr_set_tflags(pfrts, io->pfrio_size, 2590 io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange, 2591 &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2592 PF_RULES_WUNLOCK(); 2593 free(pfrts, M_TEMP); 2594 break; 2595 } 2596 2597 case DIOCRCLRADDRS: { 2598 struct pfioc_table *io = (struct pfioc_table *)addr; 2599 2600 if (io->pfrio_esize != 0) { 2601 error = ENODEV; 2602 break; 2603 } 2604 PF_RULES_WLOCK(); 2605 error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel, 2606 io->pfrio_flags | PFR_FLAG_USERIOCTL); 2607 PF_RULES_WUNLOCK(); 2608 break; 2609 } 2610 2611 case DIOCRADDADDRS: { 2612 struct pfioc_table *io = (struct pfioc_table *)addr; 2613 struct pfr_addr *pfras; 2614 size_t totlen; 2615 2616 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2617 error = ENODEV; 2618 break; 2619 } 2620 totlen = io->pfrio_size * sizeof(struct pfr_addr); 2621 pfras = malloc(totlen, M_TEMP, M_WAITOK); 2622 error = copyin(io->pfrio_buffer, pfras, totlen); 2623 if (error) { 2624 free(pfras, M_TEMP); 2625 break; 2626 } 2627 PF_RULES_WLOCK(); 2628 error = pfr_add_addrs(&io->pfrio_table, pfras, 2629 io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags | 2630 PFR_FLAG_USERIOCTL); 2631 PF_RULES_WUNLOCK(); 2632 if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK) 2633 error = copyout(pfras, io->pfrio_buffer, totlen); 2634 free(pfras, M_TEMP); 2635 break; 2636 } 2637 2638 case DIOCRDELADDRS: { 2639 struct pfioc_table *io = (struct pfioc_table *)addr; 2640 struct pfr_addr *pfras; 2641 size_t totlen; 2642 2643 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2644 error = ENODEV; 2645 break; 2646 } 2647 totlen = io->pfrio_size * sizeof(struct pfr_addr); 2648 pfras = malloc(totlen, M_TEMP, M_WAITOK); 2649 error = copyin(io->pfrio_buffer, pfras, totlen); 2650 if (error) { 2651 free(pfras, M_TEMP); 2652 break; 2653 } 2654 PF_RULES_WLOCK(); 2655 error = pfr_del_addrs(&io->pfrio_table, pfras, 2656 io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags | 2657 PFR_FLAG_USERIOCTL); 2658 PF_RULES_WUNLOCK(); 2659 if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK) 2660 error = copyout(pfras, io->pfrio_buffer, totlen); 2661 free(pfras, M_TEMP); 2662 break; 2663 } 2664 2665 case DIOCRSETADDRS: { 2666 struct pfioc_table *io = (struct pfioc_table *)addr; 2667 struct pfr_addr *pfras; 2668 size_t totlen; 2669 2670 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2671 error = ENODEV; 2672 break; 2673 } 2674 totlen = (io->pfrio_size + io->pfrio_size2) * 2675 sizeof(struct pfr_addr); 2676 pfras = malloc(totlen, M_TEMP, M_WAITOK); 2677 error = copyin(io->pfrio_buffer, pfras, totlen); 2678 if (error) { 2679 free(pfras, M_TEMP); 2680 break; 2681 } 2682 PF_RULES_WLOCK(); 2683 error = pfr_set_addrs(&io->pfrio_table, pfras, 2684 io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd, 2685 &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags | 2686 PFR_FLAG_USERIOCTL, 0); 2687 PF_RULES_WUNLOCK(); 2688 if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK) 2689 error = copyout(pfras, io->pfrio_buffer, totlen); 2690 free(pfras, M_TEMP); 2691 break; 2692 } 2693 2694 case DIOCRGETADDRS: { 2695 struct pfioc_table *io = (struct pfioc_table *)addr; 2696 struct pfr_addr *pfras; 2697 size_t totlen; 2698 2699 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2700 error = ENODEV; 2701 break; 2702 } 2703 totlen = io->pfrio_size * sizeof(struct pfr_addr); 2704 pfras = malloc(totlen, M_TEMP, M_WAITOK); 2705 PF_RULES_RLOCK(); 2706 error = pfr_get_addrs(&io->pfrio_table, pfras, 2707 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2708 PF_RULES_RUNLOCK(); 2709 if (error == 0) 2710 error = copyout(pfras, io->pfrio_buffer, totlen); 2711 free(pfras, M_TEMP); 2712 break; 2713 } 2714 2715 case DIOCRGETASTATS: { 2716 struct pfioc_table *io = (struct pfioc_table *)addr; 2717 struct pfr_astats *pfrastats; 2718 size_t totlen; 2719 2720 if (io->pfrio_esize != sizeof(struct pfr_astats)) { 2721 error = ENODEV; 2722 break; 2723 } 2724 totlen = io->pfrio_size * sizeof(struct pfr_astats); 2725 pfrastats = malloc(totlen, M_TEMP, M_WAITOK); 2726 PF_RULES_RLOCK(); 2727 error = pfr_get_astats(&io->pfrio_table, pfrastats, 2728 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2729 PF_RULES_RUNLOCK(); 2730 if (error == 0) 2731 error = copyout(pfrastats, io->pfrio_buffer, totlen); 2732 free(pfrastats, M_TEMP); 2733 break; 2734 } 2735 2736 case DIOCRCLRASTATS: { 2737 struct pfioc_table *io = (struct pfioc_table *)addr; 2738 struct pfr_addr *pfras; 2739 size_t totlen; 2740 2741 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2742 error = ENODEV; 2743 break; 2744 } 2745 totlen = io->pfrio_size * sizeof(struct pfr_addr); 2746 pfras = malloc(totlen, M_TEMP, M_WAITOK); 2747 error = copyin(io->pfrio_buffer, pfras, totlen); 2748 if (error) { 2749 free(pfras, M_TEMP); 2750 break; 2751 } 2752 PF_RULES_WLOCK(); 2753 error = pfr_clr_astats(&io->pfrio_table, pfras, 2754 io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags | 2755 PFR_FLAG_USERIOCTL); 2756 PF_RULES_WUNLOCK(); 2757 if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK) 2758 error = copyout(pfras, io->pfrio_buffer, totlen); 2759 free(pfras, M_TEMP); 2760 break; 2761 } 2762 2763 case DIOCRTSTADDRS: { 2764 struct pfioc_table *io = (struct pfioc_table *)addr; 2765 struct pfr_addr *pfras; 2766 size_t totlen; 2767 2768 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2769 error = ENODEV; 2770 break; 2771 } 2772 totlen = io->pfrio_size * sizeof(struct pfr_addr); 2773 pfras = malloc(totlen, M_TEMP, M_WAITOK); 2774 error = copyin(io->pfrio_buffer, pfras, totlen); 2775 if (error) { 2776 free(pfras, M_TEMP); 2777 break; 2778 } 2779 PF_RULES_RLOCK(); 2780 error = pfr_tst_addrs(&io->pfrio_table, pfras, 2781 io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags | 2782 PFR_FLAG_USERIOCTL); 2783 PF_RULES_RUNLOCK(); 2784 if (error == 0) 2785 error = copyout(pfras, io->pfrio_buffer, totlen); 2786 free(pfras, M_TEMP); 2787 break; 2788 } 2789 2790 case DIOCRINADEFINE: { 2791 struct pfioc_table *io = (struct pfioc_table *)addr; 2792 struct pfr_addr *pfras; 2793 size_t totlen; 2794 2795 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2796 error = ENODEV; 2797 break; 2798 } 2799 totlen = io->pfrio_size * sizeof(struct pfr_addr); 2800 pfras = malloc(totlen, M_TEMP, M_WAITOK); 2801 error = copyin(io->pfrio_buffer, pfras, totlen); 2802 if (error) { 2803 free(pfras, M_TEMP); 2804 break; 2805 } 2806 PF_RULES_WLOCK(); 2807 error = pfr_ina_define(&io->pfrio_table, pfras, 2808 io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr, 2809 io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2810 PF_RULES_WUNLOCK(); 2811 free(pfras, M_TEMP); 2812 break; 2813 } 2814 2815 case DIOCOSFPADD: { 2816 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 2817 PF_RULES_WLOCK(); 2818 error = pf_osfp_add(io); 2819 PF_RULES_WUNLOCK(); 2820 break; 2821 } 2822 2823 case DIOCOSFPGET: { 2824 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 2825 PF_RULES_RLOCK(); 2826 error = pf_osfp_get(io); 2827 PF_RULES_RUNLOCK(); 2828 break; 2829 } 2830 2831 case DIOCXBEGIN: { 2832 struct pfioc_trans *io = (struct pfioc_trans *)addr; 2833 struct pfioc_trans_e *ioes, *ioe; 2834 size_t totlen; 2835 int i; 2836 2837 if (io->esize != sizeof(*ioe)) { 2838 error = ENODEV; 2839 break; 2840 } 2841 totlen = sizeof(struct pfioc_trans_e) * io->size; 2842 ioes = malloc(totlen, M_TEMP, M_WAITOK); 2843 error = copyin(io->array, ioes, totlen); 2844 if (error) { 2845 free(ioes, M_TEMP); 2846 break; 2847 } 2848 PF_RULES_WLOCK(); 2849 for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { 2850 switch (ioe->rs_num) { 2851#ifdef ALTQ 2852 case PF_RULESET_ALTQ: 2853 if (ioe->anchor[0]) { 2854 PF_RULES_WUNLOCK(); 2855 free(ioes, M_TEMP); 2856 error = EINVAL; 2857 goto fail; 2858 } 2859 if ((error = pf_begin_altq(&ioe->ticket))) { 2860 PF_RULES_WUNLOCK(); 2861 free(ioes, M_TEMP); 2862 goto fail; 2863 } 2864 break; 2865#endif /* ALTQ */ 2866 case PF_RULESET_TABLE: 2867 { 2868 struct pfr_table table; 2869 2870 bzero(&table, sizeof(table)); 2871 strlcpy(table.pfrt_anchor, ioe->anchor, 2872 sizeof(table.pfrt_anchor)); 2873 if ((error = pfr_ina_begin(&table, 2874 &ioe->ticket, NULL, 0))) { 2875 PF_RULES_WUNLOCK(); 2876 free(ioes, M_TEMP); 2877 goto fail; 2878 } 2879 break; 2880 } 2881 default: 2882 if ((error = pf_begin_rules(&ioe->ticket, 2883 ioe->rs_num, ioe->anchor))) { 2884 PF_RULES_WUNLOCK(); 2885 free(ioes, M_TEMP); 2886 goto fail; 2887 } 2888 break; 2889 } 2890 } 2891 PF_RULES_WUNLOCK(); 2892 error = copyout(ioes, io->array, totlen); 2893 free(ioes, M_TEMP); 2894 break; 2895 } 2896 2897 case DIOCXROLLBACK: { 2898 struct pfioc_trans *io = (struct pfioc_trans *)addr; 2899 struct pfioc_trans_e *ioe, *ioes; 2900 size_t totlen; 2901 int i; 2902 2903 if (io->esize != sizeof(*ioe)) { 2904 error = ENODEV; 2905 break; 2906 } 2907 totlen = sizeof(struct pfioc_trans_e) * io->size; 2908 ioes = malloc(totlen, M_TEMP, M_WAITOK); 2909 error = copyin(io->array, ioes, totlen); 2910 if (error) { 2911 free(ioes, M_TEMP); 2912 break; 2913 } 2914 PF_RULES_WLOCK(); 2915 for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { 2916 switch (ioe->rs_num) { 2917#ifdef ALTQ 2918 case PF_RULESET_ALTQ: 2919 if (ioe->anchor[0]) { 2920 PF_RULES_WUNLOCK(); 2921 free(ioes, M_TEMP); 2922 error = EINVAL; 2923 goto fail; 2924 } 2925 if ((error = pf_rollback_altq(ioe->ticket))) { 2926 PF_RULES_WUNLOCK(); 2927 free(ioes, M_TEMP); 2928 goto fail; /* really bad */ 2929 } 2930 break; 2931#endif /* ALTQ */ 2932 case PF_RULESET_TABLE: 2933 { 2934 struct pfr_table table; 2935 2936 bzero(&table, sizeof(table)); 2937 strlcpy(table.pfrt_anchor, ioe->anchor, 2938 sizeof(table.pfrt_anchor)); 2939 if ((error = pfr_ina_rollback(&table, 2940 ioe->ticket, NULL, 0))) { 2941 PF_RULES_WUNLOCK(); 2942 free(ioes, M_TEMP); 2943 goto fail; /* really bad */ 2944 } 2945 break; 2946 } 2947 default: 2948 if ((error = pf_rollback_rules(ioe->ticket, 2949 ioe->rs_num, ioe->anchor))) { 2950 PF_RULES_WUNLOCK(); 2951 free(ioes, M_TEMP); 2952 goto fail; /* really bad */ 2953 } 2954 break; 2955 } 2956 } 2957 PF_RULES_WUNLOCK(); 2958 free(ioes, M_TEMP); 2959 break; 2960 } 2961 2962 case DIOCXCOMMIT: { 2963 struct pfioc_trans *io = (struct pfioc_trans *)addr; 2964 struct pfioc_trans_e *ioe, *ioes; 2965 struct pf_ruleset *rs; 2966 size_t totlen; 2967 int i; 2968 2969 if (io->esize != sizeof(*ioe)) { 2970 error = ENODEV; 2971 break; 2972 } 2973 totlen = sizeof(struct pfioc_trans_e) * io->size; 2974 ioes = malloc(totlen, M_TEMP, M_WAITOK); 2975 error = copyin(io->array, ioes, totlen); 2976 if (error) { 2977 free(ioes, M_TEMP); 2978 break; 2979 } 2980 PF_RULES_WLOCK(); 2981 /* First makes sure everything will succeed. */ 2982 for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { 2983 switch (ioe->rs_num) { 2984#ifdef ALTQ 2985 case PF_RULESET_ALTQ: 2986 if (ioe->anchor[0]) { 2987 PF_RULES_WUNLOCK(); 2988 free(ioes, M_TEMP); 2989 error = EINVAL; 2990 goto fail; 2991 } 2992 if (!V_altqs_inactive_open || ioe->ticket != 2993 V_ticket_altqs_inactive) { 2994 PF_RULES_WUNLOCK(); 2995 free(ioes, M_TEMP); 2996 error = EBUSY; 2997 goto fail; 2998 } 2999 break; 3000#endif /* ALTQ */ 3001 case PF_RULESET_TABLE: 3002 rs = pf_find_ruleset(ioe->anchor); 3003 if (rs == NULL || !rs->topen || ioe->ticket != 3004 rs->tticket) { 3005 PF_RULES_WUNLOCK(); 3006 free(ioes, M_TEMP); 3007 error = EBUSY; 3008 goto fail; 3009 } 3010 break; 3011 default: 3012 if (ioe->rs_num < 0 || ioe->rs_num >= 3013 PF_RULESET_MAX) { 3014 PF_RULES_WUNLOCK(); 3015 free(ioes, M_TEMP); 3016 error = EINVAL; 3017 goto fail; 3018 } 3019 rs = pf_find_ruleset(ioe->anchor); 3020 if (rs == NULL || 3021 !rs->rules[ioe->rs_num].inactive.open || 3022 rs->rules[ioe->rs_num].inactive.ticket != 3023 ioe->ticket) { 3024 PF_RULES_WUNLOCK(); 3025 free(ioes, M_TEMP); 3026 error = EBUSY; 3027 goto fail; 3028 } 3029 break; 3030 } 3031 } 3032 /* Now do the commit - no errors should happen here. */ 3033 for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { 3034 switch (ioe->rs_num) { 3035#ifdef ALTQ 3036 case PF_RULESET_ALTQ: 3037 if ((error = pf_commit_altq(ioe->ticket))) { 3038 PF_RULES_WUNLOCK(); 3039 free(ioes, M_TEMP); 3040 goto fail; /* really bad */ 3041 } 3042 break; 3043#endif /* ALTQ */ 3044 case PF_RULESET_TABLE: 3045 { 3046 struct pfr_table table; 3047 3048 bzero(&table, sizeof(table)); 3049 strlcpy(table.pfrt_anchor, ioe->anchor, 3050 sizeof(table.pfrt_anchor)); 3051 if ((error = pfr_ina_commit(&table, 3052 ioe->ticket, NULL, NULL, 0))) { 3053 PF_RULES_WUNLOCK(); 3054 free(ioes, M_TEMP); 3055 goto fail; /* really bad */ 3056 } 3057 break; 3058 } 3059 default: 3060 if ((error = pf_commit_rules(ioe->ticket, 3061 ioe->rs_num, ioe->anchor))) { 3062 PF_RULES_WUNLOCK(); 3063 free(ioes, M_TEMP); 3064 goto fail; /* really bad */ 3065 } 3066 break; 3067 } 3068 } 3069 PF_RULES_WUNLOCK(); 3070 free(ioes, M_TEMP); 3071 break; 3072 } 3073 3074 case DIOCGETSRCNODES: { 3075 struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr; 3076 struct pf_srchash *sh; 3077 struct pf_src_node *n, *p, *pstore; 3078 uint32_t i, nr = 0; 3079 3080 if (psn->psn_len == 0) { 3081 for (i = 0, sh = V_pf_srchash; i <= V_pf_srchashmask; 3082 i++, sh++) { 3083 PF_HASHROW_LOCK(sh); 3084 LIST_FOREACH(n, &sh->nodes, entry) 3085 nr++; 3086 PF_HASHROW_UNLOCK(sh); 3087 } 3088 psn->psn_len = sizeof(struct pf_src_node) * nr; 3089 break; 3090 } 3091 3092 p = pstore = malloc(psn->psn_len, M_TEMP, M_WAITOK); 3093 for (i = 0, sh = V_pf_srchash; i <= V_pf_srchashmask; 3094 i++, sh++) { 3095 PF_HASHROW_LOCK(sh); 3096 LIST_FOREACH(n, &sh->nodes, entry) { 3097 int secs = time_uptime, diff; 3098 3099 if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len) 3100 break; 3101 3102 bcopy(n, p, sizeof(struct pf_src_node)); 3103 if (n->rule.ptr != NULL) 3104 p->rule.nr = n->rule.ptr->nr; 3105 p->creation = secs - p->creation; 3106 if (p->expire > secs) 3107 p->expire -= secs; 3108 else 3109 p->expire = 0; 3110 3111 /* Adjust the connection rate estimate. */ 3112 diff = secs - n->conn_rate.last; 3113 if (diff >= n->conn_rate.seconds) 3114 p->conn_rate.count = 0; 3115 else 3116 p->conn_rate.count -= 3117 n->conn_rate.count * diff / 3118 n->conn_rate.seconds; 3119 p++; 3120 nr++; 3121 } 3122 PF_HASHROW_UNLOCK(sh); 3123 } 3124 error = copyout(pstore, psn->psn_src_nodes, 3125 sizeof(struct pf_src_node) * nr); 3126 if (error) { 3127 free(pstore, M_TEMP); 3128 break; 3129 } 3130 psn->psn_len = sizeof(struct pf_src_node) * nr; 3131 free(pstore, M_TEMP); 3132 break; 3133 } 3134 3135 case DIOCCLRSRCNODES: { 3136 3137 pf_clear_srcnodes(NULL); 3138 pf_purge_expired_src_nodes(); 3139 V_pf_status.src_nodes = 0; 3140 break; 3141 } 3142 3143 case DIOCKILLSRCNODES: 3144 pf_kill_srcnodes((struct pfioc_src_node_kill *)addr); 3145 break; 3146 3147 case DIOCSETHOSTID: { 3148 u_int32_t *hostid = (u_int32_t *)addr; 3149 3150 PF_RULES_WLOCK(); 3151 if (*hostid == 0) 3152 V_pf_status.hostid = arc4random(); 3153 else 3154 V_pf_status.hostid = *hostid; 3155 PF_RULES_WUNLOCK(); 3156 break; 3157 } 3158 3159 case DIOCOSFPFLUSH: 3160 PF_RULES_WLOCK(); 3161 pf_osfp_flush(); 3162 PF_RULES_WUNLOCK(); 3163 break; 3164 3165 case DIOCIGETIFACES: { 3166 struct pfioc_iface *io = (struct pfioc_iface *)addr; 3167 struct pfi_kif *ifstore; 3168 size_t bufsiz; 3169 3170 if (io->pfiio_esize != sizeof(struct pfi_kif)) { 3171 error = ENODEV; 3172 break; 3173 } 3174 3175 bufsiz = io->pfiio_size * sizeof(struct pfi_kif); 3176 ifstore = malloc(bufsiz, M_TEMP, M_WAITOK); 3177 PF_RULES_RLOCK(); 3178 pfi_get_ifaces(io->pfiio_name, ifstore, &io->pfiio_size); 3179 PF_RULES_RUNLOCK(); 3180 error = copyout(ifstore, io->pfiio_buffer, bufsiz); 3181 free(ifstore, M_TEMP); 3182 break; 3183 } 3184 3185 case DIOCSETIFFLAG: { 3186 struct pfioc_iface *io = (struct pfioc_iface *)addr; 3187 3188 PF_RULES_WLOCK(); 3189 error = pfi_set_flags(io->pfiio_name, io->pfiio_flags); 3190 PF_RULES_WUNLOCK(); 3191 break; 3192 } 3193 3194 case DIOCCLRIFFLAG: { 3195 struct pfioc_iface *io = (struct pfioc_iface *)addr; 3196 3197 PF_RULES_WLOCK(); 3198 error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags); 3199 PF_RULES_WUNLOCK(); 3200 break; 3201 } 3202 3203 default: 3204 error = ENODEV; 3205 break; 3206 } 3207fail: 3208 CURVNET_RESTORE(); 3209 3210 return (error); 3211} 3212 3213void 3214pfsync_state_export(struct pfsync_state *sp, struct pf_state *st) 3215{ 3216 bzero(sp, sizeof(struct pfsync_state)); 3217 3218 /* copy from state key */ 3219 sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0]; 3220 sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1]; 3221 sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0]; 3222 sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1]; 3223 sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0]; 3224 sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1]; 3225 sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; 3226 sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; 3227 sp->proto = st->key[PF_SK_WIRE]->proto; 3228 sp->af = st->key[PF_SK_WIRE]->af; 3229 3230 /* copy from state */ 3231 strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); 3232 bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 3233 sp->creation = htonl(time_uptime - st->creation); 3234 sp->expire = pf_state_expires(st); 3235 if (sp->expire <= time_uptime) 3236 sp->expire = htonl(0); 3237 else 3238 sp->expire = htonl(sp->expire - time_uptime); 3239 3240 sp->direction = st->direction; 3241 sp->log = st->log; 3242 sp->timeout = st->timeout; 3243 sp->state_flags = st->state_flags; 3244 if (st->src_node) 3245 sp->sync_flags |= PFSYNC_FLAG_SRCNODE; 3246 if (st->nat_src_node) 3247 sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; 3248 3249 sp->id = st->id; 3250 sp->creatorid = st->creatorid; 3251 pf_state_peer_hton(&st->src, &sp->src); 3252 pf_state_peer_hton(&st->dst, &sp->dst); 3253 3254 if (st->rule.ptr == NULL) 3255 sp->rule = htonl(-1); 3256 else 3257 sp->rule = htonl(st->rule.ptr->nr); 3258 if (st->anchor.ptr == NULL) 3259 sp->anchor = htonl(-1); 3260 else 3261 sp->anchor = htonl(st->anchor.ptr->nr); 3262 if (st->nat_rule.ptr == NULL) 3263 sp->nat_rule = htonl(-1); 3264 else 3265 sp->nat_rule = htonl(st->nat_rule.ptr->nr); 3266 3267 pf_state_counter_hton(st->packets[0], sp->packets[0]); 3268 pf_state_counter_hton(st->packets[1], sp->packets[1]); 3269 pf_state_counter_hton(st->bytes[0], sp->bytes[0]); 3270 pf_state_counter_hton(st->bytes[1], sp->bytes[1]); 3271 3272} 3273 3274static void 3275pf_tbladdr_copyout(struct pf_addr_wrap *aw) 3276{ 3277 struct pfr_ktable *kt; 3278 3279 KASSERT(aw->type == PF_ADDR_TABLE, ("%s: type %u", __func__, aw->type)); 3280 3281 kt = aw->p.tbl; 3282 if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 3283 kt = kt->pfrkt_root; 3284 aw->p.tbl = NULL; 3285 aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ? 3286 kt->pfrkt_cnt : -1; 3287} 3288 3289/* 3290 * XXX - Check for version missmatch!!! 3291 */ 3292static void 3293pf_clear_states(void) 3294{ 3295 struct pf_state *s; 3296 u_int i; 3297 3298 for (i = 0; i <= V_pf_hashmask; i++) { 3299 struct pf_idhash *ih = &V_pf_idhash[i]; 3300relock: 3301 PF_HASHROW_LOCK(ih); 3302 LIST_FOREACH(s, &ih->states, entry) { 3303 s->timeout = PFTM_PURGE; 3304 /* Don't send out individual delete messages. */ 3305 s->sync_state = PFSTATE_NOSYNC; 3306 pf_unlink_state(s, PF_ENTER_LOCKED); 3307 goto relock; 3308 } 3309 PF_HASHROW_UNLOCK(ih); 3310 } 3311} 3312 3313static int 3314pf_clear_tables(void) 3315{ 3316 struct pfioc_table io; 3317 int error; 3318 3319 bzero(&io, sizeof(io)); 3320 3321 error = pfr_clr_tables(&io.pfrio_table, &io.pfrio_ndel, 3322 io.pfrio_flags); 3323 3324 return (error); 3325} 3326 3327static void 3328pf_clear_srcnodes(struct pf_src_node *n) 3329{ 3330 struct pf_state *s; 3331 int i; 3332 3333 for (i = 0; i <= V_pf_hashmask; i++) { 3334 struct pf_idhash *ih = &V_pf_idhash[i]; 3335 3336 PF_HASHROW_LOCK(ih); 3337 LIST_FOREACH(s, &ih->states, entry) { 3338 if (n == NULL || n == s->src_node) 3339 s->src_node = NULL; 3340 if (n == NULL || n == s->nat_src_node) 3341 s->nat_src_node = NULL; 3342 } 3343 PF_HASHROW_UNLOCK(ih); 3344 } 3345 3346 if (n == NULL) { 3347 struct pf_srchash *sh; 3348 3349 for (i = 0, sh = V_pf_srchash; i <= V_pf_srchashmask; 3350 i++, sh++) { 3351 PF_HASHROW_LOCK(sh); 3352 LIST_FOREACH(n, &sh->nodes, entry) { 3353 n->expire = 1; 3354 n->states = 0; 3355 } 3356 PF_HASHROW_UNLOCK(sh); 3357 } 3358 } else { 3359 /* XXX: hash slot should already be locked here. */ 3360 n->expire = 1; 3361 n->states = 0; 3362 } 3363} 3364 3365static void 3366pf_kill_srcnodes(struct pfioc_src_node_kill *psnk) 3367{ 3368 struct pf_src_node_list kill; 3369 3370 LIST_INIT(&kill); 3371 for (int i = 0; i <= V_pf_srchashmask; i++) { 3372 struct pf_srchash *sh = &V_pf_srchash[i]; 3373 struct pf_src_node *sn, *tmp; 3374 3375 PF_HASHROW_LOCK(sh); 3376 LIST_FOREACH_SAFE(sn, &sh->nodes, entry, tmp) 3377 if (PF_MATCHA(psnk->psnk_src.neg, 3378 &psnk->psnk_src.addr.v.a.addr, 3379 &psnk->psnk_src.addr.v.a.mask, 3380 &sn->addr, sn->af) && 3381 PF_MATCHA(psnk->psnk_dst.neg, 3382 &psnk->psnk_dst.addr.v.a.addr, 3383 &psnk->psnk_dst.addr.v.a.mask, 3384 &sn->raddr, sn->af)) { 3385 pf_unlink_src_node_locked(sn); 3386 LIST_INSERT_HEAD(&kill, sn, entry); 3387 sn->expire = 1; 3388 } 3389 PF_HASHROW_UNLOCK(sh); 3390 } 3391 3392 for (int i = 0; i <= V_pf_hashmask; i++) { 3393 struct pf_idhash *ih = &V_pf_idhash[i]; 3394 struct pf_state *s; 3395 3396 PF_HASHROW_LOCK(ih); 3397 LIST_FOREACH(s, &ih->states, entry) { 3398 if (s->src_node && s->src_node->expire == 1) { 3399#ifdef INVARIANTS 3400 s->src_node->states--; 3401#endif 3402 s->src_node = NULL; 3403 } 3404 if (s->nat_src_node && s->nat_src_node->expire == 1) { 3405#ifdef INVARIANTS 3406 s->nat_src_node->states--; 3407#endif 3408 s->nat_src_node = NULL; 3409 } 3410 } 3411 PF_HASHROW_UNLOCK(ih); 3412 } 3413 3414 psnk->psnk_killed = pf_free_src_nodes(&kill); 3415} 3416 3417/* 3418 * XXX - Check for version missmatch!!! 3419 */ 3420 3421/* 3422 * Duplicate pfctl -Fa operation to get rid of as much as we can. 3423 */ 3424static int 3425shutdown_pf(void) 3426{ 3427 int error = 0; 3428 u_int32_t t[5]; 3429 char nn = '\0'; 3430 3431 V_pf_status.running = 0; 3432 do { 3433 if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn)) 3434 != 0) { 3435 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: SCRUB\n")); 3436 break; 3437 } 3438 if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn)) 3439 != 0) { 3440 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: FILTER\n")); 3441 break; /* XXX: rollback? */ 3442 } 3443 if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn)) 3444 != 0) { 3445 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: NAT\n")); 3446 break; /* XXX: rollback? */ 3447 } 3448 if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn)) 3449 != 0) { 3450 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: BINAT\n")); 3451 break; /* XXX: rollback? */ 3452 } 3453 if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn)) 3454 != 0) { 3455 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: RDR\n")); 3456 break; /* XXX: rollback? */ 3457 } 3458 3459 /* XXX: these should always succeed here */ 3460 pf_commit_rules(t[0], PF_RULESET_SCRUB, &nn); 3461 pf_commit_rules(t[1], PF_RULESET_FILTER, &nn); 3462 pf_commit_rules(t[2], PF_RULESET_NAT, &nn); 3463 pf_commit_rules(t[3], PF_RULESET_BINAT, &nn); 3464 pf_commit_rules(t[4], PF_RULESET_RDR, &nn); 3465 3466 if ((error = pf_clear_tables()) != 0) 3467 break; 3468 3469#ifdef ALTQ 3470 if ((error = pf_begin_altq(&t[0])) != 0) { 3471 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n")); 3472 break; 3473 } 3474 pf_commit_altq(t[0]); 3475#endif 3476 3477 pf_clear_states(); 3478 3479 pf_clear_srcnodes(NULL); 3480 3481 /* status does not use malloced mem so no need to cleanup */ 3482 /* fingerprints and interfaces have thier own cleanup code */ 3483 } while(0); 3484 3485 return (error); 3486} 3487 3488#ifdef INET 3489static int 3490pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 3491 struct inpcb *inp) 3492{ 3493 int chk; 3494 3495 chk = pf_test(PF_IN, ifp, m, inp); 3496 if (chk && *m) { 3497 m_freem(*m); 3498 *m = NULL; 3499 } 3500 3501 return (chk); 3502} 3503 3504static int 3505pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 3506 struct inpcb *inp) 3507{ 3508 int chk; 3509 3510 /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */ 3511 if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 3512 in_delayed_cksum(*m); 3513 (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 3514 } 3515 3516 chk = pf_test(PF_OUT, ifp, m, inp); 3517 if (chk && *m) { 3518 m_freem(*m); 3519 *m = NULL; 3520 } 3521 3522 return (chk); 3523} 3524#endif 3525 3526#ifdef INET6 3527static int 3528pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 3529 struct inpcb *inp) 3530{ 3531 int chk; 3532 3533 /* 3534 * In case of loopback traffic IPv6 uses the real interface in 3535 * order to support scoped addresses. In order to support stateful 3536 * filtering we have change this to lo0 as it is the case in IPv4. 3537 */ 3538 CURVNET_SET(ifp->if_vnet); 3539 chk = pf_test6(PF_IN, (*m)->m_flags & M_LOOP ? V_loif : ifp, m, inp); 3540 CURVNET_RESTORE(); 3541 if (chk && *m) { 3542 m_freem(*m); 3543 *m = NULL; 3544 } 3545 return chk; 3546} 3547 3548static int 3549pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, 3550 struct inpcb *inp) 3551{ 3552 int chk; 3553 3554 /* We need a proper CSUM before we start (s. OpenBSD ip_output) */ 3555 if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 3556#ifdef INET 3557 /* XXX-BZ copy&paste error from r126261? */ 3558 in_delayed_cksum(*m); 3559#endif 3560 (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 3561 } 3562 CURVNET_SET(ifp->if_vnet); 3563 chk = pf_test6(PF_OUT, ifp, m, inp); 3564 CURVNET_RESTORE(); 3565 if (chk && *m) { 3566 m_freem(*m); 3567 *m = NULL; 3568 } 3569 return chk; 3570} 3571#endif /* INET6 */ 3572 3573static int 3574hook_pf(void) 3575{ 3576#ifdef INET 3577 struct pfil_head *pfh_inet; 3578#endif 3579#ifdef INET6 3580 struct pfil_head *pfh_inet6; 3581#endif 3582 3583 if (V_pf_pfil_hooked) 3584 return (0); 3585 3586#ifdef INET 3587 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 3588 if (pfh_inet == NULL) 3589 return (ESRCH); /* XXX */ 3590 pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); 3591 pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); 3592#endif 3593#ifdef INET6 3594 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 3595 if (pfh_inet6 == NULL) { 3596#ifdef INET 3597 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, 3598 pfh_inet); 3599 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 3600 pfh_inet); 3601#endif 3602 return (ESRCH); /* XXX */ 3603 } 3604 pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); 3605 pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); 3606#endif 3607 3608 V_pf_pfil_hooked = 1; 3609 return (0); 3610} 3611 3612static int 3613dehook_pf(void) 3614{ 3615#ifdef INET 3616 struct pfil_head *pfh_inet; 3617#endif 3618#ifdef INET6 3619 struct pfil_head *pfh_inet6; 3620#endif 3621 3622 if (V_pf_pfil_hooked == 0) 3623 return (0); 3624 3625#ifdef INET 3626 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 3627 if (pfh_inet == NULL) 3628 return (ESRCH); /* XXX */ 3629 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, 3630 pfh_inet); 3631 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 3632 pfh_inet); 3633#endif 3634#ifdef INET6 3635 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 3636 if (pfh_inet6 == NULL) 3637 return (ESRCH); /* XXX */ 3638 pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, 3639 pfh_inet6); 3640 pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, 3641 pfh_inet6); 3642#endif 3643 3644 V_pf_pfil_hooked = 0; 3645 return (0); 3646} 3647 3648static int 3649pf_load(void) 3650{ 3651 int error; 3652 3653 VNET_ITERATOR_DECL(vnet_iter); 3654 3655 VNET_LIST_RLOCK(); 3656 VNET_FOREACH(vnet_iter) { 3657 CURVNET_SET(vnet_iter); 3658 V_pf_pfil_hooked = 0; 3659 V_pf_end_threads = 0; 3660 TAILQ_INIT(&V_pf_tags); 3661 TAILQ_INIT(&V_pf_qids); 3662 CURVNET_RESTORE(); 3663 } 3664 VNET_LIST_RUNLOCK(); 3665 3666 rw_init(&pf_rules_lock, "pf rulesets"); 3667 3668 pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME); 3669 if ((error = pfattach()) != 0) 3670 return (error); 3671 3672 return (0); 3673} 3674 3675static int 3676pf_unload(void) 3677{ 3678 int error = 0; 3679 3680 PF_RULES_WLOCK(); 3681 V_pf_status.running = 0; 3682 PF_RULES_WUNLOCK(); 3683 swi_remove(V_pf_swi_cookie); 3684 error = dehook_pf(); 3685 if (error) { 3686 /* 3687 * Should not happen! 3688 * XXX Due to error code ESRCH, kldunload will show 3689 * a message like 'No such process'. 3690 */ 3691 printf("%s : pfil unregisteration fail\n", __FUNCTION__); 3692 return error; 3693 } 3694 PF_RULES_WLOCK(); 3695 shutdown_pf(); 3696 V_pf_end_threads = 1; 3697 while (V_pf_end_threads < 2) { 3698 wakeup_one(pf_purge_thread); 3699 rw_sleep(pf_purge_thread, &pf_rules_lock, 0, "pftmo", 0); 3700 } 3701 pf_normalize_cleanup(); 3702 pfi_cleanup(); 3703 pfr_cleanup(); 3704 pf_osfp_flush(); 3705 pf_cleanup(); 3706 PF_RULES_WUNLOCK(); 3707 destroy_dev(pf_dev); 3708 rw_destroy(&pf_rules_lock); 3709 3710 return (error); 3711} 3712 3713static int 3714pf_modevent(module_t mod, int type, void *data) 3715{ 3716 int error = 0; 3717 3718 switch(type) { 3719 case MOD_LOAD: 3720 error = pf_load(); 3721 break; 3722 case MOD_QUIESCE: 3723 /* 3724 * Module should not be unloaded due to race conditions. 3725 */ 3726 error = EBUSY; 3727 break; 3728 case MOD_UNLOAD: 3729 error = pf_unload(); 3730 break; 3731 default: 3732 error = EINVAL; 3733 break; 3734 } 3735 3736 return (error); 3737} 3738 3739static moduledata_t pf_mod = { 3740 "pf", 3741 pf_modevent, 3742 0 3743}; 3744 3745DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_FIRST); 3746MODULE_VERSION(pf, PF_MODVER); 3747