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