1 /* $OpenBSD: pf_ioctl.c,v 1.87 2003/11/02 01:33:56 mcbride Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Daniel Hartmeier 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 * Effort sponsored in part by the Defense Advanced Research Projects 32 * Agency (DARPA) and Air Force Research Laboratory, Air Force 33 * Materiel Command, USAF, under agreement number F30602-01-2-0537. 34 * 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/mbuf.h> 40 #include <sys/filio.h> 41 #include <sys/fcntl.h> 42 #include <sys/socket.h> 43 #include <sys/socketvar.h> 44 #include <sys/kernel.h> 45 #include <sys/time.h> 46 #include <sys/timeout.h> 47 #include <sys/pool.h> 48 #include <sys/malloc.h> 49 50 #include <net/if.h> 51 #include <net/if_types.h> 52 #include <net/route.h> 53 54 #include <netinet/in.h> 55 #include <netinet/in_var.h> 56 #include <netinet/in_systm.h> 57 #include <netinet/ip.h> 58 #include <netinet/ip_var.h> 59 #include <netinet/ip_icmp.h> 60 61 #include <net/pfvar.h> 62 63 #ifdef INET6 64 #include <netinet/ip6.h> 65 #include <netinet/in_pcb.h> 66 #endif /* INET6 */ 67 68 #ifdef ALTQ 69 #include <altq/altq.h> 70 #endif 71 72 void pfattach(int); 73 int pfopen(dev_t, int, int, struct proc *); 74 int pfclose(dev_t, int, int, struct proc *); 75 struct pf_pool *pf_get_pool(char *, char *, u_int32_t, 76 u_int8_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t); 77 int pf_get_ruleset_number(u_int8_t); 78 void pf_init_ruleset(struct pf_ruleset *); 79 void pf_mv_pool(struct pf_palist *, struct pf_palist *); 80 void pf_empty_pool(struct pf_palist *); 81 int pfioctl(dev_t, u_long, caddr_t, int, struct proc *); 82 #ifdef ALTQ 83 int pf_begin_altq(u_int32_t *); 84 int pf_rollback_altq(u_int32_t); 85 int pf_commit_altq(u_int32_t); 86 #endif /* ALTQ */ 87 int pf_begin_rules(u_int32_t *, int, char *, char *); 88 int pf_rollback_rules(u_int32_t, int, char *, char *); 89 int pf_commit_rules(u_int32_t, int, char *, char *); 90 91 extern struct timeout pf_expire_to; 92 93 struct pf_rule pf_default_rule; 94 95 #define TAGID_MAX 50000 96 TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags); 97 98 #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x 99 100 void 101 pfattach(int num) 102 { 103 u_int32_t *timeout = pf_default_rule.timeout; 104 105 pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl", 106 &pool_allocator_nointr); 107 pool_init(&pf_addr_pl, sizeof(struct pf_addr_dyn), 0, 0, 0, "pfaddrpl", 108 &pool_allocator_nointr); 109 pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", 110 NULL); 111 pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", 112 NULL); 113 pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, 114 "pfpooladdrpl", NULL); 115 pfr_initialize(); 116 pf_osfp_initialize(); 117 118 pool_sethardlimit(&pf_state_pl, pf_pool_limits[PF_LIMIT_STATES].limit, 119 NULL, 0); 120 121 RB_INIT(&tree_lan_ext); 122 RB_INIT(&tree_ext_gwy); 123 TAILQ_INIT(&pf_anchors); 124 pf_init_ruleset(&pf_main_ruleset); 125 TAILQ_INIT(&pf_altqs[0]); 126 TAILQ_INIT(&pf_altqs[1]); 127 TAILQ_INIT(&pf_pabuf); 128 pf_altqs_active = &pf_altqs[0]; 129 pf_altqs_inactive = &pf_altqs[1]; 130 131 /* default rule should never be garbage collected */ 132 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; 133 pf_default_rule.action = PF_PASS; 134 pf_default_rule.nr = -1; 135 136 /* initialize default timeouts */ 137 timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */ 138 timeout[PFTM_TCP_OPENING] = 30; /* No response yet */ 139 timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */ 140 timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */ 141 timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */ 142 timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */ 143 timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */ 144 timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */ 145 timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */ 146 timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */ 147 timeout[PFTM_ICMP_ERROR_REPLY] = 10; /* Got error response */ 148 timeout[PFTM_OTHER_FIRST_PACKET] = 60; /* First packet */ 149 timeout[PFTM_OTHER_SINGLE] = 30; /* Unidirectional */ 150 timeout[PFTM_OTHER_MULTIPLE] = 60; /* Bidirectional */ 151 timeout[PFTM_FRAG] = 30; /* Fragment expire */ 152 timeout[PFTM_INTERVAL] = 10; /* Expire interval */ 153 154 timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to); 155 timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz); 156 157 pf_normalize_init(); 158 pf_status.debug = PF_DEBUG_URGENT; 159 } 160 161 int 162 pfopen(dev_t dev, int flags, int fmt, struct proc *p) 163 { 164 if (minor(dev) >= 1) 165 return (ENXIO); 166 return (0); 167 } 168 169 int 170 pfclose(dev_t dev, int flags, int fmt, struct proc *p) 171 { 172 if (minor(dev) >= 1) 173 return (ENXIO); 174 return (0); 175 } 176 177 struct pf_pool * 178 pf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket, 179 u_int8_t rule_action, u_int8_t rule_number, u_int8_t r_last, 180 u_int8_t active, u_int8_t check_ticket) 181 { 182 struct pf_ruleset *ruleset; 183 struct pf_rule *rule; 184 int rs_num; 185 186 ruleset = pf_find_ruleset(anchorname, rulesetname); 187 if (ruleset == NULL) 188 return (NULL); 189 rs_num = pf_get_ruleset_number(rule_action); 190 if (rs_num >= PF_RULESET_MAX) 191 return (NULL); 192 if (active) { 193 if (check_ticket && ticket != 194 ruleset->rules[rs_num].active.ticket) 195 return (NULL); 196 if (r_last) 197 rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 198 pf_rulequeue); 199 else 200 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 201 } else { 202 if (check_ticket && ticket != 203 ruleset->rules[rs_num].inactive.ticket) 204 return (NULL); 205 if (r_last) 206 rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 207 pf_rulequeue); 208 else 209 rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr); 210 } 211 if (!r_last) { 212 while ((rule != NULL) && (rule->nr != rule_number)) 213 rule = TAILQ_NEXT(rule, entries); 214 } 215 if (rule == NULL) 216 return (NULL); 217 218 return (&rule->rpool); 219 } 220 221 int 222 pf_get_ruleset_number(u_int8_t action) 223 { 224 switch (action) { 225 case PF_SCRUB: 226 return (PF_RULESET_SCRUB); 227 break; 228 case PF_PASS: 229 case PF_DROP: 230 return (PF_RULESET_FILTER); 231 break; 232 case PF_NAT: 233 case PF_NONAT: 234 return (PF_RULESET_NAT); 235 break; 236 case PF_BINAT: 237 case PF_NOBINAT: 238 return (PF_RULESET_BINAT); 239 break; 240 case PF_RDR: 241 case PF_NORDR: 242 return (PF_RULESET_RDR); 243 break; 244 default: 245 return (PF_RULESET_MAX); 246 break; 247 } 248 } 249 250 void 251 pf_init_ruleset(struct pf_ruleset *ruleset) 252 { 253 int i; 254 255 memset(ruleset, 0, sizeof(struct pf_ruleset)); 256 for (i = 0; i < PF_RULESET_MAX; i++) { 257 TAILQ_INIT(&ruleset->rules[i].queues[0]); 258 TAILQ_INIT(&ruleset->rules[i].queues[1]); 259 ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0]; 260 ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1]; 261 } 262 } 263 264 struct pf_anchor * 265 pf_find_anchor(const char *anchorname) 266 { 267 struct pf_anchor *anchor; 268 int n = -1; 269 270 anchor = TAILQ_FIRST(&pf_anchors); 271 while (anchor != NULL && (n = strcmp(anchor->name, anchorname)) < 0) 272 anchor = TAILQ_NEXT(anchor, entries); 273 if (n == 0) 274 return (anchor); 275 else 276 return (NULL); 277 } 278 279 struct pf_ruleset * 280 pf_find_ruleset(char *anchorname, char *rulesetname) 281 { 282 struct pf_anchor *anchor; 283 struct pf_ruleset *ruleset; 284 285 if (!anchorname[0] && !rulesetname[0]) 286 return (&pf_main_ruleset); 287 if (!anchorname[0] || !rulesetname[0]) 288 return (NULL); 289 anchorname[PF_ANCHOR_NAME_SIZE-1] = 0; 290 rulesetname[PF_RULESET_NAME_SIZE-1] = 0; 291 anchor = pf_find_anchor(anchorname); 292 if (anchor == NULL) 293 return (NULL); 294 ruleset = TAILQ_FIRST(&anchor->rulesets); 295 while (ruleset != NULL && strcmp(ruleset->name, rulesetname) < 0) 296 ruleset = TAILQ_NEXT(ruleset, entries); 297 if (ruleset != NULL && !strcmp(ruleset->name, rulesetname)) 298 return (ruleset); 299 else 300 return (NULL); 301 } 302 303 struct pf_ruleset * 304 pf_find_or_create_ruleset(char *anchorname, char *rulesetname) 305 { 306 struct pf_anchor *anchor, *a; 307 struct pf_ruleset *ruleset, *r; 308 309 if (!anchorname[0] && !rulesetname[0]) 310 return (&pf_main_ruleset); 311 if (!anchorname[0] || !rulesetname[0]) 312 return (NULL); 313 anchorname[PF_ANCHOR_NAME_SIZE-1] = 0; 314 rulesetname[PF_RULESET_NAME_SIZE-1] = 0; 315 a = TAILQ_FIRST(&pf_anchors); 316 while (a != NULL && strcmp(a->name, anchorname) < 0) 317 a = TAILQ_NEXT(a, entries); 318 if (a != NULL && !strcmp(a->name, anchorname)) 319 anchor = a; 320 else { 321 anchor = (struct pf_anchor *)malloc(sizeof(struct pf_anchor), 322 M_TEMP, M_NOWAIT); 323 if (anchor == NULL) 324 return (NULL); 325 memset(anchor, 0, sizeof(struct pf_anchor)); 326 bcopy(anchorname, anchor->name, sizeof(anchor->name)); 327 TAILQ_INIT(&anchor->rulesets); 328 if (a != NULL) 329 TAILQ_INSERT_BEFORE(a, anchor, entries); 330 else 331 TAILQ_INSERT_TAIL(&pf_anchors, anchor, entries); 332 } 333 r = TAILQ_FIRST(&anchor->rulesets); 334 while (r != NULL && strcmp(r->name, rulesetname) < 0) 335 r = TAILQ_NEXT(r, entries); 336 if (r != NULL && !strcmp(r->name, rulesetname)) 337 return (r); 338 ruleset = (struct pf_ruleset *)malloc(sizeof(struct pf_ruleset), 339 M_TEMP, M_NOWAIT); 340 if (ruleset != NULL) { 341 pf_init_ruleset(ruleset); 342 bcopy(rulesetname, ruleset->name, sizeof(ruleset->name)); 343 ruleset->anchor = anchor; 344 if (r != NULL) 345 TAILQ_INSERT_BEFORE(r, ruleset, entries); 346 else 347 TAILQ_INSERT_TAIL(&anchor->rulesets, ruleset, entries); 348 } 349 return (ruleset); 350 } 351 352 void 353 pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset) 354 { 355 struct pf_anchor *anchor; 356 int i; 357 358 if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 || ruleset->topen) 359 return; 360 for (i = 0; i < PF_RULESET_MAX; ++i) 361 if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) || 362 !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) || 363 ruleset->rules[i].inactive.open) 364 return; 365 366 anchor = ruleset->anchor; 367 TAILQ_REMOVE(&anchor->rulesets, ruleset, entries); 368 free(ruleset, M_TEMP); 369 370 if (TAILQ_EMPTY(&anchor->rulesets)) { 371 TAILQ_REMOVE(&pf_anchors, anchor, entries); 372 free(anchor, M_TEMP); 373 } 374 } 375 376 void 377 pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb) 378 { 379 struct pf_pooladdr *mv_pool_pa; 380 381 while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) { 382 TAILQ_REMOVE(poola, mv_pool_pa, entries); 383 TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries); 384 } 385 } 386 387 void 388 pf_empty_pool(struct pf_palist *poola) 389 { 390 struct pf_pooladdr *empty_pool_pa; 391 392 while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) { 393 pf_dynaddr_remove(&empty_pool_pa->addr); 394 pf_tbladdr_remove(&empty_pool_pa->addr); 395 TAILQ_REMOVE(poola, empty_pool_pa, entries); 396 pool_put(&pf_pooladdr_pl, empty_pool_pa); 397 } 398 } 399 400 void 401 pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) 402 { 403 if (rulequeue != NULL) { 404 if (rule->states <= 0) { 405 /* 406 * XXX - we need to remove the table *before* detaching 407 * the rule to make sure the table code does not delete 408 * the anchor under our feet. 409 */ 410 pf_tbladdr_remove(&rule->src.addr); 411 pf_tbladdr_remove(&rule->dst.addr); 412 } 413 TAILQ_REMOVE(rulequeue, rule, entries); 414 rule->entries.tqe_prev = NULL; 415 rule->nr = -1; 416 } 417 if (rule->states > 0 || rule->entries.tqe_prev != NULL) 418 return; 419 pf_tag_unref(rule->tag); 420 pf_tag_unref(rule->match_tag); 421 pf_dynaddr_remove(&rule->src.addr); 422 pf_dynaddr_remove(&rule->dst.addr); 423 if (rulequeue == NULL) { 424 pf_tbladdr_remove(&rule->src.addr); 425 pf_tbladdr_remove(&rule->dst.addr); 426 } 427 pf_empty_pool(&rule->rpool.list); 428 pool_put(&pf_rule_pl, rule); 429 } 430 431 u_int16_t 432 pf_tagname2tag(char *tagname) 433 { 434 struct pf_tagname *tag, *p = NULL; 435 u_int16_t new_tagid = 1; 436 437 TAILQ_FOREACH(tag, &pf_tags, entries) 438 if (strcmp(tagname, tag->name) == 0) { 439 tag->ref++; 440 return (tag->tag); 441 } 442 443 /* 444 * to avoid fragmentation, we do a linear search from the beginning 445 * and take the first free slot we find. if there is none or the list 446 * is empty, append a new entry at the end. 447 */ 448 449 /* new entry */ 450 if (!TAILQ_EMPTY(&pf_tags)) 451 for (p = TAILQ_FIRST(&pf_tags); p != NULL && 452 p->tag == new_tagid; p = TAILQ_NEXT(p, entries)) 453 new_tagid = p->tag + 1; 454 455 if (new_tagid > TAGID_MAX) 456 return (0); 457 458 /* allocate and fill new struct pf_tagname */ 459 tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname), 460 M_TEMP, M_NOWAIT); 461 if (tag == NULL) 462 return (0); 463 bzero(tag, sizeof(struct pf_tagname)); 464 strlcpy(tag->name, tagname, sizeof(tag->name)); 465 tag->tag = new_tagid; 466 tag->ref++; 467 468 if (p != NULL) /* insert new entry before p */ 469 TAILQ_INSERT_BEFORE(p, tag, entries); 470 else /* either list empty or no free slot in between */ 471 TAILQ_INSERT_TAIL(&pf_tags, tag, entries); 472 473 return (tag->tag); 474 } 475 476 void 477 pf_tag2tagname(u_int16_t tagid, char *p) 478 { 479 struct pf_tagname *tag; 480 481 TAILQ_FOREACH(tag, &pf_tags, entries) 482 if (tag->tag == tagid) { 483 strlcpy(p, tag->name, PF_TAG_NAME_SIZE); 484 return; 485 } 486 } 487 488 void 489 pf_tag_unref(u_int16_t tag) 490 { 491 struct pf_tagname *p, *next; 492 493 if (tag == 0) 494 return; 495 496 for (p = TAILQ_FIRST(&pf_tags); p != NULL; p = next) { 497 next = TAILQ_NEXT(p, entries); 498 if (tag == p->tag) { 499 if (--p->ref == 0) { 500 TAILQ_REMOVE(&pf_tags, p, entries); 501 free(p, M_TEMP); 502 } 503 break; 504 } 505 } 506 } 507 508 #ifdef ALTQ 509 int 510 pf_begin_altq(u_int32_t *ticket) 511 { 512 struct pf_altq *altq; 513 int error = 0; 514 515 /* Purge the old altq list */ 516 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 517 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 518 if (altq->qname[0] == 0) { 519 /* detach and destroy the discipline */ 520 error = altq_remove(altq); 521 } 522 pool_put(&pf_altq_pl, altq); 523 } 524 if (error) 525 return (error); 526 *ticket = ++ticket_altqs_inactive; 527 altqs_inactive_open = 1; 528 return (0); 529 } 530 531 int 532 pf_rollback_altq(u_int32_t ticket) 533 { 534 struct pf_altq *altq; 535 int error = 0; 536 537 if (!altqs_inactive_open || ticket != ticket_altqs_inactive) 538 return (0); 539 /* Purge the old altq list */ 540 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 541 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 542 if (altq->qname[0] == 0) { 543 /* detach and destroy the discipline */ 544 error = altq_remove(altq); 545 } 546 pool_put(&pf_altq_pl, altq); 547 } 548 altqs_inactive_open = 0; 549 return (error); 550 } 551 552 int 553 pf_commit_altq(u_int32_t ticket) 554 { 555 struct pf_altqqueue *old_altqs; 556 struct pf_altq *altq; 557 struct pf_anchor *anchor; 558 struct pf_ruleset *ruleset; 559 int s, err, error = 0; 560 561 if (!altqs_inactive_open || ticket != ticket_altqs_inactive) 562 return (EBUSY); 563 564 /* swap altqs, keep the old. */ 565 s = splsoftnet(); 566 old_altqs = pf_altqs_active; 567 pf_altqs_active = pf_altqs_inactive; 568 pf_altqs_inactive = old_altqs; 569 ticket_altqs_active = ticket_altqs_inactive; 570 571 /* Attach new disciplines */ 572 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 573 if (altq->qname[0] == 0) { 574 /* attach the discipline */ 575 error = altq_pfattach(altq); 576 if (error) { 577 splx(s); 578 return (error); 579 } 580 } 581 } 582 583 /* Purge the old altq list */ 584 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { 585 TAILQ_REMOVE(pf_altqs_inactive, altq, entries); 586 if (altq->qname[0] == 0) { 587 /* detach and destroy the discipline */ 588 err = altq_pfdetach(altq); 589 if (err != 0 && error == 0) 590 error = err; 591 err = altq_remove(altq); 592 if (err != 0 && error == 0) 593 error = err; 594 } 595 pool_put(&pf_altq_pl, altq); 596 } 597 splx(s); 598 599 /* update queue IDs */ 600 pf_rule_set_qid( 601 pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); 602 TAILQ_FOREACH(anchor, &pf_anchors, entries) { 603 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) { 604 pf_rule_set_qid( 605 ruleset->rules[PF_RULESET_FILTER].active.ptr 606 ); 607 } 608 } 609 altqs_inactive_open = 0; 610 return (error); 611 } 612 #endif /* ALTQ */ 613 614 int 615 pf_begin_rules(u_int32_t *ticket, int rs_num, char *anchor, char *ruleset) 616 { 617 struct pf_ruleset *rs; 618 struct pf_rule *rule; 619 620 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 621 return (EINVAL); 622 rs = pf_find_or_create_ruleset(anchor, ruleset); 623 if (rs == NULL) 624 return (EINVAL); 625 while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) 626 pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); 627 *ticket = ++rs->rules[rs_num].inactive.ticket; 628 rs->rules[rs_num].inactive.open = 1; 629 return (0); 630 } 631 632 int 633 pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset) 634 { 635 struct pf_ruleset *rs; 636 struct pf_rule *rule; 637 638 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 639 return (EINVAL); 640 rs = pf_find_ruleset(anchor, ruleset); 641 if (rs == NULL || !rs->rules[rs_num].inactive.open || 642 rs->rules[rs_num].inactive.ticket != ticket) 643 return (0); 644 while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) 645 pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); 646 rs->rules[rs_num].inactive.open = 0; 647 return (0); 648 } 649 650 int 651 pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset) 652 { 653 struct pf_ruleset *rs; 654 struct pf_rule *rule; 655 struct pf_rulequeue *old_rules; 656 int s; 657 658 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) 659 return (EINVAL); 660 rs = pf_find_ruleset(anchor, ruleset); 661 if (rs == NULL || !rs->rules[rs_num].inactive.open || 662 ticket != rs->rules[rs_num].inactive.ticket) 663 return (EBUSY); 664 665 #ifdef ALTQ 666 /* set queue IDs */ 667 if (rs_num == PF_RULESET_FILTER) 668 pf_rule_set_qid(rs->rules[rs_num].inactive.ptr); 669 #endif 670 671 /* Swap rules, keep the old. */ 672 s = splsoftnet(); 673 old_rules = rs->rules[rs_num].active.ptr; 674 rs->rules[rs_num].active.ptr = 675 rs->rules[rs_num].inactive.ptr; 676 rs->rules[rs_num].inactive.ptr = old_rules; 677 rs->rules[rs_num].active.ticket = 678 rs->rules[rs_num].inactive.ticket; 679 pf_calc_skip_steps(rs->rules[rs_num].active.ptr); 680 681 /* Purge the old rule list. */ 682 while ((rule = TAILQ_FIRST(old_rules)) != NULL) 683 pf_rm_rule(old_rules, rule); 684 rs->rules[rs_num].inactive.open = 0; 685 pf_remove_if_empty_ruleset(rs); 686 pf_update_anchor_rules(); 687 splx(s); 688 return (0); 689 } 690 691 int 692 pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 693 { 694 struct pf_pooladdr *pa = NULL; 695 struct pf_pool *pool = NULL; 696 int s; 697 int error = 0; 698 699 /* XXX keep in sync with switch() below */ 700 if (securelevel > 1) 701 switch (cmd) { 702 case DIOCGETRULES: 703 case DIOCGETRULE: 704 case DIOCGETADDRS: 705 case DIOCGETADDR: 706 case DIOCGETSTATE: 707 case DIOCSETSTATUSIF: 708 case DIOCGETSTATUS: 709 case DIOCCLRSTATUS: 710 case DIOCNATLOOK: 711 case DIOCSETDEBUG: 712 case DIOCGETSTATES: 713 case DIOCGETTIMEOUT: 714 case DIOCCLRRULECTRS: 715 case DIOCGETLIMIT: 716 case DIOCGETALTQS: 717 case DIOCGETALTQ: 718 case DIOCGETQSTATS: 719 case DIOCGETANCHORS: 720 case DIOCGETANCHOR: 721 case DIOCGETRULESETS: 722 case DIOCGETRULESET: 723 case DIOCRGETTABLES: 724 case DIOCRGETTSTATS: 725 case DIOCRCLRTSTATS: 726 case DIOCRCLRADDRS: 727 case DIOCRADDADDRS: 728 case DIOCRDELADDRS: 729 case DIOCRSETADDRS: 730 case DIOCRGETADDRS: 731 case DIOCRGETASTATS: 732 case DIOCRCLRASTATS: 733 case DIOCRTSTADDRS: 734 case DIOCOSFPGET: 735 break; 736 default: 737 return (EPERM); 738 } 739 740 if (!(flags & FWRITE)) 741 switch (cmd) { 742 case DIOCGETRULES: 743 case DIOCGETRULE: 744 case DIOCGETADDRS: 745 case DIOCGETADDR: 746 case DIOCGETSTATE: 747 case DIOCGETSTATUS: 748 case DIOCGETSTATES: 749 case DIOCGETTIMEOUT: 750 case DIOCGETLIMIT: 751 case DIOCGETALTQS: 752 case DIOCGETALTQ: 753 case DIOCGETQSTATS: 754 case DIOCGETANCHORS: 755 case DIOCGETANCHOR: 756 case DIOCGETRULESETS: 757 case DIOCGETRULESET: 758 case DIOCRGETTABLES: 759 case DIOCRGETTSTATS: 760 case DIOCRGETADDRS: 761 case DIOCRGETASTATS: 762 case DIOCRTSTADDRS: 763 case DIOCOSFPGET: 764 break; 765 default: 766 return (EACCES); 767 } 768 769 switch (cmd) { 770 771 case DIOCSTART: 772 if (pf_status.running) 773 error = EEXIST; 774 else { 775 u_int32_t states = pf_status.states; 776 u_int32_t debug = pf_status.debug; 777 bzero(&pf_status, sizeof(struct pf_status)); 778 pf_status.running = 1; 779 pf_status.states = states; 780 pf_status.debug = debug; 781 pf_status.since = time.tv_sec; 782 if (status_ifp != NULL) 783 strlcpy(pf_status.ifname, 784 status_ifp->if_xname, IFNAMSIZ); 785 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); 786 } 787 break; 788 789 case DIOCSTOP: 790 if (!pf_status.running) 791 error = ENOENT; 792 else { 793 pf_status.running = 0; 794 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); 795 } 796 break; 797 798 case DIOCBEGINRULES: { 799 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 800 801 error = pf_begin_rules(&pr->ticket, pf_get_ruleset_number( 802 pr->rule.action), pr->anchor, pr->ruleset); 803 break; 804 } 805 806 case DIOCADDRULE: { 807 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 808 struct pf_ruleset *ruleset; 809 struct pf_rule *rule, *tail; 810 struct pf_pooladdr *pa; 811 int rs_num; 812 813 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 814 if (ruleset == NULL) { 815 error = EINVAL; 816 break; 817 } 818 rs_num = pf_get_ruleset_number(pr->rule.action); 819 if (rs_num >= PF_RULESET_MAX) { 820 error = EINVAL; 821 break; 822 } 823 if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) { 824 error = EINVAL; 825 break; 826 } 827 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 828 error = EINVAL; 829 break; 830 } 831 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { 832 error = EBUSY; 833 break; 834 } 835 if (pr->pool_ticket != ticket_pabuf) { 836 error = EBUSY; 837 break; 838 } 839 rule = pool_get(&pf_rule_pl, PR_NOWAIT); 840 if (rule == NULL) { 841 error = ENOMEM; 842 break; 843 } 844 bcopy(&pr->rule, rule, sizeof(struct pf_rule)); 845 rule->anchor = NULL; 846 rule->ifp = NULL; 847 TAILQ_INIT(&rule->rpool.list); 848 /* initialize refcounting */ 849 rule->states = 0; 850 rule->entries.tqe_prev = NULL; 851 #ifndef INET 852 if (rule->af == AF_INET) { 853 pool_put(&pf_rule_pl, rule); 854 error = EAFNOSUPPORT; 855 break; 856 } 857 #endif /* INET */ 858 #ifndef INET6 859 if (rule->af == AF_INET6) { 860 pool_put(&pf_rule_pl, rule); 861 error = EAFNOSUPPORT; 862 break; 863 } 864 #endif /* INET6 */ 865 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr, 866 pf_rulequeue); 867 if (tail) 868 rule->nr = tail->nr + 1; 869 else 870 rule->nr = 0; 871 if (rule->ifname[0]) { 872 rule->ifp = ifunit(rule->ifname); 873 if (rule->ifp == NULL) { 874 pool_put(&pf_rule_pl, rule); 875 error = EINVAL; 876 break; 877 } 878 } 879 880 if (rule->tagname[0]) 881 if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) 882 error = EBUSY; 883 if (rule->match_tagname[0]) 884 if ((rule->match_tag = 885 pf_tagname2tag(rule->match_tagname)) == 0) 886 error = EBUSY; 887 if (rule->rt && !rule->direction) 888 error = EINVAL; 889 if (pf_dynaddr_setup(&rule->src.addr, rule->af)) 890 error = EINVAL; 891 if (pf_dynaddr_setup(&rule->dst.addr, rule->af)) 892 error = EINVAL; 893 if (pf_tbladdr_setup(ruleset, &rule->src.addr)) 894 error = EINVAL; 895 if (pf_tbladdr_setup(ruleset, &rule->dst.addr)) 896 error = EINVAL; 897 TAILQ_FOREACH(pa, &pf_pabuf, entries) 898 if (pf_tbladdr_setup(ruleset, &pa->addr)) 899 error = EINVAL; 900 901 pf_mv_pool(&pf_pabuf, &rule->rpool.list); 902 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || 903 (rule->action == PF_BINAT)) && !rule->anchorname[0]) || 904 (rule->rt > PF_FASTROUTE)) && 905 (TAILQ_FIRST(&rule->rpool.list) == NULL)) 906 error = EINVAL; 907 908 if (error) { 909 pf_rm_rule(NULL, rule); 910 break; 911 } 912 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list); 913 rule->evaluations = rule->packets = rule->bytes = 0; 914 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, 915 rule, entries); 916 break; 917 } 918 919 case DIOCCOMMITRULES: { 920 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 921 922 error = pf_commit_rules(pr->ticket, pf_get_ruleset_number( 923 pr->rule.action), pr->anchor, pr->ruleset); 924 break; 925 } 926 927 case DIOCGETRULES: { 928 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 929 struct pf_ruleset *ruleset; 930 struct pf_rule *tail; 931 int rs_num; 932 933 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 934 if (ruleset == NULL) { 935 error = EINVAL; 936 break; 937 } 938 rs_num = pf_get_ruleset_number(pr->rule.action); 939 if (rs_num >= PF_RULESET_MAX) { 940 error = EINVAL; 941 break; 942 } 943 s = splsoftnet(); 944 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, 945 pf_rulequeue); 946 if (tail) 947 pr->nr = tail->nr + 1; 948 else 949 pr->nr = 0; 950 pr->ticket = ruleset->rules[rs_num].active.ticket; 951 splx(s); 952 break; 953 } 954 955 case DIOCGETRULE: { 956 struct pfioc_rule *pr = (struct pfioc_rule *)addr; 957 struct pf_ruleset *ruleset; 958 struct pf_rule *rule; 959 int rs_num, i; 960 961 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); 962 if (ruleset == NULL) { 963 error = EINVAL; 964 break; 965 } 966 rs_num = pf_get_ruleset_number(pr->rule.action); 967 if (rs_num >= PF_RULESET_MAX) { 968 error = EINVAL; 969 break; 970 } 971 if (pr->ticket != ruleset->rules[rs_num].active.ticket) { 972 error = EBUSY; 973 break; 974 } 975 s = splsoftnet(); 976 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr); 977 while ((rule != NULL) && (rule->nr != pr->nr)) 978 rule = TAILQ_NEXT(rule, entries); 979 if (rule == NULL) { 980 error = EBUSY; 981 splx(s); 982 break; 983 } 984 bcopy(rule, &pr->rule, sizeof(struct pf_rule)); 985 pf_dynaddr_copyout(&pr->rule.src.addr); 986 pf_dynaddr_copyout(&pr->rule.dst.addr); 987 pf_tbladdr_copyout(&pr->rule.src.addr); 988 pf_tbladdr_copyout(&pr->rule.dst.addr); 989 for (i = 0; i < PF_SKIP_COUNT; ++i) 990 if (rule->skip[i].ptr == NULL) 991 pr->rule.skip[i].nr = -1; 992 else 993 pr->rule.skip[i].nr = 994 rule->skip[i].ptr->nr; 995 splx(s); 996 break; 997 } 998 999 case DIOCCHANGERULE: { 1000 struct pfioc_rule *pcr = (struct pfioc_rule *)addr; 1001 struct pf_ruleset *ruleset; 1002 struct pf_rule *oldrule = NULL, *newrule = NULL; 1003 u_int32_t nr = 0; 1004 int rs_num; 1005 1006 if (!(pcr->action == PF_CHANGE_REMOVE || 1007 pcr->action == PF_CHANGE_GET_TICKET) && 1008 pcr->pool_ticket != ticket_pabuf) { 1009 error = EBUSY; 1010 break; 1011 } 1012 1013 if (pcr->action < PF_CHANGE_ADD_HEAD || 1014 pcr->action > PF_CHANGE_GET_TICKET) { 1015 error = EINVAL; 1016 break; 1017 } 1018 ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset); 1019 if (ruleset == NULL) { 1020 error = EINVAL; 1021 break; 1022 } 1023 rs_num = pf_get_ruleset_number(pcr->rule.action); 1024 if (rs_num >= PF_RULESET_MAX) { 1025 error = EINVAL; 1026 break; 1027 } 1028 1029 if (pcr->action == PF_CHANGE_GET_TICKET) { 1030 pcr->ticket = ++ruleset->rules[rs_num].active.ticket; 1031 break; 1032 } else { 1033 if (pcr->ticket != 1034 ruleset->rules[rs_num].active.ticket) { 1035 error = EINVAL; 1036 break; 1037 } 1038 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { 1039 error = EINVAL; 1040 break; 1041 } 1042 } 1043 1044 if (pcr->action != PF_CHANGE_REMOVE) { 1045 newrule = pool_get(&pf_rule_pl, PR_NOWAIT); 1046 if (newrule == NULL) { 1047 error = ENOMEM; 1048 break; 1049 } 1050 bcopy(&pcr->rule, newrule, sizeof(struct pf_rule)); 1051 TAILQ_INIT(&newrule->rpool.list); 1052 /* initialize refcounting */ 1053 newrule->states = 0; 1054 newrule->entries.tqe_prev = NULL; 1055 #ifndef INET 1056 if (newrule->af == AF_INET) { 1057 pool_put(&pf_rule_pl, newrule); 1058 error = EAFNOSUPPORT; 1059 break; 1060 } 1061 #endif /* INET */ 1062 #ifndef INET6 1063 if (newrule->af == AF_INET6) { 1064 pool_put(&pf_rule_pl, newrule); 1065 error = EAFNOSUPPORT; 1066 break; 1067 } 1068 #endif /* INET6 */ 1069 if (newrule->ifname[0]) { 1070 newrule->ifp = ifunit(newrule->ifname); 1071 if (newrule->ifp == NULL) { 1072 pool_put(&pf_rule_pl, newrule); 1073 error = EINVAL; 1074 break; 1075 } 1076 } else 1077 newrule->ifp = NULL; 1078 1079 #ifdef ALTQ 1080 /* set queue IDs */ 1081 if (newrule->qname[0] != 0) { 1082 newrule->qid = pf_qname_to_qid(newrule->qname); 1083 if (newrule->pqname[0] != 0) 1084 newrule->pqid = 1085 pf_qname_to_qid(newrule->pqname); 1086 else 1087 newrule->pqid = newrule->qid; 1088 } 1089 #endif 1090 if (newrule->tagname[0]) 1091 if ((newrule->tag = 1092 pf_tagname2tag(newrule->tagname)) == 0) 1093 error = EBUSY; 1094 if (newrule->match_tagname[0]) 1095 if ((newrule->match_tag = pf_tagname2tag( 1096 newrule->match_tagname)) == 0) 1097 error = EBUSY; 1098 1099 if (newrule->rt && !newrule->direction) 1100 error = EINVAL; 1101 if (pf_dynaddr_setup(&newrule->src.addr, newrule->af)) 1102 error = EINVAL; 1103 if (pf_dynaddr_setup(&newrule->dst.addr, newrule->af)) 1104 error = EINVAL; 1105 if (pf_tbladdr_setup(ruleset, &newrule->src.addr)) 1106 error = EINVAL; 1107 if (pf_tbladdr_setup(ruleset, &newrule->dst.addr)) 1108 error = EINVAL; 1109 1110 pf_mv_pool(&pf_pabuf, &newrule->rpool.list); 1111 if (((((newrule->action == PF_NAT) || 1112 (newrule->action == PF_RDR) || 1113 (newrule->action == PF_BINAT) || 1114 (newrule->rt > PF_FASTROUTE)) && 1115 !newrule->anchorname[0])) && 1116 (TAILQ_FIRST(&newrule->rpool.list) == NULL)) 1117 error = EINVAL; 1118 1119 if (error) { 1120 pf_rm_rule(NULL, newrule); 1121 break; 1122 } 1123 newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list); 1124 newrule->evaluations = newrule->packets = 0; 1125 newrule->bytes = 0; 1126 } 1127 pf_empty_pool(&pf_pabuf); 1128 1129 s = splsoftnet(); 1130 1131 if (pcr->action == PF_CHANGE_ADD_HEAD) 1132 oldrule = TAILQ_FIRST( 1133 ruleset->rules[rs_num].active.ptr); 1134 else if (pcr->action == PF_CHANGE_ADD_TAIL) 1135 oldrule = TAILQ_LAST( 1136 ruleset->rules[rs_num].active.ptr, pf_rulequeue); 1137 else { 1138 oldrule = TAILQ_FIRST( 1139 ruleset->rules[rs_num].active.ptr); 1140 while ((oldrule != NULL) && (oldrule->nr != pcr->nr)) 1141 oldrule = TAILQ_NEXT(oldrule, entries); 1142 if (oldrule == NULL) { 1143 pf_rm_rule(NULL, newrule); 1144 error = EINVAL; 1145 splx(s); 1146 break; 1147 } 1148 } 1149 1150 if (pcr->action == PF_CHANGE_REMOVE) 1151 pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule); 1152 else { 1153 if (oldrule == NULL) 1154 TAILQ_INSERT_TAIL( 1155 ruleset->rules[rs_num].active.ptr, 1156 newrule, entries); 1157 else if (pcr->action == PF_CHANGE_ADD_HEAD || 1158 pcr->action == PF_CHANGE_ADD_BEFORE) 1159 TAILQ_INSERT_BEFORE(oldrule, newrule, entries); 1160 else 1161 TAILQ_INSERT_AFTER( 1162 ruleset->rules[rs_num].active.ptr, 1163 oldrule, newrule, entries); 1164 } 1165 1166 nr = 0; 1167 TAILQ_FOREACH(oldrule, 1168 ruleset->rules[rs_num].active.ptr, entries) 1169 oldrule->nr = nr++; 1170 1171 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); 1172 pf_remove_if_empty_ruleset(ruleset); 1173 pf_update_anchor_rules(); 1174 1175 ruleset->rules[rs_num].active.ticket++; 1176 splx(s); 1177 break; 1178 } 1179 1180 case DIOCCLRSTATES: { 1181 struct pf_state *state; 1182 1183 s = splsoftnet(); 1184 RB_FOREACH(state, pf_state_tree_ext_gwy, &tree_ext_gwy) 1185 state->timeout = PFTM_PURGE; 1186 pf_purge_expired_states(); 1187 pf_status.states = 0; 1188 splx(s); 1189 break; 1190 } 1191 1192 case DIOCKILLSTATES: { 1193 struct pf_state *state; 1194 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; 1195 int killed = 0; 1196 1197 s = splsoftnet(); 1198 RB_FOREACH(state, pf_state_tree_ext_gwy, &tree_ext_gwy) { 1199 if ((!psk->psk_af || state->af == psk->psk_af) && 1200 (!psk->psk_proto || psk->psk_proto == state->proto) && 1201 PF_MATCHA(psk->psk_src.not, 1202 &psk->psk_src.addr.v.a.addr, 1203 &psk->psk_src.addr.v.a.mask, &state->lan.addr, 1204 state->af) && 1205 PF_MATCHA(psk->psk_dst.not, 1206 &psk->psk_dst.addr.v.a.addr, 1207 &psk->psk_dst.addr.v.a.mask, &state->ext.addr, 1208 state->af) && 1209 (psk->psk_src.port_op == 0 || 1210 pf_match_port(psk->psk_src.port_op, 1211 psk->psk_src.port[0], psk->psk_src.port[1], 1212 state->lan.port)) && 1213 (psk->psk_dst.port_op == 0 || 1214 pf_match_port(psk->psk_dst.port_op, 1215 psk->psk_dst.port[0], psk->psk_dst.port[1], 1216 state->ext.port))) { 1217 state->timeout = PFTM_PURGE; 1218 killed++; 1219 } 1220 } 1221 pf_purge_expired_states(); 1222 splx(s); 1223 psk->psk_af = killed; 1224 break; 1225 } 1226 1227 case DIOCADDSTATE: { 1228 struct pfioc_state *ps = (struct pfioc_state *)addr; 1229 struct pf_state *state; 1230 1231 if (ps->state.timeout >= PFTM_MAX && 1232 ps->state.timeout != PFTM_UNTIL_PACKET) { 1233 error = EINVAL; 1234 break; 1235 } 1236 state = pool_get(&pf_state_pl, PR_NOWAIT); 1237 if (state == NULL) { 1238 error = ENOMEM; 1239 break; 1240 } 1241 s = splsoftnet(); 1242 bcopy(&ps->state, state, sizeof(struct pf_state)); 1243 state->rule.ptr = NULL; 1244 state->nat_rule.ptr = NULL; 1245 state->anchor.ptr = NULL; 1246 state->rt_ifp = NULL; 1247 state->creation = time.tv_sec; 1248 state->packets[0] = state->packets[1] = 0; 1249 state->bytes[0] = state->bytes[1] = 0; 1250 if (pf_insert_state(state)) { 1251 pool_put(&pf_state_pl, state); 1252 error = ENOMEM; 1253 } 1254 splx(s); 1255 break; 1256 } 1257 1258 case DIOCGETSTATE: { 1259 struct pfioc_state *ps = (struct pfioc_state *)addr; 1260 struct pf_state *state; 1261 u_int32_t nr; 1262 1263 nr = 0; 1264 s = splsoftnet(); 1265 RB_FOREACH(state, pf_state_tree_ext_gwy, &tree_ext_gwy) { 1266 if (nr >= ps->nr) 1267 break; 1268 nr++; 1269 } 1270 if (state == NULL) { 1271 error = EBUSY; 1272 splx(s); 1273 break; 1274 } 1275 bcopy(state, &ps->state, sizeof(struct pf_state)); 1276 ps->state.rule.nr = state->rule.ptr->nr; 1277 ps->state.nat_rule.nr = (state->nat_rule.ptr == NULL) ? 1278 -1 : state->nat_rule.ptr->nr; 1279 ps->state.anchor.nr = (state->anchor.ptr == NULL) ? 1280 -1 : state->anchor.ptr->nr; 1281 splx(s); 1282 ps->state.expire = pf_state_expires(state); 1283 if (ps->state.expire > time.tv_sec) 1284 ps->state.expire -= time.tv_sec; 1285 else 1286 ps->state.expire = 0; 1287 break; 1288 } 1289 1290 case DIOCGETSTATES: { 1291 struct pfioc_states *ps = (struct pfioc_states *)addr; 1292 struct pf_state *state; 1293 struct pf_state *p, pstore; 1294 u_int32_t nr = 0; 1295 int space = ps->ps_len; 1296 1297 if (space == 0) { 1298 s = splsoftnet(); 1299 RB_FOREACH(state, pf_state_tree_ext_gwy, &tree_ext_gwy) 1300 nr++; 1301 splx(s); 1302 ps->ps_len = sizeof(struct pf_state) * nr; 1303 return (0); 1304 } 1305 1306 s = splsoftnet(); 1307 p = ps->ps_states; 1308 RB_FOREACH(state, pf_state_tree_ext_gwy, &tree_ext_gwy) { 1309 int secs = time.tv_sec; 1310 1311 if ((nr + 1) * sizeof(*p) > (unsigned)ps->ps_len) 1312 break; 1313 1314 bcopy(state, &pstore, sizeof(pstore)); 1315 pstore.rule.nr = state->rule.ptr->nr; 1316 pstore.nat_rule.nr = (state->nat_rule.ptr == NULL) ? 1317 -1 : state->nat_rule.ptr->nr; 1318 pstore.anchor.nr = (state->anchor.ptr == NULL) ? 1319 -1 : state->anchor.ptr->nr; 1320 pstore.creation = secs - pstore.creation; 1321 pstore.expire = pf_state_expires(state); 1322 if (pstore.expire > secs) 1323 pstore.expire -= secs; 1324 else 1325 pstore.expire = 0; 1326 error = copyout(&pstore, p, sizeof(*p)); 1327 if (error) { 1328 splx(s); 1329 goto fail; 1330 } 1331 p++; 1332 nr++; 1333 } 1334 ps->ps_len = sizeof(struct pf_state) * nr; 1335 splx(s); 1336 break; 1337 } 1338 1339 case DIOCGETSTATUS: { 1340 struct pf_status *s = (struct pf_status *)addr; 1341 bcopy(&pf_status, s, sizeof(struct pf_status)); 1342 break; 1343 } 1344 1345 case DIOCSETSTATUSIF: { 1346 struct pfioc_if *pi = (struct pfioc_if *)addr; 1347 struct ifnet *ifp; 1348 1349 if (pi->ifname[0] == 0) { 1350 status_ifp = NULL; 1351 bzero(pf_status.ifname, IFNAMSIZ); 1352 break; 1353 } 1354 if ((ifp = ifunit(pi->ifname)) == NULL) { 1355 error = EINVAL; 1356 break; 1357 } else if (ifp == status_ifp) 1358 break; 1359 status_ifp = ifp; 1360 /* fallthrough into DIOCCLRSTATUS */ 1361 } 1362 1363 case DIOCCLRSTATUS: { 1364 u_int32_t running = pf_status.running; 1365 u_int32_t states = pf_status.states; 1366 u_int32_t since = pf_status.since; 1367 u_int32_t debug = pf_status.debug; 1368 1369 bzero(&pf_status, sizeof(struct pf_status)); 1370 pf_status.running = running; 1371 pf_status.states = states; 1372 pf_status.since = since; 1373 pf_status.debug = debug; 1374 if (status_ifp != NULL) 1375 strlcpy(pf_status.ifname, 1376 status_ifp->if_xname, IFNAMSIZ); 1377 break; 1378 } 1379 1380 case DIOCNATLOOK: { 1381 struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; 1382 struct pf_state *state; 1383 struct pf_state key; 1384 int direction = pnl->direction; 1385 1386 key.af = pnl->af; 1387 key.proto = pnl->proto; 1388 1389 if (!pnl->proto || 1390 PF_AZERO(&pnl->saddr, pnl->af) || 1391 PF_AZERO(&pnl->daddr, pnl->af) || 1392 !pnl->dport || !pnl->sport) 1393 error = EINVAL; 1394 else { 1395 s = splsoftnet(); 1396 1397 /* 1398 * userland gives us source and dest of connection, 1399 * reverse the lookup so we ask for what happens with 1400 * the return traffic, enabling us to find it in the 1401 * state tree. 1402 */ 1403 if (direction == PF_IN) { 1404 PF_ACPY(&key.ext.addr, &pnl->daddr, pnl->af); 1405 key.ext.port = pnl->dport; 1406 PF_ACPY(&key.gwy.addr, &pnl->saddr, pnl->af); 1407 key.gwy.port = pnl->sport; 1408 state = pf_find_state(&key, PF_EXT_GWY); 1409 } else { 1410 PF_ACPY(&key.lan.addr, &pnl->daddr, pnl->af); 1411 key.lan.port = pnl->dport; 1412 PF_ACPY(&key.ext.addr, &pnl->saddr, pnl->af); 1413 key.ext.port = pnl->sport; 1414 state = pf_find_state(&key, PF_LAN_EXT); 1415 } 1416 if (state != NULL) { 1417 if (direction == PF_IN) { 1418 PF_ACPY(&pnl->rsaddr, &state->lan.addr, 1419 state->af); 1420 pnl->rsport = state->lan.port; 1421 PF_ACPY(&pnl->rdaddr, &pnl->daddr, 1422 pnl->af); 1423 pnl->rdport = pnl->dport; 1424 } else { 1425 PF_ACPY(&pnl->rdaddr, &state->gwy.addr, 1426 state->af); 1427 pnl->rdport = state->gwy.port; 1428 PF_ACPY(&pnl->rsaddr, &pnl->saddr, 1429 pnl->af); 1430 pnl->rsport = pnl->sport; 1431 } 1432 } else 1433 error = ENOENT; 1434 splx(s); 1435 } 1436 break; 1437 } 1438 1439 case DIOCSETTIMEOUT: { 1440 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 1441 int old; 1442 1443 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX || 1444 pt->seconds < 0) { 1445 error = EINVAL; 1446 goto fail; 1447 } 1448 old = pf_default_rule.timeout[pt->timeout]; 1449 pf_default_rule.timeout[pt->timeout] = pt->seconds; 1450 pt->seconds = old; 1451 break; 1452 } 1453 1454 case DIOCGETTIMEOUT: { 1455 struct pfioc_tm *pt = (struct pfioc_tm *)addr; 1456 1457 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) { 1458 error = EINVAL; 1459 goto fail; 1460 } 1461 pt->seconds = pf_default_rule.timeout[pt->timeout]; 1462 break; 1463 } 1464 1465 case DIOCGETLIMIT: { 1466 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 1467 1468 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { 1469 error = EINVAL; 1470 goto fail; 1471 } 1472 pl->limit = pf_pool_limits[pl->index].limit; 1473 break; 1474 } 1475 1476 case DIOCSETLIMIT: { 1477 struct pfioc_limit *pl = (struct pfioc_limit *)addr; 1478 int old_limit; 1479 1480 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { 1481 error = EINVAL; 1482 goto fail; 1483 } 1484 if (pool_sethardlimit(pf_pool_limits[pl->index].pp, 1485 pl->limit, NULL, 0) != 0) { 1486 error = EBUSY; 1487 goto fail; 1488 } 1489 old_limit = pf_pool_limits[pl->index].limit; 1490 pf_pool_limits[pl->index].limit = pl->limit; 1491 pl->limit = old_limit; 1492 break; 1493 } 1494 1495 case DIOCSETDEBUG: { 1496 u_int32_t *level = (u_int32_t *)addr; 1497 1498 pf_status.debug = *level; 1499 break; 1500 } 1501 1502 case DIOCCLRRULECTRS: { 1503 struct pf_ruleset *ruleset = &pf_main_ruleset; 1504 struct pf_rule *rule; 1505 1506 s = splsoftnet(); 1507 TAILQ_FOREACH(rule, 1508 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) 1509 rule->evaluations = rule->packets = 1510 rule->bytes = 0; 1511 splx(s); 1512 break; 1513 } 1514 1515 #ifdef ALTQ 1516 case DIOCSTARTALTQ: { 1517 struct pf_altq *altq; 1518 struct ifnet *ifp; 1519 struct tb_profile tb; 1520 1521 /* enable all altq interfaces on active list */ 1522 s = splsoftnet(); 1523 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 1524 if (altq->qname[0] == 0) { 1525 if ((ifp = ifunit(altq->ifname)) == NULL) { 1526 error = EINVAL; 1527 break; 1528 } 1529 if (ifp->if_snd.altq_type != ALTQT_NONE) 1530 error = altq_enable(&ifp->if_snd); 1531 if (error != 0) 1532 break; 1533 /* set tokenbucket regulator */ 1534 tb.rate = altq->ifbandwidth; 1535 tb.depth = altq->tbrsize; 1536 error = tbr_set(&ifp->if_snd, &tb); 1537 if (error != 0) 1538 break; 1539 } 1540 } 1541 if (error == 0) 1542 pfaltq_running = 1; 1543 splx(s); 1544 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n")); 1545 break; 1546 } 1547 1548 case DIOCSTOPALTQ: { 1549 struct pf_altq *altq; 1550 struct ifnet *ifp; 1551 struct tb_profile tb; 1552 int err; 1553 1554 /* disable all altq interfaces on active list */ 1555 s = splsoftnet(); 1556 TAILQ_FOREACH(altq, pf_altqs_active, entries) { 1557 if (altq->qname[0] == 0) { 1558 if ((ifp = ifunit(altq->ifname)) == NULL) { 1559 error = EINVAL; 1560 break; 1561 } 1562 if (ifp->if_snd.altq_type != ALTQT_NONE) { 1563 err = altq_disable(&ifp->if_snd); 1564 if (err != 0 && error == 0) 1565 error = err; 1566 } 1567 /* clear tokenbucket regulator */ 1568 tb.rate = 0; 1569 err = tbr_set(&ifp->if_snd, &tb); 1570 if (err != 0 && error == 0) 1571 error = err; 1572 } 1573 } 1574 if (error == 0) 1575 pfaltq_running = 0; 1576 splx(s); 1577 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n")); 1578 break; 1579 } 1580 1581 case DIOCBEGINALTQS: { 1582 u_int32_t *ticket = (u_int32_t *)addr; 1583 1584 error = pf_begin_altq(ticket); 1585 break; 1586 } 1587 1588 case DIOCADDALTQ: { 1589 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 1590 struct pf_altq *altq, *a; 1591 1592 if (pa->ticket != ticket_altqs_inactive) { 1593 error = EBUSY; 1594 break; 1595 } 1596 altq = pool_get(&pf_altq_pl, PR_NOWAIT); 1597 if (altq == NULL) { 1598 error = ENOMEM; 1599 break; 1600 } 1601 bcopy(&pa->altq, altq, sizeof(struct pf_altq)); 1602 1603 /* 1604 * if this is for a queue, find the discipline and 1605 * copy the necessary fields 1606 */ 1607 if (altq->qname[0] != 0) { 1608 TAILQ_FOREACH(a, pf_altqs_inactive, entries) { 1609 if (strncmp(a->ifname, altq->ifname, 1610 IFNAMSIZ) == 0 && a->qname[0] == 0) { 1611 altq->altq_disc = a->altq_disc; 1612 break; 1613 } 1614 } 1615 } 1616 1617 error = altq_add(altq); 1618 if (error) { 1619 pool_put(&pf_altq_pl, altq); 1620 break; 1621 } 1622 1623 TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries); 1624 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 1625 break; 1626 } 1627 1628 case DIOCCOMMITALTQS: { 1629 u_int32_t ticket = *(u_int32_t *)addr; 1630 1631 error = pf_commit_altq(ticket); 1632 break; 1633 } 1634 1635 case DIOCGETALTQS: { 1636 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 1637 struct pf_altq *altq; 1638 1639 pa->nr = 0; 1640 s = splsoftnet(); 1641 TAILQ_FOREACH(altq, pf_altqs_active, entries) 1642 pa->nr++; 1643 pa->ticket = ticket_altqs_active; 1644 splx(s); 1645 break; 1646 } 1647 1648 case DIOCGETALTQ: { 1649 struct pfioc_altq *pa = (struct pfioc_altq *)addr; 1650 struct pf_altq *altq; 1651 u_int32_t nr; 1652 1653 if (pa->ticket != ticket_altqs_active) { 1654 error = EBUSY; 1655 break; 1656 } 1657 nr = 0; 1658 s = splsoftnet(); 1659 altq = TAILQ_FIRST(pf_altqs_active); 1660 while ((altq != NULL) && (nr < pa->nr)) { 1661 altq = TAILQ_NEXT(altq, entries); 1662 nr++; 1663 } 1664 if (altq == NULL) { 1665 error = EBUSY; 1666 splx(s); 1667 break; 1668 } 1669 bcopy(altq, &pa->altq, sizeof(struct pf_altq)); 1670 splx(s); 1671 break; 1672 } 1673 1674 case DIOCCHANGEALTQ: 1675 /* CHANGEALTQ not supported yet! */ 1676 error = ENODEV; 1677 break; 1678 1679 case DIOCGETQSTATS: { 1680 struct pfioc_qstats *pq = (struct pfioc_qstats *)addr; 1681 struct pf_altq *altq; 1682 u_int32_t nr; 1683 int nbytes; 1684 1685 if (pq->ticket != ticket_altqs_active) { 1686 error = EBUSY; 1687 break; 1688 } 1689 nbytes = pq->nbytes; 1690 nr = 0; 1691 s = splsoftnet(); 1692 altq = TAILQ_FIRST(pf_altqs_active); 1693 while ((altq != NULL) && (nr < pq->nr)) { 1694 altq = TAILQ_NEXT(altq, entries); 1695 nr++; 1696 } 1697 if (altq == NULL) { 1698 error = EBUSY; 1699 splx(s); 1700 break; 1701 } 1702 error = altq_getqstats(altq, pq->buf, &nbytes); 1703 splx(s); 1704 if (error == 0) { 1705 pq->scheduler = altq->scheduler; 1706 pq->nbytes = nbytes; 1707 } 1708 break; 1709 } 1710 #endif /* ALTQ */ 1711 1712 case DIOCBEGINADDRS: { 1713 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 1714 1715 pf_empty_pool(&pf_pabuf); 1716 pp->ticket = ++ticket_pabuf; 1717 break; 1718 } 1719 1720 case DIOCADDADDR: { 1721 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 1722 1723 #ifndef INET 1724 if (pp->af == AF_INET) { 1725 error = EAFNOSUPPORT; 1726 break; 1727 } 1728 #endif /* INET */ 1729 #ifndef INET6 1730 if (pp->af == AF_INET6) { 1731 error = EAFNOSUPPORT; 1732 break; 1733 } 1734 #endif /* INET6 */ 1735 if (pp->addr.addr.type != PF_ADDR_ADDRMASK && 1736 pp->addr.addr.type != PF_ADDR_DYNIFTL && 1737 pp->addr.addr.type != PF_ADDR_TABLE) { 1738 error = EINVAL; 1739 break; 1740 } 1741 pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT); 1742 if (pa == NULL) { 1743 error = ENOMEM; 1744 break; 1745 } 1746 bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr)); 1747 if (pa->ifname[0]) { 1748 pa->ifp = ifunit(pa->ifname); 1749 if (pa->ifp == NULL) { 1750 pool_put(&pf_pooladdr_pl, pa); 1751 error = EINVAL; 1752 break; 1753 } 1754 } 1755 if (pf_dynaddr_setup(&pa->addr, pp->af)) { 1756 pf_dynaddr_remove(&pa->addr); 1757 pool_put(&pf_pooladdr_pl, pa); 1758 error = EINVAL; 1759 break; 1760 } 1761 TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries); 1762 break; 1763 } 1764 1765 case DIOCGETADDRS: { 1766 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 1767 1768 pp->nr = 0; 1769 s = splsoftnet(); 1770 pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket, 1771 pp->r_action, pp->r_num, 0, 1, 0); 1772 if (pool == NULL) { 1773 error = EBUSY; 1774 splx(s); 1775 break; 1776 } 1777 TAILQ_FOREACH(pa, &pool->list, entries) 1778 pp->nr++; 1779 splx(s); 1780 break; 1781 } 1782 1783 case DIOCGETADDR: { 1784 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; 1785 u_int32_t nr = 0; 1786 1787 s = splsoftnet(); 1788 pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket, 1789 pp->r_action, pp->r_num, 0, 1, 1); 1790 if (pool == NULL) { 1791 error = EBUSY; 1792 splx(s); 1793 break; 1794 } 1795 pa = TAILQ_FIRST(&pool->list); 1796 while ((pa != NULL) && (nr < pp->nr)) { 1797 pa = TAILQ_NEXT(pa, entries); 1798 nr++; 1799 } 1800 if (pa == NULL) { 1801 error = EBUSY; 1802 splx(s); 1803 break; 1804 } 1805 bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr)); 1806 pf_dynaddr_copyout(&pp->addr.addr); 1807 pf_tbladdr_copyout(&pp->addr.addr); 1808 splx(s); 1809 break; 1810 } 1811 1812 case DIOCCHANGEADDR: { 1813 struct pfioc_pooladdr *pca = (struct pfioc_pooladdr *)addr; 1814 struct pf_pooladdr *oldpa = NULL, *newpa = NULL; 1815 struct pf_ruleset *ruleset; 1816 1817 if (pca->action < PF_CHANGE_ADD_HEAD || 1818 pca->action > PF_CHANGE_REMOVE) { 1819 error = EINVAL; 1820 break; 1821 } 1822 if (pca->addr.addr.type != PF_ADDR_ADDRMASK && 1823 pca->addr.addr.type != PF_ADDR_DYNIFTL && 1824 pca->addr.addr.type != PF_ADDR_TABLE) { 1825 error = EINVAL; 1826 break; 1827 } 1828 1829 ruleset = pf_find_ruleset(pca->anchor, pca->ruleset); 1830 if (ruleset == NULL) { 1831 error = EBUSY; 1832 break; 1833 } 1834 pool = pf_get_pool(pca->anchor, pca->ruleset, pca->ticket, 1835 pca->r_action, pca->r_num, pca->r_last, 1, 1); 1836 if (pool == NULL) { 1837 error = EBUSY; 1838 break; 1839 } 1840 if (pca->action != PF_CHANGE_REMOVE) { 1841 newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT); 1842 if (newpa == NULL) { 1843 error = ENOMEM; 1844 break; 1845 } 1846 bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr)); 1847 #ifndef INET 1848 if (pca->af == AF_INET) { 1849 pool_put(&pf_pooladdr_pl, newpa); 1850 error = EAFNOSUPPORT; 1851 break; 1852 } 1853 #endif /* INET */ 1854 #ifndef INET6 1855 if (pca->af == AF_INET6) { 1856 pool_put(&pf_pooladdr_pl, newpa); 1857 error = EAFNOSUPPORT; 1858 break; 1859 } 1860 #endif /* INET6 */ 1861 if (newpa->ifname[0]) { 1862 newpa->ifp = ifunit(newpa->ifname); 1863 if (newpa->ifp == NULL) { 1864 pool_put(&pf_pooladdr_pl, newpa); 1865 error = EINVAL; 1866 break; 1867 } 1868 } else 1869 newpa->ifp = NULL; 1870 if (pf_dynaddr_setup(&newpa->addr, pca->af) || 1871 pf_tbladdr_setup(ruleset, &newpa->addr)) { 1872 pf_dynaddr_remove(&newpa->addr); 1873 pool_put(&pf_pooladdr_pl, newpa); 1874 error = EINVAL; 1875 break; 1876 } 1877 } 1878 1879 s = splsoftnet(); 1880 1881 if (pca->action == PF_CHANGE_ADD_HEAD) 1882 oldpa = TAILQ_FIRST(&pool->list); 1883 else if (pca->action == PF_CHANGE_ADD_TAIL) 1884 oldpa = TAILQ_LAST(&pool->list, pf_palist); 1885 else { 1886 int i = 0; 1887 1888 oldpa = TAILQ_FIRST(&pool->list); 1889 while ((oldpa != NULL) && (i < pca->nr)) { 1890 oldpa = TAILQ_NEXT(oldpa, entries); 1891 i++; 1892 } 1893 if (oldpa == NULL) { 1894 error = EINVAL; 1895 splx(s); 1896 break; 1897 } 1898 } 1899 1900 if (pca->action == PF_CHANGE_REMOVE) { 1901 TAILQ_REMOVE(&pool->list, oldpa, entries); 1902 pf_dynaddr_remove(&oldpa->addr); 1903 pf_tbladdr_remove(&oldpa->addr); 1904 pool_put(&pf_pooladdr_pl, oldpa); 1905 } else { 1906 if (oldpa == NULL) 1907 TAILQ_INSERT_TAIL(&pool->list, newpa, entries); 1908 else if (pca->action == PF_CHANGE_ADD_HEAD || 1909 pca->action == PF_CHANGE_ADD_BEFORE) 1910 TAILQ_INSERT_BEFORE(oldpa, newpa, entries); 1911 else 1912 TAILQ_INSERT_AFTER(&pool->list, oldpa, 1913 newpa, entries); 1914 } 1915 1916 pool->cur = TAILQ_FIRST(&pool->list); 1917 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, 1918 pca->af); 1919 splx(s); 1920 break; 1921 } 1922 1923 case DIOCGETANCHORS: { 1924 struct pfioc_anchor *pa = (struct pfioc_anchor *)addr; 1925 struct pf_anchor *anchor; 1926 1927 pa->nr = 0; 1928 TAILQ_FOREACH(anchor, &pf_anchors, entries) 1929 pa->nr++; 1930 break; 1931 } 1932 1933 case DIOCGETANCHOR: { 1934 struct pfioc_anchor *pa = (struct pfioc_anchor *)addr; 1935 struct pf_anchor *anchor; 1936 u_int32_t nr = 0; 1937 1938 anchor = TAILQ_FIRST(&pf_anchors); 1939 while (anchor != NULL && nr < pa->nr) { 1940 anchor = TAILQ_NEXT(anchor, entries); 1941 nr++; 1942 } 1943 if (anchor == NULL) 1944 error = EBUSY; 1945 else 1946 bcopy(anchor->name, pa->name, sizeof(pa->name)); 1947 break; 1948 } 1949 1950 case DIOCGETRULESETS: { 1951 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 1952 struct pf_anchor *anchor; 1953 struct pf_ruleset *ruleset; 1954 1955 pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0; 1956 if ((anchor = pf_find_anchor(pr->anchor)) == NULL) { 1957 error = EINVAL; 1958 break; 1959 } 1960 pr->nr = 0; 1961 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) 1962 pr->nr++; 1963 break; 1964 } 1965 1966 case DIOCGETRULESET: { 1967 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; 1968 struct pf_anchor *anchor; 1969 struct pf_ruleset *ruleset; 1970 u_int32_t nr = 0; 1971 1972 if ((anchor = pf_find_anchor(pr->anchor)) == NULL) { 1973 error = EINVAL; 1974 break; 1975 } 1976 ruleset = TAILQ_FIRST(&anchor->rulesets); 1977 while (ruleset != NULL && nr < pr->nr) { 1978 ruleset = TAILQ_NEXT(ruleset, entries); 1979 nr++; 1980 } 1981 if (ruleset == NULL) 1982 error = EBUSY; 1983 else 1984 bcopy(ruleset->name, pr->name, sizeof(pr->name)); 1985 break; 1986 } 1987 1988 case DIOCRCLRTABLES: { 1989 struct pfioc_table *io = (struct pfioc_table *)addr; 1990 1991 if (io->pfrio_esize != 0) { 1992 error = ENODEV; 1993 break; 1994 } 1995 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, 1996 io->pfrio_flags); 1997 break; 1998 } 1999 2000 case DIOCRADDTABLES: { 2001 struct pfioc_table *io = (struct pfioc_table *)addr; 2002 2003 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2004 error = ENODEV; 2005 break; 2006 } 2007 error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size, 2008 &io->pfrio_nadd, io->pfrio_flags); 2009 break; 2010 } 2011 2012 case DIOCRDELTABLES: { 2013 struct pfioc_table *io = (struct pfioc_table *)addr; 2014 2015 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2016 error = ENODEV; 2017 break; 2018 } 2019 error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size, 2020 &io->pfrio_ndel, io->pfrio_flags); 2021 break; 2022 } 2023 2024 case DIOCRGETTABLES: { 2025 struct pfioc_table *io = (struct pfioc_table *)addr; 2026 2027 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2028 error = ENODEV; 2029 break; 2030 } 2031 error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer, 2032 &io->pfrio_size, io->pfrio_flags); 2033 break; 2034 } 2035 2036 case DIOCRGETTSTATS: { 2037 struct pfioc_table *io = (struct pfioc_table *)addr; 2038 2039 if (io->pfrio_esize != sizeof(struct pfr_tstats)) { 2040 error = ENODEV; 2041 break; 2042 } 2043 error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer, 2044 &io->pfrio_size, io->pfrio_flags); 2045 break; 2046 } 2047 2048 case DIOCRCLRTSTATS: { 2049 struct pfioc_table *io = (struct pfioc_table *)addr; 2050 2051 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2052 error = ENODEV; 2053 break; 2054 } 2055 error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size, 2056 &io->pfrio_nzero, io->pfrio_flags); 2057 break; 2058 } 2059 2060 case DIOCRSETTFLAGS: { 2061 struct pfioc_table *io = (struct pfioc_table *)addr; 2062 2063 if (io->pfrio_esize != sizeof(struct pfr_table)) { 2064 error = ENODEV; 2065 break; 2066 } 2067 error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size, 2068 io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange, 2069 &io->pfrio_ndel, io->pfrio_flags); 2070 break; 2071 } 2072 2073 case DIOCRCLRADDRS: { 2074 struct pfioc_table *io = (struct pfioc_table *)addr; 2075 2076 if (io->pfrio_esize != 0) { 2077 error = ENODEV; 2078 break; 2079 } 2080 error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel, 2081 io->pfrio_flags); 2082 break; 2083 } 2084 2085 case DIOCRADDADDRS: { 2086 struct pfioc_table *io = (struct pfioc_table *)addr; 2087 2088 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2089 error = ENODEV; 2090 break; 2091 } 2092 error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer, 2093 io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags); 2094 break; 2095 } 2096 2097 case DIOCRDELADDRS: { 2098 struct pfioc_table *io = (struct pfioc_table *)addr; 2099 2100 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2101 error = ENODEV; 2102 break; 2103 } 2104 error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer, 2105 io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags); 2106 break; 2107 } 2108 2109 case DIOCRSETADDRS: { 2110 struct pfioc_table *io = (struct pfioc_table *)addr; 2111 2112 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2113 error = ENODEV; 2114 break; 2115 } 2116 error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer, 2117 io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd, 2118 &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags); 2119 break; 2120 } 2121 2122 case DIOCRGETADDRS: { 2123 struct pfioc_table *io = (struct pfioc_table *)addr; 2124 2125 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2126 error = ENODEV; 2127 break; 2128 } 2129 error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer, 2130 &io->pfrio_size, io->pfrio_flags); 2131 break; 2132 } 2133 2134 case DIOCRGETASTATS: { 2135 struct pfioc_table *io = (struct pfioc_table *)addr; 2136 2137 if (io->pfrio_esize != sizeof(struct pfr_astats)) { 2138 error = ENODEV; 2139 break; 2140 } 2141 error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer, 2142 &io->pfrio_size, io->pfrio_flags); 2143 break; 2144 } 2145 2146 case DIOCRCLRASTATS: { 2147 struct pfioc_table *io = (struct pfioc_table *)addr; 2148 2149 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2150 error = ENODEV; 2151 break; 2152 } 2153 error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer, 2154 io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags); 2155 break; 2156 } 2157 2158 case DIOCRTSTADDRS: { 2159 struct pfioc_table *io = (struct pfioc_table *)addr; 2160 2161 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2162 error = ENODEV; 2163 break; 2164 } 2165 error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer, 2166 io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags); 2167 break; 2168 } 2169 2170 case DIOCRINABEGIN: { 2171 struct pfioc_table *io = (struct pfioc_table *)addr; 2172 2173 if (io->pfrio_esize != 0) { 2174 error = ENODEV; 2175 break; 2176 } 2177 error = pfr_ina_begin(&io->pfrio_table, &io->pfrio_ticket, 2178 &io->pfrio_ndel, io->pfrio_flags); 2179 break; 2180 } 2181 2182 case DIOCRINACOMMIT: { 2183 struct pfioc_table *io = (struct pfioc_table *)addr; 2184 2185 if (io->pfrio_esize != 0) { 2186 error = ENODEV; 2187 break; 2188 } 2189 error = pfr_ina_commit(&io->pfrio_table, io->pfrio_ticket, 2190 &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags); 2191 break; 2192 } 2193 2194 case DIOCRINADEFINE: { 2195 struct pfioc_table *io = (struct pfioc_table *)addr; 2196 2197 if (io->pfrio_esize != sizeof(struct pfr_addr)) { 2198 error = ENODEV; 2199 break; 2200 } 2201 error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer, 2202 io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr, 2203 io->pfrio_ticket, io->pfrio_flags); 2204 break; 2205 } 2206 2207 case DIOCOSFPFLUSH: 2208 s = splsoftnet(); 2209 pf_osfp_flush(); 2210 splx(s); 2211 break; 2212 2213 case DIOCOSFPADD: { 2214 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 2215 s = splsoftnet(); 2216 error = pf_osfp_add(io); 2217 splx(s); 2218 break; 2219 } 2220 2221 case DIOCOSFPGET: { 2222 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; 2223 s = splsoftnet(); 2224 error = pf_osfp_get(io); 2225 splx(s); 2226 break; 2227 } 2228 2229 case DIOCXBEGIN: { 2230 struct pfioc_trans *io = (struct pfioc_trans *)addr; 2231 struct pfioc_trans_e ioe; 2232 struct pfr_table table; 2233 int i; 2234 2235 if (io->esize != sizeof(ioe)) { 2236 error = ENODEV; 2237 goto fail; 2238 } 2239 for (i = 0; i < io->size; i++) { 2240 if (copyin(io->array+i, &ioe, sizeof(ioe))) { 2241 error = EFAULT; 2242 goto fail; 2243 } 2244 switch(ioe.rs_num) { 2245 #ifdef ALTQ 2246 case PF_RULESET_ALTQ: 2247 if (ioe.anchor[0] || ioe.ruleset[0]) { 2248 error = EINVAL; 2249 goto fail; 2250 } 2251 if ((error = pf_begin_altq(&ioe.ticket))) 2252 goto fail; 2253 break; 2254 #endif /* ALTQ */ 2255 case PF_RULESET_TABLE: 2256 bzero(&table, sizeof(table)); 2257 strlcpy(table.pfrt_anchor, ioe.anchor, 2258 sizeof(table.pfrt_anchor)); 2259 strlcpy(table.pfrt_ruleset, ioe.ruleset, 2260 sizeof(table.pfrt_ruleset)); 2261 if ((error = pfr_ina_begin(&table, 2262 &ioe.ticket, NULL, 0))) 2263 goto fail; 2264 break; 2265 default: 2266 if ((error = pf_begin_rules(&ioe.ticket, 2267 ioe.rs_num, ioe.anchor, ioe.ruleset))) 2268 goto fail; 2269 break; 2270 } 2271 if (copyout(&ioe, io->array+i, sizeof(io->array[i]))) { 2272 error = EFAULT; 2273 goto fail; 2274 } 2275 } 2276 break; 2277 } 2278 2279 case DIOCXROLLBACK: { 2280 struct pfioc_trans *io = (struct pfioc_trans *)addr; 2281 struct pfioc_trans_e ioe; 2282 struct pfr_table table; 2283 int i; 2284 2285 if (io->esize != sizeof(ioe)) { 2286 error = ENODEV; 2287 goto fail; 2288 } 2289 for (i = 0; i < io->size; i++) { 2290 if (copyin(io->array+i, &ioe, sizeof(ioe))) { 2291 error = EFAULT; 2292 goto fail; 2293 } 2294 switch(ioe.rs_num) { 2295 #ifdef ALTQ 2296 case PF_RULESET_ALTQ: 2297 if (ioe.anchor[0] || ioe.ruleset[0]) { 2298 error = EINVAL; 2299 goto fail; 2300 } 2301 if ((error = pf_rollback_altq(ioe.ticket))) 2302 goto fail; /* really bad */ 2303 break; 2304 #endif /* ALTQ */ 2305 case PF_RULESET_TABLE: 2306 bzero(&table, sizeof(table)); 2307 strlcpy(table.pfrt_anchor, ioe.anchor, 2308 sizeof(table.pfrt_anchor)); 2309 strlcpy(table.pfrt_ruleset, ioe.ruleset, 2310 sizeof(table.pfrt_ruleset)); 2311 if ((error = pfr_ina_rollback(&table, 2312 ioe.ticket, NULL, 0))) 2313 goto fail; /* really bad */ 2314 break; 2315 default: 2316 if ((error = pf_rollback_rules(ioe.ticket, 2317 ioe.rs_num, ioe.anchor, ioe.ruleset))) 2318 goto fail; /* really bad */ 2319 break; 2320 } 2321 } 2322 break; 2323 } 2324 2325 case DIOCXCOMMIT: { 2326 struct pfioc_trans *io = (struct pfioc_trans *)addr; 2327 struct pfioc_trans_e ioe; 2328 struct pfr_table table; 2329 struct pf_ruleset *rs; 2330 int i; 2331 2332 if (io->esize != sizeof(ioe)) { 2333 error = ENODEV; 2334 goto fail; 2335 } 2336 /* first makes sure everything will succeed */ 2337 for (i = 0; i < io->size; i++) { 2338 if (copyin(io->array+i, &ioe, sizeof(ioe))) { 2339 error = EFAULT; 2340 goto fail; 2341 } 2342 switch (ioe.rs_num) { 2343 #ifdef ALTQ 2344 case PF_RULESET_ALTQ: 2345 if (ioe.anchor[0] || ioe.ruleset[0]) { 2346 error = EINVAL; 2347 goto fail; 2348 } 2349 if (!altqs_inactive_open || ioe.ticket != 2350 ticket_altqs_inactive) { 2351 error = EBUSY; 2352 goto fail; 2353 } 2354 break; 2355 #endif /* ALTQ */ 2356 case PF_RULESET_TABLE: 2357 rs = pf_find_ruleset(ioe.anchor, ioe.ruleset); 2358 if (rs == NULL || !rs->topen || ioe.ticket != 2359 rs->tticket) { 2360 error = EBUSY; 2361 goto fail; 2362 } 2363 break; 2364 default: 2365 if (ioe.rs_num < 0 || ioe.rs_num >= 2366 PF_RULESET_MAX) { 2367 error = EINVAL; 2368 goto fail; 2369 } 2370 rs = pf_find_ruleset(ioe.anchor, ioe.ruleset); 2371 if (rs == NULL || 2372 !rs->rules[ioe.rs_num].inactive.open || 2373 rs->rules[ioe.rs_num].inactive.ticket != 2374 ioe.ticket) { 2375 error = EBUSY; 2376 goto fail; 2377 } 2378 break; 2379 } 2380 } 2381 /* now do the commit - no errors should happen here */ 2382 for (i = 0; i < io->size; i++) { 2383 if (copyin(io->array+i, &ioe, sizeof(ioe))) { 2384 error = EFAULT; 2385 goto fail; 2386 } 2387 switch (ioe.rs_num) { 2388 #ifdef ALTQ 2389 case PF_RULESET_ALTQ: 2390 if ((error = pf_commit_altq(ioe.ticket))) 2391 goto fail; /* really bad */ 2392 break; 2393 #endif /* ALTQ */ 2394 case PF_RULESET_TABLE: 2395 bzero(&table, sizeof(table)); 2396 strlcpy(table.pfrt_anchor, ioe.anchor, 2397 sizeof(table.pfrt_anchor)); 2398 strlcpy(table.pfrt_ruleset, ioe.ruleset, 2399 sizeof(table.pfrt_ruleset)); 2400 if ((error = pfr_ina_commit(&table, ioe.ticket, 2401 NULL, NULL, 0))) 2402 goto fail; /* really bad */ 2403 break; 2404 default: 2405 if ((error = pf_commit_rules(ioe.ticket, 2406 ioe.rs_num, ioe.anchor, ioe.ruleset))) 2407 goto fail; /* really bad */ 2408 break; 2409 } 2410 } 2411 break; 2412 } 2413 2414 default: 2415 error = ENODEV; 2416 break; 2417 } 2418 fail: 2419 2420 return (error); 2421 } 2422