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