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