1d8aa10ccSGleb Smirnoff /*- 23b3a8eb9SGleb Smirnoff * Copyright (c) 2002 Cedric Berger 33b3a8eb9SGleb Smirnoff * All rights reserved. 43b3a8eb9SGleb Smirnoff * 53b3a8eb9SGleb Smirnoff * Redistribution and use in source and binary forms, with or without 63b3a8eb9SGleb Smirnoff * modification, are permitted provided that the following conditions 73b3a8eb9SGleb Smirnoff * are met: 83b3a8eb9SGleb Smirnoff * 93b3a8eb9SGleb Smirnoff * - Redistributions of source code must retain the above copyright 103b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer. 113b3a8eb9SGleb Smirnoff * - Redistributions in binary form must reproduce the above 123b3a8eb9SGleb Smirnoff * copyright notice, this list of conditions and the following 133b3a8eb9SGleb Smirnoff * disclaimer in the documentation and/or other materials provided 143b3a8eb9SGleb Smirnoff * with the distribution. 153b3a8eb9SGleb Smirnoff * 163b3a8eb9SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173b3a8eb9SGleb Smirnoff * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183b3a8eb9SGleb Smirnoff * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 193b3a8eb9SGleb Smirnoff * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 203b3a8eb9SGleb Smirnoff * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 213b3a8eb9SGleb Smirnoff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 223b3a8eb9SGleb Smirnoff * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 233b3a8eb9SGleb Smirnoff * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 243b3a8eb9SGleb Smirnoff * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 253b3a8eb9SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 263b3a8eb9SGleb Smirnoff * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 273b3a8eb9SGleb Smirnoff * POSSIBILITY OF SUCH DAMAGE. 283b3a8eb9SGleb Smirnoff * 29d8aa10ccSGleb Smirnoff * $OpenBSD: pf_table.c,v 1.79 2008/10/08 06:24:50 mcbride Exp $ 303b3a8eb9SGleb Smirnoff */ 313b3a8eb9SGleb Smirnoff 323b3a8eb9SGleb Smirnoff #include <sys/cdefs.h> 333b3a8eb9SGleb Smirnoff __FBSDID("$FreeBSD$"); 343b3a8eb9SGleb Smirnoff 353b3a8eb9SGleb Smirnoff #include "opt_inet.h" 363b3a8eb9SGleb Smirnoff #include "opt_inet6.h" 373b3a8eb9SGleb Smirnoff 383b3a8eb9SGleb Smirnoff #include <sys/param.h> 393b3a8eb9SGleb Smirnoff #include <sys/kernel.h> 403b3a8eb9SGleb Smirnoff #include <sys/lock.h> 413b3a8eb9SGleb Smirnoff #include <sys/malloc.h> 42eedc7fd9SGleb Smirnoff #include <sys/mbuf.h> 433b3a8eb9SGleb Smirnoff #include <sys/mutex.h> 443b3a8eb9SGleb Smirnoff #include <sys/refcount.h> 453b3a8eb9SGleb Smirnoff #include <sys/rwlock.h> 463b3a8eb9SGleb Smirnoff #include <sys/socket.h> 473b3a8eb9SGleb Smirnoff #include <vm/uma.h> 483b3a8eb9SGleb Smirnoff 493b3a8eb9SGleb Smirnoff #include <net/if.h> 503b3a8eb9SGleb Smirnoff #include <net/vnet.h> 513b3a8eb9SGleb Smirnoff #include <net/pfvar.h> 523b3a8eb9SGleb Smirnoff 533b3a8eb9SGleb Smirnoff #define ACCEPT_FLAGS(flags, oklist) \ 543b3a8eb9SGleb Smirnoff do { \ 553b3a8eb9SGleb Smirnoff if ((flags & ~(oklist)) & \ 563b3a8eb9SGleb Smirnoff PFR_FLAG_ALLMASK) \ 573b3a8eb9SGleb Smirnoff return (EINVAL); \ 583b3a8eb9SGleb Smirnoff } while (0) 593b3a8eb9SGleb Smirnoff 603b3a8eb9SGleb Smirnoff #define FILLIN_SIN(sin, addr) \ 613b3a8eb9SGleb Smirnoff do { \ 623b3a8eb9SGleb Smirnoff (sin).sin_len = sizeof(sin); \ 633b3a8eb9SGleb Smirnoff (sin).sin_family = AF_INET; \ 643b3a8eb9SGleb Smirnoff (sin).sin_addr = (addr); \ 653b3a8eb9SGleb Smirnoff } while (0) 663b3a8eb9SGleb Smirnoff 673b3a8eb9SGleb Smirnoff #define FILLIN_SIN6(sin6, addr) \ 683b3a8eb9SGleb Smirnoff do { \ 693b3a8eb9SGleb Smirnoff (sin6).sin6_len = sizeof(sin6); \ 703b3a8eb9SGleb Smirnoff (sin6).sin6_family = AF_INET6; \ 713b3a8eb9SGleb Smirnoff (sin6).sin6_addr = (addr); \ 723b3a8eb9SGleb Smirnoff } while (0) 733b3a8eb9SGleb Smirnoff 743b3a8eb9SGleb Smirnoff #define SWAP(type, a1, a2) \ 753b3a8eb9SGleb Smirnoff do { \ 763b3a8eb9SGleb Smirnoff type tmp = a1; \ 773b3a8eb9SGleb Smirnoff a1 = a2; \ 783b3a8eb9SGleb Smirnoff a2 = tmp; \ 793b3a8eb9SGleb Smirnoff } while (0) 803b3a8eb9SGleb Smirnoff 813b3a8eb9SGleb Smirnoff #define SUNION2PF(su, af) (((af)==AF_INET) ? \ 823b3a8eb9SGleb Smirnoff (struct pf_addr *)&(su)->sin.sin_addr : \ 833b3a8eb9SGleb Smirnoff (struct pf_addr *)&(su)->sin6.sin6_addr) 843b3a8eb9SGleb Smirnoff 853b3a8eb9SGleb Smirnoff #define AF_BITS(af) (((af)==AF_INET)?32:128) 863b3a8eb9SGleb Smirnoff #define ADDR_NETWORK(ad) ((ad)->pfra_net < AF_BITS((ad)->pfra_af)) 873b3a8eb9SGleb Smirnoff #define KENTRY_NETWORK(ke) ((ke)->pfrke_net < AF_BITS((ke)->pfrke_af)) 883b3a8eb9SGleb Smirnoff #define KENTRY_RNF_ROOT(ke) \ 893b3a8eb9SGleb Smirnoff ((((struct radix_node *)(ke))->rn_flags & RNF_ROOT) != 0) 903b3a8eb9SGleb Smirnoff 913b3a8eb9SGleb Smirnoff #define NO_ADDRESSES (-1) 923b3a8eb9SGleb Smirnoff #define ENQUEUE_UNMARKED_ONLY (1) 933b3a8eb9SGleb Smirnoff #define INVERT_NEG_FLAG (1) 943b3a8eb9SGleb Smirnoff 953b3a8eb9SGleb Smirnoff struct pfr_walktree { 963b3a8eb9SGleb Smirnoff enum pfrw_op { 973b3a8eb9SGleb Smirnoff PFRW_MARK, 983b3a8eb9SGleb Smirnoff PFRW_SWEEP, 993b3a8eb9SGleb Smirnoff PFRW_ENQUEUE, 1003b3a8eb9SGleb Smirnoff PFRW_GET_ADDRS, 1013b3a8eb9SGleb Smirnoff PFRW_GET_ASTATS, 1023b3a8eb9SGleb Smirnoff PFRW_POOL_GET, 1033b3a8eb9SGleb Smirnoff PFRW_DYNADDR_UPDATE 1043b3a8eb9SGleb Smirnoff } pfrw_op; 1053b3a8eb9SGleb Smirnoff union { 1063b3a8eb9SGleb Smirnoff struct pfr_addr *pfrw1_addr; 1073b3a8eb9SGleb Smirnoff struct pfr_astats *pfrw1_astats; 1083b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *pfrw1_workq; 1093b3a8eb9SGleb Smirnoff struct pfr_kentry *pfrw1_kentry; 1103b3a8eb9SGleb Smirnoff struct pfi_dynaddr *pfrw1_dyn; 1113b3a8eb9SGleb Smirnoff } pfrw_1; 1123b3a8eb9SGleb Smirnoff int pfrw_free; 1133b3a8eb9SGleb Smirnoff }; 1143b3a8eb9SGleb Smirnoff #define pfrw_addr pfrw_1.pfrw1_addr 1153b3a8eb9SGleb Smirnoff #define pfrw_astats pfrw_1.pfrw1_astats 1163b3a8eb9SGleb Smirnoff #define pfrw_workq pfrw_1.pfrw1_workq 1173b3a8eb9SGleb Smirnoff #define pfrw_kentry pfrw_1.pfrw1_kentry 1183b3a8eb9SGleb Smirnoff #define pfrw_dyn pfrw_1.pfrw1_dyn 1193b3a8eb9SGleb Smirnoff #define pfrw_cnt pfrw_free 1203b3a8eb9SGleb Smirnoff 1213b3a8eb9SGleb Smirnoff #define senderr(e) do { rv = (e); goto _bad; } while (0) 1223b3a8eb9SGleb Smirnoff 1233b3a8eb9SGleb Smirnoff static MALLOC_DEFINE(M_PFTABLE, "pf_table", "pf(4) tables structures"); 1243b3a8eb9SGleb Smirnoff static VNET_DEFINE(uma_zone_t, pfr_kentry_z); 1253b3a8eb9SGleb Smirnoff #define V_pfr_kentry_z VNET(pfr_kentry_z) 1263b3a8eb9SGleb Smirnoff static VNET_DEFINE(uma_zone_t, pfr_kcounters_z); 1273b3a8eb9SGleb Smirnoff #define V_pfr_kcounters_z VNET(pfr_kcounters_z) 1283b3a8eb9SGleb Smirnoff 1293b3a8eb9SGleb Smirnoff static struct pf_addr pfr_ffaddr = { 1303b3a8eb9SGleb Smirnoff .addr32 = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } 1313b3a8eb9SGleb Smirnoff }; 1323b3a8eb9SGleb Smirnoff 1333b3a8eb9SGleb Smirnoff static void pfr_copyout_addr(struct pfr_addr *, 1343b3a8eb9SGleb Smirnoff struct pfr_kentry *ke); 1353b3a8eb9SGleb Smirnoff static int pfr_validate_addr(struct pfr_addr *); 1363b3a8eb9SGleb Smirnoff static void pfr_enqueue_addrs(struct pfr_ktable *, 1373b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *, int *, int); 1383b3a8eb9SGleb Smirnoff static void pfr_mark_addrs(struct pfr_ktable *); 1393b3a8eb9SGleb Smirnoff static struct pfr_kentry 1403b3a8eb9SGleb Smirnoff *pfr_lookup_addr(struct pfr_ktable *, 1413b3a8eb9SGleb Smirnoff struct pfr_addr *, int); 1423b3a8eb9SGleb Smirnoff static struct pfr_kentry *pfr_create_kentry(struct pfr_addr *); 1433b3a8eb9SGleb Smirnoff static void pfr_destroy_kentries(struct pfr_kentryworkq *); 1443b3a8eb9SGleb Smirnoff static void pfr_destroy_kentry(struct pfr_kentry *); 1453b3a8eb9SGleb Smirnoff static void pfr_insert_kentries(struct pfr_ktable *, 1463b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *, long); 1473b3a8eb9SGleb Smirnoff static void pfr_remove_kentries(struct pfr_ktable *, 1483b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *); 1493b3a8eb9SGleb Smirnoff static void pfr_clstats_kentries(struct pfr_kentryworkq *, long, 1503b3a8eb9SGleb Smirnoff int); 1513b3a8eb9SGleb Smirnoff static void pfr_reset_feedback(struct pfr_addr *, int); 1523b3a8eb9SGleb Smirnoff static void pfr_prepare_network(union sockaddr_union *, int, int); 1533b3a8eb9SGleb Smirnoff static int pfr_route_kentry(struct pfr_ktable *, 1543b3a8eb9SGleb Smirnoff struct pfr_kentry *); 1553b3a8eb9SGleb Smirnoff static int pfr_unroute_kentry(struct pfr_ktable *, 1563b3a8eb9SGleb Smirnoff struct pfr_kentry *); 1573b3a8eb9SGleb Smirnoff static int pfr_walktree(struct radix_node *, void *); 1583b3a8eb9SGleb Smirnoff static int pfr_validate_table(struct pfr_table *, int, int); 1593b3a8eb9SGleb Smirnoff static int pfr_fix_anchor(char *); 1603b3a8eb9SGleb Smirnoff static void pfr_commit_ktable(struct pfr_ktable *, long); 1613b3a8eb9SGleb Smirnoff static void pfr_insert_ktables(struct pfr_ktableworkq *); 1623b3a8eb9SGleb Smirnoff static void pfr_insert_ktable(struct pfr_ktable *); 1633b3a8eb9SGleb Smirnoff static void pfr_setflags_ktables(struct pfr_ktableworkq *); 1643b3a8eb9SGleb Smirnoff static void pfr_setflags_ktable(struct pfr_ktable *, int); 1653b3a8eb9SGleb Smirnoff static void pfr_clstats_ktables(struct pfr_ktableworkq *, long, 1663b3a8eb9SGleb Smirnoff int); 1673b3a8eb9SGleb Smirnoff static void pfr_clstats_ktable(struct pfr_ktable *, long, int); 1683b3a8eb9SGleb Smirnoff static struct pfr_ktable 1693b3a8eb9SGleb Smirnoff *pfr_create_ktable(struct pfr_table *, long, int); 1703b3a8eb9SGleb Smirnoff static void pfr_destroy_ktables(struct pfr_ktableworkq *, int); 1713b3a8eb9SGleb Smirnoff static void pfr_destroy_ktable(struct pfr_ktable *, int); 1723b3a8eb9SGleb Smirnoff static int pfr_ktable_compare(struct pfr_ktable *, 1733b3a8eb9SGleb Smirnoff struct pfr_ktable *); 1743b3a8eb9SGleb Smirnoff static struct pfr_ktable 1753b3a8eb9SGleb Smirnoff *pfr_lookup_table(struct pfr_table *); 1763b3a8eb9SGleb Smirnoff static void pfr_clean_node_mask(struct pfr_ktable *, 1773b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *); 1783b3a8eb9SGleb Smirnoff static int pfr_table_count(struct pfr_table *, int); 1793b3a8eb9SGleb Smirnoff static int pfr_skip_table(struct pfr_table *, 1803b3a8eb9SGleb Smirnoff struct pfr_ktable *, int); 1813b3a8eb9SGleb Smirnoff static struct pfr_kentry 1823b3a8eb9SGleb Smirnoff *pfr_kentry_byidx(struct pfr_ktable *, int, int); 1833b3a8eb9SGleb Smirnoff 1843b3a8eb9SGleb Smirnoff static RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); 1853b3a8eb9SGleb Smirnoff static RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); 1863b3a8eb9SGleb Smirnoff 1873b3a8eb9SGleb Smirnoff struct pfr_ktablehead pfr_ktables; 1883b3a8eb9SGleb Smirnoff struct pfr_table pfr_nulltable; 1893b3a8eb9SGleb Smirnoff int pfr_ktable_cnt; 1903b3a8eb9SGleb Smirnoff 1913b3a8eb9SGleb Smirnoff void 1923b3a8eb9SGleb Smirnoff pfr_initialize(void) 1933b3a8eb9SGleb Smirnoff { 1943b3a8eb9SGleb Smirnoff 1953b3a8eb9SGleb Smirnoff V_pfr_kentry_z = uma_zcreate("pf table entries", 1963b3a8eb9SGleb Smirnoff sizeof(struct pfr_kentry), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 1973b3a8eb9SGleb Smirnoff 0); 1983b3a8eb9SGleb Smirnoff V_pfr_kcounters_z = uma_zcreate("pf table counters", 1993b3a8eb9SGleb Smirnoff sizeof(struct pfr_kcounters), NULL, NULL, NULL, NULL, 2003b3a8eb9SGleb Smirnoff UMA_ALIGN_PTR, 0); 2013b3a8eb9SGleb Smirnoff V_pf_limits[PF_LIMIT_TABLE_ENTRIES].zone = V_pfr_kentry_z; 2023b3a8eb9SGleb Smirnoff V_pf_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT; 2033b3a8eb9SGleb Smirnoff } 2043b3a8eb9SGleb Smirnoff 2053b3a8eb9SGleb Smirnoff void 2063b3a8eb9SGleb Smirnoff pfr_cleanup(void) 2073b3a8eb9SGleb Smirnoff { 2083b3a8eb9SGleb Smirnoff 2093b3a8eb9SGleb Smirnoff uma_zdestroy(V_pfr_kentry_z); 2103b3a8eb9SGleb Smirnoff uma_zdestroy(V_pfr_kcounters_z); 2113b3a8eb9SGleb Smirnoff } 2123b3a8eb9SGleb Smirnoff 2133b3a8eb9SGleb Smirnoff int 2143b3a8eb9SGleb Smirnoff pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) 2153b3a8eb9SGleb Smirnoff { 2163b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 2173b3a8eb9SGleb Smirnoff struct pfr_kentryworkq workq; 2183b3a8eb9SGleb Smirnoff 2193b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 2203b3a8eb9SGleb Smirnoff 2213b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 2223b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 2233b3a8eb9SGleb Smirnoff return (EINVAL); 2243b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 2253b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 2263b3a8eb9SGleb Smirnoff return (ESRCH); 2273b3a8eb9SGleb Smirnoff if (kt->pfrkt_flags & PFR_TFLAG_CONST) 2283b3a8eb9SGleb Smirnoff return (EPERM); 2293b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &workq, ndel, 0); 2303b3a8eb9SGleb Smirnoff 2313b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 2323b3a8eb9SGleb Smirnoff pfr_remove_kentries(kt, &workq); 2333b3a8eb9SGleb Smirnoff KASSERT(kt->pfrkt_cnt == 0, ("%s: non-null pfrkt_cnt", __func__)); 2343b3a8eb9SGleb Smirnoff } 2353b3a8eb9SGleb Smirnoff return (0); 2363b3a8eb9SGleb Smirnoff } 2373b3a8eb9SGleb Smirnoff 2383b3a8eb9SGleb Smirnoff int 2393b3a8eb9SGleb Smirnoff pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 2403b3a8eb9SGleb Smirnoff int *nadd, int flags) 2413b3a8eb9SGleb Smirnoff { 2423b3a8eb9SGleb Smirnoff struct pfr_ktable *kt, *tmpkt; 2433b3a8eb9SGleb Smirnoff struct pfr_kentryworkq workq; 2443b3a8eb9SGleb Smirnoff struct pfr_kentry *p, *q; 2453b3a8eb9SGleb Smirnoff struct pfr_addr *ad; 2463b3a8eb9SGleb Smirnoff int i, rv, xadd = 0; 2473b3a8eb9SGleb Smirnoff long tzero = time_second; 2483b3a8eb9SGleb Smirnoff 2493b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 2503b3a8eb9SGleb Smirnoff 2513b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK); 2523b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 2533b3a8eb9SGleb Smirnoff return (EINVAL); 2543b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 2553b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 2563b3a8eb9SGleb Smirnoff return (ESRCH); 2573b3a8eb9SGleb Smirnoff if (kt->pfrkt_flags & PFR_TFLAG_CONST) 2583b3a8eb9SGleb Smirnoff return (EPERM); 2593b3a8eb9SGleb Smirnoff tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0); 2603b3a8eb9SGleb Smirnoff if (tmpkt == NULL) 2613b3a8eb9SGleb Smirnoff return (ENOMEM); 2623b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 2633b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) { 2643b3a8eb9SGleb Smirnoff if (pfr_validate_addr(ad)) 2653b3a8eb9SGleb Smirnoff senderr(EINVAL); 2663b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, ad, 1); 2673b3a8eb9SGleb Smirnoff q = pfr_lookup_addr(tmpkt, ad, 1); 2683b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) { 2693b3a8eb9SGleb Smirnoff if (q != NULL) 2703b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_DUPLICATE; 2713b3a8eb9SGleb Smirnoff else if (p == NULL) 2723b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_ADDED; 2733b3a8eb9SGleb Smirnoff else if (p->pfrke_not != ad->pfra_not) 2743b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_CONFLICT; 2753b3a8eb9SGleb Smirnoff else 2763b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_NONE; 2773b3a8eb9SGleb Smirnoff } 2783b3a8eb9SGleb Smirnoff if (p == NULL && q == NULL) { 2793b3a8eb9SGleb Smirnoff p = pfr_create_kentry(ad); 2803b3a8eb9SGleb Smirnoff if (p == NULL) 2813b3a8eb9SGleb Smirnoff senderr(ENOMEM); 2823b3a8eb9SGleb Smirnoff if (pfr_route_kentry(tmpkt, p)) { 2833b3a8eb9SGleb Smirnoff pfr_destroy_kentry(p); 2843b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_NONE; 2853b3a8eb9SGleb Smirnoff } else { 2863b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrke_workq); 2873b3a8eb9SGleb Smirnoff xadd++; 2883b3a8eb9SGleb Smirnoff } 2893b3a8eb9SGleb Smirnoff } 2903b3a8eb9SGleb Smirnoff } 2913b3a8eb9SGleb Smirnoff pfr_clean_node_mask(tmpkt, &workq); 2923b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 2933b3a8eb9SGleb Smirnoff pfr_insert_kentries(kt, &workq, tzero); 2943b3a8eb9SGleb Smirnoff else 2953b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&workq); 2963b3a8eb9SGleb Smirnoff if (nadd != NULL) 2973b3a8eb9SGleb Smirnoff *nadd = xadd; 2983b3a8eb9SGleb Smirnoff pfr_destroy_ktable(tmpkt, 0); 2993b3a8eb9SGleb Smirnoff return (0); 3003b3a8eb9SGleb Smirnoff _bad: 3013b3a8eb9SGleb Smirnoff pfr_clean_node_mask(tmpkt, &workq); 3023b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&workq); 3033b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) 3043b3a8eb9SGleb Smirnoff pfr_reset_feedback(addr, size); 3053b3a8eb9SGleb Smirnoff pfr_destroy_ktable(tmpkt, 0); 3063b3a8eb9SGleb Smirnoff return (rv); 3073b3a8eb9SGleb Smirnoff } 3083b3a8eb9SGleb Smirnoff 3093b3a8eb9SGleb Smirnoff int 3103b3a8eb9SGleb Smirnoff pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 3113b3a8eb9SGleb Smirnoff int *ndel, int flags) 3123b3a8eb9SGleb Smirnoff { 3133b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 3143b3a8eb9SGleb Smirnoff struct pfr_kentryworkq workq; 3153b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 3163b3a8eb9SGleb Smirnoff struct pfr_addr *ad; 3173b3a8eb9SGleb Smirnoff int i, rv, xdel = 0, log = 1; 3183b3a8eb9SGleb Smirnoff 3193b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 3203b3a8eb9SGleb Smirnoff 3213b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK); 3223b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 3233b3a8eb9SGleb Smirnoff return (EINVAL); 3243b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 3253b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 3263b3a8eb9SGleb Smirnoff return (ESRCH); 3273b3a8eb9SGleb Smirnoff if (kt->pfrkt_flags & PFR_TFLAG_CONST) 3283b3a8eb9SGleb Smirnoff return (EPERM); 3293b3a8eb9SGleb Smirnoff /* 3303b3a8eb9SGleb Smirnoff * there are two algorithms to choose from here. 3313b3a8eb9SGleb Smirnoff * with: 3323b3a8eb9SGleb Smirnoff * n: number of addresses to delete 3333b3a8eb9SGleb Smirnoff * N: number of addresses in the table 3343b3a8eb9SGleb Smirnoff * 3353b3a8eb9SGleb Smirnoff * one is O(N) and is better for large 'n' 3363b3a8eb9SGleb Smirnoff * one is O(n*LOG(N)) and is better for small 'n' 3373b3a8eb9SGleb Smirnoff * 3383b3a8eb9SGleb Smirnoff * following code try to decide which one is best. 3393b3a8eb9SGleb Smirnoff */ 3403b3a8eb9SGleb Smirnoff for (i = kt->pfrkt_cnt; i > 0; i >>= 1) 3413b3a8eb9SGleb Smirnoff log++; 3423b3a8eb9SGleb Smirnoff if (size > kt->pfrkt_cnt/log) { 3433b3a8eb9SGleb Smirnoff /* full table scan */ 3443b3a8eb9SGleb Smirnoff pfr_mark_addrs(kt); 3453b3a8eb9SGleb Smirnoff } else { 3463b3a8eb9SGleb Smirnoff /* iterate over addresses to delete */ 3473b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) { 3483b3a8eb9SGleb Smirnoff if (pfr_validate_addr(ad)) 3493b3a8eb9SGleb Smirnoff return (EINVAL); 3503b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, ad, 1); 3513b3a8eb9SGleb Smirnoff if (p != NULL) 3523b3a8eb9SGleb Smirnoff p->pfrke_mark = 0; 3533b3a8eb9SGleb Smirnoff } 3543b3a8eb9SGleb Smirnoff } 3553b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 3563b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) { 3573b3a8eb9SGleb Smirnoff if (pfr_validate_addr(ad)) 3583b3a8eb9SGleb Smirnoff senderr(EINVAL); 3593b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, ad, 1); 3603b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) { 3613b3a8eb9SGleb Smirnoff if (p == NULL) 3623b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_NONE; 3633b3a8eb9SGleb Smirnoff else if (p->pfrke_not != ad->pfra_not) 3643b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_CONFLICT; 3653b3a8eb9SGleb Smirnoff else if (p->pfrke_mark) 3663b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_DUPLICATE; 3673b3a8eb9SGleb Smirnoff else 3683b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_DELETED; 3693b3a8eb9SGleb Smirnoff } 3703b3a8eb9SGleb Smirnoff if (p != NULL && p->pfrke_not == ad->pfra_not && 3713b3a8eb9SGleb Smirnoff !p->pfrke_mark) { 3723b3a8eb9SGleb Smirnoff p->pfrke_mark = 1; 3733b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrke_workq); 3743b3a8eb9SGleb Smirnoff xdel++; 3753b3a8eb9SGleb Smirnoff } 3763b3a8eb9SGleb Smirnoff } 3773b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 3783b3a8eb9SGleb Smirnoff pfr_remove_kentries(kt, &workq); 3793b3a8eb9SGleb Smirnoff if (ndel != NULL) 3803b3a8eb9SGleb Smirnoff *ndel = xdel; 3813b3a8eb9SGleb Smirnoff return (0); 3823b3a8eb9SGleb Smirnoff _bad: 3833b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) 3843b3a8eb9SGleb Smirnoff pfr_reset_feedback(addr, size); 3853b3a8eb9SGleb Smirnoff return (rv); 3863b3a8eb9SGleb Smirnoff } 3873b3a8eb9SGleb Smirnoff 3883b3a8eb9SGleb Smirnoff int 3893b3a8eb9SGleb Smirnoff pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 3903b3a8eb9SGleb Smirnoff int *size2, int *nadd, int *ndel, int *nchange, int flags, 3913b3a8eb9SGleb Smirnoff u_int32_t ignore_pfrt_flags) 3923b3a8eb9SGleb Smirnoff { 3933b3a8eb9SGleb Smirnoff struct pfr_ktable *kt, *tmpkt; 3943b3a8eb9SGleb Smirnoff struct pfr_kentryworkq addq, delq, changeq; 3953b3a8eb9SGleb Smirnoff struct pfr_kentry *p, *q; 3963b3a8eb9SGleb Smirnoff struct pfr_addr ad; 3973b3a8eb9SGleb Smirnoff int i, rv, xadd = 0, xdel = 0, xchange = 0; 3983b3a8eb9SGleb Smirnoff long tzero = time_second; 3993b3a8eb9SGleb Smirnoff 4003b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 4013b3a8eb9SGleb Smirnoff 4023b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK); 4033b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, ignore_pfrt_flags, flags & 4043b3a8eb9SGleb Smirnoff PFR_FLAG_USERIOCTL)) 4053b3a8eb9SGleb Smirnoff return (EINVAL); 4063b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 4073b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 4083b3a8eb9SGleb Smirnoff return (ESRCH); 4093b3a8eb9SGleb Smirnoff if (kt->pfrkt_flags & PFR_TFLAG_CONST) 4103b3a8eb9SGleb Smirnoff return (EPERM); 4113b3a8eb9SGleb Smirnoff tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0); 4123b3a8eb9SGleb Smirnoff if (tmpkt == NULL) 4133b3a8eb9SGleb Smirnoff return (ENOMEM); 4143b3a8eb9SGleb Smirnoff pfr_mark_addrs(kt); 4153b3a8eb9SGleb Smirnoff SLIST_INIT(&addq); 4163b3a8eb9SGleb Smirnoff SLIST_INIT(&delq); 4173b3a8eb9SGleb Smirnoff SLIST_INIT(&changeq); 4183b3a8eb9SGleb Smirnoff for (i = 0; i < size; i++) { 4193b3a8eb9SGleb Smirnoff /* 4203b3a8eb9SGleb Smirnoff * XXXGL: undertand pf_if usage of this function 4213b3a8eb9SGleb Smirnoff * and make ad a moving pointer 4223b3a8eb9SGleb Smirnoff */ 4233b3a8eb9SGleb Smirnoff bcopy(addr + i, &ad, sizeof(ad)); 4243b3a8eb9SGleb Smirnoff if (pfr_validate_addr(&ad)) 4253b3a8eb9SGleb Smirnoff senderr(EINVAL); 4263b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_NONE; 4273b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, &ad, 1); 4283b3a8eb9SGleb Smirnoff if (p != NULL) { 4293b3a8eb9SGleb Smirnoff if (p->pfrke_mark) { 4303b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_DUPLICATE; 4313b3a8eb9SGleb Smirnoff goto _skip; 4323b3a8eb9SGleb Smirnoff } 4333b3a8eb9SGleb Smirnoff p->pfrke_mark = 1; 4343b3a8eb9SGleb Smirnoff if (p->pfrke_not != ad.pfra_not) { 4353b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&changeq, p, pfrke_workq); 4363b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_CHANGED; 4373b3a8eb9SGleb Smirnoff xchange++; 4383b3a8eb9SGleb Smirnoff } 4393b3a8eb9SGleb Smirnoff } else { 4403b3a8eb9SGleb Smirnoff q = pfr_lookup_addr(tmpkt, &ad, 1); 4413b3a8eb9SGleb Smirnoff if (q != NULL) { 4423b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_DUPLICATE; 4433b3a8eb9SGleb Smirnoff goto _skip; 4443b3a8eb9SGleb Smirnoff } 4453b3a8eb9SGleb Smirnoff p = pfr_create_kentry(&ad); 4463b3a8eb9SGleb Smirnoff if (p == NULL) 4473b3a8eb9SGleb Smirnoff senderr(ENOMEM); 4483b3a8eb9SGleb Smirnoff if (pfr_route_kentry(tmpkt, p)) { 4493b3a8eb9SGleb Smirnoff pfr_destroy_kentry(p); 4503b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_NONE; 4513b3a8eb9SGleb Smirnoff } else { 4523b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&addq, p, pfrke_workq); 4533b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_ADDED; 4543b3a8eb9SGleb Smirnoff xadd++; 4553b3a8eb9SGleb Smirnoff } 4563b3a8eb9SGleb Smirnoff } 4573b3a8eb9SGleb Smirnoff _skip: 4583b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) 4593b3a8eb9SGleb Smirnoff bcopy(&ad, addr + i, sizeof(ad)); 4603b3a8eb9SGleb Smirnoff } 4613b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY); 4623b3a8eb9SGleb Smirnoff if ((flags & PFR_FLAG_FEEDBACK) && *size2) { 4633b3a8eb9SGleb Smirnoff if (*size2 < size+xdel) { 4643b3a8eb9SGleb Smirnoff *size2 = size+xdel; 4653b3a8eb9SGleb Smirnoff senderr(0); 4663b3a8eb9SGleb Smirnoff } 4673b3a8eb9SGleb Smirnoff i = 0; 4683b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, &delq, pfrke_workq) { 4693b3a8eb9SGleb Smirnoff pfr_copyout_addr(&ad, p); 4703b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_DELETED; 4713b3a8eb9SGleb Smirnoff bcopy(&ad, addr + size + i, sizeof(ad)); 4723b3a8eb9SGleb Smirnoff i++; 4733b3a8eb9SGleb Smirnoff } 4743b3a8eb9SGleb Smirnoff } 4753b3a8eb9SGleb Smirnoff pfr_clean_node_mask(tmpkt, &addq); 4763b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 4773b3a8eb9SGleb Smirnoff pfr_insert_kentries(kt, &addq, tzero); 4783b3a8eb9SGleb Smirnoff pfr_remove_kentries(kt, &delq); 4793b3a8eb9SGleb Smirnoff pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG); 4803b3a8eb9SGleb Smirnoff } else 4813b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&addq); 4823b3a8eb9SGleb Smirnoff if (nadd != NULL) 4833b3a8eb9SGleb Smirnoff *nadd = xadd; 4843b3a8eb9SGleb Smirnoff if (ndel != NULL) 4853b3a8eb9SGleb Smirnoff *ndel = xdel; 4863b3a8eb9SGleb Smirnoff if (nchange != NULL) 4873b3a8eb9SGleb Smirnoff *nchange = xchange; 4883b3a8eb9SGleb Smirnoff if ((flags & PFR_FLAG_FEEDBACK) && size2) 4893b3a8eb9SGleb Smirnoff *size2 = size+xdel; 4903b3a8eb9SGleb Smirnoff pfr_destroy_ktable(tmpkt, 0); 4913b3a8eb9SGleb Smirnoff return (0); 4923b3a8eb9SGleb Smirnoff _bad: 4933b3a8eb9SGleb Smirnoff pfr_clean_node_mask(tmpkt, &addq); 4943b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&addq); 4953b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) 4963b3a8eb9SGleb Smirnoff pfr_reset_feedback(addr, size); 4973b3a8eb9SGleb Smirnoff pfr_destroy_ktable(tmpkt, 0); 4983b3a8eb9SGleb Smirnoff return (rv); 4993b3a8eb9SGleb Smirnoff } 5003b3a8eb9SGleb Smirnoff 5013b3a8eb9SGleb Smirnoff int 5023b3a8eb9SGleb Smirnoff pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 5033b3a8eb9SGleb Smirnoff int *nmatch, int flags) 5043b3a8eb9SGleb Smirnoff { 5053b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 5063b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 5073b3a8eb9SGleb Smirnoff struct pfr_addr *ad; 5083b3a8eb9SGleb Smirnoff int i, xmatch = 0; 5093b3a8eb9SGleb Smirnoff 5103b3a8eb9SGleb Smirnoff PF_RULES_RASSERT(); 5113b3a8eb9SGleb Smirnoff 5123b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_REPLACE); 5133b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, 0)) 5143b3a8eb9SGleb Smirnoff return (EINVAL); 5153b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 5163b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 5173b3a8eb9SGleb Smirnoff return (ESRCH); 5183b3a8eb9SGleb Smirnoff 5193b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) { 5203b3a8eb9SGleb Smirnoff if (pfr_validate_addr(ad)) 5213b3a8eb9SGleb Smirnoff return (EINVAL); 5223b3a8eb9SGleb Smirnoff if (ADDR_NETWORK(ad)) 5233b3a8eb9SGleb Smirnoff return (EINVAL); 5243b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, ad, 0); 5253b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_REPLACE) 5263b3a8eb9SGleb Smirnoff pfr_copyout_addr(ad, p); 5273b3a8eb9SGleb Smirnoff ad->pfra_fback = (p == NULL) ? PFR_FB_NONE : 5283b3a8eb9SGleb Smirnoff (p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH); 5293b3a8eb9SGleb Smirnoff if (p != NULL && !p->pfrke_not) 5303b3a8eb9SGleb Smirnoff xmatch++; 5313b3a8eb9SGleb Smirnoff } 5323b3a8eb9SGleb Smirnoff if (nmatch != NULL) 5333b3a8eb9SGleb Smirnoff *nmatch = xmatch; 5343b3a8eb9SGleb Smirnoff return (0); 5353b3a8eb9SGleb Smirnoff } 5363b3a8eb9SGleb Smirnoff 5373b3a8eb9SGleb Smirnoff int 5383b3a8eb9SGleb Smirnoff pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, 5393b3a8eb9SGleb Smirnoff int flags) 5403b3a8eb9SGleb Smirnoff { 5413b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 5423b3a8eb9SGleb Smirnoff struct pfr_walktree w; 5433b3a8eb9SGleb Smirnoff int rv; 5443b3a8eb9SGleb Smirnoff 5453b3a8eb9SGleb Smirnoff PF_RULES_RASSERT(); 5463b3a8eb9SGleb Smirnoff 5473b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, 0); 5483b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, 0)) 5493b3a8eb9SGleb Smirnoff return (EINVAL); 5503b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 5513b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 5523b3a8eb9SGleb Smirnoff return (ESRCH); 5533b3a8eb9SGleb Smirnoff if (kt->pfrkt_cnt > *size) { 5543b3a8eb9SGleb Smirnoff *size = kt->pfrkt_cnt; 5553b3a8eb9SGleb Smirnoff return (0); 5563b3a8eb9SGleb Smirnoff } 5573b3a8eb9SGleb Smirnoff 5583b3a8eb9SGleb Smirnoff bzero(&w, sizeof(w)); 5593b3a8eb9SGleb Smirnoff w.pfrw_op = PFRW_GET_ADDRS; 5603b3a8eb9SGleb Smirnoff w.pfrw_addr = addr; 5613b3a8eb9SGleb Smirnoff w.pfrw_free = kt->pfrkt_cnt; 5623b3a8eb9SGleb Smirnoff rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 5633b3a8eb9SGleb Smirnoff if (!rv) 5643b3a8eb9SGleb Smirnoff rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, 5653b3a8eb9SGleb Smirnoff &w); 5663b3a8eb9SGleb Smirnoff if (rv) 5673b3a8eb9SGleb Smirnoff return (rv); 5683b3a8eb9SGleb Smirnoff 5693b3a8eb9SGleb Smirnoff KASSERT(w.pfrw_free == 0, ("%s: corruption detected (%d)", __func__, 5703b3a8eb9SGleb Smirnoff w.pfrw_free)); 5713b3a8eb9SGleb Smirnoff 5723b3a8eb9SGleb Smirnoff *size = kt->pfrkt_cnt; 5733b3a8eb9SGleb Smirnoff return (0); 5743b3a8eb9SGleb Smirnoff } 5753b3a8eb9SGleb Smirnoff 5763b3a8eb9SGleb Smirnoff int 5773b3a8eb9SGleb Smirnoff pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, 5783b3a8eb9SGleb Smirnoff int flags) 5793b3a8eb9SGleb Smirnoff { 5803b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 5813b3a8eb9SGleb Smirnoff struct pfr_walktree w; 5823b3a8eb9SGleb Smirnoff struct pfr_kentryworkq workq; 5833b3a8eb9SGleb Smirnoff int rv; 5843b3a8eb9SGleb Smirnoff long tzero = time_second; 5853b3a8eb9SGleb Smirnoff 5863b3a8eb9SGleb Smirnoff PF_RULES_RASSERT(); 5873b3a8eb9SGleb Smirnoff 5883b3a8eb9SGleb Smirnoff /* XXX PFR_FLAG_CLSTATS disabled */ 5893b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, 0); 5903b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, 0)) 5913b3a8eb9SGleb Smirnoff return (EINVAL); 5923b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 5933b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 5943b3a8eb9SGleb Smirnoff return (ESRCH); 5953b3a8eb9SGleb Smirnoff if (kt->pfrkt_cnt > *size) { 5963b3a8eb9SGleb Smirnoff *size = kt->pfrkt_cnt; 5973b3a8eb9SGleb Smirnoff return (0); 5983b3a8eb9SGleb Smirnoff } 5993b3a8eb9SGleb Smirnoff 6003b3a8eb9SGleb Smirnoff bzero(&w, sizeof(w)); 6013b3a8eb9SGleb Smirnoff w.pfrw_op = PFRW_GET_ASTATS; 6023b3a8eb9SGleb Smirnoff w.pfrw_astats = addr; 6033b3a8eb9SGleb Smirnoff w.pfrw_free = kt->pfrkt_cnt; 6043b3a8eb9SGleb Smirnoff rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 6053b3a8eb9SGleb Smirnoff if (!rv) 6063b3a8eb9SGleb Smirnoff rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, 6073b3a8eb9SGleb Smirnoff &w); 6083b3a8eb9SGleb Smirnoff if (!rv && (flags & PFR_FLAG_CLSTATS)) { 6093b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &workq, NULL, 0); 6103b3a8eb9SGleb Smirnoff pfr_clstats_kentries(&workq, tzero, 0); 6113b3a8eb9SGleb Smirnoff } 6123b3a8eb9SGleb Smirnoff if (rv) 6133b3a8eb9SGleb Smirnoff return (rv); 6143b3a8eb9SGleb Smirnoff 6153b3a8eb9SGleb Smirnoff if (w.pfrw_free) { 6163b3a8eb9SGleb Smirnoff printf("pfr_get_astats: corruption detected (%d).\n", 6173b3a8eb9SGleb Smirnoff w.pfrw_free); 6183b3a8eb9SGleb Smirnoff return (ENOTTY); 6193b3a8eb9SGleb Smirnoff } 6203b3a8eb9SGleb Smirnoff *size = kt->pfrkt_cnt; 6213b3a8eb9SGleb Smirnoff return (0); 6223b3a8eb9SGleb Smirnoff } 6233b3a8eb9SGleb Smirnoff 6243b3a8eb9SGleb Smirnoff int 6253b3a8eb9SGleb Smirnoff pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, 6263b3a8eb9SGleb Smirnoff int *nzero, int flags) 6273b3a8eb9SGleb Smirnoff { 6283b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 6293b3a8eb9SGleb Smirnoff struct pfr_kentryworkq workq; 6303b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 6313b3a8eb9SGleb Smirnoff struct pfr_addr *ad; 6323b3a8eb9SGleb Smirnoff int i, rv, xzero = 0; 6333b3a8eb9SGleb Smirnoff 6343b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 6353b3a8eb9SGleb Smirnoff 6363b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK); 6373b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, 0)) 6383b3a8eb9SGleb Smirnoff return (EINVAL); 6393b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 6403b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 6413b3a8eb9SGleb Smirnoff return (ESRCH); 6423b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 6433b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) { 6443b3a8eb9SGleb Smirnoff if (pfr_validate_addr(ad)) 6453b3a8eb9SGleb Smirnoff senderr(EINVAL); 6463b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, ad, 1); 6473b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) { 6483b3a8eb9SGleb Smirnoff ad->pfra_fback = (p != NULL) ? 6493b3a8eb9SGleb Smirnoff PFR_FB_CLEARED : PFR_FB_NONE; 6503b3a8eb9SGleb Smirnoff } 6513b3a8eb9SGleb Smirnoff if (p != NULL) { 6523b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrke_workq); 6533b3a8eb9SGleb Smirnoff xzero++; 6543b3a8eb9SGleb Smirnoff } 6553b3a8eb9SGleb Smirnoff } 6563b3a8eb9SGleb Smirnoff 6573b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 6583b3a8eb9SGleb Smirnoff pfr_clstats_kentries(&workq, 0, 0); 6593b3a8eb9SGleb Smirnoff if (nzero != NULL) 6603b3a8eb9SGleb Smirnoff *nzero = xzero; 6613b3a8eb9SGleb Smirnoff return (0); 6623b3a8eb9SGleb Smirnoff _bad: 6633b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) 6643b3a8eb9SGleb Smirnoff pfr_reset_feedback(addr, size); 6653b3a8eb9SGleb Smirnoff return (rv); 6663b3a8eb9SGleb Smirnoff } 6673b3a8eb9SGleb Smirnoff 6683b3a8eb9SGleb Smirnoff static int 6693b3a8eb9SGleb Smirnoff pfr_validate_addr(struct pfr_addr *ad) 6703b3a8eb9SGleb Smirnoff { 6713b3a8eb9SGleb Smirnoff int i; 6723b3a8eb9SGleb Smirnoff 6733b3a8eb9SGleb Smirnoff switch (ad->pfra_af) { 6743b3a8eb9SGleb Smirnoff #ifdef INET 6753b3a8eb9SGleb Smirnoff case AF_INET: 6763b3a8eb9SGleb Smirnoff if (ad->pfra_net > 32) 6773b3a8eb9SGleb Smirnoff return (-1); 6783b3a8eb9SGleb Smirnoff break; 6793b3a8eb9SGleb Smirnoff #endif /* INET */ 6803b3a8eb9SGleb Smirnoff #ifdef INET6 6813b3a8eb9SGleb Smirnoff case AF_INET6: 6823b3a8eb9SGleb Smirnoff if (ad->pfra_net > 128) 6833b3a8eb9SGleb Smirnoff return (-1); 6843b3a8eb9SGleb Smirnoff break; 6853b3a8eb9SGleb Smirnoff #endif /* INET6 */ 6863b3a8eb9SGleb Smirnoff default: 6873b3a8eb9SGleb Smirnoff return (-1); 6883b3a8eb9SGleb Smirnoff } 6893b3a8eb9SGleb Smirnoff if (ad->pfra_net < 128 && 6903b3a8eb9SGleb Smirnoff (((caddr_t)ad)[ad->pfra_net/8] & (0xFF >> (ad->pfra_net%8)))) 6913b3a8eb9SGleb Smirnoff return (-1); 6923b3a8eb9SGleb Smirnoff for (i = (ad->pfra_net+7)/8; i < sizeof(ad->pfra_u); i++) 6933b3a8eb9SGleb Smirnoff if (((caddr_t)ad)[i]) 6943b3a8eb9SGleb Smirnoff return (-1); 6953b3a8eb9SGleb Smirnoff if (ad->pfra_not && ad->pfra_not != 1) 6963b3a8eb9SGleb Smirnoff return (-1); 6973b3a8eb9SGleb Smirnoff if (ad->pfra_fback) 6983b3a8eb9SGleb Smirnoff return (-1); 6993b3a8eb9SGleb Smirnoff return (0); 7003b3a8eb9SGleb Smirnoff } 7013b3a8eb9SGleb Smirnoff 7023b3a8eb9SGleb Smirnoff static void 7033b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq, 7043b3a8eb9SGleb Smirnoff int *naddr, int sweep) 7053b3a8eb9SGleb Smirnoff { 7063b3a8eb9SGleb Smirnoff struct pfr_walktree w; 7073b3a8eb9SGleb Smirnoff 7083b3a8eb9SGleb Smirnoff SLIST_INIT(workq); 7093b3a8eb9SGleb Smirnoff bzero(&w, sizeof(w)); 7103b3a8eb9SGleb Smirnoff w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE; 7113b3a8eb9SGleb Smirnoff w.pfrw_workq = workq; 7123b3a8eb9SGleb Smirnoff if (kt->pfrkt_ip4 != NULL) 7133b3a8eb9SGleb Smirnoff if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, 7143b3a8eb9SGleb Smirnoff &w)) 7153b3a8eb9SGleb Smirnoff printf("pfr_enqueue_addrs: IPv4 walktree failed.\n"); 7163b3a8eb9SGleb Smirnoff if (kt->pfrkt_ip6 != NULL) 7173b3a8eb9SGleb Smirnoff if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, 7183b3a8eb9SGleb Smirnoff &w)) 7193b3a8eb9SGleb Smirnoff printf("pfr_enqueue_addrs: IPv6 walktree failed.\n"); 7203b3a8eb9SGleb Smirnoff if (naddr != NULL) 7213b3a8eb9SGleb Smirnoff *naddr = w.pfrw_cnt; 7223b3a8eb9SGleb Smirnoff } 7233b3a8eb9SGleb Smirnoff 7243b3a8eb9SGleb Smirnoff static void 7253b3a8eb9SGleb Smirnoff pfr_mark_addrs(struct pfr_ktable *kt) 7263b3a8eb9SGleb Smirnoff { 7273b3a8eb9SGleb Smirnoff struct pfr_walktree w; 7283b3a8eb9SGleb Smirnoff 7293b3a8eb9SGleb Smirnoff bzero(&w, sizeof(w)); 7303b3a8eb9SGleb Smirnoff w.pfrw_op = PFRW_MARK; 7313b3a8eb9SGleb Smirnoff if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) 7323b3a8eb9SGleb Smirnoff printf("pfr_mark_addrs: IPv4 walktree failed.\n"); 7333b3a8eb9SGleb Smirnoff if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) 7343b3a8eb9SGleb Smirnoff printf("pfr_mark_addrs: IPv6 walktree failed.\n"); 7353b3a8eb9SGleb Smirnoff } 7363b3a8eb9SGleb Smirnoff 7373b3a8eb9SGleb Smirnoff 7383b3a8eb9SGleb Smirnoff static struct pfr_kentry * 7393b3a8eb9SGleb Smirnoff pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) 7403b3a8eb9SGleb Smirnoff { 7413b3a8eb9SGleb Smirnoff union sockaddr_union sa, mask; 7423b3a8eb9SGleb Smirnoff struct radix_node_head *head = NULL; 7433b3a8eb9SGleb Smirnoff struct pfr_kentry *ke; 7443b3a8eb9SGleb Smirnoff 74529bdd62cSGleb Smirnoff PF_RULES_ASSERT(); 74629bdd62cSGleb Smirnoff 7473b3a8eb9SGleb Smirnoff bzero(&sa, sizeof(sa)); 7483b3a8eb9SGleb Smirnoff if (ad->pfra_af == AF_INET) { 7493b3a8eb9SGleb Smirnoff FILLIN_SIN(sa.sin, ad->pfra_ip4addr); 7503b3a8eb9SGleb Smirnoff head = kt->pfrkt_ip4; 7513b3a8eb9SGleb Smirnoff } else if ( ad->pfra_af == AF_INET6 ) { 7523b3a8eb9SGleb Smirnoff FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr); 7533b3a8eb9SGleb Smirnoff head = kt->pfrkt_ip6; 7543b3a8eb9SGleb Smirnoff } 7553b3a8eb9SGleb Smirnoff if (ADDR_NETWORK(ad)) { 7563b3a8eb9SGleb Smirnoff pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net); 7573b3a8eb9SGleb Smirnoff ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head); 7583b3a8eb9SGleb Smirnoff if (ke && KENTRY_RNF_ROOT(ke)) 7593b3a8eb9SGleb Smirnoff ke = NULL; 7603b3a8eb9SGleb Smirnoff } else { 7613b3a8eb9SGleb Smirnoff ke = (struct pfr_kentry *)rn_match(&sa, head); 7623b3a8eb9SGleb Smirnoff if (ke && KENTRY_RNF_ROOT(ke)) 7633b3a8eb9SGleb Smirnoff ke = NULL; 7643b3a8eb9SGleb Smirnoff if (exact && ke && KENTRY_NETWORK(ke)) 7653b3a8eb9SGleb Smirnoff ke = NULL; 7663b3a8eb9SGleb Smirnoff } 7673b3a8eb9SGleb Smirnoff return (ke); 7683b3a8eb9SGleb Smirnoff } 7693b3a8eb9SGleb Smirnoff 7703b3a8eb9SGleb Smirnoff static struct pfr_kentry * 7713b3a8eb9SGleb Smirnoff pfr_create_kentry(struct pfr_addr *ad) 7723b3a8eb9SGleb Smirnoff { 7733b3a8eb9SGleb Smirnoff struct pfr_kentry *ke; 7743b3a8eb9SGleb Smirnoff 7753b3a8eb9SGleb Smirnoff ke = uma_zalloc(V_pfr_kentry_z, M_NOWAIT | M_ZERO); 7763b3a8eb9SGleb Smirnoff if (ke == NULL) 7773b3a8eb9SGleb Smirnoff return (NULL); 7783b3a8eb9SGleb Smirnoff 7793b3a8eb9SGleb Smirnoff if (ad->pfra_af == AF_INET) 7803b3a8eb9SGleb Smirnoff FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr); 7813b3a8eb9SGleb Smirnoff else if (ad->pfra_af == AF_INET6) 7823b3a8eb9SGleb Smirnoff FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr); 7833b3a8eb9SGleb Smirnoff ke->pfrke_af = ad->pfra_af; 7843b3a8eb9SGleb Smirnoff ke->pfrke_net = ad->pfra_net; 7853b3a8eb9SGleb Smirnoff ke->pfrke_not = ad->pfra_not; 7863b3a8eb9SGleb Smirnoff return (ke); 7873b3a8eb9SGleb Smirnoff } 7883b3a8eb9SGleb Smirnoff 7893b3a8eb9SGleb Smirnoff static void 7903b3a8eb9SGleb Smirnoff pfr_destroy_kentries(struct pfr_kentryworkq *workq) 7913b3a8eb9SGleb Smirnoff { 7923b3a8eb9SGleb Smirnoff struct pfr_kentry *p, *q; 7933b3a8eb9SGleb Smirnoff 7943b3a8eb9SGleb Smirnoff for (p = SLIST_FIRST(workq); p != NULL; p = q) { 7953b3a8eb9SGleb Smirnoff q = SLIST_NEXT(p, pfrke_workq); 7963b3a8eb9SGleb Smirnoff pfr_destroy_kentry(p); 7973b3a8eb9SGleb Smirnoff } 7983b3a8eb9SGleb Smirnoff } 7993b3a8eb9SGleb Smirnoff 8003b3a8eb9SGleb Smirnoff static void 8013b3a8eb9SGleb Smirnoff pfr_destroy_kentry(struct pfr_kentry *ke) 8023b3a8eb9SGleb Smirnoff { 8033b3a8eb9SGleb Smirnoff if (ke->pfrke_counters) 8043b3a8eb9SGleb Smirnoff uma_zfree(V_pfr_kcounters_z, ke->pfrke_counters); 8053b3a8eb9SGleb Smirnoff uma_zfree(V_pfr_kentry_z, ke); 8063b3a8eb9SGleb Smirnoff } 8073b3a8eb9SGleb Smirnoff 8083b3a8eb9SGleb Smirnoff static void 8093b3a8eb9SGleb Smirnoff pfr_insert_kentries(struct pfr_ktable *kt, 8103b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *workq, long tzero) 8113b3a8eb9SGleb Smirnoff { 8123b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 8133b3a8eb9SGleb Smirnoff int rv, n = 0; 8143b3a8eb9SGleb Smirnoff 8153b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, workq, pfrke_workq) { 8163b3a8eb9SGleb Smirnoff rv = pfr_route_kentry(kt, p); 8173b3a8eb9SGleb Smirnoff if (rv) { 8183b3a8eb9SGleb Smirnoff printf("pfr_insert_kentries: cannot route entry " 8193b3a8eb9SGleb Smirnoff "(code=%d).\n", rv); 8203b3a8eb9SGleb Smirnoff break; 8213b3a8eb9SGleb Smirnoff } 8223b3a8eb9SGleb Smirnoff p->pfrke_tzero = tzero; 8233b3a8eb9SGleb Smirnoff n++; 8243b3a8eb9SGleb Smirnoff } 8253b3a8eb9SGleb Smirnoff kt->pfrkt_cnt += n; 8263b3a8eb9SGleb Smirnoff } 8273b3a8eb9SGleb Smirnoff 8283b3a8eb9SGleb Smirnoff int 8293b3a8eb9SGleb Smirnoff pfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, long tzero) 8303b3a8eb9SGleb Smirnoff { 8313b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 8323b3a8eb9SGleb Smirnoff int rv; 8333b3a8eb9SGleb Smirnoff 8343b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, ad, 1); 8353b3a8eb9SGleb Smirnoff if (p != NULL) 8363b3a8eb9SGleb Smirnoff return (0); 8373b3a8eb9SGleb Smirnoff p = pfr_create_kentry(ad); 8383b3a8eb9SGleb Smirnoff if (p == NULL) 839e706fd3aSGleb Smirnoff return (ENOMEM); 8403b3a8eb9SGleb Smirnoff 8413b3a8eb9SGleb Smirnoff rv = pfr_route_kentry(kt, p); 8423b3a8eb9SGleb Smirnoff if (rv) 8433b3a8eb9SGleb Smirnoff return (rv); 8443b3a8eb9SGleb Smirnoff 8453b3a8eb9SGleb Smirnoff p->pfrke_tzero = tzero; 8463b3a8eb9SGleb Smirnoff kt->pfrkt_cnt++; 8473b3a8eb9SGleb Smirnoff 8483b3a8eb9SGleb Smirnoff return (0); 8493b3a8eb9SGleb Smirnoff } 8503b3a8eb9SGleb Smirnoff 8513b3a8eb9SGleb Smirnoff static void 8523b3a8eb9SGleb Smirnoff pfr_remove_kentries(struct pfr_ktable *kt, 8533b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *workq) 8543b3a8eb9SGleb Smirnoff { 8553b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 8563b3a8eb9SGleb Smirnoff int n = 0; 8573b3a8eb9SGleb Smirnoff 8583b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, workq, pfrke_workq) { 8593b3a8eb9SGleb Smirnoff pfr_unroute_kentry(kt, p); 8603b3a8eb9SGleb Smirnoff n++; 8613b3a8eb9SGleb Smirnoff } 8623b3a8eb9SGleb Smirnoff kt->pfrkt_cnt -= n; 8633b3a8eb9SGleb Smirnoff pfr_destroy_kentries(workq); 8643b3a8eb9SGleb Smirnoff } 8653b3a8eb9SGleb Smirnoff 8663b3a8eb9SGleb Smirnoff static void 8673b3a8eb9SGleb Smirnoff pfr_clean_node_mask(struct pfr_ktable *kt, 8683b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *workq) 8693b3a8eb9SGleb Smirnoff { 8703b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 8713b3a8eb9SGleb Smirnoff 8723b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, workq, pfrke_workq) 8733b3a8eb9SGleb Smirnoff pfr_unroute_kentry(kt, p); 8743b3a8eb9SGleb Smirnoff } 8753b3a8eb9SGleb Smirnoff 8763b3a8eb9SGleb Smirnoff static void 8773b3a8eb9SGleb Smirnoff pfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange) 8783b3a8eb9SGleb Smirnoff { 8793b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 8803b3a8eb9SGleb Smirnoff 8813b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, workq, pfrke_workq) { 8823b3a8eb9SGleb Smirnoff if (negchange) 8833b3a8eb9SGleb Smirnoff p->pfrke_not = !p->pfrke_not; 8843b3a8eb9SGleb Smirnoff if (p->pfrke_counters) { 8853b3a8eb9SGleb Smirnoff uma_zfree(V_pfr_kcounters_z, p->pfrke_counters); 8863b3a8eb9SGleb Smirnoff p->pfrke_counters = NULL; 8873b3a8eb9SGleb Smirnoff } 8883b3a8eb9SGleb Smirnoff p->pfrke_tzero = tzero; 8893b3a8eb9SGleb Smirnoff } 8903b3a8eb9SGleb Smirnoff } 8913b3a8eb9SGleb Smirnoff 8923b3a8eb9SGleb Smirnoff static void 8933b3a8eb9SGleb Smirnoff pfr_reset_feedback(struct pfr_addr *addr, int size) 8943b3a8eb9SGleb Smirnoff { 8953b3a8eb9SGleb Smirnoff struct pfr_addr *ad; 8963b3a8eb9SGleb Smirnoff int i; 8973b3a8eb9SGleb Smirnoff 8983b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) 8993b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_NONE; 9003b3a8eb9SGleb Smirnoff } 9013b3a8eb9SGleb Smirnoff 9023b3a8eb9SGleb Smirnoff static void 9033b3a8eb9SGleb Smirnoff pfr_prepare_network(union sockaddr_union *sa, int af, int net) 9043b3a8eb9SGleb Smirnoff { 9053b3a8eb9SGleb Smirnoff int i; 9063b3a8eb9SGleb Smirnoff 9073b3a8eb9SGleb Smirnoff bzero(sa, sizeof(*sa)); 9083b3a8eb9SGleb Smirnoff if (af == AF_INET) { 9093b3a8eb9SGleb Smirnoff sa->sin.sin_len = sizeof(sa->sin); 9103b3a8eb9SGleb Smirnoff sa->sin.sin_family = AF_INET; 9113b3a8eb9SGleb Smirnoff sa->sin.sin_addr.s_addr = net ? htonl(-1 << (32-net)) : 0; 9123b3a8eb9SGleb Smirnoff } else if (af == AF_INET6) { 9133b3a8eb9SGleb Smirnoff sa->sin6.sin6_len = sizeof(sa->sin6); 9143b3a8eb9SGleb Smirnoff sa->sin6.sin6_family = AF_INET6; 9153b3a8eb9SGleb Smirnoff for (i = 0; i < 4; i++) { 9163b3a8eb9SGleb Smirnoff if (net <= 32) { 9173b3a8eb9SGleb Smirnoff sa->sin6.sin6_addr.s6_addr32[i] = 9183b3a8eb9SGleb Smirnoff net ? htonl(-1 << (32-net)) : 0; 9193b3a8eb9SGleb Smirnoff break; 9203b3a8eb9SGleb Smirnoff } 9213b3a8eb9SGleb Smirnoff sa->sin6.sin6_addr.s6_addr32[i] = 0xFFFFFFFF; 9223b3a8eb9SGleb Smirnoff net -= 32; 9233b3a8eb9SGleb Smirnoff } 9243b3a8eb9SGleb Smirnoff } 9253b3a8eb9SGleb Smirnoff } 9263b3a8eb9SGleb Smirnoff 9273b3a8eb9SGleb Smirnoff static int 9283b3a8eb9SGleb Smirnoff pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) 9293b3a8eb9SGleb Smirnoff { 9303b3a8eb9SGleb Smirnoff union sockaddr_union mask; 9313b3a8eb9SGleb Smirnoff struct radix_node *rn; 9323b3a8eb9SGleb Smirnoff struct radix_node_head *head = NULL; 9333b3a8eb9SGleb Smirnoff 93429bdd62cSGleb Smirnoff PF_RULES_WASSERT(); 93529bdd62cSGleb Smirnoff 9363b3a8eb9SGleb Smirnoff bzero(ke->pfrke_node, sizeof(ke->pfrke_node)); 9373b3a8eb9SGleb Smirnoff if (ke->pfrke_af == AF_INET) 9383b3a8eb9SGleb Smirnoff head = kt->pfrkt_ip4; 9393b3a8eb9SGleb Smirnoff else if (ke->pfrke_af == AF_INET6) 9403b3a8eb9SGleb Smirnoff head = kt->pfrkt_ip6; 9413b3a8eb9SGleb Smirnoff 9423b3a8eb9SGleb Smirnoff if (KENTRY_NETWORK(ke)) { 9433b3a8eb9SGleb Smirnoff pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); 9443b3a8eb9SGleb Smirnoff rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node); 9453b3a8eb9SGleb Smirnoff } else 9463b3a8eb9SGleb Smirnoff rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node); 9473b3a8eb9SGleb Smirnoff 9483b3a8eb9SGleb Smirnoff return (rn == NULL ? -1 : 0); 9493b3a8eb9SGleb Smirnoff } 9503b3a8eb9SGleb Smirnoff 9513b3a8eb9SGleb Smirnoff static int 9523b3a8eb9SGleb Smirnoff pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) 9533b3a8eb9SGleb Smirnoff { 9543b3a8eb9SGleb Smirnoff union sockaddr_union mask; 9553b3a8eb9SGleb Smirnoff struct radix_node *rn; 9563b3a8eb9SGleb Smirnoff struct radix_node_head *head = NULL; 9573b3a8eb9SGleb Smirnoff 9583b3a8eb9SGleb Smirnoff if (ke->pfrke_af == AF_INET) 9593b3a8eb9SGleb Smirnoff head = kt->pfrkt_ip4; 9603b3a8eb9SGleb Smirnoff else if (ke->pfrke_af == AF_INET6) 9613b3a8eb9SGleb Smirnoff head = kt->pfrkt_ip6; 9623b3a8eb9SGleb Smirnoff 9633b3a8eb9SGleb Smirnoff if (KENTRY_NETWORK(ke)) { 9643b3a8eb9SGleb Smirnoff pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); 9653b3a8eb9SGleb Smirnoff rn = rn_delete(&ke->pfrke_sa, &mask, head); 9663b3a8eb9SGleb Smirnoff } else 9673b3a8eb9SGleb Smirnoff rn = rn_delete(&ke->pfrke_sa, NULL, head); 9683b3a8eb9SGleb Smirnoff 9693b3a8eb9SGleb Smirnoff if (rn == NULL) { 9703b3a8eb9SGleb Smirnoff printf("pfr_unroute_kentry: delete failed.\n"); 9713b3a8eb9SGleb Smirnoff return (-1); 9723b3a8eb9SGleb Smirnoff } 9733b3a8eb9SGleb Smirnoff return (0); 9743b3a8eb9SGleb Smirnoff } 9753b3a8eb9SGleb Smirnoff 9763b3a8eb9SGleb Smirnoff static void 9773b3a8eb9SGleb Smirnoff pfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke) 9783b3a8eb9SGleb Smirnoff { 9793b3a8eb9SGleb Smirnoff bzero(ad, sizeof(*ad)); 9803b3a8eb9SGleb Smirnoff if (ke == NULL) 9813b3a8eb9SGleb Smirnoff return; 9823b3a8eb9SGleb Smirnoff ad->pfra_af = ke->pfrke_af; 9833b3a8eb9SGleb Smirnoff ad->pfra_net = ke->pfrke_net; 9843b3a8eb9SGleb Smirnoff ad->pfra_not = ke->pfrke_not; 9853b3a8eb9SGleb Smirnoff if (ad->pfra_af == AF_INET) 9863b3a8eb9SGleb Smirnoff ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr; 9873b3a8eb9SGleb Smirnoff else if (ad->pfra_af == AF_INET6) 9883b3a8eb9SGleb Smirnoff ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr; 9893b3a8eb9SGleb Smirnoff } 9903b3a8eb9SGleb Smirnoff 9913b3a8eb9SGleb Smirnoff static int 9923b3a8eb9SGleb Smirnoff pfr_walktree(struct radix_node *rn, void *arg) 9933b3a8eb9SGleb Smirnoff { 9943b3a8eb9SGleb Smirnoff struct pfr_kentry *ke = (struct pfr_kentry *)rn; 9953b3a8eb9SGleb Smirnoff struct pfr_walktree *w = arg; 9963b3a8eb9SGleb Smirnoff 9973b3a8eb9SGleb Smirnoff switch (w->pfrw_op) { 9983b3a8eb9SGleb Smirnoff case PFRW_MARK: 9993b3a8eb9SGleb Smirnoff ke->pfrke_mark = 0; 10003b3a8eb9SGleb Smirnoff break; 10013b3a8eb9SGleb Smirnoff case PFRW_SWEEP: 10023b3a8eb9SGleb Smirnoff if (ke->pfrke_mark) 10033b3a8eb9SGleb Smirnoff break; 10043b3a8eb9SGleb Smirnoff /* FALLTHROUGH */ 10053b3a8eb9SGleb Smirnoff case PFRW_ENQUEUE: 10063b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(w->pfrw_workq, ke, pfrke_workq); 10073b3a8eb9SGleb Smirnoff w->pfrw_cnt++; 10083b3a8eb9SGleb Smirnoff break; 10093b3a8eb9SGleb Smirnoff case PFRW_GET_ADDRS: 10103b3a8eb9SGleb Smirnoff if (w->pfrw_free-- > 0) { 10113b3a8eb9SGleb Smirnoff pfr_copyout_addr(w->pfrw_addr, ke); 10123b3a8eb9SGleb Smirnoff w->pfrw_addr++; 10133b3a8eb9SGleb Smirnoff } 10143b3a8eb9SGleb Smirnoff break; 10153b3a8eb9SGleb Smirnoff case PFRW_GET_ASTATS: 10163b3a8eb9SGleb Smirnoff if (w->pfrw_free-- > 0) { 10173b3a8eb9SGleb Smirnoff struct pfr_astats as; 10183b3a8eb9SGleb Smirnoff 10193b3a8eb9SGleb Smirnoff pfr_copyout_addr(&as.pfras_a, ke); 10203b3a8eb9SGleb Smirnoff 10213b3a8eb9SGleb Smirnoff if (ke->pfrke_counters) { 10223b3a8eb9SGleb Smirnoff bcopy(ke->pfrke_counters->pfrkc_packets, 10233b3a8eb9SGleb Smirnoff as.pfras_packets, sizeof(as.pfras_packets)); 10243b3a8eb9SGleb Smirnoff bcopy(ke->pfrke_counters->pfrkc_bytes, 10253b3a8eb9SGleb Smirnoff as.pfras_bytes, sizeof(as.pfras_bytes)); 10263b3a8eb9SGleb Smirnoff } else { 10273b3a8eb9SGleb Smirnoff bzero(as.pfras_packets, sizeof(as.pfras_packets)); 10283b3a8eb9SGleb Smirnoff bzero(as.pfras_bytes, sizeof(as.pfras_bytes)); 10293b3a8eb9SGleb Smirnoff as.pfras_a.pfra_fback = PFR_FB_NOCOUNT; 10303b3a8eb9SGleb Smirnoff } 10313b3a8eb9SGleb Smirnoff as.pfras_tzero = ke->pfrke_tzero; 10323b3a8eb9SGleb Smirnoff 10333b3a8eb9SGleb Smirnoff bcopy(&as, w->pfrw_astats, sizeof(as)); 10343b3a8eb9SGleb Smirnoff w->pfrw_astats++; 10353b3a8eb9SGleb Smirnoff } 10363b3a8eb9SGleb Smirnoff break; 10373b3a8eb9SGleb Smirnoff case PFRW_POOL_GET: 10383b3a8eb9SGleb Smirnoff if (ke->pfrke_not) 10393b3a8eb9SGleb Smirnoff break; /* negative entries are ignored */ 10403b3a8eb9SGleb Smirnoff if (!w->pfrw_cnt--) { 10413b3a8eb9SGleb Smirnoff w->pfrw_kentry = ke; 10423b3a8eb9SGleb Smirnoff return (1); /* finish search */ 10433b3a8eb9SGleb Smirnoff } 10443b3a8eb9SGleb Smirnoff break; 10453b3a8eb9SGleb Smirnoff case PFRW_DYNADDR_UPDATE: 10463b3a8eb9SGleb Smirnoff { 10473b3a8eb9SGleb Smirnoff union sockaddr_union pfr_mask; 10483b3a8eb9SGleb Smirnoff 10493b3a8eb9SGleb Smirnoff if (ke->pfrke_af == AF_INET) { 10503b3a8eb9SGleb Smirnoff if (w->pfrw_dyn->pfid_acnt4++ > 0) 10513b3a8eb9SGleb Smirnoff break; 10523b3a8eb9SGleb Smirnoff pfr_prepare_network(&pfr_mask, AF_INET, ke->pfrke_net); 10533b3a8eb9SGleb Smirnoff w->pfrw_dyn->pfid_addr4 = *SUNION2PF(&ke->pfrke_sa, 10543b3a8eb9SGleb Smirnoff AF_INET); 10553b3a8eb9SGleb Smirnoff w->pfrw_dyn->pfid_mask4 = *SUNION2PF(&pfr_mask, 10563b3a8eb9SGleb Smirnoff AF_INET); 10573b3a8eb9SGleb Smirnoff } else if (ke->pfrke_af == AF_INET6){ 10583b3a8eb9SGleb Smirnoff if (w->pfrw_dyn->pfid_acnt6++ > 0) 10593b3a8eb9SGleb Smirnoff break; 10603b3a8eb9SGleb Smirnoff pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net); 10613b3a8eb9SGleb Smirnoff w->pfrw_dyn->pfid_addr6 = *SUNION2PF(&ke->pfrke_sa, 10623b3a8eb9SGleb Smirnoff AF_INET6); 10633b3a8eb9SGleb Smirnoff w->pfrw_dyn->pfid_mask6 = *SUNION2PF(&pfr_mask, 10643b3a8eb9SGleb Smirnoff AF_INET6); 10653b3a8eb9SGleb Smirnoff } 10663b3a8eb9SGleb Smirnoff break; 10673b3a8eb9SGleb Smirnoff } 10683b3a8eb9SGleb Smirnoff } 10693b3a8eb9SGleb Smirnoff return (0); 10703b3a8eb9SGleb Smirnoff } 10713b3a8eb9SGleb Smirnoff 10723b3a8eb9SGleb Smirnoff int 10733b3a8eb9SGleb Smirnoff pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) 10743b3a8eb9SGleb Smirnoff { 10753b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 10763b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 10773b3a8eb9SGleb Smirnoff int xdel = 0; 10783b3a8eb9SGleb Smirnoff 10793b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ALLRSETS); 10803b3a8eb9SGleb Smirnoff if (pfr_fix_anchor(filter->pfrt_anchor)) 10813b3a8eb9SGleb Smirnoff return (EINVAL); 10823b3a8eb9SGleb Smirnoff if (pfr_table_count(filter, flags) < 0) 10833b3a8eb9SGleb Smirnoff return (ENOENT); 10843b3a8eb9SGleb Smirnoff 10853b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 10863b3a8eb9SGleb Smirnoff RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 10873b3a8eb9SGleb Smirnoff if (pfr_skip_table(filter, p, flags)) 10883b3a8eb9SGleb Smirnoff continue; 10893b3a8eb9SGleb Smirnoff if (!strcmp(p->pfrkt_anchor, PF_RESERVED_ANCHOR)) 10903b3a8eb9SGleb Smirnoff continue; 10913b3a8eb9SGleb Smirnoff if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) 10923b3a8eb9SGleb Smirnoff continue; 10933b3a8eb9SGleb Smirnoff p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE; 10943b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 10953b3a8eb9SGleb Smirnoff xdel++; 10963b3a8eb9SGleb Smirnoff } 10973b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 10983b3a8eb9SGleb Smirnoff pfr_setflags_ktables(&workq); 10993b3a8eb9SGleb Smirnoff if (ndel != NULL) 11003b3a8eb9SGleb Smirnoff *ndel = xdel; 11013b3a8eb9SGleb Smirnoff return (0); 11023b3a8eb9SGleb Smirnoff } 11033b3a8eb9SGleb Smirnoff 11043b3a8eb9SGleb Smirnoff int 11053b3a8eb9SGleb Smirnoff pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) 11063b3a8eb9SGleb Smirnoff { 11073b3a8eb9SGleb Smirnoff struct pfr_ktableworkq addq, changeq; 11083b3a8eb9SGleb Smirnoff struct pfr_ktable *p, *q, *r, key; 11093b3a8eb9SGleb Smirnoff int i, rv, xadd = 0; 11103b3a8eb9SGleb Smirnoff long tzero = time_second; 11113b3a8eb9SGleb Smirnoff 11123b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 11133b3a8eb9SGleb Smirnoff SLIST_INIT(&addq); 11143b3a8eb9SGleb Smirnoff SLIST_INIT(&changeq); 11153b3a8eb9SGleb Smirnoff for (i = 0; i < size; i++) { 11163b3a8eb9SGleb Smirnoff bcopy(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)); 11173b3a8eb9SGleb Smirnoff if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK, 11183b3a8eb9SGleb Smirnoff flags & PFR_FLAG_USERIOCTL)) 11193b3a8eb9SGleb Smirnoff senderr(EINVAL); 11203b3a8eb9SGleb Smirnoff key.pfrkt_flags |= PFR_TFLAG_ACTIVE; 11213b3a8eb9SGleb Smirnoff p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 11223b3a8eb9SGleb Smirnoff if (p == NULL) { 11233b3a8eb9SGleb Smirnoff p = pfr_create_ktable(&key.pfrkt_t, tzero, 1); 11243b3a8eb9SGleb Smirnoff if (p == NULL) 11253b3a8eb9SGleb Smirnoff senderr(ENOMEM); 11263b3a8eb9SGleb Smirnoff SLIST_FOREACH(q, &addq, pfrkt_workq) { 11273b3a8eb9SGleb Smirnoff if (!pfr_ktable_compare(p, q)) 11283b3a8eb9SGleb Smirnoff goto _skip; 11293b3a8eb9SGleb Smirnoff } 11303b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&addq, p, pfrkt_workq); 11313b3a8eb9SGleb Smirnoff xadd++; 11323b3a8eb9SGleb Smirnoff if (!key.pfrkt_anchor[0]) 11333b3a8eb9SGleb Smirnoff goto _skip; 11343b3a8eb9SGleb Smirnoff 11353b3a8eb9SGleb Smirnoff /* find or create root table */ 11363b3a8eb9SGleb Smirnoff bzero(key.pfrkt_anchor, sizeof(key.pfrkt_anchor)); 11373b3a8eb9SGleb Smirnoff r = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 11383b3a8eb9SGleb Smirnoff if (r != NULL) { 11393b3a8eb9SGleb Smirnoff p->pfrkt_root = r; 11403b3a8eb9SGleb Smirnoff goto _skip; 11413b3a8eb9SGleb Smirnoff } 11423b3a8eb9SGleb Smirnoff SLIST_FOREACH(q, &addq, pfrkt_workq) { 11433b3a8eb9SGleb Smirnoff if (!pfr_ktable_compare(&key, q)) { 11443b3a8eb9SGleb Smirnoff p->pfrkt_root = q; 11453b3a8eb9SGleb Smirnoff goto _skip; 11463b3a8eb9SGleb Smirnoff } 11473b3a8eb9SGleb Smirnoff } 11483b3a8eb9SGleb Smirnoff key.pfrkt_flags = 0; 11493b3a8eb9SGleb Smirnoff r = pfr_create_ktable(&key.pfrkt_t, 0, 1); 11503b3a8eb9SGleb Smirnoff if (r == NULL) 11513b3a8eb9SGleb Smirnoff senderr(ENOMEM); 11523b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&addq, r, pfrkt_workq); 11533b3a8eb9SGleb Smirnoff p->pfrkt_root = r; 11543b3a8eb9SGleb Smirnoff } else if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { 11553b3a8eb9SGleb Smirnoff SLIST_FOREACH(q, &changeq, pfrkt_workq) 11563b3a8eb9SGleb Smirnoff if (!pfr_ktable_compare(&key, q)) 11573b3a8eb9SGleb Smirnoff goto _skip; 11583b3a8eb9SGleb Smirnoff p->pfrkt_nflags = (p->pfrkt_flags & 11593b3a8eb9SGleb Smirnoff ~PFR_TFLAG_USRMASK) | key.pfrkt_flags; 11603b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq); 11613b3a8eb9SGleb Smirnoff xadd++; 11623b3a8eb9SGleb Smirnoff } 11633b3a8eb9SGleb Smirnoff _skip: 11643b3a8eb9SGleb Smirnoff ; 11653b3a8eb9SGleb Smirnoff } 11663b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 11673b3a8eb9SGleb Smirnoff pfr_insert_ktables(&addq); 11683b3a8eb9SGleb Smirnoff pfr_setflags_ktables(&changeq); 11693b3a8eb9SGleb Smirnoff } else 11703b3a8eb9SGleb Smirnoff pfr_destroy_ktables(&addq, 0); 11713b3a8eb9SGleb Smirnoff if (nadd != NULL) 11723b3a8eb9SGleb Smirnoff *nadd = xadd; 11733b3a8eb9SGleb Smirnoff return (0); 11743b3a8eb9SGleb Smirnoff _bad: 11753b3a8eb9SGleb Smirnoff pfr_destroy_ktables(&addq, 0); 11763b3a8eb9SGleb Smirnoff return (rv); 11773b3a8eb9SGleb Smirnoff } 11783b3a8eb9SGleb Smirnoff 11793b3a8eb9SGleb Smirnoff int 11803b3a8eb9SGleb Smirnoff pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) 11813b3a8eb9SGleb Smirnoff { 11823b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 11833b3a8eb9SGleb Smirnoff struct pfr_ktable *p, *q, key; 11843b3a8eb9SGleb Smirnoff int i, xdel = 0; 11853b3a8eb9SGleb Smirnoff 11863b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 11873b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 11883b3a8eb9SGleb Smirnoff for (i = 0; i < size; i++) { 11893b3a8eb9SGleb Smirnoff bcopy(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)); 11903b3a8eb9SGleb Smirnoff if (pfr_validate_table(&key.pfrkt_t, 0, 11913b3a8eb9SGleb Smirnoff flags & PFR_FLAG_USERIOCTL)) 11923b3a8eb9SGleb Smirnoff return (EINVAL); 11933b3a8eb9SGleb Smirnoff p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 11943b3a8eb9SGleb Smirnoff if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { 11953b3a8eb9SGleb Smirnoff SLIST_FOREACH(q, &workq, pfrkt_workq) 11963b3a8eb9SGleb Smirnoff if (!pfr_ktable_compare(p, q)) 11973b3a8eb9SGleb Smirnoff goto _skip; 11983b3a8eb9SGleb Smirnoff p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE; 11993b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 12003b3a8eb9SGleb Smirnoff xdel++; 12013b3a8eb9SGleb Smirnoff } 12023b3a8eb9SGleb Smirnoff _skip: 12033b3a8eb9SGleb Smirnoff ; 12043b3a8eb9SGleb Smirnoff } 12053b3a8eb9SGleb Smirnoff 12063b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 12073b3a8eb9SGleb Smirnoff pfr_setflags_ktables(&workq); 12083b3a8eb9SGleb Smirnoff if (ndel != NULL) 12093b3a8eb9SGleb Smirnoff *ndel = xdel; 12103b3a8eb9SGleb Smirnoff return (0); 12113b3a8eb9SGleb Smirnoff } 12123b3a8eb9SGleb Smirnoff 12133b3a8eb9SGleb Smirnoff int 12143b3a8eb9SGleb Smirnoff pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, 12153b3a8eb9SGleb Smirnoff int flags) 12163b3a8eb9SGleb Smirnoff { 12173b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 12183b3a8eb9SGleb Smirnoff int n, nn; 12193b3a8eb9SGleb Smirnoff 12203b3a8eb9SGleb Smirnoff PF_RULES_RASSERT(); 12213b3a8eb9SGleb Smirnoff 12223b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS); 12233b3a8eb9SGleb Smirnoff if (pfr_fix_anchor(filter->pfrt_anchor)) 12243b3a8eb9SGleb Smirnoff return (EINVAL); 12253b3a8eb9SGleb Smirnoff n = nn = pfr_table_count(filter, flags); 12263b3a8eb9SGleb Smirnoff if (n < 0) 12273b3a8eb9SGleb Smirnoff return (ENOENT); 12283b3a8eb9SGleb Smirnoff if (n > *size) { 12293b3a8eb9SGleb Smirnoff *size = n; 12303b3a8eb9SGleb Smirnoff return (0); 12313b3a8eb9SGleb Smirnoff } 12323b3a8eb9SGleb Smirnoff RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 12333b3a8eb9SGleb Smirnoff if (pfr_skip_table(filter, p, flags)) 12343b3a8eb9SGleb Smirnoff continue; 12353b3a8eb9SGleb Smirnoff if (n-- <= 0) 12363b3a8eb9SGleb Smirnoff continue; 12373b3a8eb9SGleb Smirnoff bcopy(&p->pfrkt_t, tbl++, sizeof(*tbl)); 12383b3a8eb9SGleb Smirnoff } 12393b3a8eb9SGleb Smirnoff 12403b3a8eb9SGleb Smirnoff KASSERT(n == 0, ("%s: corruption detected (%d)", __func__, n)); 12413b3a8eb9SGleb Smirnoff 12423b3a8eb9SGleb Smirnoff *size = nn; 12433b3a8eb9SGleb Smirnoff return (0); 12443b3a8eb9SGleb Smirnoff } 12453b3a8eb9SGleb Smirnoff 12463b3a8eb9SGleb Smirnoff int 12473b3a8eb9SGleb Smirnoff pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, 12483b3a8eb9SGleb Smirnoff int flags) 12493b3a8eb9SGleb Smirnoff { 12503b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 12513b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 12523b3a8eb9SGleb Smirnoff int n, nn; 12533b3a8eb9SGleb Smirnoff long tzero = time_second; 12543b3a8eb9SGleb Smirnoff 12553b3a8eb9SGleb Smirnoff /* XXX PFR_FLAG_CLSTATS disabled */ 12563b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS); 12573b3a8eb9SGleb Smirnoff if (pfr_fix_anchor(filter->pfrt_anchor)) 12583b3a8eb9SGleb Smirnoff return (EINVAL); 12593b3a8eb9SGleb Smirnoff n = nn = pfr_table_count(filter, flags); 12603b3a8eb9SGleb Smirnoff if (n < 0) 12613b3a8eb9SGleb Smirnoff return (ENOENT); 12623b3a8eb9SGleb Smirnoff if (n > *size) { 12633b3a8eb9SGleb Smirnoff *size = n; 12643b3a8eb9SGleb Smirnoff return (0); 12653b3a8eb9SGleb Smirnoff } 12663b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 12673b3a8eb9SGleb Smirnoff RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 12683b3a8eb9SGleb Smirnoff if (pfr_skip_table(filter, p, flags)) 12693b3a8eb9SGleb Smirnoff continue; 12703b3a8eb9SGleb Smirnoff if (n-- <= 0) 12713b3a8eb9SGleb Smirnoff continue; 12723b3a8eb9SGleb Smirnoff bcopy(&p->pfrkt_ts, tbl++, sizeof(*tbl)); 12733b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 12743b3a8eb9SGleb Smirnoff } 12753b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_CLSTATS) 12763b3a8eb9SGleb Smirnoff pfr_clstats_ktables(&workq, tzero, 12773b3a8eb9SGleb Smirnoff flags & PFR_FLAG_ADDRSTOO); 12783b3a8eb9SGleb Smirnoff 12793b3a8eb9SGleb Smirnoff KASSERT(n == 0, ("%s: corruption detected (%d)", __func__, n)); 12803b3a8eb9SGleb Smirnoff 12813b3a8eb9SGleb Smirnoff *size = nn; 12823b3a8eb9SGleb Smirnoff return (0); 12833b3a8eb9SGleb Smirnoff } 12843b3a8eb9SGleb Smirnoff 12853b3a8eb9SGleb Smirnoff int 12863b3a8eb9SGleb Smirnoff pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) 12873b3a8eb9SGleb Smirnoff { 12883b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 12893b3a8eb9SGleb Smirnoff struct pfr_ktable *p, key; 12903b3a8eb9SGleb Smirnoff int i, xzero = 0; 12913b3a8eb9SGleb Smirnoff long tzero = time_second; 12923b3a8eb9SGleb Smirnoff 12933b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ADDRSTOO); 12943b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 12953b3a8eb9SGleb Smirnoff for (i = 0; i < size; i++) { 12963b3a8eb9SGleb Smirnoff bcopy(tbl + i, &key.pfrkt_t, sizeof(key.pfrkt_t)); 12973b3a8eb9SGleb Smirnoff if (pfr_validate_table(&key.pfrkt_t, 0, 0)) 12983b3a8eb9SGleb Smirnoff return (EINVAL); 12993b3a8eb9SGleb Smirnoff p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 13003b3a8eb9SGleb Smirnoff if (p != NULL) { 13013b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 13023b3a8eb9SGleb Smirnoff xzero++; 13033b3a8eb9SGleb Smirnoff } 13043b3a8eb9SGleb Smirnoff } 13053b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 13063b3a8eb9SGleb Smirnoff pfr_clstats_ktables(&workq, tzero, flags & PFR_FLAG_ADDRSTOO); 13073b3a8eb9SGleb Smirnoff if (nzero != NULL) 13083b3a8eb9SGleb Smirnoff *nzero = xzero; 13093b3a8eb9SGleb Smirnoff return (0); 13103b3a8eb9SGleb Smirnoff } 13113b3a8eb9SGleb Smirnoff 13123b3a8eb9SGleb Smirnoff int 13133b3a8eb9SGleb Smirnoff pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag, 13143b3a8eb9SGleb Smirnoff int *nchange, int *ndel, int flags) 13153b3a8eb9SGleb Smirnoff { 13163b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 13173b3a8eb9SGleb Smirnoff struct pfr_ktable *p, *q, key; 13183b3a8eb9SGleb Smirnoff int i, xchange = 0, xdel = 0; 13193b3a8eb9SGleb Smirnoff 13203b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 13213b3a8eb9SGleb Smirnoff if ((setflag & ~PFR_TFLAG_USRMASK) || 13223b3a8eb9SGleb Smirnoff (clrflag & ~PFR_TFLAG_USRMASK) || 13233b3a8eb9SGleb Smirnoff (setflag & clrflag)) 13243b3a8eb9SGleb Smirnoff return (EINVAL); 13253b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 13263b3a8eb9SGleb Smirnoff for (i = 0; i < size; i++) { 13273b3a8eb9SGleb Smirnoff bcopy(tbl + i, &key.pfrkt_t, sizeof(key.pfrkt_t)); 13283b3a8eb9SGleb Smirnoff if (pfr_validate_table(&key.pfrkt_t, 0, 13293b3a8eb9SGleb Smirnoff flags & PFR_FLAG_USERIOCTL)) 13303b3a8eb9SGleb Smirnoff return (EINVAL); 13313b3a8eb9SGleb Smirnoff p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 13323b3a8eb9SGleb Smirnoff if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { 13333b3a8eb9SGleb Smirnoff p->pfrkt_nflags = (p->pfrkt_flags | setflag) & 13343b3a8eb9SGleb Smirnoff ~clrflag; 13353b3a8eb9SGleb Smirnoff if (p->pfrkt_nflags == p->pfrkt_flags) 13363b3a8eb9SGleb Smirnoff goto _skip; 13373b3a8eb9SGleb Smirnoff SLIST_FOREACH(q, &workq, pfrkt_workq) 13383b3a8eb9SGleb Smirnoff if (!pfr_ktable_compare(p, q)) 13393b3a8eb9SGleb Smirnoff goto _skip; 13403b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 13413b3a8eb9SGleb Smirnoff if ((p->pfrkt_flags & PFR_TFLAG_PERSIST) && 13423b3a8eb9SGleb Smirnoff (clrflag & PFR_TFLAG_PERSIST) && 13433b3a8eb9SGleb Smirnoff !(p->pfrkt_flags & PFR_TFLAG_REFERENCED)) 13443b3a8eb9SGleb Smirnoff xdel++; 13453b3a8eb9SGleb Smirnoff else 13463b3a8eb9SGleb Smirnoff xchange++; 13473b3a8eb9SGleb Smirnoff } 13483b3a8eb9SGleb Smirnoff _skip: 13493b3a8eb9SGleb Smirnoff ; 13503b3a8eb9SGleb Smirnoff } 13513b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 13523b3a8eb9SGleb Smirnoff pfr_setflags_ktables(&workq); 13533b3a8eb9SGleb Smirnoff if (nchange != NULL) 13543b3a8eb9SGleb Smirnoff *nchange = xchange; 13553b3a8eb9SGleb Smirnoff if (ndel != NULL) 13563b3a8eb9SGleb Smirnoff *ndel = xdel; 13573b3a8eb9SGleb Smirnoff return (0); 13583b3a8eb9SGleb Smirnoff } 13593b3a8eb9SGleb Smirnoff 13603b3a8eb9SGleb Smirnoff int 13613b3a8eb9SGleb Smirnoff pfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags) 13623b3a8eb9SGleb Smirnoff { 13633b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 13643b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 13653b3a8eb9SGleb Smirnoff struct pf_ruleset *rs; 13663b3a8eb9SGleb Smirnoff int xdel = 0; 13673b3a8eb9SGleb Smirnoff 13683b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 13693b3a8eb9SGleb Smirnoff rs = pf_find_or_create_ruleset(trs->pfrt_anchor); 13703b3a8eb9SGleb Smirnoff if (rs == NULL) 13713b3a8eb9SGleb Smirnoff return (ENOMEM); 13723b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 13733b3a8eb9SGleb Smirnoff RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 13743b3a8eb9SGleb Smirnoff if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || 13753b3a8eb9SGleb Smirnoff pfr_skip_table(trs, p, 0)) 13763b3a8eb9SGleb Smirnoff continue; 13773b3a8eb9SGleb Smirnoff p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE; 13783b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 13793b3a8eb9SGleb Smirnoff xdel++; 13803b3a8eb9SGleb Smirnoff } 13813b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 13823b3a8eb9SGleb Smirnoff pfr_setflags_ktables(&workq); 13833b3a8eb9SGleb Smirnoff if (ticket != NULL) 13843b3a8eb9SGleb Smirnoff *ticket = ++rs->tticket; 13853b3a8eb9SGleb Smirnoff rs->topen = 1; 13863b3a8eb9SGleb Smirnoff } else 13873b3a8eb9SGleb Smirnoff pf_remove_if_empty_ruleset(rs); 13883b3a8eb9SGleb Smirnoff if (ndel != NULL) 13893b3a8eb9SGleb Smirnoff *ndel = xdel; 13903b3a8eb9SGleb Smirnoff return (0); 13913b3a8eb9SGleb Smirnoff } 13923b3a8eb9SGleb Smirnoff 13933b3a8eb9SGleb Smirnoff int 13943b3a8eb9SGleb Smirnoff pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, 13953b3a8eb9SGleb Smirnoff int *nadd, int *naddr, u_int32_t ticket, int flags) 13963b3a8eb9SGleb Smirnoff { 13973b3a8eb9SGleb Smirnoff struct pfr_ktableworkq tableq; 13983b3a8eb9SGleb Smirnoff struct pfr_kentryworkq addrq; 13993b3a8eb9SGleb Smirnoff struct pfr_ktable *kt, *rt, *shadow, key; 14003b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 14013b3a8eb9SGleb Smirnoff struct pfr_addr *ad; 14023b3a8eb9SGleb Smirnoff struct pf_ruleset *rs; 14033b3a8eb9SGleb Smirnoff int i, rv, xadd = 0, xaddr = 0; 14043b3a8eb9SGleb Smirnoff 14053b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 14063b3a8eb9SGleb Smirnoff 14073b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ADDRSTOO); 14083b3a8eb9SGleb Smirnoff if (size && !(flags & PFR_FLAG_ADDRSTOO)) 14093b3a8eb9SGleb Smirnoff return (EINVAL); 14103b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK, 14113b3a8eb9SGleb Smirnoff flags & PFR_FLAG_USERIOCTL)) 14123b3a8eb9SGleb Smirnoff return (EINVAL); 14133b3a8eb9SGleb Smirnoff rs = pf_find_ruleset(tbl->pfrt_anchor); 14143b3a8eb9SGleb Smirnoff if (rs == NULL || !rs->topen || ticket != rs->tticket) 14153b3a8eb9SGleb Smirnoff return (EBUSY); 14163b3a8eb9SGleb Smirnoff tbl->pfrt_flags |= PFR_TFLAG_INACTIVE; 14173b3a8eb9SGleb Smirnoff SLIST_INIT(&tableq); 14183b3a8eb9SGleb Smirnoff kt = RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl); 14193b3a8eb9SGleb Smirnoff if (kt == NULL) { 14203b3a8eb9SGleb Smirnoff kt = pfr_create_ktable(tbl, 0, 1); 14213b3a8eb9SGleb Smirnoff if (kt == NULL) 14223b3a8eb9SGleb Smirnoff return (ENOMEM); 14233b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&tableq, kt, pfrkt_workq); 14243b3a8eb9SGleb Smirnoff xadd++; 14253b3a8eb9SGleb Smirnoff if (!tbl->pfrt_anchor[0]) 14263b3a8eb9SGleb Smirnoff goto _skip; 14273b3a8eb9SGleb Smirnoff 14283b3a8eb9SGleb Smirnoff /* find or create root table */ 14293b3a8eb9SGleb Smirnoff bzero(&key, sizeof(key)); 14303b3a8eb9SGleb Smirnoff strlcpy(key.pfrkt_name, tbl->pfrt_name, sizeof(key.pfrkt_name)); 14313b3a8eb9SGleb Smirnoff rt = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 14323b3a8eb9SGleb Smirnoff if (rt != NULL) { 14333b3a8eb9SGleb Smirnoff kt->pfrkt_root = rt; 14343b3a8eb9SGleb Smirnoff goto _skip; 14353b3a8eb9SGleb Smirnoff } 14363b3a8eb9SGleb Smirnoff rt = pfr_create_ktable(&key.pfrkt_t, 0, 1); 14373b3a8eb9SGleb Smirnoff if (rt == NULL) { 14383b3a8eb9SGleb Smirnoff pfr_destroy_ktables(&tableq, 0); 14393b3a8eb9SGleb Smirnoff return (ENOMEM); 14403b3a8eb9SGleb Smirnoff } 14413b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&tableq, rt, pfrkt_workq); 14423b3a8eb9SGleb Smirnoff kt->pfrkt_root = rt; 14433b3a8eb9SGleb Smirnoff } else if (!(kt->pfrkt_flags & PFR_TFLAG_INACTIVE)) 14443b3a8eb9SGleb Smirnoff xadd++; 14453b3a8eb9SGleb Smirnoff _skip: 14463b3a8eb9SGleb Smirnoff shadow = pfr_create_ktable(tbl, 0, 0); 14473b3a8eb9SGleb Smirnoff if (shadow == NULL) { 14483b3a8eb9SGleb Smirnoff pfr_destroy_ktables(&tableq, 0); 14493b3a8eb9SGleb Smirnoff return (ENOMEM); 14503b3a8eb9SGleb Smirnoff } 14513b3a8eb9SGleb Smirnoff SLIST_INIT(&addrq); 14523b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) { 14533b3a8eb9SGleb Smirnoff if (pfr_validate_addr(ad)) 14543b3a8eb9SGleb Smirnoff senderr(EINVAL); 14553b3a8eb9SGleb Smirnoff if (pfr_lookup_addr(shadow, ad, 1) != NULL) 14563b3a8eb9SGleb Smirnoff continue; 14573b3a8eb9SGleb Smirnoff p = pfr_create_kentry(ad); 14583b3a8eb9SGleb Smirnoff if (p == NULL) 14593b3a8eb9SGleb Smirnoff senderr(ENOMEM); 14603b3a8eb9SGleb Smirnoff if (pfr_route_kentry(shadow, p)) { 14613b3a8eb9SGleb Smirnoff pfr_destroy_kentry(p); 14623b3a8eb9SGleb Smirnoff continue; 14633b3a8eb9SGleb Smirnoff } 14643b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&addrq, p, pfrke_workq); 14653b3a8eb9SGleb Smirnoff xaddr++; 14663b3a8eb9SGleb Smirnoff } 14673b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 14683b3a8eb9SGleb Smirnoff if (kt->pfrkt_shadow != NULL) 14693b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt->pfrkt_shadow, 1); 14703b3a8eb9SGleb Smirnoff kt->pfrkt_flags |= PFR_TFLAG_INACTIVE; 14713b3a8eb9SGleb Smirnoff pfr_insert_ktables(&tableq); 14723b3a8eb9SGleb Smirnoff shadow->pfrkt_cnt = (flags & PFR_FLAG_ADDRSTOO) ? 14733b3a8eb9SGleb Smirnoff xaddr : NO_ADDRESSES; 14743b3a8eb9SGleb Smirnoff kt->pfrkt_shadow = shadow; 14753b3a8eb9SGleb Smirnoff } else { 14763b3a8eb9SGleb Smirnoff pfr_clean_node_mask(shadow, &addrq); 14773b3a8eb9SGleb Smirnoff pfr_destroy_ktable(shadow, 0); 14783b3a8eb9SGleb Smirnoff pfr_destroy_ktables(&tableq, 0); 14793b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&addrq); 14803b3a8eb9SGleb Smirnoff } 14813b3a8eb9SGleb Smirnoff if (nadd != NULL) 14823b3a8eb9SGleb Smirnoff *nadd = xadd; 14833b3a8eb9SGleb Smirnoff if (naddr != NULL) 14843b3a8eb9SGleb Smirnoff *naddr = xaddr; 14853b3a8eb9SGleb Smirnoff return (0); 14863b3a8eb9SGleb Smirnoff _bad: 14873b3a8eb9SGleb Smirnoff pfr_destroy_ktable(shadow, 0); 14883b3a8eb9SGleb Smirnoff pfr_destroy_ktables(&tableq, 0); 14893b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&addrq); 14903b3a8eb9SGleb Smirnoff return (rv); 14913b3a8eb9SGleb Smirnoff } 14923b3a8eb9SGleb Smirnoff 14933b3a8eb9SGleb Smirnoff int 14943b3a8eb9SGleb Smirnoff pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags) 14953b3a8eb9SGleb Smirnoff { 14963b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 14973b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 14983b3a8eb9SGleb Smirnoff struct pf_ruleset *rs; 14993b3a8eb9SGleb Smirnoff int xdel = 0; 15003b3a8eb9SGleb Smirnoff 15013b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 15023b3a8eb9SGleb Smirnoff 15033b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 15043b3a8eb9SGleb Smirnoff rs = pf_find_ruleset(trs->pfrt_anchor); 15053b3a8eb9SGleb Smirnoff if (rs == NULL || !rs->topen || ticket != rs->tticket) 15063b3a8eb9SGleb Smirnoff return (0); 15073b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 15083b3a8eb9SGleb Smirnoff RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 15093b3a8eb9SGleb Smirnoff if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || 15103b3a8eb9SGleb Smirnoff pfr_skip_table(trs, p, 0)) 15113b3a8eb9SGleb Smirnoff continue; 15123b3a8eb9SGleb Smirnoff p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE; 15133b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 15143b3a8eb9SGleb Smirnoff xdel++; 15153b3a8eb9SGleb Smirnoff } 15163b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 15173b3a8eb9SGleb Smirnoff pfr_setflags_ktables(&workq); 15183b3a8eb9SGleb Smirnoff rs->topen = 0; 15193b3a8eb9SGleb Smirnoff pf_remove_if_empty_ruleset(rs); 15203b3a8eb9SGleb Smirnoff } 15213b3a8eb9SGleb Smirnoff if (ndel != NULL) 15223b3a8eb9SGleb Smirnoff *ndel = xdel; 15233b3a8eb9SGleb Smirnoff return (0); 15243b3a8eb9SGleb Smirnoff } 15253b3a8eb9SGleb Smirnoff 15263b3a8eb9SGleb Smirnoff int 15273b3a8eb9SGleb Smirnoff pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd, 15283b3a8eb9SGleb Smirnoff int *nchange, int flags) 15293b3a8eb9SGleb Smirnoff { 15303b3a8eb9SGleb Smirnoff struct pfr_ktable *p, *q; 15313b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 15323b3a8eb9SGleb Smirnoff struct pf_ruleset *rs; 15333b3a8eb9SGleb Smirnoff int xadd = 0, xchange = 0; 15343b3a8eb9SGleb Smirnoff long tzero = time_second; 15353b3a8eb9SGleb Smirnoff 15363b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 15373b3a8eb9SGleb Smirnoff 15383b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 15393b3a8eb9SGleb Smirnoff rs = pf_find_ruleset(trs->pfrt_anchor); 15403b3a8eb9SGleb Smirnoff if (rs == NULL || !rs->topen || ticket != rs->tticket) 15413b3a8eb9SGleb Smirnoff return (EBUSY); 15423b3a8eb9SGleb Smirnoff 15433b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 15443b3a8eb9SGleb Smirnoff RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 15453b3a8eb9SGleb Smirnoff if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || 15463b3a8eb9SGleb Smirnoff pfr_skip_table(trs, p, 0)) 15473b3a8eb9SGleb Smirnoff continue; 15483b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 15493b3a8eb9SGleb Smirnoff if (p->pfrkt_flags & PFR_TFLAG_ACTIVE) 15503b3a8eb9SGleb Smirnoff xchange++; 15513b3a8eb9SGleb Smirnoff else 15523b3a8eb9SGleb Smirnoff xadd++; 15533b3a8eb9SGleb Smirnoff } 15543b3a8eb9SGleb Smirnoff 15553b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 15563b3a8eb9SGleb Smirnoff for (p = SLIST_FIRST(&workq); p != NULL; p = q) { 15573b3a8eb9SGleb Smirnoff q = SLIST_NEXT(p, pfrkt_workq); 15583b3a8eb9SGleb Smirnoff pfr_commit_ktable(p, tzero); 15593b3a8eb9SGleb Smirnoff } 15603b3a8eb9SGleb Smirnoff rs->topen = 0; 15613b3a8eb9SGleb Smirnoff pf_remove_if_empty_ruleset(rs); 15623b3a8eb9SGleb Smirnoff } 15633b3a8eb9SGleb Smirnoff if (nadd != NULL) 15643b3a8eb9SGleb Smirnoff *nadd = xadd; 15653b3a8eb9SGleb Smirnoff if (nchange != NULL) 15663b3a8eb9SGleb Smirnoff *nchange = xchange; 15673b3a8eb9SGleb Smirnoff 15683b3a8eb9SGleb Smirnoff return (0); 15693b3a8eb9SGleb Smirnoff } 15703b3a8eb9SGleb Smirnoff 15713b3a8eb9SGleb Smirnoff static void 15723b3a8eb9SGleb Smirnoff pfr_commit_ktable(struct pfr_ktable *kt, long tzero) 15733b3a8eb9SGleb Smirnoff { 15743b3a8eb9SGleb Smirnoff struct pfr_ktable *shadow = kt->pfrkt_shadow; 15753b3a8eb9SGleb Smirnoff int nflags; 15763b3a8eb9SGleb Smirnoff 15773b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 15783b3a8eb9SGleb Smirnoff 15793b3a8eb9SGleb Smirnoff if (shadow->pfrkt_cnt == NO_ADDRESSES) { 15803b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 15813b3a8eb9SGleb Smirnoff pfr_clstats_ktable(kt, tzero, 1); 15823b3a8eb9SGleb Smirnoff } else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) { 15833b3a8eb9SGleb Smirnoff /* kt might contain addresses */ 15843b3a8eb9SGleb Smirnoff struct pfr_kentryworkq addrq, addq, changeq, delq, garbageq; 15853b3a8eb9SGleb Smirnoff struct pfr_kentry *p, *q, *next; 15863b3a8eb9SGleb Smirnoff struct pfr_addr ad; 15873b3a8eb9SGleb Smirnoff 15883b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(shadow, &addrq, NULL, 0); 15893b3a8eb9SGleb Smirnoff pfr_mark_addrs(kt); 15903b3a8eb9SGleb Smirnoff SLIST_INIT(&addq); 15913b3a8eb9SGleb Smirnoff SLIST_INIT(&changeq); 15923b3a8eb9SGleb Smirnoff SLIST_INIT(&delq); 15933b3a8eb9SGleb Smirnoff SLIST_INIT(&garbageq); 15943b3a8eb9SGleb Smirnoff pfr_clean_node_mask(shadow, &addrq); 15953b3a8eb9SGleb Smirnoff for (p = SLIST_FIRST(&addrq); p != NULL; p = next) { 15963b3a8eb9SGleb Smirnoff next = SLIST_NEXT(p, pfrke_workq); /* XXX */ 15973b3a8eb9SGleb Smirnoff pfr_copyout_addr(&ad, p); 15983b3a8eb9SGleb Smirnoff q = pfr_lookup_addr(kt, &ad, 1); 15993b3a8eb9SGleb Smirnoff if (q != NULL) { 16003b3a8eb9SGleb Smirnoff if (q->pfrke_not != p->pfrke_not) 16013b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&changeq, q, 16023b3a8eb9SGleb Smirnoff pfrke_workq); 16033b3a8eb9SGleb Smirnoff q->pfrke_mark = 1; 16043b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq); 16053b3a8eb9SGleb Smirnoff } else { 16063b3a8eb9SGleb Smirnoff p->pfrke_tzero = tzero; 16073b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&addq, p, pfrke_workq); 16083b3a8eb9SGleb Smirnoff } 16093b3a8eb9SGleb Smirnoff } 16103b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &delq, NULL, ENQUEUE_UNMARKED_ONLY); 16113b3a8eb9SGleb Smirnoff pfr_insert_kentries(kt, &addq, tzero); 16123b3a8eb9SGleb Smirnoff pfr_remove_kentries(kt, &delq); 16133b3a8eb9SGleb Smirnoff pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG); 16143b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&garbageq); 16153b3a8eb9SGleb Smirnoff } else { 16163b3a8eb9SGleb Smirnoff /* kt cannot contain addresses */ 16173b3a8eb9SGleb Smirnoff SWAP(struct radix_node_head *, kt->pfrkt_ip4, 16183b3a8eb9SGleb Smirnoff shadow->pfrkt_ip4); 16193b3a8eb9SGleb Smirnoff SWAP(struct radix_node_head *, kt->pfrkt_ip6, 16203b3a8eb9SGleb Smirnoff shadow->pfrkt_ip6); 16213b3a8eb9SGleb Smirnoff SWAP(int, kt->pfrkt_cnt, shadow->pfrkt_cnt); 16223b3a8eb9SGleb Smirnoff pfr_clstats_ktable(kt, tzero, 1); 16233b3a8eb9SGleb Smirnoff } 16243b3a8eb9SGleb Smirnoff nflags = ((shadow->pfrkt_flags & PFR_TFLAG_USRMASK) | 16253b3a8eb9SGleb Smirnoff (kt->pfrkt_flags & PFR_TFLAG_SETMASK) | PFR_TFLAG_ACTIVE) 16263b3a8eb9SGleb Smirnoff & ~PFR_TFLAG_INACTIVE; 16273b3a8eb9SGleb Smirnoff pfr_destroy_ktable(shadow, 0); 16283b3a8eb9SGleb Smirnoff kt->pfrkt_shadow = NULL; 16293b3a8eb9SGleb Smirnoff pfr_setflags_ktable(kt, nflags); 16303b3a8eb9SGleb Smirnoff } 16313b3a8eb9SGleb Smirnoff 16323b3a8eb9SGleb Smirnoff static int 16333b3a8eb9SGleb Smirnoff pfr_validate_table(struct pfr_table *tbl, int allowedflags, int no_reserved) 16343b3a8eb9SGleb Smirnoff { 16353b3a8eb9SGleb Smirnoff int i; 16363b3a8eb9SGleb Smirnoff 16373b3a8eb9SGleb Smirnoff if (!tbl->pfrt_name[0]) 16383b3a8eb9SGleb Smirnoff return (-1); 16393b3a8eb9SGleb Smirnoff if (no_reserved && !strcmp(tbl->pfrt_anchor, PF_RESERVED_ANCHOR)) 16403b3a8eb9SGleb Smirnoff return (-1); 16413b3a8eb9SGleb Smirnoff if (tbl->pfrt_name[PF_TABLE_NAME_SIZE-1]) 16423b3a8eb9SGleb Smirnoff return (-1); 16433b3a8eb9SGleb Smirnoff for (i = strlen(tbl->pfrt_name); i < PF_TABLE_NAME_SIZE; i++) 16443b3a8eb9SGleb Smirnoff if (tbl->pfrt_name[i]) 16453b3a8eb9SGleb Smirnoff return (-1); 16463b3a8eb9SGleb Smirnoff if (pfr_fix_anchor(tbl->pfrt_anchor)) 16473b3a8eb9SGleb Smirnoff return (-1); 16483b3a8eb9SGleb Smirnoff if (tbl->pfrt_flags & ~allowedflags) 16493b3a8eb9SGleb Smirnoff return (-1); 16503b3a8eb9SGleb Smirnoff return (0); 16513b3a8eb9SGleb Smirnoff } 16523b3a8eb9SGleb Smirnoff 16533b3a8eb9SGleb Smirnoff /* 16543b3a8eb9SGleb Smirnoff * Rewrite anchors referenced by tables to remove slashes 16553b3a8eb9SGleb Smirnoff * and check for validity. 16563b3a8eb9SGleb Smirnoff */ 16573b3a8eb9SGleb Smirnoff static int 16583b3a8eb9SGleb Smirnoff pfr_fix_anchor(char *anchor) 16593b3a8eb9SGleb Smirnoff { 16603b3a8eb9SGleb Smirnoff size_t siz = MAXPATHLEN; 16613b3a8eb9SGleb Smirnoff int i; 16623b3a8eb9SGleb Smirnoff 16633b3a8eb9SGleb Smirnoff if (anchor[0] == '/') { 16643b3a8eb9SGleb Smirnoff char *path; 16653b3a8eb9SGleb Smirnoff int off; 16663b3a8eb9SGleb Smirnoff 16673b3a8eb9SGleb Smirnoff path = anchor; 16683b3a8eb9SGleb Smirnoff off = 1; 16693b3a8eb9SGleb Smirnoff while (*++path == '/') 16703b3a8eb9SGleb Smirnoff off++; 16713b3a8eb9SGleb Smirnoff bcopy(path, anchor, siz - off); 16723b3a8eb9SGleb Smirnoff memset(anchor + siz - off, 0, off); 16733b3a8eb9SGleb Smirnoff } 16743b3a8eb9SGleb Smirnoff if (anchor[siz - 1]) 16753b3a8eb9SGleb Smirnoff return (-1); 16763b3a8eb9SGleb Smirnoff for (i = strlen(anchor); i < siz; i++) 16773b3a8eb9SGleb Smirnoff if (anchor[i]) 16783b3a8eb9SGleb Smirnoff return (-1); 16793b3a8eb9SGleb Smirnoff return (0); 16803b3a8eb9SGleb Smirnoff } 16813b3a8eb9SGleb Smirnoff 16823b3a8eb9SGleb Smirnoff static int 16833b3a8eb9SGleb Smirnoff pfr_table_count(struct pfr_table *filter, int flags) 16843b3a8eb9SGleb Smirnoff { 16853b3a8eb9SGleb Smirnoff struct pf_ruleset *rs; 16863b3a8eb9SGleb Smirnoff 16873b3a8eb9SGleb Smirnoff PF_RULES_ASSERT(); 16883b3a8eb9SGleb Smirnoff 16893b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_ALLRSETS) 16903b3a8eb9SGleb Smirnoff return (pfr_ktable_cnt); 16913b3a8eb9SGleb Smirnoff if (filter->pfrt_anchor[0]) { 16923b3a8eb9SGleb Smirnoff rs = pf_find_ruleset(filter->pfrt_anchor); 16933b3a8eb9SGleb Smirnoff return ((rs != NULL) ? rs->tables : -1); 16943b3a8eb9SGleb Smirnoff } 16953b3a8eb9SGleb Smirnoff return (pf_main_ruleset.tables); 16963b3a8eb9SGleb Smirnoff } 16973b3a8eb9SGleb Smirnoff 16983b3a8eb9SGleb Smirnoff static int 16993b3a8eb9SGleb Smirnoff pfr_skip_table(struct pfr_table *filter, struct pfr_ktable *kt, int flags) 17003b3a8eb9SGleb Smirnoff { 17013b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_ALLRSETS) 17023b3a8eb9SGleb Smirnoff return (0); 17033b3a8eb9SGleb Smirnoff if (strcmp(filter->pfrt_anchor, kt->pfrkt_anchor)) 17043b3a8eb9SGleb Smirnoff return (1); 17053b3a8eb9SGleb Smirnoff return (0); 17063b3a8eb9SGleb Smirnoff } 17073b3a8eb9SGleb Smirnoff 17083b3a8eb9SGleb Smirnoff static void 17093b3a8eb9SGleb Smirnoff pfr_insert_ktables(struct pfr_ktableworkq *workq) 17103b3a8eb9SGleb Smirnoff { 17113b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 17123b3a8eb9SGleb Smirnoff 17133b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, workq, pfrkt_workq) 17143b3a8eb9SGleb Smirnoff pfr_insert_ktable(p); 17153b3a8eb9SGleb Smirnoff } 17163b3a8eb9SGleb Smirnoff 17173b3a8eb9SGleb Smirnoff static void 17183b3a8eb9SGleb Smirnoff pfr_insert_ktable(struct pfr_ktable *kt) 17193b3a8eb9SGleb Smirnoff { 17203b3a8eb9SGleb Smirnoff 17213b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 17223b3a8eb9SGleb Smirnoff 17233b3a8eb9SGleb Smirnoff RB_INSERT(pfr_ktablehead, &pfr_ktables, kt); 17243b3a8eb9SGleb Smirnoff pfr_ktable_cnt++; 17253b3a8eb9SGleb Smirnoff if (kt->pfrkt_root != NULL) 17263b3a8eb9SGleb Smirnoff if (!kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]++) 17273b3a8eb9SGleb Smirnoff pfr_setflags_ktable(kt->pfrkt_root, 17283b3a8eb9SGleb Smirnoff kt->pfrkt_root->pfrkt_flags|PFR_TFLAG_REFDANCHOR); 17293b3a8eb9SGleb Smirnoff } 17303b3a8eb9SGleb Smirnoff 17313b3a8eb9SGleb Smirnoff static void 17323b3a8eb9SGleb Smirnoff pfr_setflags_ktables(struct pfr_ktableworkq *workq) 17333b3a8eb9SGleb Smirnoff { 17343b3a8eb9SGleb Smirnoff struct pfr_ktable *p, *q; 17353b3a8eb9SGleb Smirnoff 17363b3a8eb9SGleb Smirnoff for (p = SLIST_FIRST(workq); p; p = q) { 17373b3a8eb9SGleb Smirnoff q = SLIST_NEXT(p, pfrkt_workq); 17383b3a8eb9SGleb Smirnoff pfr_setflags_ktable(p, p->pfrkt_nflags); 17393b3a8eb9SGleb Smirnoff } 17403b3a8eb9SGleb Smirnoff } 17413b3a8eb9SGleb Smirnoff 17423b3a8eb9SGleb Smirnoff static void 17433b3a8eb9SGleb Smirnoff pfr_setflags_ktable(struct pfr_ktable *kt, int newf) 17443b3a8eb9SGleb Smirnoff { 17453b3a8eb9SGleb Smirnoff struct pfr_kentryworkq addrq; 17463b3a8eb9SGleb Smirnoff 17473b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 17483b3a8eb9SGleb Smirnoff 17493b3a8eb9SGleb Smirnoff if (!(newf & PFR_TFLAG_REFERENCED) && 17503b3a8eb9SGleb Smirnoff !(newf & PFR_TFLAG_PERSIST)) 17513b3a8eb9SGleb Smirnoff newf &= ~PFR_TFLAG_ACTIVE; 17523b3a8eb9SGleb Smirnoff if (!(newf & PFR_TFLAG_ACTIVE)) 17533b3a8eb9SGleb Smirnoff newf &= ~PFR_TFLAG_USRMASK; 17543b3a8eb9SGleb Smirnoff if (!(newf & PFR_TFLAG_SETMASK)) { 17553b3a8eb9SGleb Smirnoff RB_REMOVE(pfr_ktablehead, &pfr_ktables, kt); 17563b3a8eb9SGleb Smirnoff if (kt->pfrkt_root != NULL) 17573b3a8eb9SGleb Smirnoff if (!--kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]) 17583b3a8eb9SGleb Smirnoff pfr_setflags_ktable(kt->pfrkt_root, 17593b3a8eb9SGleb Smirnoff kt->pfrkt_root->pfrkt_flags & 17603b3a8eb9SGleb Smirnoff ~PFR_TFLAG_REFDANCHOR); 17613b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt, 1); 17623b3a8eb9SGleb Smirnoff pfr_ktable_cnt--; 17633b3a8eb9SGleb Smirnoff return; 17643b3a8eb9SGleb Smirnoff } 17653b3a8eb9SGleb Smirnoff if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) { 17663b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &addrq, NULL, 0); 17673b3a8eb9SGleb Smirnoff pfr_remove_kentries(kt, &addrq); 17683b3a8eb9SGleb Smirnoff } 17693b3a8eb9SGleb Smirnoff if (!(newf & PFR_TFLAG_INACTIVE) && kt->pfrkt_shadow != NULL) { 17703b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt->pfrkt_shadow, 1); 17713b3a8eb9SGleb Smirnoff kt->pfrkt_shadow = NULL; 17723b3a8eb9SGleb Smirnoff } 17733b3a8eb9SGleb Smirnoff kt->pfrkt_flags = newf; 17743b3a8eb9SGleb Smirnoff } 17753b3a8eb9SGleb Smirnoff 17763b3a8eb9SGleb Smirnoff static void 17773b3a8eb9SGleb Smirnoff pfr_clstats_ktables(struct pfr_ktableworkq *workq, long tzero, int recurse) 17783b3a8eb9SGleb Smirnoff { 17793b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 17803b3a8eb9SGleb Smirnoff 17813b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, workq, pfrkt_workq) 17823b3a8eb9SGleb Smirnoff pfr_clstats_ktable(p, tzero, recurse); 17833b3a8eb9SGleb Smirnoff } 17843b3a8eb9SGleb Smirnoff 17853b3a8eb9SGleb Smirnoff static void 17863b3a8eb9SGleb Smirnoff pfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse) 17873b3a8eb9SGleb Smirnoff { 17883b3a8eb9SGleb Smirnoff struct pfr_kentryworkq addrq; 17893b3a8eb9SGleb Smirnoff 17903b3a8eb9SGleb Smirnoff if (recurse) { 17913b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &addrq, NULL, 0); 17923b3a8eb9SGleb Smirnoff pfr_clstats_kentries(&addrq, tzero, 0); 17933b3a8eb9SGleb Smirnoff } 17943b3a8eb9SGleb Smirnoff bzero(kt->pfrkt_packets, sizeof(kt->pfrkt_packets)); 17953b3a8eb9SGleb Smirnoff bzero(kt->pfrkt_bytes, sizeof(kt->pfrkt_bytes)); 17963b3a8eb9SGleb Smirnoff kt->pfrkt_match = kt->pfrkt_nomatch = 0; 17973b3a8eb9SGleb Smirnoff kt->pfrkt_tzero = tzero; 17983b3a8eb9SGleb Smirnoff } 17993b3a8eb9SGleb Smirnoff 18003b3a8eb9SGleb Smirnoff static struct pfr_ktable * 18013b3a8eb9SGleb Smirnoff pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset) 18023b3a8eb9SGleb Smirnoff { 18033b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 18043b3a8eb9SGleb Smirnoff struct pf_ruleset *rs; 18053b3a8eb9SGleb Smirnoff 18063b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 18073b3a8eb9SGleb Smirnoff 18083b3a8eb9SGleb Smirnoff kt = malloc(sizeof(*kt), M_PFTABLE, M_NOWAIT|M_ZERO); 18093b3a8eb9SGleb Smirnoff if (kt == NULL) 18103b3a8eb9SGleb Smirnoff return (NULL); 18113b3a8eb9SGleb Smirnoff kt->pfrkt_t = *tbl; 18123b3a8eb9SGleb Smirnoff 18133b3a8eb9SGleb Smirnoff if (attachruleset) { 18143b3a8eb9SGleb Smirnoff rs = pf_find_or_create_ruleset(tbl->pfrt_anchor); 18153b3a8eb9SGleb Smirnoff if (!rs) { 18163b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt, 0); 18173b3a8eb9SGleb Smirnoff return (NULL); 18183b3a8eb9SGleb Smirnoff } 18193b3a8eb9SGleb Smirnoff kt->pfrkt_rs = rs; 18203b3a8eb9SGleb Smirnoff rs->tables++; 18213b3a8eb9SGleb Smirnoff } 18223b3a8eb9SGleb Smirnoff 18233b3a8eb9SGleb Smirnoff if (!rn_inithead((void **)&kt->pfrkt_ip4, 18243b3a8eb9SGleb Smirnoff offsetof(struct sockaddr_in, sin_addr) * 8) || 18253b3a8eb9SGleb Smirnoff !rn_inithead((void **)&kt->pfrkt_ip6, 18263b3a8eb9SGleb Smirnoff offsetof(struct sockaddr_in6, sin6_addr) * 8)) { 18273b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt, 0); 18283b3a8eb9SGleb Smirnoff return (NULL); 18293b3a8eb9SGleb Smirnoff } 18303b3a8eb9SGleb Smirnoff kt->pfrkt_tzero = tzero; 18313b3a8eb9SGleb Smirnoff 18323b3a8eb9SGleb Smirnoff return (kt); 18333b3a8eb9SGleb Smirnoff } 18343b3a8eb9SGleb Smirnoff 18353b3a8eb9SGleb Smirnoff static void 18363b3a8eb9SGleb Smirnoff pfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr) 18373b3a8eb9SGleb Smirnoff { 18383b3a8eb9SGleb Smirnoff struct pfr_ktable *p, *q; 18393b3a8eb9SGleb Smirnoff 18403b3a8eb9SGleb Smirnoff for (p = SLIST_FIRST(workq); p; p = q) { 18413b3a8eb9SGleb Smirnoff q = SLIST_NEXT(p, pfrkt_workq); 18423b3a8eb9SGleb Smirnoff pfr_destroy_ktable(p, flushaddr); 18433b3a8eb9SGleb Smirnoff } 18443b3a8eb9SGleb Smirnoff } 18453b3a8eb9SGleb Smirnoff 18463b3a8eb9SGleb Smirnoff static void 18473b3a8eb9SGleb Smirnoff pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr) 18483b3a8eb9SGleb Smirnoff { 18493b3a8eb9SGleb Smirnoff struct pfr_kentryworkq addrq; 18503b3a8eb9SGleb Smirnoff 18513b3a8eb9SGleb Smirnoff if (flushaddr) { 18523b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &addrq, NULL, 0); 18533b3a8eb9SGleb Smirnoff pfr_clean_node_mask(kt, &addrq); 18543b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&addrq); 18553b3a8eb9SGleb Smirnoff } 18563b3a8eb9SGleb Smirnoff if (kt->pfrkt_ip4 != NULL) { 18573b3a8eb9SGleb Smirnoff RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip4); 1858*495a22b5SGleb Smirnoff rn_detachhead((void **)&kt->pfrkt_ip4); 18593b3a8eb9SGleb Smirnoff } 18603b3a8eb9SGleb Smirnoff if (kt->pfrkt_ip6 != NULL) { 18613b3a8eb9SGleb Smirnoff RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip6); 1862*495a22b5SGleb Smirnoff rn_detachhead((void **)&kt->pfrkt_ip6); 18633b3a8eb9SGleb Smirnoff } 18643b3a8eb9SGleb Smirnoff if (kt->pfrkt_shadow != NULL) 18653b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr); 18663b3a8eb9SGleb Smirnoff if (kt->pfrkt_rs != NULL) { 18673b3a8eb9SGleb Smirnoff kt->pfrkt_rs->tables--; 18683b3a8eb9SGleb Smirnoff pf_remove_if_empty_ruleset(kt->pfrkt_rs); 18693b3a8eb9SGleb Smirnoff } 18703b3a8eb9SGleb Smirnoff free(kt, M_PFTABLE); 18713b3a8eb9SGleb Smirnoff } 18723b3a8eb9SGleb Smirnoff 18733b3a8eb9SGleb Smirnoff static int 18743b3a8eb9SGleb Smirnoff pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q) 18753b3a8eb9SGleb Smirnoff { 18763b3a8eb9SGleb Smirnoff int d; 18773b3a8eb9SGleb Smirnoff 18783b3a8eb9SGleb Smirnoff if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE))) 18793b3a8eb9SGleb Smirnoff return (d); 18803b3a8eb9SGleb Smirnoff return (strcmp(p->pfrkt_anchor, q->pfrkt_anchor)); 18813b3a8eb9SGleb Smirnoff } 18823b3a8eb9SGleb Smirnoff 18833b3a8eb9SGleb Smirnoff static struct pfr_ktable * 18843b3a8eb9SGleb Smirnoff pfr_lookup_table(struct pfr_table *tbl) 18853b3a8eb9SGleb Smirnoff { 18863b3a8eb9SGleb Smirnoff /* struct pfr_ktable start like a struct pfr_table */ 18873b3a8eb9SGleb Smirnoff return (RB_FIND(pfr_ktablehead, &pfr_ktables, 18883b3a8eb9SGleb Smirnoff (struct pfr_ktable *)tbl)); 18893b3a8eb9SGleb Smirnoff } 18903b3a8eb9SGleb Smirnoff 18913b3a8eb9SGleb Smirnoff int 18923b3a8eb9SGleb Smirnoff pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) 18933b3a8eb9SGleb Smirnoff { 18943b3a8eb9SGleb Smirnoff struct pfr_kentry *ke = NULL; 18953b3a8eb9SGleb Smirnoff int match; 18963b3a8eb9SGleb Smirnoff 18973b3a8eb9SGleb Smirnoff PF_RULES_RASSERT(); 18983b3a8eb9SGleb Smirnoff 18993b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 19003b3a8eb9SGleb Smirnoff kt = kt->pfrkt_root; 19013b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 19023b3a8eb9SGleb Smirnoff return (0); 19033b3a8eb9SGleb Smirnoff 19043b3a8eb9SGleb Smirnoff switch (af) { 19053b3a8eb9SGleb Smirnoff #ifdef INET 19063b3a8eb9SGleb Smirnoff case AF_INET: 19073b3a8eb9SGleb Smirnoff { 19083b3a8eb9SGleb Smirnoff struct sockaddr_in sin; 19093b3a8eb9SGleb Smirnoff 19103b3a8eb9SGleb Smirnoff bzero(&sin, sizeof(sin)); 19113b3a8eb9SGleb Smirnoff sin.sin_len = sizeof(sin); 19123b3a8eb9SGleb Smirnoff sin.sin_family = AF_INET; 19133b3a8eb9SGleb Smirnoff sin.sin_addr.s_addr = a->addr32[0]; 19143b3a8eb9SGleb Smirnoff ke = (struct pfr_kentry *)rn_match(&sin, kt->pfrkt_ip4); 19153b3a8eb9SGleb Smirnoff if (ke && KENTRY_RNF_ROOT(ke)) 19163b3a8eb9SGleb Smirnoff ke = NULL; 19173b3a8eb9SGleb Smirnoff break; 19183b3a8eb9SGleb Smirnoff } 19193b3a8eb9SGleb Smirnoff #endif /* INET */ 19203b3a8eb9SGleb Smirnoff #ifdef INET6 19213b3a8eb9SGleb Smirnoff case AF_INET6: 19223b3a8eb9SGleb Smirnoff { 19233b3a8eb9SGleb Smirnoff struct sockaddr_in6 sin6; 19243b3a8eb9SGleb Smirnoff 19253b3a8eb9SGleb Smirnoff bzero(&sin6, sizeof(sin6)); 19263b3a8eb9SGleb Smirnoff sin6.sin6_len = sizeof(sin6); 19273b3a8eb9SGleb Smirnoff sin6.sin6_family = AF_INET6; 19283b3a8eb9SGleb Smirnoff bcopy(a, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); 19293b3a8eb9SGleb Smirnoff ke = (struct pfr_kentry *)rn_match(&sin6, kt->pfrkt_ip6); 19303b3a8eb9SGleb Smirnoff if (ke && KENTRY_RNF_ROOT(ke)) 19313b3a8eb9SGleb Smirnoff ke = NULL; 19323b3a8eb9SGleb Smirnoff break; 19333b3a8eb9SGleb Smirnoff } 19343b3a8eb9SGleb Smirnoff #endif /* INET6 */ 19353b3a8eb9SGleb Smirnoff } 19363b3a8eb9SGleb Smirnoff match = (ke && !ke->pfrke_not); 19373b3a8eb9SGleb Smirnoff if (match) 19383b3a8eb9SGleb Smirnoff kt->pfrkt_match++; 19393b3a8eb9SGleb Smirnoff else 19403b3a8eb9SGleb Smirnoff kt->pfrkt_nomatch++; 19413b3a8eb9SGleb Smirnoff return (match); 19423b3a8eb9SGleb Smirnoff } 19433b3a8eb9SGleb Smirnoff 19443b3a8eb9SGleb Smirnoff void 19453b3a8eb9SGleb Smirnoff pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, 19463b3a8eb9SGleb Smirnoff u_int64_t len, int dir_out, int op_pass, int notrule) 19473b3a8eb9SGleb Smirnoff { 19483b3a8eb9SGleb Smirnoff struct pfr_kentry *ke = NULL; 19493b3a8eb9SGleb Smirnoff 19503b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 19513b3a8eb9SGleb Smirnoff kt = kt->pfrkt_root; 19523b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 19533b3a8eb9SGleb Smirnoff return; 19543b3a8eb9SGleb Smirnoff 19553b3a8eb9SGleb Smirnoff switch (af) { 19563b3a8eb9SGleb Smirnoff #ifdef INET 19573b3a8eb9SGleb Smirnoff case AF_INET: 19583b3a8eb9SGleb Smirnoff { 19593b3a8eb9SGleb Smirnoff struct sockaddr_in sin; 19603b3a8eb9SGleb Smirnoff 19617348c524SGleb Smirnoff bzero(&sin, sizeof(sin)); 19623b3a8eb9SGleb Smirnoff sin.sin_len = sizeof(sin); 19633b3a8eb9SGleb Smirnoff sin.sin_family = AF_INET; 19643b3a8eb9SGleb Smirnoff sin.sin_addr.s_addr = a->addr32[0]; 19653b3a8eb9SGleb Smirnoff ke = (struct pfr_kentry *)rn_match(&sin, kt->pfrkt_ip4); 19663b3a8eb9SGleb Smirnoff if (ke && KENTRY_RNF_ROOT(ke)) 19673b3a8eb9SGleb Smirnoff ke = NULL; 19683b3a8eb9SGleb Smirnoff break; 19693b3a8eb9SGleb Smirnoff } 19703b3a8eb9SGleb Smirnoff #endif /* INET */ 19713b3a8eb9SGleb Smirnoff #ifdef INET6 19723b3a8eb9SGleb Smirnoff case AF_INET6: 19733b3a8eb9SGleb Smirnoff { 19743b3a8eb9SGleb Smirnoff struct sockaddr_in6 sin6; 19753b3a8eb9SGleb Smirnoff 19767348c524SGleb Smirnoff bzero(&sin6, sizeof(sin6)); 19773b3a8eb9SGleb Smirnoff sin6.sin6_len = sizeof(sin6); 19783b3a8eb9SGleb Smirnoff sin6.sin6_family = AF_INET6; 19793b3a8eb9SGleb Smirnoff bcopy(a, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); 19803b3a8eb9SGleb Smirnoff ke = (struct pfr_kentry *)rn_match(&sin6, kt->pfrkt_ip6); 19813b3a8eb9SGleb Smirnoff if (ke && KENTRY_RNF_ROOT(ke)) 19823b3a8eb9SGleb Smirnoff ke = NULL; 19833b3a8eb9SGleb Smirnoff break; 19843b3a8eb9SGleb Smirnoff } 19853b3a8eb9SGleb Smirnoff #endif /* INET6 */ 19863b3a8eb9SGleb Smirnoff default: 19877348c524SGleb Smirnoff panic("%s: unknown address family %u", __func__, af); 19883b3a8eb9SGleb Smirnoff } 19893b3a8eb9SGleb Smirnoff if ((ke == NULL || ke->pfrke_not) != notrule) { 19903b3a8eb9SGleb Smirnoff if (op_pass != PFR_OP_PASS) 19913b3a8eb9SGleb Smirnoff printf("pfr_update_stats: assertion failed.\n"); 19923b3a8eb9SGleb Smirnoff op_pass = PFR_OP_XPASS; 19933b3a8eb9SGleb Smirnoff } 19943b3a8eb9SGleb Smirnoff kt->pfrkt_packets[dir_out][op_pass]++; 19953b3a8eb9SGleb Smirnoff kt->pfrkt_bytes[dir_out][op_pass] += len; 19963b3a8eb9SGleb Smirnoff if (ke != NULL && op_pass != PFR_OP_XPASS && 19973b3a8eb9SGleb Smirnoff (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) { 19983b3a8eb9SGleb Smirnoff if (ke->pfrke_counters == NULL) 19993b3a8eb9SGleb Smirnoff ke->pfrke_counters = uma_zalloc(V_pfr_kcounters_z, 20003b3a8eb9SGleb Smirnoff M_NOWAIT | M_ZERO); 20013b3a8eb9SGleb Smirnoff if (ke->pfrke_counters != NULL) { 20023b3a8eb9SGleb Smirnoff ke->pfrke_counters->pfrkc_packets[dir_out][op_pass]++; 20033b3a8eb9SGleb Smirnoff ke->pfrke_counters->pfrkc_bytes[dir_out][op_pass] += len; 20043b3a8eb9SGleb Smirnoff } 20053b3a8eb9SGleb Smirnoff } 20063b3a8eb9SGleb Smirnoff } 20073b3a8eb9SGleb Smirnoff 20083b3a8eb9SGleb Smirnoff struct pfr_ktable * 20093b3a8eb9SGleb Smirnoff pfr_attach_table(struct pf_ruleset *rs, char *name) 20103b3a8eb9SGleb Smirnoff { 20113b3a8eb9SGleb Smirnoff struct pfr_ktable *kt, *rt; 20123b3a8eb9SGleb Smirnoff struct pfr_table tbl; 20133b3a8eb9SGleb Smirnoff struct pf_anchor *ac = rs->anchor; 20143b3a8eb9SGleb Smirnoff 20153b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 20163b3a8eb9SGleb Smirnoff 20173b3a8eb9SGleb Smirnoff bzero(&tbl, sizeof(tbl)); 20183b3a8eb9SGleb Smirnoff strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)); 20193b3a8eb9SGleb Smirnoff if (ac != NULL) 20203b3a8eb9SGleb Smirnoff strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor)); 20213b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(&tbl); 20223b3a8eb9SGleb Smirnoff if (kt == NULL) { 20233b3a8eb9SGleb Smirnoff kt = pfr_create_ktable(&tbl, time_second, 1); 20243b3a8eb9SGleb Smirnoff if (kt == NULL) 20253b3a8eb9SGleb Smirnoff return (NULL); 20263b3a8eb9SGleb Smirnoff if (ac != NULL) { 20273b3a8eb9SGleb Smirnoff bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor)); 20283b3a8eb9SGleb Smirnoff rt = pfr_lookup_table(&tbl); 20293b3a8eb9SGleb Smirnoff if (rt == NULL) { 20303b3a8eb9SGleb Smirnoff rt = pfr_create_ktable(&tbl, 0, 1); 20313b3a8eb9SGleb Smirnoff if (rt == NULL) { 20323b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt, 0); 20333b3a8eb9SGleb Smirnoff return (NULL); 20343b3a8eb9SGleb Smirnoff } 20353b3a8eb9SGleb Smirnoff pfr_insert_ktable(rt); 20363b3a8eb9SGleb Smirnoff } 20373b3a8eb9SGleb Smirnoff kt->pfrkt_root = rt; 20383b3a8eb9SGleb Smirnoff } 20393b3a8eb9SGleb Smirnoff pfr_insert_ktable(kt); 20403b3a8eb9SGleb Smirnoff } 20413b3a8eb9SGleb Smirnoff if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++) 20423b3a8eb9SGleb Smirnoff pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED); 20433b3a8eb9SGleb Smirnoff return (kt); 20443b3a8eb9SGleb Smirnoff } 20453b3a8eb9SGleb Smirnoff 20463b3a8eb9SGleb Smirnoff void 20473b3a8eb9SGleb Smirnoff pfr_detach_table(struct pfr_ktable *kt) 20483b3a8eb9SGleb Smirnoff { 20493b3a8eb9SGleb Smirnoff 20503b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 20513b3a8eb9SGleb Smirnoff KASSERT(kt->pfrkt_refcnt[PFR_REFCNT_RULE] > 0, ("%s: refcount %d\n", 20523b3a8eb9SGleb Smirnoff __func__, kt->pfrkt_refcnt[PFR_REFCNT_RULE])); 20533b3a8eb9SGleb Smirnoff 20543b3a8eb9SGleb Smirnoff if (!--kt->pfrkt_refcnt[PFR_REFCNT_RULE]) 20553b3a8eb9SGleb Smirnoff pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED); 20563b3a8eb9SGleb Smirnoff } 20573b3a8eb9SGleb Smirnoff 20583b3a8eb9SGleb Smirnoff int 20593b3a8eb9SGleb Smirnoff pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, 20603b3a8eb9SGleb Smirnoff sa_family_t af) 20613b3a8eb9SGleb Smirnoff { 20623b3a8eb9SGleb Smirnoff struct pf_addr *addr, *cur, *mask; 20633b3a8eb9SGleb Smirnoff union sockaddr_union uaddr, umask; 20643b3a8eb9SGleb Smirnoff struct pfr_kentry *ke, *ke2 = NULL; 20653b3a8eb9SGleb Smirnoff int idx = -1, use_counter = 0; 20663b3a8eb9SGleb Smirnoff 20673b3a8eb9SGleb Smirnoff switch (af) { 20683b3a8eb9SGleb Smirnoff case AF_INET: 20693b3a8eb9SGleb Smirnoff uaddr.sin.sin_len = sizeof(struct sockaddr_in); 20703b3a8eb9SGleb Smirnoff uaddr.sin.sin_family = AF_INET; 20713b3a8eb9SGleb Smirnoff break; 20723b3a8eb9SGleb Smirnoff case AF_INET6: 20733b3a8eb9SGleb Smirnoff uaddr.sin6.sin6_len = sizeof(struct sockaddr_in6); 20743b3a8eb9SGleb Smirnoff uaddr.sin6.sin6_family = AF_INET6; 20753b3a8eb9SGleb Smirnoff break; 20763b3a8eb9SGleb Smirnoff } 20773b3a8eb9SGleb Smirnoff addr = SUNION2PF(&uaddr, af); 20783b3a8eb9SGleb Smirnoff 20793b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 20803b3a8eb9SGleb Smirnoff kt = kt->pfrkt_root; 20813b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 20823b3a8eb9SGleb Smirnoff return (-1); 20833b3a8eb9SGleb Smirnoff 20843b3a8eb9SGleb Smirnoff if (pidx != NULL) 20853b3a8eb9SGleb Smirnoff idx = *pidx; 20863b3a8eb9SGleb Smirnoff if (counter != NULL && idx >= 0) 20873b3a8eb9SGleb Smirnoff use_counter = 1; 20883b3a8eb9SGleb Smirnoff if (idx < 0) 20893b3a8eb9SGleb Smirnoff idx = 0; 20903b3a8eb9SGleb Smirnoff 20913b3a8eb9SGleb Smirnoff _next_block: 20923b3a8eb9SGleb Smirnoff ke = pfr_kentry_byidx(kt, idx, af); 20933b3a8eb9SGleb Smirnoff if (ke == NULL) { 20943b3a8eb9SGleb Smirnoff kt->pfrkt_nomatch++; 20953b3a8eb9SGleb Smirnoff return (1); 20963b3a8eb9SGleb Smirnoff } 20973b3a8eb9SGleb Smirnoff pfr_prepare_network(&umask, af, ke->pfrke_net); 20983b3a8eb9SGleb Smirnoff cur = SUNION2PF(&ke->pfrke_sa, af); 20993b3a8eb9SGleb Smirnoff mask = SUNION2PF(&umask, af); 21003b3a8eb9SGleb Smirnoff 21013b3a8eb9SGleb Smirnoff if (use_counter) { 21023b3a8eb9SGleb Smirnoff /* is supplied address within block? */ 21033b3a8eb9SGleb Smirnoff if (!PF_MATCHA(0, cur, mask, counter, af)) { 21043b3a8eb9SGleb Smirnoff /* no, go to next block in table */ 21053b3a8eb9SGleb Smirnoff idx++; 21063b3a8eb9SGleb Smirnoff use_counter = 0; 21073b3a8eb9SGleb Smirnoff goto _next_block; 21083b3a8eb9SGleb Smirnoff } 21093b3a8eb9SGleb Smirnoff PF_ACPY(addr, counter, af); 21103b3a8eb9SGleb Smirnoff } else { 21113b3a8eb9SGleb Smirnoff /* use first address of block */ 21123b3a8eb9SGleb Smirnoff PF_ACPY(addr, cur, af); 21133b3a8eb9SGleb Smirnoff } 21143b3a8eb9SGleb Smirnoff 21153b3a8eb9SGleb Smirnoff if (!KENTRY_NETWORK(ke)) { 21163b3a8eb9SGleb Smirnoff /* this is a single IP address - no possible nested block */ 21173b3a8eb9SGleb Smirnoff PF_ACPY(counter, addr, af); 21183b3a8eb9SGleb Smirnoff *pidx = idx; 21193b3a8eb9SGleb Smirnoff kt->pfrkt_match++; 21203b3a8eb9SGleb Smirnoff return (0); 21213b3a8eb9SGleb Smirnoff } 21223b3a8eb9SGleb Smirnoff for (;;) { 21233b3a8eb9SGleb Smirnoff /* we don't want to use a nested block */ 21243b3a8eb9SGleb Smirnoff switch (af) { 21253b3a8eb9SGleb Smirnoff case AF_INET: 21263b3a8eb9SGleb Smirnoff ke2 = (struct pfr_kentry *)rn_match(&uaddr, 21273b3a8eb9SGleb Smirnoff kt->pfrkt_ip4); 21283b3a8eb9SGleb Smirnoff break; 21293b3a8eb9SGleb Smirnoff case AF_INET6: 21303b3a8eb9SGleb Smirnoff ke2 = (struct pfr_kentry *)rn_match(&uaddr, 21313b3a8eb9SGleb Smirnoff kt->pfrkt_ip6); 21323b3a8eb9SGleb Smirnoff break; 21333b3a8eb9SGleb Smirnoff } 21343b3a8eb9SGleb Smirnoff /* no need to check KENTRY_RNF_ROOT() here */ 21353b3a8eb9SGleb Smirnoff if (ke2 == ke) { 21363b3a8eb9SGleb Smirnoff /* lookup return the same block - perfect */ 21373b3a8eb9SGleb Smirnoff PF_ACPY(counter, addr, af); 21383b3a8eb9SGleb Smirnoff *pidx = idx; 21393b3a8eb9SGleb Smirnoff kt->pfrkt_match++; 21403b3a8eb9SGleb Smirnoff return (0); 21413b3a8eb9SGleb Smirnoff } 21423b3a8eb9SGleb Smirnoff 21433b3a8eb9SGleb Smirnoff /* we need to increase the counter past the nested block */ 21443b3a8eb9SGleb Smirnoff pfr_prepare_network(&umask, AF_INET, ke2->pfrke_net); 21453b3a8eb9SGleb Smirnoff PF_POOLMASK(addr, addr, SUNION2PF(&umask, af), &pfr_ffaddr, af); 21463b3a8eb9SGleb Smirnoff PF_AINC(addr, af); 21473b3a8eb9SGleb Smirnoff if (!PF_MATCHA(0, cur, mask, addr, af)) { 21483b3a8eb9SGleb Smirnoff /* ok, we reached the end of our main block */ 21493b3a8eb9SGleb Smirnoff /* go to next block in table */ 21503b3a8eb9SGleb Smirnoff idx++; 21513b3a8eb9SGleb Smirnoff use_counter = 0; 21523b3a8eb9SGleb Smirnoff goto _next_block; 21533b3a8eb9SGleb Smirnoff } 21543b3a8eb9SGleb Smirnoff } 21553b3a8eb9SGleb Smirnoff } 21563b3a8eb9SGleb Smirnoff 21573b3a8eb9SGleb Smirnoff static struct pfr_kentry * 21583b3a8eb9SGleb Smirnoff pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af) 21593b3a8eb9SGleb Smirnoff { 21603b3a8eb9SGleb Smirnoff struct pfr_walktree w; 21613b3a8eb9SGleb Smirnoff 21623b3a8eb9SGleb Smirnoff bzero(&w, sizeof(w)); 21633b3a8eb9SGleb Smirnoff w.pfrw_op = PFRW_POOL_GET; 21643b3a8eb9SGleb Smirnoff w.pfrw_cnt = idx; 21653b3a8eb9SGleb Smirnoff 21663b3a8eb9SGleb Smirnoff switch (af) { 21673b3a8eb9SGleb Smirnoff #ifdef INET 21683b3a8eb9SGleb Smirnoff case AF_INET: 21693b3a8eb9SGleb Smirnoff kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 21703b3a8eb9SGleb Smirnoff return (w.pfrw_kentry); 21713b3a8eb9SGleb Smirnoff #endif /* INET */ 21723b3a8eb9SGleb Smirnoff #ifdef INET6 21733b3a8eb9SGleb Smirnoff case AF_INET6: 21743b3a8eb9SGleb Smirnoff kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); 21753b3a8eb9SGleb Smirnoff return (w.pfrw_kentry); 21763b3a8eb9SGleb Smirnoff #endif /* INET6 */ 21773b3a8eb9SGleb Smirnoff default: 21783b3a8eb9SGleb Smirnoff return (NULL); 21793b3a8eb9SGleb Smirnoff } 21803b3a8eb9SGleb Smirnoff } 21813b3a8eb9SGleb Smirnoff 21823b3a8eb9SGleb Smirnoff void 21833b3a8eb9SGleb Smirnoff pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn) 21843b3a8eb9SGleb Smirnoff { 21853b3a8eb9SGleb Smirnoff struct pfr_walktree w; 21863b3a8eb9SGleb Smirnoff 21873b3a8eb9SGleb Smirnoff bzero(&w, sizeof(w)); 21883b3a8eb9SGleb Smirnoff w.pfrw_op = PFRW_DYNADDR_UPDATE; 21893b3a8eb9SGleb Smirnoff w.pfrw_dyn = dyn; 21903b3a8eb9SGleb Smirnoff 21913b3a8eb9SGleb Smirnoff dyn->pfid_acnt4 = 0; 21923b3a8eb9SGleb Smirnoff dyn->pfid_acnt6 = 0; 21933b3a8eb9SGleb Smirnoff if (!dyn->pfid_af || dyn->pfid_af == AF_INET) 21943b3a8eb9SGleb Smirnoff kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 21953b3a8eb9SGleb Smirnoff if (!dyn->pfid_af || dyn->pfid_af == AF_INET6) 21963b3a8eb9SGleb Smirnoff kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); 21973b3a8eb9SGleb Smirnoff } 2198