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