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