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