1223637Sbz/* $OpenBSD: pf_table.c,v 1.79 2008/10/08 06:24:50 mcbride Exp $ */ 2126258Smlaier 3126258Smlaier/* 4126258Smlaier * Copyright (c) 2002 Cedric Berger 5126258Smlaier * All rights reserved. 6126258Smlaier * 7126258Smlaier * Redistribution and use in source and binary forms, with or without 8126258Smlaier * modification, are permitted provided that the following conditions 9126258Smlaier * are met: 10126258Smlaier * 11126258Smlaier * - Redistributions of source code must retain the above copyright 12126258Smlaier * notice, this list of conditions and the following disclaimer. 13126258Smlaier * - Redistributions in binary form must reproduce the above 14126258Smlaier * copyright notice, this list of conditions and the following 15126258Smlaier * disclaimer in the documentation and/or other materials provided 16126258Smlaier * with the distribution. 17126258Smlaier * 18126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19126258Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20126258Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21126258Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22126258Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23126258Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24126258Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25126258Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26126258Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27126258Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28126258Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29126258Smlaier * POSSIBILITY OF SUCH DAMAGE. 30126258Smlaier * 31126258Smlaier */ 32126258Smlaier 33127145Smlaier#ifdef __FreeBSD__ 34126261Smlaier#include "opt_inet.h" 35126261Smlaier#include "opt_inet6.h" 36171168Smlaier 37171168Smlaier#include <sys/cdefs.h> 38171168Smlaier__FBSDID("$FreeBSD$"); 39126261Smlaier#endif 40126261Smlaier 41126258Smlaier#include <sys/param.h> 42126258Smlaier#include <sys/systm.h> 43126258Smlaier#include <sys/socket.h> 44126258Smlaier#include <sys/mbuf.h> 45126258Smlaier#include <sys/kernel.h> 46127145Smlaier#ifdef __FreeBSD__ 47126261Smlaier#include <sys/malloc.h> 48223637Sbz#else 49223637Sbz#include <sys/pool.h> 50126261Smlaier#endif 51126258Smlaier 52126258Smlaier#include <net/if.h> 53126258Smlaier#include <net/route.h> 54126258Smlaier#include <netinet/in.h> 55127145Smlaier#ifndef __FreeBSD__ 56126258Smlaier#include <netinet/ip_ipsp.h> 57126261Smlaier#endif 58126258Smlaier#include <net/pfvar.h> 59126258Smlaier 60223637Sbz#define ACCEPT_FLAGS(flags, oklist) \ 61126258Smlaier do { \ 62126258Smlaier if ((flags & ~(oklist)) & \ 63126258Smlaier PFR_FLAG_ALLMASK) \ 64126258Smlaier return (EINVAL); \ 65126258Smlaier } while (0) 66126258Smlaier 67130613Smlaier#ifdef __FreeBSD__ 68130613Smlaierstatic inline int 69130613Smlaier_copyin(const void *uaddr, void *kaddr, size_t len) 70130613Smlaier{ 71130613Smlaier int r; 72130613Smlaier 73130613Smlaier PF_UNLOCK(); 74130613Smlaier r = copyin(uaddr, kaddr, len); 75130613Smlaier PF_LOCK(); 76130613Smlaier 77130613Smlaier return (r); 78130613Smlaier} 79130613Smlaier 80130613Smlaierstatic inline int 81130613Smlaier_copyout(const void *uaddr, void *kaddr, size_t len) 82130613Smlaier{ 83130613Smlaier int r; 84130613Smlaier 85130613Smlaier PF_UNLOCK(); 86130613Smlaier r = copyout(uaddr, kaddr, len); 87130613Smlaier PF_LOCK(); 88130613Smlaier 89130613Smlaier return (r); 90130613Smlaier} 91130613Smlaier 92223637Sbz#define COPYIN(from, to, size, flags) \ 93130613Smlaier ((flags & PFR_FLAG_USERIOCTL) ? \ 94130613Smlaier _copyin((from), (to), (size)) : \ 95130613Smlaier (bcopy((from), (to), (size)), 0)) 96130613Smlaier 97223637Sbz#define COPYOUT(from, to, size, flags) \ 98130613Smlaier ((flags & PFR_FLAG_USERIOCTL) ? \ 99130613Smlaier _copyout((from), (to), (size)) : \ 100130613Smlaier (bcopy((from), (to), (size)), 0)) 101130613Smlaier 102130613Smlaier#else 103223637Sbz#define COPYIN(from, to, size, flags) \ 104130613Smlaier ((flags & PFR_FLAG_USERIOCTL) ? \ 105130613Smlaier copyin((from), (to), (size)) : \ 106130613Smlaier (bcopy((from), (to), (size)), 0)) 107130613Smlaier 108223637Sbz#define COPYOUT(from, to, size, flags) \ 109130613Smlaier ((flags & PFR_FLAG_USERIOCTL) ? \ 110130613Smlaier copyout((from), (to), (size)) : \ 111130613Smlaier (bcopy((from), (to), (size)), 0)) 112130613Smlaier#endif 113130613Smlaier 114126258Smlaier#define FILLIN_SIN(sin, addr) \ 115126258Smlaier do { \ 116126258Smlaier (sin).sin_len = sizeof(sin); \ 117126258Smlaier (sin).sin_family = AF_INET; \ 118126258Smlaier (sin).sin_addr = (addr); \ 119126258Smlaier } while (0) 120126258Smlaier 121126258Smlaier#define FILLIN_SIN6(sin6, addr) \ 122126258Smlaier do { \ 123126258Smlaier (sin6).sin6_len = sizeof(sin6); \ 124126258Smlaier (sin6).sin6_family = AF_INET6; \ 125126258Smlaier (sin6).sin6_addr = (addr); \ 126126258Smlaier } while (0) 127126258Smlaier 128223637Sbz#define SWAP(type, a1, a2) \ 129126258Smlaier do { \ 130126258Smlaier type tmp = a1; \ 131126258Smlaier a1 = a2; \ 132126258Smlaier a2 = tmp; \ 133126258Smlaier } while (0) 134126258Smlaier 135223637Sbz#define SUNION2PF(su, af) (((af)==AF_INET) ? \ 136130613Smlaier (struct pf_addr *)&(su)->sin.sin_addr : \ 137130613Smlaier (struct pf_addr *)&(su)->sin6.sin6_addr) 138126258Smlaier 139126258Smlaier#define AF_BITS(af) (((af)==AF_INET)?32:128) 140126258Smlaier#define ADDR_NETWORK(ad) ((ad)->pfra_net < AF_BITS((ad)->pfra_af)) 141126258Smlaier#define KENTRY_NETWORK(ke) ((ke)->pfrke_net < AF_BITS((ke)->pfrke_af)) 142223637Sbz#define KENTRY_RNF_ROOT(ke) \ 143126258Smlaier ((((struct radix_node *)(ke))->rn_flags & RNF_ROOT) != 0) 144126258Smlaier 145223637Sbz#define NO_ADDRESSES (-1) 146223637Sbz#define ENQUEUE_UNMARKED_ONLY (1) 147223637Sbz#define INVERT_NEG_FLAG (1) 148126258Smlaier 149126258Smlaierstruct pfr_walktree { 150126258Smlaier enum pfrw_op { 151126258Smlaier PFRW_MARK, 152126258Smlaier PFRW_SWEEP, 153126258Smlaier PFRW_ENQUEUE, 154126258Smlaier PFRW_GET_ADDRS, 155126258Smlaier PFRW_GET_ASTATS, 156130613Smlaier PFRW_POOL_GET, 157130613Smlaier PFRW_DYNADDR_UPDATE 158126258Smlaier } pfrw_op; 159126258Smlaier union { 160126258Smlaier struct pfr_addr *pfrw1_addr; 161126258Smlaier struct pfr_astats *pfrw1_astats; 162126258Smlaier struct pfr_kentryworkq *pfrw1_workq; 163126258Smlaier struct pfr_kentry *pfrw1_kentry; 164130613Smlaier struct pfi_dynaddr *pfrw1_dyn; 165126258Smlaier } pfrw_1; 166126258Smlaier int pfrw_free; 167130613Smlaier int pfrw_flags; 168126258Smlaier}; 169223637Sbz#define pfrw_addr pfrw_1.pfrw1_addr 170223637Sbz#define pfrw_astats pfrw_1.pfrw1_astats 171223637Sbz#define pfrw_workq pfrw_1.pfrw1_workq 172223637Sbz#define pfrw_kentry pfrw_1.pfrw1_kentry 173223637Sbz#define pfrw_dyn pfrw_1.pfrw1_dyn 174223637Sbz#define pfrw_cnt pfrw_free 175126258Smlaier 176223637Sbz#define senderr(e) do { rv = (e); goto _bad; } while (0) 177126258Smlaier 178127145Smlaier#ifdef __FreeBSD__ 179223637SbzVNET_DEFINE(uma_zone_t, pfr_ktable_pl); 180223637SbzVNET_DEFINE(uma_zone_t, pfr_kentry_pl); 181223637SbzVNET_DEFINE(uma_zone_t, pfr_kcounters_pl); 182223637SbzVNET_DEFINE(struct sockaddr_in, pfr_sin); 183223637Sbz#define V_pfr_sin VNET(pfr_sin) 184223637SbzVNET_DEFINE(struct sockaddr_in6, pfr_sin6); 185223637Sbz#define V_pfr_sin6 VNET(pfr_sin6) 186223637SbzVNET_DEFINE(union sockaddr_union, pfr_mask); 187223637Sbz#define V_pfr_mask VNET(pfr_mask) 188223637SbzVNET_DEFINE(struct pf_addr, pfr_ffaddr); 189223637Sbz#define V_pfr_ffaddr VNET(pfr_ffaddr) 190126261Smlaier#else 191126258Smlaierstruct pool pfr_ktable_pl; 192126258Smlaierstruct pool pfr_kentry_pl; 193223637Sbzstruct pool pfr_kcounters_pl; 194126258Smlaierstruct sockaddr_in pfr_sin; 195126258Smlaierstruct sockaddr_in6 pfr_sin6; 196130613Smlaierunion sockaddr_union pfr_mask; 197126258Smlaierstruct pf_addr pfr_ffaddr; 198223637Sbz#endif 199126258Smlaier 200126258Smlaiervoid pfr_copyout_addr(struct pfr_addr *, 201126258Smlaier struct pfr_kentry *ke); 202126258Smlaierint pfr_validate_addr(struct pfr_addr *); 203126258Smlaiervoid pfr_enqueue_addrs(struct pfr_ktable *, 204126258Smlaier struct pfr_kentryworkq *, int *, int); 205126258Smlaiervoid pfr_mark_addrs(struct pfr_ktable *); 206126258Smlaierstruct pfr_kentry *pfr_lookup_addr(struct pfr_ktable *, 207126258Smlaier struct pfr_addr *, int); 208145836Smlaierstruct pfr_kentry *pfr_create_kentry(struct pfr_addr *, int); 209126258Smlaiervoid pfr_destroy_kentries(struct pfr_kentryworkq *); 210126258Smlaiervoid pfr_destroy_kentry(struct pfr_kentry *); 211126258Smlaiervoid pfr_insert_kentries(struct pfr_ktable *, 212126258Smlaier struct pfr_kentryworkq *, long); 213126258Smlaiervoid pfr_remove_kentries(struct pfr_ktable *, 214126258Smlaier struct pfr_kentryworkq *); 215126258Smlaiervoid pfr_clstats_kentries(struct pfr_kentryworkq *, long, 216126258Smlaier int); 217130613Smlaiervoid pfr_reset_feedback(struct pfr_addr *, int, int); 218126258Smlaiervoid pfr_prepare_network(union sockaddr_union *, int, int); 219126258Smlaierint pfr_route_kentry(struct pfr_ktable *, 220126258Smlaier struct pfr_kentry *); 221126258Smlaierint pfr_unroute_kentry(struct pfr_ktable *, 222126258Smlaier struct pfr_kentry *); 223126258Smlaierint pfr_walktree(struct radix_node *, void *); 224130613Smlaierint pfr_validate_table(struct pfr_table *, int, int); 225145836Smlaierint pfr_fix_anchor(char *); 226126258Smlaiervoid pfr_commit_ktable(struct pfr_ktable *, long); 227126258Smlaiervoid pfr_insert_ktables(struct pfr_ktableworkq *); 228126258Smlaiervoid pfr_insert_ktable(struct pfr_ktable *); 229126258Smlaiervoid pfr_setflags_ktables(struct pfr_ktableworkq *); 230126258Smlaiervoid pfr_setflags_ktable(struct pfr_ktable *, int); 231126258Smlaiervoid pfr_clstats_ktables(struct pfr_ktableworkq *, long, 232126258Smlaier int); 233126258Smlaiervoid pfr_clstats_ktable(struct pfr_ktable *, long, int); 234223637Sbzstruct pfr_ktable *pfr_create_ktable(struct pfr_table *, long, int, int); 235126258Smlaiervoid pfr_destroy_ktables(struct pfr_ktableworkq *, int); 236126258Smlaiervoid pfr_destroy_ktable(struct pfr_ktable *, int); 237126258Smlaierint pfr_ktable_compare(struct pfr_ktable *, 238126258Smlaier struct pfr_ktable *); 239126258Smlaierstruct pfr_ktable *pfr_lookup_table(struct pfr_table *); 240130613Smlaiervoid pfr_clean_node_mask(struct pfr_ktable *, 241126258Smlaier struct pfr_kentryworkq *); 242126258Smlaierint pfr_table_count(struct pfr_table *, int); 243126258Smlaierint pfr_skip_table(struct pfr_table *, 244126258Smlaier struct pfr_ktable *, int); 245130613Smlaierstruct pfr_kentry *pfr_kentry_byidx(struct pfr_ktable *, int, int); 246126258Smlaier 247126258SmlaierRB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); 248126258SmlaierRB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); 249126258Smlaier 250126258Smlaierstruct pfr_ktablehead pfr_ktables; 251126258Smlaierstruct pfr_table pfr_nulltable; 252126258Smlaierint pfr_ktable_cnt; 253126258Smlaier 254126258Smlaiervoid 255126258Smlaierpfr_initialize(void) 256126258Smlaier{ 257127145Smlaier#ifndef __FreeBSD__ 258126258Smlaier pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0, 259223637Sbz "pfrktable", NULL); 260126258Smlaier pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0, 261223637Sbz "pfrkentry", NULL); 262223637Sbz pool_init(&pfr_kcounters_pl, sizeof(struct pfr_kcounters), 0, 0, 0, 263223637Sbz "pfrkcounters", NULL); 264126258Smlaier 265126258Smlaier pfr_sin.sin_len = sizeof(pfr_sin); 266126258Smlaier pfr_sin.sin_family = AF_INET; 267126258Smlaier pfr_sin6.sin6_len = sizeof(pfr_sin6); 268126258Smlaier pfr_sin6.sin6_family = AF_INET6; 269126258Smlaier 270126258Smlaier memset(&pfr_ffaddr, 0xff, sizeof(pfr_ffaddr)); 271223637Sbz#else 272223637Sbz V_pfr_sin.sin_len = sizeof(V_pfr_sin); 273223637Sbz V_pfr_sin.sin_family = AF_INET; 274223637Sbz V_pfr_sin6.sin6_len = sizeof(V_pfr_sin6); 275223637Sbz V_pfr_sin6.sin6_family = AF_INET6; 276223637Sbz 277223637Sbz memset(&V_pfr_ffaddr, 0xff, sizeof(V_pfr_ffaddr)); 278223637Sbz#endif 279126258Smlaier} 280126258Smlaier 281126258Smlaierint 282126258Smlaierpfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) 283126258Smlaier{ 284126258Smlaier struct pfr_ktable *kt; 285126258Smlaier struct pfr_kentryworkq workq; 286126258Smlaier int s; 287126258Smlaier 288223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY); 289130613Smlaier if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 290126258Smlaier return (EINVAL); 291126258Smlaier kt = pfr_lookup_table(tbl); 292126258Smlaier if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 293126258Smlaier return (ESRCH); 294126258Smlaier if (kt->pfrkt_flags & PFR_TFLAG_CONST) 295126258Smlaier return (EPERM); 296126258Smlaier pfr_enqueue_addrs(kt, &workq, ndel, 0); 297126258Smlaier 298126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 299126258Smlaier if (flags & PFR_FLAG_ATOMIC) 300126258Smlaier s = splsoftnet(); 301126258Smlaier pfr_remove_kentries(kt, &workq); 302126258Smlaier if (flags & PFR_FLAG_ATOMIC) 303126258Smlaier splx(s); 304126258Smlaier if (kt->pfrkt_cnt) { 305126258Smlaier printf("pfr_clr_addrs: corruption detected (%d).\n", 306126258Smlaier kt->pfrkt_cnt); 307126258Smlaier kt->pfrkt_cnt = 0; 308126258Smlaier } 309126258Smlaier } 310126258Smlaier return (0); 311126258Smlaier} 312126258Smlaier 313126258Smlaierint 314126258Smlaierpfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 315126258Smlaier int *nadd, int flags) 316126258Smlaier{ 317126258Smlaier struct pfr_ktable *kt, *tmpkt; 318126258Smlaier struct pfr_kentryworkq workq; 319126258Smlaier struct pfr_kentry *p, *q; 320126258Smlaier struct pfr_addr ad; 321223637Sbz int i, rv, s, xadd = 0; 322145836Smlaier long tzero = time_second; 323126258Smlaier 324223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY | 325223637Sbz PFR_FLAG_FEEDBACK); 326130613Smlaier if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 327126258Smlaier return (EINVAL); 328126258Smlaier kt = pfr_lookup_table(tbl); 329126258Smlaier if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 330126258Smlaier return (ESRCH); 331126258Smlaier if (kt->pfrkt_flags & PFR_TFLAG_CONST) 332126258Smlaier return (EPERM); 333223637Sbz tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0, 334223637Sbz !(flags & PFR_FLAG_USERIOCTL)); 335126258Smlaier if (tmpkt == NULL) 336126258Smlaier return (ENOMEM); 337126258Smlaier SLIST_INIT(&workq); 338126258Smlaier for (i = 0; i < size; i++) { 339223637Sbz if (COPYIN(addr+i, &ad, sizeof(ad), flags)) 340126261Smlaier senderr(EFAULT); 341126258Smlaier if (pfr_validate_addr(&ad)) 342126258Smlaier senderr(EINVAL); 343126258Smlaier p = pfr_lookup_addr(kt, &ad, 1); 344126258Smlaier q = pfr_lookup_addr(tmpkt, &ad, 1); 345126258Smlaier if (flags & PFR_FLAG_FEEDBACK) { 346126258Smlaier if (q != NULL) 347126258Smlaier ad.pfra_fback = PFR_FB_DUPLICATE; 348126258Smlaier else if (p == NULL) 349126258Smlaier ad.pfra_fback = PFR_FB_ADDED; 350126258Smlaier else if (p->pfrke_not != ad.pfra_not) 351126258Smlaier ad.pfra_fback = PFR_FB_CONFLICT; 352126258Smlaier else 353126258Smlaier ad.pfra_fback = PFR_FB_NONE; 354126258Smlaier } 355126258Smlaier if (p == NULL && q == NULL) { 356223637Sbz p = pfr_create_kentry(&ad, 357223637Sbz !(flags & PFR_FLAG_USERIOCTL)); 358126258Smlaier if (p == NULL) 359126258Smlaier senderr(ENOMEM); 360126258Smlaier if (pfr_route_kentry(tmpkt, p)) { 361126258Smlaier pfr_destroy_kentry(p); 362126258Smlaier ad.pfra_fback = PFR_FB_NONE; 363126258Smlaier } else { 364126258Smlaier SLIST_INSERT_HEAD(&workq, p, pfrke_workq); 365126258Smlaier xadd++; 366126258Smlaier } 367126258Smlaier } 368223637Sbz if (flags & PFR_FLAG_FEEDBACK) 369223637Sbz if (COPYOUT(&ad, addr+i, sizeof(ad), flags)) 370126261Smlaier senderr(EFAULT); 371126258Smlaier } 372126258Smlaier pfr_clean_node_mask(tmpkt, &workq); 373126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 374126258Smlaier if (flags & PFR_FLAG_ATOMIC) 375126258Smlaier s = splsoftnet(); 376126258Smlaier pfr_insert_kentries(kt, &workq, tzero); 377126258Smlaier if (flags & PFR_FLAG_ATOMIC) 378126258Smlaier splx(s); 379126258Smlaier } else 380126258Smlaier pfr_destroy_kentries(&workq); 381126258Smlaier if (nadd != NULL) 382126258Smlaier *nadd = xadd; 383126258Smlaier pfr_destroy_ktable(tmpkt, 0); 384126258Smlaier return (0); 385126258Smlaier_bad: 386126258Smlaier pfr_clean_node_mask(tmpkt, &workq); 387126258Smlaier pfr_destroy_kentries(&workq); 388126258Smlaier if (flags & PFR_FLAG_FEEDBACK) 389130613Smlaier pfr_reset_feedback(addr, size, flags); 390126258Smlaier pfr_destroy_ktable(tmpkt, 0); 391126258Smlaier return (rv); 392126258Smlaier} 393126258Smlaier 394126258Smlaierint 395126258Smlaierpfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 396126258Smlaier int *ndel, int flags) 397126258Smlaier{ 398126258Smlaier struct pfr_ktable *kt; 399126258Smlaier struct pfr_kentryworkq workq; 400126258Smlaier struct pfr_kentry *p; 401126258Smlaier struct pfr_addr ad; 402223637Sbz int i, rv, s, xdel = 0, log = 1; 403126258Smlaier 404223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY | 405223637Sbz PFR_FLAG_FEEDBACK); 406130613Smlaier if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 407126258Smlaier return (EINVAL); 408126258Smlaier kt = pfr_lookup_table(tbl); 409126258Smlaier if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 410126258Smlaier return (ESRCH); 411126258Smlaier if (kt->pfrkt_flags & PFR_TFLAG_CONST) 412126258Smlaier return (EPERM); 413145836Smlaier /* 414145836Smlaier * there are two algorithms to choose from here. 415145836Smlaier * with: 416145836Smlaier * n: number of addresses to delete 417145836Smlaier * N: number of addresses in the table 418145836Smlaier * 419145836Smlaier * one is O(N) and is better for large 'n' 420145836Smlaier * one is O(n*LOG(N)) and is better for small 'n' 421145836Smlaier * 422145836Smlaier * following code try to decide which one is best. 423145836Smlaier */ 424145836Smlaier for (i = kt->pfrkt_cnt; i > 0; i >>= 1) 425145836Smlaier log++; 426145836Smlaier if (size > kt->pfrkt_cnt/log) { 427145836Smlaier /* full table scan */ 428145836Smlaier pfr_mark_addrs(kt); 429145836Smlaier } else { 430145836Smlaier /* iterate over addresses to delete */ 431145836Smlaier for (i = 0; i < size; i++) { 432223637Sbz if (COPYIN(addr+i, &ad, sizeof(ad), flags)) 433145836Smlaier return (EFAULT); 434145836Smlaier if (pfr_validate_addr(&ad)) 435145836Smlaier return (EINVAL); 436145836Smlaier p = pfr_lookup_addr(kt, &ad, 1); 437145836Smlaier if (p != NULL) 438145836Smlaier p->pfrke_mark = 0; 439145836Smlaier } 440145836Smlaier } 441126258Smlaier SLIST_INIT(&workq); 442126258Smlaier for (i = 0; i < size; i++) { 443223637Sbz if (COPYIN(addr+i, &ad, sizeof(ad), flags)) 444126261Smlaier senderr(EFAULT); 445126258Smlaier if (pfr_validate_addr(&ad)) 446126258Smlaier senderr(EINVAL); 447126258Smlaier p = pfr_lookup_addr(kt, &ad, 1); 448126258Smlaier if (flags & PFR_FLAG_FEEDBACK) { 449126258Smlaier if (p == NULL) 450126258Smlaier ad.pfra_fback = PFR_FB_NONE; 451126258Smlaier else if (p->pfrke_not != ad.pfra_not) 452126258Smlaier ad.pfra_fback = PFR_FB_CONFLICT; 453126258Smlaier else if (p->pfrke_mark) 454126258Smlaier ad.pfra_fback = PFR_FB_DUPLICATE; 455126258Smlaier else 456126258Smlaier ad.pfra_fback = PFR_FB_DELETED; 457126258Smlaier } 458126258Smlaier if (p != NULL && p->pfrke_not == ad.pfra_not && 459126258Smlaier !p->pfrke_mark) { 460126258Smlaier p->pfrke_mark = 1; 461126258Smlaier SLIST_INSERT_HEAD(&workq, p, pfrke_workq); 462126258Smlaier xdel++; 463126258Smlaier } 464126258Smlaier if (flags & PFR_FLAG_FEEDBACK) 465223637Sbz if (COPYOUT(&ad, addr+i, sizeof(ad), flags)) 466126258Smlaier senderr(EFAULT); 467126258Smlaier } 468126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 469126258Smlaier if (flags & PFR_FLAG_ATOMIC) 470126258Smlaier s = splsoftnet(); 471126258Smlaier pfr_remove_kentries(kt, &workq); 472126258Smlaier if (flags & PFR_FLAG_ATOMIC) 473126258Smlaier splx(s); 474126258Smlaier } 475126258Smlaier if (ndel != NULL) 476126258Smlaier *ndel = xdel; 477126258Smlaier return (0); 478126258Smlaier_bad: 479126258Smlaier if (flags & PFR_FLAG_FEEDBACK) 480130613Smlaier pfr_reset_feedback(addr, size, flags); 481126258Smlaier return (rv); 482126258Smlaier} 483126258Smlaier 484126258Smlaierint 485126258Smlaierpfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 486171168Smlaier int *size2, int *nadd, int *ndel, int *nchange, int flags, 487171168Smlaier u_int32_t ignore_pfrt_flags) 488126258Smlaier{ 489126258Smlaier struct pfr_ktable *kt, *tmpkt; 490126258Smlaier struct pfr_kentryworkq addq, delq, changeq; 491126258Smlaier struct pfr_kentry *p, *q; 492126258Smlaier struct pfr_addr ad; 493223637Sbz int i, rv, s, xadd = 0, xdel = 0, xchange = 0; 494145836Smlaier long tzero = time_second; 495126258Smlaier 496223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY | 497223637Sbz PFR_FLAG_FEEDBACK); 498171168Smlaier if (pfr_validate_table(tbl, ignore_pfrt_flags, flags & 499171168Smlaier PFR_FLAG_USERIOCTL)) 500126258Smlaier return (EINVAL); 501126258Smlaier kt = pfr_lookup_table(tbl); 502126258Smlaier if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 503126258Smlaier return (ESRCH); 504126258Smlaier if (kt->pfrkt_flags & PFR_TFLAG_CONST) 505126258Smlaier return (EPERM); 506223637Sbz tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0, 507223637Sbz !(flags & PFR_FLAG_USERIOCTL)); 508126258Smlaier if (tmpkt == NULL) 509126258Smlaier return (ENOMEM); 510126258Smlaier pfr_mark_addrs(kt); 511126258Smlaier SLIST_INIT(&addq); 512126258Smlaier SLIST_INIT(&delq); 513126258Smlaier SLIST_INIT(&changeq); 514126258Smlaier for (i = 0; i < size; i++) { 515223637Sbz if (COPYIN(addr+i, &ad, sizeof(ad), flags)) 516126261Smlaier senderr(EFAULT); 517126258Smlaier if (pfr_validate_addr(&ad)) 518126258Smlaier senderr(EINVAL); 519126258Smlaier ad.pfra_fback = PFR_FB_NONE; 520126258Smlaier p = pfr_lookup_addr(kt, &ad, 1); 521126258Smlaier if (p != NULL) { 522126258Smlaier if (p->pfrke_mark) { 523126258Smlaier ad.pfra_fback = PFR_FB_DUPLICATE; 524126258Smlaier goto _skip; 525126258Smlaier } 526126258Smlaier p->pfrke_mark = 1; 527126258Smlaier if (p->pfrke_not != ad.pfra_not) { 528126258Smlaier SLIST_INSERT_HEAD(&changeq, p, pfrke_workq); 529126258Smlaier ad.pfra_fback = PFR_FB_CHANGED; 530126258Smlaier xchange++; 531126258Smlaier } 532126258Smlaier } else { 533126258Smlaier q = pfr_lookup_addr(tmpkt, &ad, 1); 534126258Smlaier if (q != NULL) { 535126258Smlaier ad.pfra_fback = PFR_FB_DUPLICATE; 536126258Smlaier goto _skip; 537126258Smlaier } 538223637Sbz p = pfr_create_kentry(&ad, 539223637Sbz !(flags & PFR_FLAG_USERIOCTL)); 540126258Smlaier if (p == NULL) 541126258Smlaier senderr(ENOMEM); 542126258Smlaier if (pfr_route_kentry(tmpkt, p)) { 543126258Smlaier pfr_destroy_kentry(p); 544126258Smlaier ad.pfra_fback = PFR_FB_NONE; 545126258Smlaier } else { 546126258Smlaier SLIST_INSERT_HEAD(&addq, p, pfrke_workq); 547126258Smlaier ad.pfra_fback = PFR_FB_ADDED; 548126258Smlaier xadd++; 549126258Smlaier } 550126258Smlaier } 551126258Smlaier_skip: 552126258Smlaier if (flags & PFR_FLAG_FEEDBACK) 553223637Sbz if (COPYOUT(&ad, addr+i, sizeof(ad), flags)) 554126258Smlaier senderr(EFAULT); 555126258Smlaier } 556126258Smlaier pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY); 557126258Smlaier if ((flags & PFR_FLAG_FEEDBACK) && *size2) { 558126258Smlaier if (*size2 < size+xdel) { 559126258Smlaier *size2 = size+xdel; 560126258Smlaier senderr(0); 561126258Smlaier } 562126258Smlaier i = 0; 563126258Smlaier SLIST_FOREACH(p, &delq, pfrke_workq) { 564126258Smlaier pfr_copyout_addr(&ad, p); 565126258Smlaier ad.pfra_fback = PFR_FB_DELETED; 566223637Sbz if (COPYOUT(&ad, addr+size+i, sizeof(ad), flags)) 567126261Smlaier senderr(EFAULT); 568126258Smlaier i++; 569126258Smlaier } 570126258Smlaier } 571126258Smlaier pfr_clean_node_mask(tmpkt, &addq); 572126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 573126258Smlaier if (flags & PFR_FLAG_ATOMIC) 574126258Smlaier s = splsoftnet(); 575126258Smlaier pfr_insert_kentries(kt, &addq, tzero); 576126258Smlaier pfr_remove_kentries(kt, &delq); 577126258Smlaier pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG); 578126258Smlaier if (flags & PFR_FLAG_ATOMIC) 579126258Smlaier splx(s); 580126258Smlaier } else 581126258Smlaier pfr_destroy_kentries(&addq); 582126258Smlaier if (nadd != NULL) 583126258Smlaier *nadd = xadd; 584126258Smlaier if (ndel != NULL) 585126258Smlaier *ndel = xdel; 586126258Smlaier if (nchange != NULL) 587126258Smlaier *nchange = xchange; 588130613Smlaier if ((flags & PFR_FLAG_FEEDBACK) && size2) 589126258Smlaier *size2 = size+xdel; 590126258Smlaier pfr_destroy_ktable(tmpkt, 0); 591126258Smlaier return (0); 592126258Smlaier_bad: 593126258Smlaier pfr_clean_node_mask(tmpkt, &addq); 594126258Smlaier pfr_destroy_kentries(&addq); 595126258Smlaier if (flags & PFR_FLAG_FEEDBACK) 596130613Smlaier pfr_reset_feedback(addr, size, flags); 597126258Smlaier pfr_destroy_ktable(tmpkt, 0); 598126258Smlaier return (rv); 599126258Smlaier} 600126258Smlaier 601126258Smlaierint 602126258Smlaierpfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 603126258Smlaier int *nmatch, int flags) 604126258Smlaier{ 605126258Smlaier struct pfr_ktable *kt; 606126258Smlaier struct pfr_kentry *p; 607126258Smlaier struct pfr_addr ad; 608126258Smlaier int i, xmatch = 0; 609126258Smlaier 610223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_REPLACE); 611130613Smlaier if (pfr_validate_table(tbl, 0, 0)) 612126258Smlaier return (EINVAL); 613126258Smlaier kt = pfr_lookup_table(tbl); 614126258Smlaier if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 615126258Smlaier return (ESRCH); 616126258Smlaier 617126258Smlaier for (i = 0; i < size; i++) { 618223637Sbz if (COPYIN(addr+i, &ad, sizeof(ad), flags)) 619126261Smlaier return (EFAULT); 620126258Smlaier if (pfr_validate_addr(&ad)) 621126258Smlaier return (EINVAL); 622126258Smlaier if (ADDR_NETWORK(&ad)) 623126258Smlaier return (EINVAL); 624126258Smlaier p = pfr_lookup_addr(kt, &ad, 0); 625126258Smlaier if (flags & PFR_FLAG_REPLACE) 626126258Smlaier pfr_copyout_addr(&ad, p); 627126258Smlaier ad.pfra_fback = (p == NULL) ? PFR_FB_NONE : 628126258Smlaier (p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH); 629126258Smlaier if (p != NULL && !p->pfrke_not) 630126258Smlaier xmatch++; 631223637Sbz if (COPYOUT(&ad, addr+i, sizeof(ad), flags)) 632126261Smlaier return (EFAULT); 633126258Smlaier } 634126258Smlaier if (nmatch != NULL) 635126258Smlaier *nmatch = xmatch; 636126258Smlaier return (0); 637126258Smlaier} 638126258Smlaier 639126258Smlaierint 640126258Smlaierpfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, 641126258Smlaier int flags) 642126258Smlaier{ 643126258Smlaier struct pfr_ktable *kt; 644126258Smlaier struct pfr_walktree w; 645126258Smlaier int rv; 646126258Smlaier 647223637Sbz ACCEPT_FLAGS(flags, 0); 648130613Smlaier if (pfr_validate_table(tbl, 0, 0)) 649126258Smlaier return (EINVAL); 650126258Smlaier kt = pfr_lookup_table(tbl); 651126258Smlaier if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 652126258Smlaier return (ESRCH); 653126258Smlaier if (kt->pfrkt_cnt > *size) { 654126258Smlaier *size = kt->pfrkt_cnt; 655126258Smlaier return (0); 656126258Smlaier } 657126258Smlaier 658126258Smlaier bzero(&w, sizeof(w)); 659126258Smlaier w.pfrw_op = PFRW_GET_ADDRS; 660126258Smlaier w.pfrw_addr = addr; 661126258Smlaier w.pfrw_free = kt->pfrkt_cnt; 662130613Smlaier w.pfrw_flags = flags; 663127145Smlaier#ifdef __FreeBSD__ 664126261Smlaier rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 665126261Smlaier#else 666126258Smlaier rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 667126261Smlaier#endif 668126258Smlaier if (!rv) 669127145Smlaier#ifdef __FreeBSD__ 670223637Sbz rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, 671126261Smlaier &w); 672126261Smlaier#else 673126258Smlaier rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); 674126261Smlaier#endif 675126258Smlaier if (rv) 676126258Smlaier return (rv); 677126258Smlaier 678126258Smlaier if (w.pfrw_free) { 679126258Smlaier printf("pfr_get_addrs: corruption detected (%d).\n", 680126258Smlaier w.pfrw_free); 681126258Smlaier return (ENOTTY); 682126258Smlaier } 683126258Smlaier *size = kt->pfrkt_cnt; 684126258Smlaier return (0); 685126258Smlaier} 686126258Smlaier 687126258Smlaierint 688126258Smlaierpfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, 689126258Smlaier int flags) 690126258Smlaier{ 691126258Smlaier struct pfr_ktable *kt; 692126258Smlaier struct pfr_walktree w; 693126258Smlaier struct pfr_kentryworkq workq; 694223637Sbz int rv, s; 695145836Smlaier long tzero = time_second; 696126258Smlaier 697223637Sbz /* XXX PFR_FLAG_CLSTATS disabled */ 698223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC); 699130613Smlaier if (pfr_validate_table(tbl, 0, 0)) 700126258Smlaier return (EINVAL); 701126258Smlaier kt = pfr_lookup_table(tbl); 702126258Smlaier if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 703126258Smlaier return (ESRCH); 704126258Smlaier if (kt->pfrkt_cnt > *size) { 705126258Smlaier *size = kt->pfrkt_cnt; 706126258Smlaier return (0); 707126258Smlaier } 708126258Smlaier 709126258Smlaier bzero(&w, sizeof(w)); 710126258Smlaier w.pfrw_op = PFRW_GET_ASTATS; 711126258Smlaier w.pfrw_astats = addr; 712126258Smlaier w.pfrw_free = kt->pfrkt_cnt; 713130613Smlaier w.pfrw_flags = flags; 714126258Smlaier if (flags & PFR_FLAG_ATOMIC) 715126258Smlaier s = splsoftnet(); 716127145Smlaier#ifdef __FreeBSD__ 717126261Smlaier rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 718126261Smlaier#else 719126258Smlaier rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 720126261Smlaier#endif 721126258Smlaier if (!rv) 722127145Smlaier#ifdef __FreeBSD__ 723126261Smlaier rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, 724126261Smlaier &w); 725126261Smlaier#else 726126258Smlaier rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); 727126261Smlaier#endif 728126258Smlaier if (!rv && (flags & PFR_FLAG_CLSTATS)) { 729126258Smlaier pfr_enqueue_addrs(kt, &workq, NULL, 0); 730126258Smlaier pfr_clstats_kentries(&workq, tzero, 0); 731126258Smlaier } 732126258Smlaier if (flags & PFR_FLAG_ATOMIC) 733126258Smlaier splx(s); 734126258Smlaier if (rv) 735126258Smlaier return (rv); 736126258Smlaier 737126258Smlaier if (w.pfrw_free) { 738126258Smlaier printf("pfr_get_astats: corruption detected (%d).\n", 739126258Smlaier w.pfrw_free); 740126258Smlaier return (ENOTTY); 741126258Smlaier } 742126258Smlaier *size = kt->pfrkt_cnt; 743126258Smlaier return (0); 744126258Smlaier} 745126258Smlaier 746126258Smlaierint 747126258Smlaierpfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, 748126258Smlaier int *nzero, int flags) 749126258Smlaier{ 750126258Smlaier struct pfr_ktable *kt; 751126258Smlaier struct pfr_kentryworkq workq; 752126258Smlaier struct pfr_kentry *p; 753126258Smlaier struct pfr_addr ad; 754223637Sbz int i, rv, s, xzero = 0; 755126258Smlaier 756223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY | 757223637Sbz PFR_FLAG_FEEDBACK); 758130613Smlaier if (pfr_validate_table(tbl, 0, 0)) 759126258Smlaier return (EINVAL); 760126258Smlaier kt = pfr_lookup_table(tbl); 761126258Smlaier if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 762126258Smlaier return (ESRCH); 763126258Smlaier SLIST_INIT(&workq); 764126258Smlaier for (i = 0; i < size; i++) { 765223637Sbz if (COPYIN(addr+i, &ad, sizeof(ad), flags)) 766126261Smlaier senderr(EFAULT); 767126258Smlaier if (pfr_validate_addr(&ad)) 768126258Smlaier senderr(EINVAL); 769126258Smlaier p = pfr_lookup_addr(kt, &ad, 1); 770126258Smlaier if (flags & PFR_FLAG_FEEDBACK) { 771126258Smlaier ad.pfra_fback = (p != NULL) ? 772126258Smlaier PFR_FB_CLEARED : PFR_FB_NONE; 773223637Sbz if (COPYOUT(&ad, addr+i, sizeof(ad), flags)) 774126261Smlaier senderr(EFAULT); 775126258Smlaier } 776126258Smlaier if (p != NULL) { 777126258Smlaier SLIST_INSERT_HEAD(&workq, p, pfrke_workq); 778126258Smlaier xzero++; 779126258Smlaier } 780126258Smlaier } 781126258Smlaier 782126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 783126258Smlaier if (flags & PFR_FLAG_ATOMIC) 784126258Smlaier s = splsoftnet(); 785126258Smlaier pfr_clstats_kentries(&workq, 0, 0); 786126258Smlaier if (flags & PFR_FLAG_ATOMIC) 787126258Smlaier splx(s); 788126258Smlaier } 789126258Smlaier if (nzero != NULL) 790126258Smlaier *nzero = xzero; 791126258Smlaier return (0); 792126258Smlaier_bad: 793126258Smlaier if (flags & PFR_FLAG_FEEDBACK) 794130613Smlaier pfr_reset_feedback(addr, size, flags); 795126258Smlaier return (rv); 796126258Smlaier} 797126258Smlaier 798126258Smlaierint 799126258Smlaierpfr_validate_addr(struct pfr_addr *ad) 800126258Smlaier{ 801126258Smlaier int i; 802126258Smlaier 803126258Smlaier switch (ad->pfra_af) { 804145836Smlaier#ifdef INET 805126258Smlaier case AF_INET: 806126258Smlaier if (ad->pfra_net > 32) 807126258Smlaier return (-1); 808126258Smlaier break; 809145836Smlaier#endif /* INET */ 810145836Smlaier#ifdef INET6 811126258Smlaier case AF_INET6: 812126258Smlaier if (ad->pfra_net > 128) 813126258Smlaier return (-1); 814126258Smlaier break; 815145836Smlaier#endif /* INET6 */ 816126258Smlaier default: 817126258Smlaier return (-1); 818126258Smlaier } 819126258Smlaier if (ad->pfra_net < 128 && 820126258Smlaier (((caddr_t)ad)[ad->pfra_net/8] & (0xFF >> (ad->pfra_net%8)))) 821126258Smlaier return (-1); 822126258Smlaier for (i = (ad->pfra_net+7)/8; i < sizeof(ad->pfra_u); i++) 823126258Smlaier if (((caddr_t)ad)[i]) 824126258Smlaier return (-1); 825126258Smlaier if (ad->pfra_not && ad->pfra_not != 1) 826126258Smlaier return (-1); 827126258Smlaier if (ad->pfra_fback) 828126258Smlaier return (-1); 829126258Smlaier return (0); 830126258Smlaier} 831126258Smlaier 832126258Smlaiervoid 833126258Smlaierpfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq, 834126258Smlaier int *naddr, int sweep) 835126258Smlaier{ 836126258Smlaier struct pfr_walktree w; 837126258Smlaier 838126258Smlaier SLIST_INIT(workq); 839126258Smlaier bzero(&w, sizeof(w)); 840126258Smlaier w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE; 841126258Smlaier w.pfrw_workq = workq; 842126258Smlaier if (kt->pfrkt_ip4 != NULL) 843127145Smlaier#ifdef __FreeBSD__ 844126261Smlaier if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, 845126261Smlaier &w)) 846126261Smlaier#else 847126258Smlaier if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) 848126261Smlaier#endif 849126258Smlaier printf("pfr_enqueue_addrs: IPv4 walktree failed.\n"); 850126258Smlaier if (kt->pfrkt_ip6 != NULL) 851127145Smlaier#ifdef __FreeBSD__ 852126261Smlaier if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, 853126261Smlaier &w)) 854126261Smlaier#else 855126258Smlaier if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) 856126261Smlaier#endif 857126258Smlaier printf("pfr_enqueue_addrs: IPv6 walktree failed.\n"); 858126258Smlaier if (naddr != NULL) 859126258Smlaier *naddr = w.pfrw_cnt; 860126258Smlaier} 861126258Smlaier 862126258Smlaiervoid 863126258Smlaierpfr_mark_addrs(struct pfr_ktable *kt) 864126258Smlaier{ 865126258Smlaier struct pfr_walktree w; 866126258Smlaier 867126258Smlaier bzero(&w, sizeof(w)); 868126258Smlaier w.pfrw_op = PFRW_MARK; 869127145Smlaier#ifdef __FreeBSD__ 870126261Smlaier if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) 871126261Smlaier#else 872126258Smlaier if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) 873126261Smlaier#endif 874126258Smlaier printf("pfr_mark_addrs: IPv4 walktree failed.\n"); 875127145Smlaier#ifdef __FreeBSD__ 876126261Smlaier if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) 877126261Smlaier#else 878126258Smlaier if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) 879126261Smlaier#endif 880126258Smlaier printf("pfr_mark_addrs: IPv6 walktree failed.\n"); 881126258Smlaier} 882126258Smlaier 883126258Smlaier 884126258Smlaierstruct pfr_kentry * 885126258Smlaierpfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) 886126258Smlaier{ 887126258Smlaier union sockaddr_union sa, mask; 888223637Sbz#ifdef __FreeBSD__ 889223637Sbz struct radix_node_head *head = NULL; 890223637Sbz#else 891223637Sbz struct radix_node_head *head; 892223637Sbz#endif 893126258Smlaier struct pfr_kentry *ke; 894126258Smlaier int s; 895126258Smlaier 896126258Smlaier bzero(&sa, sizeof(sa)); 897126258Smlaier if (ad->pfra_af == AF_INET) { 898126258Smlaier FILLIN_SIN(sa.sin, ad->pfra_ip4addr); 899126258Smlaier head = kt->pfrkt_ip4; 900145836Smlaier } else if ( ad->pfra_af == AF_INET6 ) { 901126258Smlaier FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr); 902126258Smlaier head = kt->pfrkt_ip6; 903126258Smlaier } 904126258Smlaier if (ADDR_NETWORK(ad)) { 905126258Smlaier pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net); 906126258Smlaier s = splsoftnet(); /* rn_lookup makes use of globals */ 907171168Smlaier#ifdef __FreeBSD__ 908226801Sglebius PF_LOCK_ASSERT(); 909126261Smlaier#endif 910126258Smlaier ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head); 911126258Smlaier splx(s); 912126258Smlaier if (ke && KENTRY_RNF_ROOT(ke)) 913126258Smlaier ke = NULL; 914126258Smlaier } else { 915126258Smlaier ke = (struct pfr_kentry *)rn_match(&sa, head); 916126258Smlaier if (ke && KENTRY_RNF_ROOT(ke)) 917126258Smlaier ke = NULL; 918126258Smlaier if (exact && ke && KENTRY_NETWORK(ke)) 919126258Smlaier ke = NULL; 920126258Smlaier } 921126258Smlaier return (ke); 922126258Smlaier} 923126258Smlaier 924126258Smlaierstruct pfr_kentry * 925145836Smlaierpfr_create_kentry(struct pfr_addr *ad, int intr) 926126258Smlaier{ 927126258Smlaier struct pfr_kentry *ke; 928126258Smlaier 929223637Sbz#ifdef __FreeBSD__ 930238600Sglebius ke = pool_get(&V_pfr_kentry_pl, PR_NOWAIT | PR_ZERO); 931223637Sbz#else 932238600Sglebius if (intr) 933223637Sbz ke = pool_get(&pfr_kentry_pl, PR_NOWAIT | PR_ZERO); 934145836Smlaier else 935223637Sbz ke = pool_get(&pfr_kentry_pl, PR_WAITOK|PR_ZERO|PR_LIMITFAIL); 936223637Sbz#endif 937126258Smlaier if (ke == NULL) 938126258Smlaier return (NULL); 939126258Smlaier 940126258Smlaier if (ad->pfra_af == AF_INET) 941126258Smlaier FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr); 942145836Smlaier else if (ad->pfra_af == AF_INET6) 943126258Smlaier FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr); 944126258Smlaier ke->pfrke_af = ad->pfra_af; 945126258Smlaier ke->pfrke_net = ad->pfra_net; 946126258Smlaier ke->pfrke_not = ad->pfra_not; 947126258Smlaier return (ke); 948126258Smlaier} 949126258Smlaier 950126258Smlaiervoid 951126258Smlaierpfr_destroy_kentries(struct pfr_kentryworkq *workq) 952126258Smlaier{ 953126258Smlaier struct pfr_kentry *p, *q; 954126258Smlaier 955126258Smlaier for (p = SLIST_FIRST(workq); p != NULL; p = q) { 956126258Smlaier q = SLIST_NEXT(p, pfrke_workq); 957126258Smlaier pfr_destroy_kentry(p); 958126258Smlaier } 959126258Smlaier} 960126258Smlaier 961126258Smlaiervoid 962126258Smlaierpfr_destroy_kentry(struct pfr_kentry *ke) 963126258Smlaier{ 964223637Sbz if (ke->pfrke_counters) 965223637Sbz#ifdef __FreeBSD__ 966223637Sbz pool_put(&V_pfr_kcounters_pl, ke->pfrke_counters); 967223637Sbz pool_put(&V_pfr_kentry_pl, ke); 968223637Sbz#else 969223637Sbz pool_put(&pfr_kcounters_pl, ke->pfrke_counters); 970223637Sbz pool_put(&pfr_kentry_pl, ke); 971223637Sbz#endif 972126258Smlaier} 973126258Smlaier 974126258Smlaiervoid 975126258Smlaierpfr_insert_kentries(struct pfr_ktable *kt, 976126258Smlaier struct pfr_kentryworkq *workq, long tzero) 977126258Smlaier{ 978126258Smlaier struct pfr_kentry *p; 979126258Smlaier int rv, n = 0; 980126258Smlaier 981126258Smlaier SLIST_FOREACH(p, workq, pfrke_workq) { 982126258Smlaier rv = pfr_route_kentry(kt, p); 983126258Smlaier if (rv) { 984126258Smlaier printf("pfr_insert_kentries: cannot route entry " 985126258Smlaier "(code=%d).\n", rv); 986126258Smlaier break; 987126258Smlaier } 988126258Smlaier p->pfrke_tzero = tzero; 989126258Smlaier n++; 990126258Smlaier } 991126258Smlaier kt->pfrkt_cnt += n; 992126258Smlaier} 993126258Smlaier 994145836Smlaierint 995145836Smlaierpfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, long tzero) 996145836Smlaier{ 997145836Smlaier struct pfr_kentry *p; 998145836Smlaier int rv; 999145836Smlaier 1000145836Smlaier p = pfr_lookup_addr(kt, ad, 1); 1001145836Smlaier if (p != NULL) 1002145836Smlaier return (0); 1003145836Smlaier p = pfr_create_kentry(ad, 1); 1004145836Smlaier if (p == NULL) 1005145836Smlaier return (EINVAL); 1006145836Smlaier 1007145836Smlaier rv = pfr_route_kentry(kt, p); 1008145836Smlaier if (rv) 1009145836Smlaier return (rv); 1010145836Smlaier 1011145836Smlaier p->pfrke_tzero = tzero; 1012145836Smlaier kt->pfrkt_cnt++; 1013145836Smlaier 1014145836Smlaier return (0); 1015145836Smlaier} 1016145836Smlaier 1017126258Smlaiervoid 1018126258Smlaierpfr_remove_kentries(struct pfr_ktable *kt, 1019126258Smlaier struct pfr_kentryworkq *workq) 1020126258Smlaier{ 1021126258Smlaier struct pfr_kentry *p; 1022126258Smlaier int n = 0; 1023126258Smlaier 1024126258Smlaier SLIST_FOREACH(p, workq, pfrke_workq) { 1025126258Smlaier pfr_unroute_kentry(kt, p); 1026126258Smlaier n++; 1027126258Smlaier } 1028126258Smlaier kt->pfrkt_cnt -= n; 1029126258Smlaier pfr_destroy_kentries(workq); 1030126258Smlaier} 1031126258Smlaier 1032126258Smlaiervoid 1033126258Smlaierpfr_clean_node_mask(struct pfr_ktable *kt, 1034126258Smlaier struct pfr_kentryworkq *workq) 1035126258Smlaier{ 1036130613Smlaier struct pfr_kentry *p; 1037126258Smlaier 1038130613Smlaier SLIST_FOREACH(p, workq, pfrke_workq) 1039130613Smlaier pfr_unroute_kentry(kt, p); 1040126258Smlaier} 1041126258Smlaier 1042126258Smlaiervoid 1043126258Smlaierpfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange) 1044126258Smlaier{ 1045126258Smlaier struct pfr_kentry *p; 1046126258Smlaier int s; 1047126258Smlaier 1048126258Smlaier SLIST_FOREACH(p, workq, pfrke_workq) { 1049126258Smlaier s = splsoftnet(); 1050126258Smlaier if (negchange) 1051126258Smlaier p->pfrke_not = !p->pfrke_not; 1052223637Sbz if (p->pfrke_counters) { 1053223637Sbz#ifdef __FreeBSD__ 1054223637Sbz pool_put(&V_pfr_kcounters_pl, p->pfrke_counters); 1055223637Sbz#else 1056223637Sbz pool_put(&pfr_kcounters_pl, p->pfrke_counters); 1057223637Sbz#endif 1058223637Sbz p->pfrke_counters = NULL; 1059223637Sbz } 1060126258Smlaier splx(s); 1061126258Smlaier p->pfrke_tzero = tzero; 1062126258Smlaier } 1063126258Smlaier} 1064126258Smlaier 1065126258Smlaiervoid 1066130613Smlaierpfr_reset_feedback(struct pfr_addr *addr, int size, int flags) 1067126258Smlaier{ 1068126258Smlaier struct pfr_addr ad; 1069126258Smlaier int i; 1070126258Smlaier 1071126258Smlaier for (i = 0; i < size; i++) { 1072223637Sbz if (COPYIN(addr+i, &ad, sizeof(ad), flags)) 1073126261Smlaier break; 1074126258Smlaier ad.pfra_fback = PFR_FB_NONE; 1075223637Sbz if (COPYOUT(&ad, addr+i, sizeof(ad), flags)) 1076126261Smlaier break; 1077126258Smlaier } 1078126258Smlaier} 1079126258Smlaier 1080126258Smlaiervoid 1081126258Smlaierpfr_prepare_network(union sockaddr_union *sa, int af, int net) 1082126258Smlaier{ 1083126258Smlaier int i; 1084126258Smlaier 1085126258Smlaier bzero(sa, sizeof(*sa)); 1086126258Smlaier if (af == AF_INET) { 1087126258Smlaier sa->sin.sin_len = sizeof(sa->sin); 1088126258Smlaier sa->sin.sin_family = AF_INET; 1089145836Smlaier sa->sin.sin_addr.s_addr = net ? htonl(-1 << (32-net)) : 0; 1090145836Smlaier } else if (af == AF_INET6) { 1091126258Smlaier sa->sin6.sin6_len = sizeof(sa->sin6); 1092126258Smlaier sa->sin6.sin6_family = AF_INET6; 1093126258Smlaier for (i = 0; i < 4; i++) { 1094126258Smlaier if (net <= 32) { 1095126258Smlaier sa->sin6.sin6_addr.s6_addr32[i] = 1096145836Smlaier net ? htonl(-1 << (32-net)) : 0; 1097126258Smlaier break; 1098126258Smlaier } 1099126258Smlaier sa->sin6.sin6_addr.s6_addr32[i] = 0xFFFFFFFF; 1100126258Smlaier net -= 32; 1101126258Smlaier } 1102126258Smlaier } 1103126258Smlaier} 1104126258Smlaier 1105126258Smlaierint 1106126258Smlaierpfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) 1107126258Smlaier{ 1108126258Smlaier union sockaddr_union mask; 1109126258Smlaier struct radix_node *rn; 1110223637Sbz#ifdef __FreeBSD__ 1111223637Sbz struct radix_node_head *head = NULL; 1112223637Sbz#else 1113223637Sbz struct radix_node_head *head; 1114223637Sbz#endif 1115126258Smlaier int s; 1116126258Smlaier 1117126258Smlaier bzero(ke->pfrke_node, sizeof(ke->pfrke_node)); 1118126258Smlaier if (ke->pfrke_af == AF_INET) 1119126258Smlaier head = kt->pfrkt_ip4; 1120145836Smlaier else if (ke->pfrke_af == AF_INET6) 1121126258Smlaier head = kt->pfrkt_ip6; 1122126258Smlaier 1123126258Smlaier s = splsoftnet(); 1124171168Smlaier#ifdef __FreeBSD__ 1125226801Sglebius PF_LOCK_ASSERT(); 1126126261Smlaier#endif 1127126258Smlaier if (KENTRY_NETWORK(ke)) { 1128126258Smlaier pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); 1129223637Sbz#ifdef __FreeBSD__ 1130126258Smlaier rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node); 1131223637Sbz#else 1132223637Sbz rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node, 0); 1133223637Sbz#endif 1134126258Smlaier } else 1135223637Sbz#ifdef __FreeBSD__ 1136126258Smlaier rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node); 1137223637Sbz#else 1138223637Sbz rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node, 0); 1139223637Sbz#endif 1140126258Smlaier splx(s); 1141126258Smlaier 1142126258Smlaier return (rn == NULL ? -1 : 0); 1143126258Smlaier} 1144126258Smlaier 1145126258Smlaierint 1146126258Smlaierpfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) 1147126258Smlaier{ 1148126258Smlaier union sockaddr_union mask; 1149126258Smlaier struct radix_node *rn; 1150223637Sbz#ifdef __FreeBSD__ 1151223637Sbz struct radix_node_head *head = NULL; 1152223637Sbz#else 1153223637Sbz struct radix_node_head *head; 1154223637Sbz#endif 1155126258Smlaier int s; 1156126258Smlaier 1157126258Smlaier if (ke->pfrke_af == AF_INET) 1158126258Smlaier head = kt->pfrkt_ip4; 1159145836Smlaier else if (ke->pfrke_af == AF_INET6) 1160126258Smlaier head = kt->pfrkt_ip6; 1161126258Smlaier 1162126258Smlaier s = splsoftnet(); 1163171168Smlaier#ifdef __FreeBSD__ 1164226801Sglebius PF_LOCK_ASSERT(); 1165126261Smlaier#endif 1166126258Smlaier if (KENTRY_NETWORK(ke)) { 1167126258Smlaier pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); 1168145836Smlaier#ifdef __FreeBSD__ 1169126258Smlaier rn = rn_delete(&ke->pfrke_sa, &mask, head); 1170145836Smlaier#else 1171145836Smlaier rn = rn_delete(&ke->pfrke_sa, &mask, head, NULL); 1172145836Smlaier#endif 1173126258Smlaier } else 1174145836Smlaier#ifdef __FreeBSD__ 1175126258Smlaier rn = rn_delete(&ke->pfrke_sa, NULL, head); 1176145836Smlaier#else 1177145836Smlaier rn = rn_delete(&ke->pfrke_sa, NULL, head, NULL); 1178145836Smlaier#endif 1179126258Smlaier splx(s); 1180126258Smlaier 1181126258Smlaier if (rn == NULL) { 1182126258Smlaier printf("pfr_unroute_kentry: delete failed.\n"); 1183126258Smlaier return (-1); 1184126258Smlaier } 1185126258Smlaier return (0); 1186126258Smlaier} 1187126258Smlaier 1188126258Smlaiervoid 1189126258Smlaierpfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke) 1190126258Smlaier{ 1191126258Smlaier bzero(ad, sizeof(*ad)); 1192126258Smlaier if (ke == NULL) 1193126258Smlaier return; 1194126258Smlaier ad->pfra_af = ke->pfrke_af; 1195126258Smlaier ad->pfra_net = ke->pfrke_net; 1196126258Smlaier ad->pfra_not = ke->pfrke_not; 1197126258Smlaier if (ad->pfra_af == AF_INET) 1198126258Smlaier ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr; 1199145836Smlaier else if (ad->pfra_af == AF_INET6) 1200126258Smlaier ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr; 1201126258Smlaier} 1202126258Smlaier 1203126258Smlaierint 1204126258Smlaierpfr_walktree(struct radix_node *rn, void *arg) 1205126258Smlaier{ 1206126258Smlaier struct pfr_kentry *ke = (struct pfr_kentry *)rn; 1207126258Smlaier struct pfr_walktree *w = arg; 1208130613Smlaier int s, flags = w->pfrw_flags; 1209126258Smlaier 1210126258Smlaier switch (w->pfrw_op) { 1211126258Smlaier case PFRW_MARK: 1212126258Smlaier ke->pfrke_mark = 0; 1213126258Smlaier break; 1214126258Smlaier case PFRW_SWEEP: 1215126258Smlaier if (ke->pfrke_mark) 1216126258Smlaier break; 1217130613Smlaier /* FALLTHROUGH */ 1218126258Smlaier case PFRW_ENQUEUE: 1219126258Smlaier SLIST_INSERT_HEAD(w->pfrw_workq, ke, pfrke_workq); 1220126258Smlaier w->pfrw_cnt++; 1221126258Smlaier break; 1222126258Smlaier case PFRW_GET_ADDRS: 1223126258Smlaier if (w->pfrw_free-- > 0) { 1224126258Smlaier struct pfr_addr ad; 1225126258Smlaier 1226126258Smlaier pfr_copyout_addr(&ad, ke); 1227223637Sbz if (copyout(&ad, w->pfrw_addr, sizeof(ad))) 1228126258Smlaier return (EFAULT); 1229126258Smlaier w->pfrw_addr++; 1230126258Smlaier } 1231126258Smlaier break; 1232126258Smlaier case PFRW_GET_ASTATS: 1233126258Smlaier if (w->pfrw_free-- > 0) { 1234126258Smlaier struct pfr_astats as; 1235126258Smlaier 1236126258Smlaier pfr_copyout_addr(&as.pfras_a, ke); 1237126258Smlaier 1238126258Smlaier s = splsoftnet(); 1239223637Sbz if (ke->pfrke_counters) { 1240223637Sbz bcopy(ke->pfrke_counters->pfrkc_packets, 1241223637Sbz as.pfras_packets, sizeof(as.pfras_packets)); 1242223637Sbz bcopy(ke->pfrke_counters->pfrkc_bytes, 1243223637Sbz as.pfras_bytes, sizeof(as.pfras_bytes)); 1244223637Sbz } else { 1245223637Sbz bzero(as.pfras_packets, sizeof(as.pfras_packets)); 1246223637Sbz bzero(as.pfras_bytes, sizeof(as.pfras_bytes)); 1247223637Sbz as.pfras_a.pfra_fback = PFR_FB_NOCOUNT; 1248223637Sbz } 1249126258Smlaier splx(s); 1250126258Smlaier as.pfras_tzero = ke->pfrke_tzero; 1251126258Smlaier 1252223637Sbz if (COPYOUT(&as, w->pfrw_astats, sizeof(as), flags)) 1253126261Smlaier return (EFAULT); 1254126258Smlaier w->pfrw_astats++; 1255126258Smlaier } 1256126258Smlaier break; 1257126258Smlaier case PFRW_POOL_GET: 1258126258Smlaier if (ke->pfrke_not) 1259126258Smlaier break; /* negative entries are ignored */ 1260126258Smlaier if (!w->pfrw_cnt--) { 1261126258Smlaier w->pfrw_kentry = ke; 1262126258Smlaier return (1); /* finish search */ 1263126258Smlaier } 1264126258Smlaier break; 1265130613Smlaier case PFRW_DYNADDR_UPDATE: 1266130613Smlaier if (ke->pfrke_af == AF_INET) { 1267130613Smlaier if (w->pfrw_dyn->pfid_acnt4++ > 0) 1268130613Smlaier break; 1269223637Sbz#ifdef __FreeBSD__ 1270223637Sbz pfr_prepare_network(&V_pfr_mask, AF_INET, ke->pfrke_net); 1271223637Sbz#else 1272130613Smlaier pfr_prepare_network(&pfr_mask, AF_INET, ke->pfrke_net); 1273223637Sbz#endif 1274130613Smlaier w->pfrw_dyn->pfid_addr4 = *SUNION2PF( 1275130613Smlaier &ke->pfrke_sa, AF_INET); 1276130613Smlaier w->pfrw_dyn->pfid_mask4 = *SUNION2PF( 1277223637Sbz#ifdef __FreeBSD__ 1278223637Sbz &V_pfr_mask, AF_INET); 1279223637Sbz#else 1280130613Smlaier &pfr_mask, AF_INET); 1281223637Sbz#endif 1282145836Smlaier } else if (ke->pfrke_af == AF_INET6){ 1283130613Smlaier if (w->pfrw_dyn->pfid_acnt6++ > 0) 1284130613Smlaier break; 1285223637Sbz#ifdef __FreeBSD__ 1286223637Sbz pfr_prepare_network(&V_pfr_mask, AF_INET6, ke->pfrke_net); 1287223637Sbz#else 1288130613Smlaier pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net); 1289223637Sbz#endif 1290130613Smlaier w->pfrw_dyn->pfid_addr6 = *SUNION2PF( 1291130613Smlaier &ke->pfrke_sa, AF_INET6); 1292130613Smlaier w->pfrw_dyn->pfid_mask6 = *SUNION2PF( 1293223637Sbz#ifdef __FreeBSD__ 1294223637Sbz &V_pfr_mask, AF_INET6); 1295223637Sbz#else 1296130613Smlaier &pfr_mask, AF_INET6); 1297223637Sbz#endif 1298130613Smlaier } 1299130613Smlaier break; 1300126258Smlaier } 1301126258Smlaier return (0); 1302126258Smlaier} 1303126258Smlaier 1304126258Smlaierint 1305126258Smlaierpfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) 1306126258Smlaier{ 1307126258Smlaier struct pfr_ktableworkq workq; 1308126258Smlaier struct pfr_ktable *p; 1309223637Sbz int s, xdel = 0; 1310126258Smlaier 1311223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY | 1312223637Sbz PFR_FLAG_ALLRSETS); 1313145836Smlaier if (pfr_fix_anchor(filter->pfrt_anchor)) 1314145836Smlaier return (EINVAL); 1315126258Smlaier if (pfr_table_count(filter, flags) < 0) 1316126258Smlaier return (ENOENT); 1317126258Smlaier 1318126258Smlaier SLIST_INIT(&workq); 1319126258Smlaier RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 1320126258Smlaier if (pfr_skip_table(filter, p, flags)) 1321126258Smlaier continue; 1322130613Smlaier if (!strcmp(p->pfrkt_anchor, PF_RESERVED_ANCHOR)) 1323130613Smlaier continue; 1324126258Smlaier if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) 1325126258Smlaier continue; 1326126258Smlaier p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE; 1327126258Smlaier SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1328126258Smlaier xdel++; 1329126258Smlaier } 1330126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 1331126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1332126258Smlaier s = splsoftnet(); 1333126258Smlaier pfr_setflags_ktables(&workq); 1334126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1335126258Smlaier splx(s); 1336126258Smlaier } 1337126258Smlaier if (ndel != NULL) 1338126258Smlaier *ndel = xdel; 1339126258Smlaier return (0); 1340126258Smlaier} 1341126258Smlaier 1342126258Smlaierint 1343126258Smlaierpfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) 1344126258Smlaier{ 1345126258Smlaier struct pfr_ktableworkq addq, changeq; 1346126258Smlaier struct pfr_ktable *p, *q, *r, key; 1347223637Sbz int i, rv, s, xadd = 0; 1348145836Smlaier long tzero = time_second; 1349126258Smlaier 1350223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY); 1351126258Smlaier SLIST_INIT(&addq); 1352126258Smlaier SLIST_INIT(&changeq); 1353126258Smlaier for (i = 0; i < size; i++) { 1354223637Sbz if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags)) 1355126261Smlaier senderr(EFAULT); 1356130613Smlaier if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK, 1357130613Smlaier flags & PFR_FLAG_USERIOCTL)) 1358126258Smlaier senderr(EINVAL); 1359126258Smlaier key.pfrkt_flags |= PFR_TFLAG_ACTIVE; 1360126258Smlaier p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 1361126258Smlaier if (p == NULL) { 1362223637Sbz p = pfr_create_ktable(&key.pfrkt_t, tzero, 1, 1363223637Sbz !(flags & PFR_FLAG_USERIOCTL)); 1364126258Smlaier if (p == NULL) 1365126258Smlaier senderr(ENOMEM); 1366126258Smlaier SLIST_FOREACH(q, &addq, pfrkt_workq) { 1367126258Smlaier if (!pfr_ktable_compare(p, q)) 1368126258Smlaier goto _skip; 1369126258Smlaier } 1370126258Smlaier SLIST_INSERT_HEAD(&addq, p, pfrkt_workq); 1371126258Smlaier xadd++; 1372126258Smlaier if (!key.pfrkt_anchor[0]) 1373126258Smlaier goto _skip; 1374126258Smlaier 1375126258Smlaier /* find or create root table */ 1376126258Smlaier bzero(key.pfrkt_anchor, sizeof(key.pfrkt_anchor)); 1377126258Smlaier r = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 1378126258Smlaier if (r != NULL) { 1379126258Smlaier p->pfrkt_root = r; 1380126258Smlaier goto _skip; 1381126258Smlaier } 1382126258Smlaier SLIST_FOREACH(q, &addq, pfrkt_workq) { 1383126258Smlaier if (!pfr_ktable_compare(&key, q)) { 1384126258Smlaier p->pfrkt_root = q; 1385126258Smlaier goto _skip; 1386126258Smlaier } 1387126258Smlaier } 1388126258Smlaier key.pfrkt_flags = 0; 1389223637Sbz r = pfr_create_ktable(&key.pfrkt_t, 0, 1, 1390223637Sbz !(flags & PFR_FLAG_USERIOCTL)); 1391126258Smlaier if (r == NULL) 1392126258Smlaier senderr(ENOMEM); 1393126258Smlaier SLIST_INSERT_HEAD(&addq, r, pfrkt_workq); 1394126258Smlaier p->pfrkt_root = r; 1395126258Smlaier } else if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { 1396126258Smlaier SLIST_FOREACH(q, &changeq, pfrkt_workq) 1397126258Smlaier if (!pfr_ktable_compare(&key, q)) 1398126258Smlaier goto _skip; 1399126258Smlaier p->pfrkt_nflags = (p->pfrkt_flags & 1400126258Smlaier ~PFR_TFLAG_USRMASK) | key.pfrkt_flags; 1401126258Smlaier SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq); 1402126258Smlaier xadd++; 1403126258Smlaier } 1404126258Smlaier_skip: 1405126258Smlaier ; 1406126258Smlaier } 1407126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 1408126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1409126258Smlaier s = splsoftnet(); 1410126258Smlaier pfr_insert_ktables(&addq); 1411126258Smlaier pfr_setflags_ktables(&changeq); 1412126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1413126258Smlaier splx(s); 1414126258Smlaier } else 1415126258Smlaier pfr_destroy_ktables(&addq, 0); 1416126258Smlaier if (nadd != NULL) 1417126258Smlaier *nadd = xadd; 1418126258Smlaier return (0); 1419126258Smlaier_bad: 1420126258Smlaier pfr_destroy_ktables(&addq, 0); 1421126258Smlaier return (rv); 1422126258Smlaier} 1423126258Smlaier 1424126258Smlaierint 1425126258Smlaierpfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) 1426126258Smlaier{ 1427126258Smlaier struct pfr_ktableworkq workq; 1428126258Smlaier struct pfr_ktable *p, *q, key; 1429223637Sbz int i, s, xdel = 0; 1430126258Smlaier 1431223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY); 1432126258Smlaier SLIST_INIT(&workq); 1433126258Smlaier for (i = 0; i < size; i++) { 1434223637Sbz if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags)) 1435126261Smlaier return (EFAULT); 1436130613Smlaier if (pfr_validate_table(&key.pfrkt_t, 0, 1437130613Smlaier flags & PFR_FLAG_USERIOCTL)) 1438126258Smlaier return (EINVAL); 1439126258Smlaier p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 1440126258Smlaier if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { 1441126258Smlaier SLIST_FOREACH(q, &workq, pfrkt_workq) 1442126258Smlaier if (!pfr_ktable_compare(p, q)) 1443126258Smlaier goto _skip; 1444126258Smlaier p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE; 1445126258Smlaier SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1446126258Smlaier xdel++; 1447126258Smlaier } 1448126258Smlaier_skip: 1449126258Smlaier ; 1450126258Smlaier } 1451126258Smlaier 1452126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 1453126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1454126258Smlaier s = splsoftnet(); 1455126258Smlaier pfr_setflags_ktables(&workq); 1456126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1457126258Smlaier splx(s); 1458126258Smlaier } 1459126258Smlaier if (ndel != NULL) 1460126258Smlaier *ndel = xdel; 1461126258Smlaier return (0); 1462126258Smlaier} 1463126258Smlaier 1464126258Smlaierint 1465126258Smlaierpfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, 1466126258Smlaier int flags) 1467126258Smlaier{ 1468126258Smlaier struct pfr_ktable *p; 1469126258Smlaier int n, nn; 1470126258Smlaier 1471223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS); 1472145836Smlaier if (pfr_fix_anchor(filter->pfrt_anchor)) 1473145836Smlaier return (EINVAL); 1474126258Smlaier n = nn = pfr_table_count(filter, flags); 1475126258Smlaier if (n < 0) 1476126258Smlaier return (ENOENT); 1477126258Smlaier if (n > *size) { 1478126258Smlaier *size = n; 1479126258Smlaier return (0); 1480126258Smlaier } 1481126258Smlaier RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 1482126258Smlaier if (pfr_skip_table(filter, p, flags)) 1483126258Smlaier continue; 1484126258Smlaier if (n-- <= 0) 1485126258Smlaier continue; 1486223637Sbz if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl), flags)) 1487126261Smlaier return (EFAULT); 1488126258Smlaier } 1489126258Smlaier if (n) { 1490126258Smlaier printf("pfr_get_tables: corruption detected (%d).\n", n); 1491126258Smlaier return (ENOTTY); 1492126258Smlaier } 1493126258Smlaier *size = nn; 1494126258Smlaier return (0); 1495126258Smlaier} 1496126258Smlaier 1497126258Smlaierint 1498126258Smlaierpfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, 1499126258Smlaier int flags) 1500126258Smlaier{ 1501126258Smlaier struct pfr_ktable *p; 1502126258Smlaier struct pfr_ktableworkq workq; 1503223637Sbz int s, n, nn; 1504145836Smlaier long tzero = time_second; 1505126258Smlaier 1506223637Sbz /* XXX PFR_FLAG_CLSTATS disabled */ 1507223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_ALLRSETS); 1508145836Smlaier if (pfr_fix_anchor(filter->pfrt_anchor)) 1509145836Smlaier return (EINVAL); 1510126258Smlaier n = nn = pfr_table_count(filter, flags); 1511126258Smlaier if (n < 0) 1512126258Smlaier return (ENOENT); 1513126258Smlaier if (n > *size) { 1514126258Smlaier *size = n; 1515126258Smlaier return (0); 1516126258Smlaier } 1517126258Smlaier SLIST_INIT(&workq); 1518126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1519126258Smlaier s = splsoftnet(); 1520126258Smlaier RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 1521126258Smlaier if (pfr_skip_table(filter, p, flags)) 1522126258Smlaier continue; 1523126258Smlaier if (n-- <= 0) 1524126258Smlaier continue; 1525126258Smlaier if (!(flags & PFR_FLAG_ATOMIC)) 1526126258Smlaier s = splsoftnet(); 1527223637Sbz if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl), flags)) { 1528223637Sbz splx(s); 1529126261Smlaier return (EFAULT); 1530126261Smlaier } 1531126258Smlaier if (!(flags & PFR_FLAG_ATOMIC)) 1532126258Smlaier splx(s); 1533126258Smlaier SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1534126258Smlaier } 1535126258Smlaier if (flags & PFR_FLAG_CLSTATS) 1536126258Smlaier pfr_clstats_ktables(&workq, tzero, 1537126258Smlaier flags & PFR_FLAG_ADDRSTOO); 1538126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1539126258Smlaier splx(s); 1540126258Smlaier if (n) { 1541126258Smlaier printf("pfr_get_tstats: corruption detected (%d).\n", n); 1542126258Smlaier return (ENOTTY); 1543126258Smlaier } 1544126258Smlaier *size = nn; 1545126258Smlaier return (0); 1546126258Smlaier} 1547126258Smlaier 1548126258Smlaierint 1549126258Smlaierpfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) 1550126258Smlaier{ 1551126258Smlaier struct pfr_ktableworkq workq; 1552126258Smlaier struct pfr_ktable *p, key; 1553223637Sbz int i, s, xzero = 0; 1554145836Smlaier long tzero = time_second; 1555126258Smlaier 1556223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY | 1557223637Sbz PFR_FLAG_ADDRSTOO); 1558126258Smlaier SLIST_INIT(&workq); 1559126258Smlaier for (i = 0; i < size; i++) { 1560223637Sbz if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags)) 1561126261Smlaier return (EFAULT); 1562130613Smlaier if (pfr_validate_table(&key.pfrkt_t, 0, 0)) 1563126258Smlaier return (EINVAL); 1564126258Smlaier p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 1565126258Smlaier if (p != NULL) { 1566126258Smlaier SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1567126258Smlaier xzero++; 1568126258Smlaier } 1569126258Smlaier } 1570126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 1571126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1572126258Smlaier s = splsoftnet(); 1573126258Smlaier pfr_clstats_ktables(&workq, tzero, flags & PFR_FLAG_ADDRSTOO); 1574126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1575126258Smlaier splx(s); 1576126258Smlaier } 1577126258Smlaier if (nzero != NULL) 1578126258Smlaier *nzero = xzero; 1579126258Smlaier return (0); 1580126258Smlaier} 1581126258Smlaier 1582126258Smlaierint 1583126258Smlaierpfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag, 1584126258Smlaier int *nchange, int *ndel, int flags) 1585126258Smlaier{ 1586126258Smlaier struct pfr_ktableworkq workq; 1587126258Smlaier struct pfr_ktable *p, *q, key; 1588223637Sbz int i, s, xchange = 0, xdel = 0; 1589126258Smlaier 1590223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY); 1591126258Smlaier if ((setflag & ~PFR_TFLAG_USRMASK) || 1592126258Smlaier (clrflag & ~PFR_TFLAG_USRMASK) || 1593126258Smlaier (setflag & clrflag)) 1594126258Smlaier return (EINVAL); 1595126258Smlaier SLIST_INIT(&workq); 1596126258Smlaier for (i = 0; i < size; i++) { 1597223637Sbz if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags)) 1598126261Smlaier return (EFAULT); 1599130613Smlaier if (pfr_validate_table(&key.pfrkt_t, 0, 1600130613Smlaier flags & PFR_FLAG_USERIOCTL)) 1601126258Smlaier return (EINVAL); 1602126258Smlaier p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 1603126258Smlaier if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { 1604126258Smlaier p->pfrkt_nflags = (p->pfrkt_flags | setflag) & 1605126258Smlaier ~clrflag; 1606126258Smlaier if (p->pfrkt_nflags == p->pfrkt_flags) 1607126258Smlaier goto _skip; 1608126258Smlaier SLIST_FOREACH(q, &workq, pfrkt_workq) 1609126258Smlaier if (!pfr_ktable_compare(p, q)) 1610126258Smlaier goto _skip; 1611126258Smlaier SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1612126258Smlaier if ((p->pfrkt_flags & PFR_TFLAG_PERSIST) && 1613126258Smlaier (clrflag & PFR_TFLAG_PERSIST) && 1614126258Smlaier !(p->pfrkt_flags & PFR_TFLAG_REFERENCED)) 1615126258Smlaier xdel++; 1616126258Smlaier else 1617126258Smlaier xchange++; 1618126258Smlaier } 1619126258Smlaier_skip: 1620126258Smlaier ; 1621126258Smlaier } 1622126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 1623126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1624126258Smlaier s = splsoftnet(); 1625126258Smlaier pfr_setflags_ktables(&workq); 1626126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1627126258Smlaier splx(s); 1628126258Smlaier } 1629126258Smlaier if (nchange != NULL) 1630126258Smlaier *nchange = xchange; 1631126258Smlaier if (ndel != NULL) 1632126258Smlaier *ndel = xdel; 1633126258Smlaier return (0); 1634126258Smlaier} 1635126258Smlaier 1636126258Smlaierint 1637126258Smlaierpfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags) 1638126258Smlaier{ 1639126258Smlaier struct pfr_ktableworkq workq; 1640126258Smlaier struct pfr_ktable *p; 1641126258Smlaier struct pf_ruleset *rs; 1642126258Smlaier int xdel = 0; 1643126258Smlaier 1644223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 1645145836Smlaier rs = pf_find_or_create_ruleset(trs->pfrt_anchor); 1646126258Smlaier if (rs == NULL) 1647126258Smlaier return (ENOMEM); 1648126258Smlaier SLIST_INIT(&workq); 1649126258Smlaier RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 1650126258Smlaier if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || 1651126258Smlaier pfr_skip_table(trs, p, 0)) 1652126258Smlaier continue; 1653126258Smlaier p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE; 1654126258Smlaier SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1655126258Smlaier xdel++; 1656126258Smlaier } 1657126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 1658126258Smlaier pfr_setflags_ktables(&workq); 1659126258Smlaier if (ticket != NULL) 1660126258Smlaier *ticket = ++rs->tticket; 1661126258Smlaier rs->topen = 1; 1662126258Smlaier } else 1663126258Smlaier pf_remove_if_empty_ruleset(rs); 1664126258Smlaier if (ndel != NULL) 1665126258Smlaier *ndel = xdel; 1666126258Smlaier return (0); 1667126258Smlaier} 1668126258Smlaier 1669126258Smlaierint 1670126258Smlaierpfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, 1671126258Smlaier int *nadd, int *naddr, u_int32_t ticket, int flags) 1672126258Smlaier{ 1673126258Smlaier struct pfr_ktableworkq tableq; 1674126258Smlaier struct pfr_kentryworkq addrq; 1675126258Smlaier struct pfr_ktable *kt, *rt, *shadow, key; 1676126258Smlaier struct pfr_kentry *p; 1677126258Smlaier struct pfr_addr ad; 1678126258Smlaier struct pf_ruleset *rs; 1679126258Smlaier int i, rv, xadd = 0, xaddr = 0; 1680126258Smlaier 1681223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ADDRSTOO); 1682126258Smlaier if (size && !(flags & PFR_FLAG_ADDRSTOO)) 1683126258Smlaier return (EINVAL); 1684130613Smlaier if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK, 1685130613Smlaier flags & PFR_FLAG_USERIOCTL)) 1686126258Smlaier return (EINVAL); 1687145836Smlaier rs = pf_find_ruleset(tbl->pfrt_anchor); 1688126258Smlaier if (rs == NULL || !rs->topen || ticket != rs->tticket) 1689126258Smlaier return (EBUSY); 1690126258Smlaier tbl->pfrt_flags |= PFR_TFLAG_INACTIVE; 1691126258Smlaier SLIST_INIT(&tableq); 1692126258Smlaier kt = RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl); 1693126258Smlaier if (kt == NULL) { 1694223637Sbz kt = pfr_create_ktable(tbl, 0, 1, 1695223637Sbz !(flags & PFR_FLAG_USERIOCTL)); 1696126258Smlaier if (kt == NULL) 1697126258Smlaier return (ENOMEM); 1698126258Smlaier SLIST_INSERT_HEAD(&tableq, kt, pfrkt_workq); 1699126258Smlaier xadd++; 1700126258Smlaier if (!tbl->pfrt_anchor[0]) 1701126258Smlaier goto _skip; 1702126258Smlaier 1703126258Smlaier /* find or create root table */ 1704126258Smlaier bzero(&key, sizeof(key)); 1705126258Smlaier strlcpy(key.pfrkt_name, tbl->pfrt_name, sizeof(key.pfrkt_name)); 1706126258Smlaier rt = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 1707126258Smlaier if (rt != NULL) { 1708126258Smlaier kt->pfrkt_root = rt; 1709126258Smlaier goto _skip; 1710126258Smlaier } 1711223637Sbz rt = pfr_create_ktable(&key.pfrkt_t, 0, 1, 1712223637Sbz !(flags & PFR_FLAG_USERIOCTL)); 1713126258Smlaier if (rt == NULL) { 1714126258Smlaier pfr_destroy_ktables(&tableq, 0); 1715126258Smlaier return (ENOMEM); 1716126258Smlaier } 1717126258Smlaier SLIST_INSERT_HEAD(&tableq, rt, pfrkt_workq); 1718126258Smlaier kt->pfrkt_root = rt; 1719126258Smlaier } else if (!(kt->pfrkt_flags & PFR_TFLAG_INACTIVE)) 1720126258Smlaier xadd++; 1721126258Smlaier_skip: 1722223637Sbz shadow = pfr_create_ktable(tbl, 0, 0, !(flags & PFR_FLAG_USERIOCTL)); 1723126258Smlaier if (shadow == NULL) { 1724126258Smlaier pfr_destroy_ktables(&tableq, 0); 1725126258Smlaier return (ENOMEM); 1726126258Smlaier } 1727126258Smlaier SLIST_INIT(&addrq); 1728126258Smlaier for (i = 0; i < size; i++) { 1729223637Sbz if (COPYIN(addr+i, &ad, sizeof(ad), flags)) 1730126261Smlaier senderr(EFAULT); 1731126258Smlaier if (pfr_validate_addr(&ad)) 1732126258Smlaier senderr(EINVAL); 1733126258Smlaier if (pfr_lookup_addr(shadow, &ad, 1) != NULL) 1734126258Smlaier continue; 1735145836Smlaier p = pfr_create_kentry(&ad, 0); 1736126258Smlaier if (p == NULL) 1737126258Smlaier senderr(ENOMEM); 1738126258Smlaier if (pfr_route_kentry(shadow, p)) { 1739126258Smlaier pfr_destroy_kentry(p); 1740126258Smlaier continue; 1741126258Smlaier } 1742126258Smlaier SLIST_INSERT_HEAD(&addrq, p, pfrke_workq); 1743126258Smlaier xaddr++; 1744126258Smlaier } 1745126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 1746126258Smlaier if (kt->pfrkt_shadow != NULL) 1747126258Smlaier pfr_destroy_ktable(kt->pfrkt_shadow, 1); 1748126258Smlaier kt->pfrkt_flags |= PFR_TFLAG_INACTIVE; 1749126258Smlaier pfr_insert_ktables(&tableq); 1750126258Smlaier shadow->pfrkt_cnt = (flags & PFR_FLAG_ADDRSTOO) ? 1751126258Smlaier xaddr : NO_ADDRESSES; 1752126258Smlaier kt->pfrkt_shadow = shadow; 1753126258Smlaier } else { 1754126258Smlaier pfr_clean_node_mask(shadow, &addrq); 1755126258Smlaier pfr_destroy_ktable(shadow, 0); 1756126258Smlaier pfr_destroy_ktables(&tableq, 0); 1757126258Smlaier pfr_destroy_kentries(&addrq); 1758126258Smlaier } 1759126258Smlaier if (nadd != NULL) 1760126258Smlaier *nadd = xadd; 1761126258Smlaier if (naddr != NULL) 1762126258Smlaier *naddr = xaddr; 1763126258Smlaier return (0); 1764126258Smlaier_bad: 1765126258Smlaier pfr_destroy_ktable(shadow, 0); 1766126258Smlaier pfr_destroy_ktables(&tableq, 0); 1767126258Smlaier pfr_destroy_kentries(&addrq); 1768126258Smlaier return (rv); 1769126258Smlaier} 1770126258Smlaier 1771126258Smlaierint 1772130613Smlaierpfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags) 1773130613Smlaier{ 1774130613Smlaier struct pfr_ktableworkq workq; 1775130613Smlaier struct pfr_ktable *p; 1776130613Smlaier struct pf_ruleset *rs; 1777130613Smlaier int xdel = 0; 1778130613Smlaier 1779223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 1780145836Smlaier rs = pf_find_ruleset(trs->pfrt_anchor); 1781130613Smlaier if (rs == NULL || !rs->topen || ticket != rs->tticket) 1782130613Smlaier return (0); 1783130613Smlaier SLIST_INIT(&workq); 1784130613Smlaier RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 1785130613Smlaier if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || 1786130613Smlaier pfr_skip_table(trs, p, 0)) 1787130613Smlaier continue; 1788130613Smlaier p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE; 1789130613Smlaier SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1790130613Smlaier xdel++; 1791130613Smlaier } 1792130613Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 1793130613Smlaier pfr_setflags_ktables(&workq); 1794130613Smlaier rs->topen = 0; 1795130613Smlaier pf_remove_if_empty_ruleset(rs); 1796130613Smlaier } 1797130613Smlaier if (ndel != NULL) 1798130613Smlaier *ndel = xdel; 1799130613Smlaier return (0); 1800130613Smlaier} 1801130613Smlaier 1802130613Smlaierint 1803126258Smlaierpfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd, 1804126258Smlaier int *nchange, int flags) 1805126258Smlaier{ 1806145836Smlaier struct pfr_ktable *p, *q; 1807126258Smlaier struct pfr_ktableworkq workq; 1808126258Smlaier struct pf_ruleset *rs; 1809223637Sbz int s, xadd = 0, xchange = 0; 1810145836Smlaier long tzero = time_second; 1811126258Smlaier 1812223637Sbz ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY); 1813145836Smlaier rs = pf_find_ruleset(trs->pfrt_anchor); 1814126258Smlaier if (rs == NULL || !rs->topen || ticket != rs->tticket) 1815126258Smlaier return (EBUSY); 1816126258Smlaier 1817126258Smlaier SLIST_INIT(&workq); 1818126258Smlaier RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 1819126258Smlaier if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || 1820126258Smlaier pfr_skip_table(trs, p, 0)) 1821126258Smlaier continue; 1822126258Smlaier SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1823126258Smlaier if (p->pfrkt_flags & PFR_TFLAG_ACTIVE) 1824126258Smlaier xchange++; 1825126258Smlaier else 1826126258Smlaier xadd++; 1827126258Smlaier } 1828126258Smlaier 1829126258Smlaier if (!(flags & PFR_FLAG_DUMMY)) { 1830126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1831126258Smlaier s = splsoftnet(); 1832145836Smlaier for (p = SLIST_FIRST(&workq); p != NULL; p = q) { 1833145836Smlaier q = SLIST_NEXT(p, pfrkt_workq); 1834126258Smlaier pfr_commit_ktable(p, tzero); 1835145836Smlaier } 1836126258Smlaier if (flags & PFR_FLAG_ATOMIC) 1837126258Smlaier splx(s); 1838126258Smlaier rs->topen = 0; 1839126258Smlaier pf_remove_if_empty_ruleset(rs); 1840126258Smlaier } 1841126258Smlaier if (nadd != NULL) 1842126258Smlaier *nadd = xadd; 1843126258Smlaier if (nchange != NULL) 1844126258Smlaier *nchange = xchange; 1845126258Smlaier 1846126258Smlaier return (0); 1847126258Smlaier} 1848126258Smlaier 1849126258Smlaiervoid 1850126258Smlaierpfr_commit_ktable(struct pfr_ktable *kt, long tzero) 1851126258Smlaier{ 1852126258Smlaier struct pfr_ktable *shadow = kt->pfrkt_shadow; 1853126258Smlaier int nflags; 1854126258Smlaier 1855126258Smlaier if (shadow->pfrkt_cnt == NO_ADDRESSES) { 1856126258Smlaier if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 1857126258Smlaier pfr_clstats_ktable(kt, tzero, 1); 1858126258Smlaier } else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) { 1859126258Smlaier /* kt might contain addresses */ 1860126258Smlaier struct pfr_kentryworkq addrq, addq, changeq, delq, garbageq; 1861126258Smlaier struct pfr_kentry *p, *q, *next; 1862126258Smlaier struct pfr_addr ad; 1863126258Smlaier 1864126258Smlaier pfr_enqueue_addrs(shadow, &addrq, NULL, 0); 1865126258Smlaier pfr_mark_addrs(kt); 1866126258Smlaier SLIST_INIT(&addq); 1867126258Smlaier SLIST_INIT(&changeq); 1868126258Smlaier SLIST_INIT(&delq); 1869126258Smlaier SLIST_INIT(&garbageq); 1870126258Smlaier pfr_clean_node_mask(shadow, &addrq); 1871126258Smlaier for (p = SLIST_FIRST(&addrq); p != NULL; p = next) { 1872126258Smlaier next = SLIST_NEXT(p, pfrke_workq); /* XXX */ 1873126258Smlaier pfr_copyout_addr(&ad, p); 1874126258Smlaier q = pfr_lookup_addr(kt, &ad, 1); 1875126258Smlaier if (q != NULL) { 1876126258Smlaier if (q->pfrke_not != p->pfrke_not) 1877126258Smlaier SLIST_INSERT_HEAD(&changeq, q, 1878126258Smlaier pfrke_workq); 1879126258Smlaier q->pfrke_mark = 1; 1880126258Smlaier SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq); 1881126258Smlaier } else { 1882126258Smlaier p->pfrke_tzero = tzero; 1883126258Smlaier SLIST_INSERT_HEAD(&addq, p, pfrke_workq); 1884126258Smlaier } 1885126258Smlaier } 1886126258Smlaier pfr_enqueue_addrs(kt, &delq, NULL, ENQUEUE_UNMARKED_ONLY); 1887126258Smlaier pfr_insert_kentries(kt, &addq, tzero); 1888126258Smlaier pfr_remove_kentries(kt, &delq); 1889126258Smlaier pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG); 1890126258Smlaier pfr_destroy_kentries(&garbageq); 1891126258Smlaier } else { 1892126258Smlaier /* kt cannot contain addresses */ 1893126258Smlaier SWAP(struct radix_node_head *, kt->pfrkt_ip4, 1894126258Smlaier shadow->pfrkt_ip4); 1895126258Smlaier SWAP(struct radix_node_head *, kt->pfrkt_ip6, 1896126258Smlaier shadow->pfrkt_ip6); 1897126258Smlaier SWAP(int, kt->pfrkt_cnt, shadow->pfrkt_cnt); 1898126258Smlaier pfr_clstats_ktable(kt, tzero, 1); 1899126258Smlaier } 1900126258Smlaier nflags = ((shadow->pfrkt_flags & PFR_TFLAG_USRMASK) | 1901126258Smlaier (kt->pfrkt_flags & PFR_TFLAG_SETMASK) | PFR_TFLAG_ACTIVE) 1902126258Smlaier & ~PFR_TFLAG_INACTIVE; 1903126258Smlaier pfr_destroy_ktable(shadow, 0); 1904126258Smlaier kt->pfrkt_shadow = NULL; 1905126258Smlaier pfr_setflags_ktable(kt, nflags); 1906126258Smlaier} 1907126258Smlaier 1908126258Smlaierint 1909130613Smlaierpfr_validate_table(struct pfr_table *tbl, int allowedflags, int no_reserved) 1910126258Smlaier{ 1911126258Smlaier int i; 1912126258Smlaier 1913126258Smlaier if (!tbl->pfrt_name[0]) 1914126258Smlaier return (-1); 1915130613Smlaier if (no_reserved && !strcmp(tbl->pfrt_anchor, PF_RESERVED_ANCHOR)) 1916130613Smlaier return (-1); 1917126258Smlaier if (tbl->pfrt_name[PF_TABLE_NAME_SIZE-1]) 1918126258Smlaier return (-1); 1919126258Smlaier for (i = strlen(tbl->pfrt_name); i < PF_TABLE_NAME_SIZE; i++) 1920126258Smlaier if (tbl->pfrt_name[i]) 1921126258Smlaier return (-1); 1922145836Smlaier if (pfr_fix_anchor(tbl->pfrt_anchor)) 1923145836Smlaier return (-1); 1924126258Smlaier if (tbl->pfrt_flags & ~allowedflags) 1925126258Smlaier return (-1); 1926126258Smlaier return (0); 1927126258Smlaier} 1928126258Smlaier 1929145836Smlaier/* 1930145836Smlaier * Rewrite anchors referenced by tables to remove slashes 1931145836Smlaier * and check for validity. 1932145836Smlaier */ 1933126258Smlaierint 1934145836Smlaierpfr_fix_anchor(char *anchor) 1935145836Smlaier{ 1936145836Smlaier size_t siz = MAXPATHLEN; 1937145836Smlaier int i; 1938145836Smlaier 1939145836Smlaier if (anchor[0] == '/') { 1940145836Smlaier char *path; 1941145836Smlaier int off; 1942145836Smlaier 1943145836Smlaier path = anchor; 1944145836Smlaier off = 1; 1945145836Smlaier while (*++path == '/') 1946145836Smlaier off++; 1947145836Smlaier bcopy(path, anchor, siz - off); 1948145836Smlaier memset(anchor + siz - off, 0, off); 1949145836Smlaier } 1950145836Smlaier if (anchor[siz - 1]) 1951145836Smlaier return (-1); 1952145836Smlaier for (i = strlen(anchor); i < siz; i++) 1953145836Smlaier if (anchor[i]) 1954145836Smlaier return (-1); 1955145836Smlaier return (0); 1956145836Smlaier} 1957145836Smlaier 1958145836Smlaierint 1959126258Smlaierpfr_table_count(struct pfr_table *filter, int flags) 1960126258Smlaier{ 1961126258Smlaier struct pf_ruleset *rs; 1962126258Smlaier 1963126258Smlaier if (flags & PFR_FLAG_ALLRSETS) 1964126258Smlaier return (pfr_ktable_cnt); 1965145836Smlaier if (filter->pfrt_anchor[0]) { 1966145836Smlaier rs = pf_find_ruleset(filter->pfrt_anchor); 1967126258Smlaier return ((rs != NULL) ? rs->tables : -1); 1968126258Smlaier } 1969126258Smlaier return (pf_main_ruleset.tables); 1970126258Smlaier} 1971126258Smlaier 1972126258Smlaierint 1973126258Smlaierpfr_skip_table(struct pfr_table *filter, struct pfr_ktable *kt, int flags) 1974126258Smlaier{ 1975126258Smlaier if (flags & PFR_FLAG_ALLRSETS) 1976126258Smlaier return (0); 1977145836Smlaier if (strcmp(filter->pfrt_anchor, kt->pfrkt_anchor)) 1978126258Smlaier return (1); 1979126258Smlaier return (0); 1980126258Smlaier} 1981126258Smlaier 1982126258Smlaiervoid 1983126258Smlaierpfr_insert_ktables(struct pfr_ktableworkq *workq) 1984126258Smlaier{ 1985126258Smlaier struct pfr_ktable *p; 1986126258Smlaier 1987126258Smlaier SLIST_FOREACH(p, workq, pfrkt_workq) 1988126258Smlaier pfr_insert_ktable(p); 1989126258Smlaier} 1990126258Smlaier 1991126258Smlaiervoid 1992126258Smlaierpfr_insert_ktable(struct pfr_ktable *kt) 1993126258Smlaier{ 1994126258Smlaier RB_INSERT(pfr_ktablehead, &pfr_ktables, kt); 1995126258Smlaier pfr_ktable_cnt++; 1996126258Smlaier if (kt->pfrkt_root != NULL) 1997126258Smlaier if (!kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]++) 1998126258Smlaier pfr_setflags_ktable(kt->pfrkt_root, 1999126258Smlaier kt->pfrkt_root->pfrkt_flags|PFR_TFLAG_REFDANCHOR); 2000126258Smlaier} 2001126258Smlaier 2002126258Smlaiervoid 2003126258Smlaierpfr_setflags_ktables(struct pfr_ktableworkq *workq) 2004126258Smlaier{ 2005145836Smlaier struct pfr_ktable *p, *q; 2006126258Smlaier 2007145836Smlaier for (p = SLIST_FIRST(workq); p; p = q) { 2008145836Smlaier q = SLIST_NEXT(p, pfrkt_workq); 2009126258Smlaier pfr_setflags_ktable(p, p->pfrkt_nflags); 2010145836Smlaier } 2011126258Smlaier} 2012126258Smlaier 2013126258Smlaiervoid 2014126258Smlaierpfr_setflags_ktable(struct pfr_ktable *kt, int newf) 2015126258Smlaier{ 2016126258Smlaier struct pfr_kentryworkq addrq; 2017126258Smlaier 2018126258Smlaier if (!(newf & PFR_TFLAG_REFERENCED) && 2019126258Smlaier !(newf & PFR_TFLAG_PERSIST)) 2020126258Smlaier newf &= ~PFR_TFLAG_ACTIVE; 2021126258Smlaier if (!(newf & PFR_TFLAG_ACTIVE)) 2022126258Smlaier newf &= ~PFR_TFLAG_USRMASK; 2023126258Smlaier if (!(newf & PFR_TFLAG_SETMASK)) { 2024126258Smlaier RB_REMOVE(pfr_ktablehead, &pfr_ktables, kt); 2025126258Smlaier if (kt->pfrkt_root != NULL) 2026126258Smlaier if (!--kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]) 2027126258Smlaier pfr_setflags_ktable(kt->pfrkt_root, 2028126258Smlaier kt->pfrkt_root->pfrkt_flags & 2029126258Smlaier ~PFR_TFLAG_REFDANCHOR); 2030126258Smlaier pfr_destroy_ktable(kt, 1); 2031126258Smlaier pfr_ktable_cnt--; 2032126258Smlaier return; 2033126258Smlaier } 2034126258Smlaier if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) { 2035126258Smlaier pfr_enqueue_addrs(kt, &addrq, NULL, 0); 2036126258Smlaier pfr_remove_kentries(kt, &addrq); 2037126258Smlaier } 2038126258Smlaier if (!(newf & PFR_TFLAG_INACTIVE) && kt->pfrkt_shadow != NULL) { 2039126258Smlaier pfr_destroy_ktable(kt->pfrkt_shadow, 1); 2040126258Smlaier kt->pfrkt_shadow = NULL; 2041126258Smlaier } 2042126258Smlaier kt->pfrkt_flags = newf; 2043126258Smlaier} 2044126258Smlaier 2045126258Smlaiervoid 2046126258Smlaierpfr_clstats_ktables(struct pfr_ktableworkq *workq, long tzero, int recurse) 2047126258Smlaier{ 2048126258Smlaier struct pfr_ktable *p; 2049126258Smlaier 2050126258Smlaier SLIST_FOREACH(p, workq, pfrkt_workq) 2051126258Smlaier pfr_clstats_ktable(p, tzero, recurse); 2052126258Smlaier} 2053126258Smlaier 2054126258Smlaiervoid 2055126258Smlaierpfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse) 2056126258Smlaier{ 2057126258Smlaier struct pfr_kentryworkq addrq; 2058126258Smlaier int s; 2059126258Smlaier 2060126258Smlaier if (recurse) { 2061126258Smlaier pfr_enqueue_addrs(kt, &addrq, NULL, 0); 2062126258Smlaier pfr_clstats_kentries(&addrq, tzero, 0); 2063126258Smlaier } 2064126258Smlaier s = splsoftnet(); 2065126258Smlaier bzero(kt->pfrkt_packets, sizeof(kt->pfrkt_packets)); 2066126258Smlaier bzero(kt->pfrkt_bytes, sizeof(kt->pfrkt_bytes)); 2067126258Smlaier kt->pfrkt_match = kt->pfrkt_nomatch = 0; 2068126258Smlaier splx(s); 2069126258Smlaier kt->pfrkt_tzero = tzero; 2070126258Smlaier} 2071126258Smlaier 2072126258Smlaierstruct pfr_ktable * 2073223637Sbzpfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset, 2074223637Sbz int intr) 2075126258Smlaier{ 2076126258Smlaier struct pfr_ktable *kt; 2077126258Smlaier struct pf_ruleset *rs; 2078126258Smlaier 2079223637Sbz#ifdef __FreeBSD__ 2080238600Sglebius kt = pool_get(&V_pfr_ktable_pl, PR_NOWAIT|PR_ZERO); 2081223637Sbz#else 2082238600Sglebius if (intr) 2083223637Sbz kt = pool_get(&pfr_ktable_pl, PR_NOWAIT|PR_ZERO|PR_LIMITFAIL); 2084223637Sbz else 2085223637Sbz kt = pool_get(&pfr_ktable_pl, PR_WAITOK|PR_ZERO|PR_LIMITFAIL); 2086223637Sbz#endif 2087126258Smlaier if (kt == NULL) 2088126258Smlaier return (NULL); 2089126258Smlaier kt->pfrkt_t = *tbl; 2090126258Smlaier 2091126258Smlaier if (attachruleset) { 2092145836Smlaier rs = pf_find_or_create_ruleset(tbl->pfrt_anchor); 2093126258Smlaier if (!rs) { 2094126258Smlaier pfr_destroy_ktable(kt, 0); 2095126258Smlaier return (NULL); 2096126258Smlaier } 2097126258Smlaier kt->pfrkt_rs = rs; 2098126258Smlaier rs->tables++; 2099126258Smlaier } 2100126258Smlaier 2101126258Smlaier if (!rn_inithead((void **)&kt->pfrkt_ip4, 2102126258Smlaier offsetof(struct sockaddr_in, sin_addr) * 8) || 2103126258Smlaier !rn_inithead((void **)&kt->pfrkt_ip6, 2104126258Smlaier offsetof(struct sockaddr_in6, sin6_addr) * 8)) { 2105126258Smlaier pfr_destroy_ktable(kt, 0); 2106126258Smlaier return (NULL); 2107126258Smlaier } 2108126258Smlaier kt->pfrkt_tzero = tzero; 2109126258Smlaier 2110126258Smlaier return (kt); 2111126258Smlaier} 2112126258Smlaier 2113126258Smlaiervoid 2114126258Smlaierpfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr) 2115126258Smlaier{ 2116126258Smlaier struct pfr_ktable *p, *q; 2117126258Smlaier 2118126258Smlaier for (p = SLIST_FIRST(workq); p; p = q) { 2119126258Smlaier q = SLIST_NEXT(p, pfrkt_workq); 2120126258Smlaier pfr_destroy_ktable(p, flushaddr); 2121126258Smlaier } 2122126258Smlaier} 2123126258Smlaier 2124126258Smlaiervoid 2125126258Smlaierpfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr) 2126126258Smlaier{ 2127126258Smlaier struct pfr_kentryworkq addrq; 2128126258Smlaier 2129126258Smlaier if (flushaddr) { 2130126258Smlaier pfr_enqueue_addrs(kt, &addrq, NULL, 0); 2131126258Smlaier pfr_clean_node_mask(kt, &addrq); 2132126258Smlaier pfr_destroy_kentries(&addrq); 2133126258Smlaier } 2134126261Smlaier#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) 2135126261Smlaier if (kt->pfrkt_ip4 != NULL) { 2136126261Smlaier RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip4); 2137126261Smlaier free((caddr_t)kt->pfrkt_ip4, M_RTABLE); 2138126261Smlaier } 2139126261Smlaier if (kt->pfrkt_ip6 != NULL) { 2140126261Smlaier RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip6); 2141126261Smlaier free((caddr_t)kt->pfrkt_ip6, M_RTABLE); 2142126261Smlaier } 2143126261Smlaier#else 2144126258Smlaier if (kt->pfrkt_ip4 != NULL) 2145126258Smlaier free((caddr_t)kt->pfrkt_ip4, M_RTABLE); 2146126258Smlaier if (kt->pfrkt_ip6 != NULL) 2147126258Smlaier free((caddr_t)kt->pfrkt_ip6, M_RTABLE); 2148126261Smlaier#endif 2149126258Smlaier if (kt->pfrkt_shadow != NULL) 2150126258Smlaier pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr); 2151126258Smlaier if (kt->pfrkt_rs != NULL) { 2152126258Smlaier kt->pfrkt_rs->tables--; 2153126258Smlaier pf_remove_if_empty_ruleset(kt->pfrkt_rs); 2154126258Smlaier } 2155223637Sbz#ifdef __FreeBSD__ 2156223637Sbz pool_put(&V_pfr_ktable_pl, kt); 2157223637Sbz#else 2158126258Smlaier pool_put(&pfr_ktable_pl, kt); 2159223637Sbz#endif 2160126258Smlaier} 2161126258Smlaier 2162126258Smlaierint 2163126258Smlaierpfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q) 2164126258Smlaier{ 2165126258Smlaier int d; 2166126258Smlaier 2167126258Smlaier if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE))) 2168126258Smlaier return (d); 2169145836Smlaier return (strcmp(p->pfrkt_anchor, q->pfrkt_anchor)); 2170126258Smlaier} 2171126258Smlaier 2172126258Smlaierstruct pfr_ktable * 2173126258Smlaierpfr_lookup_table(struct pfr_table *tbl) 2174126258Smlaier{ 2175126258Smlaier /* struct pfr_ktable start like a struct pfr_table */ 2176130613Smlaier return (RB_FIND(pfr_ktablehead, &pfr_ktables, 2177130613Smlaier (struct pfr_ktable *)tbl)); 2178126258Smlaier} 2179126258Smlaier 2180126258Smlaierint 2181126258Smlaierpfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) 2182126258Smlaier{ 2183126258Smlaier struct pfr_kentry *ke = NULL; 2184126258Smlaier int match; 2185126258Smlaier 2186126258Smlaier if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 2187126258Smlaier kt = kt->pfrkt_root; 2188126258Smlaier if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 2189130613Smlaier return (0); 2190126258Smlaier 2191126258Smlaier switch (af) { 2192145836Smlaier#ifdef INET 2193126258Smlaier case AF_INET: 2194223637Sbz#ifdef __FreeBSD__ 2195223637Sbz V_pfr_sin.sin_addr.s_addr = a->addr32[0]; 2196223637Sbz ke = (struct pfr_kentry *)rn_match(&V_pfr_sin, kt->pfrkt_ip4); 2197223637Sbz#else 2198126258Smlaier pfr_sin.sin_addr.s_addr = a->addr32[0]; 2199126258Smlaier ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4); 2200223637Sbz#endif 2201126258Smlaier if (ke && KENTRY_RNF_ROOT(ke)) 2202126258Smlaier ke = NULL; 2203126258Smlaier break; 2204145836Smlaier#endif /* INET */ 2205145836Smlaier#ifdef INET6 2206126258Smlaier case AF_INET6: 2207223637Sbz#ifdef __FreeBSD__ 2208223637Sbz bcopy(a, &V_pfr_sin6.sin6_addr, sizeof(V_pfr_sin6.sin6_addr)); 2209223637Sbz ke = (struct pfr_kentry *)rn_match(&V_pfr_sin6, kt->pfrkt_ip6); 2210223637Sbz#else 2211126258Smlaier bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr)); 2212126258Smlaier ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6); 2213223637Sbz#endif 2214126258Smlaier if (ke && KENTRY_RNF_ROOT(ke)) 2215126258Smlaier ke = NULL; 2216126258Smlaier break; 2217145836Smlaier#endif /* INET6 */ 2218126258Smlaier } 2219126258Smlaier match = (ke && !ke->pfrke_not); 2220126258Smlaier if (match) 2221126258Smlaier kt->pfrkt_match++; 2222126258Smlaier else 2223126258Smlaier kt->pfrkt_nomatch++; 2224126258Smlaier return (match); 2225126258Smlaier} 2226126258Smlaier 2227126258Smlaiervoid 2228126258Smlaierpfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, 2229126258Smlaier u_int64_t len, int dir_out, int op_pass, int notrule) 2230126258Smlaier{ 2231126258Smlaier struct pfr_kentry *ke = NULL; 2232126258Smlaier 2233126258Smlaier if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 2234126258Smlaier kt = kt->pfrkt_root; 2235126258Smlaier if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 2236126258Smlaier return; 2237126258Smlaier 2238126258Smlaier switch (af) { 2239145836Smlaier#ifdef INET 2240126258Smlaier case AF_INET: 2241223637Sbz#ifdef __FreeBSD__ 2242223637Sbz V_pfr_sin.sin_addr.s_addr = a->addr32[0]; 2243223637Sbz ke = (struct pfr_kentry *)rn_match(&V_pfr_sin, kt->pfrkt_ip4); 2244223637Sbz#else 2245126258Smlaier pfr_sin.sin_addr.s_addr = a->addr32[0]; 2246126258Smlaier ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4); 2247223637Sbz#endif 2248126258Smlaier if (ke && KENTRY_RNF_ROOT(ke)) 2249126258Smlaier ke = NULL; 2250126258Smlaier break; 2251145836Smlaier#endif /* INET */ 2252145836Smlaier#ifdef INET6 2253126258Smlaier case AF_INET6: 2254223637Sbz#ifdef __FreeBSD__ 2255223637Sbz bcopy(a, &V_pfr_sin6.sin6_addr, sizeof(V_pfr_sin6.sin6_addr)); 2256223637Sbz ke = (struct pfr_kentry *)rn_match(&V_pfr_sin6, kt->pfrkt_ip6); 2257223637Sbz#else 2258126258Smlaier bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr)); 2259126258Smlaier ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6); 2260223637Sbz#endif 2261126258Smlaier if (ke && KENTRY_RNF_ROOT(ke)) 2262126258Smlaier ke = NULL; 2263126258Smlaier break; 2264145836Smlaier#endif /* INET6 */ 2265145836Smlaier default: 2266145836Smlaier ; 2267126258Smlaier } 2268126258Smlaier if ((ke == NULL || ke->pfrke_not) != notrule) { 2269126258Smlaier if (op_pass != PFR_OP_PASS) 2270126258Smlaier printf("pfr_update_stats: assertion failed.\n"); 2271126258Smlaier op_pass = PFR_OP_XPASS; 2272126258Smlaier } 2273126258Smlaier kt->pfrkt_packets[dir_out][op_pass]++; 2274126258Smlaier kt->pfrkt_bytes[dir_out][op_pass] += len; 2275223637Sbz if (ke != NULL && op_pass != PFR_OP_XPASS && 2276223637Sbz (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) { 2277223637Sbz if (ke->pfrke_counters == NULL) 2278223637Sbz#ifdef __FreeBSD__ 2279223637Sbz ke->pfrke_counters = pool_get(&V_pfr_kcounters_pl, 2280223637Sbz#else 2281223637Sbz ke->pfrke_counters = pool_get(&pfr_kcounters_pl, 2282223637Sbz#endif 2283223637Sbz PR_NOWAIT | PR_ZERO); 2284223637Sbz if (ke->pfrke_counters != NULL) { 2285223637Sbz ke->pfrke_counters->pfrkc_packets[dir_out][op_pass]++; 2286223637Sbz ke->pfrke_counters->pfrkc_bytes[dir_out][op_pass] += len; 2287223637Sbz } 2288126258Smlaier } 2289126258Smlaier} 2290126258Smlaier 2291126258Smlaierstruct pfr_ktable * 2292223637Sbzpfr_attach_table(struct pf_ruleset *rs, char *name, int intr) 2293126258Smlaier{ 2294126258Smlaier struct pfr_ktable *kt, *rt; 2295126258Smlaier struct pfr_table tbl; 2296126258Smlaier struct pf_anchor *ac = rs->anchor; 2297126258Smlaier 2298126258Smlaier bzero(&tbl, sizeof(tbl)); 2299126258Smlaier strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)); 2300145836Smlaier if (ac != NULL) 2301171168Smlaier strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor)); 2302126258Smlaier kt = pfr_lookup_table(&tbl); 2303126258Smlaier if (kt == NULL) { 2304223637Sbz kt = pfr_create_ktable(&tbl, time_second, 1, intr); 2305126258Smlaier if (kt == NULL) 2306126258Smlaier return (NULL); 2307126258Smlaier if (ac != NULL) { 2308126258Smlaier bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor)); 2309126258Smlaier rt = pfr_lookup_table(&tbl); 2310126258Smlaier if (rt == NULL) { 2311223637Sbz rt = pfr_create_ktable(&tbl, 0, 1, intr); 2312126258Smlaier if (rt == NULL) { 2313126258Smlaier pfr_destroy_ktable(kt, 0); 2314126258Smlaier return (NULL); 2315126258Smlaier } 2316126258Smlaier pfr_insert_ktable(rt); 2317126258Smlaier } 2318126258Smlaier kt->pfrkt_root = rt; 2319126258Smlaier } 2320126258Smlaier pfr_insert_ktable(kt); 2321126258Smlaier } 2322126258Smlaier if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++) 2323126258Smlaier pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED); 2324130613Smlaier return (kt); 2325126258Smlaier} 2326126258Smlaier 2327126258Smlaiervoid 2328126258Smlaierpfr_detach_table(struct pfr_ktable *kt) 2329126258Smlaier{ 2330126258Smlaier if (kt->pfrkt_refcnt[PFR_REFCNT_RULE] <= 0) 2331126258Smlaier printf("pfr_detach_table: refcount = %d.\n", 2332126258Smlaier kt->pfrkt_refcnt[PFR_REFCNT_RULE]); 2333126258Smlaier else if (!--kt->pfrkt_refcnt[PFR_REFCNT_RULE]) 2334126258Smlaier pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED); 2335126258Smlaier} 2336126258Smlaier 2337126258Smlaierint 2338126258Smlaierpfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, 2339126258Smlaier struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af) 2340126258Smlaier{ 2341223637Sbz#ifdef __FreeBSD__ 2342145836Smlaier struct pfr_kentry *ke, *ke2 = NULL; 2343145836Smlaier struct pf_addr *addr = NULL; 2344223637Sbz#else 2345223637Sbz struct pfr_kentry *ke, *ke2; 2346223637Sbz struct pf_addr *addr; 2347223637Sbz#endif 2348126258Smlaier union sockaddr_union mask; 2349126258Smlaier int idx = -1, use_counter = 0; 2350126258Smlaier 2351223637Sbz#ifdef __FreeBSD__ 2352145836Smlaier if (af == AF_INET) 2353223637Sbz addr = (struct pf_addr *)&V_pfr_sin.sin_addr; 2354223637Sbz else if (af == AF_INET6) 2355223637Sbz addr = (struct pf_addr *)&V_pfr_sin6.sin6_addr; 2356223637Sbz#else 2357223637Sbz if (af == AF_INET) 2358145836Smlaier addr = (struct pf_addr *)&pfr_sin.sin_addr; 2359145836Smlaier else if (af == AF_INET6) 2360145836Smlaier addr = (struct pf_addr *)&pfr_sin6.sin6_addr; 2361223637Sbz#endif 2362126258Smlaier if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 2363126258Smlaier kt = kt->pfrkt_root; 2364126258Smlaier if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 2365126258Smlaier return (-1); 2366126258Smlaier 2367126258Smlaier if (pidx != NULL) 2368126258Smlaier idx = *pidx; 2369126258Smlaier if (counter != NULL && idx >= 0) 2370126258Smlaier use_counter = 1; 2371126258Smlaier if (idx < 0) 2372126258Smlaier idx = 0; 2373126258Smlaier 2374126258Smlaier_next_block: 2375126258Smlaier ke = pfr_kentry_byidx(kt, idx, af); 2376223637Sbz if (ke == NULL) { 2377223637Sbz kt->pfrkt_nomatch++; 2378126258Smlaier return (1); 2379223637Sbz } 2380223637Sbz#ifdef __FreeBSD__ 2381223637Sbz pfr_prepare_network(&V_pfr_mask, af, ke->pfrke_net); 2382223637Sbz#else 2383126258Smlaier pfr_prepare_network(&pfr_mask, af, ke->pfrke_net); 2384223637Sbz#endif 2385126258Smlaier *raddr = SUNION2PF(&ke->pfrke_sa, af); 2386223637Sbz#ifdef __FreeBSD__ 2387223637Sbz *rmask = SUNION2PF(&V_pfr_mask, af); 2388223637Sbz#else 2389126258Smlaier *rmask = SUNION2PF(&pfr_mask, af); 2390223637Sbz#endif 2391126258Smlaier 2392126258Smlaier if (use_counter) { 2393126258Smlaier /* is supplied address within block? */ 2394126258Smlaier if (!PF_MATCHA(0, *raddr, *rmask, counter, af)) { 2395126258Smlaier /* no, go to next block in table */ 2396126258Smlaier idx++; 2397126258Smlaier use_counter = 0; 2398126258Smlaier goto _next_block; 2399126258Smlaier } 2400126258Smlaier PF_ACPY(addr, counter, af); 2401126258Smlaier } else { 2402126258Smlaier /* use first address of block */ 2403126258Smlaier PF_ACPY(addr, *raddr, af); 2404126258Smlaier } 2405126258Smlaier 2406126258Smlaier if (!KENTRY_NETWORK(ke)) { 2407126258Smlaier /* this is a single IP address - no possible nested block */ 2408126258Smlaier PF_ACPY(counter, addr, af); 2409126258Smlaier *pidx = idx; 2410223637Sbz kt->pfrkt_match++; 2411126258Smlaier return (0); 2412126258Smlaier } 2413126258Smlaier for (;;) { 2414126258Smlaier /* we don't want to use a nested block */ 2415223637Sbz#ifdef __FreeBSD__ 2416145836Smlaier if (af == AF_INET) 2417223637Sbz ke2 = (struct pfr_kentry *)rn_match(&V_pfr_sin, 2418223637Sbz kt->pfrkt_ip4); 2419223637Sbz else if (af == AF_INET6) 2420223637Sbz ke2 = (struct pfr_kentry *)rn_match(&V_pfr_sin6, 2421223637Sbz kt->pfrkt_ip6); 2422223637Sbz#else 2423223637Sbz if (af == AF_INET) 2424145836Smlaier ke2 = (struct pfr_kentry *)rn_match(&pfr_sin, 2425145836Smlaier kt->pfrkt_ip4); 2426145836Smlaier else if (af == AF_INET6) 2427145836Smlaier ke2 = (struct pfr_kentry *)rn_match(&pfr_sin6, 2428145836Smlaier kt->pfrkt_ip6); 2429223637Sbz#endif 2430126258Smlaier /* no need to check KENTRY_RNF_ROOT() here */ 2431126258Smlaier if (ke2 == ke) { 2432126258Smlaier /* lookup return the same block - perfect */ 2433126258Smlaier PF_ACPY(counter, addr, af); 2434126258Smlaier *pidx = idx; 2435223637Sbz kt->pfrkt_match++; 2436126258Smlaier return (0); 2437126258Smlaier } 2438126258Smlaier 2439126258Smlaier /* we need to increase the counter past the nested block */ 2440126258Smlaier pfr_prepare_network(&mask, AF_INET, ke2->pfrke_net); 2441223637Sbz#ifdef __FreeBSD__ 2442223637Sbz PF_POOLMASK(addr, addr, SUNION2PF(&mask, af), &V_pfr_ffaddr, af); 2443223637Sbz#else 2444126258Smlaier PF_POOLMASK(addr, addr, SUNION2PF(&mask, af), &pfr_ffaddr, af); 2445223637Sbz#endif 2446126258Smlaier PF_AINC(addr, af); 2447126258Smlaier if (!PF_MATCHA(0, *raddr, *rmask, addr, af)) { 2448126258Smlaier /* ok, we reached the end of our main block */ 2449126258Smlaier /* go to next block in table */ 2450126258Smlaier idx++; 2451126258Smlaier use_counter = 0; 2452126258Smlaier goto _next_block; 2453126258Smlaier } 2454126258Smlaier } 2455126258Smlaier} 2456126258Smlaier 2457126258Smlaierstruct pfr_kentry * 2458126258Smlaierpfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af) 2459126258Smlaier{ 2460126258Smlaier struct pfr_walktree w; 2461126258Smlaier 2462130613Smlaier bzero(&w, sizeof(w)); 2463130613Smlaier w.pfrw_op = PFRW_POOL_GET; 2464130613Smlaier w.pfrw_cnt = idx; 2465126258Smlaier 2466130613Smlaier switch (af) { 2467145836Smlaier#ifdef INET 2468126258Smlaier case AF_INET: 2469127145Smlaier#ifdef __FreeBSD__ 2470126261Smlaier kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 2471126261Smlaier#else 2472126258Smlaier rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 2473126261Smlaier#endif 2474130613Smlaier return (w.pfrw_kentry); 2475145836Smlaier#endif /* INET */ 2476145836Smlaier#ifdef INET6 2477126258Smlaier case AF_INET6: 2478127145Smlaier#ifdef __FreeBSD__ 2479126261Smlaier kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); 2480126261Smlaier#else 2481126258Smlaier rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); 2482126261Smlaier#endif 2483130613Smlaier return (w.pfrw_kentry); 2484145836Smlaier#endif /* INET6 */ 2485126258Smlaier default: 2486130613Smlaier return (NULL); 2487126258Smlaier } 2488126258Smlaier} 2489130613Smlaier 2490130613Smlaiervoid 2491130613Smlaierpfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn) 2492130613Smlaier{ 2493130613Smlaier struct pfr_walktree w; 2494130613Smlaier int s; 2495130613Smlaier 2496130613Smlaier bzero(&w, sizeof(w)); 2497130613Smlaier w.pfrw_op = PFRW_DYNADDR_UPDATE; 2498130613Smlaier w.pfrw_dyn = dyn; 2499130613Smlaier 2500130613Smlaier s = splsoftnet(); 2501130613Smlaier dyn->pfid_acnt4 = 0; 2502130613Smlaier dyn->pfid_acnt6 = 0; 2503130613Smlaier if (!dyn->pfid_af || dyn->pfid_af == AF_INET) 2504130613Smlaier#ifdef __FreeBSD__ 2505130613Smlaier kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 2506130613Smlaier#else 2507130613Smlaier rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 2508130613Smlaier#endif 2509130613Smlaier if (!dyn->pfid_af || dyn->pfid_af == AF_INET6) 2510130613Smlaier#ifdef __FreeBSD__ 2511130613Smlaier kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); 2512130613Smlaier#else 2513130613Smlaier rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); 2514130613Smlaier#endif 2515130613Smlaier splx(s); 2516130613Smlaier} 2517