1 /* $NetBSD: pf_if.c,v 1.10 2005/12/11 12:24:25 christos Exp $ */ 2 /* $OpenBSD: pf_if.c,v 1.23 2004/12/22 17:17:55 dhartmei 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; 390 struct pfr_ktable *kt; 391 392 if (dyn == NULL || dyn->pfid_kif == NULL || dyn->pfid_kt == NULL) 393 panic("pfi_dynaddr_update"); 394 395 kif = dyn->pfid_kif; 396 kt = dyn->pfid_kt; 397 if (kt->pfrkt_larg != pfi_update) { 398 /* this table needs to be brought up-to-date */ 399 pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags); 400 kt->pfrkt_larg = pfi_update; 401 } 402 pfr_dynaddr_update(kt, dyn); 403 } 404 405 void 406 pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags) 407 { 408 int e, size2 = 0; 409 struct pfi_kif *p; 410 struct pfr_table t; 411 412 if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) { 413 pfr_clr_addrs(&kt->pfrkt_t, NULL, 0); 414 return; 415 } 416 pfi_buffer_cnt = 0; 417 if ((kif->pfik_flags & PFI_IFLAG_INSTANCE)) 418 pfi_instance_add(kif->pfik_ifp, net, flags); 419 else if (strcmp(kif->pfik_name, "self")) { 420 TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances) 421 pfi_instance_add(p->pfik_ifp, net, flags); 422 } else { 423 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) 424 if (p->pfik_flags & PFI_IFLAG_INSTANCE) 425 pfi_instance_add(p->pfik_ifp, net, flags); 426 } 427 t = kt->pfrkt_t; 428 t.pfrt_flags = 0; 429 if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2, 430 NULL, NULL, NULL, 0))) 431 printf("pfi_table_update: cannot set %d new addresses " 432 "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e); 433 } 434 435 void 436 pfi_instance_add(struct ifnet *ifp, int net, int flags) 437 { 438 struct ifaddr *ia; 439 int got4 = 0, got6 = 0; 440 int net2, af; 441 442 if (ifp == NULL) 443 return; 444 TAILQ_FOREACH(ia, &ifp->if_addrlist, ifa_list) { 445 if (ia->ifa_addr == NULL) 446 continue; 447 af = ia->ifa_addr->sa_family; 448 if (af != AF_INET && af != AF_INET6) 449 continue; 450 if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6) 451 continue; 452 if ((flags & PFI_AFLAG_BROADCAST) && 453 !(ifp->if_flags & IFF_BROADCAST)) 454 continue; 455 if ((flags & PFI_AFLAG_PEER) && 456 !(ifp->if_flags & IFF_POINTOPOINT)) 457 continue; 458 if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 && 459 IN6_IS_ADDR_LINKLOCAL( 460 &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr)) 461 continue; 462 if (flags & PFI_AFLAG_NOALIAS) { 463 if (af == AF_INET && got4) 464 continue; 465 if (af == AF_INET6 && got6) 466 continue; 467 } 468 if (af == AF_INET) 469 got4 = 1; 470 else if (af == AF_INET6) 471 got6 = 1; 472 net2 = net; 473 if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) { 474 if (af == AF_INET) { 475 net2 = pfi_unmask(&((struct sockaddr_in *) 476 ia->ifa_netmask)->sin_addr); 477 } else if (af == AF_INET6) { 478 net2 = pfi_unmask(&((struct sockaddr_in6 *) 479 ia->ifa_netmask)->sin6_addr); 480 } 481 } 482 if (af == AF_INET && net2 > 32) 483 net2 = 32; 484 if (flags & PFI_AFLAG_BROADCAST) 485 pfi_address_add(ia->ifa_broadaddr, af, net2); 486 else if (flags & PFI_AFLAG_PEER) 487 pfi_address_add(ia->ifa_dstaddr, af, net2); 488 else 489 pfi_address_add(ia->ifa_addr, af, net2); 490 } 491 } 492 493 void 494 pfi_address_add(struct sockaddr *sa, int af, int net) 495 { 496 struct pfr_addr *p; 497 int i; 498 499 if (pfi_buffer_cnt >= pfi_buffer_max) { 500 int new_max = pfi_buffer_max * 2; 501 502 if (new_max > PFI_BUFFER_MAX) { 503 printf("pfi_address_add: address buffer full (%d/%d)\n", 504 pfi_buffer_cnt, PFI_BUFFER_MAX); 505 return; 506 } 507 p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE, 508 M_DONTWAIT); 509 if (p == NULL) { 510 printf("pfi_address_add: no memory to grow buffer " 511 "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX); 512 return; 513 } 514 memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer)); 515 /* no need to zero buffer */ 516 free(pfi_buffer, PFI_MTYPE); 517 pfi_buffer = p; 518 pfi_buffer_max = new_max; 519 } 520 if (af == AF_INET && net > 32) 521 net = 128; 522 p = pfi_buffer + pfi_buffer_cnt++; 523 bzero(p, sizeof(*p)); 524 p->pfra_af = af; 525 p->pfra_net = net; 526 if (af == AF_INET) 527 p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr; 528 if (af == AF_INET6) { 529 p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr; 530 if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr)) 531 p->pfra_ip6addr.s6_addr16[1] = 0; 532 } 533 /* mask network address bits */ 534 if (net < 128) 535 ((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8)); 536 for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++) 537 ((caddr_t)p)[i] = 0; 538 } 539 540 void 541 pfi_dynaddr_remove(struct pf_addr_wrap *aw) 542 { 543 int s; 544 545 if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL || 546 aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL) 547 return; 548 549 s = splsoftnet(); 550 hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head, 551 aw->p.dyn->pfid_hook_cookie); 552 pfi_detach_rule(aw->p.dyn->pfid_kif); 553 aw->p.dyn->pfid_kif = NULL; 554 pfr_detach_table(aw->p.dyn->pfid_kt); 555 aw->p.dyn->pfid_kt = NULL; 556 pool_put(&pfi_addr_pl, aw->p.dyn); 557 aw->p.dyn = NULL; 558 splx(s); 559 } 560 561 void 562 pfi_dynaddr_copyout(struct pf_addr_wrap *aw) 563 { 564 if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL || 565 aw->p.dyn->pfid_kif == NULL) 566 return; 567 aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6; 568 } 569 570 void 571 pfi_kifaddr_update(void *v) 572 { 573 int s; 574 575 s = splsoftnet(); 576 pfi_update++; 577 pfi_dohooks(v); 578 splx(s); 579 } 580 581 #ifdef __NetBSD__ 582 void 583 pfi_kifaddr_update_if(struct ifnet *ifp) 584 { 585 struct pfi_kif *p; 586 587 p = pfi_lookup_if(ifp->if_xname); 588 if (p == NULL) 589 panic("can't find interface"); 590 pfi_kifaddr_update(p); 591 } 592 #endif 593 594 int 595 pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q) 596 { 597 return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ)); 598 } 599 600 struct pfi_kif * 601 pfi_if_create(const char *name, struct pfi_kif *q, int flags) 602 { 603 struct pfi_kif *p; 604 605 p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT); 606 if (p == NULL) 607 return (NULL); 608 bzero(p, sizeof(*p)); 609 p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE, 610 M_DONTWAIT); 611 if (p->pfik_ah_head == NULL) { 612 free(p, PFI_MTYPE); 613 return (NULL); 614 } 615 bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head)); 616 TAILQ_INIT(p->pfik_ah_head); 617 TAILQ_INIT(&p->pfik_grouphead); 618 #ifdef __NetBSD__ 619 bzero(&p->pfik_ifaddrhooks, sizeof(p->pfik_ifaddrhooks)); 620 TAILQ_INIT(&p->pfik_ifaddrhooks); 621 #endif 622 strlcpy(p->pfik_name, name, sizeof(p->pfik_name)); 623 RB_INIT(&p->pfik_lan_ext); 624 RB_INIT(&p->pfik_ext_gwy); 625 p->pfik_flags = flags; 626 p->pfik_parent = q; 627 p->pfik_tzero = time_second; 628 629 RB_INSERT(pfi_ifhead, &pfi_ifs, p); 630 if (q != NULL) { 631 q->pfik_addcnt++; 632 TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances); 633 } 634 pfi_ifcnt++; 635 return (p); 636 } 637 638 int 639 pfi_maybe_destroy(struct pfi_kif *p) 640 { 641 int i, j, k, s; 642 struct pfi_kif *q = p->pfik_parent; 643 644 if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) || 645 p->pfik_rules > 0 || p->pfik_states > 0) 646 return (0); 647 648 s = splsoftnet(); 649 if (q != NULL) { 650 for (i = 0; i < 2; i++) 651 for (j = 0; j < 2; j++) 652 for (k = 0; k < 2; k++) { 653 q->pfik_bytes[i][j][k] += 654 p->pfik_bytes[i][j][k]; 655 q->pfik_packets[i][j][k] += 656 p->pfik_packets[i][j][k]; 657 } 658 q->pfik_delcnt++; 659 TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances); 660 } 661 pfi_ifcnt--; 662 RB_REMOVE(pfi_ifhead, &pfi_ifs, p); 663 splx(s); 664 665 free(p->pfik_ah_head, PFI_MTYPE); 666 free(p, PFI_MTYPE); 667 return (1); 668 } 669 670 void 671 pfi_copy_group(char *p, const char *q, int m) 672 { 673 while (m > 1 && *q && !(*q >= '0' && *q <= '9')) { 674 *p++ = *q++; 675 m--; 676 } 677 if (m > 0) 678 *p++ = '\0'; 679 } 680 681 void 682 pfi_newgroup(const char *name, int flags) 683 { 684 struct pfi_kif *p; 685 686 p = pfi_lookup_if(name); 687 if (p == NULL) 688 p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP); 689 if (p == NULL) { 690 printf("pfi_newgroup: cannot allocate '%s' group", name); 691 return; 692 } 693 p->pfik_flags |= flags; 694 } 695 696 void 697 pfi_fill_oldstatus(struct pf_status *pfs) 698 { 699 struct pfi_kif *p, key; 700 int i, j, k, s; 701 702 strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name)); 703 s = splsoftnet(); 704 p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 705 if (p == NULL) { 706 splx(s); 707 return; 708 } 709 bzero(pfs->pcounters, sizeof(pfs->pcounters)); 710 bzero(pfs->bcounters, sizeof(pfs->bcounters)); 711 for (i = 0; i < 2; i++) 712 for (j = 0; j < 2; j++) 713 for (k = 0; k < 2; k++) { 714 pfs->pcounters[i][j][k] = 715 p->pfik_packets[i][j][k]; 716 pfs->bcounters[i][j] += 717 p->pfik_bytes[i][j][k]; 718 } 719 splx(s); 720 } 721 722 int 723 pfi_clr_istats(const char *name, int *nzero, int flags) 724 { 725 struct pfi_kif *p; 726 int n = 0, s; 727 long tzero = time_second; 728 729 ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE); 730 s = splsoftnet(); 731 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 732 if (pfi_skip_if(name, p, flags)) 733 continue; 734 bzero(p->pfik_packets, sizeof(p->pfik_packets)); 735 bzero(p->pfik_bytes, sizeof(p->pfik_bytes)); 736 p->pfik_tzero = tzero; 737 n++; 738 } 739 splx(s); 740 if (nzero != NULL) 741 *nzero = n; 742 return (0); 743 } 744 745 int 746 pfi_set_flags(const char *name, int flags) 747 { 748 struct pfi_kif *p; 749 int s; 750 751 if (flags & ~PFI_IFLAG_SETABLE_MASK) 752 return (EINVAL); 753 754 s = splsoftnet(); 755 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 756 if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE)) 757 continue; 758 p->pfik_flags |= flags; 759 } 760 splx(s); 761 return (0); 762 } 763 764 int 765 pfi_clear_flags(const char *name, int flags) 766 { 767 struct pfi_kif *p; 768 int s; 769 770 if (flags & ~PFI_IFLAG_SETABLE_MASK) 771 return (EINVAL); 772 773 s = splsoftnet(); 774 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 775 if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE)) 776 continue; 777 p->pfik_flags &= ~flags; 778 } 779 splx(s); 780 return (0); 781 } 782 783 int 784 pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags) 785 { 786 struct pfi_kif *p; 787 int s, n = 0; 788 789 ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE); 790 s = splsoftnet(); 791 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 792 if (pfi_skip_if(name, p, flags)) 793 continue; 794 if (*size > n++) { 795 if (!p->pfik_tzero) 796 p->pfik_tzero = time_second; 797 if (copyout(p, buf++, sizeof(*buf))) { 798 splx(s); 799 return (EFAULT); 800 } 801 } 802 } 803 splx(s); 804 *size = n; 805 return (0); 806 } 807 808 struct pfi_kif * 809 pfi_lookup_if(const char *name) 810 { 811 struct pfi_kif *p, key; 812 813 strlcpy(key.pfik_name, name, sizeof(key.pfik_name)); 814 p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 815 return (p); 816 } 817 818 int 819 pfi_skip_if(const char *filter, struct pfi_kif *p, int f) 820 { 821 int n; 822 823 if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP)) 824 return (1); 825 if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE)) 826 return (1); 827 if (filter == NULL || !*filter) 828 return (0); 829 if (!strcmp(p->pfik_name, filter)) 830 return (0); /* exact match */ 831 n = strlen(filter); 832 if (n < 1 || n >= IFNAMSIZ) 833 return (1); /* sanity check */ 834 if (filter[n-1] >= '0' && filter[n-1] <= '9') 835 return (1); /* only do exact match in that case */ 836 if (strncmp(p->pfik_name, filter, n)) 837 return (1); /* prefix doesn't match */ 838 return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9'); 839 } 840 841 /* from pf_print_state.c */ 842 int 843 pfi_unmask(void *addr) 844 { 845 struct pf_addr *m = addr; 846 int i = 31, j = 0, b = 0; 847 u_int32_t tmp; 848 849 while (j < 4 && m->addr32[j] == 0xffffffff) { 850 b += 32; 851 j++; 852 } 853 if (j < 4) { 854 tmp = ntohl(m->addr32[j]); 855 for (i = 31; tmp & (1 << i); --i) 856 b++; 857 } 858 return (b); 859 } 860 861 void 862 pfi_dohooks(struct pfi_kif *p) 863 { 864 for (; p != NULL; p = p->pfik_parent) 865 dohooks(p->pfik_ah_head, 0); 866 } 867 868 int 869 pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) 870 { 871 switch (af) { 872 #ifdef INET 873 case AF_INET: 874 switch (dyn->pfid_acnt4) { 875 case 0: 876 return (0); 877 case 1: 878 return (PF_MATCHA(0, &dyn->pfid_addr4, 879 &dyn->pfid_mask4, a, AF_INET)); 880 default: 881 return (pfr_match_addr(dyn->pfid_kt, a, AF_INET)); 882 } 883 break; 884 #endif /* INET */ 885 #ifdef INET6 886 case AF_INET6: 887 switch (dyn->pfid_acnt6) { 888 case 0: 889 return (0); 890 case 1: 891 return (PF_MATCHA(0, &dyn->pfid_addr6, 892 &dyn->pfid_mask6, a, AF_INET6)); 893 default: 894 return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6)); 895 } 896 break; 897 #endif /* INET6 */ 898 default: 899 return (0); 900 } 901 } 902 903 /* from openbsd/sys/kern/kern_subr.c */ 904 #ifdef __NetBSD__ 905 static void * 906 hook_establish(struct hook_desc_head *head, int tail, void (*fn)(void *), 907 void *arg) 908 { 909 struct hook_desc *hdp; 910 911 hdp = (struct hook_desc *)malloc(sizeof (*hdp), M_DEVBUF, M_NOWAIT); 912 if (hdp == NULL) 913 return (NULL); 914 915 hdp->hd_fn = fn; 916 hdp->hd_arg = arg; 917 if (tail) 918 TAILQ_INSERT_TAIL(head, hdp, hd_list); 919 else 920 TAILQ_INSERT_HEAD(head, hdp, hd_list); 921 922 return (hdp); 923 } 924 925 static void 926 hook_disestablish(struct hook_desc_head *head, void *vhook) 927 { 928 struct hook_desc *hdp; 929 930 #ifdef DIAGNOSTIC 931 for (hdp = TAILQ_FIRST(head); hdp != NULL; 932 hdp = TAILQ_NEXT(hdp, hd_list)) 933 if (hdp == vhook) 934 break; 935 if (hdp == NULL) 936 panic("hook_disestablish: hook not established"); 937 #endif 938 hdp = vhook; 939 TAILQ_REMOVE(head, hdp, hd_list); 940 free(hdp, M_DEVBUF); 941 } 942 943 static void 944 dohooks(struct hook_desc_head *head, int flags) 945 { 946 struct hook_desc *hdp; 947 948 if ((flags & HOOK_REMOVE) == 0) { 949 TAILQ_FOREACH(hdp, head, hd_list) { 950 (*hdp->hd_fn)(hdp->hd_arg); 951 } 952 } else { 953 while ((hdp = TAILQ_FIRST(head)) != NULL) { 954 TAILQ_REMOVE(head, hdp, hd_list); 955 (*hdp->hd_fn)(hdp->hd_arg); 956 if ((flags & HOOK_FREE) != 0) 957 free(hdp, M_DEVBUF); 958 } 959 } 960 } 961 #endif 962