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