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