1 /* $NetBSD: pf_if.c,v 1.24 2013/07/01 08:32:48 skrll Exp $ */ 2 /* $OpenBSD: pf_if.c,v 1.47 2007/07/13 09:17:48 markus Exp $ */ 3 4 /* 5 * Copyright 2005 Henning Brauer <henning@openbsd.org> 6 * Copyright 2005 Ryan McBride <mcbride@openbsd.org> 7 * Copyright (c) 2001 Daniel Hartmeier 8 * Copyright (c) 2003 Cedric Berger 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 15 * - Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * - Redistributions in binary form must reproduce the above 18 * copyright notice, this list of conditions and the following 19 * disclaimer in the documentation and/or other materials provided 20 * with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: pf_if.c,v 1.24 2013/07/01 08:32:48 skrll Exp $"); 38 39 #ifdef _KERNEL_OPT 40 #include "opt_inet.h" 41 #endif 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/mbuf.h> 46 #include <sys/filio.h> 47 #include <sys/socket.h> 48 #include <sys/socketvar.h> 49 #include <sys/kernel.h> 50 #include <sys/device.h> 51 #include <sys/time.h> 52 53 #include <net/if.h> 54 #include <net/if_types.h> 55 56 #include <netinet/in.h> 57 #include <netinet/in_var.h> 58 #include <netinet/in_systm.h> 59 #include <netinet/ip.h> 60 #include <netinet/ip_var.h> 61 62 #include <net/pfvar.h> 63 64 #ifdef INET6 65 #include <netinet/ip6.h> 66 #endif /* INET6 */ 67 68 struct pfi_kif *pfi_all = NULL; 69 struct pool pfi_addr_pl; 70 struct pfi_ifhead pfi_ifs; 71 long pfi_update = 1; 72 struct pfr_addr *pfi_buffer; 73 int pfi_buffer_cnt; 74 int pfi_buffer_max; 75 76 void pfi_kif_update(struct pfi_kif *); 77 void pfi_dynaddr_update(struct pfi_dynaddr *dyn); 78 void pfi_table_update(struct pfr_ktable *, struct pfi_kif *, 79 int, int); 80 void pfi_kifaddr_update(void *); 81 void pfi_instance_add(struct ifnet *, int, int); 82 void pfi_address_add(struct sockaddr *, int, int); 83 int pfi_if_compare(struct pfi_kif *, struct pfi_kif *); 84 int pfi_skip_if(const char *, struct pfi_kif *); 85 int pfi_unmask(void *); 86 #ifdef __NetBSD__ 87 void pfi_init_groups(struct ifnet *); 88 void pfi_destroy_groups(struct ifnet *); 89 90 int pfil_ifnet_wrapper(void *, struct mbuf **, struct ifnet *, int); 91 int pfil_ifaddr_wrapper(void *, struct mbuf **, struct ifnet *, int); 92 #endif 93 94 RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); 95 RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); 96 97 #define PFI_BUFFER_MAX 0x10000 98 #define PFI_MTYPE M_IFADDR 99 100 void 101 pfi_initialize(void) 102 { 103 #ifdef __NetBSD__ 104 int i; 105 #endif /* __NetBSD__ */ 106 107 if (pfi_all != NULL) /* already initialized */ 108 return; 109 110 #ifdef __NetBSD__ 111 pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0, 112 "pfiaddrpl", &pool_allocator_nointr, IPL_NONE); 113 #else 114 pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0, 115 "pfiaddrpl", &pool_allocator_nointr); 116 #endif /* !__NetBSD__ */ 117 pfi_buffer_max = 64; 118 pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer), 119 PFI_MTYPE, M_WAITOK); 120 121 if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL) 122 panic("pfi_kif_get for pfi_all failed"); 123 124 #ifdef __NetBSD__ 125 for (i = 0; i < if_indexlim; i++) { 126 struct ifnet *ifp = ifindex2ifnet[i]; 127 128 if (ifp != NULL) { 129 pfi_init_groups(ifp); 130 131 pfi_attach_ifnet(ifp); 132 } 133 } 134 135 pfil_add_hook(pfil_ifnet_wrapper, NULL, PFIL_IFNET, if_pfil); 136 pfil_add_hook(pfil_ifaddr_wrapper, NULL, PFIL_IFADDR, if_pfil); 137 #endif /* __NetBSD__ */ 138 } 139 140 #ifdef _MODULE 141 void 142 pfi_destroy(void) 143 { 144 struct pfi_kif *p; 145 int i; 146 147 pfil_remove_hook(pfil_ifaddr_wrapper, NULL, PFIL_IFADDR, if_pfil); 148 pfil_remove_hook(pfil_ifnet_wrapper, NULL, PFIL_IFNET, if_pfil); 149 150 for (i = 0; i < if_indexlim; i++) { 151 struct ifnet *ifp = ifindex2ifnet[i]; 152 153 if (ifp != NULL) { 154 pfi_detach_ifnet(ifp); 155 156 pfi_destroy_groups(ifp); 157 } 158 } 159 160 while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) { 161 RB_REMOVE(pfi_ifhead, &pfi_ifs, p); 162 free(p, PFI_MTYPE); 163 } 164 165 pool_destroy(&pfi_addr_pl); 166 167 free(pfi_buffer, PFI_MTYPE); 168 } 169 #endif /* _MODULE */ 170 171 struct pfi_kif * 172 pfi_kif_get(const char *kif_name) 173 { 174 struct pfi_kif *kif; 175 struct pfi_kif_cmp s; 176 177 bzero(&s, sizeof(s)); 178 strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name)); 179 if ((kif = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s)) != NULL) 180 return (kif); 181 182 /* create new one */ 183 if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_NOWAIT|M_ZERO)) == NULL) 184 return (NULL); 185 186 strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name)); 187 #ifdef __NetBSD__ 188 /* time_second is not valid yet */ 189 kif->pfik_tzero = (time_second > 7200) ? time_second : 0; 190 #else 191 kif->pfik_tzero = time_second; 192 #endif /* !__NetBSD__ */ 193 TAILQ_INIT(&kif->pfik_dynaddrs); 194 195 RB_INSERT(pfi_ifhead, &pfi_ifs, kif); 196 return (kif); 197 } 198 199 void 200 pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what) 201 { 202 switch (what) { 203 case PFI_KIF_REF_RULE: 204 kif->pfik_rules++; 205 break; 206 case PFI_KIF_REF_STATE: 207 kif->pfik_states++; 208 break; 209 default: 210 panic("pfi_kif_ref with unknown type"); 211 } 212 } 213 214 void 215 pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what) 216 { 217 if (kif == NULL) 218 return; 219 220 switch (what) { 221 case PFI_KIF_REF_NONE: 222 break; 223 case PFI_KIF_REF_RULE: 224 if (kif->pfik_rules <= 0) { 225 printf("pfi_kif_unref: rules refcount <= 0\n"); 226 return; 227 } 228 kif->pfik_rules--; 229 break; 230 case PFI_KIF_REF_STATE: 231 if (kif->pfik_states <= 0) { 232 printf("pfi_kif_unref: state refcount <= 0\n"); 233 return; 234 } 235 kif->pfik_states--; 236 break; 237 default: 238 panic("pfi_kif_unref with unknown type"); 239 } 240 241 if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all) 242 return; 243 244 if (kif->pfik_rules || kif->pfik_states) 245 return; 246 247 RB_REMOVE(pfi_ifhead, &pfi_ifs, kif); 248 free(kif, PFI_MTYPE); 249 } 250 251 int 252 pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif) 253 { 254 struct ifg_list *p; 255 256 if (rule_kif == NULL || rule_kif == packet_kif) 257 return (1); 258 259 if (rule_kif->pfik_group != NULL) { 260 struct ifg_list_head *ifgh = 261 if_get_groups(packet_kif->pfik_ifp); 262 263 TAILQ_FOREACH(p, ifgh, ifgl_next) 264 if (p->ifgl_group == rule_kif->pfik_group) 265 return (1); 266 } 267 268 return (0); 269 } 270 271 void 272 pfi_attach_ifnet(struct ifnet *ifp) 273 { 274 struct pfi_kif *kif; 275 int s; 276 277 pfi_initialize(); 278 s = splsoftnet(); 279 pfi_update++; 280 if ((kif = pfi_kif_get(ifp->if_xname)) == NULL) 281 panic("pfi_kif_get failed"); 282 283 kif->pfik_ifp = ifp; 284 ifp->if_pf_kif = kif; 285 286 #ifndef __NetBSD__ 287 if ((kif->pfik_ah_cookie = hook_establish(ifp->if_addrhooks, 1, 288 pfi_kifaddr_update, kif)) == NULL) 289 panic("pfi_attach_ifnet: cannot allocate '%s' address hook", 290 ifp->if_xname); 291 #endif /* !__NetBSD__ */ 292 293 pfi_kif_update(kif); 294 295 splx(s); 296 } 297 298 void 299 pfi_detach_ifnet(struct ifnet *ifp) 300 { 301 int s; 302 struct pfi_kif *kif; 303 304 if ((kif = (struct pfi_kif *)ifp->if_pf_kif) == NULL) 305 return; 306 307 s = splsoftnet(); 308 pfi_update++; 309 #ifndef __NetBSD__ 310 hook_disestablish(ifp->if_addrhooks, kif->pfik_ah_cookie); 311 #endif /* !__NetBSD__ */ 312 pfi_kif_update(kif); 313 314 kif->pfik_ifp = NULL; 315 ifp->if_pf_kif = NULL; 316 pfi_kif_unref(kif, PFI_KIF_REF_NONE); 317 splx(s); 318 } 319 320 void 321 pfi_attach_ifgroup(struct ifg_group *ifg) 322 { 323 struct pfi_kif *kif; 324 int s; 325 326 pfi_initialize(); 327 s = splsoftnet(); 328 pfi_update++; 329 if ((kif = pfi_kif_get(ifg->ifg_group)) == NULL) 330 panic("pfi_kif_get failed"); 331 332 kif->pfik_group = ifg; 333 ifg->ifg_pf_kif = kif; 334 335 splx(s); 336 } 337 338 void 339 pfi_detach_ifgroup(struct ifg_group *ifg) 340 { 341 int s; 342 struct pfi_kif *kif; 343 344 if ((kif = (struct pfi_kif *)ifg->ifg_pf_kif) == NULL) 345 return; 346 347 s = splsoftnet(); 348 pfi_update++; 349 350 kif->pfik_group = NULL; 351 ifg->ifg_pf_kif = NULL; 352 pfi_kif_unref(kif, PFI_KIF_REF_NONE); 353 splx(s); 354 } 355 356 void 357 pfi_group_change(const char *group) 358 { 359 struct pfi_kif *kif; 360 int s; 361 362 s = splsoftnet(); 363 pfi_update++; 364 if ((kif = pfi_kif_get(group)) == NULL) 365 panic("pfi_kif_get failed"); 366 367 pfi_kif_update(kif); 368 369 splx(s); 370 } 371 372 int 373 pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) 374 { 375 switch (af) { 376 #ifdef INET 377 case AF_INET: 378 switch (dyn->pfid_acnt4) { 379 case 0: 380 return (0); 381 case 1: 382 return (PF_MATCHA(0, &dyn->pfid_addr4, 383 &dyn->pfid_mask4, a, AF_INET)); 384 default: 385 return (pfr_match_addr(dyn->pfid_kt, a, AF_INET)); 386 } 387 break; 388 #endif /* INET */ 389 #ifdef INET6 390 case AF_INET6: 391 switch (dyn->pfid_acnt6) { 392 case 0: 393 return (0); 394 case 1: 395 return (PF_MATCHA(0, &dyn->pfid_addr6, 396 &dyn->pfid_mask6, a, AF_INET6)); 397 default: 398 return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6)); 399 } 400 break; 401 #endif /* INET6 */ 402 default: 403 return (0); 404 } 405 } 406 407 int 408 pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) 409 { 410 struct pfi_dynaddr *dyn; 411 char tblname[PF_TABLE_NAME_SIZE]; 412 struct pf_ruleset *ruleset = NULL; 413 int s, rv = 0; 414 415 if (aw->type != PF_ADDR_DYNIFTL) 416 return (0); 417 if ((dyn = pool_get(&pfi_addr_pl, PR_NOWAIT)) == NULL) 418 return (1); 419 bzero(dyn, sizeof(*dyn)); 420 421 s = splsoftnet(); 422 if (!strcmp(aw->v.ifname, "self")) 423 dyn->pfid_kif = pfi_kif_get(IFG_ALL); 424 else 425 dyn->pfid_kif = pfi_kif_get(aw->v.ifname); 426 if (dyn->pfid_kif == NULL) { 427 rv = 1; 428 goto _bad; 429 } 430 pfi_kif_ref(dyn->pfid_kif, PFI_KIF_REF_RULE); 431 432 dyn->pfid_net = pfi_unmask(&aw->v.a.mask); 433 if (af == AF_INET && dyn->pfid_net == 32) 434 dyn->pfid_net = 128; 435 strlcpy(tblname, aw->v.ifname, sizeof(tblname)); 436 if (aw->iflags & PFI_AFLAG_NETWORK) 437 strlcat(tblname, ":network", sizeof(tblname)); 438 if (aw->iflags & PFI_AFLAG_BROADCAST) 439 strlcat(tblname, ":broadcast", sizeof(tblname)); 440 if (aw->iflags & PFI_AFLAG_PEER) 441 strlcat(tblname, ":peer", sizeof(tblname)); 442 if (aw->iflags & PFI_AFLAG_NOALIAS) 443 strlcat(tblname, ":0", sizeof(tblname)); 444 if (dyn->pfid_net != 128) 445 snprintf(tblname + strlen(tblname), 446 sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net); 447 if ((ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR)) == NULL) { 448 rv = 1; 449 goto _bad; 450 } 451 452 if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname)) == NULL) { 453 rv = 1; 454 goto _bad; 455 } 456 457 dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE; 458 dyn->pfid_iflags = aw->iflags; 459 dyn->pfid_af = af; 460 461 TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry); 462 aw->p.dyn = dyn; 463 pfi_kif_update(dyn->pfid_kif); 464 splx(s); 465 return (0); 466 467 _bad: 468 if (dyn->pfid_kt != NULL) 469 pfr_detach_table(dyn->pfid_kt); 470 if (ruleset != NULL) 471 pf_remove_if_empty_ruleset(ruleset); 472 if (dyn->pfid_kif != NULL) 473 pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE); 474 pool_put(&pfi_addr_pl, dyn); 475 splx(s); 476 return (rv); 477 } 478 479 void 480 pfi_kif_update(struct pfi_kif *kif) 481 { 482 struct ifg_list *ifgl; 483 struct pfi_dynaddr *p; 484 485 /* update all dynaddr */ 486 TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry) 487 pfi_dynaddr_update(p); 488 489 /* again for all groups kif is member of */ 490 if (kif->pfik_ifp != NULL) { 491 struct ifg_list_head *ifgh = if_get_groups(kif->pfik_ifp); 492 493 TAILQ_FOREACH(ifgl, ifgh, ifgl_next) 494 pfi_kif_update((struct pfi_kif *) 495 ifgl->ifgl_group->ifg_pf_kif); 496 } 497 } 498 499 void 500 pfi_dynaddr_update(struct pfi_dynaddr *dyn) 501 { 502 struct pfi_kif *kif; 503 struct pfr_ktable *kt; 504 505 if (dyn == NULL || dyn->pfid_kif == NULL || dyn->pfid_kt == NULL) 506 panic("pfi_dynaddr_update"); 507 508 kif = dyn->pfid_kif; 509 kt = dyn->pfid_kt; 510 511 if (kt->pfrkt_larg != pfi_update) { 512 /* this table needs to be brought up-to-date */ 513 pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags); 514 kt->pfrkt_larg = pfi_update; 515 } 516 pfr_dynaddr_update(kt, dyn); 517 } 518 519 void 520 pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags) 521 { 522 int e, size2 = 0; 523 struct ifg_member *ifgm; 524 525 pfi_buffer_cnt = 0; 526 527 if (kif->pfik_ifp != NULL) 528 pfi_instance_add(kif->pfik_ifp, net, flags); 529 else if (kif->pfik_group != NULL) 530 TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next) 531 pfi_instance_add(ifgm->ifgm_ifp, net, flags); 532 533 if ((e = pfr_set_addrs(&kt->pfrkt_t, pfi_buffer, pfi_buffer_cnt, &size2, 534 NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK))) 535 printf("pfi_table_update: cannot set %d new addresses " 536 "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e); 537 } 538 539 void 540 pfi_instance_add(struct ifnet *ifp, int net, int flags) 541 { 542 struct ifaddr *ia; 543 int got4 = 0, got6 = 0; 544 int net2, af; 545 546 if (ifp == NULL) 547 return; 548 IFADDR_FOREACH(ia, ifp) { 549 if (ia->ifa_addr == NULL) 550 continue; 551 af = ia->ifa_addr->sa_family; 552 if (af != AF_INET && af != AF_INET6) 553 continue; 554 if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6) 555 continue; 556 if ((flags & PFI_AFLAG_BROADCAST) && 557 !(ifp->if_flags & IFF_BROADCAST)) 558 continue; 559 if ((flags & PFI_AFLAG_PEER) && 560 !(ifp->if_flags & IFF_POINTOPOINT)) 561 continue; 562 if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 && 563 IN6_IS_ADDR_LINKLOCAL( 564 &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr)) 565 continue; 566 if (flags & PFI_AFLAG_NOALIAS) { 567 if (af == AF_INET && got4) 568 continue; 569 if (af == AF_INET6 && got6) 570 continue; 571 } 572 if (af == AF_INET) 573 got4 = 1; 574 else if (af == AF_INET6) 575 got6 = 1; 576 net2 = net; 577 if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) { 578 if (af == AF_INET) 579 net2 = pfi_unmask(&((struct sockaddr_in *) 580 ia->ifa_netmask)->sin_addr); 581 else if (af == AF_INET6) 582 net2 = pfi_unmask(&((struct sockaddr_in6 *) 583 ia->ifa_netmask)->sin6_addr); 584 } 585 if (af == AF_INET && net2 > 32) 586 net2 = 32; 587 if (flags & PFI_AFLAG_BROADCAST) 588 pfi_address_add(ia->ifa_broadaddr, af, net2); 589 else if (flags & PFI_AFLAG_PEER) 590 pfi_address_add(ia->ifa_dstaddr, af, net2); 591 else 592 pfi_address_add(ia->ifa_addr, af, net2); 593 } 594 } 595 596 void 597 pfi_address_add(struct sockaddr *sa, int af, int net) 598 { 599 struct pfr_addr *p; 600 int i; 601 602 if (pfi_buffer_cnt >= pfi_buffer_max) { 603 int new_max = pfi_buffer_max * 2; 604 605 if (new_max > PFI_BUFFER_MAX) { 606 printf("pfi_address_add: address buffer full (%d/%d)\n", 607 pfi_buffer_cnt, PFI_BUFFER_MAX); 608 return; 609 } 610 p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE, M_NOWAIT); 611 if (p == NULL) { 612 printf("pfi_address_add: no memory to grow buffer " 613 "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX); 614 return; 615 } 616 memcpy(p, pfi_buffer, pfi_buffer_cnt * sizeof(*pfi_buffer)); 617 /* no need to zero buffer */ 618 free(pfi_buffer, PFI_MTYPE); 619 pfi_buffer = p; 620 pfi_buffer_max = new_max; 621 } 622 if (af == AF_INET && net > 32) 623 net = 128; 624 p = pfi_buffer + pfi_buffer_cnt++; 625 bzero(p, sizeof(*p)); 626 p->pfra_af = af; 627 p->pfra_net = net; 628 if (af == AF_INET) 629 p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr; 630 else if (af == AF_INET6) { 631 p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr; 632 if (IN6_IS_SCOPE_EMBEDDABLE(&p->pfra_ip6addr)) 633 p->pfra_ip6addr.s6_addr16[1] = 0; 634 } 635 /* mask network address bits */ 636 if (net < 128) 637 ((char *)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8)); 638 for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++) 639 ((char *)p)[i] = 0; 640 } 641 642 void 643 pfi_dynaddr_remove(struct pf_addr_wrap *aw) 644 { 645 int s; 646 647 if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL || 648 aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL) 649 return; 650 651 s = splsoftnet(); 652 TAILQ_REMOVE(&aw->p.dyn->pfid_kif->pfik_dynaddrs, aw->p.dyn, entry); 653 pfi_kif_unref(aw->p.dyn->pfid_kif, PFI_KIF_REF_RULE); 654 aw->p.dyn->pfid_kif = NULL; 655 pfr_detach_table(aw->p.dyn->pfid_kt); 656 aw->p.dyn->pfid_kt = NULL; 657 pool_put(&pfi_addr_pl, aw->p.dyn); 658 aw->p.dyn = NULL; 659 splx(s); 660 } 661 662 void 663 pfi_dynaddr_copyout(struct pf_addr_wrap *aw) 664 { 665 if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL || 666 aw->p.dyn->pfid_kif == NULL) 667 return; 668 aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6; 669 } 670 671 void 672 pfi_kifaddr_update(void *v) 673 { 674 int s; 675 struct pfi_kif *kif = (struct pfi_kif *)v; 676 677 s = splsoftnet(); 678 pfi_update++; 679 pfi_kif_update(kif); 680 splx(s); 681 } 682 683 int 684 pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q) 685 { 686 return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ)); 687 } 688 689 void 690 pfi_fill_oldstatus(struct pf_status *pfs) 691 { 692 struct pfi_kif *p; 693 struct pfi_kif_cmp key; 694 int i, j, k, s; 695 696 strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name)); 697 s = splsoftnet(); 698 p = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&key); 699 if (p == NULL) { 700 splx(s); 701 return; 702 } 703 bzero(pfs->pcounters, sizeof(pfs->pcounters)); 704 bzero(pfs->bcounters, sizeof(pfs->bcounters)); 705 for (i = 0; i < 2; i++) 706 for (j = 0; j < 2; j++) 707 for (k = 0; k < 2; k++) { 708 pfs->pcounters[i][j][k] = 709 p->pfik_packets[i][j][k]; 710 pfs->bcounters[i][j] += 711 p->pfik_bytes[i][j][k]; 712 } 713 splx(s); 714 } 715 716 int 717 pfi_clr_istats(const char *name) 718 { 719 struct pfi_kif *p; 720 int s; 721 722 s = splsoftnet(); 723 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 724 if (pfi_skip_if(name, p)) 725 continue; 726 bzero(p->pfik_packets, sizeof(p->pfik_packets)); 727 bzero(p->pfik_bytes, sizeof(p->pfik_bytes)); 728 p->pfik_tzero = time_second; 729 } 730 splx(s); 731 732 return (0); 733 } 734 735 int 736 pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size) 737 { 738 struct pfi_kif *p, *nextp; 739 int s, n = 0; 740 741 s = splsoftnet(); 742 for (p = RB_MIN(pfi_ifhead, &pfi_ifs); p; p = nextp) { 743 nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p); 744 if (pfi_skip_if(name, p)) 745 continue; 746 if (*size > n++) { 747 if (!p->pfik_tzero) 748 p->pfik_tzero = time_second; 749 pfi_kif_ref(p, PFI_KIF_REF_RULE); 750 if (copyout(p, buf++, sizeof(*buf))) { 751 pfi_kif_unref(p, PFI_KIF_REF_RULE); 752 splx(s); 753 return (EFAULT); 754 } 755 nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p); 756 pfi_kif_unref(p, PFI_KIF_REF_RULE); 757 } 758 } 759 splx(s); 760 *size = n; 761 return (0); 762 } 763 764 int 765 pfi_skip_if(const char *filter, struct pfi_kif *p) 766 { 767 int n; 768 769 if (filter == NULL || !*filter) 770 return (0); 771 if (!strcmp(p->pfik_name, filter)) 772 return (0); /* exact match */ 773 n = strlen(filter); 774 if (n < 1 || n >= IFNAMSIZ) 775 return (1); /* sanity check */ 776 if (filter[n-1] >= '0' && filter[n-1] <= '9') 777 return (1); /* only do exact match in that case */ 778 if (strncmp(p->pfik_name, filter, n)) 779 return (1); /* prefix doesn't match */ 780 return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9'); 781 } 782 783 int 784 pfi_set_flags(const char *name, int flags) 785 { 786 struct pfi_kif *p; 787 int s; 788 789 s = splsoftnet(); 790 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 791 if (pfi_skip_if(name, p)) 792 continue; 793 p->pfik_flags |= flags; 794 } 795 splx(s); 796 return (0); 797 } 798 799 int 800 pfi_clear_flags(const char *name, int flags) 801 { 802 struct pfi_kif *p; 803 int s; 804 805 s = splsoftnet(); 806 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 807 if (pfi_skip_if(name, p)) 808 continue; 809 p->pfik_flags &= ~flags; 810 } 811 splx(s); 812 return (0); 813 } 814 815 /* from pf_print_state.c */ 816 int 817 pfi_unmask(void *addr) 818 { 819 struct pf_addr *m = addr; 820 int i = 31, j = 0, b = 0; 821 u_int32_t tmp; 822 823 while (j < 4 && m->addr32[j] == 0xffffffff) { 824 b += 32; 825 j++; 826 } 827 if (j < 4) { 828 tmp = ntohl(m->addr32[j]); 829 for (i = 31; tmp & (1 << i); --i) 830 b++; 831 } 832 return (b); 833 } 834 835 #ifdef __NetBSD__ 836 static void 837 pfi_copy_group(char *dest, const char *src, ssize_t sz) 838 { 839 while (sz > 1 && *src && !(*src >= '0' && *src <= '9')) { 840 *dest++ = *src++; 841 sz--; 842 } 843 if (sz > 0) 844 *dest++ = '\0'; 845 } 846 847 void 848 pfi_init_groups(struct ifnet *ifp) 849 { 850 char group[IFNAMSIZ]; 851 852 if_init_groups(ifp); 853 if_addgroup(ifp, IFG_ALL); 854 855 pfi_copy_group(group, ifp->if_xname, sizeof(group)); 856 if_addgroup(ifp, group); 857 } 858 859 void 860 pfi_destroy_groups(struct ifnet *ifp) 861 { 862 char group[IFNAMSIZ]; 863 864 pfi_copy_group(group, ifp->if_xname, sizeof(group)); 865 if_delgroup(ifp, group); 866 867 if_delgroup(ifp, IFG_ALL); 868 if_destroy_groups(ifp); 869 } 870 871 int 872 pfil_ifnet_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 873 { 874 u_long cmd = (u_long)mp; 875 876 switch (cmd) { 877 case PFIL_IFNET_ATTACH: 878 pfi_init_groups(ifp); 879 880 pfi_attach_ifnet(ifp); 881 break; 882 case PFIL_IFNET_DETACH: 883 pfi_detach_ifnet(ifp); 884 885 pfi_destroy_groups(ifp); 886 break; 887 default: 888 panic("pfil_ifnet_wrapper: unexpected cmd %lu", cmd); 889 } 890 891 return (0); 892 } 893 894 int 895 pfil_ifaddr_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 896 { 897 u_long cmd = (u_long)mp; 898 899 switch (cmd) { 900 case SIOCSIFADDR: 901 case SIOCAIFADDR: 902 case SIOCDIFADDR: 903 #ifdef INET6 904 case SIOCAIFADDR_IN6: 905 case SIOCDIFADDR_IN6: 906 #endif /* INET6 */ 907 pfi_kifaddr_update(ifp->if_pf_kif); 908 break; 909 default: 910 panic("pfil_ifaddr_wrapper: unexpected ioctl %lu", cmd); 911 } 912 913 return (0); 914 } 915 #endif /* __NetBSD__ */ 916