1244769Sglebius/*- 2130610Smlaier * Copyright (c) 2001 Daniel Hartmeier 3130610Smlaier * Copyright (c) 2003 Cedric Berger 4244769Sglebius * Copyright (c) 2005 Henning Brauer <henning@openbsd.org> 5244769Sglebius * Copyright (c) 2005 Ryan McBride <mcbride@openbsd.org> 6244769Sglebius * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org> 7130610Smlaier * All rights reserved. 8130610Smlaier * 9130610Smlaier * Redistribution and use in source and binary forms, with or without 10130610Smlaier * modification, are permitted provided that the following conditions 11130610Smlaier * are met: 12130610Smlaier * 13130610Smlaier * - Redistributions of source code must retain the above copyright 14130610Smlaier * notice, this list of conditions and the following disclaimer. 15130610Smlaier * - Redistributions in binary form must reproduce the above 16130610Smlaier * copyright notice, this list of conditions and the following 17130610Smlaier * disclaimer in the documentation and/or other materials provided 18130610Smlaier * with the distribution. 19130610Smlaier * 20130610Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21130610Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22130610Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23130610Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24130610Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25130610Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26130610Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27130610Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28130610Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29130610Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30130610Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31130610Smlaier * POSSIBILITY OF SUCH DAMAGE. 32244769Sglebius * 33244769Sglebius * $OpenBSD: pf_if.c,v 1.54 2008/06/14 16:55:28 mk Exp $ 34130610Smlaier */ 35130610Smlaier 36240233Sglebius#include <sys/cdefs.h> 37240233Sglebius__FBSDID("$FreeBSD$"); 38240233Sglebius 39130613Smlaier#include "opt_inet.h" 40130613Smlaier#include "opt_inet6.h" 41171168Smlaier 42130610Smlaier#include <sys/param.h> 43240233Sglebius#include <sys/kernel.h> 44130610Smlaier#include <sys/socket.h> 45130610Smlaier 46130610Smlaier#include <net/if.h> 47130610Smlaier#include <net/pfvar.h> 48240233Sglebius#include <net/route.h> 49130610Smlaier 50240233SglebiusVNET_DEFINE(struct pfi_kif *, pfi_all); 51240233Sglebiusstatic VNET_DEFINE(long, pfi_update); 52240233Sglebius#define V_pfi_update VNET(pfi_update) 53240233Sglebius#define PFI_BUFFER_MAX 0x10000 54130610Smlaier 55240233Sglebiusstatic VNET_DEFINE(struct pfr_addr *, pfi_buffer); 56240233Sglebiusstatic VNET_DEFINE(int, pfi_buffer_cnt); 57240233Sglebiusstatic VNET_DEFINE(int, pfi_buffer_max); 58223637Sbz#define V_pfi_buffer VNET(pfi_buffer) 59223637Sbz#define V_pfi_buffer_cnt VNET(pfi_buffer_cnt) 60223637Sbz#define V_pfi_buffer_max VNET(pfi_buffer_max) 61240233Sglebius 62223637Sbzeventhandler_tag pfi_attach_cookie; 63223637Sbzeventhandler_tag pfi_detach_cookie; 64223637Sbzeventhandler_tag pfi_attach_group_cookie; 65223637Sbzeventhandler_tag pfi_change_group_cookie; 66223637Sbzeventhandler_tag pfi_detach_group_cookie; 67223637Sbzeventhandler_tag pfi_ifaddr_event_cookie; 68130610Smlaier 69240233Sglebiusstatic void pfi_attach_ifnet(struct ifnet *); 70240233Sglebiusstatic void pfi_attach_ifgroup(struct ifg_group *); 71130610Smlaier 72240233Sglebiusstatic void pfi_kif_update(struct pfi_kif *); 73240233Sglebiusstatic void pfi_dynaddr_update(struct pfi_dynaddr *dyn); 74240233Sglebiusstatic void pfi_table_update(struct pfr_ktable *, struct pfi_kif *, int, 75240233Sglebius int); 76240233Sglebiusstatic void pfi_instance_add(struct ifnet *, int, int); 77240233Sglebiusstatic void pfi_address_add(struct sockaddr *, int, int); 78240233Sglebiusstatic int pfi_if_compare(struct pfi_kif *, struct pfi_kif *); 79240233Sglebiusstatic int pfi_skip_if(const char *, struct pfi_kif *); 80240233Sglebiusstatic int pfi_unmask(void *); 81240233Sglebiusstatic void pfi_attach_ifnet_event(void * __unused, struct ifnet *); 82240233Sglebiusstatic void pfi_detach_ifnet_event(void * __unused, struct ifnet *); 83240233Sglebiusstatic void pfi_attach_group_event(void *, struct ifg_group *); 84240233Sglebiusstatic void pfi_change_group_event(void *, char *); 85240233Sglebiusstatic void pfi_detach_group_event(void *, struct ifg_group *); 86240233Sglebiusstatic void pfi_ifaddr_event(void * __unused, struct ifnet *); 87130610Smlaier 88240233SglebiusRB_HEAD(pfi_ifhead, pfi_kif); 89240233Sglebiusstatic RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); 90240233Sglebiusstatic RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); 91240233Sglebiusstatic VNET_DEFINE(struct pfi_ifhead, pfi_ifs); 92240233Sglebius#define V_pfi_ifs VNET(pfi_ifs) 93130610Smlaier 94240233Sglebius#define PFI_BUFFER_MAX 0x10000 95240233SglebiusMALLOC_DEFINE(PFI_MTYPE, "pf_ifnet", "pf(4) interface database"); 96240233Sglebius 97240233SglebiusLIST_HEAD(pfi_list, pfi_kif); 98240233Sglebiusstatic VNET_DEFINE(struct pfi_list, pfi_unlinked_kifs); 99240233Sglebius#define V_pfi_unlinked_kifs VNET(pfi_unlinked_kifs) 100240233Sglebiusstatic struct mtx pfi_unlnkdkifs_mtx; 101240233Sglebius 102130610Smlaiervoid 103130610Smlaierpfi_initialize(void) 104130610Smlaier{ 105240233Sglebius struct ifg_group *ifg; 106240233Sglebius struct ifnet *ifp; 107240233Sglebius struct pfi_kif *kif; 108130610Smlaier 109223637Sbz V_pfi_buffer_max = 64; 110223637Sbz V_pfi_buffer = malloc(V_pfi_buffer_max * sizeof(*V_pfi_buffer), 111223637Sbz PFI_MTYPE, M_WAITOK); 112223637Sbz 113240233Sglebius mtx_init(&pfi_unlnkdkifs_mtx, "pf unlinked interfaces", NULL, MTX_DEF); 114171168Smlaier 115240233Sglebius kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); 116240233Sglebius PF_RULES_WLOCK(); 117240233Sglebius V_pfi_all = pfi_kif_attach(kif, IFG_ALL); 118240233Sglebius PF_RULES_WUNLOCK(); 119171168Smlaier 120130613Smlaier IFNET_RLOCK(); 121181803Sbz TAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) 122171168Smlaier pfi_attach_ifgroup(ifg); 123181803Sbz TAILQ_FOREACH(ifp, &V_ifnet, if_link) 124137159Smlaier pfi_attach_ifnet(ifp); 125130613Smlaier IFNET_RUNLOCK(); 126171168Smlaier 127130613Smlaier pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event, 128130613Smlaier pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); 129130613Smlaier pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event, 130130613Smlaier pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); 131171168Smlaier pfi_attach_group_cookie = EVENTHANDLER_REGISTER(group_attach_event, 132223637Sbz pfi_attach_group_event, curvnet, EVENTHANDLER_PRI_ANY); 133171168Smlaier pfi_change_group_cookie = EVENTHANDLER_REGISTER(group_change_event, 134223637Sbz pfi_change_group_event, curvnet, EVENTHANDLER_PRI_ANY); 135171168Smlaier pfi_detach_group_cookie = EVENTHANDLER_REGISTER(group_detach_event, 136223637Sbz pfi_detach_group_event, curvnet, EVENTHANDLER_PRI_ANY); 137171168Smlaier pfi_ifaddr_event_cookie = EVENTHANDLER_REGISTER(ifaddr_event, 138171168Smlaier pfi_ifaddr_event, NULL, EVENTHANDLER_PRI_ANY); 139130610Smlaier} 140130610Smlaier 141173822Smlaiervoid 142173822Smlaierpfi_cleanup(void) 143173822Smlaier{ 144173822Smlaier struct pfi_kif *p; 145173822Smlaier 146173822Smlaier EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie); 147173822Smlaier EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie); 148173822Smlaier EVENTHANDLER_DEREGISTER(group_attach_event, pfi_attach_group_cookie); 149173822Smlaier EVENTHANDLER_DEREGISTER(group_change_event, pfi_change_group_cookie); 150173822Smlaier EVENTHANDLER_DEREGISTER(group_detach_event, pfi_detach_group_cookie); 151173822Smlaier EVENTHANDLER_DEREGISTER(ifaddr_event, pfi_ifaddr_event_cookie); 152173822Smlaier 153223637Sbz V_pfi_all = NULL; 154223637Sbz while ((p = RB_MIN(pfi_ifhead, &V_pfi_ifs))) { 155223637Sbz RB_REMOVE(pfi_ifhead, &V_pfi_ifs, p); 156173822Smlaier free(p, PFI_MTYPE); 157173822Smlaier } 158173822Smlaier 159240233Sglebius while ((p = LIST_FIRST(&V_pfi_unlinked_kifs))) { 160240233Sglebius LIST_REMOVE(p, pfik_list); 161240233Sglebius free(p, PFI_MTYPE); 162240233Sglebius } 163240233Sglebius 164240233Sglebius mtx_destroy(&pfi_unlnkdkifs_mtx); 165240233Sglebius 166223637Sbz free(V_pfi_buffer, PFI_MTYPE); 167173822Smlaier} 168173822Smlaier 169171168Smlaierstruct pfi_kif * 170240233Sglebiuspfi_kif_find(const char *kif_name) 171130613Smlaier{ 172240233Sglebius struct pfi_kif_cmp s; 173130613Smlaier 174240233Sglebius PF_RULES_ASSERT(); 175240233Sglebius 176171168Smlaier bzero(&s, sizeof(s)); 177171168Smlaier strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name)); 178132567Smlaier 179240233Sglebius return (RB_FIND(pfi_ifhead, &V_pfi_ifs, (struct pfi_kif *)&s)); 180240233Sglebius} 181130613Smlaier 182240233Sglebiusstruct pfi_kif * 183240233Sglebiuspfi_kif_attach(struct pfi_kif *kif, const char *kif_name) 184240233Sglebius{ 185240233Sglebius struct pfi_kif *kif1; 186240233Sglebius 187240233Sglebius PF_RULES_WASSERT(); 188240233Sglebius KASSERT(kif != NULL, ("%s: null kif", __func__)); 189240233Sglebius 190240233Sglebius kif1 = pfi_kif_find(kif_name); 191240233Sglebius if (kif1 != NULL) { 192240233Sglebius free(kif, PFI_MTYPE); 193240233Sglebius return (kif1); 194240233Sglebius } 195240233Sglebius 196240233Sglebius bzero(kif, sizeof(*kif)); 197171168Smlaier strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name)); 198173825Smlaier /* 199173825Smlaier * It seems that the value of time_second is in unintialzied state 200173825Smlaier * when pf sets interface statistics clear time in boot phase if pf 201173825Smlaier * was statically linked to kernel. Instead of setting the bogus 202173825Smlaier * time value have pfi_get_ifaces handle this case. In 203240233Sglebius * pfi_get_ifaces it uses time_second if it sees the time is 0. 204173825Smlaier */ 205173825Smlaier kif->pfik_tzero = time_second > 1 ? time_second : 0; 206171168Smlaier TAILQ_INIT(&kif->pfik_dynaddrs); 207130613Smlaier 208223637Sbz RB_INSERT(pfi_ifhead, &V_pfi_ifs, kif); 209223637Sbz 210171168Smlaier return (kif); 211130613Smlaier} 212130613Smlaier 213130613Smlaiervoid 214240233Sglebiuspfi_kif_ref(struct pfi_kif *kif) 215130613Smlaier{ 216240233Sglebius 217240233Sglebius PF_RULES_WASSERT(); 218240233Sglebius kif->pfik_rulerefs++; 219130613Smlaier} 220130613Smlaier 221130613Smlaiervoid 222240233Sglebiuspfi_kif_unref(struct pfi_kif *kif) 223130613Smlaier{ 224130613Smlaier 225240233Sglebius PF_RULES_WASSERT(); 226240233Sglebius KASSERT(kif->pfik_rulerefs > 0, ("%s: %p has zero refs", __func__, kif)); 227171168Smlaier 228240233Sglebius kif->pfik_rulerefs--; 229240233Sglebius 230240233Sglebius if (kif->pfik_rulerefs > 0) 231171168Smlaier return; 232171168Smlaier 233240233Sglebius /* kif referencing an existing ifnet or group should exist. */ 234240233Sglebius if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == V_pfi_all) 235171168Smlaier return; 236171168Smlaier 237223637Sbz RB_REMOVE(pfi_ifhead, &V_pfi_ifs, kif); 238240233Sglebius 239240233Sglebius kif->pfik_flags |= PFI_IFLAG_REFS; 240240233Sglebius 241240233Sglebius mtx_lock(&pfi_unlnkdkifs_mtx); 242240233Sglebius LIST_INSERT_HEAD(&V_pfi_unlinked_kifs, kif, pfik_list); 243240233Sglebius mtx_unlock(&pfi_unlnkdkifs_mtx); 244130613Smlaier} 245130613Smlaier 246240233Sglebiusvoid 247240233Sglebiuspfi_kif_purge(void) 248240233Sglebius{ 249240233Sglebius struct pfi_kif *kif, *kif1; 250240233Sglebius 251240233Sglebius /* 252240233Sglebius * Do naive mark-and-sweep garbage collecting of old kifs. 253240233Sglebius * Reference flag is raised by pf_purge_expired_states(). 254240233Sglebius */ 255240233Sglebius mtx_lock(&pfi_unlnkdkifs_mtx); 256240233Sglebius LIST_FOREACH_SAFE(kif, &V_pfi_unlinked_kifs, pfik_list, kif1) { 257240233Sglebius if (!(kif->pfik_flags & PFI_IFLAG_REFS)) { 258240233Sglebius LIST_REMOVE(kif, pfik_list); 259240233Sglebius free(kif, PFI_MTYPE); 260240233Sglebius } else 261240233Sglebius kif->pfik_flags &= ~PFI_IFLAG_REFS; 262240233Sglebius } 263240233Sglebius mtx_unlock(&pfi_unlnkdkifs_mtx); 264240233Sglebius} 265240233Sglebius 266171168Smlaierint 267171168Smlaierpfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif) 268130613Smlaier{ 269171168Smlaier struct ifg_list *p; 270130613Smlaier 271171168Smlaier if (rule_kif == NULL || rule_kif == packet_kif) 272171168Smlaier return (1); 273171168Smlaier 274171168Smlaier if (rule_kif->pfik_group != NULL) 275240233Sglebius /* XXXGL: locking? */ 276171168Smlaier TAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next) 277171168Smlaier if (p->ifgl_group == rule_kif->pfik_group) 278171168Smlaier return (1); 279171168Smlaier 280171168Smlaier return (0); 281130610Smlaier} 282130610Smlaier 283240233Sglebiusstatic void 284130610Smlaierpfi_attach_ifnet(struct ifnet *ifp) 285130610Smlaier{ 286240233Sglebius struct pfi_kif *kif; 287130610Smlaier 288240233Sglebius kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); 289240233Sglebius 290240233Sglebius PF_RULES_WLOCK(); 291223637Sbz V_pfi_update++; 292240233Sglebius kif = pfi_kif_attach(kif, ifp->if_xname); 293130610Smlaier 294171168Smlaier kif->pfik_ifp = ifp; 295240233Sglebius ifp->if_pf_kif = kif; 296130610Smlaier 297171168Smlaier pfi_kif_update(kif); 298240233Sglebius PF_RULES_WUNLOCK(); 299130610Smlaier} 300130610Smlaier 301240233Sglebiusstatic void 302240233Sglebiuspfi_attach_ifgroup(struct ifg_group *ifg) 303130610Smlaier{ 304240233Sglebius struct pfi_kif *kif; 305130610Smlaier 306240233Sglebius kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); 307130610Smlaier 308240233Sglebius PF_RULES_WLOCK(); 309223637Sbz V_pfi_update++; 310240233Sglebius kif = pfi_kif_attach(kif, ifg->ifg_group); 311171168Smlaier 312171168Smlaier kif->pfik_group = ifg; 313240233Sglebius ifg->ifg_pf_kif = kif; 314240233Sglebius PF_RULES_WUNLOCK(); 315130610Smlaier} 316130610Smlaier 317171168Smlaierint 318171168Smlaierpfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) 319130610Smlaier{ 320171168Smlaier switch (af) { 321171168Smlaier#ifdef INET 322171168Smlaier case AF_INET: 323171168Smlaier switch (dyn->pfid_acnt4) { 324171168Smlaier case 0: 325171168Smlaier return (0); 326171168Smlaier case 1: 327171168Smlaier return (PF_MATCHA(0, &dyn->pfid_addr4, 328171168Smlaier &dyn->pfid_mask4, a, AF_INET)); 329171168Smlaier default: 330171168Smlaier return (pfr_match_addr(dyn->pfid_kt, a, AF_INET)); 331171168Smlaier } 332171168Smlaier break; 333171168Smlaier#endif /* INET */ 334171168Smlaier#ifdef INET6 335171168Smlaier case AF_INET6: 336171168Smlaier switch (dyn->pfid_acnt6) { 337171168Smlaier case 0: 338171168Smlaier return (0); 339171168Smlaier case 1: 340171168Smlaier return (PF_MATCHA(0, &dyn->pfid_addr6, 341171168Smlaier &dyn->pfid_mask6, a, AF_INET6)); 342171168Smlaier default: 343171168Smlaier return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6)); 344171168Smlaier } 345171168Smlaier break; 346171168Smlaier#endif /* INET6 */ 347171168Smlaier default: 348171168Smlaier return (0); 349130610Smlaier } 350130610Smlaier} 351130610Smlaier 352130610Smlaierint 353130610Smlaierpfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) 354130610Smlaier{ 355130610Smlaier struct pfi_dynaddr *dyn; 356130610Smlaier char tblname[PF_TABLE_NAME_SIZE]; 357130610Smlaier struct pf_ruleset *ruleset = NULL; 358240233Sglebius struct pfi_kif *kif; 359240233Sglebius int rv = 0; 360130610Smlaier 361240233Sglebius PF_RULES_WASSERT(); 362240233Sglebius KASSERT(aw->type == PF_ADDR_DYNIFTL, ("%s: type %u", 363240233Sglebius __func__, aw->type)); 364240233Sglebius KASSERT(aw->p.dyn == NULL, ("%s: dyn is %p", __func__, aw->p.dyn)); 365130610Smlaier 366240233Sglebius if ((dyn = malloc(sizeof(*dyn), PFI_MTYPE, M_NOWAIT | M_ZERO)) == NULL) 367240233Sglebius return (ENOMEM); 368240233Sglebius 369240233Sglebius if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_NOWAIT)) == NULL) { 370240233Sglebius free(dyn, PFI_MTYPE); 371240233Sglebius return (ENOMEM); 372240233Sglebius } 373240233Sglebius 374171168Smlaier if (!strcmp(aw->v.ifname, "self")) 375240233Sglebius dyn->pfid_kif = pfi_kif_attach(kif, IFG_ALL); 376171168Smlaier else 377240233Sglebius dyn->pfid_kif = pfi_kif_attach(kif, aw->v.ifname); 378240233Sglebius pfi_kif_ref(dyn->pfid_kif); 379130610Smlaier 380130610Smlaier dyn->pfid_net = pfi_unmask(&aw->v.a.mask); 381130610Smlaier if (af == AF_INET && dyn->pfid_net == 32) 382130610Smlaier dyn->pfid_net = 128; 383130610Smlaier strlcpy(tblname, aw->v.ifname, sizeof(tblname)); 384130610Smlaier if (aw->iflags & PFI_AFLAG_NETWORK) 385130610Smlaier strlcat(tblname, ":network", sizeof(tblname)); 386130610Smlaier if (aw->iflags & PFI_AFLAG_BROADCAST) 387130610Smlaier strlcat(tblname, ":broadcast", sizeof(tblname)); 388130610Smlaier if (aw->iflags & PFI_AFLAG_PEER) 389130610Smlaier strlcat(tblname, ":peer", sizeof(tblname)); 390130610Smlaier if (aw->iflags & PFI_AFLAG_NOALIAS) 391130610Smlaier strlcat(tblname, ":0", sizeof(tblname)); 392130610Smlaier if (dyn->pfid_net != 128) 393130610Smlaier snprintf(tblname + strlen(tblname), 394130610Smlaier sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net); 395171168Smlaier if ((ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR)) == NULL) { 396240233Sglebius rv = ENOMEM; 397171168Smlaier goto _bad; 398171168Smlaier } 399130610Smlaier 400240233Sglebius if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname)) == NULL) { 401240233Sglebius rv = ENOMEM; 402171168Smlaier goto _bad; 403171168Smlaier } 404130610Smlaier 405130610Smlaier dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE; 406130610Smlaier dyn->pfid_iflags = aw->iflags; 407130610Smlaier dyn->pfid_af = af; 408130610Smlaier 409171168Smlaier TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry); 410130610Smlaier aw->p.dyn = dyn; 411171168Smlaier pfi_kif_update(dyn->pfid_kif); 412240233Sglebius 413130610Smlaier return (0); 414130610Smlaier 415130610Smlaier_bad: 416130610Smlaier if (dyn->pfid_kt != NULL) 417130610Smlaier pfr_detach_table(dyn->pfid_kt); 418130610Smlaier if (ruleset != NULL) 419130610Smlaier pf_remove_if_empty_ruleset(ruleset); 420130610Smlaier if (dyn->pfid_kif != NULL) 421240233Sglebius pfi_kif_unref(dyn->pfid_kif); 422240233Sglebius free(dyn, PFI_MTYPE); 423240233Sglebius 424130610Smlaier return (rv); 425130610Smlaier} 426130610Smlaier 427240233Sglebiusstatic void 428171168Smlaierpfi_kif_update(struct pfi_kif *kif) 429130610Smlaier{ 430171168Smlaier struct ifg_list *ifgl; 431171168Smlaier struct pfi_dynaddr *p; 432171168Smlaier 433240233Sglebius PF_RULES_WASSERT(); 434240233Sglebius 435171168Smlaier /* update all dynaddr */ 436171168Smlaier TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry) 437171168Smlaier pfi_dynaddr_update(p); 438171168Smlaier 439171168Smlaier /* again for all groups kif is member of */ 440240233Sglebius if (kif->pfik_ifp != NULL) { 441240233Sglebius IF_ADDR_RLOCK(kif->pfik_ifp); 442171168Smlaier TAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next) 443171168Smlaier pfi_kif_update((struct pfi_kif *) 444171168Smlaier ifgl->ifgl_group->ifg_pf_kif); 445240233Sglebius IF_ADDR_RUNLOCK(kif->pfik_ifp); 446240233Sglebius } 447171168Smlaier} 448171168Smlaier 449240233Sglebiusstatic void 450171168Smlaierpfi_dynaddr_update(struct pfi_dynaddr *dyn) 451171168Smlaier{ 452145836Smlaier struct pfi_kif *kif; 453145836Smlaier struct pfr_ktable *kt; 454130610Smlaier 455240233Sglebius PF_RULES_WASSERT(); 456240233Sglebius KASSERT(dyn && dyn->pfid_kif && dyn->pfid_kt, 457240233Sglebius ("%s: bad argument", __func__)); 458145836Smlaier 459145836Smlaier kif = dyn->pfid_kif; 460145836Smlaier kt = dyn->pfid_kt; 461171168Smlaier 462223637Sbz if (kt->pfrkt_larg != V_pfi_update) { 463130610Smlaier /* this table needs to be brought up-to-date */ 464130610Smlaier pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags); 465223637Sbz kt->pfrkt_larg = V_pfi_update; 466130610Smlaier } 467130610Smlaier pfr_dynaddr_update(kt, dyn); 468130610Smlaier} 469130610Smlaier 470240233Sglebiusstatic void 471130610Smlaierpfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags) 472130610Smlaier{ 473130610Smlaier int e, size2 = 0; 474171168Smlaier struct ifg_member *ifgm; 475130610Smlaier 476223637Sbz V_pfi_buffer_cnt = 0; 477171168Smlaier 478171168Smlaier if (kif->pfik_ifp != NULL) 479130610Smlaier pfi_instance_add(kif->pfik_ifp, net, flags); 480240233Sglebius else if (kif->pfik_group != NULL) { 481244210Sglebius IFNET_RLOCK_NOSLEEP(); 482171168Smlaier TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next) 483171168Smlaier pfi_instance_add(ifgm->ifgm_ifp, net, flags); 484244210Sglebius IFNET_RUNLOCK_NOSLEEP(); 485240233Sglebius } 486171168Smlaier 487223637Sbz if ((e = pfr_set_addrs(&kt->pfrkt_t, V_pfi_buffer, V_pfi_buffer_cnt, &size2, 488223637Sbz NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK))) 489240233Sglebius printf("%s: cannot set %d new addresses into table %s: %d\n", 490240233Sglebius __func__, V_pfi_buffer_cnt, kt->pfrkt_name, e); 491130610Smlaier} 492130610Smlaier 493240233Sglebiusstatic void 494130610Smlaierpfi_instance_add(struct ifnet *ifp, int net, int flags) 495130610Smlaier{ 496130610Smlaier struct ifaddr *ia; 497130610Smlaier int got4 = 0, got6 = 0; 498130610Smlaier int net2, af; 499130610Smlaier 500240233Sglebius IF_ADDR_RLOCK(ifp); 501240233Sglebius TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_list) { 502130610Smlaier if (ia->ifa_addr == NULL) 503130610Smlaier continue; 504130610Smlaier af = ia->ifa_addr->sa_family; 505130610Smlaier if (af != AF_INET && af != AF_INET6) 506130610Smlaier continue; 507173825Smlaier /* 508173825Smlaier * XXX: For point-to-point interfaces, (ifname:0) and IPv4, 509223637Sbz * jump over addresses without a proper route to work 510223637Sbz * around a problem with ppp not fully removing the 511223637Sbz * address used during IPCP. 512173825Smlaier */ 513173825Smlaier if ((ifp->if_flags & IFF_POINTOPOINT) && 514173825Smlaier !(ia->ifa_flags & IFA_ROUTE) && 515173825Smlaier (flags & PFI_AFLAG_NOALIAS) && (af == AF_INET)) 516173825Smlaier continue; 517130610Smlaier if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6) 518130610Smlaier continue; 519130610Smlaier if ((flags & PFI_AFLAG_BROADCAST) && 520130610Smlaier !(ifp->if_flags & IFF_BROADCAST)) 521130610Smlaier continue; 522130610Smlaier if ((flags & PFI_AFLAG_PEER) && 523130610Smlaier !(ifp->if_flags & IFF_POINTOPOINT)) 524130610Smlaier continue; 525130610Smlaier if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 && 526130610Smlaier IN6_IS_ADDR_LINKLOCAL( 527130610Smlaier &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr)) 528130610Smlaier continue; 529130610Smlaier if (flags & PFI_AFLAG_NOALIAS) { 530130610Smlaier if (af == AF_INET && got4) 531130610Smlaier continue; 532130610Smlaier if (af == AF_INET6 && got6) 533130610Smlaier continue; 534130610Smlaier } 535130610Smlaier if (af == AF_INET) 536130610Smlaier got4 = 1; 537145836Smlaier else if (af == AF_INET6) 538130610Smlaier got6 = 1; 539130610Smlaier net2 = net; 540130610Smlaier if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) { 541171168Smlaier if (af == AF_INET) 542130610Smlaier net2 = pfi_unmask(&((struct sockaddr_in *) 543130610Smlaier ia->ifa_netmask)->sin_addr); 544171168Smlaier else if (af == AF_INET6) 545130610Smlaier net2 = pfi_unmask(&((struct sockaddr_in6 *) 546130610Smlaier ia->ifa_netmask)->sin6_addr); 547130610Smlaier } 548130610Smlaier if (af == AF_INET && net2 > 32) 549130610Smlaier net2 = 32; 550130610Smlaier if (flags & PFI_AFLAG_BROADCAST) 551130610Smlaier pfi_address_add(ia->ifa_broadaddr, af, net2); 552130610Smlaier else if (flags & PFI_AFLAG_PEER) 553130610Smlaier pfi_address_add(ia->ifa_dstaddr, af, net2); 554130610Smlaier else 555130610Smlaier pfi_address_add(ia->ifa_addr, af, net2); 556130610Smlaier } 557240233Sglebius IF_ADDR_RUNLOCK(ifp); 558130610Smlaier} 559130610Smlaier 560240233Sglebiusstatic void 561130610Smlaierpfi_address_add(struct sockaddr *sa, int af, int net) 562130610Smlaier{ 563130610Smlaier struct pfr_addr *p; 564130610Smlaier int i; 565130610Smlaier 566223637Sbz if (V_pfi_buffer_cnt >= V_pfi_buffer_max) { 567223637Sbz int new_max = V_pfi_buffer_max * 2; 568130610Smlaier 569130610Smlaier if (new_max > PFI_BUFFER_MAX) { 570240233Sglebius printf("%s: address buffer full (%d/%d)\n", __func__, 571223637Sbz V_pfi_buffer_cnt, PFI_BUFFER_MAX); 572130610Smlaier return; 573130610Smlaier } 574223637Sbz p = malloc(new_max * sizeof(*V_pfi_buffer), PFI_MTYPE, 575130613Smlaier M_NOWAIT); 576130610Smlaier if (p == NULL) { 577240233Sglebius printf("%s: no memory to grow buffer (%d/%d)\n", 578240233Sglebius __func__, V_pfi_buffer_cnt, PFI_BUFFER_MAX); 579130610Smlaier return; 580130610Smlaier } 581223637Sbz memcpy(V_pfi_buffer, p, V_pfi_buffer_cnt * sizeof(*V_pfi_buffer)); 582130610Smlaier /* no need to zero buffer */ 583223637Sbz free(V_pfi_buffer, PFI_MTYPE); 584223637Sbz V_pfi_buffer = p; 585223637Sbz V_pfi_buffer_max = new_max; 586130610Smlaier } 587130610Smlaier if (af == AF_INET && net > 32) 588130610Smlaier net = 128; 589223637Sbz p = V_pfi_buffer + V_pfi_buffer_cnt++; 590130610Smlaier bzero(p, sizeof(*p)); 591130610Smlaier p->pfra_af = af; 592130610Smlaier p->pfra_net = net; 593130610Smlaier if (af == AF_INET) 594130610Smlaier p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr; 595171168Smlaier else if (af == AF_INET6) { 596130610Smlaier p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr; 597171168Smlaier if (IN6_IS_SCOPE_EMBED(&p->pfra_ip6addr)) 598130610Smlaier p->pfra_ip6addr.s6_addr16[1] = 0; 599130610Smlaier } 600130610Smlaier /* mask network address bits */ 601130610Smlaier if (net < 128) 602130610Smlaier ((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8)); 603130610Smlaier for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++) 604130610Smlaier ((caddr_t)p)[i] = 0; 605130610Smlaier} 606130610Smlaier 607130610Smlaiervoid 608240233Sglebiuspfi_dynaddr_remove(struct pfi_dynaddr *dyn) 609130610Smlaier{ 610130610Smlaier 611240233Sglebius KASSERT(dyn->pfid_kif != NULL, ("%s: null pfid_kif", __func__)); 612240233Sglebius KASSERT(dyn->pfid_kt != NULL, ("%s: null pfid_kt", __func__)); 613130610Smlaier 614240233Sglebius TAILQ_REMOVE(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry); 615240233Sglebius pfi_kif_unref(dyn->pfid_kif); 616240233Sglebius pfr_detach_table(dyn->pfid_kt); 617240233Sglebius free(dyn, PFI_MTYPE); 618130610Smlaier} 619130610Smlaier 620130610Smlaiervoid 621130610Smlaierpfi_dynaddr_copyout(struct pf_addr_wrap *aw) 622130610Smlaier{ 623240233Sglebius 624240233Sglebius KASSERT(aw->type == PF_ADDR_DYNIFTL, 625240233Sglebius ("%s: type %u", __func__, aw->type)); 626240233Sglebius 627240233Sglebius if (aw->p.dyn == NULL || aw->p.dyn->pfid_kif == NULL) 628130610Smlaier return; 629130610Smlaier aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6; 630130610Smlaier} 631130610Smlaier 632240233Sglebiusstatic int 633130610Smlaierpfi_if_compare(struct pfi_kif *p, struct pfi_kif *q) 634130610Smlaier{ 635130610Smlaier return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ)); 636130610Smlaier} 637130610Smlaier 638130610Smlaiervoid 639223637Sbzpfi_update_status(const char *name, struct pf_status *pfs) 640130610Smlaier{ 641171168Smlaier struct pfi_kif *p; 642223637Sbz struct pfi_kif_cmp key; 643223637Sbz struct ifg_member p_member, *ifgm; 644223637Sbz TAILQ_HEAD(, ifg_member) ifg_members; 645240233Sglebius int i, j, k; 646130610Smlaier 647223637Sbz strlcpy(key.pfik_name, name, sizeof(key.pfik_name)); 648223637Sbz p = RB_FIND(pfi_ifhead, &V_pfi_ifs, (struct pfi_kif *)&key); 649240233Sglebius if (p == NULL) 650130610Smlaier return; 651240233Sglebius 652223637Sbz if (p->pfik_group != NULL) { 653223637Sbz bcopy(&p->pfik_group->ifg_members, &ifg_members, 654223637Sbz sizeof(ifg_members)); 655223637Sbz } else { 656223637Sbz /* build a temporary list for p only */ 657223637Sbz bzero(&p_member, sizeof(p_member)); 658223637Sbz p_member.ifgm_ifp = p->pfik_ifp; 659223637Sbz TAILQ_INIT(&ifg_members); 660223637Sbz TAILQ_INSERT_TAIL(&ifg_members, &p_member, ifgm_next); 661223637Sbz } 662223637Sbz if (pfs) { 663223637Sbz bzero(pfs->pcounters, sizeof(pfs->pcounters)); 664223637Sbz bzero(pfs->bcounters, sizeof(pfs->bcounters)); 665223637Sbz } 666223637Sbz TAILQ_FOREACH(ifgm, &ifg_members, ifgm_next) { 667223637Sbz if (ifgm->ifgm_ifp == NULL) 668223637Sbz continue; 669223637Sbz p = (struct pfi_kif *)ifgm->ifgm_ifp->if_pf_kif; 670130610Smlaier 671223637Sbz /* just clear statistics */ 672223637Sbz if (pfs == NULL) { 673223637Sbz bzero(p->pfik_packets, sizeof(p->pfik_packets)); 674223637Sbz bzero(p->pfik_bytes, sizeof(p->pfik_bytes)); 675223637Sbz p->pfik_tzero = time_second; 676130610Smlaier continue; 677223637Sbz } 678223637Sbz for (i = 0; i < 2; i++) 679223637Sbz for (j = 0; j < 2; j++) 680223637Sbz for (k = 0; k < 2; k++) { 681223637Sbz pfs->pcounters[i][j][k] += 682223637Sbz p->pfik_packets[i][j][k]; 683223637Sbz pfs->bcounters[i][j] += 684223637Sbz p->pfik_bytes[i][j][k]; 685223637Sbz } 686130610Smlaier } 687145836Smlaier} 688145836Smlaier 689240233Sglebiusvoid 690171168Smlaierpfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size) 691145836Smlaier{ 692171168Smlaier struct pfi_kif *p, *nextp; 693240233Sglebius int n = 0; 694130610Smlaier 695223637Sbz for (p = RB_MIN(pfi_ifhead, &V_pfi_ifs); p; p = nextp) { 696223637Sbz nextp = RB_NEXT(pfi_ifhead, &V_pfi_ifs, p); 697171168Smlaier if (pfi_skip_if(name, p)) 698130610Smlaier continue; 699240233Sglebius if (*size <= n++) 700240233Sglebius break; 701240233Sglebius if (!p->pfik_tzero) 702240233Sglebius p->pfik_tzero = time_second; 703240233Sglebius bcopy(p, buf++, sizeof(*buf)); 704240233Sglebius nextp = RB_NEXT(pfi_ifhead, &V_pfi_ifs, p); 705130610Smlaier } 706130610Smlaier *size = n; 707130610Smlaier} 708130610Smlaier 709240233Sglebiusstatic int 710171168Smlaierpfi_skip_if(const char *filter, struct pfi_kif *p) 711130610Smlaier{ 712130610Smlaier int n; 713130610Smlaier 714130610Smlaier if (filter == NULL || !*filter) 715130610Smlaier return (0); 716130610Smlaier if (!strcmp(p->pfik_name, filter)) 717130610Smlaier return (0); /* exact match */ 718130610Smlaier n = strlen(filter); 719130610Smlaier if (n < 1 || n >= IFNAMSIZ) 720130610Smlaier return (1); /* sanity check */ 721130610Smlaier if (filter[n-1] >= '0' && filter[n-1] <= '9') 722130610Smlaier return (1); /* only do exact match in that case */ 723130610Smlaier if (strncmp(p->pfik_name, filter, n)) 724130610Smlaier return (1); /* prefix doesn't match */ 725130610Smlaier return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9'); 726130610Smlaier} 727130610Smlaier 728171168Smlaierint 729171168Smlaierpfi_set_flags(const char *name, int flags) 730171168Smlaier{ 731171168Smlaier struct pfi_kif *p; 732171168Smlaier 733223637Sbz RB_FOREACH(p, pfi_ifhead, &V_pfi_ifs) { 734171168Smlaier if (pfi_skip_if(name, p)) 735171168Smlaier continue; 736171168Smlaier p->pfik_flags |= flags; 737171168Smlaier } 738171168Smlaier return (0); 739171168Smlaier} 740171168Smlaier 741171168Smlaierint 742171168Smlaierpfi_clear_flags(const char *name, int flags) 743171168Smlaier{ 744171168Smlaier struct pfi_kif *p; 745171168Smlaier 746223637Sbz RB_FOREACH(p, pfi_ifhead, &V_pfi_ifs) { 747171168Smlaier if (pfi_skip_if(name, p)) 748171168Smlaier continue; 749171168Smlaier p->pfik_flags &= ~flags; 750171168Smlaier } 751171168Smlaier return (0); 752171168Smlaier} 753171168Smlaier 754130610Smlaier/* from pf_print_state.c */ 755240233Sglebiusstatic int 756130610Smlaierpfi_unmask(void *addr) 757130610Smlaier{ 758130610Smlaier struct pf_addr *m = addr; 759130610Smlaier int i = 31, j = 0, b = 0; 760130610Smlaier u_int32_t tmp; 761130610Smlaier 762130610Smlaier while (j < 4 && m->addr32[j] == 0xffffffff) { 763130610Smlaier b += 32; 764130610Smlaier j++; 765130610Smlaier } 766130610Smlaier if (j < 4) { 767130610Smlaier tmp = ntohl(m->addr32[j]); 768130610Smlaier for (i = 31; tmp & (1 << i); --i) 769130610Smlaier b++; 770130610Smlaier } 771130610Smlaier return (b); 772130610Smlaier} 773130610Smlaier 774240233Sglebiusstatic void 775171168Smlaierpfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp) 776130610Smlaier{ 777223637Sbz 778223637Sbz CURVNET_SET(ifp->if_vnet); 779171168Smlaier pfi_attach_ifnet(ifp); 780177700Smlaier#ifdef ALTQ 781240233Sglebius PF_RULES_WLOCK(); 782177700Smlaier pf_altq_ifnet_event(ifp, 0); 783240233Sglebius PF_RULES_WUNLOCK(); 784177700Smlaier#endif 785223637Sbz CURVNET_RESTORE(); 786130610Smlaier} 787130610Smlaier 788240233Sglebiusstatic void 789171168Smlaierpfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp) 790130610Smlaier{ 791240233Sglebius struct pfi_kif *kif = (struct pfi_kif *)ifp->if_pf_kif; 792223637Sbz 793223637Sbz CURVNET_SET(ifp->if_vnet); 794240233Sglebius PF_RULES_WLOCK(); 795240233Sglebius V_pfi_update++; 796240233Sglebius pfi_kif_update(kif); 797240233Sglebius 798240233Sglebius kif->pfik_ifp = NULL; 799240233Sglebius ifp->if_pf_kif = NULL; 800177700Smlaier#ifdef ALTQ 801177700Smlaier pf_altq_ifnet_event(ifp, 1); 802177700Smlaier#endif 803240233Sglebius PF_RULES_WUNLOCK(); 804223637Sbz CURVNET_RESTORE(); 805130610Smlaier} 806171168Smlaier 807240233Sglebiusstatic void 808223637Sbzpfi_attach_group_event(void *arg , struct ifg_group *ifg) 809171168Smlaier{ 810223637Sbz 811223637Sbz CURVNET_SET((struct vnet *)arg); 812171168Smlaier pfi_attach_ifgroup(ifg); 813223637Sbz CURVNET_RESTORE(); 814171168Smlaier} 815171168Smlaier 816240233Sglebiusstatic void 817223637Sbzpfi_change_group_event(void *arg, char *gname) 818171168Smlaier{ 819240233Sglebius struct pfi_kif *kif; 820223637Sbz 821240233Sglebius kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); 822240233Sglebius 823223637Sbz CURVNET_SET((struct vnet *)arg); 824240233Sglebius PF_RULES_WLOCK(); 825240233Sglebius V_pfi_update++; 826240233Sglebius kif = pfi_kif_attach(kif, gname); 827240233Sglebius pfi_kif_update(kif); 828240233Sglebius PF_RULES_WUNLOCK(); 829223637Sbz CURVNET_RESTORE(); 830171168Smlaier} 831171168Smlaier 832240233Sglebiusstatic void 833223637Sbzpfi_detach_group_event(void *arg, struct ifg_group *ifg) 834171168Smlaier{ 835240233Sglebius struct pfi_kif *kif = (struct pfi_kif *)ifg->ifg_pf_kif; 836223637Sbz 837223637Sbz CURVNET_SET((struct vnet *)arg); 838240233Sglebius PF_RULES_WLOCK(); 839240233Sglebius V_pfi_update++; 840240233Sglebius 841240233Sglebius kif->pfik_group = NULL; 842240233Sglebius ifg->ifg_pf_kif = NULL; 843240233Sglebius PF_RULES_WUNLOCK(); 844223637Sbz CURVNET_RESTORE(); 845171168Smlaier} 846171168Smlaier 847240233Sglebiusstatic void 848171168Smlaierpfi_ifaddr_event(void *arg __unused, struct ifnet *ifp) 849171168Smlaier{ 850223637Sbz 851223637Sbz CURVNET_SET(ifp->if_vnet); 852240233Sglebius PF_RULES_WLOCK(); 853240233Sglebius if (ifp && ifp->if_pf_kif) { 854240233Sglebius V_pfi_update++; 855240233Sglebius pfi_kif_update(ifp->if_pf_kif); 856240233Sglebius } 857240233Sglebius PF_RULES_WUNLOCK(); 858223637Sbz CURVNET_RESTORE(); 859171168Smlaier} 860