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