1d8aa10ccSGleb Smirnoff /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3fe267a55SPedro F. Giffuni * 43b3a8eb9SGleb Smirnoff * Copyright (c) 2002 Cedric Berger 53b3a8eb9SGleb Smirnoff * All rights reserved. 63b3a8eb9SGleb Smirnoff * 73b3a8eb9SGleb Smirnoff * Redistribution and use in source and binary forms, with or without 83b3a8eb9SGleb Smirnoff * modification, are permitted provided that the following conditions 93b3a8eb9SGleb Smirnoff * are met: 103b3a8eb9SGleb Smirnoff * 113b3a8eb9SGleb Smirnoff * - Redistributions of source code must retain the above copyright 123b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer. 133b3a8eb9SGleb Smirnoff * - Redistributions in binary form must reproduce the above 143b3a8eb9SGleb Smirnoff * copyright notice, this list of conditions and the following 153b3a8eb9SGleb Smirnoff * disclaimer in the documentation and/or other materials provided 163b3a8eb9SGleb Smirnoff * with the distribution. 173b3a8eb9SGleb Smirnoff * 183b3a8eb9SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 193b3a8eb9SGleb Smirnoff * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 203b3a8eb9SGleb Smirnoff * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 213b3a8eb9SGleb Smirnoff * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 223b3a8eb9SGleb Smirnoff * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 233b3a8eb9SGleb Smirnoff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 243b3a8eb9SGleb Smirnoff * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 253b3a8eb9SGleb Smirnoff * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 263b3a8eb9SGleb Smirnoff * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 273b3a8eb9SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 283b3a8eb9SGleb Smirnoff * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 293b3a8eb9SGleb Smirnoff * POSSIBILITY OF SUCH DAMAGE. 303b3a8eb9SGleb Smirnoff * 31d8aa10ccSGleb Smirnoff * $OpenBSD: pf_table.c,v 1.79 2008/10/08 06:24:50 mcbride Exp $ 323b3a8eb9SGleb Smirnoff */ 333b3a8eb9SGleb Smirnoff 343b3a8eb9SGleb Smirnoff #include <sys/cdefs.h> 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/socket.h> 463b3a8eb9SGleb Smirnoff #include <vm/uma.h> 473b3a8eb9SGleb Smirnoff 483b3a8eb9SGleb Smirnoff #include <net/if.h> 493b3a8eb9SGleb Smirnoff #include <net/vnet.h> 503b3a8eb9SGleb Smirnoff #include <net/pfvar.h> 513b3a8eb9SGleb Smirnoff 52032dff66SKristof Provost #define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x 53032dff66SKristof Provost 543b3a8eb9SGleb Smirnoff #define ACCEPT_FLAGS(flags, oklist) \ 553b3a8eb9SGleb Smirnoff do { \ 563b3a8eb9SGleb Smirnoff if ((flags & ~(oklist)) & \ 573b3a8eb9SGleb Smirnoff PFR_FLAG_ALLMASK) \ 583b3a8eb9SGleb Smirnoff return (EINVAL); \ 593b3a8eb9SGleb Smirnoff } while (0) 603b3a8eb9SGleb Smirnoff 613b3a8eb9SGleb Smirnoff #define FILLIN_SIN(sin, addr) \ 623b3a8eb9SGleb Smirnoff do { \ 633b3a8eb9SGleb Smirnoff (sin).sin_len = sizeof(sin); \ 643b3a8eb9SGleb Smirnoff (sin).sin_family = AF_INET; \ 653b3a8eb9SGleb Smirnoff (sin).sin_addr = (addr); \ 663b3a8eb9SGleb Smirnoff } while (0) 673b3a8eb9SGleb Smirnoff 683b3a8eb9SGleb Smirnoff #define FILLIN_SIN6(sin6, addr) \ 693b3a8eb9SGleb Smirnoff do { \ 703b3a8eb9SGleb Smirnoff (sin6).sin6_len = sizeof(sin6); \ 713b3a8eb9SGleb Smirnoff (sin6).sin6_family = AF_INET6; \ 723b3a8eb9SGleb Smirnoff (sin6).sin6_addr = (addr); \ 733b3a8eb9SGleb Smirnoff } while (0) 743b3a8eb9SGleb Smirnoff 753b3a8eb9SGleb Smirnoff #define SWAP(type, a1, a2) \ 763b3a8eb9SGleb Smirnoff do { \ 773b3a8eb9SGleb Smirnoff type tmp = a1; \ 783b3a8eb9SGleb Smirnoff a1 = a2; \ 793b3a8eb9SGleb Smirnoff a2 = tmp; \ 803b3a8eb9SGleb Smirnoff } while (0) 813b3a8eb9SGleb Smirnoff 823b3a8eb9SGleb Smirnoff #define AF_BITS(af) (((af)==AF_INET)?32:128) 833b3a8eb9SGleb Smirnoff #define ADDR_NETWORK(ad) ((ad)->pfra_net < AF_BITS((ad)->pfra_af)) 843b3a8eb9SGleb Smirnoff #define KENTRY_NETWORK(ke) ((ke)->pfrke_net < AF_BITS((ke)->pfrke_af)) 853b3a8eb9SGleb Smirnoff #define KENTRY_RNF_ROOT(ke) \ 863b3a8eb9SGleb Smirnoff ((((struct radix_node *)(ke))->rn_flags & RNF_ROOT) != 0) 873b3a8eb9SGleb Smirnoff 883b3a8eb9SGleb Smirnoff #define NO_ADDRESSES (-1) 893b3a8eb9SGleb Smirnoff #define ENQUEUE_UNMARKED_ONLY (1) 903b3a8eb9SGleb Smirnoff #define INVERT_NEG_FLAG (1) 913b3a8eb9SGleb Smirnoff 923b3a8eb9SGleb Smirnoff struct pfr_walktree { 933b3a8eb9SGleb Smirnoff enum pfrw_op { 943b3a8eb9SGleb Smirnoff PFRW_MARK, 953b3a8eb9SGleb Smirnoff PFRW_SWEEP, 963b3a8eb9SGleb Smirnoff PFRW_ENQUEUE, 973b3a8eb9SGleb Smirnoff PFRW_GET_ADDRS, 983b3a8eb9SGleb Smirnoff PFRW_GET_ASTATS, 993b3a8eb9SGleb Smirnoff PFRW_POOL_GET, 100b21826bfSKristof Provost PFRW_DYNADDR_UPDATE, 101b21826bfSKristof Provost PFRW_COUNTERS 1023b3a8eb9SGleb Smirnoff } pfrw_op; 1033b3a8eb9SGleb Smirnoff union { 1047b676698SKristof Provost struct pfr_addr *pfrw_addr; 1057b676698SKristof Provost struct pfr_astats *pfrw_astats; 1067b676698SKristof Provost struct pfr_kentryworkq *pfrw_workq; 1077b676698SKristof Provost struct pfr_kentry *pfrw_kentry; 1087b676698SKristof Provost struct pfi_dynaddr *pfrw_dyn; 1097b676698SKristof Provost }; 1103b3a8eb9SGleb Smirnoff int pfrw_free; 11159048686SKristof Provost int pfrw_flags; 1123b3a8eb9SGleb Smirnoff }; 1133b3a8eb9SGleb Smirnoff 1143b3a8eb9SGleb Smirnoff #define senderr(e) do { rv = (e); goto _bad; } while (0) 1153b3a8eb9SGleb Smirnoff 1163b3a8eb9SGleb Smirnoff static MALLOC_DEFINE(M_PFTABLE, "pf_table", "pf(4) tables structures"); 1175f901c92SAndrew Turner VNET_DEFINE_STATIC(uma_zone_t, pfr_kentry_z); 1183b3a8eb9SGleb Smirnoff #define V_pfr_kentry_z VNET(pfr_kentry_z) 119c1be8399SMark Johnston VNET_DEFINE_STATIC(uma_zone_t, pfr_kentry_counter_z); 120c1be8399SMark Johnston #define V_pfr_kentry_counter_z VNET(pfr_kentry_counter_z) 1213b3a8eb9SGleb Smirnoff 1223b3a8eb9SGleb Smirnoff static struct pf_addr pfr_ffaddr = { 1233b3a8eb9SGleb Smirnoff .addr32 = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } 1243b3a8eb9SGleb Smirnoff }; 1253b3a8eb9SGleb Smirnoff 12659048686SKristof Provost static void pfr_copyout_astats(struct pfr_astats *, 12759048686SKristof Provost const struct pfr_kentry *, 12859048686SKristof Provost const struct pfr_walktree *); 1293b3a8eb9SGleb Smirnoff static void pfr_copyout_addr(struct pfr_addr *, 13059048686SKristof Provost const struct pfr_kentry *ke); 1313b3a8eb9SGleb Smirnoff static int pfr_validate_addr(struct pfr_addr *); 1323b3a8eb9SGleb Smirnoff static void pfr_enqueue_addrs(struct pfr_ktable *, 1333b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *, int *, int); 1343b3a8eb9SGleb Smirnoff static void pfr_mark_addrs(struct pfr_ktable *); 1353b3a8eb9SGleb Smirnoff static struct pfr_kentry 1363b3a8eb9SGleb Smirnoff *pfr_lookup_addr(struct pfr_ktable *, 1373b3a8eb9SGleb Smirnoff struct pfr_addr *, int); 13821121f9bSMark Johnston static struct pfr_kentry *pfr_create_kentry(struct pfr_addr *, bool); 1393b3a8eb9SGleb Smirnoff static void pfr_destroy_kentries(struct pfr_kentryworkq *); 1403b3a8eb9SGleb Smirnoff static void pfr_destroy_kentry(struct pfr_kentry *); 1413b3a8eb9SGleb Smirnoff static void pfr_insert_kentries(struct pfr_ktable *, 1427e7f8800SKristof Provost struct pfr_kentryworkq *, time_t); 1433b3a8eb9SGleb Smirnoff static void pfr_remove_kentries(struct pfr_ktable *, 1443b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *); 14521121f9bSMark Johnston static void pfr_clstats_kentries(struct pfr_ktable *, 1467e7f8800SKristof Provost struct pfr_kentryworkq *, time_t, int); 1473b3a8eb9SGleb Smirnoff static void pfr_reset_feedback(struct pfr_addr *, int); 1483b3a8eb9SGleb Smirnoff static void pfr_prepare_network(union sockaddr_union *, int, int); 1493b3a8eb9SGleb Smirnoff static int pfr_route_kentry(struct pfr_ktable *, 1503b3a8eb9SGleb Smirnoff struct pfr_kentry *); 1513b3a8eb9SGleb Smirnoff static int pfr_unroute_kentry(struct pfr_ktable *, 1523b3a8eb9SGleb Smirnoff struct pfr_kentry *); 1533b3a8eb9SGleb Smirnoff static int pfr_walktree(struct radix_node *, void *); 1543b3a8eb9SGleb Smirnoff static int pfr_validate_table(struct pfr_table *, int, int); 1553b3a8eb9SGleb Smirnoff static int pfr_fix_anchor(char *); 1567e7f8800SKristof Provost static void pfr_commit_ktable(struct pfr_ktable *, time_t); 1573b3a8eb9SGleb Smirnoff static void pfr_insert_ktables(struct pfr_ktableworkq *); 1583b3a8eb9SGleb Smirnoff static void pfr_insert_ktable(struct pfr_ktable *); 1593b3a8eb9SGleb Smirnoff static void pfr_setflags_ktables(struct pfr_ktableworkq *); 1603b3a8eb9SGleb Smirnoff static void pfr_setflags_ktable(struct pfr_ktable *, int); 1617e7f8800SKristof Provost static void pfr_clstats_ktables(struct pfr_ktableworkq *, time_t, 1623b3a8eb9SGleb Smirnoff int); 1637e7f8800SKristof Provost static void pfr_clstats_ktable(struct pfr_ktable *, time_t, int); 1643b3a8eb9SGleb Smirnoff static struct pfr_ktable 1657e7f8800SKristof Provost *pfr_create_ktable(struct pfr_table *, time_t, int); 1663b3a8eb9SGleb Smirnoff static void pfr_destroy_ktables(struct pfr_ktableworkq *, int); 1673b3a8eb9SGleb Smirnoff static void pfr_destroy_ktable(struct pfr_ktable *, int); 1683b3a8eb9SGleb Smirnoff static int pfr_ktable_compare(struct pfr_ktable *, 1693b3a8eb9SGleb Smirnoff struct pfr_ktable *); 1703b3a8eb9SGleb Smirnoff static struct pfr_ktable 1713b3a8eb9SGleb Smirnoff *pfr_lookup_table(struct pfr_table *); 1723b3a8eb9SGleb Smirnoff static void pfr_clean_node_mask(struct pfr_ktable *, 1733b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *); 1743b3a8eb9SGleb Smirnoff static int pfr_skip_table(struct pfr_table *, 1753b3a8eb9SGleb Smirnoff struct pfr_ktable *, int); 1763b3a8eb9SGleb Smirnoff static struct pfr_kentry 1773b3a8eb9SGleb Smirnoff *pfr_kentry_byidx(struct pfr_ktable *, int, int); 1783b3a8eb9SGleb Smirnoff 1793b3a8eb9SGleb Smirnoff static RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); 1803b3a8eb9SGleb Smirnoff static RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); 1813b3a8eb9SGleb Smirnoff 1825f901c92SAndrew Turner VNET_DEFINE_STATIC(struct pfr_ktablehead, pfr_ktables); 1831e9e3741SMarko Zec #define V_pfr_ktables VNET(pfr_ktables) 1841e9e3741SMarko Zec 1855f901c92SAndrew Turner VNET_DEFINE_STATIC(struct pfr_table, pfr_nulltable); 1861e9e3741SMarko Zec #define V_pfr_nulltable VNET(pfr_nulltable) 1871e9e3741SMarko Zec 1885f901c92SAndrew Turner VNET_DEFINE_STATIC(int, pfr_ktable_cnt); 1891e9e3741SMarko Zec #define V_pfr_ktable_cnt VNET(pfr_ktable_cnt) 1903b3a8eb9SGleb Smirnoff 1913b3a8eb9SGleb Smirnoff void 1923b3a8eb9SGleb Smirnoff pfr_initialize(void) 1933b3a8eb9SGleb Smirnoff { 1943b3a8eb9SGleb Smirnoff 195c1be8399SMark Johnston V_pfr_kentry_counter_z = uma_zcreate("pf table entry counters", 196c1be8399SMark Johnston PFR_NUM_COUNTERS * sizeof(uint64_t), NULL, NULL, NULL, NULL, 197c1be8399SMark Johnston UMA_ALIGN_PTR, UMA_ZONE_PCPU); 1983b3a8eb9SGleb Smirnoff V_pfr_kentry_z = uma_zcreate("pf table entries", 1993b3a8eb9SGleb Smirnoff sizeof(struct pfr_kentry), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 2003b3a8eb9SGleb Smirnoff 0); 2017d1ab866SMark Johnston uma_zone_set_max(V_pfr_kentry_z, PFR_KENTRY_HIWAT); 2023b3a8eb9SGleb Smirnoff V_pf_limits[PF_LIMIT_TABLE_ENTRIES].zone = V_pfr_kentry_z; 2033b3a8eb9SGleb Smirnoff V_pf_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT; 2043b3a8eb9SGleb Smirnoff } 2053b3a8eb9SGleb Smirnoff 2063b3a8eb9SGleb Smirnoff void 2073b3a8eb9SGleb Smirnoff pfr_cleanup(void) 2083b3a8eb9SGleb Smirnoff { 2093b3a8eb9SGleb Smirnoff 2103b3a8eb9SGleb Smirnoff uma_zdestroy(V_pfr_kentry_z); 211c1be8399SMark Johnston uma_zdestroy(V_pfr_kentry_counter_z); 2123b3a8eb9SGleb Smirnoff } 2133b3a8eb9SGleb Smirnoff 2143b3a8eb9SGleb Smirnoff int 2153b3a8eb9SGleb Smirnoff pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) 2163b3a8eb9SGleb Smirnoff { 2173b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 2183b3a8eb9SGleb Smirnoff struct pfr_kentryworkq workq; 2193b3a8eb9SGleb Smirnoff 2203b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 2213b3a8eb9SGleb Smirnoff 2223b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 2233b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 2243b3a8eb9SGleb Smirnoff return (EINVAL); 2253b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 2263b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 2273b3a8eb9SGleb Smirnoff return (ESRCH); 2283b3a8eb9SGleb Smirnoff if (kt->pfrkt_flags & PFR_TFLAG_CONST) 2293b3a8eb9SGleb Smirnoff return (EPERM); 2303b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &workq, ndel, 0); 2313b3a8eb9SGleb Smirnoff 2323b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 2333b3a8eb9SGleb Smirnoff pfr_remove_kentries(kt, &workq); 2343b3a8eb9SGleb Smirnoff KASSERT(kt->pfrkt_cnt == 0, ("%s: non-null pfrkt_cnt", __func__)); 2353b3a8eb9SGleb Smirnoff } 2363b3a8eb9SGleb Smirnoff return (0); 2373b3a8eb9SGleb Smirnoff } 2383b3a8eb9SGleb Smirnoff 2393b3a8eb9SGleb Smirnoff int 2403b3a8eb9SGleb Smirnoff pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 2413b3a8eb9SGleb Smirnoff int *nadd, int flags) 2423b3a8eb9SGleb Smirnoff { 2433b3a8eb9SGleb Smirnoff struct pfr_ktable *kt, *tmpkt; 2443b3a8eb9SGleb Smirnoff struct pfr_kentryworkq workq; 2453b3a8eb9SGleb Smirnoff struct pfr_kentry *p, *q; 2463b3a8eb9SGleb Smirnoff struct pfr_addr *ad; 2473b3a8eb9SGleb Smirnoff int i, rv, xadd = 0; 2487e7f8800SKristof Provost time_t tzero = time_second; 2493b3a8eb9SGleb Smirnoff 2503b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 2513b3a8eb9SGleb Smirnoff 2523b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK); 2533b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 2543b3a8eb9SGleb Smirnoff return (EINVAL); 2553b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 2563b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 2573b3a8eb9SGleb Smirnoff return (ESRCH); 2583b3a8eb9SGleb Smirnoff if (kt->pfrkt_flags & PFR_TFLAG_CONST) 2593b3a8eb9SGleb Smirnoff return (EPERM); 2601e9e3741SMarko Zec tmpkt = pfr_create_ktable(&V_pfr_nulltable, 0, 0); 2613b3a8eb9SGleb Smirnoff if (tmpkt == NULL) 2623b3a8eb9SGleb Smirnoff return (ENOMEM); 2633b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 2643b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) { 2653b3a8eb9SGleb Smirnoff if (pfr_validate_addr(ad)) 2663b3a8eb9SGleb Smirnoff senderr(EINVAL); 2673b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, ad, 1); 2683b3a8eb9SGleb Smirnoff q = pfr_lookup_addr(tmpkt, ad, 1); 2693b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) { 2703b3a8eb9SGleb Smirnoff if (q != NULL) 2713b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_DUPLICATE; 2723b3a8eb9SGleb Smirnoff else if (p == NULL) 2733b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_ADDED; 2743b3a8eb9SGleb Smirnoff else if (p->pfrke_not != ad->pfra_not) 2753b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_CONFLICT; 2763b3a8eb9SGleb Smirnoff else 2773b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_NONE; 2783b3a8eb9SGleb Smirnoff } 2793b3a8eb9SGleb Smirnoff if (p == NULL && q == NULL) { 28021121f9bSMark Johnston p = pfr_create_kentry(ad, 28121121f9bSMark Johnston (kt->pfrkt_flags & PFR_TFLAG_COUNTERS) != 0); 2823b3a8eb9SGleb Smirnoff if (p == NULL) 2833b3a8eb9SGleb Smirnoff senderr(ENOMEM); 2843b3a8eb9SGleb Smirnoff if (pfr_route_kentry(tmpkt, p)) { 2853b3a8eb9SGleb Smirnoff pfr_destroy_kentry(p); 2863b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_NONE; 2873b3a8eb9SGleb Smirnoff } else { 2883b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrke_workq); 2893b3a8eb9SGleb Smirnoff xadd++; 2903b3a8eb9SGleb Smirnoff } 2913b3a8eb9SGleb Smirnoff } 2923b3a8eb9SGleb Smirnoff } 2933b3a8eb9SGleb Smirnoff pfr_clean_node_mask(tmpkt, &workq); 2943b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 2953b3a8eb9SGleb Smirnoff pfr_insert_kentries(kt, &workq, tzero); 2963b3a8eb9SGleb Smirnoff else 2973b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&workq); 2983b3a8eb9SGleb Smirnoff if (nadd != NULL) 2993b3a8eb9SGleb Smirnoff *nadd = xadd; 3003b3a8eb9SGleb Smirnoff pfr_destroy_ktable(tmpkt, 0); 3013b3a8eb9SGleb Smirnoff return (0); 3023b3a8eb9SGleb Smirnoff _bad: 3033b3a8eb9SGleb Smirnoff pfr_clean_node_mask(tmpkt, &workq); 3043b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&workq); 3053b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) 3063b3a8eb9SGleb Smirnoff pfr_reset_feedback(addr, size); 3073b3a8eb9SGleb Smirnoff pfr_destroy_ktable(tmpkt, 0); 3083b3a8eb9SGleb Smirnoff return (rv); 3093b3a8eb9SGleb Smirnoff } 3103b3a8eb9SGleb Smirnoff 3113b3a8eb9SGleb Smirnoff int 3123b3a8eb9SGleb Smirnoff pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 3133b3a8eb9SGleb Smirnoff int *ndel, int flags) 3143b3a8eb9SGleb Smirnoff { 3153b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 3163b3a8eb9SGleb Smirnoff struct pfr_kentryworkq workq; 3173b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 3183b3a8eb9SGleb Smirnoff struct pfr_addr *ad; 3193b3a8eb9SGleb Smirnoff int i, rv, xdel = 0, log = 1; 3203b3a8eb9SGleb Smirnoff 3213b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 3223b3a8eb9SGleb Smirnoff 3233b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK); 3243b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 3253b3a8eb9SGleb Smirnoff return (EINVAL); 3263b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 3273b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 3283b3a8eb9SGleb Smirnoff return (ESRCH); 3293b3a8eb9SGleb Smirnoff if (kt->pfrkt_flags & PFR_TFLAG_CONST) 3303b3a8eb9SGleb Smirnoff return (EPERM); 3313b3a8eb9SGleb Smirnoff /* 3323b3a8eb9SGleb Smirnoff * there are two algorithms to choose from here. 3333b3a8eb9SGleb Smirnoff * with: 3343b3a8eb9SGleb Smirnoff * n: number of addresses to delete 3353b3a8eb9SGleb Smirnoff * N: number of addresses in the table 3363b3a8eb9SGleb Smirnoff * 3373b3a8eb9SGleb Smirnoff * one is O(N) and is better for large 'n' 3383b3a8eb9SGleb Smirnoff * one is O(n*LOG(N)) and is better for small 'n' 3393b3a8eb9SGleb Smirnoff * 3403b3a8eb9SGleb Smirnoff * following code try to decide which one is best. 3413b3a8eb9SGleb Smirnoff */ 3423b3a8eb9SGleb Smirnoff for (i = kt->pfrkt_cnt; i > 0; i >>= 1) 3433b3a8eb9SGleb Smirnoff log++; 3443b3a8eb9SGleb Smirnoff if (size > kt->pfrkt_cnt/log) { 3453b3a8eb9SGleb Smirnoff /* full table scan */ 3463b3a8eb9SGleb Smirnoff pfr_mark_addrs(kt); 3473b3a8eb9SGleb Smirnoff } else { 3483b3a8eb9SGleb Smirnoff /* iterate over addresses to delete */ 3493b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) { 3503b3a8eb9SGleb Smirnoff if (pfr_validate_addr(ad)) 3513b3a8eb9SGleb Smirnoff return (EINVAL); 3523b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, ad, 1); 3533b3a8eb9SGleb Smirnoff if (p != NULL) 3543b3a8eb9SGleb Smirnoff p->pfrke_mark = 0; 3553b3a8eb9SGleb Smirnoff } 3563b3a8eb9SGleb Smirnoff } 3573b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 3583b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) { 3593b3a8eb9SGleb Smirnoff if (pfr_validate_addr(ad)) 3603b3a8eb9SGleb Smirnoff senderr(EINVAL); 3613b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, ad, 1); 3623b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) { 3633b3a8eb9SGleb Smirnoff if (p == NULL) 3643b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_NONE; 3653b3a8eb9SGleb Smirnoff else if (p->pfrke_not != ad->pfra_not) 3663b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_CONFLICT; 3673b3a8eb9SGleb Smirnoff else if (p->pfrke_mark) 3683b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_DUPLICATE; 3693b3a8eb9SGleb Smirnoff else 3703b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_DELETED; 3713b3a8eb9SGleb Smirnoff } 3723b3a8eb9SGleb Smirnoff if (p != NULL && p->pfrke_not == ad->pfra_not && 3733b3a8eb9SGleb Smirnoff !p->pfrke_mark) { 3743b3a8eb9SGleb Smirnoff p->pfrke_mark = 1; 3753b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrke_workq); 3763b3a8eb9SGleb Smirnoff xdel++; 3773b3a8eb9SGleb Smirnoff } 3783b3a8eb9SGleb Smirnoff } 3793b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 3803b3a8eb9SGleb Smirnoff pfr_remove_kentries(kt, &workq); 3813b3a8eb9SGleb Smirnoff if (ndel != NULL) 3823b3a8eb9SGleb Smirnoff *ndel = xdel; 3833b3a8eb9SGleb Smirnoff return (0); 3843b3a8eb9SGleb Smirnoff _bad: 3853b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) 3863b3a8eb9SGleb Smirnoff pfr_reset_feedback(addr, size); 3873b3a8eb9SGleb Smirnoff return (rv); 3883b3a8eb9SGleb Smirnoff } 3893b3a8eb9SGleb Smirnoff 3903b3a8eb9SGleb Smirnoff int 3913b3a8eb9SGleb Smirnoff pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 3923b3a8eb9SGleb Smirnoff int *size2, int *nadd, int *ndel, int *nchange, int flags, 3933b3a8eb9SGleb Smirnoff u_int32_t ignore_pfrt_flags) 3943b3a8eb9SGleb Smirnoff { 3953b3a8eb9SGleb Smirnoff struct pfr_ktable *kt, *tmpkt; 3963b3a8eb9SGleb Smirnoff struct pfr_kentryworkq addq, delq, changeq; 3973b3a8eb9SGleb Smirnoff struct pfr_kentry *p, *q; 3983b3a8eb9SGleb Smirnoff struct pfr_addr ad; 3993b3a8eb9SGleb Smirnoff int i, rv, xadd = 0, xdel = 0, xchange = 0; 4007e7f8800SKristof Provost time_t tzero = time_second; 4013b3a8eb9SGleb Smirnoff 4023b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 4033b3a8eb9SGleb Smirnoff 4043b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK); 4053b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, ignore_pfrt_flags, flags & 4063b3a8eb9SGleb Smirnoff PFR_FLAG_USERIOCTL)) 4073b3a8eb9SGleb Smirnoff return (EINVAL); 4083b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 4093b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 4103b3a8eb9SGleb Smirnoff return (ESRCH); 4113b3a8eb9SGleb Smirnoff if (kt->pfrkt_flags & PFR_TFLAG_CONST) 4123b3a8eb9SGleb Smirnoff return (EPERM); 4131e9e3741SMarko Zec tmpkt = pfr_create_ktable(&V_pfr_nulltable, 0, 0); 4143b3a8eb9SGleb Smirnoff if (tmpkt == NULL) 4153b3a8eb9SGleb Smirnoff return (ENOMEM); 4163b3a8eb9SGleb Smirnoff pfr_mark_addrs(kt); 4173b3a8eb9SGleb Smirnoff SLIST_INIT(&addq); 4183b3a8eb9SGleb Smirnoff SLIST_INIT(&delq); 4193b3a8eb9SGleb Smirnoff SLIST_INIT(&changeq); 4203b3a8eb9SGleb Smirnoff for (i = 0; i < size; i++) { 4213b3a8eb9SGleb Smirnoff /* 4223b3a8eb9SGleb Smirnoff * XXXGL: undertand pf_if usage of this function 4233b3a8eb9SGleb Smirnoff * and make ad a moving pointer 4243b3a8eb9SGleb Smirnoff */ 4253b3a8eb9SGleb Smirnoff bcopy(addr + i, &ad, sizeof(ad)); 4263b3a8eb9SGleb Smirnoff if (pfr_validate_addr(&ad)) 4273b3a8eb9SGleb Smirnoff senderr(EINVAL); 4283b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_NONE; 4293b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, &ad, 1); 4303b3a8eb9SGleb Smirnoff if (p != NULL) { 4313b3a8eb9SGleb Smirnoff if (p->pfrke_mark) { 4323b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_DUPLICATE; 4333b3a8eb9SGleb Smirnoff goto _skip; 4343b3a8eb9SGleb Smirnoff } 4353b3a8eb9SGleb Smirnoff p->pfrke_mark = 1; 4363b3a8eb9SGleb Smirnoff if (p->pfrke_not != ad.pfra_not) { 4373b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&changeq, p, pfrke_workq); 4383b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_CHANGED; 4393b3a8eb9SGleb Smirnoff xchange++; 4403b3a8eb9SGleb Smirnoff } 4413b3a8eb9SGleb Smirnoff } else { 4423b3a8eb9SGleb Smirnoff q = pfr_lookup_addr(tmpkt, &ad, 1); 4433b3a8eb9SGleb Smirnoff if (q != NULL) { 4443b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_DUPLICATE; 4453b3a8eb9SGleb Smirnoff goto _skip; 4463b3a8eb9SGleb Smirnoff } 44721121f9bSMark Johnston p = pfr_create_kentry(&ad, 44821121f9bSMark Johnston (kt->pfrkt_flags & PFR_TFLAG_COUNTERS) != 0); 4493b3a8eb9SGleb Smirnoff if (p == NULL) 4503b3a8eb9SGleb Smirnoff senderr(ENOMEM); 4513b3a8eb9SGleb Smirnoff if (pfr_route_kentry(tmpkt, p)) { 4523b3a8eb9SGleb Smirnoff pfr_destroy_kentry(p); 4533b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_NONE; 4543b3a8eb9SGleb Smirnoff } else { 4553b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&addq, p, pfrke_workq); 4563b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_ADDED; 4573b3a8eb9SGleb Smirnoff xadd++; 4583b3a8eb9SGleb Smirnoff } 4593b3a8eb9SGleb Smirnoff } 4603b3a8eb9SGleb Smirnoff _skip: 4613b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) 4623b3a8eb9SGleb Smirnoff bcopy(&ad, addr + i, sizeof(ad)); 4633b3a8eb9SGleb Smirnoff } 4643b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY); 4653b3a8eb9SGleb Smirnoff if ((flags & PFR_FLAG_FEEDBACK) && *size2) { 4663b3a8eb9SGleb Smirnoff if (*size2 < size+xdel) { 4673b3a8eb9SGleb Smirnoff *size2 = size+xdel; 4683b3a8eb9SGleb Smirnoff senderr(0); 4693b3a8eb9SGleb Smirnoff } 4703b3a8eb9SGleb Smirnoff i = 0; 4713b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, &delq, pfrke_workq) { 4723b3a8eb9SGleb Smirnoff pfr_copyout_addr(&ad, p); 4733b3a8eb9SGleb Smirnoff ad.pfra_fback = PFR_FB_DELETED; 4743b3a8eb9SGleb Smirnoff bcopy(&ad, addr + size + i, sizeof(ad)); 4753b3a8eb9SGleb Smirnoff i++; 4763b3a8eb9SGleb Smirnoff } 4773b3a8eb9SGleb Smirnoff } 4783b3a8eb9SGleb Smirnoff pfr_clean_node_mask(tmpkt, &addq); 4793b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 4803b3a8eb9SGleb Smirnoff pfr_insert_kentries(kt, &addq, tzero); 4813b3a8eb9SGleb Smirnoff pfr_remove_kentries(kt, &delq); 48221121f9bSMark Johnston pfr_clstats_kentries(kt, &changeq, tzero, INVERT_NEG_FLAG); 4833b3a8eb9SGleb Smirnoff } else 4843b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&addq); 4853b3a8eb9SGleb Smirnoff if (nadd != NULL) 4863b3a8eb9SGleb Smirnoff *nadd = xadd; 4873b3a8eb9SGleb Smirnoff if (ndel != NULL) 4883b3a8eb9SGleb Smirnoff *ndel = xdel; 4893b3a8eb9SGleb Smirnoff if (nchange != NULL) 4903b3a8eb9SGleb Smirnoff *nchange = xchange; 4913b3a8eb9SGleb Smirnoff if ((flags & PFR_FLAG_FEEDBACK) && size2) 4923b3a8eb9SGleb Smirnoff *size2 = size+xdel; 4933b3a8eb9SGleb Smirnoff pfr_destroy_ktable(tmpkt, 0); 4943b3a8eb9SGleb Smirnoff return (0); 4953b3a8eb9SGleb Smirnoff _bad: 4963b3a8eb9SGleb Smirnoff pfr_clean_node_mask(tmpkt, &addq); 4973b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&addq); 4983b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) 4993b3a8eb9SGleb Smirnoff pfr_reset_feedback(addr, size); 5003b3a8eb9SGleb Smirnoff pfr_destroy_ktable(tmpkt, 0); 5013b3a8eb9SGleb Smirnoff return (rv); 5023b3a8eb9SGleb Smirnoff } 5033b3a8eb9SGleb Smirnoff 5043b3a8eb9SGleb Smirnoff int 5053b3a8eb9SGleb Smirnoff pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 5063b3a8eb9SGleb Smirnoff int *nmatch, int flags) 5073b3a8eb9SGleb Smirnoff { 5083b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 5093b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 5103b3a8eb9SGleb Smirnoff struct pfr_addr *ad; 5113b3a8eb9SGleb Smirnoff int i, xmatch = 0; 5123b3a8eb9SGleb Smirnoff 5133b3a8eb9SGleb Smirnoff PF_RULES_RASSERT(); 5143b3a8eb9SGleb Smirnoff 5153b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_REPLACE); 5163b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, 0)) 5173b3a8eb9SGleb Smirnoff return (EINVAL); 5183b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 5193b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 5203b3a8eb9SGleb Smirnoff return (ESRCH); 5213b3a8eb9SGleb Smirnoff 5223b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) { 5233b3a8eb9SGleb Smirnoff if (pfr_validate_addr(ad)) 5243b3a8eb9SGleb Smirnoff return (EINVAL); 5253b3a8eb9SGleb Smirnoff if (ADDR_NETWORK(ad)) 5263b3a8eb9SGleb Smirnoff return (EINVAL); 5273b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, ad, 0); 5283b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_REPLACE) 5293b3a8eb9SGleb Smirnoff pfr_copyout_addr(ad, p); 5303b3a8eb9SGleb Smirnoff ad->pfra_fback = (p == NULL) ? PFR_FB_NONE : 5313b3a8eb9SGleb Smirnoff (p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH); 5323b3a8eb9SGleb Smirnoff if (p != NULL && !p->pfrke_not) 5333b3a8eb9SGleb Smirnoff xmatch++; 5343b3a8eb9SGleb Smirnoff } 5353b3a8eb9SGleb Smirnoff if (nmatch != NULL) 5363b3a8eb9SGleb Smirnoff *nmatch = xmatch; 5373b3a8eb9SGleb Smirnoff return (0); 5383b3a8eb9SGleb Smirnoff } 5393b3a8eb9SGleb Smirnoff 5403b3a8eb9SGleb Smirnoff int 5413b3a8eb9SGleb Smirnoff pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, 5423b3a8eb9SGleb Smirnoff int flags) 5433b3a8eb9SGleb Smirnoff { 5443b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 5453b3a8eb9SGleb Smirnoff struct pfr_walktree w; 5463b3a8eb9SGleb Smirnoff int rv; 5473b3a8eb9SGleb Smirnoff 5483b3a8eb9SGleb Smirnoff PF_RULES_RASSERT(); 5493b3a8eb9SGleb Smirnoff 5503b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, 0); 5513b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, 0)) 5523b3a8eb9SGleb Smirnoff return (EINVAL); 5533b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 5543b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 5553b3a8eb9SGleb Smirnoff return (ESRCH); 5563b3a8eb9SGleb Smirnoff if (kt->pfrkt_cnt > *size) { 5573b3a8eb9SGleb Smirnoff *size = kt->pfrkt_cnt; 5583b3a8eb9SGleb Smirnoff return (0); 5593b3a8eb9SGleb Smirnoff } 5603b3a8eb9SGleb Smirnoff 5613b3a8eb9SGleb Smirnoff bzero(&w, sizeof(w)); 5623b3a8eb9SGleb Smirnoff w.pfrw_op = PFRW_GET_ADDRS; 5633b3a8eb9SGleb Smirnoff w.pfrw_addr = addr; 5643b3a8eb9SGleb Smirnoff w.pfrw_free = kt->pfrkt_cnt; 56561eee0e2SAlexander V. Chernikov rv = kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); 5663b3a8eb9SGleb Smirnoff if (!rv) 56761eee0e2SAlexander V. Chernikov rv = kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, 56861eee0e2SAlexander V. Chernikov pfr_walktree, &w); 5693b3a8eb9SGleb Smirnoff if (rv) 5703b3a8eb9SGleb Smirnoff return (rv); 5713b3a8eb9SGleb Smirnoff 5723b3a8eb9SGleb Smirnoff KASSERT(w.pfrw_free == 0, ("%s: corruption detected (%d)", __func__, 5733b3a8eb9SGleb Smirnoff w.pfrw_free)); 5743b3a8eb9SGleb Smirnoff 5753b3a8eb9SGleb Smirnoff *size = kt->pfrkt_cnt; 5763b3a8eb9SGleb Smirnoff return (0); 5773b3a8eb9SGleb Smirnoff } 5783b3a8eb9SGleb Smirnoff 5793b3a8eb9SGleb Smirnoff int 5803b3a8eb9SGleb Smirnoff pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, 5813b3a8eb9SGleb Smirnoff int flags) 5823b3a8eb9SGleb Smirnoff { 5833b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 5843b3a8eb9SGleb Smirnoff struct pfr_walktree w; 5853b3a8eb9SGleb Smirnoff struct pfr_kentryworkq workq; 5863b3a8eb9SGleb Smirnoff int rv; 5877e7f8800SKristof Provost time_t tzero = time_second; 5883b3a8eb9SGleb Smirnoff 5893b3a8eb9SGleb Smirnoff PF_RULES_RASSERT(); 5903b3a8eb9SGleb Smirnoff 5913b3a8eb9SGleb Smirnoff /* XXX PFR_FLAG_CLSTATS disabled */ 5923b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, 0); 5933b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, 0)) 5943b3a8eb9SGleb Smirnoff return (EINVAL); 5953b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 5963b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 5973b3a8eb9SGleb Smirnoff return (ESRCH); 5983b3a8eb9SGleb Smirnoff if (kt->pfrkt_cnt > *size) { 5993b3a8eb9SGleb Smirnoff *size = kt->pfrkt_cnt; 6003b3a8eb9SGleb Smirnoff return (0); 6013b3a8eb9SGleb Smirnoff } 6023b3a8eb9SGleb Smirnoff 6033b3a8eb9SGleb Smirnoff bzero(&w, sizeof(w)); 6043b3a8eb9SGleb Smirnoff w.pfrw_op = PFRW_GET_ASTATS; 6053b3a8eb9SGleb Smirnoff w.pfrw_astats = addr; 6063b3a8eb9SGleb Smirnoff w.pfrw_free = kt->pfrkt_cnt; 60759048686SKristof Provost /* 60859048686SKristof Provost * Flags below are for backward compatibility. It was possible to have 60959048686SKristof Provost * a table without per-entry counters. Now they are always allocated, 61059048686SKristof Provost * we just discard data when reading it if table is not configured to 61159048686SKristof Provost * have counters. 61259048686SKristof Provost */ 61359048686SKristof Provost w.pfrw_flags = kt->pfrkt_flags; 61461eee0e2SAlexander V. Chernikov rv = kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); 6153b3a8eb9SGleb Smirnoff if (!rv) 61661eee0e2SAlexander V. Chernikov rv = kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, 61761eee0e2SAlexander V. Chernikov pfr_walktree, &w); 6183b3a8eb9SGleb Smirnoff if (!rv && (flags & PFR_FLAG_CLSTATS)) { 6193b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &workq, NULL, 0); 62021121f9bSMark Johnston pfr_clstats_kentries(kt, &workq, tzero, 0); 6213b3a8eb9SGleb Smirnoff } 6223b3a8eb9SGleb Smirnoff if (rv) 6233b3a8eb9SGleb Smirnoff return (rv); 6243b3a8eb9SGleb Smirnoff 6253b3a8eb9SGleb Smirnoff if (w.pfrw_free) { 6263b3a8eb9SGleb Smirnoff printf("pfr_get_astats: corruption detected (%d).\n", 6273b3a8eb9SGleb Smirnoff w.pfrw_free); 6283b3a8eb9SGleb Smirnoff return (ENOTTY); 6293b3a8eb9SGleb Smirnoff } 6303b3a8eb9SGleb Smirnoff *size = kt->pfrkt_cnt; 6313b3a8eb9SGleb Smirnoff return (0); 6323b3a8eb9SGleb Smirnoff } 6333b3a8eb9SGleb Smirnoff 6343b3a8eb9SGleb Smirnoff int 6353b3a8eb9SGleb Smirnoff pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, 6363b3a8eb9SGleb Smirnoff int *nzero, int flags) 6373b3a8eb9SGleb Smirnoff { 6383b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 6393b3a8eb9SGleb Smirnoff struct pfr_kentryworkq workq; 6403b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 6413b3a8eb9SGleb Smirnoff struct pfr_addr *ad; 6423b3a8eb9SGleb Smirnoff int i, rv, xzero = 0; 6433b3a8eb9SGleb Smirnoff 6443b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 6453b3a8eb9SGleb Smirnoff 6463b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK); 6473b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, 0, 0)) 6483b3a8eb9SGleb Smirnoff return (EINVAL); 6493b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(tbl); 6503b3a8eb9SGleb Smirnoff if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 6513b3a8eb9SGleb Smirnoff return (ESRCH); 6523b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 6533b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) { 6543b3a8eb9SGleb Smirnoff if (pfr_validate_addr(ad)) 6553b3a8eb9SGleb Smirnoff senderr(EINVAL); 6563b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, ad, 1); 6573b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) { 6583b3a8eb9SGleb Smirnoff ad->pfra_fback = (p != NULL) ? 6593b3a8eb9SGleb Smirnoff PFR_FB_CLEARED : PFR_FB_NONE; 6603b3a8eb9SGleb Smirnoff } 6613b3a8eb9SGleb Smirnoff if (p != NULL) { 6623b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrke_workq); 6633b3a8eb9SGleb Smirnoff xzero++; 6643b3a8eb9SGleb Smirnoff } 6653b3a8eb9SGleb Smirnoff } 6663b3a8eb9SGleb Smirnoff 6673b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 6681a5dc6eeSKajetan Staszkiewicz pfr_clstats_kentries(kt, &workq, time_second, 0); 6693b3a8eb9SGleb Smirnoff if (nzero != NULL) 6703b3a8eb9SGleb Smirnoff *nzero = xzero; 6713b3a8eb9SGleb Smirnoff return (0); 6723b3a8eb9SGleb Smirnoff _bad: 6733b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_FEEDBACK) 6743b3a8eb9SGleb Smirnoff pfr_reset_feedback(addr, size); 6753b3a8eb9SGleb Smirnoff return (rv); 6763b3a8eb9SGleb Smirnoff } 6773b3a8eb9SGleb Smirnoff 6783b3a8eb9SGleb Smirnoff static int 6793b3a8eb9SGleb Smirnoff pfr_validate_addr(struct pfr_addr *ad) 6803b3a8eb9SGleb Smirnoff { 6813b3a8eb9SGleb Smirnoff int i; 6823b3a8eb9SGleb Smirnoff 6833b3a8eb9SGleb Smirnoff switch (ad->pfra_af) { 6843b3a8eb9SGleb Smirnoff #ifdef INET 6853b3a8eb9SGleb Smirnoff case AF_INET: 6863b3a8eb9SGleb Smirnoff if (ad->pfra_net > 32) 6873b3a8eb9SGleb Smirnoff return (-1); 6883b3a8eb9SGleb Smirnoff break; 6893b3a8eb9SGleb Smirnoff #endif /* INET */ 6903b3a8eb9SGleb Smirnoff #ifdef INET6 6913b3a8eb9SGleb Smirnoff case AF_INET6: 6923b3a8eb9SGleb Smirnoff if (ad->pfra_net > 128) 6933b3a8eb9SGleb Smirnoff return (-1); 6943b3a8eb9SGleb Smirnoff break; 6953b3a8eb9SGleb Smirnoff #endif /* INET6 */ 6963b3a8eb9SGleb Smirnoff default: 6973b3a8eb9SGleb Smirnoff return (-1); 6983b3a8eb9SGleb Smirnoff } 6993b3a8eb9SGleb Smirnoff if (ad->pfra_net < 128 && 7003b3a8eb9SGleb Smirnoff (((caddr_t)ad)[ad->pfra_net/8] & (0xFF >> (ad->pfra_net%8)))) 7013b3a8eb9SGleb Smirnoff return (-1); 7023b3a8eb9SGleb Smirnoff for (i = (ad->pfra_net+7)/8; i < sizeof(ad->pfra_u); i++) 7033b3a8eb9SGleb Smirnoff if (((caddr_t)ad)[i]) 7043b3a8eb9SGleb Smirnoff return (-1); 7053b3a8eb9SGleb Smirnoff if (ad->pfra_not && ad->pfra_not != 1) 7063b3a8eb9SGleb Smirnoff return (-1); 7073b3a8eb9SGleb Smirnoff if (ad->pfra_fback) 7083b3a8eb9SGleb Smirnoff return (-1); 7093b3a8eb9SGleb Smirnoff return (0); 7103b3a8eb9SGleb Smirnoff } 7113b3a8eb9SGleb Smirnoff 7123b3a8eb9SGleb Smirnoff static void 7133b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq, 7143b3a8eb9SGleb Smirnoff int *naddr, int sweep) 7153b3a8eb9SGleb Smirnoff { 7163b3a8eb9SGleb Smirnoff struct pfr_walktree w; 7173b3a8eb9SGleb Smirnoff 7183b3a8eb9SGleb Smirnoff SLIST_INIT(workq); 7193b3a8eb9SGleb Smirnoff bzero(&w, sizeof(w)); 7203b3a8eb9SGleb Smirnoff w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE; 7213b3a8eb9SGleb Smirnoff w.pfrw_workq = workq; 7223b3a8eb9SGleb Smirnoff if (kt->pfrkt_ip4 != NULL) 72361eee0e2SAlexander V. Chernikov if (kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, 72461eee0e2SAlexander V. Chernikov pfr_walktree, &w)) 7253b3a8eb9SGleb Smirnoff printf("pfr_enqueue_addrs: IPv4 walktree failed.\n"); 7263b3a8eb9SGleb Smirnoff if (kt->pfrkt_ip6 != NULL) 72761eee0e2SAlexander V. Chernikov if (kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, 72861eee0e2SAlexander V. Chernikov pfr_walktree, &w)) 7293b3a8eb9SGleb Smirnoff printf("pfr_enqueue_addrs: IPv6 walktree failed.\n"); 7303b3a8eb9SGleb Smirnoff if (naddr != NULL) 7317b676698SKristof Provost *naddr = w.pfrw_free; 7323b3a8eb9SGleb Smirnoff } 7333b3a8eb9SGleb Smirnoff 7343b3a8eb9SGleb Smirnoff static void 7353b3a8eb9SGleb Smirnoff pfr_mark_addrs(struct pfr_ktable *kt) 7363b3a8eb9SGleb Smirnoff { 7373b3a8eb9SGleb Smirnoff struct pfr_walktree w; 7383b3a8eb9SGleb Smirnoff 7393b3a8eb9SGleb Smirnoff bzero(&w, sizeof(w)); 7403b3a8eb9SGleb Smirnoff w.pfrw_op = PFRW_MARK; 74161eee0e2SAlexander V. Chernikov if (kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w)) 7423b3a8eb9SGleb Smirnoff printf("pfr_mark_addrs: IPv4 walktree failed.\n"); 74361eee0e2SAlexander V. Chernikov if (kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, pfr_walktree, &w)) 7443b3a8eb9SGleb Smirnoff printf("pfr_mark_addrs: IPv6 walktree failed.\n"); 7453b3a8eb9SGleb Smirnoff } 7463b3a8eb9SGleb Smirnoff 7473b3a8eb9SGleb Smirnoff static struct pfr_kentry * 7483b3a8eb9SGleb Smirnoff pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) 7493b3a8eb9SGleb Smirnoff { 7503b3a8eb9SGleb Smirnoff union sockaddr_union sa, mask; 75161eee0e2SAlexander V. Chernikov struct radix_head *head = NULL; 7523b3a8eb9SGleb Smirnoff struct pfr_kentry *ke; 7533b3a8eb9SGleb Smirnoff 75429bdd62cSGleb Smirnoff PF_RULES_ASSERT(); 75529bdd62cSGleb Smirnoff 7563b3a8eb9SGleb Smirnoff bzero(&sa, sizeof(sa)); 7577e51bc6cSKristof Provost switch (ad->pfra_af) { 7587e51bc6cSKristof Provost case AF_INET: 7593b3a8eb9SGleb Smirnoff FILLIN_SIN(sa.sin, ad->pfra_ip4addr); 76061eee0e2SAlexander V. Chernikov head = &kt->pfrkt_ip4->rh; 7617e51bc6cSKristof Provost break; 7627e51bc6cSKristof Provost case AF_INET6: 7633b3a8eb9SGleb Smirnoff FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr); 76461eee0e2SAlexander V. Chernikov head = &kt->pfrkt_ip6->rh; 7657e51bc6cSKristof Provost break; 7667e51bc6cSKristof Provost default: 7677e51bc6cSKristof Provost unhandled_af(ad->pfra_af); 7683b3a8eb9SGleb Smirnoff } 7693b3a8eb9SGleb Smirnoff if (ADDR_NETWORK(ad)) { 7703b3a8eb9SGleb Smirnoff pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net); 7713b3a8eb9SGleb Smirnoff ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head); 7723b3a8eb9SGleb Smirnoff if (ke && KENTRY_RNF_ROOT(ke)) 7733b3a8eb9SGleb Smirnoff ke = NULL; 7743b3a8eb9SGleb Smirnoff } else { 7753b3a8eb9SGleb Smirnoff ke = (struct pfr_kentry *)rn_match(&sa, head); 7763b3a8eb9SGleb Smirnoff if (ke && KENTRY_RNF_ROOT(ke)) 7773b3a8eb9SGleb Smirnoff ke = NULL; 7783b3a8eb9SGleb Smirnoff if (exact && ke && KENTRY_NETWORK(ke)) 7793b3a8eb9SGleb Smirnoff ke = NULL; 7803b3a8eb9SGleb Smirnoff } 7813b3a8eb9SGleb Smirnoff return (ke); 7823b3a8eb9SGleb Smirnoff } 7833b3a8eb9SGleb Smirnoff 7843b3a8eb9SGleb Smirnoff static struct pfr_kentry * 78521121f9bSMark Johnston pfr_create_kentry(struct pfr_addr *ad, bool counters) 7863b3a8eb9SGleb Smirnoff { 7873b3a8eb9SGleb Smirnoff struct pfr_kentry *ke; 788c1be8399SMark Johnston counter_u64_t c; 7893b3a8eb9SGleb Smirnoff 7903b3a8eb9SGleb Smirnoff ke = uma_zalloc(V_pfr_kentry_z, M_NOWAIT | M_ZERO); 7913b3a8eb9SGleb Smirnoff if (ke == NULL) 7923b3a8eb9SGleb Smirnoff return (NULL); 7933b3a8eb9SGleb Smirnoff 794*abda72f3SKristof Provost switch (ad->pfra_af) { 795*abda72f3SKristof Provost case AF_INET: 7963b3a8eb9SGleb Smirnoff FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr); 797*abda72f3SKristof Provost break; 798*abda72f3SKristof Provost case AF_INET6: 7993b3a8eb9SGleb Smirnoff FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr); 800*abda72f3SKristof Provost break; 801*abda72f3SKristof Provost default: 802*abda72f3SKristof Provost unhandled_af(ad->pfra_af); 803*abda72f3SKristof Provost } 8043b3a8eb9SGleb Smirnoff ke->pfrke_af = ad->pfra_af; 8053b3a8eb9SGleb Smirnoff ke->pfrke_net = ad->pfra_net; 8063b3a8eb9SGleb Smirnoff ke->pfrke_not = ad->pfra_not; 80721121f9bSMark Johnston ke->pfrke_counters.pfrkc_tzero = 0; 808c1be8399SMark Johnston if (counters) { 809c1be8399SMark Johnston c = uma_zalloc_pcpu(V_pfr_kentry_counter_z, M_NOWAIT | M_ZERO); 810c1be8399SMark Johnston if (c == NULL) { 81159048686SKristof Provost pfr_destroy_kentry(ke); 81259048686SKristof Provost return (NULL); 81359048686SKristof Provost } 814c1be8399SMark Johnston ke->pfrke_counters.pfrkc_counters = c; 81559048686SKristof Provost } 8163b3a8eb9SGleb Smirnoff return (ke); 8173b3a8eb9SGleb Smirnoff } 8183b3a8eb9SGleb Smirnoff 8193b3a8eb9SGleb Smirnoff static void 8203b3a8eb9SGleb Smirnoff pfr_destroy_kentries(struct pfr_kentryworkq *workq) 8213b3a8eb9SGleb Smirnoff { 8223b3a8eb9SGleb Smirnoff struct pfr_kentry *p, *q; 8233b3a8eb9SGleb Smirnoff 8243b3a8eb9SGleb Smirnoff for (p = SLIST_FIRST(workq); p != NULL; p = q) { 8253b3a8eb9SGleb Smirnoff q = SLIST_NEXT(p, pfrke_workq); 8263b3a8eb9SGleb Smirnoff pfr_destroy_kentry(p); 8273b3a8eb9SGleb Smirnoff } 8283b3a8eb9SGleb Smirnoff } 8293b3a8eb9SGleb Smirnoff 8303b3a8eb9SGleb Smirnoff static void 831c1be8399SMark Johnston pfr_destroy_kentry(struct pfr_kentry *ke) 83259048686SKristof Provost { 83321121f9bSMark Johnston counter_u64_t c; 83421121f9bSMark Johnston 835c1be8399SMark Johnston if ((c = ke->pfrke_counters.pfrkc_counters) != NULL) 836c1be8399SMark Johnston uma_zfree_pcpu(V_pfr_kentry_counter_z, c); 8373b3a8eb9SGleb Smirnoff uma_zfree(V_pfr_kentry_z, ke); 8383b3a8eb9SGleb Smirnoff } 8393b3a8eb9SGleb Smirnoff 8403b3a8eb9SGleb Smirnoff static void 8413b3a8eb9SGleb Smirnoff pfr_insert_kentries(struct pfr_ktable *kt, 8427e7f8800SKristof Provost struct pfr_kentryworkq *workq, time_t tzero) 8433b3a8eb9SGleb Smirnoff { 8443b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 8453b3a8eb9SGleb Smirnoff int rv, n = 0; 8463b3a8eb9SGleb Smirnoff 8473b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, workq, pfrke_workq) { 8483b3a8eb9SGleb Smirnoff rv = pfr_route_kentry(kt, p); 8493b3a8eb9SGleb Smirnoff if (rv) { 8503b3a8eb9SGleb Smirnoff printf("pfr_insert_kentries: cannot route entry " 8513b3a8eb9SGleb Smirnoff "(code=%d).\n", rv); 8523b3a8eb9SGleb Smirnoff break; 8533b3a8eb9SGleb Smirnoff } 85459048686SKristof Provost p->pfrke_counters.pfrkc_tzero = tzero; 8553b3a8eb9SGleb Smirnoff n++; 8563b3a8eb9SGleb Smirnoff } 8573b3a8eb9SGleb Smirnoff kt->pfrkt_cnt += n; 8583b3a8eb9SGleb Smirnoff } 8593b3a8eb9SGleb Smirnoff 8603b3a8eb9SGleb Smirnoff int 8617e7f8800SKristof Provost pfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, time_t tzero) 8623b3a8eb9SGleb Smirnoff { 8633b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 8643b3a8eb9SGleb Smirnoff int rv; 8653b3a8eb9SGleb Smirnoff 8663b3a8eb9SGleb Smirnoff p = pfr_lookup_addr(kt, ad, 1); 8673b3a8eb9SGleb Smirnoff if (p != NULL) 8683b3a8eb9SGleb Smirnoff return (0); 86921121f9bSMark Johnston p = pfr_create_kentry(ad, (kt->pfrkt_flags & PFR_TFLAG_COUNTERS) != 0); 8703b3a8eb9SGleb Smirnoff if (p == NULL) 871e706fd3aSGleb Smirnoff return (ENOMEM); 8723b3a8eb9SGleb Smirnoff 8733b3a8eb9SGleb Smirnoff rv = pfr_route_kentry(kt, p); 8743b3a8eb9SGleb Smirnoff if (rv) 8753b3a8eb9SGleb Smirnoff return (rv); 8763b3a8eb9SGleb Smirnoff 87759048686SKristof Provost p->pfrke_counters.pfrkc_tzero = tzero; 8783b3a8eb9SGleb Smirnoff kt->pfrkt_cnt++; 8793b3a8eb9SGleb Smirnoff 8803b3a8eb9SGleb Smirnoff return (0); 8813b3a8eb9SGleb Smirnoff } 8823b3a8eb9SGleb Smirnoff 8833b3a8eb9SGleb Smirnoff static void 8843b3a8eb9SGleb Smirnoff pfr_remove_kentries(struct pfr_ktable *kt, 8853b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *workq) 8863b3a8eb9SGleb Smirnoff { 8873b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 8883b3a8eb9SGleb Smirnoff int n = 0; 8893b3a8eb9SGleb Smirnoff 8903b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, workq, pfrke_workq) { 8913b3a8eb9SGleb Smirnoff pfr_unroute_kentry(kt, p); 8923b3a8eb9SGleb Smirnoff n++; 8933b3a8eb9SGleb Smirnoff } 8943b3a8eb9SGleb Smirnoff kt->pfrkt_cnt -= n; 8953b3a8eb9SGleb Smirnoff pfr_destroy_kentries(workq); 8963b3a8eb9SGleb Smirnoff } 8973b3a8eb9SGleb Smirnoff 8983b3a8eb9SGleb Smirnoff static void 8993b3a8eb9SGleb Smirnoff pfr_clean_node_mask(struct pfr_ktable *kt, 9003b3a8eb9SGleb Smirnoff struct pfr_kentryworkq *workq) 9013b3a8eb9SGleb Smirnoff { 9023b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 9033b3a8eb9SGleb Smirnoff 9043b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, workq, pfrke_workq) 9053b3a8eb9SGleb Smirnoff pfr_unroute_kentry(kt, p); 9063b3a8eb9SGleb Smirnoff } 9073b3a8eb9SGleb Smirnoff 9083b3a8eb9SGleb Smirnoff static void 90921121f9bSMark Johnston pfr_clstats_kentries(struct pfr_ktable *kt, struct pfr_kentryworkq *workq, 9107e7f8800SKristof Provost time_t tzero, int negchange) 9113b3a8eb9SGleb Smirnoff { 9123b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 913c1be8399SMark Johnston int i; 9143b3a8eb9SGleb Smirnoff 9153b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, workq, pfrke_workq) { 9163b3a8eb9SGleb Smirnoff if (negchange) 9173b3a8eb9SGleb Smirnoff p->pfrke_not = !p->pfrke_not; 91821121f9bSMark Johnston if ((kt->pfrkt_flags & PFR_TFLAG_COUNTERS) != 0) 919c1be8399SMark Johnston for (i = 0; i < PFR_NUM_COUNTERS; i++) 920c1be8399SMark Johnston counter_u64_zero( 921c1be8399SMark Johnston p->pfrke_counters.pfrkc_counters + i); 92259048686SKristof Provost p->pfrke_counters.pfrkc_tzero = tzero; 9233b3a8eb9SGleb Smirnoff } 9243b3a8eb9SGleb Smirnoff } 9253b3a8eb9SGleb Smirnoff 9263b3a8eb9SGleb Smirnoff static void 9273b3a8eb9SGleb Smirnoff pfr_reset_feedback(struct pfr_addr *addr, int size) 9283b3a8eb9SGleb Smirnoff { 9293b3a8eb9SGleb Smirnoff struct pfr_addr *ad; 9303b3a8eb9SGleb Smirnoff int i; 9313b3a8eb9SGleb Smirnoff 9323b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) 9333b3a8eb9SGleb Smirnoff ad->pfra_fback = PFR_FB_NONE; 9343b3a8eb9SGleb Smirnoff } 9353b3a8eb9SGleb Smirnoff 9363b3a8eb9SGleb Smirnoff static void 9373b3a8eb9SGleb Smirnoff pfr_prepare_network(union sockaddr_union *sa, int af, int net) 9383b3a8eb9SGleb Smirnoff { 9393b3a8eb9SGleb Smirnoff int i; 9403b3a8eb9SGleb Smirnoff 9413b3a8eb9SGleb Smirnoff bzero(sa, sizeof(*sa)); 942*abda72f3SKristof Provost switch (af) { 943*abda72f3SKristof Provost case AF_INET: 9443b3a8eb9SGleb Smirnoff sa->sin.sin_len = sizeof(sa->sin); 9453b3a8eb9SGleb Smirnoff sa->sin.sin_family = AF_INET; 9463b3a8eb9SGleb Smirnoff sa->sin.sin_addr.s_addr = net ? htonl(-1 << (32-net)) : 0; 947*abda72f3SKristof Provost break; 948*abda72f3SKristof Provost case AF_INET6: 9493b3a8eb9SGleb Smirnoff sa->sin6.sin6_len = sizeof(sa->sin6); 9503b3a8eb9SGleb Smirnoff sa->sin6.sin6_family = AF_INET6; 9513b3a8eb9SGleb Smirnoff for (i = 0; i < 4; i++) { 9523b3a8eb9SGleb Smirnoff if (net <= 32) { 9533b3a8eb9SGleb Smirnoff sa->sin6.sin6_addr.s6_addr32[i] = 9543b3a8eb9SGleb Smirnoff net ? htonl(-1 << (32-net)) : 0; 9553b3a8eb9SGleb Smirnoff break; 9563b3a8eb9SGleb Smirnoff } 9573b3a8eb9SGleb Smirnoff sa->sin6.sin6_addr.s6_addr32[i] = 0xFFFFFFFF; 9583b3a8eb9SGleb Smirnoff net -= 32; 9593b3a8eb9SGleb Smirnoff } 960*abda72f3SKristof Provost break; 961*abda72f3SKristof Provost default: 962*abda72f3SKristof Provost unhandled_af(af); 9633b3a8eb9SGleb Smirnoff } 9643b3a8eb9SGleb Smirnoff } 9653b3a8eb9SGleb Smirnoff 9663b3a8eb9SGleb Smirnoff static int 9673b3a8eb9SGleb Smirnoff pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) 9683b3a8eb9SGleb Smirnoff { 9693b3a8eb9SGleb Smirnoff union sockaddr_union mask; 9703b3a8eb9SGleb Smirnoff struct radix_node *rn; 97161eee0e2SAlexander V. Chernikov struct radix_head *head = NULL; 9723b3a8eb9SGleb Smirnoff 97329bdd62cSGleb Smirnoff PF_RULES_WASSERT(); 97429bdd62cSGleb Smirnoff 9753b3a8eb9SGleb Smirnoff bzero(ke->pfrke_node, sizeof(ke->pfrke_node)); 9767e51bc6cSKristof Provost switch (ke->pfrke_af) { 9777e51bc6cSKristof Provost case AF_INET: 97861eee0e2SAlexander V. Chernikov head = &kt->pfrkt_ip4->rh; 9797e51bc6cSKristof Provost break; 9807e51bc6cSKristof Provost case AF_INET6: 98161eee0e2SAlexander V. Chernikov head = &kt->pfrkt_ip6->rh; 9827e51bc6cSKristof Provost break; 9837e51bc6cSKristof Provost default: 9847e51bc6cSKristof Provost unhandled_af(ke->pfrke_af); 9857e51bc6cSKristof Provost } 9863b3a8eb9SGleb Smirnoff 9873b3a8eb9SGleb Smirnoff if (KENTRY_NETWORK(ke)) { 9883b3a8eb9SGleb Smirnoff pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); 9893b3a8eb9SGleb Smirnoff rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node); 9903b3a8eb9SGleb Smirnoff } else 9913b3a8eb9SGleb Smirnoff rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node); 9923b3a8eb9SGleb Smirnoff 9933b3a8eb9SGleb Smirnoff return (rn == NULL ? -1 : 0); 9943b3a8eb9SGleb Smirnoff } 9953b3a8eb9SGleb Smirnoff 9963b3a8eb9SGleb Smirnoff static int 9973b3a8eb9SGleb Smirnoff pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) 9983b3a8eb9SGleb Smirnoff { 9993b3a8eb9SGleb Smirnoff union sockaddr_union mask; 10003b3a8eb9SGleb Smirnoff struct radix_node *rn; 100161eee0e2SAlexander V. Chernikov struct radix_head *head = NULL; 10023b3a8eb9SGleb Smirnoff 10037e51bc6cSKristof Provost switch (ke->pfrke_af) { 10047e51bc6cSKristof Provost case AF_INET: 100561eee0e2SAlexander V. Chernikov head = &kt->pfrkt_ip4->rh; 10067e51bc6cSKristof Provost break; 10077e51bc6cSKristof Provost case AF_INET6: 100861eee0e2SAlexander V. Chernikov head = &kt->pfrkt_ip6->rh; 10097e51bc6cSKristof Provost break; 10107e51bc6cSKristof Provost default: 10117e51bc6cSKristof Provost unhandled_af(ke->pfrke_af); 10127e51bc6cSKristof Provost } 10133b3a8eb9SGleb Smirnoff 10143b3a8eb9SGleb Smirnoff if (KENTRY_NETWORK(ke)) { 10153b3a8eb9SGleb Smirnoff pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); 10163b3a8eb9SGleb Smirnoff rn = rn_delete(&ke->pfrke_sa, &mask, head); 10173b3a8eb9SGleb Smirnoff } else 10183b3a8eb9SGleb Smirnoff rn = rn_delete(&ke->pfrke_sa, NULL, head); 10193b3a8eb9SGleb Smirnoff 10203b3a8eb9SGleb Smirnoff if (rn == NULL) { 10213b3a8eb9SGleb Smirnoff printf("pfr_unroute_kentry: delete failed.\n"); 10223b3a8eb9SGleb Smirnoff return (-1); 10233b3a8eb9SGleb Smirnoff } 10243b3a8eb9SGleb Smirnoff return (0); 10253b3a8eb9SGleb Smirnoff } 10263b3a8eb9SGleb Smirnoff 10273b3a8eb9SGleb Smirnoff static void 102859048686SKristof Provost pfr_copyout_addr(struct pfr_addr *ad, const struct pfr_kentry *ke) 10293b3a8eb9SGleb Smirnoff { 10303b3a8eb9SGleb Smirnoff bzero(ad, sizeof(*ad)); 10313b3a8eb9SGleb Smirnoff if (ke == NULL) 10323b3a8eb9SGleb Smirnoff return; 10333b3a8eb9SGleb Smirnoff ad->pfra_af = ke->pfrke_af; 10343b3a8eb9SGleb Smirnoff ad->pfra_net = ke->pfrke_net; 10353b3a8eb9SGleb Smirnoff ad->pfra_not = ke->pfrke_not; 1036*abda72f3SKristof Provost switch (ad->pfra_af) { 1037*abda72f3SKristof Provost case AF_INET: 10383b3a8eb9SGleb Smirnoff ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr; 1039*abda72f3SKristof Provost break; 1040*abda72f3SKristof Provost case AF_INET6: 10413b3a8eb9SGleb Smirnoff ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr; 1042*abda72f3SKristof Provost break; 1043*abda72f3SKristof Provost default: 1044*abda72f3SKristof Provost unhandled_af(ad->pfra_af); 1045*abda72f3SKristof Provost } 10463b3a8eb9SGleb Smirnoff } 10473b3a8eb9SGleb Smirnoff 104859048686SKristof Provost static void 104959048686SKristof Provost pfr_copyout_astats(struct pfr_astats *as, const struct pfr_kentry *ke, 105059048686SKristof Provost const struct pfr_walktree *w) 105159048686SKristof Provost { 105259048686SKristof Provost int dir, op; 105359048686SKristof Provost const struct pfr_kcounters *kc = &ke->pfrke_counters; 105459048686SKristof Provost 105560a38abbSMark Johnston bzero(as, sizeof(*as)); 105659048686SKristof Provost pfr_copyout_addr(&as->pfras_a, ke); 105759048686SKristof Provost as->pfras_tzero = kc->pfrkc_tzero; 105859048686SKristof Provost 1059b21826bfSKristof Provost if (! (w->pfrw_flags & PFR_TFLAG_COUNTERS) || 1060b21826bfSKristof Provost kc->pfrkc_counters == NULL) { 106159048686SKristof Provost bzero(as->pfras_packets, sizeof(as->pfras_packets)); 106259048686SKristof Provost bzero(as->pfras_bytes, sizeof(as->pfras_bytes)); 106359048686SKristof Provost as->pfras_a.pfra_fback = PFR_FB_NOCOUNT; 106459048686SKristof Provost return; 106559048686SKristof Provost } 106659048686SKristof Provost 106759048686SKristof Provost for (dir = 0; dir < PFR_DIR_MAX; dir++) { 106859048686SKristof Provost for (op = 0; op < PFR_OP_ADDR_MAX; op ++) { 1069c1be8399SMark Johnston as->pfras_packets[dir][op] = counter_u64_fetch( 1070c1be8399SMark Johnston pfr_kentry_counter(kc, dir, op, PFR_TYPE_PACKETS)); 1071c1be8399SMark Johnston as->pfras_bytes[dir][op] = counter_u64_fetch( 1072c1be8399SMark Johnston pfr_kentry_counter(kc, dir, op, PFR_TYPE_BYTES)); 107359048686SKristof Provost } 107459048686SKristof Provost } 107559048686SKristof Provost } 107659048686SKristof Provost 10778ca12190SKristof Provost static void 10788ca12190SKristof Provost pfr_sockaddr_to_pf_addr(const union sockaddr_union *sa, struct pf_addr *a) 10798ca12190SKristof Provost { 10808ca12190SKristof Provost switch (sa->sa.sa_family) { 10818ca12190SKristof Provost case AF_INET: 10828ca12190SKristof Provost memcpy(&a->v4, &sa->sin.sin_addr, sizeof(a->v4)); 10838ca12190SKristof Provost break; 10848ca12190SKristof Provost case AF_INET6: 10858ca12190SKristof Provost memcpy(&a->v6, &sa->sin6.sin6_addr, sizeof(a->v6)); 10868ca12190SKristof Provost break; 10878ca12190SKristof Provost default: 10887e51bc6cSKristof Provost unhandled_af(sa->sa.sa_family); 10898ca12190SKristof Provost } 10908ca12190SKristof Provost } 10918ca12190SKristof Provost 10923b3a8eb9SGleb Smirnoff static int 10933b3a8eb9SGleb Smirnoff pfr_walktree(struct radix_node *rn, void *arg) 10943b3a8eb9SGleb Smirnoff { 10953b3a8eb9SGleb Smirnoff struct pfr_kentry *ke = (struct pfr_kentry *)rn; 10963b3a8eb9SGleb Smirnoff struct pfr_walktree *w = arg; 10973b3a8eb9SGleb Smirnoff 10983b3a8eb9SGleb Smirnoff switch (w->pfrw_op) { 10993b3a8eb9SGleb Smirnoff case PFRW_MARK: 11003b3a8eb9SGleb Smirnoff ke->pfrke_mark = 0; 11013b3a8eb9SGleb Smirnoff break; 11023b3a8eb9SGleb Smirnoff case PFRW_SWEEP: 11033b3a8eb9SGleb Smirnoff if (ke->pfrke_mark) 11043b3a8eb9SGleb Smirnoff break; 11053b3a8eb9SGleb Smirnoff /* FALLTHROUGH */ 11063b3a8eb9SGleb Smirnoff case PFRW_ENQUEUE: 11073b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(w->pfrw_workq, ke, pfrke_workq); 11087b676698SKristof Provost w->pfrw_free++; 11093b3a8eb9SGleb Smirnoff break; 11103b3a8eb9SGleb Smirnoff case PFRW_GET_ADDRS: 11113b3a8eb9SGleb Smirnoff if (w->pfrw_free-- > 0) { 11123b3a8eb9SGleb Smirnoff pfr_copyout_addr(w->pfrw_addr, ke); 11133b3a8eb9SGleb Smirnoff w->pfrw_addr++; 11143b3a8eb9SGleb Smirnoff } 11153b3a8eb9SGleb Smirnoff break; 11163b3a8eb9SGleb Smirnoff case PFRW_GET_ASTATS: 11173b3a8eb9SGleb Smirnoff if (w->pfrw_free-- > 0) { 11183b3a8eb9SGleb Smirnoff struct pfr_astats as; 11193b3a8eb9SGleb Smirnoff 112059048686SKristof Provost pfr_copyout_astats(&as, ke, w); 11213b3a8eb9SGleb Smirnoff 11223b3a8eb9SGleb Smirnoff bcopy(&as, w->pfrw_astats, sizeof(as)); 11233b3a8eb9SGleb Smirnoff w->pfrw_astats++; 11243b3a8eb9SGleb Smirnoff } 11253b3a8eb9SGleb Smirnoff break; 11263b3a8eb9SGleb Smirnoff case PFRW_POOL_GET: 11273b3a8eb9SGleb Smirnoff if (ke->pfrke_not) 11283b3a8eb9SGleb Smirnoff break; /* negative entries are ignored */ 11297b676698SKristof Provost if (!w->pfrw_free--) { 11303b3a8eb9SGleb Smirnoff w->pfrw_kentry = ke; 11313b3a8eb9SGleb Smirnoff return (1); /* finish search */ 11323b3a8eb9SGleb Smirnoff } 11333b3a8eb9SGleb Smirnoff break; 11343b3a8eb9SGleb Smirnoff case PFRW_DYNADDR_UPDATE: 11353b3a8eb9SGleb Smirnoff { 11363b3a8eb9SGleb Smirnoff union sockaddr_union pfr_mask; 11373b3a8eb9SGleb Smirnoff 1138*abda72f3SKristof Provost switch (ke->pfrke_af) { 1139*abda72f3SKristof Provost case AF_INET: 11403b3a8eb9SGleb Smirnoff if (w->pfrw_dyn->pfid_acnt4++ > 0) 11413b3a8eb9SGleb Smirnoff break; 11423b3a8eb9SGleb Smirnoff pfr_prepare_network(&pfr_mask, AF_INET, ke->pfrke_net); 11438ca12190SKristof Provost pfr_sockaddr_to_pf_addr(&ke->pfrke_sa, &w->pfrw_dyn->pfid_addr4); 11448ca12190SKristof Provost pfr_sockaddr_to_pf_addr(&pfr_mask, &w->pfrw_dyn->pfid_mask4); 1145*abda72f3SKristof Provost break; 1146*abda72f3SKristof Provost case AF_INET6: 11473b3a8eb9SGleb Smirnoff if (w->pfrw_dyn->pfid_acnt6++ > 0) 11483b3a8eb9SGleb Smirnoff break; 11493b3a8eb9SGleb Smirnoff pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net); 11508ca12190SKristof Provost pfr_sockaddr_to_pf_addr(&ke->pfrke_sa, &w->pfrw_dyn->pfid_addr6); 11518ca12190SKristof Provost pfr_sockaddr_to_pf_addr(&pfr_mask, &w->pfrw_dyn->pfid_mask6); 1152*abda72f3SKristof Provost break; 1153*abda72f3SKristof Provost default: 1154*abda72f3SKristof Provost unhandled_af(ke->pfrke_af); 11553b3a8eb9SGleb Smirnoff } 11563b3a8eb9SGleb Smirnoff break; 11573b3a8eb9SGleb Smirnoff } 1158b21826bfSKristof Provost case PFRW_COUNTERS: 1159b21826bfSKristof Provost { 1160b21826bfSKristof Provost if (w->pfrw_flags & PFR_TFLAG_COUNTERS) { 1161b21826bfSKristof Provost if (ke->pfrke_counters.pfrkc_counters != NULL) 1162b21826bfSKristof Provost break; 1163b21826bfSKristof Provost ke->pfrke_counters.pfrkc_counters = 1164b21826bfSKristof Provost uma_zalloc_pcpu(V_pfr_kentry_counter_z, 1165b21826bfSKristof Provost M_NOWAIT | M_ZERO); 1166b21826bfSKristof Provost } else { 1167b21826bfSKristof Provost uma_zfree_pcpu(V_pfr_kentry_counter_z, 1168b21826bfSKristof Provost ke->pfrke_counters.pfrkc_counters); 1169b21826bfSKristof Provost ke->pfrke_counters.pfrkc_counters = NULL; 1170b21826bfSKristof Provost } 1171b21826bfSKristof Provost break; 1172b21826bfSKristof Provost } 11733b3a8eb9SGleb Smirnoff } 11743b3a8eb9SGleb Smirnoff return (0); 11753b3a8eb9SGleb Smirnoff } 11763b3a8eb9SGleb Smirnoff 11773b3a8eb9SGleb Smirnoff int 11783b3a8eb9SGleb Smirnoff pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) 11793b3a8eb9SGleb Smirnoff { 11803b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 11813b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 11823b3a8eb9SGleb Smirnoff int xdel = 0; 11833b3a8eb9SGleb Smirnoff 11843b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ALLRSETS); 11853b3a8eb9SGleb Smirnoff if (pfr_fix_anchor(filter->pfrt_anchor)) 11863b3a8eb9SGleb Smirnoff return (EINVAL); 11873b3a8eb9SGleb Smirnoff if (pfr_table_count(filter, flags) < 0) 11883b3a8eb9SGleb Smirnoff return (ENOENT); 11893b3a8eb9SGleb Smirnoff 11903b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 11911e9e3741SMarko Zec RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { 11923b3a8eb9SGleb Smirnoff if (pfr_skip_table(filter, p, flags)) 11933b3a8eb9SGleb Smirnoff continue; 11943b3a8eb9SGleb Smirnoff if (!strcmp(p->pfrkt_anchor, PF_RESERVED_ANCHOR)) 11953b3a8eb9SGleb Smirnoff continue; 11963b3a8eb9SGleb Smirnoff if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) 11973b3a8eb9SGleb Smirnoff continue; 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 if (!(flags & PFR_FLAG_DUMMY)) 12033b3a8eb9SGleb Smirnoff pfr_setflags_ktables(&workq); 12043b3a8eb9SGleb Smirnoff if (ndel != NULL) 12053b3a8eb9SGleb Smirnoff *ndel = xdel; 12063b3a8eb9SGleb Smirnoff return (0); 12073b3a8eb9SGleb Smirnoff } 12083b3a8eb9SGleb Smirnoff 12093b3a8eb9SGleb Smirnoff int 12103b3a8eb9SGleb Smirnoff pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) 12113b3a8eb9SGleb Smirnoff { 12123b3a8eb9SGleb Smirnoff struct pfr_ktableworkq addq, changeq; 12133b3a8eb9SGleb Smirnoff struct pfr_ktable *p, *q, *r, key; 12143b3a8eb9SGleb Smirnoff int i, rv, xadd = 0; 12157e7f8800SKristof Provost time_t tzero = time_second; 12163b3a8eb9SGleb Smirnoff 12173b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 12183b3a8eb9SGleb Smirnoff SLIST_INIT(&addq); 12193b3a8eb9SGleb Smirnoff SLIST_INIT(&changeq); 12203b3a8eb9SGleb Smirnoff for (i = 0; i < size; i++) { 12213b3a8eb9SGleb Smirnoff bcopy(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)); 12223b3a8eb9SGleb Smirnoff if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK, 12233b3a8eb9SGleb Smirnoff flags & PFR_FLAG_USERIOCTL)) 12243b3a8eb9SGleb Smirnoff senderr(EINVAL); 12253b3a8eb9SGleb Smirnoff key.pfrkt_flags |= PFR_TFLAG_ACTIVE; 12261e9e3741SMarko Zec p = RB_FIND(pfr_ktablehead, &V_pfr_ktables, &key); 12273b3a8eb9SGleb Smirnoff if (p == NULL) { 12283b3a8eb9SGleb Smirnoff p = pfr_create_ktable(&key.pfrkt_t, tzero, 1); 12293b3a8eb9SGleb Smirnoff if (p == NULL) 12303b3a8eb9SGleb Smirnoff senderr(ENOMEM); 12313b3a8eb9SGleb Smirnoff SLIST_FOREACH(q, &addq, pfrkt_workq) { 1232b4b8fa33SKristof Provost if (!pfr_ktable_compare(p, q)) { 1233b4b8fa33SKristof Provost pfr_destroy_ktable(p, 0); 12343b3a8eb9SGleb Smirnoff goto _skip; 12353b3a8eb9SGleb Smirnoff } 1236b4b8fa33SKristof Provost } 12373b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&addq, p, pfrkt_workq); 12383b3a8eb9SGleb Smirnoff xadd++; 12393b3a8eb9SGleb Smirnoff if (!key.pfrkt_anchor[0]) 12403b3a8eb9SGleb Smirnoff goto _skip; 12413b3a8eb9SGleb Smirnoff 12423b3a8eb9SGleb Smirnoff /* find or create root table */ 12433b3a8eb9SGleb Smirnoff bzero(key.pfrkt_anchor, sizeof(key.pfrkt_anchor)); 12441e9e3741SMarko Zec r = RB_FIND(pfr_ktablehead, &V_pfr_ktables, &key); 12453b3a8eb9SGleb Smirnoff if (r != NULL) { 12463b3a8eb9SGleb Smirnoff p->pfrkt_root = r; 12473b3a8eb9SGleb Smirnoff goto _skip; 12483b3a8eb9SGleb Smirnoff } 12493b3a8eb9SGleb Smirnoff SLIST_FOREACH(q, &addq, pfrkt_workq) { 12503b3a8eb9SGleb Smirnoff if (!pfr_ktable_compare(&key, q)) { 12513b3a8eb9SGleb Smirnoff p->pfrkt_root = q; 12523b3a8eb9SGleb Smirnoff goto _skip; 12533b3a8eb9SGleb Smirnoff } 12543b3a8eb9SGleb Smirnoff } 12553b3a8eb9SGleb Smirnoff key.pfrkt_flags = 0; 12563b3a8eb9SGleb Smirnoff r = pfr_create_ktable(&key.pfrkt_t, 0, 1); 12573b3a8eb9SGleb Smirnoff if (r == NULL) 12583b3a8eb9SGleb Smirnoff senderr(ENOMEM); 12593b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&addq, r, pfrkt_workq); 12603b3a8eb9SGleb Smirnoff p->pfrkt_root = r; 12613b3a8eb9SGleb Smirnoff } else if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { 12623b3a8eb9SGleb Smirnoff SLIST_FOREACH(q, &changeq, pfrkt_workq) 12633b3a8eb9SGleb Smirnoff if (!pfr_ktable_compare(&key, q)) 12643b3a8eb9SGleb Smirnoff goto _skip; 12653b3a8eb9SGleb Smirnoff p->pfrkt_nflags = (p->pfrkt_flags & 12663b3a8eb9SGleb Smirnoff ~PFR_TFLAG_USRMASK) | key.pfrkt_flags; 12673b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq); 12683b3a8eb9SGleb Smirnoff xadd++; 12693b3a8eb9SGleb Smirnoff } 12703b3a8eb9SGleb Smirnoff _skip: 12713b3a8eb9SGleb Smirnoff ; 12723b3a8eb9SGleb Smirnoff } 12733b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 12743b3a8eb9SGleb Smirnoff pfr_insert_ktables(&addq); 12753b3a8eb9SGleb Smirnoff pfr_setflags_ktables(&changeq); 12763b3a8eb9SGleb Smirnoff } else 12773b3a8eb9SGleb Smirnoff pfr_destroy_ktables(&addq, 0); 12783b3a8eb9SGleb Smirnoff if (nadd != NULL) 12793b3a8eb9SGleb Smirnoff *nadd = xadd; 12803b3a8eb9SGleb Smirnoff return (0); 12813b3a8eb9SGleb Smirnoff _bad: 12823b3a8eb9SGleb Smirnoff pfr_destroy_ktables(&addq, 0); 12833b3a8eb9SGleb Smirnoff return (rv); 12843b3a8eb9SGleb Smirnoff } 12853b3a8eb9SGleb Smirnoff 12863b3a8eb9SGleb Smirnoff int 12873b3a8eb9SGleb Smirnoff pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) 12883b3a8eb9SGleb Smirnoff { 12893b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 12903b3a8eb9SGleb Smirnoff struct pfr_ktable *p, *q, key; 12913b3a8eb9SGleb Smirnoff int i, xdel = 0; 12923b3a8eb9SGleb Smirnoff 12933b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 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, 12983b3a8eb9SGleb Smirnoff flags & PFR_FLAG_USERIOCTL)) 12993b3a8eb9SGleb Smirnoff return (EINVAL); 13001e9e3741SMarko Zec p = RB_FIND(pfr_ktablehead, &V_pfr_ktables, &key); 13013b3a8eb9SGleb Smirnoff if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { 13023b3a8eb9SGleb Smirnoff SLIST_FOREACH(q, &workq, pfrkt_workq) 13033b3a8eb9SGleb Smirnoff if (!pfr_ktable_compare(p, q)) 13043b3a8eb9SGleb Smirnoff goto _skip; 13053b3a8eb9SGleb Smirnoff p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE; 13063b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 13073b3a8eb9SGleb Smirnoff xdel++; 13083b3a8eb9SGleb Smirnoff } 13093b3a8eb9SGleb Smirnoff _skip: 13103b3a8eb9SGleb Smirnoff ; 13113b3a8eb9SGleb Smirnoff } 13123b3a8eb9SGleb Smirnoff 13133b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 13143b3a8eb9SGleb Smirnoff pfr_setflags_ktables(&workq); 13153b3a8eb9SGleb Smirnoff if (ndel != NULL) 13163b3a8eb9SGleb Smirnoff *ndel = xdel; 13173b3a8eb9SGleb Smirnoff return (0); 13183b3a8eb9SGleb Smirnoff } 13193b3a8eb9SGleb Smirnoff 13203b3a8eb9SGleb Smirnoff int 13213b3a8eb9SGleb Smirnoff pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, 13223b3a8eb9SGleb Smirnoff int flags) 13233b3a8eb9SGleb Smirnoff { 13243b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 13253b3a8eb9SGleb Smirnoff int n, nn; 13263b3a8eb9SGleb Smirnoff 13273b3a8eb9SGleb Smirnoff PF_RULES_RASSERT(); 13283b3a8eb9SGleb Smirnoff 13293b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS); 13303b3a8eb9SGleb Smirnoff if (pfr_fix_anchor(filter->pfrt_anchor)) 13313b3a8eb9SGleb Smirnoff return (EINVAL); 13323b3a8eb9SGleb Smirnoff n = nn = pfr_table_count(filter, flags); 13333b3a8eb9SGleb Smirnoff if (n < 0) 13343b3a8eb9SGleb Smirnoff return (ENOENT); 13353b3a8eb9SGleb Smirnoff if (n > *size) { 13363b3a8eb9SGleb Smirnoff *size = n; 13373b3a8eb9SGleb Smirnoff return (0); 13383b3a8eb9SGleb Smirnoff } 13391e9e3741SMarko Zec RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { 13403b3a8eb9SGleb Smirnoff if (pfr_skip_table(filter, p, flags)) 13413b3a8eb9SGleb Smirnoff continue; 13423b3a8eb9SGleb Smirnoff if (n-- <= 0) 13433b3a8eb9SGleb Smirnoff continue; 13443b3a8eb9SGleb Smirnoff bcopy(&p->pfrkt_t, tbl++, sizeof(*tbl)); 13453b3a8eb9SGleb Smirnoff } 13463b3a8eb9SGleb Smirnoff 13473b3a8eb9SGleb Smirnoff KASSERT(n == 0, ("%s: corruption detected (%d)", __func__, n)); 13483b3a8eb9SGleb Smirnoff 13493b3a8eb9SGleb Smirnoff *size = nn; 13503b3a8eb9SGleb Smirnoff return (0); 13513b3a8eb9SGleb Smirnoff } 13523b3a8eb9SGleb Smirnoff 13533b3a8eb9SGleb Smirnoff int 13543b3a8eb9SGleb Smirnoff pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, 13553b3a8eb9SGleb Smirnoff int flags) 13563b3a8eb9SGleb Smirnoff { 13573b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 13583b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 13593b3a8eb9SGleb Smirnoff int n, nn; 13607e7f8800SKristof Provost time_t tzero = time_second; 136159048686SKristof Provost int pfr_dir, pfr_op; 13623b3a8eb9SGleb Smirnoff 13633b3a8eb9SGleb Smirnoff /* XXX PFR_FLAG_CLSTATS disabled */ 13643b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS); 13653b3a8eb9SGleb Smirnoff if (pfr_fix_anchor(filter->pfrt_anchor)) 13663b3a8eb9SGleb Smirnoff return (EINVAL); 13673b3a8eb9SGleb Smirnoff n = nn = pfr_table_count(filter, flags); 13683b3a8eb9SGleb Smirnoff if (n < 0) 13693b3a8eb9SGleb Smirnoff return (ENOENT); 13703b3a8eb9SGleb Smirnoff if (n > *size) { 13713b3a8eb9SGleb Smirnoff *size = n; 13723b3a8eb9SGleb Smirnoff return (0); 13733b3a8eb9SGleb Smirnoff } 13743b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 13751e9e3741SMarko Zec RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { 13763b3a8eb9SGleb Smirnoff if (pfr_skip_table(filter, p, flags)) 13773b3a8eb9SGleb Smirnoff continue; 13783b3a8eb9SGleb Smirnoff if (n-- <= 0) 13793b3a8eb9SGleb Smirnoff continue; 138059048686SKristof Provost bcopy(&p->pfrkt_kts.pfrts_t, &tbl->pfrts_t, 138159048686SKristof Provost sizeof(struct pfr_table)); 138259048686SKristof Provost for (pfr_dir = 0; pfr_dir < PFR_DIR_MAX; pfr_dir ++) { 138359048686SKristof Provost for (pfr_op = 0; pfr_op < PFR_OP_TABLE_MAX; pfr_op ++) { 138459048686SKristof Provost tbl->pfrts_packets[pfr_dir][pfr_op] = 1385f92c21a2SMateusz Guzik pfr_kstate_counter_fetch( 1386f92c21a2SMateusz Guzik &p->pfrkt_packets[pfr_dir][pfr_op]); 138759048686SKristof Provost tbl->pfrts_bytes[pfr_dir][pfr_op] = 1388f92c21a2SMateusz Guzik pfr_kstate_counter_fetch( 1389f92c21a2SMateusz Guzik &p->pfrkt_bytes[pfr_dir][pfr_op]); 139059048686SKristof Provost } 139159048686SKristof Provost } 1392f92c21a2SMateusz Guzik tbl->pfrts_match = pfr_kstate_counter_fetch(&p->pfrkt_match); 1393f92c21a2SMateusz Guzik tbl->pfrts_nomatch = pfr_kstate_counter_fetch(&p->pfrkt_nomatch); 139459048686SKristof Provost tbl->pfrts_tzero = p->pfrkt_tzero; 139559048686SKristof Provost tbl->pfrts_cnt = p->pfrkt_cnt; 139659048686SKristof Provost for (pfr_op = 0; pfr_op < PFR_REFCNT_MAX; pfr_op++) 139759048686SKristof Provost tbl->pfrts_refcnt[pfr_op] = p->pfrkt_refcnt[pfr_op]; 139859048686SKristof Provost tbl++; 13993b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 14003b3a8eb9SGleb Smirnoff } 14013b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_CLSTATS) 14023b3a8eb9SGleb Smirnoff pfr_clstats_ktables(&workq, tzero, 14033b3a8eb9SGleb Smirnoff flags & PFR_FLAG_ADDRSTOO); 14043b3a8eb9SGleb Smirnoff 14053b3a8eb9SGleb Smirnoff KASSERT(n == 0, ("%s: corruption detected (%d)", __func__, n)); 14063b3a8eb9SGleb Smirnoff 14073b3a8eb9SGleb Smirnoff *size = nn; 14083b3a8eb9SGleb Smirnoff return (0); 14093b3a8eb9SGleb Smirnoff } 14103b3a8eb9SGleb Smirnoff 14113b3a8eb9SGleb Smirnoff int 14123b3a8eb9SGleb Smirnoff pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) 14133b3a8eb9SGleb Smirnoff { 14143b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 14153b3a8eb9SGleb Smirnoff struct pfr_ktable *p, key; 14163b3a8eb9SGleb Smirnoff int i, xzero = 0; 14177e7f8800SKristof Provost time_t tzero = time_second; 14183b3a8eb9SGleb Smirnoff 14193b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ADDRSTOO); 14203b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 14213b3a8eb9SGleb Smirnoff for (i = 0; i < size; i++) { 14223b3a8eb9SGleb Smirnoff bcopy(tbl + i, &key.pfrkt_t, sizeof(key.pfrkt_t)); 14233b3a8eb9SGleb Smirnoff if (pfr_validate_table(&key.pfrkt_t, 0, 0)) 14243b3a8eb9SGleb Smirnoff return (EINVAL); 14251e9e3741SMarko Zec p = RB_FIND(pfr_ktablehead, &V_pfr_ktables, &key); 14263b3a8eb9SGleb Smirnoff if (p != NULL) { 14273b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 14283b3a8eb9SGleb Smirnoff xzero++; 14293b3a8eb9SGleb Smirnoff } 14303b3a8eb9SGleb Smirnoff } 14313b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 14323b3a8eb9SGleb Smirnoff pfr_clstats_ktables(&workq, tzero, flags & PFR_FLAG_ADDRSTOO); 14333b3a8eb9SGleb Smirnoff if (nzero != NULL) 14343b3a8eb9SGleb Smirnoff *nzero = xzero; 14353b3a8eb9SGleb Smirnoff return (0); 14363b3a8eb9SGleb Smirnoff } 14373b3a8eb9SGleb Smirnoff 14383b3a8eb9SGleb Smirnoff int 14393b3a8eb9SGleb Smirnoff pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag, 14403b3a8eb9SGleb Smirnoff int *nchange, int *ndel, int flags) 14413b3a8eb9SGleb Smirnoff { 14423b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 14433b3a8eb9SGleb Smirnoff struct pfr_ktable *p, *q, key; 14443b3a8eb9SGleb Smirnoff int i, xchange = 0, xdel = 0; 14453b3a8eb9SGleb Smirnoff 14463b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 14473b3a8eb9SGleb Smirnoff if ((setflag & ~PFR_TFLAG_USRMASK) || 14483b3a8eb9SGleb Smirnoff (clrflag & ~PFR_TFLAG_USRMASK) || 14493b3a8eb9SGleb Smirnoff (setflag & clrflag)) 14503b3a8eb9SGleb Smirnoff return (EINVAL); 14513b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 14523b3a8eb9SGleb Smirnoff for (i = 0; i < size; i++) { 14533b3a8eb9SGleb Smirnoff bcopy(tbl + i, &key.pfrkt_t, sizeof(key.pfrkt_t)); 14543b3a8eb9SGleb Smirnoff if (pfr_validate_table(&key.pfrkt_t, 0, 14553b3a8eb9SGleb Smirnoff flags & PFR_FLAG_USERIOCTL)) 14563b3a8eb9SGleb Smirnoff return (EINVAL); 14571e9e3741SMarko Zec p = RB_FIND(pfr_ktablehead, &V_pfr_ktables, &key); 14583b3a8eb9SGleb Smirnoff if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { 14593b3a8eb9SGleb Smirnoff p->pfrkt_nflags = (p->pfrkt_flags | setflag) & 14603b3a8eb9SGleb Smirnoff ~clrflag; 14613b3a8eb9SGleb Smirnoff if (p->pfrkt_nflags == p->pfrkt_flags) 14623b3a8eb9SGleb Smirnoff goto _skip; 14633b3a8eb9SGleb Smirnoff SLIST_FOREACH(q, &workq, pfrkt_workq) 14643b3a8eb9SGleb Smirnoff if (!pfr_ktable_compare(p, q)) 14653b3a8eb9SGleb Smirnoff goto _skip; 14663b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 14673b3a8eb9SGleb Smirnoff if ((p->pfrkt_flags & PFR_TFLAG_PERSIST) && 14683b3a8eb9SGleb Smirnoff (clrflag & PFR_TFLAG_PERSIST) && 14693b3a8eb9SGleb Smirnoff !(p->pfrkt_flags & PFR_TFLAG_REFERENCED)) 14703b3a8eb9SGleb Smirnoff xdel++; 14713b3a8eb9SGleb Smirnoff else 14723b3a8eb9SGleb Smirnoff xchange++; 14733b3a8eb9SGleb Smirnoff } 14743b3a8eb9SGleb Smirnoff _skip: 14753b3a8eb9SGleb Smirnoff ; 14763b3a8eb9SGleb Smirnoff } 14773b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) 14783b3a8eb9SGleb Smirnoff pfr_setflags_ktables(&workq); 14793b3a8eb9SGleb Smirnoff if (nchange != NULL) 14803b3a8eb9SGleb Smirnoff *nchange = xchange; 14813b3a8eb9SGleb Smirnoff if (ndel != NULL) 14823b3a8eb9SGleb Smirnoff *ndel = xdel; 14833b3a8eb9SGleb Smirnoff return (0); 14843b3a8eb9SGleb Smirnoff } 14853b3a8eb9SGleb Smirnoff 14863b3a8eb9SGleb Smirnoff int 14873b3a8eb9SGleb Smirnoff pfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags) 14883b3a8eb9SGleb Smirnoff { 14893b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 14903b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 1491e86bddeaSKristof Provost struct pf_kruleset *rs; 14923b3a8eb9SGleb Smirnoff int xdel = 0; 14933b3a8eb9SGleb Smirnoff 14943b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 1495e86bddeaSKristof Provost rs = pf_find_or_create_kruleset(trs->pfrt_anchor); 14963b3a8eb9SGleb Smirnoff if (rs == NULL) 14973b3a8eb9SGleb Smirnoff return (ENOMEM); 14983b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 14991e9e3741SMarko Zec RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { 15003b3a8eb9SGleb Smirnoff if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || 15013b3a8eb9SGleb Smirnoff pfr_skip_table(trs, p, 0)) 15023b3a8eb9SGleb Smirnoff continue; 15033b3a8eb9SGleb Smirnoff p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE; 15043b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 15053b3a8eb9SGleb Smirnoff xdel++; 15063b3a8eb9SGleb Smirnoff } 15073b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 15083b3a8eb9SGleb Smirnoff pfr_setflags_ktables(&workq); 15093b3a8eb9SGleb Smirnoff if (ticket != NULL) 15103b3a8eb9SGleb Smirnoff *ticket = ++rs->tticket; 15113b3a8eb9SGleb Smirnoff rs->topen = 1; 15123b3a8eb9SGleb Smirnoff } else 1513e86bddeaSKristof Provost pf_remove_if_empty_kruleset(rs); 15143b3a8eb9SGleb Smirnoff if (ndel != NULL) 15153b3a8eb9SGleb Smirnoff *ndel = xdel; 15163b3a8eb9SGleb Smirnoff return (0); 15173b3a8eb9SGleb Smirnoff } 15183b3a8eb9SGleb Smirnoff 15193b3a8eb9SGleb Smirnoff int 15203b3a8eb9SGleb Smirnoff pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, 15213b3a8eb9SGleb Smirnoff int *nadd, int *naddr, u_int32_t ticket, int flags) 15223b3a8eb9SGleb Smirnoff { 15233b3a8eb9SGleb Smirnoff struct pfr_ktableworkq tableq; 15243b3a8eb9SGleb Smirnoff struct pfr_kentryworkq addrq; 15253b3a8eb9SGleb Smirnoff struct pfr_ktable *kt, *rt, *shadow, key; 15263b3a8eb9SGleb Smirnoff struct pfr_kentry *p; 15273b3a8eb9SGleb Smirnoff struct pfr_addr *ad; 1528e86bddeaSKristof Provost struct pf_kruleset *rs; 15293b3a8eb9SGleb Smirnoff int i, rv, xadd = 0, xaddr = 0; 15303b3a8eb9SGleb Smirnoff 15313b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 15323b3a8eb9SGleb Smirnoff 15333b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ADDRSTOO); 15343b3a8eb9SGleb Smirnoff if (size && !(flags & PFR_FLAG_ADDRSTOO)) 15353b3a8eb9SGleb Smirnoff return (EINVAL); 15363b3a8eb9SGleb Smirnoff if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK, 15373b3a8eb9SGleb Smirnoff flags & PFR_FLAG_USERIOCTL)) 15383b3a8eb9SGleb Smirnoff return (EINVAL); 1539e86bddeaSKristof Provost rs = pf_find_kruleset(tbl->pfrt_anchor); 15403b3a8eb9SGleb Smirnoff if (rs == NULL || !rs->topen || ticket != rs->tticket) 15413b3a8eb9SGleb Smirnoff return (EBUSY); 15423b3a8eb9SGleb Smirnoff tbl->pfrt_flags |= PFR_TFLAG_INACTIVE; 15433b3a8eb9SGleb Smirnoff SLIST_INIT(&tableq); 15441e9e3741SMarko Zec kt = RB_FIND(pfr_ktablehead, &V_pfr_ktables, (struct pfr_ktable *)tbl); 15453b3a8eb9SGleb Smirnoff if (kt == NULL) { 15463b3a8eb9SGleb Smirnoff kt = pfr_create_ktable(tbl, 0, 1); 15473b3a8eb9SGleb Smirnoff if (kt == NULL) 15483b3a8eb9SGleb Smirnoff return (ENOMEM); 15493b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&tableq, kt, pfrkt_workq); 15503b3a8eb9SGleb Smirnoff xadd++; 15513b3a8eb9SGleb Smirnoff if (!tbl->pfrt_anchor[0]) 15523b3a8eb9SGleb Smirnoff goto _skip; 15533b3a8eb9SGleb Smirnoff 15543b3a8eb9SGleb Smirnoff /* find or create root table */ 15553b3a8eb9SGleb Smirnoff bzero(&key, sizeof(key)); 15563b3a8eb9SGleb Smirnoff strlcpy(key.pfrkt_name, tbl->pfrt_name, sizeof(key.pfrkt_name)); 15571e9e3741SMarko Zec rt = RB_FIND(pfr_ktablehead, &V_pfr_ktables, &key); 15583b3a8eb9SGleb Smirnoff if (rt != NULL) { 15593b3a8eb9SGleb Smirnoff kt->pfrkt_root = rt; 15603b3a8eb9SGleb Smirnoff goto _skip; 15613b3a8eb9SGleb Smirnoff } 15623b3a8eb9SGleb Smirnoff rt = pfr_create_ktable(&key.pfrkt_t, 0, 1); 15633b3a8eb9SGleb Smirnoff if (rt == NULL) { 15643b3a8eb9SGleb Smirnoff pfr_destroy_ktables(&tableq, 0); 15653b3a8eb9SGleb Smirnoff return (ENOMEM); 15663b3a8eb9SGleb Smirnoff } 15673b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&tableq, rt, pfrkt_workq); 15683b3a8eb9SGleb Smirnoff kt->pfrkt_root = rt; 15693b3a8eb9SGleb Smirnoff } else if (!(kt->pfrkt_flags & PFR_TFLAG_INACTIVE)) 15703b3a8eb9SGleb Smirnoff xadd++; 15713b3a8eb9SGleb Smirnoff _skip: 15723b3a8eb9SGleb Smirnoff shadow = pfr_create_ktable(tbl, 0, 0); 15733b3a8eb9SGleb Smirnoff if (shadow == NULL) { 15743b3a8eb9SGleb Smirnoff pfr_destroy_ktables(&tableq, 0); 15753b3a8eb9SGleb Smirnoff return (ENOMEM); 15763b3a8eb9SGleb Smirnoff } 15773b3a8eb9SGleb Smirnoff SLIST_INIT(&addrq); 15783b3a8eb9SGleb Smirnoff for (i = 0, ad = addr; i < size; i++, ad++) { 15793b3a8eb9SGleb Smirnoff if (pfr_validate_addr(ad)) 15803b3a8eb9SGleb Smirnoff senderr(EINVAL); 15813b3a8eb9SGleb Smirnoff if (pfr_lookup_addr(shadow, ad, 1) != NULL) 15823b3a8eb9SGleb Smirnoff continue; 158321121f9bSMark Johnston p = pfr_create_kentry(ad, 158421121f9bSMark Johnston (shadow->pfrkt_flags & PFR_TFLAG_COUNTERS) != 0); 15853b3a8eb9SGleb Smirnoff if (p == NULL) 15863b3a8eb9SGleb Smirnoff senderr(ENOMEM); 15873b3a8eb9SGleb Smirnoff if (pfr_route_kentry(shadow, p)) { 15883b3a8eb9SGleb Smirnoff pfr_destroy_kentry(p); 15893b3a8eb9SGleb Smirnoff continue; 15903b3a8eb9SGleb Smirnoff } 15913b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&addrq, p, pfrke_workq); 15923b3a8eb9SGleb Smirnoff xaddr++; 15933b3a8eb9SGleb Smirnoff } 15943b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 15953b3a8eb9SGleb Smirnoff if (kt->pfrkt_shadow != NULL) 15963b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt->pfrkt_shadow, 1); 15973b3a8eb9SGleb Smirnoff kt->pfrkt_flags |= PFR_TFLAG_INACTIVE; 15983b3a8eb9SGleb Smirnoff pfr_insert_ktables(&tableq); 15993b3a8eb9SGleb Smirnoff shadow->pfrkt_cnt = (flags & PFR_FLAG_ADDRSTOO) ? 16003b3a8eb9SGleb Smirnoff xaddr : NO_ADDRESSES; 16013b3a8eb9SGleb Smirnoff kt->pfrkt_shadow = shadow; 16023b3a8eb9SGleb Smirnoff } else { 16033b3a8eb9SGleb Smirnoff pfr_clean_node_mask(shadow, &addrq); 16043b3a8eb9SGleb Smirnoff pfr_destroy_ktable(shadow, 0); 16053b3a8eb9SGleb Smirnoff pfr_destroy_ktables(&tableq, 0); 16063b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&addrq); 16073b3a8eb9SGleb Smirnoff } 16083b3a8eb9SGleb Smirnoff if (nadd != NULL) 16093b3a8eb9SGleb Smirnoff *nadd = xadd; 16103b3a8eb9SGleb Smirnoff if (naddr != NULL) 16113b3a8eb9SGleb Smirnoff *naddr = xaddr; 16123b3a8eb9SGleb Smirnoff return (0); 16133b3a8eb9SGleb Smirnoff _bad: 16143b3a8eb9SGleb Smirnoff pfr_destroy_ktable(shadow, 0); 16153b3a8eb9SGleb Smirnoff pfr_destroy_ktables(&tableq, 0); 16163b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&addrq); 16173b3a8eb9SGleb Smirnoff return (rv); 16183b3a8eb9SGleb Smirnoff } 16193b3a8eb9SGleb Smirnoff 16203b3a8eb9SGleb Smirnoff int 16213b3a8eb9SGleb Smirnoff pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags) 16223b3a8eb9SGleb Smirnoff { 16233b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 16243b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 1625e86bddeaSKristof Provost struct pf_kruleset *rs; 16263b3a8eb9SGleb Smirnoff int xdel = 0; 16273b3a8eb9SGleb Smirnoff 16283b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 16293b3a8eb9SGleb Smirnoff 16303b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 1631e86bddeaSKristof Provost rs = pf_find_kruleset(trs->pfrt_anchor); 16323b3a8eb9SGleb Smirnoff if (rs == NULL || !rs->topen || ticket != rs->tticket) 16333b3a8eb9SGleb Smirnoff return (0); 16343b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 16351e9e3741SMarko Zec RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { 16363b3a8eb9SGleb Smirnoff if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || 16373b3a8eb9SGleb Smirnoff pfr_skip_table(trs, p, 0)) 16383b3a8eb9SGleb Smirnoff continue; 16393b3a8eb9SGleb Smirnoff p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE; 16403b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 16413b3a8eb9SGleb Smirnoff xdel++; 16423b3a8eb9SGleb Smirnoff } 16433b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 16443b3a8eb9SGleb Smirnoff pfr_setflags_ktables(&workq); 16453b3a8eb9SGleb Smirnoff rs->topen = 0; 1646e86bddeaSKristof Provost pf_remove_if_empty_kruleset(rs); 16473b3a8eb9SGleb Smirnoff } 16483b3a8eb9SGleb Smirnoff if (ndel != NULL) 16493b3a8eb9SGleb Smirnoff *ndel = xdel; 16503b3a8eb9SGleb Smirnoff return (0); 16513b3a8eb9SGleb Smirnoff } 16523b3a8eb9SGleb Smirnoff 16533b3a8eb9SGleb Smirnoff int 16543b3a8eb9SGleb Smirnoff pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd, 16553b3a8eb9SGleb Smirnoff int *nchange, int flags) 16563b3a8eb9SGleb Smirnoff { 16573b3a8eb9SGleb Smirnoff struct pfr_ktable *p, *q; 16583b3a8eb9SGleb Smirnoff struct pfr_ktableworkq workq; 1659e86bddeaSKristof Provost struct pf_kruleset *rs; 16603b3a8eb9SGleb Smirnoff int xadd = 0, xchange = 0; 16617e7f8800SKristof Provost time_t tzero = time_second; 16623b3a8eb9SGleb Smirnoff 16633b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 16643b3a8eb9SGleb Smirnoff 16653b3a8eb9SGleb Smirnoff ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); 1666e86bddeaSKristof Provost rs = pf_find_kruleset(trs->pfrt_anchor); 16673b3a8eb9SGleb Smirnoff if (rs == NULL || !rs->topen || ticket != rs->tticket) 16683b3a8eb9SGleb Smirnoff return (EBUSY); 16693b3a8eb9SGleb Smirnoff 16703b3a8eb9SGleb Smirnoff SLIST_INIT(&workq); 16711e9e3741SMarko Zec RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { 16723b3a8eb9SGleb Smirnoff if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || 16733b3a8eb9SGleb Smirnoff pfr_skip_table(trs, p, 0)) 16743b3a8eb9SGleb Smirnoff continue; 16753b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 16763b3a8eb9SGleb Smirnoff if (p->pfrkt_flags & PFR_TFLAG_ACTIVE) 16773b3a8eb9SGleb Smirnoff xchange++; 16783b3a8eb9SGleb Smirnoff else 16793b3a8eb9SGleb Smirnoff xadd++; 16803b3a8eb9SGleb Smirnoff } 16813b3a8eb9SGleb Smirnoff 16823b3a8eb9SGleb Smirnoff if (!(flags & PFR_FLAG_DUMMY)) { 16833b3a8eb9SGleb Smirnoff for (p = SLIST_FIRST(&workq); p != NULL; p = q) { 16843b3a8eb9SGleb Smirnoff q = SLIST_NEXT(p, pfrkt_workq); 16853b3a8eb9SGleb Smirnoff pfr_commit_ktable(p, tzero); 16863b3a8eb9SGleb Smirnoff } 16873b3a8eb9SGleb Smirnoff rs->topen = 0; 1688e86bddeaSKristof Provost pf_remove_if_empty_kruleset(rs); 16893b3a8eb9SGleb Smirnoff } 16903b3a8eb9SGleb Smirnoff if (nadd != NULL) 16913b3a8eb9SGleb Smirnoff *nadd = xadd; 16923b3a8eb9SGleb Smirnoff if (nchange != NULL) 16933b3a8eb9SGleb Smirnoff *nchange = xchange; 16943b3a8eb9SGleb Smirnoff 16953b3a8eb9SGleb Smirnoff return (0); 16963b3a8eb9SGleb Smirnoff } 16973b3a8eb9SGleb Smirnoff 16983b3a8eb9SGleb Smirnoff static void 16997e7f8800SKristof Provost pfr_commit_ktable(struct pfr_ktable *kt, time_t tzero) 17003b3a8eb9SGleb Smirnoff { 1701e6aed06fSMark Johnston counter_u64_t *pkc, *qkc; 17023b3a8eb9SGleb Smirnoff struct pfr_ktable *shadow = kt->pfrkt_shadow; 17033b3a8eb9SGleb Smirnoff int nflags; 17043b3a8eb9SGleb Smirnoff 17053b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 17063b3a8eb9SGleb Smirnoff 17073b3a8eb9SGleb Smirnoff if (shadow->pfrkt_cnt == NO_ADDRESSES) { 17083b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 17093b3a8eb9SGleb Smirnoff pfr_clstats_ktable(kt, tzero, 1); 17103b3a8eb9SGleb Smirnoff } else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) { 17113b3a8eb9SGleb Smirnoff /* kt might contain addresses */ 17123b3a8eb9SGleb Smirnoff struct pfr_kentryworkq addrq, addq, changeq, delq, garbageq; 17133b3a8eb9SGleb Smirnoff struct pfr_kentry *p, *q, *next; 17143b3a8eb9SGleb Smirnoff struct pfr_addr ad; 17153b3a8eb9SGleb Smirnoff 17163b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(shadow, &addrq, NULL, 0); 17173b3a8eb9SGleb Smirnoff pfr_mark_addrs(kt); 17183b3a8eb9SGleb Smirnoff SLIST_INIT(&addq); 17193b3a8eb9SGleb Smirnoff SLIST_INIT(&changeq); 17203b3a8eb9SGleb Smirnoff SLIST_INIT(&delq); 17213b3a8eb9SGleb Smirnoff SLIST_INIT(&garbageq); 17223b3a8eb9SGleb Smirnoff pfr_clean_node_mask(shadow, &addrq); 1723e6aed06fSMark Johnston SLIST_FOREACH_SAFE(p, &addrq, pfrke_workq, next) { 17243b3a8eb9SGleb Smirnoff pfr_copyout_addr(&ad, p); 17253b3a8eb9SGleb Smirnoff q = pfr_lookup_addr(kt, &ad, 1); 17263b3a8eb9SGleb Smirnoff if (q != NULL) { 17273b3a8eb9SGleb Smirnoff if (q->pfrke_not != p->pfrke_not) 17283b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&changeq, q, 17293b3a8eb9SGleb Smirnoff pfrke_workq); 1730e6aed06fSMark Johnston pkc = &p->pfrke_counters.pfrkc_counters; 1731e6aed06fSMark Johnston qkc = &q->pfrke_counters.pfrkc_counters; 1732e6aed06fSMark Johnston if ((*pkc == NULL) != (*qkc == NULL)) 1733e6aed06fSMark Johnston SWAP(counter_u64_t, *pkc, *qkc); 17343b3a8eb9SGleb Smirnoff q->pfrke_mark = 1; 17353b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq); 17363b3a8eb9SGleb Smirnoff } else { 173759048686SKristof Provost p->pfrke_counters.pfrkc_tzero = tzero; 17383b3a8eb9SGleb Smirnoff SLIST_INSERT_HEAD(&addq, p, pfrke_workq); 17393b3a8eb9SGleb Smirnoff } 17403b3a8eb9SGleb Smirnoff } 17413b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &delq, NULL, ENQUEUE_UNMARKED_ONLY); 17423b3a8eb9SGleb Smirnoff pfr_insert_kentries(kt, &addq, tzero); 17433b3a8eb9SGleb Smirnoff pfr_remove_kentries(kt, &delq); 174421121f9bSMark Johnston pfr_clstats_kentries(kt, &changeq, tzero, INVERT_NEG_FLAG); 17453b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&garbageq); 17463b3a8eb9SGleb Smirnoff } else { 17473b3a8eb9SGleb Smirnoff /* kt cannot contain addresses */ 17483b3a8eb9SGleb Smirnoff SWAP(struct radix_node_head *, kt->pfrkt_ip4, 17493b3a8eb9SGleb Smirnoff shadow->pfrkt_ip4); 17503b3a8eb9SGleb Smirnoff SWAP(struct radix_node_head *, kt->pfrkt_ip6, 17513b3a8eb9SGleb Smirnoff shadow->pfrkt_ip6); 17523b3a8eb9SGleb Smirnoff SWAP(int, kt->pfrkt_cnt, shadow->pfrkt_cnt); 17533b3a8eb9SGleb Smirnoff pfr_clstats_ktable(kt, tzero, 1); 17543b3a8eb9SGleb Smirnoff } 17553b3a8eb9SGleb Smirnoff nflags = ((shadow->pfrkt_flags & PFR_TFLAG_USRMASK) | 17563b3a8eb9SGleb Smirnoff (kt->pfrkt_flags & PFR_TFLAG_SETMASK) | PFR_TFLAG_ACTIVE) 17573b3a8eb9SGleb Smirnoff & ~PFR_TFLAG_INACTIVE; 17583b3a8eb9SGleb Smirnoff pfr_destroy_ktable(shadow, 0); 17593b3a8eb9SGleb Smirnoff kt->pfrkt_shadow = NULL; 17603b3a8eb9SGleb Smirnoff pfr_setflags_ktable(kt, nflags); 17613b3a8eb9SGleb Smirnoff } 17623b3a8eb9SGleb Smirnoff 17633b3a8eb9SGleb Smirnoff static int 17643b3a8eb9SGleb Smirnoff pfr_validate_table(struct pfr_table *tbl, int allowedflags, int no_reserved) 17653b3a8eb9SGleb Smirnoff { 17663b3a8eb9SGleb Smirnoff int i; 17673b3a8eb9SGleb Smirnoff 17683b3a8eb9SGleb Smirnoff if (!tbl->pfrt_name[0]) 17693b3a8eb9SGleb Smirnoff return (-1); 17703b3a8eb9SGleb Smirnoff if (no_reserved && !strcmp(tbl->pfrt_anchor, PF_RESERVED_ANCHOR)) 17713b3a8eb9SGleb Smirnoff return (-1); 17723b3a8eb9SGleb Smirnoff if (tbl->pfrt_name[PF_TABLE_NAME_SIZE-1]) 17733b3a8eb9SGleb Smirnoff return (-1); 17743b3a8eb9SGleb Smirnoff for (i = strlen(tbl->pfrt_name); i < PF_TABLE_NAME_SIZE; i++) 17753b3a8eb9SGleb Smirnoff if (tbl->pfrt_name[i]) 17763b3a8eb9SGleb Smirnoff return (-1); 17773b3a8eb9SGleb Smirnoff if (pfr_fix_anchor(tbl->pfrt_anchor)) 17783b3a8eb9SGleb Smirnoff return (-1); 17793b3a8eb9SGleb Smirnoff if (tbl->pfrt_flags & ~allowedflags) 17803b3a8eb9SGleb Smirnoff return (-1); 17813b3a8eb9SGleb Smirnoff return (0); 17823b3a8eb9SGleb Smirnoff } 17833b3a8eb9SGleb Smirnoff 17843b3a8eb9SGleb Smirnoff /* 17853b3a8eb9SGleb Smirnoff * Rewrite anchors referenced by tables to remove slashes 17863b3a8eb9SGleb Smirnoff * and check for validity. 17873b3a8eb9SGleb Smirnoff */ 17883b3a8eb9SGleb Smirnoff static int 17893b3a8eb9SGleb Smirnoff pfr_fix_anchor(char *anchor) 17903b3a8eb9SGleb Smirnoff { 17913b3a8eb9SGleb Smirnoff size_t siz = MAXPATHLEN; 17923b3a8eb9SGleb Smirnoff int i; 17933b3a8eb9SGleb Smirnoff 17943b3a8eb9SGleb Smirnoff if (anchor[0] == '/') { 17953b3a8eb9SGleb Smirnoff char *path; 17963b3a8eb9SGleb Smirnoff int off; 17973b3a8eb9SGleb Smirnoff 17983b3a8eb9SGleb Smirnoff path = anchor; 17993b3a8eb9SGleb Smirnoff off = 1; 18003b3a8eb9SGleb Smirnoff while (*++path == '/') 18013b3a8eb9SGleb Smirnoff off++; 18023b3a8eb9SGleb Smirnoff bcopy(path, anchor, siz - off); 18033b3a8eb9SGleb Smirnoff memset(anchor + siz - off, 0, off); 18043b3a8eb9SGleb Smirnoff } 18053b3a8eb9SGleb Smirnoff if (anchor[siz - 1]) 18063b3a8eb9SGleb Smirnoff return (-1); 18073b3a8eb9SGleb Smirnoff for (i = strlen(anchor); i < siz; i++) 18083b3a8eb9SGleb Smirnoff if (anchor[i]) 18093b3a8eb9SGleb Smirnoff return (-1); 18103b3a8eb9SGleb Smirnoff return (0); 18113b3a8eb9SGleb Smirnoff } 18123b3a8eb9SGleb Smirnoff 1813adfe2f6aSKristof Provost int 18143b3a8eb9SGleb Smirnoff pfr_table_count(struct pfr_table *filter, int flags) 18153b3a8eb9SGleb Smirnoff { 1816e86bddeaSKristof Provost struct pf_kruleset *rs; 18173b3a8eb9SGleb Smirnoff 18183b3a8eb9SGleb Smirnoff PF_RULES_ASSERT(); 18193b3a8eb9SGleb Smirnoff 18203b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_ALLRSETS) 18211e9e3741SMarko Zec return (V_pfr_ktable_cnt); 18223b3a8eb9SGleb Smirnoff if (filter->pfrt_anchor[0]) { 1823e86bddeaSKristof Provost rs = pf_find_kruleset(filter->pfrt_anchor); 18243b3a8eb9SGleb Smirnoff return ((rs != NULL) ? rs->tables : -1); 18253b3a8eb9SGleb Smirnoff } 18263b3a8eb9SGleb Smirnoff return (pf_main_ruleset.tables); 18273b3a8eb9SGleb Smirnoff } 18283b3a8eb9SGleb Smirnoff 18293b3a8eb9SGleb Smirnoff static int 18303b3a8eb9SGleb Smirnoff pfr_skip_table(struct pfr_table *filter, struct pfr_ktable *kt, int flags) 18313b3a8eb9SGleb Smirnoff { 18323b3a8eb9SGleb Smirnoff if (flags & PFR_FLAG_ALLRSETS) 18333b3a8eb9SGleb Smirnoff return (0); 18343b3a8eb9SGleb Smirnoff if (strcmp(filter->pfrt_anchor, kt->pfrkt_anchor)) 18353b3a8eb9SGleb Smirnoff return (1); 18363b3a8eb9SGleb Smirnoff return (0); 18373b3a8eb9SGleb Smirnoff } 18383b3a8eb9SGleb Smirnoff 18393b3a8eb9SGleb Smirnoff static void 18403b3a8eb9SGleb Smirnoff pfr_insert_ktables(struct pfr_ktableworkq *workq) 18413b3a8eb9SGleb Smirnoff { 18423b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 18433b3a8eb9SGleb Smirnoff 18443b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, workq, pfrkt_workq) 18453b3a8eb9SGleb Smirnoff pfr_insert_ktable(p); 18463b3a8eb9SGleb Smirnoff } 18473b3a8eb9SGleb Smirnoff 18483b3a8eb9SGleb Smirnoff static void 18493b3a8eb9SGleb Smirnoff pfr_insert_ktable(struct pfr_ktable *kt) 18503b3a8eb9SGleb Smirnoff { 18513b3a8eb9SGleb Smirnoff 18523b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 18533b3a8eb9SGleb Smirnoff 18541e9e3741SMarko Zec RB_INSERT(pfr_ktablehead, &V_pfr_ktables, kt); 18551e9e3741SMarko Zec V_pfr_ktable_cnt++; 18563b3a8eb9SGleb Smirnoff if (kt->pfrkt_root != NULL) 18573b3a8eb9SGleb Smirnoff if (!kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]++) 18583b3a8eb9SGleb Smirnoff pfr_setflags_ktable(kt->pfrkt_root, 18593b3a8eb9SGleb Smirnoff kt->pfrkt_root->pfrkt_flags|PFR_TFLAG_REFDANCHOR); 18603b3a8eb9SGleb Smirnoff } 18613b3a8eb9SGleb Smirnoff 18623b3a8eb9SGleb Smirnoff static void 18633b3a8eb9SGleb Smirnoff pfr_setflags_ktables(struct pfr_ktableworkq *workq) 18643b3a8eb9SGleb Smirnoff { 18653b3a8eb9SGleb Smirnoff struct pfr_ktable *p, *q; 18663b3a8eb9SGleb Smirnoff 18673b3a8eb9SGleb Smirnoff for (p = SLIST_FIRST(workq); p; p = q) { 18683b3a8eb9SGleb Smirnoff q = SLIST_NEXT(p, pfrkt_workq); 18693b3a8eb9SGleb Smirnoff pfr_setflags_ktable(p, p->pfrkt_nflags); 18703b3a8eb9SGleb Smirnoff } 18713b3a8eb9SGleb Smirnoff } 18723b3a8eb9SGleb Smirnoff 18733b3a8eb9SGleb Smirnoff static void 18743b3a8eb9SGleb Smirnoff pfr_setflags_ktable(struct pfr_ktable *kt, int newf) 18753b3a8eb9SGleb Smirnoff { 18763b3a8eb9SGleb Smirnoff struct pfr_kentryworkq addrq; 1877b21826bfSKristof Provost struct pfr_walktree w; 18783b3a8eb9SGleb Smirnoff 18793b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 18803b3a8eb9SGleb Smirnoff 18813b3a8eb9SGleb Smirnoff if (!(newf & PFR_TFLAG_REFERENCED) && 188287e4ca37SKristof Provost !(newf & PFR_TFLAG_REFDANCHOR) && 18833b3a8eb9SGleb Smirnoff !(newf & PFR_TFLAG_PERSIST)) 18843b3a8eb9SGleb Smirnoff newf &= ~PFR_TFLAG_ACTIVE; 18853b3a8eb9SGleb Smirnoff if (!(newf & PFR_TFLAG_ACTIVE)) 18863b3a8eb9SGleb Smirnoff newf &= ~PFR_TFLAG_USRMASK; 18873b3a8eb9SGleb Smirnoff if (!(newf & PFR_TFLAG_SETMASK)) { 18881e9e3741SMarko Zec RB_REMOVE(pfr_ktablehead, &V_pfr_ktables, kt); 18893b3a8eb9SGleb Smirnoff if (kt->pfrkt_root != NULL) 18903b3a8eb9SGleb Smirnoff if (!--kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]) 18913b3a8eb9SGleb Smirnoff pfr_setflags_ktable(kt->pfrkt_root, 18923b3a8eb9SGleb Smirnoff kt->pfrkt_root->pfrkt_flags & 18933b3a8eb9SGleb Smirnoff ~PFR_TFLAG_REFDANCHOR); 18943b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt, 1); 18951e9e3741SMarko Zec V_pfr_ktable_cnt--; 18963b3a8eb9SGleb Smirnoff return; 18973b3a8eb9SGleb Smirnoff } 1898b21826bfSKristof Provost if (newf & PFR_TFLAG_COUNTERS && ! (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) { 1899b21826bfSKristof Provost bzero(&w, sizeof(w)); 1900b21826bfSKristof Provost w.pfrw_op = PFRW_COUNTERS; 1901b21826bfSKristof Provost w.pfrw_flags |= PFR_TFLAG_COUNTERS; 1902b21826bfSKristof Provost kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); 1903b21826bfSKristof Provost kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, pfr_walktree, &w); 1904b21826bfSKristof Provost } 1905b21826bfSKristof Provost if (! (newf & PFR_TFLAG_COUNTERS) && (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) { 1906b21826bfSKristof Provost bzero(&w, sizeof(w)); 1907b21826bfSKristof Provost w.pfrw_op = PFRW_COUNTERS; 1908b21826bfSKristof Provost w.pfrw_flags |= 0; 1909b21826bfSKristof Provost kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); 1910b21826bfSKristof Provost kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, pfr_walktree, &w); 1911b21826bfSKristof Provost } 19123b3a8eb9SGleb Smirnoff if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) { 19133b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &addrq, NULL, 0); 19143b3a8eb9SGleb Smirnoff pfr_remove_kentries(kt, &addrq); 19153b3a8eb9SGleb Smirnoff } 19163b3a8eb9SGleb Smirnoff if (!(newf & PFR_TFLAG_INACTIVE) && kt->pfrkt_shadow != NULL) { 19173b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt->pfrkt_shadow, 1); 19183b3a8eb9SGleb Smirnoff kt->pfrkt_shadow = NULL; 19193b3a8eb9SGleb Smirnoff } 19203b3a8eb9SGleb Smirnoff kt->pfrkt_flags = newf; 19213b3a8eb9SGleb Smirnoff } 19223b3a8eb9SGleb Smirnoff 19233b3a8eb9SGleb Smirnoff static void 19247e7f8800SKristof Provost pfr_clstats_ktables(struct pfr_ktableworkq *workq, time_t tzero, int recurse) 19253b3a8eb9SGleb Smirnoff { 19263b3a8eb9SGleb Smirnoff struct pfr_ktable *p; 19273b3a8eb9SGleb Smirnoff 19283b3a8eb9SGleb Smirnoff SLIST_FOREACH(p, workq, pfrkt_workq) 19293b3a8eb9SGleb Smirnoff pfr_clstats_ktable(p, tzero, recurse); 19303b3a8eb9SGleb Smirnoff } 19313b3a8eb9SGleb Smirnoff 19323b3a8eb9SGleb Smirnoff static void 19337e7f8800SKristof Provost pfr_clstats_ktable(struct pfr_ktable *kt, time_t tzero, int recurse) 19343b3a8eb9SGleb Smirnoff { 19353b3a8eb9SGleb Smirnoff struct pfr_kentryworkq addrq; 193659048686SKristof Provost int pfr_dir, pfr_op; 19373b3a8eb9SGleb Smirnoff 1938dc1ab04eSMateusz Guzik MPASS(PF_TABLE_STATS_OWNED() || PF_RULES_WOWNED()); 1939dc1ab04eSMateusz Guzik 19403b3a8eb9SGleb Smirnoff if (recurse) { 19413b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &addrq, NULL, 0); 194221121f9bSMark Johnston pfr_clstats_kentries(kt, &addrq, tzero, 0); 19433b3a8eb9SGleb Smirnoff } 194459048686SKristof Provost for (pfr_dir = 0; pfr_dir < PFR_DIR_MAX; pfr_dir ++) { 194559048686SKristof Provost for (pfr_op = 0; pfr_op < PFR_OP_TABLE_MAX; pfr_op ++) { 1946f92c21a2SMateusz Guzik pfr_kstate_counter_zero(&kt->pfrkt_packets[pfr_dir][pfr_op]); 1947f92c21a2SMateusz Guzik pfr_kstate_counter_zero(&kt->pfrkt_bytes[pfr_dir][pfr_op]); 194859048686SKristof Provost } 194959048686SKristof Provost } 1950f92c21a2SMateusz Guzik pfr_kstate_counter_zero(&kt->pfrkt_match); 1951f92c21a2SMateusz Guzik pfr_kstate_counter_zero(&kt->pfrkt_nomatch); 19523b3a8eb9SGleb Smirnoff kt->pfrkt_tzero = tzero; 19533b3a8eb9SGleb Smirnoff } 19543b3a8eb9SGleb Smirnoff 19553b3a8eb9SGleb Smirnoff static struct pfr_ktable * 19567e7f8800SKristof Provost pfr_create_ktable(struct pfr_table *tbl, time_t tzero, int attachruleset) 19573b3a8eb9SGleb Smirnoff { 19583b3a8eb9SGleb Smirnoff struct pfr_ktable *kt; 1959e86bddeaSKristof Provost struct pf_kruleset *rs; 196059048686SKristof Provost int pfr_dir, pfr_op; 19613b3a8eb9SGleb Smirnoff 19623b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 19633b3a8eb9SGleb Smirnoff 19643b3a8eb9SGleb Smirnoff kt = malloc(sizeof(*kt), M_PFTABLE, M_NOWAIT|M_ZERO); 19653b3a8eb9SGleb Smirnoff if (kt == NULL) 19663b3a8eb9SGleb Smirnoff return (NULL); 19673b3a8eb9SGleb Smirnoff kt->pfrkt_t = *tbl; 19683b3a8eb9SGleb Smirnoff 19693b3a8eb9SGleb Smirnoff if (attachruleset) { 1970e86bddeaSKristof Provost rs = pf_find_or_create_kruleset(tbl->pfrt_anchor); 19713b3a8eb9SGleb Smirnoff if (!rs) { 19723b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt, 0); 19733b3a8eb9SGleb Smirnoff return (NULL); 19743b3a8eb9SGleb Smirnoff } 19753b3a8eb9SGleb Smirnoff kt->pfrkt_rs = rs; 19763b3a8eb9SGleb Smirnoff rs->tables++; 19773b3a8eb9SGleb Smirnoff } 19783b3a8eb9SGleb Smirnoff 197959048686SKristof Provost for (pfr_dir = 0; pfr_dir < PFR_DIR_MAX; pfr_dir ++) { 198059048686SKristof Provost for (pfr_op = 0; pfr_op < PFR_OP_TABLE_MAX; pfr_op ++) { 1981f92c21a2SMateusz Guzik if (pfr_kstate_counter_init( 1982f92c21a2SMateusz Guzik &kt->pfrkt_packets[pfr_dir][pfr_op], M_NOWAIT) != 0) { 198359048686SKristof Provost pfr_destroy_ktable(kt, 0); 198459048686SKristof Provost return (NULL); 198559048686SKristof Provost } 1986f92c21a2SMateusz Guzik if (pfr_kstate_counter_init( 1987f92c21a2SMateusz Guzik &kt->pfrkt_bytes[pfr_dir][pfr_op], M_NOWAIT) != 0) { 198859048686SKristof Provost pfr_destroy_ktable(kt, 0); 198959048686SKristof Provost return (NULL); 199059048686SKristof Provost } 199159048686SKristof Provost } 199259048686SKristof Provost } 1993f92c21a2SMateusz Guzik if (pfr_kstate_counter_init(&kt->pfrkt_match, M_NOWAIT) != 0) { 199459048686SKristof Provost pfr_destroy_ktable(kt, 0); 199559048686SKristof Provost return (NULL); 199659048686SKristof Provost } 199759048686SKristof Provost 1998f92c21a2SMateusz Guzik if (pfr_kstate_counter_init(&kt->pfrkt_nomatch, M_NOWAIT) != 0) { 199959048686SKristof Provost pfr_destroy_ktable(kt, 0); 200059048686SKristof Provost return (NULL); 200159048686SKristof Provost } 200259048686SKristof Provost 20033b3a8eb9SGleb Smirnoff if (!rn_inithead((void **)&kt->pfrkt_ip4, 20043b3a8eb9SGleb Smirnoff offsetof(struct sockaddr_in, sin_addr) * 8) || 20053b3a8eb9SGleb Smirnoff !rn_inithead((void **)&kt->pfrkt_ip6, 20063b3a8eb9SGleb Smirnoff offsetof(struct sockaddr_in6, sin6_addr) * 8)) { 20073b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt, 0); 20083b3a8eb9SGleb Smirnoff return (NULL); 20093b3a8eb9SGleb Smirnoff } 20103b3a8eb9SGleb Smirnoff kt->pfrkt_tzero = tzero; 20113b3a8eb9SGleb Smirnoff 20123b3a8eb9SGleb Smirnoff return (kt); 20133b3a8eb9SGleb Smirnoff } 20143b3a8eb9SGleb Smirnoff 20153b3a8eb9SGleb Smirnoff static void 20163b3a8eb9SGleb Smirnoff pfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr) 20173b3a8eb9SGleb Smirnoff { 20183b3a8eb9SGleb Smirnoff struct pfr_ktable *p, *q; 20193b3a8eb9SGleb Smirnoff 20203b3a8eb9SGleb Smirnoff for (p = SLIST_FIRST(workq); p; p = q) { 20213b3a8eb9SGleb Smirnoff q = SLIST_NEXT(p, pfrkt_workq); 20223b3a8eb9SGleb Smirnoff pfr_destroy_ktable(p, flushaddr); 20233b3a8eb9SGleb Smirnoff } 20243b3a8eb9SGleb Smirnoff } 20253b3a8eb9SGleb Smirnoff 20263b3a8eb9SGleb Smirnoff static void 20273b3a8eb9SGleb Smirnoff pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr) 20283b3a8eb9SGleb Smirnoff { 20293b3a8eb9SGleb Smirnoff struct pfr_kentryworkq addrq; 203059048686SKristof Provost int pfr_dir, pfr_op; 20313b3a8eb9SGleb Smirnoff 20323b3a8eb9SGleb Smirnoff if (flushaddr) { 20333b3a8eb9SGleb Smirnoff pfr_enqueue_addrs(kt, &addrq, NULL, 0); 20343b3a8eb9SGleb Smirnoff pfr_clean_node_mask(kt, &addrq); 20353b3a8eb9SGleb Smirnoff pfr_destroy_kentries(&addrq); 20363b3a8eb9SGleb Smirnoff } 203731f0d081SAlexander V. Chernikov if (kt->pfrkt_ip4 != NULL) 2038495a22b5SGleb Smirnoff rn_detachhead((void **)&kt->pfrkt_ip4); 203931f0d081SAlexander V. Chernikov if (kt->pfrkt_ip6 != NULL) 2040495a22b5SGleb Smirnoff rn_detachhead((void **)&kt->pfrkt_ip6); 20413b3a8eb9SGleb Smirnoff if (kt->pfrkt_shadow != NULL) 20423b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr); 20433b3a8eb9SGleb Smirnoff if (kt->pfrkt_rs != NULL) { 20443b3a8eb9SGleb Smirnoff kt->pfrkt_rs->tables--; 2045e86bddeaSKristof Provost pf_remove_if_empty_kruleset(kt->pfrkt_rs); 20463b3a8eb9SGleb Smirnoff } 204759048686SKristof Provost for (pfr_dir = 0; pfr_dir < PFR_DIR_MAX; pfr_dir ++) { 204859048686SKristof Provost for (pfr_op = 0; pfr_op < PFR_OP_TABLE_MAX; pfr_op ++) { 2049f92c21a2SMateusz Guzik pfr_kstate_counter_deinit(&kt->pfrkt_packets[pfr_dir][pfr_op]); 2050f92c21a2SMateusz Guzik pfr_kstate_counter_deinit(&kt->pfrkt_bytes[pfr_dir][pfr_op]); 205159048686SKristof Provost } 205259048686SKristof Provost } 2053f92c21a2SMateusz Guzik pfr_kstate_counter_deinit(&kt->pfrkt_match); 2054f92c21a2SMateusz Guzik pfr_kstate_counter_deinit(&kt->pfrkt_nomatch); 205559048686SKristof Provost 20563b3a8eb9SGleb Smirnoff free(kt, M_PFTABLE); 20573b3a8eb9SGleb Smirnoff } 20583b3a8eb9SGleb Smirnoff 20593b3a8eb9SGleb Smirnoff static int 20603b3a8eb9SGleb Smirnoff pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q) 20613b3a8eb9SGleb Smirnoff { 20623b3a8eb9SGleb Smirnoff int d; 20633b3a8eb9SGleb Smirnoff 20643b3a8eb9SGleb Smirnoff if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE))) 20653b3a8eb9SGleb Smirnoff return (d); 20663b3a8eb9SGleb Smirnoff return (strcmp(p->pfrkt_anchor, q->pfrkt_anchor)); 20673b3a8eb9SGleb Smirnoff } 20683b3a8eb9SGleb Smirnoff 20693b3a8eb9SGleb Smirnoff static struct pfr_ktable * 20703b3a8eb9SGleb Smirnoff pfr_lookup_table(struct pfr_table *tbl) 20713b3a8eb9SGleb Smirnoff { 20723b3a8eb9SGleb Smirnoff /* struct pfr_ktable start like a struct pfr_table */ 20731e9e3741SMarko Zec return (RB_FIND(pfr_ktablehead, &V_pfr_ktables, 20743b3a8eb9SGleb Smirnoff (struct pfr_ktable *)tbl)); 20753b3a8eb9SGleb Smirnoff } 20763b3a8eb9SGleb Smirnoff 20773b3a8eb9SGleb Smirnoff int 20783b3a8eb9SGleb Smirnoff pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) 20793b3a8eb9SGleb Smirnoff { 20803b3a8eb9SGleb Smirnoff struct pfr_kentry *ke = NULL; 20813b3a8eb9SGleb Smirnoff int match; 20823b3a8eb9SGleb Smirnoff 20833b3a8eb9SGleb Smirnoff PF_RULES_RASSERT(); 20843b3a8eb9SGleb Smirnoff 20853b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 20863b3a8eb9SGleb Smirnoff kt = kt->pfrkt_root; 20873b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 20883b3a8eb9SGleb Smirnoff return (0); 20893b3a8eb9SGleb Smirnoff 20903b3a8eb9SGleb Smirnoff switch (af) { 20913b3a8eb9SGleb Smirnoff #ifdef INET 20923b3a8eb9SGleb Smirnoff case AF_INET: 20933b3a8eb9SGleb Smirnoff { 20943b3a8eb9SGleb Smirnoff struct sockaddr_in sin; 20953b3a8eb9SGleb Smirnoff 20963b3a8eb9SGleb Smirnoff bzero(&sin, sizeof(sin)); 20973b3a8eb9SGleb Smirnoff sin.sin_len = sizeof(sin); 20983b3a8eb9SGleb Smirnoff sin.sin_family = AF_INET; 20993b3a8eb9SGleb Smirnoff sin.sin_addr.s_addr = a->addr32[0]; 210061eee0e2SAlexander V. Chernikov ke = (struct pfr_kentry *)rn_match(&sin, &kt->pfrkt_ip4->rh); 21013b3a8eb9SGleb Smirnoff if (ke && KENTRY_RNF_ROOT(ke)) 21023b3a8eb9SGleb Smirnoff ke = NULL; 21033b3a8eb9SGleb Smirnoff break; 21043b3a8eb9SGleb Smirnoff } 21053b3a8eb9SGleb Smirnoff #endif /* INET */ 21063b3a8eb9SGleb Smirnoff #ifdef INET6 21073b3a8eb9SGleb Smirnoff case AF_INET6: 21083b3a8eb9SGleb Smirnoff { 21093b3a8eb9SGleb Smirnoff struct sockaddr_in6 sin6; 21103b3a8eb9SGleb Smirnoff 21113b3a8eb9SGleb Smirnoff bzero(&sin6, sizeof(sin6)); 21123b3a8eb9SGleb Smirnoff sin6.sin6_len = sizeof(sin6); 21133b3a8eb9SGleb Smirnoff sin6.sin6_family = AF_INET6; 21143b3a8eb9SGleb Smirnoff bcopy(a, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); 211561eee0e2SAlexander V. Chernikov ke = (struct pfr_kentry *)rn_match(&sin6, &kt->pfrkt_ip6->rh); 21163b3a8eb9SGleb Smirnoff if (ke && KENTRY_RNF_ROOT(ke)) 21173b3a8eb9SGleb Smirnoff ke = NULL; 21183b3a8eb9SGleb Smirnoff break; 21193b3a8eb9SGleb Smirnoff } 21203b3a8eb9SGleb Smirnoff #endif /* INET6 */ 21217e51bc6cSKristof Provost default: 21227e51bc6cSKristof Provost unhandled_af(af); 21233b3a8eb9SGleb Smirnoff } 21243b3a8eb9SGleb Smirnoff match = (ke && !ke->pfrke_not); 21253b3a8eb9SGleb Smirnoff if (match) 2126f92c21a2SMateusz Guzik pfr_kstate_counter_add(&kt->pfrkt_match, 1); 21273b3a8eb9SGleb Smirnoff else 2128f92c21a2SMateusz Guzik pfr_kstate_counter_add(&kt->pfrkt_nomatch, 1); 21293b3a8eb9SGleb Smirnoff return (match); 21303b3a8eb9SGleb Smirnoff } 21313b3a8eb9SGleb Smirnoff 21323b3a8eb9SGleb Smirnoff void 21333b3a8eb9SGleb Smirnoff pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, 21343b3a8eb9SGleb Smirnoff u_int64_t len, int dir_out, int op_pass, int notrule) 21353b3a8eb9SGleb Smirnoff { 21363b3a8eb9SGleb Smirnoff struct pfr_kentry *ke = NULL; 21373b3a8eb9SGleb Smirnoff 21383b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 21393b3a8eb9SGleb Smirnoff kt = kt->pfrkt_root; 21403b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 21413b3a8eb9SGleb Smirnoff return; 21423b3a8eb9SGleb Smirnoff 21433b3a8eb9SGleb Smirnoff switch (af) { 21443b3a8eb9SGleb Smirnoff #ifdef INET 21453b3a8eb9SGleb Smirnoff case AF_INET: 21463b3a8eb9SGleb Smirnoff { 21473b3a8eb9SGleb Smirnoff struct sockaddr_in sin; 21483b3a8eb9SGleb Smirnoff 21497348c524SGleb Smirnoff bzero(&sin, sizeof(sin)); 21503b3a8eb9SGleb Smirnoff sin.sin_len = sizeof(sin); 21513b3a8eb9SGleb Smirnoff sin.sin_family = AF_INET; 21523b3a8eb9SGleb Smirnoff sin.sin_addr.s_addr = a->addr32[0]; 215361eee0e2SAlexander V. Chernikov ke = (struct pfr_kentry *)rn_match(&sin, &kt->pfrkt_ip4->rh); 21543b3a8eb9SGleb Smirnoff if (ke && KENTRY_RNF_ROOT(ke)) 21553b3a8eb9SGleb Smirnoff ke = NULL; 21563b3a8eb9SGleb Smirnoff break; 21573b3a8eb9SGleb Smirnoff } 21583b3a8eb9SGleb Smirnoff #endif /* INET */ 21593b3a8eb9SGleb Smirnoff #ifdef INET6 21603b3a8eb9SGleb Smirnoff case AF_INET6: 21613b3a8eb9SGleb Smirnoff { 21623b3a8eb9SGleb Smirnoff struct sockaddr_in6 sin6; 21633b3a8eb9SGleb Smirnoff 21647348c524SGleb Smirnoff bzero(&sin6, sizeof(sin6)); 21653b3a8eb9SGleb Smirnoff sin6.sin6_len = sizeof(sin6); 21663b3a8eb9SGleb Smirnoff sin6.sin6_family = AF_INET6; 21673b3a8eb9SGleb Smirnoff bcopy(a, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); 216861eee0e2SAlexander V. Chernikov ke = (struct pfr_kentry *)rn_match(&sin6, &kt->pfrkt_ip6->rh); 21693b3a8eb9SGleb Smirnoff if (ke && KENTRY_RNF_ROOT(ke)) 21703b3a8eb9SGleb Smirnoff ke = NULL; 21713b3a8eb9SGleb Smirnoff break; 21723b3a8eb9SGleb Smirnoff } 21733b3a8eb9SGleb Smirnoff #endif /* INET6 */ 21743b3a8eb9SGleb Smirnoff default: 21757e51bc6cSKristof Provost unhandled_af(af); 21763b3a8eb9SGleb Smirnoff } 21773b3a8eb9SGleb Smirnoff if ((ke == NULL || ke->pfrke_not) != notrule) { 21783b3a8eb9SGleb Smirnoff if (op_pass != PFR_OP_PASS) 2179032dff66SKristof Provost DPFPRINTF(PF_DEBUG_URGENT, 2180032dff66SKristof Provost ("pfr_update_stats: assertion failed.\n")); 21813b3a8eb9SGleb Smirnoff op_pass = PFR_OP_XPASS; 21823b3a8eb9SGleb Smirnoff } 2183f92c21a2SMateusz Guzik pfr_kstate_counter_add(&kt->pfrkt_packets[dir_out][op_pass], 1); 2184f92c21a2SMateusz Guzik pfr_kstate_counter_add(&kt->pfrkt_bytes[dir_out][op_pass], len); 21853b3a8eb9SGleb Smirnoff if (ke != NULL && op_pass != PFR_OP_XPASS && 21863b3a8eb9SGleb Smirnoff (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) { 2187c1be8399SMark Johnston counter_u64_add(pfr_kentry_counter(&ke->pfrke_counters, 2188c1be8399SMark Johnston dir_out, op_pass, PFR_TYPE_PACKETS), 1); 2189c1be8399SMark Johnston counter_u64_add(pfr_kentry_counter(&ke->pfrke_counters, 2190c1be8399SMark Johnston dir_out, op_pass, PFR_TYPE_BYTES), len); 21913b3a8eb9SGleb Smirnoff } 21923b3a8eb9SGleb Smirnoff } 21933b3a8eb9SGleb Smirnoff 21943b3a8eb9SGleb Smirnoff struct pfr_ktable * 2195812839e5SKristof Provost pfr_eth_attach_table(struct pf_keth_ruleset *rs, char *name) 2196812839e5SKristof Provost { 2197812839e5SKristof Provost struct pfr_ktable *kt, *rt; 2198812839e5SKristof Provost struct pfr_table tbl; 2199812839e5SKristof Provost struct pf_keth_anchor *ac = rs->anchor; 2200812839e5SKristof Provost 2201812839e5SKristof Provost PF_RULES_WASSERT(); 2202812839e5SKristof Provost 2203812839e5SKristof Provost bzero(&tbl, sizeof(tbl)); 2204812839e5SKristof Provost strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)); 2205812839e5SKristof Provost if (ac != NULL) 2206812839e5SKristof Provost strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor)); 2207812839e5SKristof Provost kt = pfr_lookup_table(&tbl); 2208812839e5SKristof Provost if (kt == NULL) { 2209812839e5SKristof Provost kt = pfr_create_ktable(&tbl, time_second, 1); 2210812839e5SKristof Provost if (kt == NULL) 2211812839e5SKristof Provost return (NULL); 2212812839e5SKristof Provost if (ac != NULL) { 2213812839e5SKristof Provost bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor)); 2214812839e5SKristof Provost rt = pfr_lookup_table(&tbl); 2215812839e5SKristof Provost if (rt == NULL) { 2216812839e5SKristof Provost rt = pfr_create_ktable(&tbl, 0, 1); 2217812839e5SKristof Provost if (rt == NULL) { 2218812839e5SKristof Provost pfr_destroy_ktable(kt, 0); 2219812839e5SKristof Provost return (NULL); 2220812839e5SKristof Provost } 2221812839e5SKristof Provost pfr_insert_ktable(rt); 2222812839e5SKristof Provost } 2223812839e5SKristof Provost kt->pfrkt_root = rt; 2224812839e5SKristof Provost } 2225812839e5SKristof Provost pfr_insert_ktable(kt); 2226812839e5SKristof Provost } 2227812839e5SKristof Provost if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++) 2228812839e5SKristof Provost pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED); 2229812839e5SKristof Provost return (kt); 2230812839e5SKristof Provost } 2231812839e5SKristof Provost 2232812839e5SKristof Provost struct pfr_ktable * 2233e86bddeaSKristof Provost pfr_attach_table(struct pf_kruleset *rs, char *name) 22343b3a8eb9SGleb Smirnoff { 22353b3a8eb9SGleb Smirnoff struct pfr_ktable *kt, *rt; 22363b3a8eb9SGleb Smirnoff struct pfr_table tbl; 2237e86bddeaSKristof Provost struct pf_kanchor *ac = rs->anchor; 22383b3a8eb9SGleb Smirnoff 22393b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 22403b3a8eb9SGleb Smirnoff 22413b3a8eb9SGleb Smirnoff bzero(&tbl, sizeof(tbl)); 22423b3a8eb9SGleb Smirnoff strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)); 22433b3a8eb9SGleb Smirnoff if (ac != NULL) 22443b3a8eb9SGleb Smirnoff strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor)); 22453b3a8eb9SGleb Smirnoff kt = pfr_lookup_table(&tbl); 22463b3a8eb9SGleb Smirnoff if (kt == NULL) { 22473b3a8eb9SGleb Smirnoff kt = pfr_create_ktable(&tbl, time_second, 1); 22483b3a8eb9SGleb Smirnoff if (kt == NULL) 22493b3a8eb9SGleb Smirnoff return (NULL); 22503b3a8eb9SGleb Smirnoff if (ac != NULL) { 22513b3a8eb9SGleb Smirnoff bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor)); 22523b3a8eb9SGleb Smirnoff rt = pfr_lookup_table(&tbl); 22533b3a8eb9SGleb Smirnoff if (rt == NULL) { 22543b3a8eb9SGleb Smirnoff rt = pfr_create_ktable(&tbl, 0, 1); 22553b3a8eb9SGleb Smirnoff if (rt == NULL) { 22563b3a8eb9SGleb Smirnoff pfr_destroy_ktable(kt, 0); 22573b3a8eb9SGleb Smirnoff return (NULL); 22583b3a8eb9SGleb Smirnoff } 22593b3a8eb9SGleb Smirnoff pfr_insert_ktable(rt); 22603b3a8eb9SGleb Smirnoff } 22613b3a8eb9SGleb Smirnoff kt->pfrkt_root = rt; 22623b3a8eb9SGleb Smirnoff } 22633b3a8eb9SGleb Smirnoff pfr_insert_ktable(kt); 22643b3a8eb9SGleb Smirnoff } 22653b3a8eb9SGleb Smirnoff if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++) 22663b3a8eb9SGleb Smirnoff pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED); 22673b3a8eb9SGleb Smirnoff return (kt); 22683b3a8eb9SGleb Smirnoff } 22693b3a8eb9SGleb Smirnoff 22703b3a8eb9SGleb Smirnoff void 22713b3a8eb9SGleb Smirnoff pfr_detach_table(struct pfr_ktable *kt) 22723b3a8eb9SGleb Smirnoff { 22733b3a8eb9SGleb Smirnoff 22743b3a8eb9SGleb Smirnoff PF_RULES_WASSERT(); 22753b3a8eb9SGleb Smirnoff KASSERT(kt->pfrkt_refcnt[PFR_REFCNT_RULE] > 0, ("%s: refcount %d\n", 22763b3a8eb9SGleb Smirnoff __func__, kt->pfrkt_refcnt[PFR_REFCNT_RULE])); 22773b3a8eb9SGleb Smirnoff 22783b3a8eb9SGleb Smirnoff if (!--kt->pfrkt_refcnt[PFR_REFCNT_RULE]) 22793b3a8eb9SGleb Smirnoff pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED); 22803b3a8eb9SGleb Smirnoff } 22813b3a8eb9SGleb Smirnoff 22823b3a8eb9SGleb Smirnoff int 22833b3a8eb9SGleb Smirnoff pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, 22847d381d0aSKristof Provost sa_family_t af, pf_addr_filter_func_t filter) 22853b3a8eb9SGleb Smirnoff { 228667b65598SKristof Provost struct pf_addr *addr, cur, mask, umask_addr; 22873b3a8eb9SGleb Smirnoff union sockaddr_union uaddr, umask; 22883b3a8eb9SGleb Smirnoff struct pfr_kentry *ke, *ke2 = NULL; 22897d0f8cd9SKristof Provost int startidx, idx = -1, loop = 0, use_counter = 0; 22903b3a8eb9SGleb Smirnoff 22918cceacc0SKristof Provost MPASS(pidx != NULL); 2292efc64d02SKristof Provost MPASS(counter != NULL); 22938cceacc0SKristof Provost 22943b3a8eb9SGleb Smirnoff switch (af) { 22953b3a8eb9SGleb Smirnoff case AF_INET: 22963b3a8eb9SGleb Smirnoff uaddr.sin.sin_len = sizeof(struct sockaddr_in); 22973b3a8eb9SGleb Smirnoff uaddr.sin.sin_family = AF_INET; 229867b65598SKristof Provost addr = (struct pf_addr *)&uaddr.sin.sin_addr; 22993b3a8eb9SGleb Smirnoff break; 23003b3a8eb9SGleb Smirnoff case AF_INET6: 23013b3a8eb9SGleb Smirnoff uaddr.sin6.sin6_len = sizeof(struct sockaddr_in6); 23023b3a8eb9SGleb Smirnoff uaddr.sin6.sin6_family = AF_INET6; 230367b65598SKristof Provost addr = (struct pf_addr *)&uaddr.sin6.sin6_addr; 23043b3a8eb9SGleb Smirnoff break; 23057e51bc6cSKristof Provost default: 23067e51bc6cSKristof Provost unhandled_af(af); 23073b3a8eb9SGleb Smirnoff } 23083b3a8eb9SGleb Smirnoff 23093b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 23103b3a8eb9SGleb Smirnoff kt = kt->pfrkt_root; 23113b3a8eb9SGleb Smirnoff if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 23123b3a8eb9SGleb Smirnoff return (-1); 23133b3a8eb9SGleb Smirnoff 23143b3a8eb9SGleb Smirnoff idx = *pidx; 2315d90854a6SKristof Provost if (idx < 0 || idx >= kt->pfrkt_cnt) 23163b3a8eb9SGleb Smirnoff idx = 0; 2317d90854a6SKristof Provost else if (counter != NULL) 2318d90854a6SKristof Provost use_counter = 1; 23197d0f8cd9SKristof Provost startidx = idx; 23203b3a8eb9SGleb Smirnoff 23213b3a8eb9SGleb Smirnoff _next_block: 23227d0f8cd9SKristof Provost if (loop && startidx == idx) { 2323f92c21a2SMateusz Guzik pfr_kstate_counter_add(&kt->pfrkt_nomatch, 1); 23243b3a8eb9SGleb Smirnoff return (1); 23253b3a8eb9SGleb Smirnoff } 23267d0f8cd9SKristof Provost 23277d0f8cd9SKristof Provost ke = pfr_kentry_byidx(kt, idx, af); 23287d0f8cd9SKristof Provost if (ke == NULL) { 23297d0f8cd9SKristof Provost /* we don't have this idx, try looping */ 23307d0f8cd9SKristof Provost if (loop || (ke = pfr_kentry_byidx(kt, 0, af)) == NULL) { 23317d0f8cd9SKristof Provost pfr_kstate_counter_add(&kt->pfrkt_nomatch, 1); 23327d0f8cd9SKristof Provost return (1); 23337d0f8cd9SKristof Provost } 23347d0f8cd9SKristof Provost idx = 0; 23357d0f8cd9SKristof Provost loop++; 23367d0f8cd9SKristof Provost } 23373b3a8eb9SGleb Smirnoff pfr_prepare_network(&umask, af, ke->pfrke_net); 23388ca12190SKristof Provost pfr_sockaddr_to_pf_addr(&ke->pfrke_sa, &cur); 23398ca12190SKristof Provost pfr_sockaddr_to_pf_addr(&umask, &mask); 23403b3a8eb9SGleb Smirnoff 23417d0f8cd9SKristof Provost if (use_counter && !PF_AZERO(counter, af)) { 23423b3a8eb9SGleb Smirnoff /* is supplied address within block? */ 23438ca12190SKristof Provost if (!PF_MATCHA(0, &cur, &mask, counter, af)) { 23443b3a8eb9SGleb Smirnoff /* no, go to next block in table */ 23453b3a8eb9SGleb Smirnoff idx++; 23463b3a8eb9SGleb Smirnoff use_counter = 0; 23473b3a8eb9SGleb Smirnoff goto _next_block; 23483b3a8eb9SGleb Smirnoff } 234967b65598SKristof Provost PF_ACPY(addr, counter, af); 23503b3a8eb9SGleb Smirnoff } else { 23513b3a8eb9SGleb Smirnoff /* use first address of block */ 235267b65598SKristof Provost PF_ACPY(addr, &cur, af); 23533b3a8eb9SGleb Smirnoff } 23543b3a8eb9SGleb Smirnoff 23553b3a8eb9SGleb Smirnoff if (!KENTRY_NETWORK(ke)) { 23563b3a8eb9SGleb Smirnoff /* this is a single IP address - no possible nested block */ 235767b65598SKristof Provost if (filter && filter(af, addr)) { 23587d381d0aSKristof Provost idx++; 23597d381d0aSKristof Provost goto _next_block; 23607d381d0aSKristof Provost } 236167b65598SKristof Provost PF_ACPY(counter, addr, af); 23623b3a8eb9SGleb Smirnoff *pidx = idx; 2363f92c21a2SMateusz Guzik pfr_kstate_counter_add(&kt->pfrkt_match, 1); 23643b3a8eb9SGleb Smirnoff return (0); 23653b3a8eb9SGleb Smirnoff } 23663b3a8eb9SGleb Smirnoff for (;;) { 23673b3a8eb9SGleb Smirnoff /* we don't want to use a nested block */ 23683b3a8eb9SGleb Smirnoff switch (af) { 23693b3a8eb9SGleb Smirnoff case AF_INET: 23703b3a8eb9SGleb Smirnoff ke2 = (struct pfr_kentry *)rn_match(&uaddr, 237161eee0e2SAlexander V. Chernikov &kt->pfrkt_ip4->rh); 23723b3a8eb9SGleb Smirnoff break; 23733b3a8eb9SGleb Smirnoff case AF_INET6: 23743b3a8eb9SGleb Smirnoff ke2 = (struct pfr_kentry *)rn_match(&uaddr, 237561eee0e2SAlexander V. Chernikov &kt->pfrkt_ip6->rh); 23763b3a8eb9SGleb Smirnoff break; 2377*abda72f3SKristof Provost default: 2378*abda72f3SKristof Provost unhandled_af(af); 23793b3a8eb9SGleb Smirnoff } 23803b3a8eb9SGleb Smirnoff /* no need to check KENTRY_RNF_ROOT() here */ 23813b3a8eb9SGleb Smirnoff if (ke2 == ke) { 23823b3a8eb9SGleb Smirnoff /* lookup return the same block - perfect */ 238367b65598SKristof Provost if (filter && filter(af, addr)) 23847d381d0aSKristof Provost goto _next_entry; 238567b65598SKristof Provost PF_ACPY(counter, addr, af); 23863b3a8eb9SGleb Smirnoff *pidx = idx; 2387f92c21a2SMateusz Guzik pfr_kstate_counter_add(&kt->pfrkt_match, 1); 23883b3a8eb9SGleb Smirnoff return (0); 23893b3a8eb9SGleb Smirnoff } 23903b3a8eb9SGleb Smirnoff 23917d381d0aSKristof Provost _next_entry: 23923b3a8eb9SGleb Smirnoff /* we need to increase the counter past the nested block */ 23933b3a8eb9SGleb Smirnoff pfr_prepare_network(&umask, AF_INET, ke2->pfrke_net); 23948ca12190SKristof Provost pfr_sockaddr_to_pf_addr(&umask, &umask_addr); 239567b65598SKristof Provost PF_POOLMASK(addr, addr, &umask_addr, &pfr_ffaddr, af); 239667b65598SKristof Provost PF_AINC(addr, af); 239767b65598SKristof Provost if (!PF_MATCHA(0, &cur, &mask, addr, af)) { 23983b3a8eb9SGleb Smirnoff /* ok, we reached the end of our main block */ 23993b3a8eb9SGleb Smirnoff /* go to next block in table */ 24003b3a8eb9SGleb Smirnoff idx++; 24013b3a8eb9SGleb Smirnoff use_counter = 0; 24023b3a8eb9SGleb Smirnoff goto _next_block; 24033b3a8eb9SGleb Smirnoff } 24043b3a8eb9SGleb Smirnoff } 24053b3a8eb9SGleb Smirnoff } 24063b3a8eb9SGleb Smirnoff 24073b3a8eb9SGleb Smirnoff static struct pfr_kentry * 24083b3a8eb9SGleb Smirnoff pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af) 24093b3a8eb9SGleb Smirnoff { 24103b3a8eb9SGleb Smirnoff struct pfr_walktree w; 24113b3a8eb9SGleb Smirnoff 24123b3a8eb9SGleb Smirnoff bzero(&w, sizeof(w)); 24133b3a8eb9SGleb Smirnoff w.pfrw_op = PFRW_POOL_GET; 24147b676698SKristof Provost w.pfrw_free = idx; 24153b3a8eb9SGleb Smirnoff 24163b3a8eb9SGleb Smirnoff switch (af) { 24173b3a8eb9SGleb Smirnoff #ifdef INET 24183b3a8eb9SGleb Smirnoff case AF_INET: 241961eee0e2SAlexander V. Chernikov kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); 24203b3a8eb9SGleb Smirnoff return (w.pfrw_kentry); 24213b3a8eb9SGleb Smirnoff #endif /* INET */ 24223b3a8eb9SGleb Smirnoff #ifdef INET6 24233b3a8eb9SGleb Smirnoff case AF_INET6: 242461eee0e2SAlexander V. Chernikov kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, pfr_walktree, &w); 24253b3a8eb9SGleb Smirnoff return (w.pfrw_kentry); 24263b3a8eb9SGleb Smirnoff #endif /* INET6 */ 24273b3a8eb9SGleb Smirnoff default: 24283b3a8eb9SGleb Smirnoff return (NULL); 24293b3a8eb9SGleb Smirnoff } 24303b3a8eb9SGleb Smirnoff } 24313b3a8eb9SGleb Smirnoff 24323b3a8eb9SGleb Smirnoff void 24333b3a8eb9SGleb Smirnoff pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn) 24343b3a8eb9SGleb Smirnoff { 24353b3a8eb9SGleb Smirnoff struct pfr_walktree w; 24363b3a8eb9SGleb Smirnoff 24373b3a8eb9SGleb Smirnoff bzero(&w, sizeof(w)); 24383b3a8eb9SGleb Smirnoff w.pfrw_op = PFRW_DYNADDR_UPDATE; 24393b3a8eb9SGleb Smirnoff w.pfrw_dyn = dyn; 24403b3a8eb9SGleb Smirnoff 24413b3a8eb9SGleb Smirnoff dyn->pfid_acnt4 = 0; 24423b3a8eb9SGleb Smirnoff dyn->pfid_acnt6 = 0; 2443*abda72f3SKristof Provost switch (dyn->pfid_af) { 2444*abda72f3SKristof Provost case AF_UNSPEC: /* look up all both addresses IPv4 + IPv6 */ 244561eee0e2SAlexander V. Chernikov kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); 244661eee0e2SAlexander V. Chernikov kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, pfr_walktree, &w); 2447*abda72f3SKristof Provost break; 2448*abda72f3SKristof Provost case AF_INET: 2449*abda72f3SKristof Provost kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); 2450*abda72f3SKristof Provost break; 2451*abda72f3SKristof Provost case AF_INET6: 2452*abda72f3SKristof Provost kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, pfr_walktree, &w); 2453*abda72f3SKristof Provost break; 2454*abda72f3SKristof Provost default: 2455*abda72f3SKristof Provost unhandled_af(dyn->pfid_af); 2456*abda72f3SKristof Provost } 24573b3a8eb9SGleb Smirnoff } 2458