pf_if.c revision 186048
11541Srgrimes/* $OpenBSD: pf_if.c,v 1.46 2006/12/13 09:01:59 itojun Exp $ */ 22531Swollman 31541Srgrimes/* 41541Srgrimes * Copyright 2005 Henning Brauer <henning@openbsd.org> 51541Srgrimes * Copyright 2005 Ryan McBride <mcbride@openbsd.org> 62531Swollman * Copyright (c) 2001 Daniel Hartmeier 72531Swollman * Copyright (c) 2003 Cedric Berger 82531Swollman * All rights reserved. 99209Swollman * 101541Srgrimes * Redistribution and use in source and binary forms, with or without 119209Swollman * modification, are permitted provided that the following conditions 121541Srgrimes * are met: 131541Srgrimes * 141541Srgrimes * - Redistributions of source code must retain the above copyright 151541Srgrimes * notice, this list of conditions and the following disclaimer. 161549Srgrimes * - Redistributions in binary form must reproduce the above 171541Srgrimes * copyright notice, this list of conditions and the following 181541Srgrimes * disclaimer in the documentation and/or other materials provided 191541Srgrimes * with the distribution. 202531Swollman * 212531Swollman * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 221541Srgrimes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 239209Swollman * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 242531Swollman * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 252531Swollman * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 267684Sdg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 271541Srgrimes * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 281541Srgrimes * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 291541Srgrimes * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 311541Srgrimes * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 322531Swollman * POSSIBILITY OF SUCH DAMAGE. 331541Srgrimes */ 341541Srgrimes 351541Srgrimes#if defined(__FreeBSD__) 361541Srgrimes#include "opt_inet.h" 371541Srgrimes#include "opt_inet6.h" 389209Swollman 391541Srgrimes#include <sys/cdefs.h> 402531Swollman__FBSDID("$FreeBSD: head/sys/contrib/pf/net/pf_if.c 186048 2008-12-13 19:13:03Z bz $"); 412531Swollman#endif 422531Swollman 432531Swollman#include <sys/param.h> 442531Swollman#include <sys/systm.h> 452531Swollman#ifdef __FreeBSD__ 462531Swollman#include <sys/malloc.h> 472531Swollman#endif 482531Swollman#include <sys/mbuf.h> 492531Swollman#include <sys/filio.h> 502531Swollman#include <sys/socket.h> 512531Swollman#include <sys/socketvar.h> 522531Swollman#include <sys/kernel.h> 531541Srgrimes#ifndef __FreeBSD__ 549209Swollman#include <sys/device.h> 559209Swollman#endif 562531Swollman#include <sys/time.h> 572531Swollman#ifdef __FreeBSD__ 582531Swollman#include <sys/vimage.h> 592531Swollman#endif 601541Srgrimes 619209Swollman#include <net/if.h> 622763Swollman#include <net/if_types.h> 632763Swollman#ifdef __FreeBSD__ 649209Swollman#include <net/vnet.h> 652531Swollman#endif 662531Swollman 679209Swollman#include <netinet/in.h> 682531Swollman#include <netinet/in_var.h> 692531Swollman#include <netinet/in_systm.h> 702531Swollman#include <netinet/ip.h> 712531Swollman#include <netinet/ip_var.h> 722531Swollman 732531Swollman#include <net/pfvar.h> 742531Swollman 759209Swollman#ifdef INET6 762754Swollman#include <netinet/ip6.h> 779209Swollman#endif /* INET6 */ 782531Swollman 799209Swollmanstruct pfi_kif *pfi_all = NULL; 809209Swollmanstruct pfi_statehead pfi_statehead; 819209Swollman#ifdef __FreeBSD__ 829209Swollmanuma_zone_t pfi_addr_pl; 839209Swollman#else 849209Swollmanstruct pool pfi_addr_pl; 859209Swollman#endif 869209Swollmanstruct pfi_ifhead pfi_ifs; 879209Swollmanlong pfi_update = 1; 889209Swollmanstruct pfr_addr *pfi_buffer; 899209Swollmanint pfi_buffer_cnt; 902754Swollmanint pfi_buffer_max; 912531Swollman#ifdef __FreeBSD__ 922531Swollmaneventhandler_tag pfi_attach_cookie = NULL; 932531Swollmaneventhandler_tag pfi_detach_cookie = NULL; 942531Swollmaneventhandler_tag pfi_attach_group_cookie = NULL; 952754Swollmaneventhandler_tag pfi_change_group_cookie = NULL; 962754Swollmaneventhandler_tag pfi_detach_group_cookie = NULL; 972531Swollmaneventhandler_tag pfi_ifaddr_event_cookie = NULL; 982754Swollman#endif 992531Swollman 1002531Swollmanvoid pfi_kif_update(struct pfi_kif *); 1012531Swollmanvoid pfi_dynaddr_update(struct pfi_dynaddr *dyn); 1022754Swollmanvoid pfi_table_update(struct pfr_ktable *, struct pfi_kif *, 1032531Swollman int, int); 1042531Swollmanvoid pfi_kifaddr_update(void *); 1052531Swollmanvoid pfi_instance_add(struct ifnet *, int, int); 1062754Swollmanvoid pfi_address_add(struct sockaddr *, int, int); 1072754Swollmanint pfi_if_compare(struct pfi_kif *, struct pfi_kif *); 1082754Swollmanint pfi_skip_if(const char *, struct pfi_kif *); 1092754Swollmanint pfi_unmask(void *); 1102754Swollman#ifdef __FreeBSD__ 1112754Swollmanvoid pfi_attach_ifnet_event(void * __unused, struct ifnet *); 1122754Swollmanvoid pfi_detach_ifnet_event(void * __unused, struct ifnet *); 1132754Swollmanvoid pfi_attach_group_event(void * __unused, struct ifg_group *); 1142754Swollmanvoid pfi_change_group_event(void * __unused, char *); 1152754Swollmanvoid pfi_detach_group_event(void * __unused, struct ifg_group *); 1162754Swollmanvoid pfi_ifaddr_event(void * __unused, struct ifnet *); 1172754Swollman 1189209Swollman#ifdef VIMAGE_GLOBALS 1199209Swollmanextern struct ifgrouphead ifg_head; 1209209Swollman#endif 1219209Swollman#endif 1229209Swollman 1239209SwollmanRB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); 1249209SwollmanRB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); 1259209Swollman 1269209Swollman#define PFI_BUFFER_MAX 0x10000 1279209Swollman#define PFI_MTYPE M_IFADDR 1289209Swollman 1299209Swollmanvoid 1309209Swollmanpfi_initialize(void) 1319209Swollman{ 1329209Swollman INIT_VNET_NET(curvnet); 1339209Swollman 1349209Swollman if (pfi_all != NULL) /* already initialized */ 1352754Swollman return; 1369209Swollman 1379209Swollman TAILQ_INIT(&pfi_statehead); 1389209Swollman#ifndef __FreeBSD__ 1399209Swollman pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0, 1402754Swollman "pfiaddrpl", &pool_allocator_nointr); 1412754Swollman#endif 1429209Swollman pfi_buffer_max = 64; 1439209Swollman pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer), 1449209Swollman PFI_MTYPE, M_WAITOK); 1459209Swollman 1462754Swollman if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL) 1472754Swollman panic("pfi_kif_get for pfi_all failed"); 1489209Swollman 1499209Swollman#ifdef __FreeBSD__ 1509209Swollman struct ifg_group *ifg; 1519209Swollman struct ifnet *ifp; 1529209Swollman 1539209Swollman IFNET_RLOCK(); 1549209Swollman TAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) 1559209Swollman pfi_attach_ifgroup(ifg); 1569209Swollman TAILQ_FOREACH(ifp, &V_ifnet, if_link) 1579209Swollman pfi_attach_ifnet(ifp); 1589209Swollman IFNET_RUNLOCK(); 1599209Swollman 1609209Swollman pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event, 1619209Swollman pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); 1629209Swollman pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event, 1639209Swollman pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); 1649209Swollman pfi_attach_group_cookie = EVENTHANDLER_REGISTER(group_attach_event, 1659209Swollman pfi_attach_group_event, NULL, EVENTHANDLER_PRI_ANY); 1669209Swollman pfi_change_group_cookie = EVENTHANDLER_REGISTER(group_change_event, 1679209Swollman pfi_change_group_event, NULL, EVENTHANDLER_PRI_ANY); 1689209Swollman pfi_detach_group_cookie = EVENTHANDLER_REGISTER(group_detach_event, 1699209Swollman pfi_detach_group_event, NULL, EVENTHANDLER_PRI_ANY); 1709209Swollman pfi_ifaddr_event_cookie = EVENTHANDLER_REGISTER(ifaddr_event, 1719209Swollman pfi_ifaddr_event, NULL, EVENTHANDLER_PRI_ANY); 1729209Swollman#endif 1739209Swollman} 1749209Swollman 1759209Swollman#ifdef __FreeBSD__ 1769209Swollmanvoid 1779209Swollmanpfi_cleanup(void) 1789209Swollman{ 1799209Swollman struct pfi_kif *p; 1807083Swollman 1812531Swollman PF_UNLOCK(); 1829209Swollman EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie); 1839209Swollman EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie); 1842531Swollman EVENTHANDLER_DEREGISTER(group_attach_event, pfi_attach_group_cookie); 1852531Swollman EVENTHANDLER_DEREGISTER(group_change_event, pfi_change_group_cookie); 1862531Swollman EVENTHANDLER_DEREGISTER(group_detach_event, pfi_detach_group_cookie); 1872531Swollman EVENTHANDLER_DEREGISTER(ifaddr_event, pfi_ifaddr_event_cookie); 1882531Swollman PF_LOCK(); 1892531Swollman 1901541Srgrimes pfi_all = NULL; 1911541Srgrimes while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) { 1921541Srgrimes if (p->pfik_rules || p->pfik_states) { 1931541Srgrimes printf("pfi_cleanup: dangling refs for %s\n", 1942763Swollman p->pfik_name); 1952531Swollman } 1962763Swollman 1972763Swollman RB_REMOVE(pfi_ifhead, &pfi_ifs, p); 1982531Swollman free(p, PFI_MTYPE); 1997083Swollman } 2002763Swollman 2012763Swollman free(pfi_buffer, PFI_MTYPE); 2022763Swollman} 2031541Srgrimes#endif 2042531Swollman 2052531Swollmanstruct pfi_kif * 2061541Srgrimespfi_kif_get(const char *kif_name) 2072531Swollman{ 2089209Swollman struct pfi_kif *kif; 2092531Swollman struct pfi_kif_cmp s; 2102531Swollman 2119209Swollman bzero(&s, sizeof(s)); 2129209Swollman strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name)); 2139209Swollman if ((kif = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s)) != NULL) 2149209Swollman return (kif); 2152531Swollman 2169209Swollman /* create new one */ 2172531Swollman#ifdef __FreeBSD__ 2189209Swollman if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_NOWAIT)) == NULL) 2199209Swollman#else 2202531Swollman if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_DONTWAIT)) == NULL) 2211541Srgrimes#endif 2222531Swollman return (NULL); 2239209Swollman 2249209Swollman bzero(kif, sizeof(*kif)); 2252531Swollman strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name)); 2262531Swollman#ifdef __FreeBSD__ 2272531Swollman /* 2282531Swollman * It seems that the value of time_second is in unintialzied state 2292531Swollman * when pf sets interface statistics clear time in boot phase if pf 2302531Swollman * was statically linked to kernel. Instead of setting the bogus 2312531Swollman * time value have pfi_get_ifaces handle this case. In 2322531Swollman * pfi_get_ifaces it uses boottime.tv_sec if it sees the time is 0. 2332531Swollman */ 2342531Swollman kif->pfik_tzero = time_second > 1 ? time_second : 0; 2352531Swollman#else 2362531Swollman kif->pfik_tzero = time_second; 2372531Swollman#endif 2382531Swollman TAILQ_INIT(&kif->pfik_dynaddrs); 2392531Swollman 2402531Swollman RB_INSERT(pfi_ifhead, &pfi_ifs, kif); 2419209Swollman return (kif); 2422531Swollman} 2432531Swollman 2442531Swollmanvoid 2452754Swollmanpfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what) 2462531Swollman{ 2472531Swollman switch (what) { 2482531Swollman case PFI_KIF_REF_RULE: 2492531Swollman kif->pfik_rules++; 2502531Swollman break; 2512531Swollman case PFI_KIF_REF_STATE: 2522531Swollman if (!kif->pfik_states++) 2532531Swollman TAILQ_INSERT_TAIL(&pfi_statehead, kif, pfik_w_states); 2549209Swollman break; 2552531Swollman default: 2562531Swollman panic("pfi_kif_ref with unknown type"); 2572531Swollman } 2582531Swollman} 2591541Srgrimes 2601541Srgrimesvoid 2612531Swollmanpfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what) 2627083Swollman{ 2639209Swollman if (kif == NULL) 2641541Srgrimes return; 2651541Srgrimes 2669209Swollman switch (what) { 2672531Swollman case PFI_KIF_REF_NONE: 2682531Swollman break; 2692531Swollman case PFI_KIF_REF_RULE: 2702531Swollman if (kif->pfik_rules <= 0) { 2712531Swollman printf("pfi_kif_unref: rules refcount <= 0\n"); 2729209Swollman return; 2739209Swollman } 2749209Swollman kif->pfik_rules--; 2752531Swollman break; 2762531Swollman case PFI_KIF_REF_STATE: 2772531Swollman if (kif->pfik_states <= 0) { 2789209Swollman printf("pfi_kif_unref: state refcount <= 0\n"); 2799209Swollman return; 2809209Swollman } 2819209Swollman if (!--kif->pfik_states) 2829209Swollman TAILQ_REMOVE(&pfi_statehead, kif, pfik_w_states); 2839209Swollman break; 2849209Swollman default: 2852531Swollman panic("pfi_kif_unref with unknown type"); 2862531Swollman } 2879209Swollman 2882531Swollman if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all) 2899209Swollman return; 2909209Swollman 2919209Swollman if (kif->pfik_rules || kif->pfik_states) 2929209Swollman return; 2939209Swollman 2949209Swollman RB_REMOVE(pfi_ifhead, &pfi_ifs, kif); 2959209Swollman free(kif, PFI_MTYPE); 2962531Swollman} 2979209Swollman 2982531Swollmanint 2992531Swollmanpfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif) 3009209Swollman{ 3018876Srgrimes struct ifg_list *p; 3029209Swollman 3039209Swollman if (rule_kif == NULL || rule_kif == packet_kif) 3049209Swollman return (1); 3059209Swollman 3069209Swollman if (rule_kif->pfik_group != NULL) 3072531Swollman TAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next) 3082531Swollman if (p->ifgl_group == rule_kif->pfik_group) 3099209Swollman return (1); 3102531Swollman 3119209Swollman return (0); 3129209Swollman} 3132531Swollman 3142531Swollmanvoid 3152531Swollmanpfi_attach_ifnet(struct ifnet *ifp) 3162531Swollman{ 3172531Swollman struct pfi_kif *kif; 3189209Swollman int s; 3192531Swollman 3209209Swollman pfi_initialize(); 3219209Swollman s = splsoftnet(); 3229209Swollman pfi_update++; 3232531Swollman if ((kif = pfi_kif_get(ifp->if_xname)) == NULL) 3249209Swollman panic("pfi_kif_get failed"); 3259209Swollman 3269209Swollman kif->pfik_ifp = ifp; 3279209Swollman ifp->if_pf_kif = (caddr_t)kif; 3289209Swollman 3299209Swollman#ifndef __FreeBSD__ 3309209Swollman if ((kif->pfik_ah_cookie = hook_establish(ifp->if_addrhooks, 1, 3319209Swollman pfi_kifaddr_update, kif)) == NULL) 3329209Swollman panic("pfi_attach_ifnet: cannot allocate '%s' address hook", 3339209Swollman ifp->if_xname); 3349209Swollman#endif 3359209Swollman 3369209Swollman pfi_kif_update(kif); 3372531Swollman 3382531Swollman splx(s); 3392531Swollman} 3402531Swollman 3412531Swollmanvoid 3422531Swollmanpfi_detach_ifnet(struct ifnet *ifp) 3432531Swollman{ 3442531Swollman int s; 3452531Swollman struct pfi_kif *kif; 3462531Swollman 3472531Swollman if ((kif = (struct pfi_kif *)ifp->if_pf_kif) == NULL) 3482531Swollman return; 3492531Swollman 3502531Swollman s = splsoftnet(); 3512531Swollman pfi_update++; 3522531Swollman#ifndef __FreeBSD__ 3532531Swollman hook_disestablish(ifp->if_addrhooks, kif->pfik_ah_cookie); 3542531Swollman#endif 3552531Swollman pfi_kif_update(kif); 3562531Swollman 3572531Swollman kif->pfik_ifp = NULL; 3582531Swollman ifp->if_pf_kif = NULL; 3592531Swollman pfi_kif_unref(kif, PFI_KIF_REF_NONE); 3602531Swollman splx(s); 3612531Swollman} 3622531Swollman 3632531Swollmanvoid 3642531Swollmanpfi_attach_ifgroup(struct ifg_group *ifg) 3659209Swollman{ 3669209Swollman struct pfi_kif *kif; 3679209Swollman int s; 3689209Swollman 3699209Swollman pfi_initialize(); 3709209Swollman s = splsoftnet(); 3712531Swollman pfi_update++; 3729209Swollman if ((kif = pfi_kif_get(ifg->ifg_group)) == NULL) 3731541Srgrimes panic("pfi_kif_get failed"); 3741541Srgrimes 3759209Swollman kif->pfik_group = ifg; 3762531Swollman ifg->ifg_pf_kif = (caddr_t)kif; 3772531Swollman 3782531Swollman splx(s); 3791541Srgrimes} 3809209Swollman 3811541Srgrimesvoid 3822531Swollmanpfi_detach_ifgroup(struct ifg_group *ifg) 3839209Swollman{ 3849209Swollman int s; 3859209Swollman struct pfi_kif *kif; 3869209Swollman 3879209Swollman if ((kif = (struct pfi_kif *)ifg->ifg_pf_kif) == NULL) 3889209Swollman return; 3899209Swollman 3902531Swollman s = splsoftnet(); 3912531Swollman pfi_update++; 3922531Swollman 3931541Srgrimes kif->pfik_group = NULL; 3942763Swollman ifg->ifg_pf_kif = NULL; 3959209Swollman pfi_kif_unref(kif, PFI_KIF_REF_NONE); 3962763Swollman splx(s); 3971541Srgrimes} 3982531Swollman 3999209Swollmanvoid 4009209Swollmanpfi_group_change(const char *group) 4019209Swollman{ 4029209Swollman struct pfi_kif *kif; 4039209Swollman int s; 4049209Swollman 4059209Swollman s = splsoftnet(); 4069209Swollman pfi_update++; 4079209Swollman if ((kif = pfi_kif_get(group)) == NULL) 4089209Swollman panic("pfi_kif_get failed"); 4099209Swollman 4109209Swollman pfi_kif_update(kif); 4119209Swollman 4129209Swollman splx(s); 4139209Swollman} 4149209Swollman 4159209Swollmanint 4169209Swollmanpfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) 4179209Swollman{ 4189209Swollman switch (af) { 4199209Swollman#ifdef INET 4209209Swollman case AF_INET: 4219209Swollman switch (dyn->pfid_acnt4) { 4229209Swollman case 0: 4239209Swollman return (0); 4249209Swollman case 1: 4252531Swollman return (PF_MATCHA(0, &dyn->pfid_addr4, 4262531Swollman &dyn->pfid_mask4, a, AF_INET)); 4272531Swollman default: 4282763Swollman return (pfr_match_addr(dyn->pfid_kt, a, AF_INET)); 4292531Swollman } 4302531Swollman break; 4312531Swollman#endif /* INET */ 4322531Swollman#ifdef INET6 4331541Srgrimes case AF_INET6: 4342531Swollman switch (dyn->pfid_acnt6) { 4359209Swollman case 0: 4369209Swollman return (0); 4379209Swollman case 1: 4389209Swollman return (PF_MATCHA(0, &dyn->pfid_addr6, 4399209Swollman &dyn->pfid_mask6, a, AF_INET6)); 4409209Swollman default: 4412531Swollman return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6)); 4429209Swollman } 4439209Swollman break; 4442531Swollman#endif /* INET6 */ 4452531Swollman default: 4462531Swollman return (0); 4471541Srgrimes } 4482763Swollman} 4492763Swollman 4502763Swollmanint 4512754Swollmanpfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) 4522531Swollman{ 4539209Swollman struct pfi_dynaddr *dyn; 4542531Swollman char tblname[PF_TABLE_NAME_SIZE]; 4559209Swollman struct pf_ruleset *ruleset = NULL; 4562531Swollman int s, rv = 0; 4572531Swollman 4582531Swollman if (aw->type != PF_ADDR_DYNIFTL) 4592531Swollman return (0); 4602531Swollman if ((dyn = pool_get(&pfi_addr_pl, PR_NOWAIT)) == NULL) 4611541Srgrimes return (1); 4622531Swollman bzero(dyn, sizeof(*dyn)); 4632531Swollman 4642531Swollman s = splsoftnet(); 4659209Swollman if (!strcmp(aw->v.ifname, "self")) 4669209Swollman dyn->pfid_kif = pfi_kif_get(IFG_ALL); 4679209Swollman else 4689209Swollman dyn->pfid_kif = pfi_kif_get(aw->v.ifname); 4699209Swollman if (dyn->pfid_kif == NULL) { 4709209Swollman rv = 1; 4711541Srgrimes goto _bad; 4722531Swollman } 4732531Swollman pfi_kif_ref(dyn->pfid_kif, PFI_KIF_REF_RULE); 4741541Srgrimes 4752531Swollman dyn->pfid_net = pfi_unmask(&aw->v.a.mask); 4769209Swollman if (af == AF_INET && dyn->pfid_net == 32) 4772531Swollman dyn->pfid_net = 128; 4789209Swollman strlcpy(tblname, aw->v.ifname, sizeof(tblname)); 4792531Swollman if (aw->iflags & PFI_AFLAG_NETWORK) 4802531Swollman strlcat(tblname, ":network", sizeof(tblname)); 4812531Swollman if (aw->iflags & PFI_AFLAG_BROADCAST) 4822531Swollman strlcat(tblname, ":broadcast", sizeof(tblname)); 4831541Srgrimes if (aw->iflags & PFI_AFLAG_PEER) 4849209Swollman strlcat(tblname, ":peer", sizeof(tblname)); 4859209Swollman if (aw->iflags & PFI_AFLAG_NOALIAS) 4862531Swollman strlcat(tblname, ":0", sizeof(tblname)); 4872531Swollman if (dyn->pfid_net != 128) 4889209Swollman snprintf(tblname + strlen(tblname), 4899209Swollman sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net); 4901541Srgrimes if ((ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR)) == NULL) { 4912531Swollman rv = 1; 4922531Swollman goto _bad; 4932531Swollman } 4941541Srgrimes 4951541Srgrimes if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname)) == NULL) { 4961541Srgrimes rv = 1; 4979209Swollman goto _bad; 4989209Swollman } 4992531Swollman 5009209Swollman dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE; 5011541Srgrimes dyn->pfid_iflags = aw->iflags; 5029209Swollman dyn->pfid_af = af; 5039209Swollman 5049209Swollman TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry); 5059209Swollman aw->p.dyn = dyn; 5069209Swollman pfi_kif_update(dyn->pfid_kif); 5079209Swollman splx(s); 5089209Swollman return (0); 5092531Swollman 5102531Swollman_bad: 5111541Srgrimes if (dyn->pfid_kt != NULL) 5129209Swollman pfr_detach_table(dyn->pfid_kt); 5139209Swollman if (ruleset != NULL) 5149209Swollman pf_remove_if_empty_ruleset(ruleset); 5159209Swollman if (dyn->pfid_kif != NULL) 5169209Swollman pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE); 5179209Swollman pool_put(&pfi_addr_pl, dyn); 5189209Swollman splx(s); 5192531Swollman return (rv); 5201541Srgrimes} 5212531Swollman 5221541Srgrimesvoid 5239209Swollmanpfi_kif_update(struct pfi_kif *kif) 5249209Swollman{ 5259209Swollman struct ifg_list *ifgl; 5269209Swollman struct pfi_dynaddr *p; 5279209Swollman 5289209Swollman /* update all dynaddr */ 5299209Swollman TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry) 5302531Swollman pfi_dynaddr_update(p); 5319209Swollman 5322531Swollman /* again for all groups kif is member of */ 5332531Swollman if (kif->pfik_ifp != NULL) 5341541Srgrimes TAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next) 5351541Srgrimes pfi_kif_update((struct pfi_kif *) 5361541Srgrimes ifgl->ifgl_group->ifg_pf_kif); 5371541Srgrimes} 5381541Srgrimes 5391541Srgrimesvoid 5402763Swollmanpfi_dynaddr_update(struct pfi_dynaddr *dyn) 5411541Srgrimes{ 5422531Swollman struct pfi_kif *kif; 5432531Swollman struct pfr_ktable *kt; 5442531Swollman 5452531Swollman if (dyn == NULL || dyn->pfid_kif == NULL || dyn->pfid_kt == NULL) 5462531Swollman panic("pfi_dynaddr_update"); 5479209Swollman 5482531Swollman kif = dyn->pfid_kif; 5492531Swollman kt = dyn->pfid_kt; 5502531Swollman 5511541Srgrimes if (kt->pfrkt_larg != pfi_update) { 5522531Swollman /* this table needs to be brought up-to-date */ 5531541Srgrimes pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags); 5542531Swollman kt->pfrkt_larg = pfi_update; 5552531Swollman } 5562531Swollman pfr_dynaddr_update(kt, dyn); 5572531Swollman} 5582531Swollman 5592531Swollmanvoid 5602531Swollmanpfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags) 5612531Swollman{ 5622531Swollman int e, size2 = 0; 5632531Swollman struct ifg_member *ifgm; 5642531Swollman 5652531Swollman pfi_buffer_cnt = 0; 5662531Swollman 5672531Swollman if (kif->pfik_ifp != NULL) 5682531Swollman pfi_instance_add(kif->pfik_ifp, net, flags); 5692531Swollman else if (kif->pfik_group != NULL) 5702531Swollman TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next) 5712531Swollman pfi_instance_add(ifgm->ifgm_ifp, net, flags); 5729209Swollman 5732531Swollman if ((e = pfr_set_addrs(&kt->pfrkt_t, pfi_buffer, pfi_buffer_cnt, &size2, 5749209Swollman NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK))) 5759209Swollman printf("pfi_table_update: cannot set %d new addresses " 5762531Swollman "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e); 5779209Swollman} 5782531Swollman 5799209Swollmanvoid 5809209Swollmanpfi_instance_add(struct ifnet *ifp, int net, int flags) 5819209Swollman{ 5829209Swollman struct ifaddr *ia; 5839209Swollman int got4 = 0, got6 = 0; 5849209Swollman int net2, af; 5859209Swollman 5869209Swollman if (ifp == NULL) 5879209Swollman return; 5889209Swollman TAILQ_FOREACH(ia, &ifp->if_addrlist, ifa_list) { 5891541Srgrimes if (ia->ifa_addr == NULL) 5902531Swollman continue; 5919209Swollman af = ia->ifa_addr->sa_family; 5921541Srgrimes if (af != AF_INET && af != AF_INET6) 5939209Swollman continue; 5941541Srgrimes#ifdef __FreeBSD__ 5952531Swollman /* 5961541Srgrimes * XXX: For point-to-point interfaces, (ifname:0) and IPv4, 5972531Swollman * jump over addresses without a proper route to work 5982531Swollman * around a problem with ppp not fully removing the 5992531Swollman * address used during IPCP. 6002531Swollman */ 6012531Swollman if ((ifp->if_flags & IFF_POINTOPOINT) && 6029209Swollman !(ia->ifa_flags & IFA_ROUTE) && 6039209Swollman (flags & PFI_AFLAG_NOALIAS) && (af == AF_INET)) 6042531Swollman continue; 6052531Swollman#endif 6062531Swollman if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6) 6072531Swollman continue; 6082531Swollman if ((flags & PFI_AFLAG_BROADCAST) && 6099209Swollman !(ifp->if_flags & IFF_BROADCAST)) 6102531Swollman continue; 6112531Swollman if ((flags & PFI_AFLAG_PEER) && 6121541Srgrimes !(ifp->if_flags & IFF_POINTOPOINT)) 6131541Srgrimes continue; 6142763Swollman if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 && 6152763Swollman IN6_IS_ADDR_LINKLOCAL( 6162763Swollman &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr)) 6172754Swollman continue; 6189209Swollman if (flags & PFI_AFLAG_NOALIAS) { 6199209Swollman if (af == AF_INET && got4) 6209209Swollman continue; 6219209Swollman if (af == AF_INET6 && got6) 6229209Swollman continue; 6239209Swollman } 6249209Swollman if (af == AF_INET) 6259209Swollman got4 = 1; 6269209Swollman else if (af == AF_INET6) 6279209Swollman got6 = 1; 6289209Swollman net2 = net; 6299209Swollman if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) { 6309209Swollman if (af == AF_INET) 6319209Swollman net2 = pfi_unmask(&((struct sockaddr_in *) 6321541Srgrimes ia->ifa_netmask)->sin_addr); 6339209Swollman else if (af == AF_INET6) 6349209Swollman net2 = pfi_unmask(&((struct sockaddr_in6 *) 6359209Swollman ia->ifa_netmask)->sin6_addr); 6369209Swollman } 6379209Swollman if (af == AF_INET && net2 > 32) 6389209Swollman net2 = 32; 6399209Swollman if (flags & PFI_AFLAG_BROADCAST) 6409209Swollman pfi_address_add(ia->ifa_broadaddr, af, net2); 6419209Swollman else if (flags & PFI_AFLAG_PEER) 6429209Swollman pfi_address_add(ia->ifa_dstaddr, af, net2); 6439209Swollman else 6449209Swollman pfi_address_add(ia->ifa_addr, af, net2); 6459209Swollman } 6469209Swollman} 6479209Swollman 6489209Swollmanvoid 6499209Swollmanpfi_address_add(struct sockaddr *sa, int af, int net) 6509209Swollman{ 6519209Swollman struct pfr_addr *p; 6529209Swollman int i; 6539209Swollman 6549209Swollman if (pfi_buffer_cnt >= pfi_buffer_max) { 6559209Swollman int new_max = pfi_buffer_max * 2; 6569209Swollman 6579209Swollman if (new_max > PFI_BUFFER_MAX) { 6589209Swollman printf("pfi_address_add: address buffer full (%d/%d)\n", 6599209Swollman pfi_buffer_cnt, PFI_BUFFER_MAX); 6609209Swollman return; 6619209Swollman } 6629209Swollman p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE, 6639209Swollman#ifdef __FreeBSD__ 6641541Srgrimes M_NOWAIT); 6651541Srgrimes#else 6661541Srgrimes M_DONTWAIT); 6671541Srgrimes#endif 6682531Swollman if (p == NULL) { 6691541Srgrimes printf("pfi_address_add: no memory to grow buffer " 6702531Swollman "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX); 6713747Swollman return; 6722531Swollman } 6732531Swollman memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer)); 6742531Swollman /* no need to zero buffer */ 6752531Swollman free(pfi_buffer, PFI_MTYPE); 6762531Swollman pfi_buffer = p; 6771541Srgrimes pfi_buffer_max = new_max; 6782531Swollman } 6792531Swollman if (af == AF_INET && net > 32) 6801541Srgrimes net = 128; 6812531Swollman p = pfi_buffer + pfi_buffer_cnt++; 6822531Swollman bzero(p, sizeof(*p)); 6832531Swollman p->pfra_af = af; 6842531Swollman p->pfra_net = net; 6852531Swollman if (af == AF_INET) 6861541Srgrimes p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr; 6872531Swollman else if (af == AF_INET6) { 6882531Swollman p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr; 6899209Swollman if (IN6_IS_SCOPE_EMBED(&p->pfra_ip6addr)) 6909209Swollman p->pfra_ip6addr.s6_addr16[1] = 0; 6919209Swollman } 6929209Swollman /* mask network address bits */ 6939209Swollman if (net < 128) 6949209Swollman ((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8)); 6959209Swollman for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++) 6969209Swollman ((caddr_t)p)[i] = 0; 6979209Swollman} 6989209Swollman 6991541Srgrimesvoid 7009209Swollmanpfi_dynaddr_remove(struct pf_addr_wrap *aw) 7019209Swollman{ 7029209Swollman int s; 7039209Swollman 7049209Swollman if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL || 7059209Swollman aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL) 7069209Swollman return; 7079209Swollman 7082531Swollman s = splsoftnet(); 7099209Swollman TAILQ_REMOVE(&aw->p.dyn->pfid_kif->pfik_dynaddrs, aw->p.dyn, entry); 7109209Swollman pfi_kif_unref(aw->p.dyn->pfid_kif, PFI_KIF_REF_RULE); 7111541Srgrimes aw->p.dyn->pfid_kif = NULL; 7122531Swollman pfr_detach_table(aw->p.dyn->pfid_kt); 7132531Swollman aw->p.dyn->pfid_kt = NULL; 7142531Swollman pool_put(&pfi_addr_pl, aw->p.dyn); 7152531Swollman aw->p.dyn = NULL; 7161541Srgrimes splx(s); 7172531Swollman} 7182531Swollman 7192531Swollmanvoid 7202531Swollmanpfi_dynaddr_copyout(struct pf_addr_wrap *aw) 7212531Swollman{ 7222531Swollman if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL || 7232531Swollman aw->p.dyn->pfid_kif == NULL) 7242531Swollman return; 7252531Swollman aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6; 7261541Srgrimes} 7272531Swollman 7282531Swollmanvoid 7292531Swollmanpfi_kifaddr_update(void *v) 7302531Swollman{ 7312531Swollman int s; 7322531Swollman struct pfi_kif *kif = (struct pfi_kif *)v; 7331541Srgrimes 7342531Swollman s = splsoftnet(); 7352531Swollman pfi_update++; 7362531Swollman pfi_kif_update(kif); 7372531Swollman splx(s); 7382531Swollman} 7392531Swollman 7409209Swollmanint 7419209Swollmanpfi_if_compare(struct pfi_kif *p, struct pfi_kif *q) 7422531Swollman{ 7432531Swollman return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ)); 7442531Swollman} 7459209Swollman 7469209Swollmanvoid 7472531Swollmanpfi_fill_oldstatus(struct pf_status *pfs) 7482531Swollman{ 7492531Swollman struct pfi_kif *p; 7502531Swollman struct pfi_kif_cmp key; 7512531Swollman int i, j, k, s; 7522531Swollman 7539209Swollman strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name)); 7549209Swollman s = splsoftnet(); 7552531Swollman p = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&key); 7562531Swollman if (p == NULL) { 7572531Swollman splx(s); 7582531Swollman return; 7599209Swollman } 7602531Swollman bzero(pfs->pcounters, sizeof(pfs->pcounters)); 7612531Swollman bzero(pfs->bcounters, sizeof(pfs->bcounters)); 7621541Srgrimes for (i = 0; i < 2; i++) 7631541Srgrimes for (j = 0; j < 2; j++) 7641541Srgrimes for (k = 0; k < 2; k++) { 7651541Srgrimes pfs->pcounters[i][j][k] = 7661541Srgrimes p->pfik_packets[i][j][k]; 7671541Srgrimes pfs->bcounters[i][j] += 7681541Srgrimes p->pfik_bytes[i][j][k]; 7692531Swollman } 7701541Srgrimes splx(s); 7712531Swollman} 7722531Swollman 7732531Swollmanint 7742531Swollmanpfi_clr_istats(const char *name) 7752531Swollman{ 7761541Srgrimes struct pfi_kif *p; 7772531Swollman int s; 7782531Swollman 7791541Srgrimes s = splsoftnet(); 7802531Swollman RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 7811541Srgrimes if (pfi_skip_if(name, p)) 7822531Swollman continue; 7832531Swollman bzero(p->pfik_packets, sizeof(p->pfik_packets)); 7842531Swollman bzero(p->pfik_bytes, sizeof(p->pfik_bytes)); 7852531Swollman p->pfik_tzero = time_second; 7862531Swollman } 7872531Swollman splx(s); 7881541Srgrimes 7892531Swollman return (0); 7902531Swollman} 7912531Swollman 7922531Swollmanint 7931541Srgrimespfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size) 7942531Swollman{ 7952531Swollman struct pfi_kif *p, *nextp; 7962531Swollman int s, n = 0; 7972531Swollman#ifdef __FreeBSD__ 7981541Srgrimes int error; 7992531Swollman#endif 8002531Swollman 8012531Swollman s = splsoftnet(); 8022531Swollman for (p = RB_MIN(pfi_ifhead, &pfi_ifs); p; p = nextp) { 8032531Swollman nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p); 8042531Swollman if (pfi_skip_if(name, p)) 8052531Swollman continue; 8062531Swollman if (*size > n++) { 8079209Swollman if (!p->pfik_tzero) 8082531Swollman p->pfik_tzero = time_second; 8092531Swollman pfi_kif_ref(p, PFI_KIF_REF_RULE); 8101541Srgrimes#ifdef __FreeBSD__ 8111541Srgrimes PF_COPYOUT(p, buf++, sizeof(*buf), error); 8121541Srgrimes if (error) { 8132531Swollman#else 8141541Srgrimes if (copyout(p, buf++, sizeof(*buf))) { 8151541Srgrimes#endif 8162531Swollman pfi_kif_unref(p, PFI_KIF_REF_RULE); 8172531Swollman splx(s); 8181541Srgrimes return (EFAULT); 8192531Swollman } 8202531Swollman nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p); 8212531Swollman pfi_kif_unref(p, PFI_KIF_REF_RULE); 8222531Swollman } 8232531Swollman } 8242531Swollman splx(s); 8252531Swollman *size = n; 8262531Swollman return (0); 8271541Srgrimes} 8289209Swollman 8291541Srgrimesint 8302531Swollmanpfi_skip_if(const char *filter, struct pfi_kif *p) 8312531Swollman{ 8329209Swollman int n; 8339209Swollman 8342531Swollman if (filter == NULL || !*filter) 8352531Swollman return (0); 8362531Swollman if (!strcmp(p->pfik_name, filter)) 8371541Srgrimes return (0); /* exact match */ 8381541Srgrimes n = strlen(filter); 8392531Swollman if (n < 1 || n >= IFNAMSIZ) 8402531Swollman return (1); /* sanity check */ 8419209Swollman if (filter[n-1] >= '0' && filter[n-1] <= '9') 8422531Swollman return (1); /* only do exact match in that case */ 8432531Swollman if (strncmp(p->pfik_name, filter, n)) 8442531Swollman return (1); /* prefix doesn't match */ 8451541Srgrimes return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9'); 8469209Swollman} 8472531Swollman 8482531Swollmanint 8492531Swollmanpfi_set_flags(const char *name, int flags) 8509209Swollman{ 8519209Swollman struct pfi_kif *p; 8521541Srgrimes int s; 8532531Swollman 8549209Swollman s = splsoftnet(); 8552531Swollman RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 8562531Swollman if (pfi_skip_if(name, p)) 8579209Swollman continue; 8589209Swollman p->pfik_flags |= flags; 8599209Swollman } 8609209Swollman splx(s); 8619209Swollman return (0); 8629209Swollman} 8639209Swollman 8641541Srgrimesint 8659209Swollmanpfi_clear_flags(const char *name, int flags) 8669209Swollman{ 8679209Swollman struct pfi_kif *p; 8689209Swollman int s; 8699209Swollman 8701541Srgrimes s = splsoftnet(); 8719209Swollman RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 8729209Swollman if (pfi_skip_if(name, p)) 8739209Swollman continue; 8749209Swollman p->pfik_flags &= ~flags; 8759209Swollman } 8769209Swollman splx(s); 8779209Swollman return (0); 8789209Swollman} 8799209Swollman 8809209Swollman/* from pf_print_state.c */ 8812531Swollmanint 8829209Swollmanpfi_unmask(void *addr) 8839209Swollman{ 8842531Swollman struct pf_addr *m = addr; 8852531Swollman int i = 31, j = 0, b = 0; 8862531Swollman u_int32_t tmp; 8872531Swollman 8882531Swollman while (j < 4 && m->addr32[j] == 0xffffffff) { 8899209Swollman b += 32; 8909209Swollman j++; 8919209Swollman } 8922531Swollman if (j < 4) { 8932531Swollman tmp = ntohl(m->addr32[j]); 8949209Swollman for (i = 31; tmp & (1 << i); --i) 8959209Swollman b++; 8969209Swollman } 8972531Swollman return (b); 8982531Swollman} 8991541Srgrimes 9002531Swollman#ifdef __FreeBSD__ 9011541Srgrimesvoid 9022531Swollmanpfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp) 9032531Swollman{ 9042531Swollman PF_LOCK(); 9052531Swollman pfi_attach_ifnet(ifp); 9069209Swollman#ifdef ALTQ 9079209Swollman pf_altq_ifnet_event(ifp, 0); 9082531Swollman#endif 9092531Swollman PF_UNLOCK(); 9102531Swollman} 9119209Swollman 9129209Swollmanvoid 9139209Swollmanpfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp) 9142531Swollman{ 9159209Swollman PF_LOCK(); 9162531Swollman pfi_detach_ifnet(ifp); 9171541Srgrimes#ifdef ALTQ 9182531Swollman pf_altq_ifnet_event(ifp, 1); 9192531Swollman#endif 9202531Swollman PF_UNLOCK(); 9212531Swollman} 9229209Swollman 9232531Swollmanvoid 9242531Swollmanpfi_attach_group_event(void *arg __unused, struct ifg_group *ifg) 9259209Swollman{ 9269209Swollman PF_LOCK(); 9279209Swollman pfi_attach_ifgroup(ifg); 9289209Swollman PF_UNLOCK(); 9299209Swollman} 9309209Swollman 9312531Swollmanvoid 9322531Swollmanpfi_change_group_event(void *arg __unused, char *gname) 9332531Swollman{ 9342531Swollman PF_LOCK(); 9352531Swollman pfi_group_change(gname); 9362531Swollman PF_UNLOCK(); 9372531Swollman} 9382531Swollman 9392531Swollmanvoid 9409209Swollmanpfi_detach_group_event(void *arg __unused, struct ifg_group *ifg) 9412531Swollman{ 9429209Swollman PF_LOCK(); 9432531Swollman pfi_detach_ifgroup(ifg); 9442531Swollman PF_UNLOCK(); 9452531Swollman} 9462531Swollman 9472531Swollmanvoid 9489209Swollmanpfi_ifaddr_event(void *arg __unused, struct ifnet *ifp) 9492531Swollman{ 9502531Swollman PF_LOCK(); 9519209Swollman if (ifp && ifp->if_pf_kif) 9529209Swollman pfi_kifaddr_update(ifp->if_pf_kif); 9539209Swollman PF_UNLOCK(); 9549209Swollman} 9559209Swollman#endif /* __FreeBSD__ */ 9562531Swollman