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