Annotation of sys/net/pf_ioctl.c, Revision 1.1.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