1 /* $NetBSD: pf_ioctl.c,v 1.31 2007/07/09 21:10:48 ad Exp $ */ 2 /* $OpenBSD: pf_ioctl.c,v 1.139 2005/03/03 07:13:39 dhartmei Exp $ */ 3 4 /* 5 * Copyright (c) 2001 Daniel Hartmeier 6 * Copyright (c) 2002,2003 Henning Brauer 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * - Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * - Redistributions in binary form must reproduce the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer in the documentation and/or other materials provided 18 * with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 * 33 * Effort sponsored in part by the Defense Advanced Research Projects 34 * Agency (DARPA) and Air Force Research Laboratory, Air Force 35 * Materiel Command, USAF, under agreement number F30602-01-2-0537. 36 * 37 */ 38 39 #ifdef _KERNEL_OPT 40 #include "opt_inet.h" 41 #include "opt_pfil_hooks.h" 42 #endif 43 44 #ifdef __OpenBSD__ 45 #include "pfsync.h" 46 #else 47 #define NPFSYNC 0 48 #endif 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/mbuf.h> 53 #include <sys/filio.h> 54 #include <sys/fcntl.h> 55 #include <sys/socket.h> 56 #include <sys/socketvar.h> 57 #include <sys/kernel.h> 58 #include <sys/time.h> 59 #ifdef __OpenBSD__ 60 #include <sys/timeout.h> 61 #else 62 #include <sys/callout.h> 63 #endif 64 #include <sys/pool.h> 65 #include <sys/malloc.h> 66 #ifdef __NetBSD__ 67 #include <sys/conf.h> 68 #include <sys/lwp.h> 69 #include <sys/kauth.h> 70 #endif 71 72 #include <net/if.h> 73 #include <net/if_types.h> 74 #include <net/route.h> 75 76 #include <netinet/in.h> 77 #include <netinet/in_var.h> 78 #include <netinet/in_systm.h> 79 #include <netinet/ip.h> 80 #include <netinet/ip_var.h> 81 #include <netinet/ip_icmp.h> 82 83 #ifdef __OpenBSD__ 84 #include <dev/rndvar.h> 85 #endif 86 #include <net/pfvar.h> 87 88 #if NPFSYNC > 0 89 #include <net/if_pfsync.h> 90 #endif /* NPFSYNC > 0 */ 91 92 #ifdef INET6 93 #include <netinet/ip6.h> 94 #include <netinet/in_pcb.h> 95 #endif /* INET6 */ 96 97 #ifdef ALTQ 98 #include <altq/altq.h> 99 #endif 100 101 void pfattach(int); 102 #ifdef _LKM 103 void pfdetach(void); 104 #endif 105 int pfopen(dev_t, int, int, struct lwp *); 106 int pfclose(dev_t, int, int, struct lwp *); 107 struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t, 108 u_int8_t, u_int8_t, u_int8_t); 109 int pf_get_ruleset_number(u_int8_t); 110 void pf_init_ruleset(struct pf_ruleset *); 111 int pf_anchor_setup(struct pf_rule *, 112 const struct pf_ruleset *, const char *); 113 int pf_anchor_copyout(const struct pf_ruleset *, 114 const struct pf_rule *, struct pfioc_rule *); 115 void pf_anchor_remove(struct pf_rule *); 116 117 void pf_mv_pool(struct pf_palist *, struct pf_palist *); 118 void pf_empty_pool(struct pf_palist *); 119 int pfioctl(dev_t, u_long, void *, int, struct lwp *); 120 #ifdef ALTQ 121 int pf_begin_altq(u_int32_t *); 122 int pf_rollback_altq(u_int32_t); 123 int pf_commit_altq(u_int32_t); 124 int pf_enable_altq(struct pf_altq *); 125 int pf_disable_altq(struct pf_altq *); 126 #endif /* ALTQ */ 127 int pf_begin_rules(u_int32_t *, int, const char *); 128 int pf_rollback_rules(u_int32_t, int, char *); 129 int pf_commit_rules(u_int32_t, int, char *); 130 131 #ifdef __NetBSD__ 132 const struct cdevsw pf_cdevsw = { 133 pfopen, pfclose, noread, nowrite, pfioctl, 134 nostop, notty, nopoll, nommap, nokqfilter, D_OTHER, 135 }; 136 137 static int pf_pfil_attach(void); 138 static int pf_pfil_detach(void); 139 140 static int pf_pfil_attached = 0; 141 #endif 142 143 #ifdef __OpenBSD__ 144 extern struct timeout pf_expire_to; 145 #else 146 extern struct callout pf_expire_to; 147 #endif 148 149 struct pf_rule pf_default_rule; 150 #ifdef ALTQ 151 static int pf_altq_running; 152 #endif 153 154 #define TAGID_MAX 50000 155 TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags), 156 pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids); 157 158 #if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE) 159 #error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE 160 #endif 161 static u_int16_t tagname2tag(struct pf_tags *, char *); 162 static void tag2tagname(struct pf_tags *, u_int16_t, char *); 163 static void tag_unref(struct pf_tags *, u_int16_t); 164 int pf_rtlabel_add(struct pf_addr_wrap *); 165 void pf_rtlabel_remove(struct pf_addr_wrap *); 166 void pf_rtlabel_copyout(struct pf_addr_wrap *); 167 168 #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x 169 170 #ifdef __NetBSD__ 171 extern struct pfil_head if_pfil; 172 #endif 173 174 void 175 pfattach(int num) 176 { 177 u_int32_t *timeout = pf_default_rule.timeout; 178 179 #ifdef __NetBSD__ 180 pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl", 181 &pool_allocator_nointr, IPL_NONE); 182 pool_init(&pf_src_tree_pl, sizeof(struct pf_src_node), 0, 0, 0, 183 "pfsrctrpl", NULL, IPL_SOFTNET); 184 pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", 185 NULL, IPL_SOFTNET); 186 pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", 187 &pool_allocator_nointr, IPL_NONE); 188 pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, 189 "pfpooladdrpl", &pool_allocator_nointr, IPL_NONE); 190 #else 191 pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl", 192 &pool_allocator_nointr); 193 pool_init(&pf_src_tree_pl, sizeof(struct pf_src_node), 0, 0, 0, 194 "pfsrctrpl", NULL); 195 pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", 196 NULL); 197 pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", 198 &pool_allocator_nointr); 199 pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, 200 "pfpooladdrpl", &pool_allocator_nointr); 201 #endif 202 203 pfr_initialize(); 204 pfi_initialize(); 205 pf_osfp_initialize(); 206 207 pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp, 208 pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0); 209 210 RB_INIT(&tree_src_tracking); 211 RB_INIT(&pf_anchors); 212 pf_init_ruleset(&pf_main_ruleset); 213 TAILQ_INIT(&pf_altqs[0]); 214 TAILQ_INIT(&pf_altqs[1]); 215 TAILQ_INIT(&pf_pabuf); 216 pf_altqs_active = &pf_altqs[0]; 217 pf_altqs_inactive = &pf_altqs[1]; 218 TAILQ_INIT(&state_updates); 219 220 /* default rule should never be garbage collected */ 221 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; 222 pf_default_rule.action = PF_PASS; 223 pf_default_rule.nr = -1; 224 225 /* initialize default timeouts */ 226 timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; 227 timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; 228 timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; 229 timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; 230 timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; 231 timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; 232 timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; 233 timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; 234 timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; 235 timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; 236 timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; 237 timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; 238 timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; 239 timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; 240 timeout[PFTM_FRAG] = PFTM_FRAG_VAL; 241 timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; 242 timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; 243 timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; 244 245 #ifdef __OpenBSD__ 246 timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to); 247 timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz); 248 #else 249 callout_init(&pf_expire_to, 0); 250 callout_reset(&pf_expire_to, timeout[PFTM_INTERVAL] * hz, 251 pf_purge_timeout, &pf_expire_to); 252 #endif 253 254 pf_normalize_init(); 255 bzero(&pf_status, sizeof(pf_status)); 256 pf_status.debug = PF_DEBUG_URGENT; 257 258 /* XXX do our best to avoid a conflict */ 259 pf_status.hostid = arc4random(); 260 } 261 262 #ifdef _LKM 263 void 264 pfdetach(void) 265 { 266 struct pf_anchor *anchor; 267 struct pf_state *state; 268 struct pf_src_node *node; 269 struct pfioc_table pt; 270 u_int32_t ticket; 271 int i; 272 char r = '\0'; 273 274 (void)pf_pfil_detach(); 275 276 callout_stop(&pf_expire_to); 277 pf_status.running = 0; 278 279 /* clear the rulesets */ 280 for (i = 0; i < PF_RULESET_MAX; i++) 281 if (pf_begin_rules(&ticket, i, &r) == 0) 282 pf_commit_rules(ticket, i, &r); 283 #ifdef ALTQ 284 if (pf_begin_altq(&ticket) == 0) 285 pf_commit_altq(ticket); 286 #endif 287 288 /* clear states */ 289 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 290 state->timeout = PFTM_PURGE; 291 #if NPFSYNC 292 state->sync_flags = PFSTATE_NOSYNC; 293 #endif 294 } 295 pf_purge_expired_states(); 296 #if NPFSYNC 297 pfsync_clear_states(pf_status.hostid, NULL); 298 #endif 299 300 /* clear source nodes */ 301 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 302 state->src_node = NULL; 303 state->nat_src_node = NULL; 304 } 305 RB_FOREACH(node, pf_src_tree, &tree_src_tracking) { 306 node->expire = 1; 307 node->states = 0; 308 } 309 pf_purge_expired_src_nodes(); 310 311 /* clear tables */ 312 memset(&pt, '\0', sizeof(pt)); 313 pfr_clr_tables(&pt.pfrio_table, &pt.pfrio_ndel, pt.pfrio_flags); 314 315 /* destroy anchors */ 316 while ((anchor = RB_MIN(pf_anchor_global, &pf_anchors)) != NULL) { 317 for (i = 0; i < PF_RULESET_MAX; i++) 318 if (pf_begin_rules(&ticket, i, anchor->name) == 0) 319 pf_commit_rules(ticket, i, anchor->name); 320 } 321 322 /* destroy main ruleset */ 323 pf_remove_if_empty_ruleset(&pf_main_ruleset); 324 325 /* destroy the pools */ 326 pool_destroy(&pf_pooladdr_pl); 327 pool_destroy(&pf_altq_pl); 328 pool_destroy(&pf_state_pl); 329 pool_destroy(&pf_rule_pl); 330 pool_destroy(&pf_src_tree_pl); 331 332 /* destroy subsystems */ 333 pf_normalize_destroy(); 334 pf_osfp_destroy(); 335 pfr_destroy(); 336 pfi_destroy(); 337 } 338 #endif 339 340 int 341 pfopen(dev_t dev, int flags, int fmt, struct lwp *l) 342 { 343 if (minor(dev) >= 1) 344 return (ENXIO); 345 return (0); 346 } 347 348 int 349 pfclose(dev_t dev, int flags, int fmt, struct lwp *l) 350 { 351 if (minor(dev) >= 1) 352 return (ENXIO); 353 return (0); 354 } 355 356 struct pf_pool * 357 pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action, 358 u_int32_t rule_number, u_int8_t r_last, u_int8_t active, 359 u_int8_t check_ticket) 360 { 361 struct pf_ruleset *ruleset; 362 struct pf_rule *rule; 363 int rs_num; 364 365 ruleset = pf_find_ruleset(anchor); 366 if (ruleset == NULL) 367 return (NULL); 368 rs_num = pf_get_ruleset_number(rule_action); 369 if (rs_num >= PF_RULESET_MAX) 370 return (NULL); 371 if (active) { 372 if (check_ticket && ticket != 373 ruleset->rules[rs_num].active.ticket) 374 return (NULL); 375 if (r_last) 376 rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 377 pf_rulequeue); 378 else 379 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 380 } else { 381 if (check_ticket && ticket != 382 ruleset->rules[rs_num].inactive.ticket) 383 return (NULL); 384 if (r_last) 385 rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 386 pf_rulequeue); 387 else 388 rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr); 389 } 390 if (!r_last) { 391 while ((rule != NULL) && (rule->nr != rule_number)) 392 rule = TAILQ_NEXT(rule, entries); 393 } 394 if (rule == NULL) 395 return (NULL); 396 397 return (&rule->rpool); 398 } 399 400 int 401 pf_get_ruleset_number(u_int8_t action) 402 { 403 switch (action) { 404 case PF_SCRUB: 405 case PF_NOSCRUB: 406 return (PF_RULESET_SCRUB); 407 break; 408 case PF_PASS: 409 case PF_DROP: 410 return (PF_RULESET_FILTER); 411 break; 412 case PF_NAT: 413 case PF_NONAT: 414 return (PF_RULESET_NAT); 415 break; 416 case PF_BINAT: 417 case PF_NOBINAT: 418 return (PF_RULESET_BINAT); 419 break; 420 case PF_RDR: 421 case PF_NORDR: 422 return (PF_RULESET_RDR); 423 break; 424 default: 425 return (PF_RULESET_MAX); 426 break; 427 } 428 } 429 430 void 431 pf_init_ruleset(struct pf_ruleset *ruleset) 432 { 433 int i; 434 435 memset(ruleset, 0, sizeof(struct pf_ruleset)); 436 for (i = 0; i < PF_RULESET_MAX; i++) { 437 TAILQ_INIT(&ruleset->rules[i].queues[0]); 438 TAILQ_INIT(&ruleset->rules[i].queues[1]); 439 ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0]; 440 ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1]; 441 } 442 } 443 444 struct pf_anchor * 445 pf_find_anchor(const char *path) 446 { 447 static struct pf_anchor key; 448 449 memset(&key, 0, sizeof(key)); 450 strlcpy(key.path, path, sizeof(key.path)); 451 return (RB_FIND(pf_anchor_global, &pf_anchors, &key)); 452 } 453 454 struct pf_ruleset * 455 pf_find_ruleset(const char *path) 456 { 457 struct pf_anchor *anchor; 458 459 while (*path == '/') 460 path++; 461 if (!*path) 462 return (&pf_main_ruleset); 463 anchor = pf_find_anchor(path); 464 if (anchor == NULL) 465 return (NULL); 466 else 467 return (&anchor->ruleset); 468 } 469 470 struct pf_ruleset * 471 pf_find_or_create_ruleset(const char *path) 472 { 473 static char p[MAXPATHLEN]; 474 char *q = NULL /* XXX gcc */, *r; 475 struct pf_ruleset *ruleset; 476 struct pf_anchor *anchor = NULL /* XXX gcc */, 477 *dup, *parent = NULL; 478 479 while (*path == '/') 480 path++; 481 ruleset = pf_find_ruleset(path); 482 if (ruleset != NULL) 483 return (ruleset); 484 strlcpy(p, path, sizeof(p)); 485 while (parent == NULL && (q = strrchr(p, '/')) != NULL) { 486 *q = 0; 487 if ((ruleset = pf_find_ruleset(p)) != NULL) { 488 parent = ruleset->anchor; 489 break; 490 } 491 } 492 if (q == NULL) 493 q = p; 494 else 495 q++; 496 strlcpy(p, path, sizeof(p)); 497 if (!*q) 498 return (NULL); 499 while ((r = strchr(q, '/')) != NULL || *q) { 500 if (r != NULL) 501 *r = 0; 502 if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE || 503 (parent != NULL && strlen(parent->path) >= 504 MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) 505 return (NULL); 506 anchor = (struct pf_anchor *)malloc(sizeof(*anchor), M_TEMP, 507 M_NOWAIT); 508 if (anchor == NULL) 509 return (NULL); 510 memset(anchor, 0, sizeof(*anchor)); 511 RB_INIT(&anchor->children); 512 strlcpy(anchor->name, q, sizeof(anchor->name)); 513 if (parent != NULL) { 514 strlcpy(anchor->path, parent->path, 515 sizeof(anchor->path)); 516 strlcat(anchor->path, "/", sizeof(anchor->path)); 517 } 518 strlcat(anchor->path, anchor->name, sizeof(anchor->path)); 519 if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) != 520 NULL) { 521 printf("pf_find_or_create_ruleset: RB_INSERT1 " 522 "'%s' '%s' collides with '%s' '%s'\n", 523 anchor->path, anchor->name, dup->path, dup->name); 524 free(anchor, M_TEMP); 525 return (NULL); 526 } 527 if (parent != NULL) { 528 anchor->parent = parent; 529 if ((dup = RB_INSERT(pf_anchor_node, &parent->children, 530 anchor)) != NULL) { 531 printf("pf_find_or_create_ruleset: " 532 "RB_INSERT2 '%s' '%s' collides with " 533 "'%s' '%s'\n", anchor->path, anchor->name, 534 dup->path, dup->name); 535 RB_REMOVE(pf_anchor_global, &pf_anchors, 536 anchor); 537 free(anchor, M_TEMP); 538 return (NULL); 539 } 540 } 541 pf_init_ruleset(&anchor->ruleset); 542 anchor->ruleset.anchor = anchor; 543 parent = anchor; 544 if (r != NULL) 545 q = r + 1; 546 else 547 *q = 0; 548 } 549 return (&anchor->ruleset); 550 } 551 552 void 553 pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset) 554 { 555 struct pf_anchor *parent; 556 int i; 557 558 while (ruleset != NULL) { 559 if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL || 560 !RB_EMPTY(&ruleset->anchor->children) || 561 ruleset->anchor->refcnt > 0 || ruleset->tables > 0 || 562 ruleset->topen) 563 return; 564 for (i = 0; i < PF_RULESET_MAX; ++i) 565 if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) || 566 !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) || 567 ruleset->rules[i].inactive.open) 568 return; 569 RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor); 570 if ((parent = ruleset->anchor->parent) != NULL) 571 RB_REMOVE(pf_anchor_node, &parent->children, 572 ruleset->anchor); 573 free(ruleset->anchor, M_TEMP); 574 if (parent == NULL) 575 return; 576 ruleset = &parent->ruleset; 577 } 578 } 579 580 int 581 pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s, 582 const char *name) 583 { 584 static char *p, path[MAXPATHLEN]; 585 struct pf_ruleset *ruleset; 586 587 r->anchor = NULL; 588 r->anchor_relative = 0; 589 r->anchor_wildcard = 0; 590 if (!name[0]) 591 return (0); 592 if (name[0] == '/') 593 strlcpy(path, name + 1, sizeof(path)); 594 else { 595 /* relative path */ 596 r->anchor_relative = 1; 597 if (s->anchor == NULL || !s->anchor->path[0]) 598 path[0] = 0; 599 else 600 strlcpy(path, s->anchor->path, sizeof(path)); 601 while (name[0] == '.' && name[1] == '.' && name[2] == '/') { 602 if (!path[0]) { 603 printf("pf_anchor_setup: .. beyond root\n"); 604 return (1); 605 } 606 if ((p = strrchr(path, '/')) != NULL) 607 *p = 0; 608 else 609 path[0] = 0; 610 r->anchor_relative++; 611 name += 3; 612 } 613 if (path[0]) 614 strlcat(path, "/", sizeof(path)); 615 strlcat(path, name, sizeof(path)); 616 } 617 if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) { 618 r->anchor_wildcard = 1; 619 *p = 0; 620 } 621 ruleset = pf_find_or_create_ruleset(path); 622 if (ruleset == NULL || ruleset->anchor == NULL) { 623 printf("pf_anchor_setup: ruleset\n"); 624 return (1); 625 } 626 r->anchor = ruleset->anchor; 627 r->anchor->refcnt++; 628 return (0); 629 } 630 631 int 632 pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r, 633 struct pfioc_rule *pr) 634 { 635 pr->anchor_call[0] = 0; 636 if (r->anchor == NULL) 637 return (0); 638 if (!r->anchor_relative) { 639 strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call)); 640 strlcat(pr->anchor_call, r->anchor->path, 641 sizeof(pr->anchor_call)); 642 } else { 643 char a[MAXPATHLEN], b[MAXPATHLEN], *p; 644 int i; 645 646 if (rs->anchor == NULL) 647 a[0] = 0; 648 else 649 strlcpy(a, rs->anchor->path, sizeof(a)); 650 strlcpy(b, r->anchor->path, sizeof(b)); 651 for (i = 1; i < r->anchor_relative; ++i) { 652 if ((p = strrchr(a, '/')) == NULL) 653 p = a; 654 *p = 0; 655 strlcat(pr->anchor_call, "../", 656 sizeof(pr->anchor_call)); 657 } 658 if (strncmp(a, b, strlen(a))) { 659 printf("pf_anchor_copyout: '%s' '%s'\n", a, b); 660 return (1); 661 } 662 if (strlen(b) > strlen(a)) 663 strlcat(pr->anchor_call, b + (a[0] ? strlen(a) + 1 : 0), 664 sizeof(pr->anchor_call)); 665 } 666 if (r->anchor_wildcard) 667 strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*", 668 sizeof(pr->anchor_call)); 669 return (0); 670 } 671 672 void 673 pf_anchor_remove(struct pf_rule *r) 674 { 675 if (r->anchor == NULL) 676 return; 677 if (r->anchor->refcnt <= 0) { 678 printf("pf_anchor_remove: broken refcount"); 679 r->anchor = NULL; 680 return; 681 } 682 if (!--r->anchor->refcnt) 683 pf_remove_if_empty_ruleset(&r->anchor->ruleset); 684 r->anchor = NULL; 685 } 686 687 void 688 pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb) 689 { 690 struct pf_pooladdr *mv_pool_pa; 691 692 while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) { 693 TAILQ_REMOVE(poola, mv_pool_pa, entries); 694 TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries); 695 } 696 } 697 698 void 699 pf_empty_pool(struct pf_palist *poola) 700 { 701 struct pf_pooladdr *empty_pool_pa; 702 703 while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) { 704 pfi_dynaddr_remove(&empty_pool_pa->addr); 705 pf_tbladdr_remove(&empty_pool_pa->addr); 706 pfi_detach_rule(empty_pool_pa->kif); 707 TAILQ_REMOVE(poola, empty_pool_pa, entries); 708 pool_put(&pf_pooladdr_pl, empty_pool_pa); 709 } 710 } 711 712 void 713 pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) 714 { 715 if (rulequeue != NULL) { 716 if (rule->states <= 0) { 717 /* 718 * XXX - we need to remove the table *before* detaching 719 * the rule to make sure the table code does not delete 720 * the anchor under our feet. 721 */ 722 pf_tbladdr_remove(&rule->src.addr); 723 pf_tbladdr_remove(&rule->dst.addr); 724 if (rule->overload_tbl) 725 pfr_detach_table(rule->overload_tbl); 726 } 727 TAILQ_REMOVE(rulequeue, rule, entries); 728 rule->entries.tqe_prev = NULL; 729 rule->nr = -1; 730 } 731 732 if (rule->states > 0 || rule->src_nodes > 0 || 733 rule->entries.tqe_prev != NULL) 734 return; 735 pf_tag_unref(rule->tag); 736 pf_tag_unref(rule->match_tag); 737 #ifdef ALTQ 738 if (rule->pqid != rule->qid) 739 pf_qid_unref(rule->pqid); 740 pf_qid_unref(rule->qid); 741 #endif 742 pf_rtlabel_remove(&rule->src.addr); 743 pf_rtlabel_remove(&rule->dst.addr); 744 pfi_dynaddr_remove(&rule->src.addr); 745 pfi_dynaddr_remove(&rule->dst.addr); 746 if (rulequeue == NULL) { 747 pf_tbladdr_remove(&rule->src.addr); 748 pf_tbladdr_remove(&rule->dst.addr); 749 if (rule->overload_tbl) 750 pfr_detach_table(rule->overload_tbl); 751 } 752 pfi_detach_rule(rule->kif); 753 pf_anchor_remove(rule); 754 pf_empty_pool(&rule->rpool.list); 755 pool_put(&pf_rule_pl, rule); 756 } 757 758 static u_int16_t 759 tagname2tag(struct pf_tags *head, char *tagname) 760 { 761 struct pf_tagname *tag, *p = NULL; 762 u_int16_t new_tagid = 1; 763 764 TAILQ_FOREACH(tag, head, entries) 765 if (strcmp(tagname, tag->name) == 0) { 766 tag->ref++; 767 return (tag->tag); 768 } 769 770 /* 771 * to avoid fragmentation, we do a linear search from the beginning 772 * and take the first free slot we find. if there is none or the list 773 * is empty, append a new entry at the end. 774 */ 775 776 /* new entry */ 777 if (!TAILQ_EMPTY(head)) 778 for (p = TAILQ_FIRST(head); p != NULL && 779 p->tag == new_tagid; p = TAILQ_NEXT(p, entries)) 780 new_tagid = p->tag + 1; 781 782 if (new_tagid > TAGID_MAX) 783 return (0); 784 785 /* allocate and fill new struct pf_tagname */ 786 tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname), 787 M_TEMP, M_NOWAIT); 788 if (tag == NULL) 789 return (0); 790 bzero(tag, sizeof(struct pf_tagname)); 791 strlcpy(tag->name, tagname, sizeof(tag->name)); 792 tag->tag = new_tagid; 793 tag->ref++; 794 795 if (p != NULL) /* insert new entry before p */ 796 TAILQ_INSERT_BEFORE(p, tag, entries); 797 else /* either list empty or no free slot in between */ 798 TAILQ_INSERT_TAIL(head, tag, entries); 799 800 return (tag->tag); 801 } 802 803 static void 804 tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p) 805 { 806 struct pf_tagname *tag; 807 808 TAILQ_FOREACH(tag, head, entries) 809 if (tag->tag == tagid) { 810 strlcpy(p, tag->name, PF_TAG_NAME_SIZE); 811 return; 812 } 813 } 814 815 static void 816 tag_unref(struct pf_tags *head, u_int16_t tag) 817 { 818 struct pf_tagname *p, *next; 819 820 if (tag == 0) 821 return; 822 823 for (p = TAILQ_FIRST(head); p != NULL; p = next) { 824 next = TAILQ_NEXT(p, entries); 825 if (tag == p->tag) { 826 if (--p->ref == 0) { 827 TAILQ_REMOVE(head, p, entries); 828 free(p, M_TEMP); 829 } 830 break; 831 } 832 } 833 } 834 835 u_int16_t 836 pf_tagname2tag(char *tagname) 837 { 838 return (tagname2tag(&pf_tags, tagname)); 839 } 840 841 void 842 pf_tag2tagname(u_int16_t tagid, char *p) 843 { 844 return (tag2tagname(&pf_tags, tagid, p)); 845 } 846 847 void 848 pf_tag_ref(u_int16_t tag) 849 { 850 struct pf_tagname *t; 851 852 TAILQ_FOREACH(t, &pf_tags, entries) 853 if (t->tag == tag) 854 break; 855 if (t != NULL) 856 t->ref++; 857 } 858 859 void 860 pf_tag_unref(u_int16_t tag) 861 { 862 return (tag_unref(&pf_tags, tag)); 863 } 864 865 int 866 pf_rtlabel_add(struct pf_addr_wrap *a) 867 { 868 #ifdef __OpenBSD__ 869 if (a->type == PF_ADDR_RTLABEL && 870 (a->v.rtlabel = rtlabel_name2id(a->v.rtlabelname)) == 0) 871 return (-1); 872 #endif 873 return (0); 874 } 875 876 void 877 pf_rtlabel_remove(struct pf_addr_wrap *a) 878 { 879 #ifdef __OpenBSD__ 880 if (a->type == PF_ADDR_RTLABEL) 881 rtlabel_unref(a->v.rtlabel); 882 #endif 883 } 884 885 void 886 pf_rtlabel_copyout(struct pf_addr_wrap *a) 887 { 888 #ifdef __OpenBSD__ 889 const char *name; 890 891 if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) { 892 if ((name = rtlabel_id2name(a->v.rtlabel)) == NULL) 893 strlcpy(a->v.rtlabelname, "?", 894 sizeof(a->v.rtlabelname)); 895 else 896 strlcpy(a->v.rtlabelname, name, 897 sizeof(a->v.rtlabelname)); 898 } 899 #endif 900 } 901 902 #ifdef ALTQ 903 u_int32_t 904 pf_qname2qid(char *qname) 905 { 906 return ((u_int32_t)tagname2tag(&pf_qids, qname)); 907 } 908 909 void 910 pf_qid2qname(u_int32_t qid, char *p) 911 { 912 return (tag2tagname(&pf_qids, (u_int16_t)qid, p)); 913 } 914 915 void 916 pf_qid_unref(u_int32_t qid) 917 { 918 return (tag_unref(&pf_qids, (u_int16_t)qid)); 919 } 920 921 int 922 pf_begin_altq(u_int32_t *ticket) 923 { 924 struct pf_altq *altq; 925 int error = 0; 926 927 /* Purge the old altq list */ 928 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 929 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 930 if (altq->qname[0] == 0) { 931 /* detach and destroy the discipline */ 932 error = altq_remove(altq); 933 } else 934 pf_qid_unref(altq->qid); 935 pool_put(&pf_altq_pl, altq); 936 } 937 if (error) 938 return (error); 939 *ticket = ++ticket_altqs_inactive; 940 altqs_inactive_open = 1; 941 return (0); 942 } 943 944 int 945 pf_rollback_altq(u_int32_t ticket) 946 { 947 struct pf_altq *altq; 948 int error = 0; 949 950 if (!altqs_inactive_open || ticket != ticket_altqs_inactive) 951 return (0); 952 /* Purge the old altq list */ 953 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 954 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 955 if (altq->qname[0] == 0) { 956 /* detach and destroy the discipline */ 957 error = altq_remove(altq); 958 } else 959 pf_qid_unref(altq->qid); 960 pool_put(&pf_altq_pl, altq); 961 } 962 altqs_inactive_open = 0; 963 return (error); 964 } 965 966 int 967 pf_commit_altq(u_int32_t ticket) 968 { 969 struct pf_altqqueue *old_altqs; 970 struct pf_altq *altq; 971 int s, err, error = 0; 972 973 if (!altqs_inactive_open || ticket != ticket_altqs_inactive) 974 return (EBUSY); 975 976 /* swap altqs, keep the old. */ 977 s = splsoftnet(); 978 old_altqs = pf_altqs_active; 979 pf_altqs_active = pf_altqs_inactive; 980 pf_altqs_inactive = old_altqs; 981 ticket_altqs_active = ticket_altqs_inactive; 982 983 /* Attach new disciplines */ 984 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 985 if (altq->qname[0] == 0) { 986 /* attach the discipline */ 987 error = altq_pfattach(altq); 988 if (error == 0 && pf_altq_running) 989 error = pf_enable_altq(altq); 990 if (error != 0) { 991 splx(s); 992 return (error); 993 } 994 } 995 } 996 997 /* Purge the old altq list */ 998 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 999 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 1000 if (altq->qname[0] == 0) { 1001 /* detach and destroy the discipline */ 1002 if (pf_altq_running) 1003 error = pf_disable_altq(altq); 1004 err = altq_pfdetach(altq); 1005 if (err != 0 && error == 0) 1006 error = err; 1007 err = altq_remove(altq); 1008 if (err != 0 && error == 0) 1009 error = err; 1010 } else 1011 pf_qid_unref(altq->qid); 1012 pool_put(&pf_altq_pl, altq); 1013 } 1014 splx(s); 1015 1016 altqs_inactive_open = 0; 1017 return (error); 1018 } 1019 1020 int 1021 pf_enable_altq(struct pf_altq *altq) 1022 { 1023 struct ifnet *ifp; 1024 struct tb_profile tb; 1025 int s, error = 0; 1026 1027 if ((ifp = ifunit(altq->ifname)) == NULL) 1028 return (EINVAL); 1029 1030 if (ifp->if_snd.altq_type != ALTQT_NONE) 1031 error = altq_enable(&ifp->if_snd); 1032 1033 /* set tokenbucket regulator */ 1034 if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { 1035 tb.rate = altq->ifbandwidth; 1036 tb.depth = altq->tbrsize; 1037 #ifdef __OpenBSD__ 1038 s = splimp(); 1039 #else 1040 s = splnet(); 1041 #endif 1042 error = tbr_set(&ifp->if_snd, &tb); 1043 splx(s); 1044 } 1045 1046 return (error); 1047 } 1048 1049 int 1050 pf_disable_altq(struct pf_altq *altq) 1051 { 1052 struct ifnet *ifp; 1053 struct tb_profile tb; 1054 int s, error; 1055 1056 if ((ifp = ifunit(altq->ifname)) == NULL) 1057 return (EINVAL); 1058 1059 /* 1060 * when the discipline is no longer referenced, it was overridden 1061 * by a new one. if so, just return. 1062 */ 1063 if (altq->altq_disc != ifp->if_snd.altq_disc) 1064 return (0); 1065 1066 error = altq_disable(&ifp->if_snd); 1067 1068 if (error == 0) { 1069 /* clear tokenbucket regulator */ 1070 tb.rate = 0; 1071 #ifdef __OpenBSD__ 1072 s = splimp(); 1073 #else 1074 s = splnet(); 1075 #endif 1076 error = tbr_set(&ifp->if_snd, &tb); 1077 splx(s); 1078 } 1079 1080 return (error); 1081 } 1082 #endif /* ALTQ */ 1083 1084 int 1085 pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor) 1086 { 1087 struct pf_ruleset *rs; 1088 struct pf_rule *rule; 1089 1090 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 1091 return (EINVAL); 1092 rs = pf_find_or_create_ruleset(anchor); 1093 if (rs == NULL) 1094 return (EINVAL); 1095 while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) 1096 pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); 1097 *ticket = ++rs->rules[rs_num].inactive.ticket; 1098 rs->rules[rs_num].inactive.open = 1; 1099 return (0); 1100 } 1101 1102 int 1103 pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor) 1104 { 1105 struct pf_ruleset *rs; 1106 struct pf_rule *rule; 1107 1108 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 1109 return (EINVAL); 1110 rs = pf_find_ruleset(anchor); 1111 if (rs == NULL || !rs->rules[rs_num].inactive.open || 1112 rs->rules[rs_num].inactive.ticket != ticket) 1113 return (0); 1114 while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) 1115 pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); 1116 rs->rules[rs_num].inactive.open = 0; 1117 return (0); 1118 } 1119 1120 int 1121 pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) 1122 { 1123 struct pf_ruleset *rs; 1124 struct pf_rule *rule; 1125 struct pf_rulequeue *old_rules; 1126 int s; 1127 1128 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 1129 return (EINVAL); 1130 rs = pf_find_ruleset(anchor); 1131 if (rs == NULL || !rs->rules[rs_num].inactive.open || 1132 ticket != rs->rules[rs_num].inactive.ticket) 1133 return (EBUSY); 1134 1135 /* Swap rules, keep the old. */ 1136 s = splsoftnet(); 1137 old_rules = rs->rules[rs_num].active.ptr; 1138 rs->rules[rs_num].active.ptr = 1139 rs->rules[rs_num].inactive.ptr; 1140 rs->rules[rs_num].inactive.ptr = old_rules; 1141 rs->rules[rs_num].active.ticket = 1142 rs->rules[rs_num].inactive.ticket; 1143 pf_calc_skip_steps(rs->rules[rs_num].active.ptr); 1144 1145 /* Purge the old rule list. */ 1146 while ((rule = TAILQ_FIRST(old_rules)) != NULL) 1147 pf_rm_rule(old_rules, rule); 1148 rs->rules[rs_num].inactive.open = 0; 1149 pf_remove_if_empty_ruleset(rs); 1150 splx(s); 1151 return (0); 1152 } 1153 1154 int 1155 pfioctl(dev_t dev, u_long cmd, void *addr, int flags, struct lwp *l) 1156 { 1157 struct pf_pooladdr *pa = NULL; 1158 struct pf_pool *pool = NULL; 1159 int s; 1160 int error = 0; 1161 1162 /* XXX keep in sync with switch() below */ 1163 if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 1164 KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) 1165 switch (cmd) { 1166 case DIOCGETRULES: 1167 case DIOCGETRULE: 1168 case DIOCGETADDRS: 1169 case DIOCGETADDR: 1170 case DIOCGETSTATE: 1171 case DIOCSETSTATUSIF: 1172 case DIOCGETSTATUS: 1173 case DIOCCLRSTATUS: 1174 case DIOCNATLOOK: 1175 case DIOCSETDEBUG: 1176 case DIOCGETSTATES: 1177 case DIOCGETTIMEOUT: 1178 case DIOCCLRRULECTRS: 1179 case DIOCGETLIMIT: 1180 case DIOCGETALTQS: 1181 case DIOCGETALTQ: 1182 case DIOCGETQSTATS: 1183 case DIOCGETRULESETS: 1184 case DIOCGETRULESET: 1185 case DIOCRGETTABLES: 1186 case DIOCRGETTSTATS: 1187 case DIOCRCLRTSTATS: 1188 case DIOCRCLRADDRS: 1189 case DIOCRADDADDRS: 1190 case DIOCRDELADDRS: 1191 case DIOCRSETADDRS: 1192 case DIOCRGETADDRS: 1193 case DIOCRGETASTATS: 1194 case DIOCRCLRASTATS: 1195 case DIOCRTSTADDRS: 1196 case DIOCOSFPGET: 1197 case DIOCGETSRCNODES: 1198 case DIOCCLRSRCNODES: 1199 case DIOCIGETIFACES: 1200 case DIOCICLRISTATS: 1201 case DIOCSETIFFLAG: 1202 case DIOCCLRIFFLAG: 1203 break; 1204 case DIOCRCLRTABLES: 1205 case DIOCRADDTABLES: 1206 case DIOCRDELTABLES: 1207 case DIOCRSETTFLAGS: 1208 if (((struct pfioc_table *)addr)->pfrio_flags & 1209 PFR_FLAG_DUMMY) 1210 break; /* dummy operation ok */ 1211 return (EPERM); 1212 default: 1213 return (EPERM); 1214 } 1215 1216 if (!(flags & FWRITE)) 1217 switch (cmd) { 1218 case DIOCGETRULES: 1219 case DIOCGETRULE: 1220 case DIOCGETADDRS: 1221 case DIOCGETADDR: 1222 case DIOCGETSTATE: 1223 case DIOCGETSTATUS: 1224 case DIOCGETSTATES: 1225 case DIOCGETTIMEOUT: 1226 case DIOCGETLIMIT: 1227 case DIOCGETALTQS: 1228 case DIOCGETALTQ: 1229 case DIOCGETQSTATS: 1230 case DIOCGETRULESETS: 1231 case DIOCGETRULESET: 1232 case DIOCRGETTABLES: 1233 case DIOCRGETTSTATS: 1234 case DIOCRGETADDRS: 1235 case DIOCRGETASTATS: 1236 case DIOCRTSTADDRS: 1237 case DIOCOSFPGET: 1238 case DIOCGETSRCNODES: 1239 case DIOCIGETIFACES: 1240 break; 1241 case DIOCRCLRTABLES: 1242 case DIOCRADDTABLES: 1243 case DIOCRDELTABLES: 1244 case DIOCRCLRTSTATS: 1245 case DIOCRCLRADDRS: 1246 case DIOCRADDADDRS: 1247 case DIOCRDELADDRS: 1248 case DIOCRSETADDRS: 1249 case DIOCRSETTFLAGS: 1250 if (((struct pfioc_table *)addr)->pfrio_flags & 1251 PFR_FLAG_DUMMY) 1252 break; /* dummy operation ok */ 1253 return (EACCES); 1254 default: 1255 return (EACCES); 1256 } 1257 1258 s = splsoftnet(); 1259 switch (cmd) { 1260 1261 case DIOCSTART: 1262 if (pf_status.running) 1263 error = EEXIST; 1264 else { 1265 #ifdef __NetBSD__ 1266 error = pf_pfil_attach(); 1267 if (error) 1268 break; 1269 #endif 1270 pf_status.running = 1; 1271 pf_status.since = time_second; 1272 if (pf_status.stateid == 0) { 1273 pf_status.stateid = time_second; 1274 pf_status.stateid = pf_status.stateid << 32; 1275 } 1276 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); 1277 } 1278 break; 1279 1280 case DIOCSTOP: 1281 if (!pf_status.running) 1282 error = ENOENT; 1283 else { 1284 #ifdef __NetBSD__ 1285 error = pf_pfil_detach(); 1286 if (error) 1287 break; 1288 #endif 1289 pf_status.running = 0; 1290 pf_status.since = time_second; 1291 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); 1292 } 1293 break; 1294 1295 case DIOCADDRULE: { 1296 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1297 struct pf_ruleset *ruleset; 1298 struct pf_rule *rule, *tail; 1299 struct pf_pooladdr *pa; 1300 int rs_num; 1301 1302 pr->anchor[sizeof(pr->anchor) - 1] = 0; 1303 ruleset = pf_find_ruleset(pr->anchor); 1304 if (ruleset == NULL) { 1305 error = EINVAL; 1306 break; 1307 } 1308 rs_num = pf_get_ruleset_number(pr->rule.action); 1309 if (rs_num >= PF_RULESET_MAX) { 1310 error = EINVAL; 1311 break; 1312 } 1313 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1314 error = EINVAL; 1315 break; 1316 } 1317 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { 1318 error = EBUSY; 1319 break; 1320 } 1321 if (pr->pool_ticket != ticket_pabuf) { 1322 error = EBUSY; 1323 break; 1324 } 1325 rule = pool_get(&pf_rule_pl, PR_NOWAIT); 1326 if (rule == NULL) { 1327 error = ENOMEM; 1328 break; 1329 } 1330 bcopy(&pr->rule, rule, sizeof(struct pf_rule)); 1331 rule->anchor = NULL; 1332 rule->kif = NULL; 1333 TAILQ_INIT(&rule->rpool.list); 1334 /* initialize refcounting */ 1335 rule->states = 0; 1336 rule->src_nodes = 0; 1337 rule->entries.tqe_prev = NULL; 1338 #ifndef INET 1339 if (rule->af == AF_INET) { 1340 pool_put(&pf_rule_pl, rule); 1341 error = EAFNOSUPPORT; 1342 break; 1343 } 1344 #endif /* INET */ 1345 #ifndef INET6 1346 if (rule->af == AF_INET6) { 1347 pool_put(&pf_rule_pl, rule); 1348 error = EAFNOSUPPORT; 1349 break; 1350 } 1351 #endif /* INET6 */ 1352 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 1353 pf_rulequeue); 1354 if (tail) 1355 rule->nr = tail->nr + 1; 1356 else 1357 rule->nr = 0; 1358 if (rule->ifname[0]) { 1359 rule->kif = pfi_attach_rule(rule->ifname); 1360 if (rule->kif == NULL) { 1361 pool_put(&pf_rule_pl, rule); 1362 error = EINVAL; 1363 break; 1364 } 1365 } 1366 1367 #ifdef ALTQ 1368 /* set queue IDs */ 1369 if (rule->qname[0] != 0) { 1370 if ((rule->qid = pf_qname2qid(rule->qname)) == 0) 1371 error = EBUSY; 1372 else if (rule->pqname[0] != 0) { 1373 if ((rule->pqid = 1374 pf_qname2qid(rule->pqname)) == 0) 1375 error = EBUSY; 1376 } else 1377 rule->pqid = rule->qid; 1378 } 1379 #endif 1380 if (rule->tagname[0]) 1381 if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) 1382 error = EBUSY; 1383 if (rule->match_tagname[0]) 1384 if ((rule->match_tag = 1385 pf_tagname2tag(rule->match_tagname)) == 0) 1386 error = EBUSY; 1387 if (rule->rt && !rule->direction) 1388 error = EINVAL; 1389 if (pf_rtlabel_add(&rule->src.addr) || 1390 pf_rtlabel_add(&rule->dst.addr)) 1391 error = EBUSY; 1392 if (pfi_dynaddr_setup(&rule->src.addr, rule->af)) 1393 error = EINVAL; 1394 if (pfi_dynaddr_setup(&rule->dst.addr, rule->af)) 1395 error = EINVAL; 1396 if (pf_tbladdr_setup(ruleset, &rule->src.addr)) 1397 error = EINVAL; 1398 if (pf_tbladdr_setup(ruleset, &rule->dst.addr)) 1399 error = EINVAL; 1400 if (pf_anchor_setup(rule, ruleset, pr->anchor_call)) 1401 error = EINVAL; 1402 TAILQ_FOREACH(pa, &pf_pabuf, entries) 1403 if (pf_tbladdr_setup(ruleset, &pa->addr)) 1404 error = EINVAL; 1405 1406 if (rule->overload_tblname[0]) { 1407 if ((rule->overload_tbl = pfr_attach_table(ruleset, 1408 rule->overload_tblname)) == NULL) 1409 error = EINVAL; 1410 else 1411 rule->overload_tbl->pfrkt_flags |= 1412 PFR_TFLAG_ACTIVE; 1413 } 1414 1415 pf_mv_pool(&pf_pabuf, &rule->rpool.list); 1416 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || 1417 (rule->action == PF_BINAT)) && rule->anchor == NULL) || 1418 (rule->rt > PF_FASTROUTE)) && 1419 (TAILQ_FIRST(&rule->rpool.list) == NULL)) 1420 error = EINVAL; 1421 1422 if (error) { 1423 pf_rm_rule(NULL, rule); 1424 break; 1425 } 1426 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list); 1427 rule->evaluations = rule->packets = rule->bytes = 0; 1428 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, 1429 rule, entries); 1430 break; 1431 } 1432 1433 case DIOCGETRULES: { 1434 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1435 struct pf_ruleset *ruleset; 1436 struct pf_rule *tail; 1437 int rs_num; 1438 1439 pr->anchor[sizeof(pr->anchor) - 1] = 0; 1440 ruleset = pf_find_ruleset(pr->anchor); 1441 if (ruleset == NULL) { 1442 error = EINVAL; 1443 break; 1444 } 1445 rs_num = pf_get_ruleset_number(pr->rule.action); 1446 if (rs_num >= PF_RULESET_MAX) { 1447 error = EINVAL; 1448 break; 1449 } 1450 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 1451 pf_rulequeue); 1452 if (tail) 1453 pr->nr = tail->nr + 1; 1454 else 1455 pr->nr = 0; 1456 pr->ticket = ruleset->rules[rs_num].active.ticket; 1457 break; 1458 } 1459 1460 case DIOCGETRULE: { 1461 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 1462 struct pf_ruleset *ruleset; 1463 struct pf_rule *rule; 1464 int rs_num, i; 1465 1466 pr->anchor[sizeof(pr->anchor) - 1] = 0; 1467 ruleset = pf_find_ruleset(pr->anchor); 1468 if (ruleset == NULL) { 1469 error = EINVAL; 1470 break; 1471 } 1472 rs_num = pf_get_ruleset_number(pr->rule.action); 1473 if (rs_num >= PF_RULESET_MAX) { 1474 error = EINVAL; 1475 break; 1476 } 1477 if (pr->ticket != ruleset->rules[rs_num].active.ticket) { 1478 error = EBUSY; 1479 break; 1480 } 1481 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 1482 while ((rule != NULL) && (rule->nr != pr->nr)) 1483 rule = TAILQ_NEXT(rule, entries); 1484 if (rule == NULL) { 1485 error = EBUSY; 1486 break; 1487 } 1488 bcopy(rule, &pr->rule, sizeof(struct pf_rule)); 1489 if (pf_anchor_copyout(ruleset, rule, pr)) { 1490 error = EBUSY; 1491 break; 1492 } 1493 pfi_dynaddr_copyout(&pr->rule.src.addr); 1494 pfi_dynaddr_copyout(&pr->rule.dst.addr); 1495 pf_tbladdr_copyout(&pr->rule.src.addr); 1496 pf_tbladdr_copyout(&pr->rule.dst.addr); 1497 pf_rtlabel_copyout(&pr->rule.src.addr); 1498 pf_rtlabel_copyout(&pr->rule.dst.addr); 1499 for (i = 0; i < PF_SKIP_COUNT; ++i) 1500 if (rule->skip[i].ptr == NULL) 1501 pr->rule.skip[i].nr = -1; 1502 else 1503 pr->rule.skip[i].nr = 1504 rule->skip[i].ptr->nr; 1505 break; 1506 } 1507 1508 case DIOCCHANGERULE: { 1509 struct pfioc_rule *pcr = (struct pfioc_rule *)addr; 1510 struct pf_ruleset *ruleset; 1511 struct pf_rule *oldrule = NULL, *newrule = NULL; 1512 u_int32_t nr = 0; 1513 int rs_num; 1514 1515 if (!(pcr->action == PF_CHANGE_REMOVE || 1516 pcr->action == PF_CHANGE_GET_TICKET) && 1517 pcr->pool_ticket != ticket_pabuf) { 1518 error = EBUSY; 1519 break; 1520 } 1521 1522 if (pcr->action < PF_CHANGE_ADD_HEAD || 1523 pcr->action > PF_CHANGE_GET_TICKET) { 1524 error = EINVAL; 1525 break; 1526 } 1527 ruleset = pf_find_ruleset(pcr->anchor); 1528 if (ruleset == NULL) { 1529 error = EINVAL; 1530 break; 1531 } 1532 rs_num = pf_get_ruleset_number(pcr->rule.action); 1533 if (rs_num >= PF_RULESET_MAX) { 1534 error = EINVAL; 1535 break; 1536 } 1537 1538 if (pcr->action == PF_CHANGE_GET_TICKET) { 1539 pcr->ticket = ++ruleset->rules[rs_num].active.ticket; 1540 break; 1541 } else { 1542 if (pcr->ticket != 1543 ruleset->rules[rs_num].active.ticket) { 1544 error = EINVAL; 1545 break; 1546 } 1547 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1548 error = EINVAL; 1549 break; 1550 } 1551 } 1552 1553 if (pcr->action != PF_CHANGE_REMOVE) { 1554 newrule = pool_get(&pf_rule_pl, PR_NOWAIT); 1555 if (newrule == NULL) { 1556 error = ENOMEM; 1557 break; 1558 } 1559 bcopy(&pcr->rule, newrule, sizeof(struct pf_rule)); 1560 TAILQ_INIT(&newrule->rpool.list); 1561 /* initialize refcounting */ 1562 newrule->states = 0; 1563 newrule->entries.tqe_prev = NULL; 1564 #ifndef INET 1565 if (newrule->af == AF_INET) { 1566 pool_put(&pf_rule_pl, newrule); 1567 error = EAFNOSUPPORT; 1568 break; 1569 } 1570 #endif /* INET */ 1571 #ifndef INET6 1572 if (newrule->af == AF_INET6) { 1573 pool_put(&pf_rule_pl, newrule); 1574 error = EAFNOSUPPORT; 1575 break; 1576 } 1577 #endif /* INET6 */ 1578 if (newrule->ifname[0]) { 1579 newrule->kif = pfi_attach_rule(newrule->ifname); 1580 if (newrule->kif == NULL) { 1581 pool_put(&pf_rule_pl, newrule); 1582 error = EINVAL; 1583 break; 1584 } 1585 } else 1586 newrule->kif = NULL; 1587 1588 #ifdef ALTQ 1589 /* set queue IDs */ 1590 if (newrule->qname[0] != 0) { 1591 if ((newrule->qid = 1592 pf_qname2qid(newrule->qname)) == 0) 1593 error = EBUSY; 1594 else if (newrule->pqname[0] != 0) { 1595 if ((newrule->pqid = 1596 pf_qname2qid(newrule->pqname)) == 0) 1597 error = EBUSY; 1598 } else 1599 newrule->pqid = newrule->qid; 1600 } 1601 #endif /* ALTQ */ 1602 if (newrule->tagname[0]) 1603 if ((newrule->tag = 1604 pf_tagname2tag(newrule->tagname)) == 0) 1605 error = EBUSY; 1606 if (newrule->match_tagname[0]) 1607 if ((newrule->match_tag = pf_tagname2tag( 1608 newrule->match_tagname)) == 0) 1609 error = EBUSY; 1610 if (newrule->rt && !newrule->direction) 1611 error = EINVAL; 1612 if (pf_rtlabel_add(&newrule->src.addr) || 1613 pf_rtlabel_add(&newrule->dst.addr)) 1614 error = EBUSY; 1615 if (pfi_dynaddr_setup(&newrule->src.addr, newrule->af)) 1616 error = EINVAL; 1617 if (pfi_dynaddr_setup(&newrule->dst.addr, newrule->af)) 1618 error = EINVAL; 1619 if (pf_tbladdr_setup(ruleset, &newrule->src.addr)) 1620 error = EINVAL; 1621 if (pf_tbladdr_setup(ruleset, &newrule->dst.addr)) 1622 error = EINVAL; 1623 if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call)) 1624 error = EINVAL; 1625 1626 if (newrule->overload_tblname[0]) { 1627 if ((newrule->overload_tbl = pfr_attach_table( 1628 ruleset, newrule->overload_tblname)) == 1629 NULL) 1630 error = EINVAL; 1631 else 1632 newrule->overload_tbl->pfrkt_flags |= 1633 PFR_TFLAG_ACTIVE; 1634 } 1635 1636 pf_mv_pool(&pf_pabuf, &newrule->rpool.list); 1637 if (((((newrule->action == PF_NAT) || 1638 (newrule->action == PF_RDR) || 1639 (newrule->action == PF_BINAT) || 1640 (newrule->rt > PF_FASTROUTE)) && 1641 !pcr->anchor[0])) && 1642 (TAILQ_FIRST(&newrule->rpool.list) == NULL)) 1643 error = EINVAL; 1644 1645 if (error) { 1646 pf_rm_rule(NULL, newrule); 1647 break; 1648 } 1649 newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list); 1650 newrule->evaluations = newrule->packets = 0; 1651 newrule->bytes = 0; 1652 } 1653 pf_empty_pool(&pf_pabuf); 1654 1655 if (pcr->action == PF_CHANGE_ADD_HEAD) 1656 oldrule = TAILQ_FIRST( 1657 ruleset->rules[rs_num].active.ptr); 1658 else if (pcr->action == PF_CHANGE_ADD_TAIL) 1659 oldrule = TAILQ_LAST( 1660 ruleset->rules[rs_num].active.ptr, pf_rulequeue); 1661 else { 1662 oldrule = TAILQ_FIRST( 1663 ruleset->rules[rs_num].active.ptr); 1664 while ((oldrule != NULL) && (oldrule->nr != pcr->nr)) 1665 oldrule = TAILQ_NEXT(oldrule, entries); 1666 if (oldrule == NULL) { 1667 if (newrule != NULL) 1668 pf_rm_rule(NULL, newrule); 1669 error = EINVAL; 1670 break; 1671 } 1672 } 1673 1674 if (pcr->action == PF_CHANGE_REMOVE) 1675 pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule); 1676 else { 1677 if (oldrule == NULL) 1678 TAILQ_INSERT_TAIL( 1679 ruleset->rules[rs_num].active.ptr, 1680 newrule, entries); 1681 else if (pcr->action == PF_CHANGE_ADD_HEAD || 1682 pcr->action == PF_CHANGE_ADD_BEFORE) 1683 TAILQ_INSERT_BEFORE(oldrule, newrule, entries); 1684 else 1685 TAILQ_INSERT_AFTER( 1686 ruleset->rules[rs_num].active.ptr, 1687 oldrule, newrule, entries); 1688 } 1689 1690 nr = 0; 1691 TAILQ_FOREACH(oldrule, 1692 ruleset->rules[rs_num].active.ptr, entries) 1693 oldrule->nr = nr++; 1694 1695 ruleset->rules[rs_num].active.ticket++; 1696 1697 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); 1698 pf_remove_if_empty_ruleset(ruleset); 1699 1700 break; 1701 } 1702 1703 case DIOCCLRSTATES: { 1704 struct pf_state *state; 1705 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 1706 int killed = 0; 1707 1708 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 1709 if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, 1710 state->u.s.kif->pfik_name)) { 1711 state->timeout = PFTM_PURGE; 1712 #if NPFSYNC 1713 /* don't send out individual delete messages */ 1714 state->sync_flags = PFSTATE_NOSYNC; 1715 #endif 1716 killed++; 1717 } 1718 } 1719 pf_purge_expired_states(); 1720 pf_status.states = 0; 1721 psk->psk_af = killed; 1722 #if NPFSYNC 1723 pfsync_clear_states(pf_status.hostid, psk->psk_ifname); 1724 #endif 1725 break; 1726 } 1727 1728 case DIOCKILLSTATES: { 1729 struct pf_state *state; 1730 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 1731 int killed = 0; 1732 1733 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 1734 if ((!psk->psk_af || state->af == psk->psk_af) 1735 && (!psk->psk_proto || psk->psk_proto == 1736 state->proto) && 1737 PF_MATCHA(psk->psk_src.neg, 1738 &psk->psk_src.addr.v.a.addr, 1739 &psk->psk_src.addr.v.a.mask, 1740 &state->lan.addr, state->af) && 1741 PF_MATCHA(psk->psk_dst.neg, 1742 &psk->psk_dst.addr.v.a.addr, 1743 &psk->psk_dst.addr.v.a.mask, 1744 &state->ext.addr, state->af) && 1745 (psk->psk_src.port_op == 0 || 1746 pf_match_port(psk->psk_src.port_op, 1747 psk->psk_src.port[0], psk->psk_src.port[1], 1748 state->lan.port)) && 1749 (psk->psk_dst.port_op == 0 || 1750 pf_match_port(psk->psk_dst.port_op, 1751 psk->psk_dst.port[0], psk->psk_dst.port[1], 1752 state->ext.port)) && 1753 (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, 1754 state->u.s.kif->pfik_name))) { 1755 state->timeout = PFTM_PURGE; 1756 killed++; 1757 } 1758 } 1759 pf_purge_expired_states(); 1760 psk->psk_af = killed; 1761 break; 1762 } 1763 1764 case DIOCADDSTATE: { 1765 struct pfioc_state *ps = (struct pfioc_state *)addr; 1766 struct pf_state *state; 1767 struct pfi_kif *kif; 1768 1769 if (ps->state.timeout >= PFTM_MAX && 1770 ps->state.timeout != PFTM_UNTIL_PACKET) { 1771 error = EINVAL; 1772 break; 1773 } 1774 state = pool_get(&pf_state_pl, PR_NOWAIT); 1775 if (state == NULL) { 1776 error = ENOMEM; 1777 break; 1778 } 1779 kif = pfi_lookup_create(ps->state.u.ifname); 1780 if (kif == NULL) { 1781 pool_put(&pf_state_pl, state); 1782 error = ENOENT; 1783 break; 1784 } 1785 bcopy(&ps->state, state, sizeof(struct pf_state)); 1786 bzero(&state->u, sizeof(state->u)); 1787 state->rule.ptr = &pf_default_rule; 1788 state->nat_rule.ptr = NULL; 1789 state->anchor.ptr = NULL; 1790 state->rt_kif = NULL; 1791 state->creation = time_second; 1792 state->pfsync_time = 0; 1793 state->packets[0] = state->packets[1] = 0; 1794 state->bytes[0] = state->bytes[1] = 0; 1795 1796 if (pf_insert_state(kif, state)) { 1797 pfi_maybe_destroy(kif); 1798 pool_put(&pf_state_pl, state); 1799 error = ENOMEM; 1800 } 1801 break; 1802 } 1803 1804 case DIOCGETSTATE: { 1805 struct pfioc_state *ps = (struct pfioc_state *)addr; 1806 struct pf_state *state; 1807 u_int32_t nr; 1808 1809 nr = 0; 1810 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 1811 if (nr >= ps->nr) 1812 break; 1813 nr++; 1814 } 1815 if (state == NULL) { 1816 error = EBUSY; 1817 break; 1818 } 1819 bcopy(state, &ps->state, sizeof(struct pf_state)); 1820 ps->state.rule.nr = state->rule.ptr->nr; 1821 ps->state.nat_rule.nr = (state->nat_rule.ptr == NULL) ? 1822 -1 : state->nat_rule.ptr->nr; 1823 ps->state.anchor.nr = (state->anchor.ptr == NULL) ? 1824 -1 : state->anchor.ptr->nr; 1825 ps->state.expire = pf_state_expires(state); 1826 if (ps->state.expire > time_second) 1827 ps->state.expire -= time_second; 1828 else 1829 ps->state.expire = 0; 1830 break; 1831 } 1832 1833 case DIOCGETSTATES: { 1834 struct pfioc_states *ps = (struct pfioc_states *)addr; 1835 struct pf_state *state; 1836 struct pf_state *p, pstore; 1837 struct pfi_kif *kif; 1838 u_int32_t nr = 0; 1839 int space = ps->ps_len; 1840 1841 if (space == 0) { 1842 TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) 1843 nr += kif->pfik_states; 1844 ps->ps_len = sizeof(struct pf_state) * nr; 1845 break; 1846 } 1847 1848 p = ps->ps_states; 1849 TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) 1850 RB_FOREACH(state, pf_state_tree_ext_gwy, 1851 &kif->pfik_ext_gwy) { 1852 int secs = time_second; 1853 1854 if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len) 1855 break; 1856 1857 bcopy(state, &pstore, sizeof(pstore)); 1858 strlcpy(pstore.u.ifname, kif->pfik_name, 1859 sizeof(pstore.u.ifname)); 1860 pstore.rule.nr = state->rule.ptr->nr; 1861 pstore.nat_rule.nr = (state->nat_rule.ptr == 1862 NULL) ? -1 : state->nat_rule.ptr->nr; 1863 pstore.anchor.nr = (state->anchor.ptr == 1864 NULL) ? -1 : state->anchor.ptr->nr; 1865 pstore.creation = secs - pstore.creation; 1866 pstore.expire = pf_state_expires(state); 1867 if (pstore.expire > secs) 1868 pstore.expire -= secs; 1869 else 1870 pstore.expire = 0; 1871 error = copyout(&pstore, p, sizeof(*p)); 1872 if (error) 1873 goto fail; 1874 p++; 1875 nr++; 1876 } 1877 ps->ps_len = sizeof(struct pf_state) * nr; 1878 break; 1879 } 1880 1881 case DIOCGETSTATUS: { 1882 struct pf_status *s = (struct pf_status *)addr; 1883 bcopy(&pf_status, s, sizeof(struct pf_status)); 1884 pfi_fill_oldstatus(s); 1885 break; 1886 } 1887 1888 case DIOCSETSTATUSIF: { 1889 struct pfioc_if *pi = (struct pfioc_if *)addr; 1890 1891 if (pi->ifname[0] == 0) { 1892 bzero(pf_status.ifname, IFNAMSIZ); 1893 break; 1894 } 1895 if (ifunit(pi->ifname) == NULL) { 1896 error = EINVAL; 1897 break; 1898 } 1899 strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ); 1900 break; 1901 } 1902 1903 case DIOCCLRSTATUS: { 1904 bzero(pf_status.counters, sizeof(pf_status.counters)); 1905 bzero(pf_status.fcounters, sizeof(pf_status.fcounters)); 1906 bzero(pf_status.scounters, sizeof(pf_status.scounters)); 1907 if (*pf_status.ifname) 1908 pfi_clr_istats(pf_status.ifname, NULL, 1909 PFI_FLAG_INSTANCE); 1910 break; 1911 } 1912 1913 case DIOCNATLOOK: { 1914 struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; 1915 struct pf_state *state; 1916 struct pf_state key; 1917 int m = 0, direction = pnl->direction; 1918 1919 key.af = pnl->af; 1920 key.proto = pnl->proto; 1921 1922 if (!pnl->proto || 1923 PF_AZERO(&pnl->saddr, pnl->af) || 1924 PF_AZERO(&pnl->daddr, pnl->af) || 1925 !pnl->dport || !pnl->sport) 1926 error = EINVAL; 1927 else { 1928 /* 1929 * userland gives us source and dest of connection, 1930 * reverse the lookup so we ask for what happens with 1931 * the return traffic, enabling us to find it in the 1932 * state tree. 1933 */ 1934 if (direction == PF_IN) { 1935 PF_ACPY(&key.ext.addr, &pnl->daddr, pnl->af); 1936 key.ext.port = pnl->dport; 1937 PF_ACPY(&key.gwy.addr, &pnl->saddr, pnl->af); 1938 key.gwy.port = pnl->sport; 1939 state = pf_find_state_all(&key, PF_EXT_GWY, &m); 1940 } else { 1941 PF_ACPY(&key.lan.addr, &pnl->daddr, pnl->af); 1942 key.lan.port = pnl->dport; 1943 PF_ACPY(&key.ext.addr, &pnl->saddr, pnl->af); 1944 key.ext.port = pnl->sport; 1945 state = pf_find_state_all(&key, PF_LAN_EXT, &m); 1946 } 1947 if (m > 1) 1948 error = E2BIG; /* more than one state */ 1949 else if (state != NULL) { 1950 if (direction == PF_IN) { 1951 PF_ACPY(&pnl->rsaddr, &state->lan.addr, 1952 state->af); 1953 pnl->rsport = state->lan.port; 1954 PF_ACPY(&pnl->rdaddr, &pnl->daddr, 1955 pnl->af); 1956 pnl->rdport = pnl->dport; 1957 } else { 1958 PF_ACPY(&pnl->rdaddr, &state->gwy.addr, 1959 state->af); 1960 pnl->rdport = state->gwy.port; 1961 PF_ACPY(&pnl->rsaddr, &pnl->saddr, 1962 pnl->af); 1963 pnl->rsport = pnl->sport; 1964 } 1965 } else 1966 error = ENOENT; 1967 } 1968 break; 1969 } 1970 1971 case DIOCSETTIMEOUT: { 1972 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 1973 int old; 1974 1975 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX || 1976 pt->seconds < 0) { 1977 error = EINVAL; 1978 goto fail; 1979 } 1980 old = pf_default_rule.timeout[pt->timeout]; 1981 pf_default_rule.timeout[pt->timeout] = pt->seconds; 1982 pt->seconds = old; 1983 break; 1984 } 1985 1986 case DIOCGETTIMEOUT: { 1987 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 1988 1989 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) { 1990 error = EINVAL; 1991 goto fail; 1992 } 1993 pt->seconds = pf_default_rule.timeout[pt->timeout]; 1994 break; 1995 } 1996 1997 case DIOCGETLIMIT: { 1998 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 1999 2000 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { 2001 error = EINVAL; 2002 goto fail; 2003 } 2004 pl->limit = pf_pool_limits[pl->index].limit; 2005 break; 2006 } 2007 2008 case DIOCSETLIMIT: { 2009 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 2010 int old_limit; 2011 2012 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX || 2013 pf_pool_limits[pl->index].pp == NULL) { 2014 error = EINVAL; 2015 goto fail; 2016 } 2017 #ifdef __OpenBSD__ 2018 if (pool_sethardlimit(pf_pool_limits[pl->index].pp, 2019 pl->limit, NULL, 0) != 0) { 2020 error = EBUSY; 2021 goto fail; 2022 } 2023 #else 2024 pool_sethardlimit(pf_pool_limits[pl->index].pp, 2025 pl->limit, NULL, 0); 2026 #endif 2027 old_limit = pf_pool_limits[pl->index].limit; 2028 pf_pool_limits[pl->index].limit = pl->limit; 2029 pl->limit = old_limit; 2030 break; 2031 } 2032 2033 case DIOCSETDEBUG: { 2034 u_int32_t *level = (u_int32_t *)addr; 2035 2036 pf_status.debug = *level; 2037 break; 2038 } 2039 2040 case DIOCCLRRULECTRS: { 2041 struct pf_ruleset *ruleset = &pf_main_ruleset; 2042 struct pf_rule *rule; 2043 2044 TAILQ_FOREACH(rule, 2045 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) 2046 rule->evaluations = rule->packets = 2047 rule->bytes = 0; 2048 break; 2049 } 2050 2051 #ifdef ALTQ 2052 case DIOCSTARTALTQ: { 2053 struct pf_altq *altq; 2054 2055 /* enable all altq interfaces on active list */ 2056 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 2057 if (altq->qname[0] == 0) { 2058 error = pf_enable_altq(altq); 2059 if (error != 0) 2060 break; 2061 } 2062 } 2063 if (error == 0) 2064 pf_altq_running = 1; 2065 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n")); 2066 break; 2067 } 2068 2069 case DIOCSTOPALTQ: { 2070 struct pf_altq *altq; 2071 2072 /* disable all altq interfaces on active list */ 2073 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 2074 if (altq->qname[0] == 0) { 2075 error = pf_disable_altq(altq); 2076 if (error != 0) 2077 break; 2078 } 2079 } 2080 if (error == 0) 2081 pf_altq_running = 0; 2082 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n")); 2083 break; 2084 } 2085 2086 case DIOCADDALTQ: { 2087 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2088 struct pf_altq *altq, *a; 2089 2090 if (pa->ticket != ticket_altqs_inactive) { 2091 error = EBUSY; 2092 break; 2093 } 2094 altq = pool_get(&pf_altq_pl, PR_NOWAIT); 2095 if (altq == NULL) { 2096 error = ENOMEM; 2097 break; 2098 } 2099 bcopy(&pa->altq, altq, sizeof(struct pf_altq)); 2100 2101 /* 2102 * if this is for a queue, find the discipline and 2103 * copy the necessary fields 2104 */ 2105 if (altq->qname[0] != 0) { 2106 if ((altq->qid = pf_qname2qid(altq->qname)) == 0) { 2107 error = EBUSY; 2108 pool_put(&pf_altq_pl, altq); 2109 break; 2110 } 2111 TAILQ_FOREACH(a, pf_altqs_inactive, entries) { 2112 if (strncmp(a->ifname, altq->ifname, 2113 IFNAMSIZ) == 0 && a->qname[0] == 0) { 2114 altq->altq_disc = a->altq_disc; 2115 break; 2116 } 2117 } 2118 } 2119 2120 error = altq_add(altq); 2121 if (error) { 2122 pool_put(&pf_altq_pl, altq); 2123 break; 2124 } 2125 2126 TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries); 2127 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 2128 break; 2129 } 2130 2131 case DIOCGETALTQS: { 2132 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2133 struct pf_altq *altq; 2134 2135 pa->nr = 0; 2136 TAILQ_FOREACH(altq, pf_altqs_active, entries) 2137 pa->nr++; 2138 pa->ticket = ticket_altqs_active; 2139 break; 2140 } 2141 2142 case DIOCGETALTQ: { 2143 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 2144 struct pf_altq *altq; 2145 u_int32_t nr; 2146 2147 if (pa->ticket != ticket_altqs_active) { 2148 error = EBUSY; 2149 break; 2150 } 2151 nr = 0; 2152 altq = TAILQ_FIRST(pf_altqs_active); 2153 while ((altq != NULL) && (nr < pa->nr)) { 2154 altq = TAILQ_NEXT(altq, entries); 2155 nr++; 2156 } 2157 if (altq == NULL) { 2158 error = EBUSY; 2159 break; 2160 } 2161 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 2162 break; 2163 } 2164 2165 case DIOCCHANGEALTQ: 2166 /* CHANGEALTQ not supported yet! */ 2167 error = ENODEV; 2168 break; 2169 2170 case DIOCGETQSTATS: { 2171 struct pfioc_qstats *pq = (struct pfioc_qstats *)addr; 2172 struct pf_altq *altq; 2173 u_int32_t nr; 2174 int nbytes; 2175 2176 if (pq->ticket != ticket_altqs_active) { 2177 error = EBUSY; 2178 break; 2179 } 2180 nbytes = pq->nbytes; 2181 nr = 0; 2182 altq = TAILQ_FIRST(pf_altqs_active); 2183 while ((altq != NULL) && (nr < pq->nr)) { 2184 altq = TAILQ_NEXT(altq, entries); 2185 nr++; 2186 } 2187 if (altq == NULL) { 2188 error = EBUSY; 2189 break; 2190 } 2191 error = altq_getqstats(altq, pq->buf, &nbytes); 2192 if (error == 0) { 2193 pq->scheduler = altq->scheduler; 2194 pq->nbytes = nbytes; 2195 } 2196 break; 2197 } 2198 #endif /* ALTQ */ 2199 2200 case DIOCBEGINADDRS: { 2201 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2202 2203 pf_empty_pool(&pf_pabuf); 2204 pp->ticket = ++ticket_pabuf; 2205 break; 2206 } 2207 2208 case DIOCADDADDR: { 2209 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2210 2211 #ifndef INET 2212 if (pp->af == AF_INET) { 2213 error = EAFNOSUPPORT; 2214 break; 2215 } 2216 #endif /* INET */ 2217 #ifndef INET6 2218 if (pp->af == AF_INET6) { 2219 error = EAFNOSUPPORT; 2220 break; 2221 } 2222 #endif /* INET6 */ 2223 if (pp->addr.addr.type != PF_ADDR_ADDRMASK && 2224 pp->addr.addr.type != PF_ADDR_DYNIFTL && 2225 pp->addr.addr.type != PF_ADDR_TABLE) { 2226 error = EINVAL; 2227 break; 2228 } 2229 pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT); 2230 if (pa == NULL) { 2231 error = ENOMEM; 2232 break; 2233 } 2234 bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr)); 2235 if (pa->ifname[0]) { 2236 pa->kif = pfi_attach_rule(pa->ifname); 2237 if (pa->kif == NULL) { 2238 pool_put(&pf_pooladdr_pl, pa); 2239 error = EINVAL; 2240 break; 2241 } 2242 } 2243 if (pfi_dynaddr_setup(&pa->addr, pp->af)) { 2244 pfi_dynaddr_remove(&pa->addr); 2245 pfi_detach_rule(pa->kif); 2246 pool_put(&pf_pooladdr_pl, pa); 2247 error = EINVAL; 2248 break; 2249 } 2250 TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries); 2251 break; 2252 } 2253 2254 case DIOCGETADDRS: { 2255 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2256 2257 pp->nr = 0; 2258 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, 2259 pp->r_num, 0, 1, 0); 2260 if (pool == NULL) { 2261 error = EBUSY; 2262 break; 2263 } 2264 TAILQ_FOREACH(pa, &pool->list, entries) 2265 pp->nr++; 2266 break; 2267 } 2268 2269 case DIOCGETADDR: { 2270 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 2271 u_int32_t nr = 0; 2272 2273 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, 2274 pp->r_num, 0, 1, 1); 2275 if (pool == NULL) { 2276 error = EBUSY; 2277 break; 2278 } 2279 pa = TAILQ_FIRST(&pool->list); 2280 while ((pa != NULL) && (nr < pp->nr)) { 2281 pa = TAILQ_NEXT(pa, entries); 2282 nr++; 2283 } 2284 if (pa == NULL) { 2285 error = EBUSY; 2286 break; 2287 } 2288 bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr)); 2289 pfi_dynaddr_copyout(&pp->addr.addr); 2290 pf_tbladdr_copyout(&pp->addr.addr); 2291 pf_rtlabel_copyout(&pp->addr.addr); 2292 break; 2293 } 2294 2295 case DIOCCHANGEADDR: { 2296 struct pfioc_pooladdr *pca = (struct pfioc_pooladdr *)addr; 2297 struct pf_pooladdr *oldpa = NULL, *newpa = NULL; 2298 struct pf_ruleset *ruleset; 2299 2300 if (pca->action < PF_CHANGE_ADD_HEAD || 2301 pca->action > PF_CHANGE_REMOVE) { 2302 error = EINVAL; 2303 break; 2304 } 2305 if (pca->addr.addr.type != PF_ADDR_ADDRMASK && 2306 pca->addr.addr.type != PF_ADDR_DYNIFTL && 2307 pca->addr.addr.type != PF_ADDR_TABLE) { 2308 error = EINVAL; 2309 break; 2310 } 2311 2312 ruleset = pf_find_ruleset(pca->anchor); 2313 if (ruleset == NULL) { 2314 error = EBUSY; 2315 break; 2316 } 2317 pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action, 2318 pca->r_num, pca->r_last, 1, 1); 2319 if (pool == NULL) { 2320 error = EBUSY; 2321 break; 2322 } 2323 if (pca->action != PF_CHANGE_REMOVE) { 2324 newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT); 2325 if (newpa == NULL) { 2326 error = ENOMEM; 2327 break; 2328 } 2329 bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr)); 2330 #ifndef INET 2331 if (pca->af == AF_INET) { 2332 pool_put(&pf_pooladdr_pl, newpa); 2333 error = EAFNOSUPPORT; 2334 break; 2335 } 2336 #endif /* INET */ 2337 #ifndef INET6 2338 if (pca->af == AF_INET6) { 2339 pool_put(&pf_pooladdr_pl, newpa); 2340 error = EAFNOSUPPORT; 2341 break; 2342 } 2343 #endif /* INET6 */ 2344 if (newpa->ifname[0]) { 2345 newpa->kif = pfi_attach_rule(newpa->ifname); 2346 if (newpa->kif == NULL) { 2347 pool_put(&pf_pooladdr_pl, newpa); 2348 error = EINVAL; 2349 break; 2350 } 2351 } else 2352 newpa->kif = NULL; 2353 if (pfi_dynaddr_setup(&newpa->addr, pca->af) || 2354 pf_tbladdr_setup(ruleset, &newpa->addr)) { 2355 pfi_dynaddr_remove(&newpa->addr); 2356 pfi_detach_rule(newpa->kif); 2357 pool_put(&pf_pooladdr_pl, newpa); 2358 error = EINVAL; 2359 break; 2360 } 2361 } 2362 2363 if (pca->action == PF_CHANGE_ADD_HEAD) 2364 oldpa = TAILQ_FIRST(&pool->list); 2365 else if (pca->action == PF_CHANGE_ADD_TAIL) 2366 oldpa = TAILQ_LAST(&pool->list, pf_palist); 2367 else { 2368 int i = 0; 2369 2370 oldpa = TAILQ_FIRST(&pool->list); 2371 while ((oldpa != NULL) && (i < pca->nr)) { 2372 oldpa = TAILQ_NEXT(oldpa, entries); 2373 i++; 2374 } 2375 if (oldpa == NULL) { 2376 error = EINVAL; 2377 break; 2378 } 2379 } 2380 2381 if (pca->action == PF_CHANGE_REMOVE) { 2382 TAILQ_REMOVE(&pool->list, oldpa, entries); 2383 pfi_dynaddr_remove(&oldpa->addr); 2384 pf_tbladdr_remove(&oldpa->addr); 2385 pfi_detach_rule(oldpa->kif); 2386 pool_put(&pf_pooladdr_pl, oldpa); 2387 } else { 2388 if (oldpa == NULL) 2389 TAILQ_INSERT_TAIL(&pool->list, newpa, entries); 2390 else if (pca->action == PF_CHANGE_ADD_HEAD || 2391 pca->action == PF_CHANGE_ADD_BEFORE) 2392 TAILQ_INSERT_BEFORE(oldpa, newpa, entries); 2393 else 2394 TAILQ_INSERT_AFTER(&pool->list, oldpa, 2395 newpa, entries); 2396 } 2397 2398 pool->cur = TAILQ_FIRST(&pool->list); 2399 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, 2400 pca->af); 2401 break; 2402 } 2403 2404 case DIOCGETRULESETS: { 2405 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 2406 struct pf_ruleset *ruleset; 2407 struct pf_anchor *anchor; 2408 2409 pr->path[sizeof(pr->path) - 1] = 0; 2410 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) { 2411 error = EINVAL; 2412 break; 2413 } 2414 pr->nr = 0; 2415 if (ruleset->anchor == NULL) { 2416 /* XXX kludge for pf_main_ruleset */ 2417 RB_FOREACH(anchor, pf_anchor_global, &pf_anchors) 2418 if (anchor->parent == NULL) 2419 pr->nr++; 2420 } else { 2421 RB_FOREACH(anchor, pf_anchor_node, 2422 &ruleset->anchor->children) 2423 pr->nr++; 2424 } 2425 break; 2426 } 2427 2428 case DIOCGETRULESET: { 2429 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 2430 struct pf_ruleset *ruleset; 2431 struct pf_anchor *anchor; 2432 u_int32_t nr = 0; 2433 2434 pr->path[sizeof(pr->path) - 1] = 0; 2435 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) { 2436 error = EINVAL; 2437 break; 2438 } 2439 pr->name[0] = 0; 2440 if (ruleset->anchor == NULL) { 2441 /* XXX kludge for pf_main_ruleset */ 2442 RB_FOREACH(anchor, pf_anchor_global, &pf_anchors) 2443 if (anchor->parent == NULL && nr++ == pr->nr) { 2444 strlcpy(pr->name, anchor->name, 2445 sizeof(pr->name)); 2446 break; 2447 } 2448 } else { 2449 RB_FOREACH(anchor, pf_anchor_node, 2450 &ruleset->anchor->children) 2451 if (nr++ == pr->nr) { 2452 strlcpy(pr->name, anchor->name, 2453 sizeof(pr->name)); 2454 break; 2455 } 2456 } 2457 if (!pr->name[0]) 2458 error = EBUSY; 2459 break; 2460 } 2461 2462 case DIOCRCLRTABLES: { 2463 struct pfioc_table *io = (struct pfioc_table *)addr; 2464 2465 if (io->pfrio_esize != 0) { 2466 error = ENODEV; 2467 break; 2468 } 2469 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, 2470 io->pfrio_flags | PFR_FLAG_USERIOCTL); 2471 break; 2472 } 2473 2474 case DIOCRADDTABLES: { 2475 struct pfioc_table *io = (struct pfioc_table *)addr; 2476 2477 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2478 error = ENODEV; 2479 break; 2480 } 2481 error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size, 2482 &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2483 break; 2484 } 2485 2486 case DIOCRDELTABLES: { 2487 struct pfioc_table *io = (struct pfioc_table *)addr; 2488 2489 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2490 error = ENODEV; 2491 break; 2492 } 2493 error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size, 2494 &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2495 break; 2496 } 2497 2498 case DIOCRGETTABLES: { 2499 struct pfioc_table *io = (struct pfioc_table *)addr; 2500 2501 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2502 error = ENODEV; 2503 break; 2504 } 2505 error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer, 2506 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2507 break; 2508 } 2509 2510 case DIOCRGETTSTATS: { 2511 struct pfioc_table *io = (struct pfioc_table *)addr; 2512 2513 if (io->pfrio_esize != sizeof(struct pfr_tstats)) { 2514 error = ENODEV; 2515 break; 2516 } 2517 error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer, 2518 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2519 break; 2520 } 2521 2522 case DIOCRCLRTSTATS: { 2523 struct pfioc_table *io = (struct pfioc_table *)addr; 2524 2525 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2526 error = ENODEV; 2527 break; 2528 } 2529 error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size, 2530 &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2531 break; 2532 } 2533 2534 case DIOCRSETTFLAGS: { 2535 struct pfioc_table *io = (struct pfioc_table *)addr; 2536 2537 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2538 error = ENODEV; 2539 break; 2540 } 2541 error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size, 2542 io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange, 2543 &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2544 break; 2545 } 2546 2547 case DIOCRCLRADDRS: { 2548 struct pfioc_table *io = (struct pfioc_table *)addr; 2549 2550 if (io->pfrio_esize != 0) { 2551 error = ENODEV; 2552 break; 2553 } 2554 error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel, 2555 io->pfrio_flags | PFR_FLAG_USERIOCTL); 2556 break; 2557 } 2558 2559 case DIOCRADDADDRS: { 2560 struct pfioc_table *io = (struct pfioc_table *)addr; 2561 2562 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2563 error = ENODEV; 2564 break; 2565 } 2566 error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer, 2567 io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags | 2568 PFR_FLAG_USERIOCTL); 2569 break; 2570 } 2571 2572 case DIOCRDELADDRS: { 2573 struct pfioc_table *io = (struct pfioc_table *)addr; 2574 2575 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2576 error = ENODEV; 2577 break; 2578 } 2579 error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer, 2580 io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags | 2581 PFR_FLAG_USERIOCTL); 2582 break; 2583 } 2584 2585 case DIOCRSETADDRS: { 2586 struct pfioc_table *io = (struct pfioc_table *)addr; 2587 2588 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2589 error = ENODEV; 2590 break; 2591 } 2592 error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer, 2593 io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd, 2594 &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags | 2595 PFR_FLAG_USERIOCTL); 2596 break; 2597 } 2598 2599 case DIOCRGETADDRS: { 2600 struct pfioc_table *io = (struct pfioc_table *)addr; 2601 2602 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2603 error = ENODEV; 2604 break; 2605 } 2606 error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer, 2607 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2608 break; 2609 } 2610 2611 case DIOCRGETASTATS: { 2612 struct pfioc_table *io = (struct pfioc_table *)addr; 2613 2614 if (io->pfrio_esize != sizeof(struct pfr_astats)) { 2615 error = ENODEV; 2616 break; 2617 } 2618 error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer, 2619 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2620 break; 2621 } 2622 2623 case DIOCRCLRASTATS: { 2624 struct pfioc_table *io = (struct pfioc_table *)addr; 2625 2626 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2627 error = ENODEV; 2628 break; 2629 } 2630 error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer, 2631 io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags | 2632 PFR_FLAG_USERIOCTL); 2633 break; 2634 } 2635 2636 case DIOCRTSTADDRS: { 2637 struct pfioc_table *io = (struct pfioc_table *)addr; 2638 2639 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2640 error = ENODEV; 2641 break; 2642 } 2643 error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer, 2644 io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags | 2645 PFR_FLAG_USERIOCTL); 2646 break; 2647 } 2648 2649 case DIOCRINADEFINE: { 2650 struct pfioc_table *io = (struct pfioc_table *)addr; 2651 2652 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2653 error = ENODEV; 2654 break; 2655 } 2656 error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer, 2657 io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr, 2658 io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL); 2659 break; 2660 } 2661 2662 case DIOCOSFPADD: { 2663 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 2664 error = pf_osfp_add(io); 2665 break; 2666 } 2667 2668 case DIOCOSFPGET: { 2669 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 2670 error = pf_osfp_get(io); 2671 break; 2672 } 2673 2674 case DIOCXBEGIN: { 2675 struct pfioc_trans *io = (struct pfioc_trans *) 2676 addr; 2677 static struct pfioc_trans_e ioe; 2678 static struct pfr_table table; 2679 int i; 2680 2681 if (io->esize != sizeof(ioe)) { 2682 error = ENODEV; 2683 goto fail; 2684 } 2685 for (i = 0; i < io->size; i++) { 2686 if (copyin(io->array+i, &ioe, sizeof(ioe))) { 2687 error = EFAULT; 2688 goto fail; 2689 } 2690 switch (ioe.rs_num) { 2691 #ifdef ALTQ 2692 case PF_RULESET_ALTQ: 2693 if (ioe.anchor[0]) { 2694 error = EINVAL; 2695 goto fail; 2696 } 2697 if ((error = pf_begin_altq(&ioe.ticket))) 2698 goto fail; 2699 break; 2700 #endif /* ALTQ */ 2701 case PF_RULESET_TABLE: 2702 bzero(&table, sizeof(table)); 2703 strlcpy(table.pfrt_anchor, ioe.anchor, 2704 sizeof(table.pfrt_anchor)); 2705 if ((error = pfr_ina_begin(&table, 2706 &ioe.ticket, NULL, 0))) 2707 goto fail; 2708 break; 2709 default: 2710 if ((error = pf_begin_rules(&ioe.ticket, 2711 ioe.rs_num, ioe.anchor))) 2712 goto fail; 2713 break; 2714 } 2715 if (copyout(&ioe, io->array+i, sizeof(io->array[i]))) { 2716 error = EFAULT; 2717 goto fail; 2718 } 2719 } 2720 break; 2721 } 2722 2723 case DIOCXROLLBACK: { 2724 struct pfioc_trans *io = (struct pfioc_trans *) 2725 addr; 2726 static struct pfioc_trans_e ioe; 2727 static struct pfr_table table; 2728 int i; 2729 2730 if (io->esize != sizeof(ioe)) { 2731 error = ENODEV; 2732 goto fail; 2733 } 2734 for (i = 0; i < io->size; i++) { 2735 if (copyin(io->array+i, &ioe, sizeof(ioe))) { 2736 error = EFAULT; 2737 goto fail; 2738 } 2739 switch (ioe.rs_num) { 2740 #ifdef ALTQ 2741 case PF_RULESET_ALTQ: 2742 if (ioe.anchor[0]) { 2743 error = EINVAL; 2744 goto fail; 2745 } 2746 if ((error = pf_rollback_altq(ioe.ticket))) 2747 goto fail; /* really bad */ 2748 break; 2749 #endif /* ALTQ */ 2750 case PF_RULESET_TABLE: 2751 bzero(&table, sizeof(table)); 2752 strlcpy(table.pfrt_anchor, ioe.anchor, 2753 sizeof(table.pfrt_anchor)); 2754 if ((error = pfr_ina_rollback(&table, 2755 ioe.ticket, NULL, 0))) 2756 goto fail; /* really bad */ 2757 break; 2758 default: 2759 if ((error = pf_rollback_rules(ioe.ticket, 2760 ioe.rs_num, ioe.anchor))) 2761 goto fail; /* really bad */ 2762 break; 2763 } 2764 } 2765 break; 2766 } 2767 2768 case DIOCXCOMMIT: { 2769 struct pfioc_trans *io = (struct pfioc_trans *) 2770 addr; 2771 static struct pfioc_trans_e ioe; 2772 static struct pfr_table table; 2773 struct pf_ruleset *rs; 2774 int i; 2775 2776 if (io->esize != sizeof(ioe)) { 2777 error = ENODEV; 2778 goto fail; 2779 } 2780 /* first makes sure everything will succeed */ 2781 for (i = 0; i < io->size; i++) { 2782 if (copyin(io->array+i, &ioe, sizeof(ioe))) { 2783 error = EFAULT; 2784 goto fail; 2785 } 2786 switch (ioe.rs_num) { 2787 #ifdef ALTQ 2788 case PF_RULESET_ALTQ: 2789 if (ioe.anchor[0]) { 2790 error = EINVAL; 2791 goto fail; 2792 } 2793 if (!altqs_inactive_open || ioe.ticket != 2794 ticket_altqs_inactive) { 2795 error = EBUSY; 2796 goto fail; 2797 } 2798 break; 2799 #endif /* ALTQ */ 2800 case PF_RULESET_TABLE: 2801 rs = pf_find_ruleset(ioe.anchor); 2802 if (rs == NULL || !rs->topen || ioe.ticket != 2803 rs->tticket) { 2804 error = EBUSY; 2805 goto fail; 2806 } 2807 break; 2808 default: 2809 if (ioe.rs_num < 0 || ioe.rs_num >= 2810 PF_RULESET_MAX) { 2811 error = EINVAL; 2812 goto fail; 2813 } 2814 rs = pf_find_ruleset(ioe.anchor); 2815 if (rs == NULL || 2816 !rs->rules[ioe.rs_num].inactive.open || 2817 rs->rules[ioe.rs_num].inactive.ticket != 2818 ioe.ticket) { 2819 error = EBUSY; 2820 goto fail; 2821 } 2822 break; 2823 } 2824 } 2825 /* now do the commit - no errors should happen here */ 2826 for (i = 0; i < io->size; i++) { 2827 if (copyin(io->array+i, &ioe, sizeof(ioe))) { 2828 error = EFAULT; 2829 goto fail; 2830 } 2831 switch (ioe.rs_num) { 2832 #ifdef ALTQ 2833 case PF_RULESET_ALTQ: 2834 if ((error = pf_commit_altq(ioe.ticket))) 2835 goto fail; /* really bad */ 2836 break; 2837 #endif /* ALTQ */ 2838 case PF_RULESET_TABLE: 2839 bzero(&table, sizeof(table)); 2840 strlcpy(table.pfrt_anchor, ioe.anchor, 2841 sizeof(table.pfrt_anchor)); 2842 if ((error = pfr_ina_commit(&table, ioe.ticket, 2843 NULL, NULL, 0))) 2844 goto fail; /* really bad */ 2845 break; 2846 default: 2847 if ((error = pf_commit_rules(ioe.ticket, 2848 ioe.rs_num, ioe.anchor))) 2849 goto fail; /* really bad */ 2850 break; 2851 } 2852 } 2853 break; 2854 } 2855 2856 case DIOCGETSRCNODES: { 2857 struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr; 2858 struct pf_src_node *n; 2859 struct pf_src_node *p, pstore; 2860 u_int32_t nr = 0; 2861 int space = psn->psn_len; 2862 2863 if (space == 0) { 2864 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) 2865 nr++; 2866 psn->psn_len = sizeof(struct pf_src_node) * nr; 2867 break; 2868 } 2869 2870 p = psn->psn_src_nodes; 2871 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { 2872 int secs = time_second, diff; 2873 2874 if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len) 2875 break; 2876 2877 bcopy(n, &pstore, sizeof(pstore)); 2878 if (n->rule.ptr != NULL) 2879 pstore.rule.nr = n->rule.ptr->nr; 2880 pstore.creation = secs - pstore.creation; 2881 if (pstore.expire > secs) 2882 pstore.expire -= secs; 2883 else 2884 pstore.expire = 0; 2885 2886 /* adjust the connection rate estimate */ 2887 diff = secs - n->conn_rate.last; 2888 if (diff >= n->conn_rate.seconds) 2889 pstore.conn_rate.count = 0; 2890 else 2891 pstore.conn_rate.count -= 2892 n->conn_rate.count * diff / 2893 n->conn_rate.seconds; 2894 2895 error = copyout(&pstore, p, sizeof(*p)); 2896 if (error) 2897 goto fail; 2898 p++; 2899 nr++; 2900 } 2901 psn->psn_len = sizeof(struct pf_src_node) * nr; 2902 break; 2903 } 2904 2905 case DIOCCLRSRCNODES: { 2906 struct pf_src_node *n; 2907 struct pf_state *state; 2908 2909 RB_FOREACH(state, pf_state_tree_id, &tree_id) { 2910 state->src_node = NULL; 2911 state->nat_src_node = NULL; 2912 } 2913 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { 2914 n->expire = 1; 2915 n->states = 0; 2916 } 2917 pf_purge_expired_src_nodes(); 2918 pf_status.src_nodes = 0; 2919 break; 2920 } 2921 2922 case DIOCSETHOSTID: { 2923 u_int32_t *hostid = (u_int32_t *)addr; 2924 2925 if (*hostid == 0) 2926 pf_status.hostid = arc4random(); 2927 else 2928 pf_status.hostid = *hostid; 2929 break; 2930 } 2931 2932 case DIOCOSFPFLUSH: 2933 pf_osfp_flush(); 2934 break; 2935 2936 case DIOCIGETIFACES: { 2937 struct pfioc_iface *io = (struct pfioc_iface *)addr; 2938 2939 if (io->pfiio_esize != sizeof(struct pfi_if)) { 2940 error = ENODEV; 2941 break; 2942 } 2943 error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer, 2944 &io->pfiio_size, io->pfiio_flags); 2945 break; 2946 } 2947 2948 case DIOCICLRISTATS: { 2949 struct pfioc_iface *io = (struct pfioc_iface *)addr; 2950 2951 error = pfi_clr_istats(io->pfiio_name, &io->pfiio_nzero, 2952 io->pfiio_flags); 2953 break; 2954 } 2955 2956 case DIOCSETIFFLAG: { 2957 struct pfioc_iface *io = (struct pfioc_iface *)addr; 2958 2959 error = pfi_set_flags(io->pfiio_name, io->pfiio_flags); 2960 break; 2961 } 2962 2963 case DIOCCLRIFFLAG: { 2964 struct pfioc_iface *io = (struct pfioc_iface *)addr; 2965 2966 error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags); 2967 break; 2968 } 2969 2970 default: 2971 error = ENODEV; 2972 break; 2973 } 2974 fail: 2975 splx(s); 2976 return (error); 2977 } 2978 2979 #ifdef __NetBSD__ 2980 #ifdef INET 2981 int 2982 pfil4_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 2983 { 2984 int error; 2985 2986 /* 2987 * ensure that mbufs are writable beforehand 2988 * as it's assumed by pf code. 2989 * ip hdr (60 bytes) + tcp hdr (60 bytes) should be enough. 2990 * XXX inefficient 2991 */ 2992 error = m_makewritable(mp, 0, 60 + 60, M_DONTWAIT); 2993 if (error) { 2994 m_freem(*mp); 2995 *mp = NULL; 2996 return error; 2997 } 2998 2999 /* 3000 * If the packet is out-bound, we can't delay checksums 3001 * here. For in-bound, the checksum has already been 3002 * validated. 3003 */ 3004 if (dir == PFIL_OUT) { 3005 if ((*mp)->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) { 3006 in_delayed_cksum(*mp); 3007 (*mp)->m_pkthdr.csum_flags &= 3008 ~(M_CSUM_TCPv4|M_CSUM_UDPv4); 3009 } 3010 } 3011 3012 if (pf_test(dir == PFIL_OUT ? PF_OUT : PF_IN, ifp, mp, NULL) 3013 != PF_PASS) { 3014 m_freem(*mp); 3015 *mp = NULL; 3016 return EHOSTUNREACH; 3017 } 3018 3019 /* 3020 * we're not compatible with fast-forward. 3021 */ 3022 3023 if (dir == PFIL_IN && *mp) { 3024 (*mp)->m_flags &= ~M_CANFASTFWD; 3025 } 3026 3027 return (0); 3028 } 3029 #endif /* INET */ 3030 3031 #ifdef INET6 3032 int 3033 pfil6_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 3034 { 3035 int error; 3036 3037 /* 3038 * ensure that mbufs are writable beforehand 3039 * as it's assumed by pf code. 3040 * XXX inefficient 3041 */ 3042 error = m_makewritable(mp, 0, M_COPYALL, M_DONTWAIT); 3043 if (error) { 3044 m_freem(*mp); 3045 *mp = NULL; 3046 return error; 3047 } 3048 3049 /* 3050 * If the packet is out-bound, we can't delay checksums 3051 * here. For in-bound, the checksum has already been 3052 * validated. 3053 */ 3054 if (dir == PFIL_OUT) { 3055 if ((*mp)->m_pkthdr.csum_flags & (M_CSUM_TCPv6|M_CSUM_UDPv6)) { 3056 in6_delayed_cksum(*mp); 3057 (*mp)->m_pkthdr.csum_flags &= 3058 ~(M_CSUM_TCPv6|M_CSUM_UDPv6); 3059 } 3060 } 3061 3062 if (pf_test6(dir == PFIL_OUT ? PF_OUT : PF_IN, ifp, mp, NULL) 3063 != PF_PASS) { 3064 m_freem(*mp); 3065 *mp = NULL; 3066 return EHOSTUNREACH; 3067 } else 3068 return (0); 3069 } 3070 #endif 3071 3072 int 3073 pfil_ifnet_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, 3074 int dir) 3075 { 3076 u_long cmd = (u_long)mp; 3077 3078 switch (cmd) { 3079 case PFIL_IFNET_ATTACH: 3080 pfi_attach_ifnet(ifp); 3081 break; 3082 case PFIL_IFNET_DETACH: 3083 pfi_detach_ifnet(ifp); 3084 break; 3085 } 3086 3087 return (0); 3088 } 3089 3090 int 3091 pfil_ifaddr_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, 3092 int dir) 3093 { 3094 extern void pfi_kifaddr_update_if(struct ifnet *); 3095 3096 u_long cmd = (u_long)mp; 3097 3098 switch (cmd) { 3099 case SIOCSIFADDR: 3100 case SIOCAIFADDR: 3101 case SIOCDIFADDR: 3102 #ifdef INET6 3103 case SIOCAIFADDR_IN6: 3104 case SIOCDIFADDR_IN6: 3105 #endif 3106 pfi_kifaddr_update_if(ifp); 3107 break; 3108 default: 3109 panic("unexpected ioctl"); 3110 } 3111 3112 return (0); 3113 } 3114 3115 static int 3116 pf_pfil_attach(void) 3117 { 3118 struct pfil_head *ph_inet; 3119 #ifdef INET6 3120 struct pfil_head *ph_inet6; 3121 #endif 3122 int error; 3123 int i; 3124 3125 if (pf_pfil_attached) 3126 return (0); 3127 3128 error = pfil_add_hook(pfil_ifnet_wrapper, NULL, PFIL_IFNET, &if_pfil); 3129 if (error) 3130 goto bad1; 3131 error = pfil_add_hook(pfil_ifaddr_wrapper, NULL, PFIL_IFADDR, &if_pfil); 3132 if (error) 3133 goto bad2; 3134 3135 ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 3136 if (ph_inet) 3137 error = pfil_add_hook((void *)pfil4_wrapper, NULL, 3138 PFIL_IN|PFIL_OUT, ph_inet); 3139 else 3140 error = ENOENT; 3141 if (error) 3142 goto bad3; 3143 3144 #ifdef INET6 3145 ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 3146 if (ph_inet6) 3147 error = pfil_add_hook((void *)pfil6_wrapper, NULL, 3148 PFIL_IN|PFIL_OUT, ph_inet6); 3149 else 3150 error = ENOENT; 3151 if (error) 3152 goto bad4; 3153 #endif 3154 3155 for (i = 0; i < if_indexlim; i++) 3156 if (ifindex2ifnet[i]) 3157 pfi_attach_ifnet(ifindex2ifnet[i]); 3158 pf_pfil_attached = 1; 3159 3160 return (0); 3161 3162 #ifdef INET6 3163 bad4: 3164 pfil_remove_hook(pfil4_wrapper, NULL, PFIL_IN|PFIL_OUT, ph_inet); 3165 #endif 3166 bad3: 3167 pfil_remove_hook(pfil_ifaddr_wrapper, NULL, PFIL_IFADDR, &if_pfil); 3168 bad2: 3169 pfil_remove_hook(pfil_ifnet_wrapper, NULL, PFIL_IFNET, &if_pfil); 3170 bad1: 3171 return (error); 3172 } 3173 3174 static int 3175 pf_pfil_detach(void) 3176 { 3177 struct pfil_head *ph_inet; 3178 #ifdef INET6 3179 struct pfil_head *ph_inet6; 3180 #endif 3181 int i; 3182 3183 if (pf_pfil_attached == 0) 3184 return (0); 3185 3186 for (i = 0; i < if_indexlim; i++) 3187 if (pfi_index2kif[i]) 3188 pfi_detach_ifnet(ifindex2ifnet[i]); 3189 3190 pfil_remove_hook(pfil_ifaddr_wrapper, NULL, PFIL_IFADDR, &if_pfil); 3191 pfil_remove_hook(pfil_ifnet_wrapper, NULL, PFIL_IFNET, &if_pfil); 3192 3193 ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 3194 if (ph_inet) 3195 pfil_remove_hook((void *)pfil4_wrapper, NULL, 3196 PFIL_IN|PFIL_OUT, ph_inet); 3197 #ifdef INET6 3198 ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 3199 if (ph_inet6) 3200 pfil_remove_hook((void *)pfil6_wrapper, NULL, 3201 PFIL_IN|PFIL_OUT, ph_inet6); 3202 #endif 3203 pf_pfil_attached = 0; 3204 3205 return (0); 3206 } 3207 #endif 3208