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