1 /* $FreeBSD: src/sys/contrib/pf/net/pf_table.c,v 1.5 2004/07/28 06:14:44 kan Exp $ */ 2 /* $OpenBSD: pf_table.c,v 1.47 2004/03/09 21:44:41 mcbride Exp $ */ 3 /* $DragonFly: src/sys/net/pf/pf_table.c,v 1.3 2005/06/15 16:32:58 joerg Exp $ */ 4 5 /* 6 * Copyright (c) 2004 The DragonFly Project. All rights reserved. 7 * 8 * Copyright (c) 2002 Cedric Berger 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 15 * - Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * - Redistributions in binary form must reproduce the above 18 * copyright notice, this list of conditions and the following 19 * disclaimer in the documentation and/or other materials provided 20 * with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 * 35 */ 36 37 #include "opt_inet.h" 38 #include "opt_inet6.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/socket.h> 43 #include <sys/mbuf.h> 44 #include <sys/kernel.h> 45 #include <sys/malloc.h> 46 #include <sys/thread2.h> 47 #include <vm/vm_zone.h> 48 49 #include <net/if.h> 50 #include <net/route.h> 51 #include <netinet/in.h> 52 #include <net/pf/pfvar.h> 53 54 #define ACCEPT_FLAGS(oklist) \ 55 do { \ 56 if ((flags & ~(oklist)) & \ 57 PFR_FLAG_ALLMASK) \ 58 return (EINVAL); \ 59 } while (0) 60 61 #define COPYIN(from, to, size) \ 62 ((flags & PFR_FLAG_USERIOCTL) ? \ 63 copyin((from), (to), (size)) : \ 64 (bcopy((from), (to), (size)), 0)) 65 66 #define COPYOUT(from, to, size) \ 67 ((flags & PFR_FLAG_USERIOCTL) ? \ 68 copyout((from), (to), (size)) : \ 69 (bcopy((from), (to), (size)), 0)) 70 71 #define FILLIN_SIN(sin, addr) \ 72 do { \ 73 (sin).sin_len = sizeof(sin); \ 74 (sin).sin_family = AF_INET; \ 75 (sin).sin_addr = (addr); \ 76 } while (0) 77 78 #define FILLIN_SIN6(sin6, addr) \ 79 do { \ 80 (sin6).sin6_len = sizeof(sin6); \ 81 (sin6).sin6_family = AF_INET6; \ 82 (sin6).sin6_addr = (addr); \ 83 } while (0) 84 85 #define SWAP(type, a1, a2) \ 86 do { \ 87 type tmp = a1; \ 88 a1 = a2; \ 89 a2 = tmp; \ 90 } while (0) 91 92 #define SUNION2PF(su, af) (((af)==AF_INET) ? \ 93 (struct pf_addr *)&(su)->sin.sin_addr : \ 94 (struct pf_addr *)&(su)->sin6.sin6_addr) 95 96 #define AF_BITS(af) (((af)==AF_INET)?32:128) 97 #define ADDR_NETWORK(ad) ((ad)->pfra_net < AF_BITS((ad)->pfra_af)) 98 #define KENTRY_NETWORK(ke) ((ke)->pfrke_net < AF_BITS((ke)->pfrke_af)) 99 #define KENTRY_RNF_ROOT(ke) \ 100 ((((struct radix_node *)(ke))->rn_flags & RNF_ROOT) != 0) 101 102 #define NO_ADDRESSES (-1) 103 #define ENQUEUE_UNMARKED_ONLY (1) 104 #define INVERT_NEG_FLAG (1) 105 106 struct pfr_walktree { 107 enum pfrw_op { 108 PFRW_MARK, 109 PFRW_SWEEP, 110 PFRW_ENQUEUE, 111 PFRW_GET_ADDRS, 112 PFRW_GET_ASTATS, 113 PFRW_POOL_GET, 114 PFRW_DYNADDR_UPDATE 115 } pfrw_op; 116 union { 117 struct pfr_addr *pfrw1_addr; 118 struct pfr_astats *pfrw1_astats; 119 struct pfr_kentryworkq *pfrw1_workq; 120 struct pfr_kentry *pfrw1_kentry; 121 struct pfi_dynaddr *pfrw1_dyn; 122 } pfrw_1; 123 int pfrw_free; 124 int pfrw_flags; 125 }; 126 #define pfrw_addr pfrw_1.pfrw1_addr 127 #define pfrw_astats pfrw_1.pfrw1_astats 128 #define pfrw_workq pfrw_1.pfrw1_workq 129 #define pfrw_kentry pfrw_1.pfrw1_kentry 130 #define pfrw_dyn pfrw_1.pfrw1_dyn 131 #define pfrw_cnt pfrw_free 132 133 #define senderr(e) do { rv = (e); goto _bad; } while (0) 134 135 vm_zone_t pfr_ktable_pl; 136 vm_zone_t pfr_kentry_pl; 137 struct sockaddr_in pfr_sin; 138 struct sockaddr_in6 pfr_sin6; 139 union sockaddr_union pfr_mask; 140 struct pf_addr pfr_ffaddr; 141 142 void pfr_copyout_addr(struct pfr_addr *, 143 struct pfr_kentry *ke); 144 int pfr_validate_addr(struct pfr_addr *); 145 void pfr_enqueue_addrs(struct pfr_ktable *, 146 struct pfr_kentryworkq *, int *, int); 147 void pfr_mark_addrs(struct pfr_ktable *); 148 struct pfr_kentry *pfr_lookup_addr(struct pfr_ktable *, 149 struct pfr_addr *, int); 150 struct pfr_kentry *pfr_create_kentry(struct pfr_addr *); 151 void pfr_destroy_kentries(struct pfr_kentryworkq *); 152 void pfr_destroy_kentry(struct pfr_kentry *); 153 void pfr_insert_kentries(struct pfr_ktable *, 154 struct pfr_kentryworkq *, long); 155 void pfr_remove_kentries(struct pfr_ktable *, 156 struct pfr_kentryworkq *); 157 void pfr_clstats_kentries(struct pfr_kentryworkq *, long, 158 int); 159 void pfr_reset_feedback(struct pfr_addr *, int, int); 160 void pfr_prepare_network(union sockaddr_union *, int, int); 161 int pfr_route_kentry(struct pfr_ktable *, 162 struct pfr_kentry *); 163 int pfr_unroute_kentry(struct pfr_ktable *, 164 struct pfr_kentry *); 165 int pfr_walktree(struct radix_node *, void *); 166 int pfr_validate_table(struct pfr_table *, int, int); 167 void pfr_commit_ktable(struct pfr_ktable *, long); 168 void pfr_insert_ktables(struct pfr_ktableworkq *); 169 void pfr_insert_ktable(struct pfr_ktable *); 170 void pfr_setflags_ktables(struct pfr_ktableworkq *); 171 void pfr_setflags_ktable(struct pfr_ktable *, int); 172 void pfr_clstats_ktables(struct pfr_ktableworkq *, long, 173 int); 174 void pfr_clstats_ktable(struct pfr_ktable *, long, int); 175 struct pfr_ktable *pfr_create_ktable(struct pfr_table *, long, int); 176 void pfr_destroy_ktables(struct pfr_ktableworkq *, int); 177 void pfr_destroy_ktable(struct pfr_ktable *, int); 178 int pfr_ktable_compare(struct pfr_ktable *, 179 struct pfr_ktable *); 180 struct pfr_ktable *pfr_lookup_table(struct pfr_table *); 181 void pfr_clean_node_mask(struct pfr_ktable *, 182 struct pfr_kentryworkq *); 183 int pfr_table_count(struct pfr_table *, int); 184 int pfr_skip_table(struct pfr_table *, 185 struct pfr_ktable *, int); 186 struct pfr_kentry *pfr_kentry_byidx(struct pfr_ktable *, int, int); 187 188 RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); 189 RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); 190 191 struct pfr_ktablehead pfr_ktables; 192 struct pfr_table pfr_nulltable; 193 int pfr_ktable_cnt; 194 195 void 196 pfr_initialize(void) 197 { 198 pfr_sin.sin_len = sizeof(pfr_sin); 199 pfr_sin.sin_family = AF_INET; 200 pfr_sin6.sin6_len = sizeof(pfr_sin6); 201 pfr_sin6.sin6_family = AF_INET6; 202 203 memset(&pfr_ffaddr, 0xff, sizeof(pfr_ffaddr)); 204 } 205 206 int 207 pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) 208 { 209 struct pfr_ktable *kt; 210 struct pfr_kentryworkq workq; 211 212 ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); 213 if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 214 return (EINVAL); 215 kt = pfr_lookup_table(tbl); 216 if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 217 return (ESRCH); 218 if (kt->pfrkt_flags & PFR_TFLAG_CONST) 219 return (EPERM); 220 pfr_enqueue_addrs(kt, &workq, ndel, 0); 221 222 if (!(flags & PFR_FLAG_DUMMY)) { 223 if (flags & PFR_FLAG_ATOMIC) 224 crit_enter(); 225 pfr_remove_kentries(kt, &workq); 226 if (flags & PFR_FLAG_ATOMIC) 227 crit_exit(); 228 if (kt->pfrkt_cnt) { 229 printf("pfr_clr_addrs: corruption detected (%d).\n", 230 kt->pfrkt_cnt); 231 kt->pfrkt_cnt = 0; 232 } 233 } 234 return (0); 235 } 236 237 int 238 pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 239 int *nadd, int flags) 240 { 241 struct pfr_ktable *kt, *tmpkt; 242 struct pfr_kentryworkq workq; 243 struct pfr_kentry *p, *q; 244 struct pfr_addr ad; 245 int i, rv, xadd = 0; 246 long tzero = time_second; 247 248 ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); 249 if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 250 return (EINVAL); 251 kt = pfr_lookup_table(tbl); 252 if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 253 return (ESRCH); 254 if (kt->pfrkt_flags & PFR_TFLAG_CONST) 255 return (EPERM); 256 tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0); 257 if (tmpkt == NULL) 258 return (ENOMEM); 259 SLIST_INIT(&workq); 260 for (i = 0; i < size; i++) { 261 if (COPYIN(addr+i, &ad, sizeof(ad))) 262 senderr(EFAULT); 263 if (pfr_validate_addr(&ad)) 264 senderr(EINVAL); 265 p = pfr_lookup_addr(kt, &ad, 1); 266 q = pfr_lookup_addr(tmpkt, &ad, 1); 267 if (flags & PFR_FLAG_FEEDBACK) { 268 if (q != NULL) 269 ad.pfra_fback = PFR_FB_DUPLICATE; 270 else if (p == NULL) 271 ad.pfra_fback = PFR_FB_ADDED; 272 else if (p->pfrke_not != ad.pfra_not) 273 ad.pfra_fback = PFR_FB_CONFLICT; 274 else 275 ad.pfra_fback = PFR_FB_NONE; 276 } 277 if (p == NULL && q == NULL) { 278 p = pfr_create_kentry(&ad); 279 if (p == NULL) 280 senderr(ENOMEM); 281 if (pfr_route_kentry(tmpkt, p)) { 282 pfr_destroy_kentry(p); 283 ad.pfra_fback = PFR_FB_NONE; 284 } else { 285 SLIST_INSERT_HEAD(&workq, p, pfrke_workq); 286 xadd++; 287 } 288 } 289 if (flags & PFR_FLAG_FEEDBACK) 290 if (COPYOUT(&ad, addr+i, sizeof(ad))) 291 senderr(EFAULT); 292 } 293 pfr_clean_node_mask(tmpkt, &workq); 294 if (!(flags & PFR_FLAG_DUMMY)) { 295 if (flags & PFR_FLAG_ATOMIC) 296 crit_enter(); 297 pfr_insert_kentries(kt, &workq, tzero); 298 if (flags & PFR_FLAG_ATOMIC) 299 crit_exit(); 300 } else 301 pfr_destroy_kentries(&workq); 302 if (nadd != NULL) 303 *nadd = xadd; 304 pfr_destroy_ktable(tmpkt, 0); 305 return (0); 306 _bad: 307 pfr_clean_node_mask(tmpkt, &workq); 308 pfr_destroy_kentries(&workq); 309 if (flags & PFR_FLAG_FEEDBACK) 310 pfr_reset_feedback(addr, size, flags); 311 pfr_destroy_ktable(tmpkt, 0); 312 return (rv); 313 } 314 315 int 316 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 317 int *ndel, int flags) 318 { 319 struct pfr_ktable *kt; 320 struct pfr_kentryworkq workq; 321 struct pfr_kentry *p; 322 struct pfr_addr ad; 323 int i, rv, xdel = 0; 324 325 ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); 326 if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 327 return (EINVAL); 328 kt = pfr_lookup_table(tbl); 329 if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 330 return (ESRCH); 331 if (kt->pfrkt_flags & PFR_TFLAG_CONST) 332 return (EPERM); 333 pfr_mark_addrs(kt); 334 SLIST_INIT(&workq); 335 for (i = 0; i < size; i++) { 336 if (COPYIN(addr+i, &ad, sizeof(ad))) 337 senderr(EFAULT); 338 if (pfr_validate_addr(&ad)) 339 senderr(EINVAL); 340 p = pfr_lookup_addr(kt, &ad, 1); 341 if (flags & PFR_FLAG_FEEDBACK) { 342 if (p == NULL) 343 ad.pfra_fback = PFR_FB_NONE; 344 else if (p->pfrke_not != ad.pfra_not) 345 ad.pfra_fback = PFR_FB_CONFLICT; 346 else if (p->pfrke_mark) 347 ad.pfra_fback = PFR_FB_DUPLICATE; 348 else 349 ad.pfra_fback = PFR_FB_DELETED; 350 } 351 if (p != NULL && p->pfrke_not == ad.pfra_not && 352 !p->pfrke_mark) { 353 p->pfrke_mark = 1; 354 SLIST_INSERT_HEAD(&workq, p, pfrke_workq); 355 xdel++; 356 } 357 if (flags & PFR_FLAG_FEEDBACK) 358 if (COPYOUT(&ad, addr+i, sizeof(ad))) 359 senderr(EFAULT); 360 } 361 if (!(flags & PFR_FLAG_DUMMY)) { 362 if (flags & PFR_FLAG_ATOMIC) 363 crit_enter(); 364 pfr_remove_kentries(kt, &workq); 365 if (flags & PFR_FLAG_ATOMIC) 366 crit_exit(); 367 } 368 if (ndel != NULL) 369 *ndel = xdel; 370 return (0); 371 _bad: 372 if (flags & PFR_FLAG_FEEDBACK) 373 pfr_reset_feedback(addr, size, flags); 374 return (rv); 375 } 376 377 int 378 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 379 int *size2, int *nadd, int *ndel, int *nchange, int flags) 380 { 381 struct pfr_ktable *kt, *tmpkt; 382 struct pfr_kentryworkq addq, delq, changeq; 383 struct pfr_kentry *p, *q; 384 struct pfr_addr ad; 385 int i, rv, xadd = 0, xdel = 0, xchange = 0; 386 long tzero = time_second; 387 388 ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); 389 if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) 390 return (EINVAL); 391 kt = pfr_lookup_table(tbl); 392 if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 393 return (ESRCH); 394 if (kt->pfrkt_flags & PFR_TFLAG_CONST) 395 return (EPERM); 396 tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0); 397 if (tmpkt == NULL) 398 return (ENOMEM); 399 pfr_mark_addrs(kt); 400 SLIST_INIT(&addq); 401 SLIST_INIT(&delq); 402 SLIST_INIT(&changeq); 403 for (i = 0; i < size; i++) { 404 if (COPYIN(addr+i, &ad, sizeof(ad))) 405 senderr(EFAULT); 406 if (pfr_validate_addr(&ad)) 407 senderr(EINVAL); 408 ad.pfra_fback = PFR_FB_NONE; 409 p = pfr_lookup_addr(kt, &ad, 1); 410 if (p != NULL) { 411 if (p->pfrke_mark) { 412 ad.pfra_fback = PFR_FB_DUPLICATE; 413 goto _skip; 414 } 415 p->pfrke_mark = 1; 416 if (p->pfrke_not != ad.pfra_not) { 417 SLIST_INSERT_HEAD(&changeq, p, pfrke_workq); 418 ad.pfra_fback = PFR_FB_CHANGED; 419 xchange++; 420 } 421 } else { 422 q = pfr_lookup_addr(tmpkt, &ad, 1); 423 if (q != NULL) { 424 ad.pfra_fback = PFR_FB_DUPLICATE; 425 goto _skip; 426 } 427 p = pfr_create_kentry(&ad); 428 if (p == NULL) 429 senderr(ENOMEM); 430 if (pfr_route_kentry(tmpkt, p)) { 431 pfr_destroy_kentry(p); 432 ad.pfra_fback = PFR_FB_NONE; 433 } else { 434 SLIST_INSERT_HEAD(&addq, p, pfrke_workq); 435 ad.pfra_fback = PFR_FB_ADDED; 436 xadd++; 437 } 438 } 439 _skip: 440 if (flags & PFR_FLAG_FEEDBACK) 441 if (COPYOUT(&ad, addr+i, sizeof(ad))) 442 senderr(EFAULT); 443 } 444 pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY); 445 if ((flags & PFR_FLAG_FEEDBACK) && *size2) { 446 if (*size2 < size+xdel) { 447 *size2 = size+xdel; 448 senderr(0); 449 } 450 i = 0; 451 SLIST_FOREACH(p, &delq, pfrke_workq) { 452 pfr_copyout_addr(&ad, p); 453 ad.pfra_fback = PFR_FB_DELETED; 454 if (COPYOUT(&ad, addr+size+i, sizeof(ad))) 455 senderr(EFAULT); 456 i++; 457 } 458 } 459 pfr_clean_node_mask(tmpkt, &addq); 460 if (!(flags & PFR_FLAG_DUMMY)) { 461 if (flags & PFR_FLAG_ATOMIC) 462 crit_enter(); 463 pfr_insert_kentries(kt, &addq, tzero); 464 pfr_remove_kentries(kt, &delq); 465 pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG); 466 if (flags & PFR_FLAG_ATOMIC) 467 crit_exit(); 468 } else 469 pfr_destroy_kentries(&addq); 470 if (nadd != NULL) 471 *nadd = xadd; 472 if (ndel != NULL) 473 *ndel = xdel; 474 if (nchange != NULL) 475 *nchange = xchange; 476 if ((flags & PFR_FLAG_FEEDBACK) && size2) 477 *size2 = size+xdel; 478 pfr_destroy_ktable(tmpkt, 0); 479 return (0); 480 _bad: 481 pfr_clean_node_mask(tmpkt, &addq); 482 pfr_destroy_kentries(&addq); 483 if (flags & PFR_FLAG_FEEDBACK) 484 pfr_reset_feedback(addr, size, flags); 485 pfr_destroy_ktable(tmpkt, 0); 486 return (rv); 487 } 488 489 int 490 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, 491 int *nmatch, int flags) 492 { 493 struct pfr_ktable *kt; 494 struct pfr_kentry *p; 495 struct pfr_addr ad; 496 int i, xmatch = 0; 497 498 ACCEPT_FLAGS(PFR_FLAG_REPLACE); 499 if (pfr_validate_table(tbl, 0, 0)) 500 return (EINVAL); 501 kt = pfr_lookup_table(tbl); 502 if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 503 return (ESRCH); 504 505 for (i = 0; i < size; i++) { 506 if (COPYIN(addr+i, &ad, sizeof(ad))) 507 return (EFAULT); 508 if (pfr_validate_addr(&ad)) 509 return (EINVAL); 510 if (ADDR_NETWORK(&ad)) 511 return (EINVAL); 512 p = pfr_lookup_addr(kt, &ad, 0); 513 if (flags & PFR_FLAG_REPLACE) 514 pfr_copyout_addr(&ad, p); 515 ad.pfra_fback = (p == NULL) ? PFR_FB_NONE : 516 (p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH); 517 if (p != NULL && !p->pfrke_not) 518 xmatch++; 519 if (COPYOUT(&ad, addr+i, sizeof(ad))) 520 return (EFAULT); 521 } 522 if (nmatch != NULL) 523 *nmatch = xmatch; 524 return (0); 525 } 526 527 int 528 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, 529 int flags) 530 { 531 struct pfr_ktable *kt; 532 struct pfr_walktree w; 533 int rv; 534 535 ACCEPT_FLAGS(0); 536 if (pfr_validate_table(tbl, 0, 0)) 537 return (EINVAL); 538 kt = pfr_lookup_table(tbl); 539 if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 540 return (ESRCH); 541 if (kt->pfrkt_cnt > *size) { 542 *size = kt->pfrkt_cnt; 543 return (0); 544 } 545 546 bzero(&w, sizeof(w)); 547 w.pfrw_op = PFRW_GET_ADDRS; 548 w.pfrw_addr = addr; 549 w.pfrw_free = kt->pfrkt_cnt; 550 w.pfrw_flags = flags; 551 rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 552 if (!rv) 553 rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); 554 if (rv) 555 return (rv); 556 557 if (w.pfrw_free) { 558 printf("pfr_get_addrs: corruption detected (%d).\n", 559 w.pfrw_free); 560 return (ENOTTY); 561 } 562 *size = kt->pfrkt_cnt; 563 return (0); 564 } 565 566 int 567 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, 568 int flags) 569 { 570 struct pfr_ktable *kt; 571 struct pfr_walktree w; 572 struct pfr_kentryworkq workq; 573 int rv; 574 long tzero = time_second; 575 576 ACCEPT_FLAGS(PFR_FLAG_ATOMIC); /* XXX PFR_FLAG_CLSTATS disabled */ 577 if (pfr_validate_table(tbl, 0, 0)) 578 return (EINVAL); 579 kt = pfr_lookup_table(tbl); 580 if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 581 return (ESRCH); 582 if (kt->pfrkt_cnt > *size) { 583 *size = kt->pfrkt_cnt; 584 return (0); 585 } 586 587 bzero(&w, sizeof(w)); 588 w.pfrw_op = PFRW_GET_ASTATS; 589 w.pfrw_astats = addr; 590 w.pfrw_free = kt->pfrkt_cnt; 591 w.pfrw_flags = flags; 592 if (flags & PFR_FLAG_ATOMIC) 593 crit_enter(); 594 rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 595 if (!rv) 596 rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); 597 if (!rv && (flags & PFR_FLAG_CLSTATS)) { 598 pfr_enqueue_addrs(kt, &workq, NULL, 0); 599 pfr_clstats_kentries(&workq, tzero, 0); 600 } 601 if (flags & PFR_FLAG_ATOMIC) 602 crit_exit(); 603 if (rv) 604 return (rv); 605 606 if (w.pfrw_free) { 607 printf("pfr_get_astats: corruption detected (%d).\n", 608 w.pfrw_free); 609 return (ENOTTY); 610 } 611 *size = kt->pfrkt_cnt; 612 return (0); 613 } 614 615 int 616 pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, 617 int *nzero, int flags) 618 { 619 struct pfr_ktable *kt; 620 struct pfr_kentryworkq workq; 621 struct pfr_kentry *p; 622 struct pfr_addr ad; 623 int i, rv, xzero = 0; 624 625 ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); 626 if (pfr_validate_table(tbl, 0, 0)) 627 return (EINVAL); 628 kt = pfr_lookup_table(tbl); 629 if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 630 return (ESRCH); 631 SLIST_INIT(&workq); 632 for (i = 0; i < size; i++) { 633 if (COPYIN(addr+i, &ad, sizeof(ad))) 634 senderr(EFAULT); 635 if (pfr_validate_addr(&ad)) 636 senderr(EINVAL); 637 p = pfr_lookup_addr(kt, &ad, 1); 638 if (flags & PFR_FLAG_FEEDBACK) { 639 ad.pfra_fback = (p != NULL) ? 640 PFR_FB_CLEARED : PFR_FB_NONE; 641 if (COPYOUT(&ad, addr+i, sizeof(ad))) 642 senderr(EFAULT); 643 } 644 if (p != NULL) { 645 SLIST_INSERT_HEAD(&workq, p, pfrke_workq); 646 xzero++; 647 } 648 } 649 650 if (!(flags & PFR_FLAG_DUMMY)) { 651 if (flags & PFR_FLAG_ATOMIC) 652 crit_enter(); 653 pfr_clstats_kentries(&workq, 0, 0); 654 if (flags & PFR_FLAG_ATOMIC) 655 crit_exit(); 656 } 657 if (nzero != NULL) 658 *nzero = xzero; 659 return (0); 660 _bad: 661 if (flags & PFR_FLAG_FEEDBACK) 662 pfr_reset_feedback(addr, size, flags); 663 return (rv); 664 } 665 666 int 667 pfr_validate_addr(struct pfr_addr *ad) 668 { 669 int i; 670 671 switch (ad->pfra_af) { 672 case AF_INET: 673 if (ad->pfra_net > 32) 674 return (-1); 675 break; 676 case AF_INET6: 677 if (ad->pfra_net > 128) 678 return (-1); 679 break; 680 default: 681 return (-1); 682 } 683 if (ad->pfra_net < 128 && 684 (((caddr_t)ad)[ad->pfra_net/8] & (0xFF >> (ad->pfra_net%8)))) 685 return (-1); 686 for (i = (ad->pfra_net+7)/8; i < sizeof(ad->pfra_u); i++) 687 if (((caddr_t)ad)[i]) 688 return (-1); 689 if (ad->pfra_not && ad->pfra_not != 1) 690 return (-1); 691 if (ad->pfra_fback) 692 return (-1); 693 return (0); 694 } 695 696 void 697 pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq, 698 int *naddr, int sweep) 699 { 700 struct pfr_walktree w; 701 702 SLIST_INIT(workq); 703 bzero(&w, sizeof(w)); 704 w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE; 705 w.pfrw_workq = workq; 706 if (kt->pfrkt_ip4 != NULL) 707 if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) 708 printf("pfr_enqueue_addrs: IPv4 walktree failed.\n"); 709 if (kt->pfrkt_ip6 != NULL) 710 if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) 711 printf("pfr_enqueue_addrs: IPv6 walktree failed.\n"); 712 if (naddr != NULL) 713 *naddr = w.pfrw_cnt; 714 } 715 716 void 717 pfr_mark_addrs(struct pfr_ktable *kt) 718 { 719 struct pfr_walktree w; 720 721 bzero(&w, sizeof(w)); 722 w.pfrw_op = PFRW_MARK; 723 if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) 724 printf("pfr_mark_addrs: IPv4 walktree failed.\n"); 725 if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) 726 printf("pfr_mark_addrs: IPv6 walktree failed.\n"); 727 } 728 729 730 struct pfr_kentry * 731 pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) 732 { 733 union sockaddr_union sa, mask; 734 struct radix_node_head *head; 735 struct pfr_kentry *ke; 736 737 bzero(&sa, sizeof(sa)); 738 if (ad->pfra_af == AF_INET) { 739 FILLIN_SIN(sa.sin, ad->pfra_ip4addr); 740 head = kt->pfrkt_ip4; 741 } else { 742 FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr); 743 head = kt->pfrkt_ip6; 744 } 745 if (ADDR_NETWORK(ad)) { 746 pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net); 747 crit_enter(); /* rn_lookup makes use of globals */ 748 ke = (struct pfr_kentry *)rn_lookup((char *)&sa, (char *)&mask, 749 head); 750 crit_exit(); 751 if (ke && KENTRY_RNF_ROOT(ke)) 752 ke = NULL; 753 } else { 754 ke = (struct pfr_kentry *)rn_match((char *)&sa, head); 755 if (ke && KENTRY_RNF_ROOT(ke)) 756 ke = NULL; 757 if (exact && ke && KENTRY_NETWORK(ke)) 758 ke = NULL; 759 } 760 return (ke); 761 } 762 763 struct pfr_kentry * 764 pfr_create_kentry(struct pfr_addr *ad) 765 { 766 struct pfr_kentry *ke; 767 768 ke = pool_get(&pfr_kentry_pl, PR_NOWAIT); 769 if (ke == NULL) 770 return (NULL); 771 bzero(ke, sizeof(*ke)); 772 773 if (ad->pfra_af == AF_INET) 774 FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr); 775 else 776 FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr); 777 ke->pfrke_af = ad->pfra_af; 778 ke->pfrke_net = ad->pfra_net; 779 ke->pfrke_not = ad->pfra_not; 780 return (ke); 781 } 782 783 void 784 pfr_destroy_kentries(struct pfr_kentryworkq *workq) 785 { 786 struct pfr_kentry *p, *q; 787 788 for (p = SLIST_FIRST(workq); p != NULL; p = q) { 789 q = SLIST_NEXT(p, pfrke_workq); 790 pfr_destroy_kentry(p); 791 } 792 } 793 794 void 795 pfr_destroy_kentry(struct pfr_kentry *ke) 796 { 797 pool_put(&pfr_kentry_pl, ke); 798 } 799 800 void 801 pfr_insert_kentries(struct pfr_ktable *kt, 802 struct pfr_kentryworkq *workq, long tzero) 803 { 804 struct pfr_kentry *p; 805 int rv, n = 0; 806 807 SLIST_FOREACH(p, workq, pfrke_workq) { 808 rv = pfr_route_kentry(kt, p); 809 if (rv) { 810 printf("pfr_insert_kentries: cannot route entry " 811 "(code=%d).\n", rv); 812 break; 813 } 814 p->pfrke_tzero = tzero; 815 n++; 816 } 817 kt->pfrkt_cnt += n; 818 } 819 820 void 821 pfr_remove_kentries(struct pfr_ktable *kt, 822 struct pfr_kentryworkq *workq) 823 { 824 struct pfr_kentry *p; 825 int n = 0; 826 827 SLIST_FOREACH(p, workq, pfrke_workq) { 828 pfr_unroute_kentry(kt, p); 829 n++; 830 } 831 kt->pfrkt_cnt -= n; 832 pfr_destroy_kentries(workq); 833 } 834 835 void 836 pfr_clean_node_mask(struct pfr_ktable *kt, 837 struct pfr_kentryworkq *workq) 838 { 839 struct pfr_kentry *p; 840 841 SLIST_FOREACH(p, workq, pfrke_workq) 842 pfr_unroute_kentry(kt, p); 843 } 844 845 void 846 pfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange) 847 { 848 struct pfr_kentry *p; 849 850 SLIST_FOREACH(p, workq, pfrke_workq) { 851 crit_enter(); 852 if (negchange) 853 p->pfrke_not = !p->pfrke_not; 854 bzero(p->pfrke_packets, sizeof(p->pfrke_packets)); 855 bzero(p->pfrke_bytes, sizeof(p->pfrke_bytes)); 856 crit_exit(); 857 p->pfrke_tzero = tzero; 858 } 859 } 860 861 void 862 pfr_reset_feedback(struct pfr_addr *addr, int size, int flags) 863 { 864 struct pfr_addr ad; 865 int i; 866 867 for (i = 0; i < size; i++) { 868 if (COPYIN(addr+i, &ad, sizeof(ad))) 869 break; 870 ad.pfra_fback = PFR_FB_NONE; 871 if (COPYOUT(&ad, addr+i, sizeof(ad))) 872 break; 873 } 874 } 875 876 void 877 pfr_prepare_network(union sockaddr_union *sa, int af, int net) 878 { 879 int i; 880 881 bzero(sa, sizeof(*sa)); 882 if (af == AF_INET) { 883 sa->sin.sin_len = sizeof(sa->sin); 884 sa->sin.sin_family = AF_INET; 885 sa->sin.sin_addr.s_addr = htonl(-1 << (32-net)); 886 } else { 887 sa->sin6.sin6_len = sizeof(sa->sin6); 888 sa->sin6.sin6_family = AF_INET6; 889 for (i = 0; i < 4; i++) { 890 if (net <= 32) { 891 sa->sin6.sin6_addr.s6_addr32[i] = 892 htonl(-1 << (32-net)); 893 break; 894 } 895 sa->sin6.sin6_addr.s6_addr32[i] = 0xFFFFFFFF; 896 net -= 32; 897 } 898 } 899 } 900 901 int 902 pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) 903 { 904 union sockaddr_union mask; 905 struct radix_node *rn; 906 struct radix_node_head *head; 907 908 bzero(ke->pfrke_node, sizeof(ke->pfrke_node)); 909 if (ke->pfrke_af == AF_INET) 910 head = kt->pfrkt_ip4; 911 else 912 head = kt->pfrkt_ip6; 913 914 crit_enter(); 915 if (KENTRY_NETWORK(ke)) { 916 pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); 917 rn = rn_addroute((char *)&ke->pfrke_sa, (char *)&mask, head, 918 ke->pfrke_node); 919 } else 920 rn = rn_addroute((char *)&ke->pfrke_sa, NULL, head, 921 ke->pfrke_node); 922 crit_exit(); 923 924 return (rn == NULL ? -1 : 0); 925 } 926 927 int 928 pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) 929 { 930 union sockaddr_union mask; 931 struct radix_node *rn; 932 struct radix_node_head *head; 933 934 if (ke->pfrke_af == AF_INET) 935 head = kt->pfrkt_ip4; 936 else 937 head = kt->pfrkt_ip6; 938 939 crit_enter(); 940 if (KENTRY_NETWORK(ke)) { 941 pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); 942 rn = rn_delete((char *)&ke->pfrke_sa, (char *)&mask, head); 943 } else 944 rn = rn_delete((char *)&ke->pfrke_sa, NULL, head); 945 crit_exit(); 946 947 if (rn == NULL) { 948 printf("pfr_unroute_kentry: delete failed.\n"); 949 return (-1); 950 } 951 return (0); 952 } 953 954 void 955 pfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke) 956 { 957 bzero(ad, sizeof(*ad)); 958 if (ke == NULL) 959 return; 960 ad->pfra_af = ke->pfrke_af; 961 ad->pfra_net = ke->pfrke_net; 962 ad->pfra_not = ke->pfrke_not; 963 if (ad->pfra_af == AF_INET) 964 ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr; 965 else 966 ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr; 967 } 968 969 int 970 pfr_walktree(struct radix_node *rn, void *arg) 971 { 972 struct pfr_kentry *ke = (struct pfr_kentry *)rn; 973 struct pfr_walktree *w = arg; 974 int flags = w->pfrw_flags; 975 976 switch (w->pfrw_op) { 977 case PFRW_MARK: 978 ke->pfrke_mark = 0; 979 break; 980 case PFRW_SWEEP: 981 if (ke->pfrke_mark) 982 break; 983 /* FALLTHROUGH */ 984 case PFRW_ENQUEUE: 985 SLIST_INSERT_HEAD(w->pfrw_workq, ke, pfrke_workq); 986 w->pfrw_cnt++; 987 break; 988 case PFRW_GET_ADDRS: 989 if (w->pfrw_free-- > 0) { 990 struct pfr_addr ad; 991 992 pfr_copyout_addr(&ad, ke); 993 if (copyout(&ad, w->pfrw_addr, sizeof(ad))) 994 return (EFAULT); 995 w->pfrw_addr++; 996 } 997 break; 998 case PFRW_GET_ASTATS: 999 if (w->pfrw_free-- > 0) { 1000 struct pfr_astats as; 1001 1002 pfr_copyout_addr(&as.pfras_a, ke); 1003 1004 crit_enter(); 1005 bcopy(ke->pfrke_packets, as.pfras_packets, 1006 sizeof(as.pfras_packets)); 1007 bcopy(ke->pfrke_bytes, as.pfras_bytes, 1008 sizeof(as.pfras_bytes)); 1009 crit_exit(); 1010 as.pfras_tzero = ke->pfrke_tzero; 1011 1012 if (COPYOUT(&as, w->pfrw_astats, sizeof(as))) 1013 return (EFAULT); 1014 w->pfrw_astats++; 1015 } 1016 break; 1017 case PFRW_POOL_GET: 1018 if (ke->pfrke_not) 1019 break; /* negative entries are ignored */ 1020 if (!w->pfrw_cnt--) { 1021 w->pfrw_kentry = ke; 1022 return (1); /* finish search */ 1023 } 1024 break; 1025 case PFRW_DYNADDR_UPDATE: 1026 if (ke->pfrke_af == AF_INET) { 1027 if (w->pfrw_dyn->pfid_acnt4++ > 0) 1028 break; 1029 pfr_prepare_network(&pfr_mask, AF_INET, ke->pfrke_net); 1030 w->pfrw_dyn->pfid_addr4 = *SUNION2PF( 1031 &ke->pfrke_sa, AF_INET); 1032 w->pfrw_dyn->pfid_mask4 = *SUNION2PF( 1033 &pfr_mask, AF_INET); 1034 } else { 1035 if (w->pfrw_dyn->pfid_acnt6++ > 0) 1036 break; 1037 pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net); 1038 w->pfrw_dyn->pfid_addr6 = *SUNION2PF( 1039 &ke->pfrke_sa, AF_INET6); 1040 w->pfrw_dyn->pfid_mask6 = *SUNION2PF( 1041 &pfr_mask, AF_INET6); 1042 } 1043 break; 1044 } 1045 return (0); 1046 } 1047 1048 int 1049 pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) 1050 { 1051 struct pfr_ktableworkq workq; 1052 struct pfr_ktable *p; 1053 int xdel = 0; 1054 1055 ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ALLRSETS); 1056 if (pfr_table_count(filter, flags) < 0) 1057 return (ENOENT); 1058 1059 SLIST_INIT(&workq); 1060 RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 1061 if (pfr_skip_table(filter, p, flags)) 1062 continue; 1063 if (!strcmp(p->pfrkt_anchor, PF_RESERVED_ANCHOR)) 1064 continue; 1065 if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) 1066 continue; 1067 p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE; 1068 SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1069 xdel++; 1070 } 1071 if (!(flags & PFR_FLAG_DUMMY)) { 1072 if (flags & PFR_FLAG_ATOMIC) 1073 crit_enter(); 1074 pfr_setflags_ktables(&workq); 1075 if (flags & PFR_FLAG_ATOMIC) 1076 crit_exit(); 1077 } 1078 if (ndel != NULL) 1079 *ndel = xdel; 1080 return (0); 1081 } 1082 1083 int 1084 pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) 1085 { 1086 struct pfr_ktableworkq addq, changeq; 1087 struct pfr_ktable *p, *q, *r, key; 1088 int i, rv, xadd = 0; 1089 long tzero = time_second; 1090 1091 ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); 1092 SLIST_INIT(&addq); 1093 SLIST_INIT(&changeq); 1094 for (i = 0; i < size; i++) { 1095 if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) 1096 senderr(EFAULT); 1097 if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK, 1098 flags & PFR_FLAG_USERIOCTL)) 1099 senderr(EINVAL); 1100 key.pfrkt_flags |= PFR_TFLAG_ACTIVE; 1101 p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 1102 if (p == NULL) { 1103 p = pfr_create_ktable(&key.pfrkt_t, tzero, 1); 1104 if (p == NULL) 1105 senderr(ENOMEM); 1106 SLIST_FOREACH(q, &addq, pfrkt_workq) { 1107 if (!pfr_ktable_compare(p, q)) 1108 goto _skip; 1109 } 1110 SLIST_INSERT_HEAD(&addq, p, pfrkt_workq); 1111 xadd++; 1112 if (!key.pfrkt_anchor[0]) 1113 goto _skip; 1114 1115 /* find or create root table */ 1116 bzero(key.pfrkt_anchor, sizeof(key.pfrkt_anchor)); 1117 bzero(key.pfrkt_ruleset, sizeof(key.pfrkt_ruleset)); 1118 r = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 1119 if (r != NULL) { 1120 p->pfrkt_root = r; 1121 goto _skip; 1122 } 1123 SLIST_FOREACH(q, &addq, pfrkt_workq) { 1124 if (!pfr_ktable_compare(&key, q)) { 1125 p->pfrkt_root = q; 1126 goto _skip; 1127 } 1128 } 1129 key.pfrkt_flags = 0; 1130 r = pfr_create_ktable(&key.pfrkt_t, 0, 1); 1131 if (r == NULL) 1132 senderr(ENOMEM); 1133 SLIST_INSERT_HEAD(&addq, r, pfrkt_workq); 1134 p->pfrkt_root = r; 1135 } else if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { 1136 SLIST_FOREACH(q, &changeq, pfrkt_workq) 1137 if (!pfr_ktable_compare(&key, q)) 1138 goto _skip; 1139 p->pfrkt_nflags = (p->pfrkt_flags & 1140 ~PFR_TFLAG_USRMASK) | key.pfrkt_flags; 1141 SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq); 1142 xadd++; 1143 } 1144 _skip: 1145 ; 1146 } 1147 if (!(flags & PFR_FLAG_DUMMY)) { 1148 if (flags & PFR_FLAG_ATOMIC) 1149 crit_enter(); 1150 pfr_insert_ktables(&addq); 1151 pfr_setflags_ktables(&changeq); 1152 if (flags & PFR_FLAG_ATOMIC) 1153 crit_exit(); 1154 } else 1155 pfr_destroy_ktables(&addq, 0); 1156 if (nadd != NULL) 1157 *nadd = xadd; 1158 return (0); 1159 _bad: 1160 pfr_destroy_ktables(&addq, 0); 1161 return (rv); 1162 } 1163 1164 int 1165 pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) 1166 { 1167 struct pfr_ktableworkq workq; 1168 struct pfr_ktable *p, *q, key; 1169 int i, xdel = 0; 1170 1171 ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); 1172 SLIST_INIT(&workq); 1173 for (i = 0; i < size; i++) { 1174 if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) 1175 return (EFAULT); 1176 if (pfr_validate_table(&key.pfrkt_t, 0, 1177 flags & PFR_FLAG_USERIOCTL)) 1178 return (EINVAL); 1179 p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 1180 if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { 1181 SLIST_FOREACH(q, &workq, pfrkt_workq) 1182 if (!pfr_ktable_compare(p, q)) 1183 goto _skip; 1184 p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE; 1185 SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1186 xdel++; 1187 } 1188 _skip: 1189 ; 1190 } 1191 1192 if (!(flags & PFR_FLAG_DUMMY)) { 1193 if (flags & PFR_FLAG_ATOMIC) 1194 crit_enter(); 1195 pfr_setflags_ktables(&workq); 1196 if (flags & PFR_FLAG_ATOMIC) 1197 crit_exit(); 1198 } 1199 if (ndel != NULL) 1200 *ndel = xdel; 1201 return (0); 1202 } 1203 1204 int 1205 pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, 1206 int flags) 1207 { 1208 struct pfr_ktable *p; 1209 int n, nn; 1210 1211 ACCEPT_FLAGS(PFR_FLAG_ALLRSETS); 1212 n = nn = pfr_table_count(filter, flags); 1213 if (n < 0) 1214 return (ENOENT); 1215 if (n > *size) { 1216 *size = n; 1217 return (0); 1218 } 1219 RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 1220 if (pfr_skip_table(filter, p, flags)) 1221 continue; 1222 if (n-- <= 0) 1223 continue; 1224 if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl))) 1225 return (EFAULT); 1226 } 1227 if (n) { 1228 printf("pfr_get_tables: corruption detected (%d).\n", n); 1229 return (ENOTTY); 1230 } 1231 *size = nn; 1232 return (0); 1233 } 1234 1235 int 1236 pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, 1237 int flags) 1238 { 1239 struct pfr_ktable *p; 1240 struct pfr_ktableworkq workq; 1241 int n, nn; 1242 long tzero = time_second; 1243 1244 ACCEPT_FLAGS(PFR_FLAG_ATOMIC|PFR_FLAG_ALLRSETS); 1245 /* XXX PFR_FLAG_CLSTATS disabled */ 1246 n = nn = pfr_table_count(filter, flags); 1247 if (n < 0) 1248 return (ENOENT); 1249 if (n > *size) { 1250 *size = n; 1251 return (0); 1252 } 1253 SLIST_INIT(&workq); 1254 if (flags & PFR_FLAG_ATOMIC) 1255 crit_enter(); 1256 RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 1257 if (pfr_skip_table(filter, p, flags)) 1258 continue; 1259 if (n-- <= 0) 1260 continue; 1261 if (!(flags & PFR_FLAG_ATOMIC)) 1262 crit_enter(); 1263 if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl))) { 1264 crit_exit(); 1265 return (EFAULT); 1266 } 1267 if (!(flags & PFR_FLAG_ATOMIC)) 1268 crit_exit(); 1269 SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1270 } 1271 if (flags & PFR_FLAG_CLSTATS) 1272 pfr_clstats_ktables(&workq, tzero, 1273 flags & PFR_FLAG_ADDRSTOO); 1274 if (flags & PFR_FLAG_ATOMIC) 1275 crit_exit(); 1276 if (n) { 1277 printf("pfr_get_tstats: corruption detected (%d).\n", n); 1278 return (ENOTTY); 1279 } 1280 *size = nn; 1281 return (0); 1282 } 1283 1284 int 1285 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) 1286 { 1287 struct pfr_ktableworkq workq; 1288 struct pfr_ktable *p, key; 1289 int i, xzero = 0; 1290 long tzero = time_second; 1291 1292 ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ADDRSTOO); 1293 SLIST_INIT(&workq); 1294 for (i = 0; i < size; i++) { 1295 if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) 1296 return (EFAULT); 1297 if (pfr_validate_table(&key.pfrkt_t, 0, 0)) 1298 return (EINVAL); 1299 p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 1300 if (p != NULL) { 1301 SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1302 xzero++; 1303 } 1304 } 1305 if (!(flags & PFR_FLAG_DUMMY)) { 1306 if (flags & PFR_FLAG_ATOMIC) 1307 crit_enter(); 1308 pfr_clstats_ktables(&workq, tzero, flags & PFR_FLAG_ADDRSTOO); 1309 if (flags & PFR_FLAG_ATOMIC) 1310 crit_exit(); 1311 } 1312 if (nzero != NULL) 1313 *nzero = xzero; 1314 return (0); 1315 } 1316 1317 int 1318 pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag, 1319 int *nchange, int *ndel, int flags) 1320 { 1321 struct pfr_ktableworkq workq; 1322 struct pfr_ktable *p, *q, key; 1323 int i, xchange = 0, xdel = 0; 1324 1325 ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); 1326 if ((setflag & ~PFR_TFLAG_USRMASK) || 1327 (clrflag & ~PFR_TFLAG_USRMASK) || 1328 (setflag & clrflag)) 1329 return (EINVAL); 1330 SLIST_INIT(&workq); 1331 for (i = 0; i < size; i++) { 1332 if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) 1333 return (EFAULT); 1334 if (pfr_validate_table(&key.pfrkt_t, 0, 1335 flags & PFR_FLAG_USERIOCTL)) 1336 return (EINVAL); 1337 p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 1338 if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { 1339 p->pfrkt_nflags = (p->pfrkt_flags | setflag) & 1340 ~clrflag; 1341 if (p->pfrkt_nflags == p->pfrkt_flags) 1342 goto _skip; 1343 SLIST_FOREACH(q, &workq, pfrkt_workq) 1344 if (!pfr_ktable_compare(p, q)) 1345 goto _skip; 1346 SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1347 if ((p->pfrkt_flags & PFR_TFLAG_PERSIST) && 1348 (clrflag & PFR_TFLAG_PERSIST) && 1349 !(p->pfrkt_flags & PFR_TFLAG_REFERENCED)) 1350 xdel++; 1351 else 1352 xchange++; 1353 } 1354 _skip: 1355 ; 1356 } 1357 if (!(flags & PFR_FLAG_DUMMY)) { 1358 if (flags & PFR_FLAG_ATOMIC) 1359 crit_enter(); 1360 pfr_setflags_ktables(&workq); 1361 if (flags & PFR_FLAG_ATOMIC) 1362 crit_exit(); 1363 } 1364 if (nchange != NULL) 1365 *nchange = xchange; 1366 if (ndel != NULL) 1367 *ndel = xdel; 1368 return (0); 1369 } 1370 1371 int 1372 pfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags) 1373 { 1374 struct pfr_ktableworkq workq; 1375 struct pfr_ktable *p; 1376 struct pf_ruleset *rs; 1377 int xdel = 0; 1378 1379 ACCEPT_FLAGS(PFR_FLAG_DUMMY); 1380 rs = pf_find_or_create_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset); 1381 if (rs == NULL) 1382 return (ENOMEM); 1383 SLIST_INIT(&workq); 1384 RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 1385 if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || 1386 pfr_skip_table(trs, p, 0)) 1387 continue; 1388 p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE; 1389 SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1390 xdel++; 1391 } 1392 if (!(flags & PFR_FLAG_DUMMY)) { 1393 pfr_setflags_ktables(&workq); 1394 if (ticket != NULL) 1395 *ticket = ++rs->tticket; 1396 rs->topen = 1; 1397 } else 1398 pf_remove_if_empty_ruleset(rs); 1399 if (ndel != NULL) 1400 *ndel = xdel; 1401 return (0); 1402 } 1403 1404 int 1405 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, 1406 int *nadd, int *naddr, u_int32_t ticket, int flags) 1407 { 1408 struct pfr_ktableworkq tableq; 1409 struct pfr_kentryworkq addrq; 1410 struct pfr_ktable *kt, *rt, *shadow, key; 1411 struct pfr_kentry *p; 1412 struct pfr_addr ad; 1413 struct pf_ruleset *rs; 1414 int i, rv, xadd = 0, xaddr = 0; 1415 1416 ACCEPT_FLAGS(PFR_FLAG_DUMMY|PFR_FLAG_ADDRSTOO); 1417 if (size && !(flags & PFR_FLAG_ADDRSTOO)) 1418 return (EINVAL); 1419 if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK, 1420 flags & PFR_FLAG_USERIOCTL)) 1421 return (EINVAL); 1422 rs = pf_find_ruleset(tbl->pfrt_anchor, tbl->pfrt_ruleset); 1423 if (rs == NULL || !rs->topen || ticket != rs->tticket) 1424 return (EBUSY); 1425 tbl->pfrt_flags |= PFR_TFLAG_INACTIVE; 1426 SLIST_INIT(&tableq); 1427 kt = RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl); 1428 if (kt == NULL) { 1429 kt = pfr_create_ktable(tbl, 0, 1); 1430 if (kt == NULL) 1431 return (ENOMEM); 1432 SLIST_INSERT_HEAD(&tableq, kt, pfrkt_workq); 1433 xadd++; 1434 if (!tbl->pfrt_anchor[0]) 1435 goto _skip; 1436 1437 /* find or create root table */ 1438 bzero(&key, sizeof(key)); 1439 strlcpy(key.pfrkt_name, tbl->pfrt_name, sizeof(key.pfrkt_name)); 1440 rt = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); 1441 if (rt != NULL) { 1442 kt->pfrkt_root = rt; 1443 goto _skip; 1444 } 1445 rt = pfr_create_ktable(&key.pfrkt_t, 0, 1); 1446 if (rt == NULL) { 1447 pfr_destroy_ktables(&tableq, 0); 1448 return (ENOMEM); 1449 } 1450 SLIST_INSERT_HEAD(&tableq, rt, pfrkt_workq); 1451 kt->pfrkt_root = rt; 1452 } else if (!(kt->pfrkt_flags & PFR_TFLAG_INACTIVE)) 1453 xadd++; 1454 _skip: 1455 shadow = pfr_create_ktable(tbl, 0, 0); 1456 if (shadow == NULL) { 1457 pfr_destroy_ktables(&tableq, 0); 1458 return (ENOMEM); 1459 } 1460 SLIST_INIT(&addrq); 1461 for (i = 0; i < size; i++) { 1462 if (COPYIN(addr+i, &ad, sizeof(ad))) 1463 senderr(EFAULT); 1464 if (pfr_validate_addr(&ad)) 1465 senderr(EINVAL); 1466 if (pfr_lookup_addr(shadow, &ad, 1) != NULL) 1467 continue; 1468 p = pfr_create_kentry(&ad); 1469 if (p == NULL) 1470 senderr(ENOMEM); 1471 if (pfr_route_kentry(shadow, p)) { 1472 pfr_destroy_kentry(p); 1473 continue; 1474 } 1475 SLIST_INSERT_HEAD(&addrq, p, pfrke_workq); 1476 xaddr++; 1477 } 1478 if (!(flags & PFR_FLAG_DUMMY)) { 1479 if (kt->pfrkt_shadow != NULL) 1480 pfr_destroy_ktable(kt->pfrkt_shadow, 1); 1481 kt->pfrkt_flags |= PFR_TFLAG_INACTIVE; 1482 pfr_insert_ktables(&tableq); 1483 shadow->pfrkt_cnt = (flags & PFR_FLAG_ADDRSTOO) ? 1484 xaddr : NO_ADDRESSES; 1485 kt->pfrkt_shadow = shadow; 1486 } else { 1487 pfr_clean_node_mask(shadow, &addrq); 1488 pfr_destroy_ktable(shadow, 0); 1489 pfr_destroy_ktables(&tableq, 0); 1490 pfr_destroy_kentries(&addrq); 1491 } 1492 if (nadd != NULL) 1493 *nadd = xadd; 1494 if (naddr != NULL) 1495 *naddr = xaddr; 1496 return (0); 1497 _bad: 1498 pfr_destroy_ktable(shadow, 0); 1499 pfr_destroy_ktables(&tableq, 0); 1500 pfr_destroy_kentries(&addrq); 1501 return (rv); 1502 } 1503 1504 int 1505 pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags) 1506 { 1507 struct pfr_ktableworkq workq; 1508 struct pfr_ktable *p; 1509 struct pf_ruleset *rs; 1510 int xdel = 0; 1511 1512 ACCEPT_FLAGS(PFR_FLAG_DUMMY); 1513 rs = pf_find_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset); 1514 if (rs == NULL || !rs->topen || ticket != rs->tticket) 1515 return (0); 1516 SLIST_INIT(&workq); 1517 RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 1518 if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || 1519 pfr_skip_table(trs, p, 0)) 1520 continue; 1521 p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE; 1522 SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1523 xdel++; 1524 } 1525 if (!(flags & PFR_FLAG_DUMMY)) { 1526 pfr_setflags_ktables(&workq); 1527 rs->topen = 0; 1528 pf_remove_if_empty_ruleset(rs); 1529 } 1530 if (ndel != NULL) 1531 *ndel = xdel; 1532 return (0); 1533 } 1534 1535 int 1536 pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd, 1537 int *nchange, int flags) 1538 { 1539 struct pfr_ktable *p; 1540 struct pfr_ktableworkq workq; 1541 struct pf_ruleset *rs; 1542 int xadd = 0, xchange = 0; 1543 long tzero = time_second; 1544 1545 ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); 1546 rs = pf_find_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset); 1547 if (rs == NULL || !rs->topen || ticket != rs->tticket) 1548 return (EBUSY); 1549 1550 SLIST_INIT(&workq); 1551 RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { 1552 if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || 1553 pfr_skip_table(trs, p, 0)) 1554 continue; 1555 SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); 1556 if (p->pfrkt_flags & PFR_TFLAG_ACTIVE) 1557 xchange++; 1558 else 1559 xadd++; 1560 } 1561 1562 if (!(flags & PFR_FLAG_DUMMY)) { 1563 if (flags & PFR_FLAG_ATOMIC) 1564 crit_enter(); 1565 SLIST_FOREACH(p, &workq, pfrkt_workq) 1566 pfr_commit_ktable(p, tzero); 1567 if (flags & PFR_FLAG_ATOMIC) 1568 crit_exit(); 1569 rs->topen = 0; 1570 pf_remove_if_empty_ruleset(rs); 1571 } 1572 if (nadd != NULL) 1573 *nadd = xadd; 1574 if (nchange != NULL) 1575 *nchange = xchange; 1576 1577 return (0); 1578 } 1579 1580 void 1581 pfr_commit_ktable(struct pfr_ktable *kt, long tzero) 1582 { 1583 struct pfr_ktable *shadow = kt->pfrkt_shadow; 1584 int nflags; 1585 1586 if (shadow->pfrkt_cnt == NO_ADDRESSES) { 1587 if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 1588 pfr_clstats_ktable(kt, tzero, 1); 1589 } else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) { 1590 /* kt might contain addresses */ 1591 struct pfr_kentryworkq addrq, addq, changeq, delq, garbageq; 1592 struct pfr_kentry *p, *q, *next; 1593 struct pfr_addr ad; 1594 1595 pfr_enqueue_addrs(shadow, &addrq, NULL, 0); 1596 pfr_mark_addrs(kt); 1597 SLIST_INIT(&addq); 1598 SLIST_INIT(&changeq); 1599 SLIST_INIT(&delq); 1600 SLIST_INIT(&garbageq); 1601 pfr_clean_node_mask(shadow, &addrq); 1602 for (p = SLIST_FIRST(&addrq); p != NULL; p = next) { 1603 next = SLIST_NEXT(p, pfrke_workq); /* XXX */ 1604 pfr_copyout_addr(&ad, p); 1605 q = pfr_lookup_addr(kt, &ad, 1); 1606 if (q != NULL) { 1607 if (q->pfrke_not != p->pfrke_not) 1608 SLIST_INSERT_HEAD(&changeq, q, 1609 pfrke_workq); 1610 q->pfrke_mark = 1; 1611 SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq); 1612 } else { 1613 p->pfrke_tzero = tzero; 1614 SLIST_INSERT_HEAD(&addq, p, pfrke_workq); 1615 } 1616 } 1617 pfr_enqueue_addrs(kt, &delq, NULL, ENQUEUE_UNMARKED_ONLY); 1618 pfr_insert_kentries(kt, &addq, tzero); 1619 pfr_remove_kentries(kt, &delq); 1620 pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG); 1621 pfr_destroy_kentries(&garbageq); 1622 } else { 1623 /* kt cannot contain addresses */ 1624 SWAP(struct radix_node_head *, kt->pfrkt_ip4, 1625 shadow->pfrkt_ip4); 1626 SWAP(struct radix_node_head *, kt->pfrkt_ip6, 1627 shadow->pfrkt_ip6); 1628 SWAP(int, kt->pfrkt_cnt, shadow->pfrkt_cnt); 1629 pfr_clstats_ktable(kt, tzero, 1); 1630 } 1631 nflags = ((shadow->pfrkt_flags & PFR_TFLAG_USRMASK) | 1632 (kt->pfrkt_flags & PFR_TFLAG_SETMASK) | PFR_TFLAG_ACTIVE) 1633 & ~PFR_TFLAG_INACTIVE; 1634 pfr_destroy_ktable(shadow, 0); 1635 kt->pfrkt_shadow = NULL; 1636 pfr_setflags_ktable(kt, nflags); 1637 } 1638 1639 int 1640 pfr_validate_table(struct pfr_table *tbl, int allowedflags, int no_reserved) 1641 { 1642 int i; 1643 1644 if (!tbl->pfrt_name[0]) 1645 return (-1); 1646 if (no_reserved && !strcmp(tbl->pfrt_anchor, PF_RESERVED_ANCHOR)) 1647 return (-1); 1648 if (tbl->pfrt_name[PF_TABLE_NAME_SIZE-1]) 1649 return (-1); 1650 for (i = strlen(tbl->pfrt_name); i < PF_TABLE_NAME_SIZE; i++) 1651 if (tbl->pfrt_name[i]) 1652 return (-1); 1653 if (tbl->pfrt_flags & ~allowedflags) 1654 return (-1); 1655 return (0); 1656 } 1657 1658 int 1659 pfr_table_count(struct pfr_table *filter, int flags) 1660 { 1661 struct pf_ruleset *rs; 1662 struct pf_anchor *ac; 1663 1664 if (flags & PFR_FLAG_ALLRSETS) 1665 return (pfr_ktable_cnt); 1666 if (filter->pfrt_ruleset[0]) { 1667 rs = pf_find_ruleset(filter->pfrt_anchor, 1668 filter->pfrt_ruleset); 1669 return ((rs != NULL) ? rs->tables : -1); 1670 } 1671 if (filter->pfrt_anchor[0]) { 1672 ac = pf_find_anchor(filter->pfrt_anchor); 1673 return ((ac != NULL) ? ac->tables : -1); 1674 } 1675 return (pf_main_ruleset.tables); 1676 } 1677 1678 int 1679 pfr_skip_table(struct pfr_table *filter, struct pfr_ktable *kt, int flags) 1680 { 1681 if (flags & PFR_FLAG_ALLRSETS) 1682 return (0); 1683 if (strncmp(filter->pfrt_anchor, kt->pfrkt_anchor, 1684 PF_ANCHOR_NAME_SIZE)) 1685 return (1); 1686 if (!filter->pfrt_ruleset[0]) 1687 return (0); 1688 if (strncmp(filter->pfrt_ruleset, kt->pfrkt_ruleset, 1689 PF_RULESET_NAME_SIZE)) 1690 return (1); 1691 return (0); 1692 } 1693 1694 void 1695 pfr_insert_ktables(struct pfr_ktableworkq *workq) 1696 { 1697 struct pfr_ktable *p; 1698 1699 SLIST_FOREACH(p, workq, pfrkt_workq) 1700 pfr_insert_ktable(p); 1701 } 1702 1703 void 1704 pfr_insert_ktable(struct pfr_ktable *kt) 1705 { 1706 RB_INSERT(pfr_ktablehead, &pfr_ktables, kt); 1707 pfr_ktable_cnt++; 1708 if (kt->pfrkt_root != NULL) 1709 if (!kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]++) 1710 pfr_setflags_ktable(kt->pfrkt_root, 1711 kt->pfrkt_root->pfrkt_flags|PFR_TFLAG_REFDANCHOR); 1712 } 1713 1714 void 1715 pfr_setflags_ktables(struct pfr_ktableworkq *workq) 1716 { 1717 struct pfr_ktable *p; 1718 1719 SLIST_FOREACH(p, workq, pfrkt_workq) 1720 pfr_setflags_ktable(p, p->pfrkt_nflags); 1721 } 1722 1723 void 1724 pfr_setflags_ktable(struct pfr_ktable *kt, int newf) 1725 { 1726 struct pfr_kentryworkq addrq; 1727 1728 if (!(newf & PFR_TFLAG_REFERENCED) && 1729 !(newf & PFR_TFLAG_PERSIST)) 1730 newf &= ~PFR_TFLAG_ACTIVE; 1731 if (!(newf & PFR_TFLAG_ACTIVE)) 1732 newf &= ~PFR_TFLAG_USRMASK; 1733 if (!(newf & PFR_TFLAG_SETMASK)) { 1734 RB_REMOVE(pfr_ktablehead, &pfr_ktables, kt); 1735 if (kt->pfrkt_root != NULL) 1736 if (!--kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]) 1737 pfr_setflags_ktable(kt->pfrkt_root, 1738 kt->pfrkt_root->pfrkt_flags & 1739 ~PFR_TFLAG_REFDANCHOR); 1740 pfr_destroy_ktable(kt, 1); 1741 pfr_ktable_cnt--; 1742 return; 1743 } 1744 if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) { 1745 pfr_enqueue_addrs(kt, &addrq, NULL, 0); 1746 pfr_remove_kentries(kt, &addrq); 1747 } 1748 if (!(newf & PFR_TFLAG_INACTIVE) && kt->pfrkt_shadow != NULL) { 1749 pfr_destroy_ktable(kt->pfrkt_shadow, 1); 1750 kt->pfrkt_shadow = NULL; 1751 } 1752 kt->pfrkt_flags = newf; 1753 } 1754 1755 void 1756 pfr_clstats_ktables(struct pfr_ktableworkq *workq, long tzero, int recurse) 1757 { 1758 struct pfr_ktable *p; 1759 1760 SLIST_FOREACH(p, workq, pfrkt_workq) 1761 pfr_clstats_ktable(p, tzero, recurse); 1762 } 1763 1764 void 1765 pfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse) 1766 { 1767 struct pfr_kentryworkq addrq; 1768 1769 if (recurse) { 1770 pfr_enqueue_addrs(kt, &addrq, NULL, 0); 1771 pfr_clstats_kentries(&addrq, tzero, 0); 1772 } 1773 crit_enter(); 1774 bzero(kt->pfrkt_packets, sizeof(kt->pfrkt_packets)); 1775 bzero(kt->pfrkt_bytes, sizeof(kt->pfrkt_bytes)); 1776 kt->pfrkt_match = kt->pfrkt_nomatch = 0; 1777 crit_exit(); 1778 kt->pfrkt_tzero = tzero; 1779 } 1780 1781 struct pfr_ktable * 1782 pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset) 1783 { 1784 struct pfr_ktable *kt; 1785 struct pf_ruleset *rs; 1786 1787 kt = pool_get(&pfr_ktable_pl, PR_NOWAIT); 1788 if (kt == NULL) 1789 return (NULL); 1790 bzero(kt, sizeof(*kt)); 1791 kt->pfrkt_t = *tbl; 1792 1793 if (attachruleset) { 1794 rs = pf_find_or_create_ruleset(tbl->pfrt_anchor, 1795 tbl->pfrt_ruleset); 1796 if (!rs) { 1797 pfr_destroy_ktable(kt, 0); 1798 return (NULL); 1799 } 1800 kt->pfrkt_rs = rs; 1801 rs->tables++; 1802 if (rs->anchor != NULL) 1803 rs->anchor->tables++; 1804 } 1805 1806 if (!rn_inithead((void **)&kt->pfrkt_ip4, 1807 offsetof(struct sockaddr_in, sin_addr) * 8) || 1808 !rn_inithead((void **)&kt->pfrkt_ip6, 1809 offsetof(struct sockaddr_in6, sin6_addr) * 8)) { 1810 pfr_destroy_ktable(kt, 0); 1811 return (NULL); 1812 } 1813 kt->pfrkt_tzero = tzero; 1814 1815 return (kt); 1816 } 1817 1818 void 1819 pfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr) 1820 { 1821 struct pfr_ktable *p, *q; 1822 1823 for (p = SLIST_FIRST(workq); p; p = q) { 1824 q = SLIST_NEXT(p, pfrkt_workq); 1825 pfr_destroy_ktable(p, flushaddr); 1826 } 1827 } 1828 1829 void 1830 pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr) 1831 { 1832 struct pfr_kentryworkq addrq; 1833 1834 if (flushaddr) { 1835 pfr_enqueue_addrs(kt, &addrq, NULL, 0); 1836 pfr_clean_node_mask(kt, &addrq); 1837 pfr_destroy_kentries(&addrq); 1838 } 1839 if (kt->pfrkt_ip4 != NULL) 1840 free((caddr_t)kt->pfrkt_ip4, M_RTABLE); 1841 if (kt->pfrkt_ip6 != NULL) 1842 free((caddr_t)kt->pfrkt_ip6, M_RTABLE); 1843 if (kt->pfrkt_shadow != NULL) 1844 pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr); 1845 if (kt->pfrkt_rs != NULL) { 1846 kt->pfrkt_rs->tables--; 1847 if (kt->pfrkt_rs->anchor != NULL) 1848 kt->pfrkt_rs->anchor->tables--; 1849 pf_remove_if_empty_ruleset(kt->pfrkt_rs); 1850 } 1851 pool_put(&pfr_ktable_pl, kt); 1852 } 1853 1854 int 1855 pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q) 1856 { 1857 int d; 1858 1859 if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE))) 1860 return (d); 1861 if ((d = strncmp(p->pfrkt_anchor, q->pfrkt_anchor, 1862 PF_ANCHOR_NAME_SIZE))) 1863 return (d); 1864 return (strncmp(p->pfrkt_ruleset, q->pfrkt_ruleset, 1865 PF_RULESET_NAME_SIZE)); 1866 } 1867 1868 struct pfr_ktable * 1869 pfr_lookup_table(struct pfr_table *tbl) 1870 { 1871 /* struct pfr_ktable start like a struct pfr_table */ 1872 return (RB_FIND(pfr_ktablehead, &pfr_ktables, 1873 (struct pfr_ktable *)tbl)); 1874 } 1875 1876 int 1877 pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) 1878 { 1879 struct pfr_kentry *ke = NULL; 1880 int match; 1881 1882 if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 1883 kt = kt->pfrkt_root; 1884 if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 1885 return (0); 1886 1887 switch (af) { 1888 case AF_INET: 1889 pfr_sin.sin_addr.s_addr = a->addr32[0]; 1890 ke = (struct pfr_kentry *)rn_match((char *)&pfr_sin, 1891 kt->pfrkt_ip4); 1892 if (ke && KENTRY_RNF_ROOT(ke)) 1893 ke = NULL; 1894 break; 1895 case AF_INET6: 1896 bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr)); 1897 ke = (struct pfr_kentry *)rn_match((char *)&pfr_sin6, 1898 kt->pfrkt_ip6); 1899 if (ke && KENTRY_RNF_ROOT(ke)) 1900 ke = NULL; 1901 break; 1902 } 1903 match = (ke && !ke->pfrke_not); 1904 if (match) 1905 kt->pfrkt_match++; 1906 else 1907 kt->pfrkt_nomatch++; 1908 return (match); 1909 } 1910 1911 void 1912 pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, 1913 u_int64_t len, int dir_out, int op_pass, int notrule) 1914 { 1915 struct pfr_kentry *ke = NULL; 1916 1917 if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 1918 kt = kt->pfrkt_root; 1919 if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 1920 return; 1921 1922 switch (af) { 1923 case AF_INET: 1924 pfr_sin.sin_addr.s_addr = a->addr32[0]; 1925 ke = (struct pfr_kentry *)rn_match((char *)&pfr_sin, 1926 kt->pfrkt_ip4); 1927 if (ke && KENTRY_RNF_ROOT(ke)) 1928 ke = NULL; 1929 break; 1930 case AF_INET6: 1931 bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr)); 1932 ke = (struct pfr_kentry *)rn_match((char *)&pfr_sin6, 1933 kt->pfrkt_ip6); 1934 if (ke && KENTRY_RNF_ROOT(ke)) 1935 ke = NULL; 1936 break; 1937 } 1938 if ((ke == NULL || ke->pfrke_not) != notrule) { 1939 if (op_pass != PFR_OP_PASS) 1940 printf("pfr_update_stats: assertion failed.\n"); 1941 op_pass = PFR_OP_XPASS; 1942 } 1943 kt->pfrkt_packets[dir_out][op_pass]++; 1944 kt->pfrkt_bytes[dir_out][op_pass] += len; 1945 if (ke != NULL && op_pass != PFR_OP_XPASS) { 1946 ke->pfrke_packets[dir_out][op_pass]++; 1947 ke->pfrke_bytes[dir_out][op_pass] += len; 1948 } 1949 } 1950 1951 struct pfr_ktable * 1952 pfr_attach_table(struct pf_ruleset *rs, char *name) 1953 { 1954 struct pfr_ktable *kt, *rt; 1955 struct pfr_table tbl; 1956 struct pf_anchor *ac = rs->anchor; 1957 1958 bzero(&tbl, sizeof(tbl)); 1959 strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)); 1960 if (ac != NULL) { 1961 strlcpy(tbl.pfrt_anchor, ac->name, sizeof(tbl.pfrt_anchor)); 1962 strlcpy(tbl.pfrt_ruleset, rs->name, sizeof(tbl.pfrt_ruleset)); 1963 } 1964 kt = pfr_lookup_table(&tbl); 1965 if (kt == NULL) { 1966 kt = pfr_create_ktable(&tbl, time_second, 1); 1967 if (kt == NULL) 1968 return (NULL); 1969 if (ac != NULL) { 1970 bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor)); 1971 bzero(tbl.pfrt_ruleset, sizeof(tbl.pfrt_ruleset)); 1972 rt = pfr_lookup_table(&tbl); 1973 if (rt == NULL) { 1974 rt = pfr_create_ktable(&tbl, 0, 1); 1975 if (rt == NULL) { 1976 pfr_destroy_ktable(kt, 0); 1977 return (NULL); 1978 } 1979 pfr_insert_ktable(rt); 1980 } 1981 kt->pfrkt_root = rt; 1982 } 1983 pfr_insert_ktable(kt); 1984 } 1985 if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++) 1986 pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED); 1987 return (kt); 1988 } 1989 1990 void 1991 pfr_detach_table(struct pfr_ktable *kt) 1992 { 1993 if (kt->pfrkt_refcnt[PFR_REFCNT_RULE] <= 0) 1994 printf("pfr_detach_table: refcount = %d.\n", 1995 kt->pfrkt_refcnt[PFR_REFCNT_RULE]); 1996 else if (!--kt->pfrkt_refcnt[PFR_REFCNT_RULE]) 1997 pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED); 1998 } 1999 2000 int 2001 pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, 2002 struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af) 2003 { 2004 struct pfr_kentry *ke, *ke2; 2005 struct pf_addr *addr; 2006 union sockaddr_union mask; 2007 int idx = -1, use_counter = 0; 2008 2009 addr = (af == AF_INET) ? (struct pf_addr *)&pfr_sin.sin_addr : 2010 (struct pf_addr *)&pfr_sin6.sin6_addr; 2011 if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 2012 kt = kt->pfrkt_root; 2013 if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) 2014 return (-1); 2015 2016 if (pidx != NULL) 2017 idx = *pidx; 2018 if (counter != NULL && idx >= 0) 2019 use_counter = 1; 2020 if (idx < 0) 2021 idx = 0; 2022 2023 _next_block: 2024 ke = pfr_kentry_byidx(kt, idx, af); 2025 if (ke == NULL) 2026 return (1); 2027 pfr_prepare_network(&pfr_mask, af, ke->pfrke_net); 2028 *raddr = SUNION2PF(&ke->pfrke_sa, af); 2029 *rmask = SUNION2PF(&pfr_mask, af); 2030 2031 if (use_counter) { 2032 /* is supplied address within block? */ 2033 if (!PF_MATCHA(0, *raddr, *rmask, counter, af)) { 2034 /* no, go to next block in table */ 2035 idx++; 2036 use_counter = 0; 2037 goto _next_block; 2038 } 2039 PF_ACPY(addr, counter, af); 2040 } else { 2041 /* use first address of block */ 2042 PF_ACPY(addr, *raddr, af); 2043 } 2044 2045 if (!KENTRY_NETWORK(ke)) { 2046 /* this is a single IP address - no possible nested block */ 2047 PF_ACPY(counter, addr, af); 2048 *pidx = idx; 2049 return (0); 2050 } 2051 for (;;) { 2052 /* we don't want to use a nested block */ 2053 ke2 = (struct pfr_kentry *)(af == AF_INET ? 2054 rn_match((char *)&pfr_sin, kt->pfrkt_ip4) : 2055 rn_match((char *)&pfr_sin6, kt->pfrkt_ip6)); 2056 /* no need to check KENTRY_RNF_ROOT() here */ 2057 if (ke2 == ke) { 2058 /* lookup return the same block - perfect */ 2059 PF_ACPY(counter, addr, af); 2060 *pidx = idx; 2061 return (0); 2062 } 2063 2064 /* we need to increase the counter past the nested block */ 2065 pfr_prepare_network(&mask, AF_INET, ke2->pfrke_net); 2066 PF_POOLMASK(addr, addr, SUNION2PF(&mask, af), &pfr_ffaddr, af); 2067 PF_AINC(addr, af); 2068 if (!PF_MATCHA(0, *raddr, *rmask, addr, af)) { 2069 /* ok, we reached the end of our main block */ 2070 /* go to next block in table */ 2071 idx++; 2072 use_counter = 0; 2073 goto _next_block; 2074 } 2075 } 2076 } 2077 2078 struct pfr_kentry * 2079 pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af) 2080 { 2081 struct pfr_walktree w; 2082 2083 bzero(&w, sizeof(w)); 2084 w.pfrw_op = PFRW_POOL_GET; 2085 w.pfrw_cnt = idx; 2086 2087 switch (af) { 2088 case AF_INET: 2089 kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 2090 return (w.pfrw_kentry); 2091 case AF_INET6: 2092 kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); 2093 return (w.pfrw_kentry); 2094 default: 2095 return (NULL); 2096 } 2097 } 2098 2099 void 2100 pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn) 2101 { 2102 struct pfr_walktree w; 2103 2104 bzero(&w, sizeof(w)); 2105 w.pfrw_op = PFRW_DYNADDR_UPDATE; 2106 w.pfrw_dyn = dyn; 2107 2108 crit_enter(); 2109 dyn->pfid_acnt4 = 0; 2110 dyn->pfid_acnt6 = 0; 2111 if (!dyn->pfid_af || dyn->pfid_af == AF_INET) 2112 kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); 2113 if (!dyn->pfid_af || dyn->pfid_af == AF_INET6) 2114 kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); 2115 crit_exit(); 2116 } 2117