1 /* $OpenBSD: pf_ioctl.c,v 1.213 2009/02/15 21:46:12 mbalmer Exp $ */
2
3 /*
4 * Copyright (c) 2001 Daniel Hartmeier
5 * Copyright (c) 2002,2003 Henning Brauer
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * - Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Effort sponsored in part by the Defense Advanced Research Projects
33 * Agency (DARPA) and Air Force Research Laboratory, Air Force
34 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
35 *
36 */
37
38 #ifdef __FreeBSD__
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD: stable/9/sys/contrib/pf/net/pf_ioctl.c 292731 2015-12-25 15:12:11Z kp $");
41
42 #include "opt_inet.h"
43 #include "opt_inet6.h"
44 #include "opt_bpf.h"
45 #include "opt_pf.h"
46
47 #define NPFSYNC 1
48
49 #ifdef DEV_PFLOG
50 #define NPFLOG DEV_PFLOG
51 #else
52 #define NPFLOG 0
53 #endif
54
55 #else /* !__FreeBSD__ */
56 #include "pfsync.h"
57 #include "pflog.h"
58 #endif /* __FreeBSD__ */
59
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/mbuf.h>
63 #include <sys/filio.h>
64 #include <sys/fcntl.h>
65 #include <sys/socket.h>
66 #include <sys/socketvar.h>
67 #include <sys/kernel.h>
68 #include <sys/time.h>
69 #ifdef __FreeBSD__
70 #include <sys/ucred.h>
71 #include <sys/jail.h>
72 #include <sys/module.h>
73 #include <sys/conf.h>
74 #include <sys/proc.h>
75 #include <sys/sysctl.h>
76 #else
77 #include <sys/timeout.h>
78 #include <sys/pool.h>
79 #endif
80 #include <sys/proc.h>
81 #include <sys/malloc.h>
82 #include <sys/kthread.h>
83 #ifndef __FreeBSD__
84 #include <sys/rwlock.h>
85 #include <uvm/uvm_extern.h>
86 #endif
87
88 #include <net/if.h>
89 #include <net/if_types.h>
90 #ifdef __FreeBSD__
91 #include <net/vnet.h>
92 #endif
93 #include <net/route.h>
94
95 #include <netinet/in.h>
96 #include <netinet/in_var.h>
97 #include <netinet/in_systm.h>
98 #include <netinet/ip.h>
99 #include <netinet/ip_var.h>
100 #include <netinet/ip_icmp.h>
101
102 #ifdef __FreeBSD__
103 #include <sys/md5.h>
104 #else
105 #include <dev/rndvar.h>
106 #include <crypto/md5.h>
107 #endif
108 #include <net/pfvar.h>
109
110 #include <net/if_pfsync.h>
111
112 #if NPFLOG > 0
113 #include <net/if_pflog.h>
114 #endif /* NPFLOG > 0 */
115
116 #ifdef INET6
117 #include <netinet/ip6.h>
118 #include <netinet/in_pcb.h>
119 #endif /* INET6 */
120
121 #ifdef ALTQ
122 #include <altq/altq.h>
123 #endif
124
125 #ifdef __FreeBSD__
126 #include <sys/limits.h>
127 #include <sys/lock.h>
128 #include <sys/mutex.h>
129 #include <net/pfil.h>
130 #endif /* __FreeBSD__ */
131
132 #ifdef __FreeBSD__
133 void init_zone_var(void);
134 void cleanup_pf_zone(void);
135 int pfattach(void);
136 #else
137 void pfattach(int);
138 void pf_thread_create(void *);
139 int pfopen(dev_t, int, int, struct proc *);
140 int pfclose(dev_t, int, int, struct proc *);
141 #endif
142 struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
143 u_int8_t, u_int8_t, u_int8_t);
144
145 void pf_mv_pool(struct pf_palist *, struct pf_palist *);
146 void pf_empty_pool(struct pf_palist *);
147 #ifdef __FreeBSD__
148 int pfioctl(struct cdev *, u_long, caddr_t, int, struct thread *);
149 #else
150 int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
151 #endif
152 #ifdef ALTQ
153 int pf_begin_altq(u_int32_t *);
154 int pf_rollback_altq(u_int32_t);
155 int pf_commit_altq(u_int32_t);
156 int pf_enable_altq(struct pf_altq *);
157 int pf_disable_altq(struct pf_altq *);
158 #endif /* ALTQ */
159 int pf_begin_rules(u_int32_t *, int, const char *);
160 int pf_rollback_rules(u_int32_t, int, char *);
161 int pf_setup_pfsync_matching(struct pf_ruleset *);
162 void pf_hash_rule(MD5_CTX *, struct pf_rule *);
163 void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *);
164 int pf_commit_rules(u_int32_t, int, char *);
165 int pf_addr_setup(struct pf_ruleset *,
166 struct pf_addr_wrap *, sa_family_t);
167 void pf_addr_copyout(struct pf_addr_wrap *);
168
169 #define TAGID_MAX 50000
170
171 #ifdef __FreeBSD__
172 VNET_DEFINE(struct pf_rule, pf_default_rule);
173 VNET_DEFINE(struct sx, pf_consistency_lock);
174
175 #ifdef ALTQ
176 static VNET_DEFINE(int, pf_altq_running);
177 #define V_pf_altq_running VNET(pf_altq_running)
178 #endif
179
180 TAILQ_HEAD(pf_tags, pf_tagname);
181
182 #define V_pf_tags VNET(pf_tags)
183 VNET_DEFINE(struct pf_tags, pf_tags);
184 #define V_pf_qids VNET(pf_qids)
185 VNET_DEFINE(struct pf_tags, pf_qids);
186
187 #else /* !__FreeBSD__ */
188 struct pf_rule pf_default_rule;
189 struct rwlock pf_consistency_lock = RWLOCK_INITIALIZER("pfcnslk");
190 #ifdef ALTQ
191 static int pf_altq_running;
192 #endif
193
194 TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags),
195 pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids);
196 #endif /* __FreeBSD__ */
197
198 #if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
199 #error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
200 #endif
201
202 u_int16_t tagname2tag(struct pf_tags *, char *);
203 void tag2tagname(struct pf_tags *, u_int16_t, char *);
204 void tag_unref(struct pf_tags *, u_int16_t);
205 int pf_rtlabel_add(struct pf_addr_wrap *);
206 void pf_rtlabel_remove(struct pf_addr_wrap *);
207 void pf_rtlabel_copyout(struct pf_addr_wrap *);
208
209 #ifdef __FreeBSD__
210 #define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x
211 #else
212 #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
213 #endif
214
215 #ifdef __FreeBSD__
216 struct cdev *pf_dev;
217
218 /*
219 * XXX - These are new and need to be checked when moveing to a new version
220 */
221 static void pf_clear_states(void);
222 static int pf_clear_tables(void);
223 static void pf_clear_srcnodes(void);
224 /*
225 * XXX - These are new and need to be checked when moveing to a new version
226 */
227
228 /*
229 * Wrapper functions for pfil(9) hooks
230 */
231 #ifdef INET
232 static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp,
233 int dir, struct inpcb *inp);
234 static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp,
235 int dir, struct inpcb *inp);
236 #endif
237 #ifdef INET6
238 static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp,
239 int dir, struct inpcb *inp);
240 static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp,
241 int dir, struct inpcb *inp);
242 #endif
243
244 static int hook_pf(void);
245 static int dehook_pf(void);
246 static int shutdown_pf(void);
247 static int pf_load(void);
248 static int pf_unload(void);
249
250 static struct cdevsw pf_cdevsw = {
251 .d_ioctl = pfioctl,
252 .d_name = PF_NAME,
253 .d_version = D_VERSION,
254 };
255
256 static volatile VNET_DEFINE(int, pf_pfil_hooked);
257 #define V_pf_pfil_hooked VNET(pf_pfil_hooked)
258 VNET_DEFINE(int, pf_end_threads);
259 struct mtx pf_task_mtx;
260
261 /* pfsync */
262 pfsync_state_import_t *pfsync_state_import_ptr = NULL;
263 pfsync_insert_state_t *pfsync_insert_state_ptr = NULL;
264 pfsync_update_state_t *pfsync_update_state_ptr = NULL;
265 pfsync_delete_state_t *pfsync_delete_state_ptr = NULL;
266 pfsync_clear_states_t *pfsync_clear_states_ptr = NULL;
267 pfsync_state_in_use_t *pfsync_state_in_use_ptr = NULL;
268 pfsync_defer_t *pfsync_defer_ptr = NULL;
269 pfsync_up_t *pfsync_up_ptr = NULL;
270 /* pflow */
271 export_pflow_t *export_pflow_ptr = NULL;
272 /* pflog */
273 pflog_packet_t *pflog_packet_ptr = NULL;
274
275 VNET_DEFINE(int, debug_pfugidhack);
276 SYSCTL_VNET_INT(_debug, OID_AUTO, pfugidhack, CTLFLAG_RW,
277 &VNET_NAME(debug_pfugidhack), 0,
278 "Enable/disable pf user/group rules mpsafe hack");
279
280 static void
init_pf_mutex(void)281 init_pf_mutex(void)
282 {
283
284 mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF);
285 }
286
287 static void
destroy_pf_mutex(void)288 destroy_pf_mutex(void)
289 {
290
291 mtx_destroy(&pf_task_mtx);
292 }
293 void
init_zone_var(void)294 init_zone_var(void)
295 {
296 V_pf_src_tree_pl = V_pf_rule_pl = NULL;
297 V_pf_state_pl = V_pf_state_key_pl = V_pf_state_item_pl = NULL;
298 V_pf_altq_pl = V_pf_pooladdr_pl = NULL;
299 V_pf_frent_pl = V_pf_frag_pl = V_pf_cache_pl = V_pf_cent_pl = NULL;
300 V_pf_state_scrub_pl = NULL;
301 V_pfr_ktable_pl = V_pfr_kentry_pl = V_pfr_kcounters_pl = NULL;
302 }
303
304 void
cleanup_pf_zone(void)305 cleanup_pf_zone(void)
306 {
307 UMA_DESTROY(V_pf_src_tree_pl);
308 UMA_DESTROY(V_pf_rule_pl);
309 UMA_DESTROY(V_pf_state_pl);
310 UMA_DESTROY(V_pf_state_key_pl);
311 UMA_DESTROY(V_pf_state_item_pl);
312 UMA_DESTROY(V_pf_altq_pl);
313 UMA_DESTROY(V_pf_pooladdr_pl);
314 UMA_DESTROY(V_pf_frent_pl);
315 UMA_DESTROY(V_pf_frag_pl);
316 UMA_DESTROY(V_pf_cache_pl);
317 UMA_DESTROY(V_pf_cent_pl);
318 UMA_DESTROY(V_pfr_ktable_pl);
319 UMA_DESTROY(V_pfr_kentry_pl);
320 UMA_DESTROY(V_pfr_kcounters_pl);
321 UMA_DESTROY(V_pf_state_scrub_pl);
322 UMA_DESTROY(V_pfi_addr_pl);
323 }
324
325 int
pfattach(void)326 pfattach(void)
327 {
328 u_int32_t *my_timeout = V_pf_default_rule.timeout;
329 int error = 1;
330
331 do {
332 UMA_CREATE(V_pf_src_tree_pl, struct pf_src_node, "pfsrctrpl");
333 UMA_CREATE(V_pf_rule_pl, struct pf_rule, "pfrulepl");
334 UMA_CREATE(V_pf_state_pl, struct pf_state, "pfstatepl");
335 UMA_CREATE(V_pf_state_key_pl, struct pf_state, "pfstatekeypl");
336 UMA_CREATE(V_pf_state_item_pl, struct pf_state, "pfstateitempl");
337 UMA_CREATE(V_pf_altq_pl, struct pf_altq, "pfaltqpl");
338 UMA_CREATE(V_pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl");
339 UMA_CREATE(V_pfr_ktable_pl, struct pfr_ktable, "pfrktable");
340 UMA_CREATE(V_pfr_kentry_pl, struct pfr_kentry, "pfrkentry");
341 UMA_CREATE(V_pfr_kcounters_pl, struct pfr_kcounters, "pfrkcounters");
342 UMA_CREATE(V_pf_frent_pl, struct pf_frent, "pffrent");
343 UMA_CREATE(V_pf_frag_pl, struct pf_fragment, "pffrag");
344 UMA_CREATE(V_pf_cache_pl, struct pf_fragment, "pffrcache");
345 UMA_CREATE(V_pf_cent_pl, struct pf_frcache, "pffrcent");
346 UMA_CREATE(V_pf_state_scrub_pl, struct pf_state_scrub,
347 "pfstatescrub");
348 UMA_CREATE(V_pfi_addr_pl, struct pfi_dynaddr, "pfiaddrpl");
349 error = 0;
350 } while(0);
351 if (error) {
352 cleanup_pf_zone();
353 return (error);
354 }
355 pfr_initialize();
356 pfi_initialize();
357 if ( (error = pf_osfp_initialize()) ) {
358 cleanup_pf_zone();
359 pf_osfp_cleanup();
360 return (error);
361 }
362
363 V_pf_pool_limits[PF_LIMIT_STATES].pp = V_pf_state_pl;
364 V_pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT;
365 V_pf_pool_limits[PF_LIMIT_SRC_NODES].pp = V_pf_src_tree_pl;
366 V_pf_pool_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT;
367 V_pf_pool_limits[PF_LIMIT_FRAGS].pp = V_pf_frent_pl;
368 V_pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT;
369 V_pf_pool_limits[PF_LIMIT_TABLES].pp = V_pfr_ktable_pl;
370 V_pf_pool_limits[PF_LIMIT_TABLES].limit = PFR_KTABLE_HIWAT;
371 V_pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].pp = V_pfr_kentry_pl;
372 V_pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT;
373 uma_zone_set_max(V_pf_pool_limits[PF_LIMIT_STATES].pp,
374 V_pf_pool_limits[PF_LIMIT_STATES].limit);
375
376 RB_INIT(&V_tree_src_tracking);
377 RB_INIT(&V_pf_anchors);
378 pf_init_ruleset(&pf_main_ruleset);
379
380 TAILQ_INIT(&V_pf_altqs[0]);
381 TAILQ_INIT(&V_pf_altqs[1]);
382 TAILQ_INIT(&V_pf_pabuf);
383 V_pf_altqs_active = &V_pf_altqs[0];
384 V_pf_altqs_inactive = &V_pf_altqs[1];
385 TAILQ_INIT(&V_state_list);
386
387 /* default rule should never be garbage collected */
388 V_pf_default_rule.entries.tqe_prev = &V_pf_default_rule.entries.tqe_next;
389 V_pf_default_rule.action = PF_PASS;
390 V_pf_default_rule.nr = -1;
391 V_pf_default_rule.rtableid = -1;
392
393 /* initialize default timeouts */
394 my_timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
395 my_timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
396 my_timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
397 my_timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
398 my_timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
399 my_timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
400 my_timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
401 my_timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
402 my_timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
403 my_timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
404 my_timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
405 my_timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
406 my_timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
407 my_timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
408 my_timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
409 my_timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
410 my_timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
411 my_timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
412 my_timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
413 my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
414
415 pf_normalize_init();
416
417 bzero(&V_pf_status, sizeof(V_pf_status));
418 V_pf_status.debug = PF_DEBUG_URGENT;
419
420 V_pf_pfil_hooked = 0;
421
422 /* XXX do our best to avoid a conflict */
423 V_pf_status.hostid = arc4random();
424
425 if (kproc_create(pf_purge_thread, curvnet, NULL, 0, 0, "pfpurge"))
426 return (ENXIO);
427
428 m_addr_chg_pf_p = pf_pkt_addr_changed;
429
430 return (error);
431 }
432 #else /* !__FreeBSD__ */
433
434 void
pfattach(int num)435 pfattach(int num)
436 {
437 u_int32_t *timeout = pf_default_rule.timeout;
438
439 pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl",
440 &pool_allocator_nointr);
441 pool_init(&pf_src_tree_pl, sizeof(struct pf_src_node), 0, 0, 0,
442 "pfsrctrpl", NULL);
443 pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl",
444 NULL);
445 pool_init(&pf_state_key_pl, sizeof(struct pf_state_key), 0, 0, 0,
446 "pfstatekeypl", NULL);
447 pool_init(&pf_state_item_pl, sizeof(struct pf_state_item), 0, 0, 0,
448 "pfstateitempl", NULL);
449 pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl",
450 &pool_allocator_nointr);
451 pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0,
452 "pfpooladdrpl", &pool_allocator_nointr);
453 pfr_initialize();
454 pfi_initialize();
455 pf_osfp_initialize();
456
457 pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp,
458 pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0);
459
460 if (physmem <= atop(100*1024*1024))
461 pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit =
462 PFR_KENTRY_HIWAT_SMALL;
463
464 RB_INIT(&tree_src_tracking);
465 RB_INIT(&pf_anchors);
466 pf_init_ruleset(&pf_main_ruleset);
467 TAILQ_INIT(&pf_altqs[0]);
468 TAILQ_INIT(&pf_altqs[1]);
469 TAILQ_INIT(&pf_pabuf);
470 pf_altqs_active = &pf_altqs[0];
471 pf_altqs_inactive = &pf_altqs[1];
472 TAILQ_INIT(&state_list);
473
474 /* default rule should never be garbage collected */
475 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
476 pf_default_rule.action = PF_PASS;
477 pf_default_rule.nr = -1;
478 pf_default_rule.rtableid = -1;
479
480 /* initialize default timeouts */
481 timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
482 timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
483 timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
484 timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
485 timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
486 timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
487 timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
488 timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
489 timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
490 timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
491 timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
492 timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
493 timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
494 timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
495 timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
496 timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
497 timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
498 timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
499 timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
500 timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
501
502 pf_normalize_init();
503 bzero(&pf_status, sizeof(pf_status));
504 pf_status.debug = PF_DEBUG_URGENT;
505
506 /* XXX do our best to avoid a conflict */
507 pf_status.hostid = arc4random();
508
509 /* require process context to purge states, so perform in a thread */
510 kthread_create_deferred(pf_thread_create, NULL);
511 }
512
513 void
pf_thread_create(void * v)514 pf_thread_create(void *v)
515 {
516 if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge"))
517 panic("pfpurge thread");
518 }
519
520 int
pfopen(dev_t dev,int flags,int fmt,struct proc * p)521 pfopen(dev_t dev, int flags, int fmt, struct proc *p)
522 {
523 if (minor(dev) >= 1)
524 return (ENXIO);
525 return (0);
526 }
527
528 int
pfclose(dev_t dev,int flags,int fmt,struct proc * p)529 pfclose(dev_t dev, int flags, int fmt, struct proc *p)
530 {
531 if (minor(dev) >= 1)
532 return (ENXIO);
533 return (0);
534 }
535 #endif
536
537 struct pf_pool *
pf_get_pool(char * anchor,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)538 pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action,
539 u_int32_t rule_number, u_int8_t r_last, u_int8_t active,
540 u_int8_t check_ticket)
541 {
542 struct pf_ruleset *ruleset;
543 struct pf_rule *rule;
544 int rs_num;
545
546 ruleset = pf_find_ruleset(anchor);
547 if (ruleset == NULL)
548 return (NULL);
549 rs_num = pf_get_ruleset_number(rule_action);
550 if (rs_num >= PF_RULESET_MAX)
551 return (NULL);
552 if (active) {
553 if (check_ticket && ticket !=
554 ruleset->rules[rs_num].active.ticket)
555 return (NULL);
556 if (r_last)
557 rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
558 pf_rulequeue);
559 else
560 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
561 } else {
562 if (check_ticket && ticket !=
563 ruleset->rules[rs_num].inactive.ticket)
564 return (NULL);
565 if (r_last)
566 rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
567 pf_rulequeue);
568 else
569 rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
570 }
571 if (!r_last) {
572 while ((rule != NULL) && (rule->nr != rule_number))
573 rule = TAILQ_NEXT(rule, entries);
574 }
575 if (rule == NULL)
576 return (NULL);
577
578 return (&rule->rpool);
579 }
580
581 void
pf_mv_pool(struct pf_palist * poola,struct pf_palist * poolb)582 pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
583 {
584 struct pf_pooladdr *mv_pool_pa;
585
586 while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
587 TAILQ_REMOVE(poola, mv_pool_pa, entries);
588 TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
589 }
590 }
591
592 void
pf_empty_pool(struct pf_palist * poola)593 pf_empty_pool(struct pf_palist *poola)
594 {
595 struct pf_pooladdr *empty_pool_pa;
596
597 while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
598 pfi_dynaddr_remove(&empty_pool_pa->addr);
599 pf_tbladdr_remove(&empty_pool_pa->addr);
600 pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE);
601 TAILQ_REMOVE(poola, empty_pool_pa, entries);
602 #ifdef __FreeBSD__
603 pool_put(&V_pf_pooladdr_pl, empty_pool_pa);
604 #else
605 pool_put(&pf_pooladdr_pl, empty_pool_pa);
606 #endif
607 }
608 }
609
610 void
pf_rm_rule(struct pf_rulequeue * rulequeue,struct pf_rule * rule)611 pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
612 {
613 if (rulequeue != NULL) {
614 if (rule->states_cur <= 0) {
615 /*
616 * XXX - we need to remove the table *before* detaching
617 * the rule to make sure the table code does not delete
618 * the anchor under our feet.
619 */
620 pf_tbladdr_remove(&rule->src.addr);
621 pf_tbladdr_remove(&rule->dst.addr);
622 if (rule->overload_tbl)
623 pfr_detach_table(rule->overload_tbl);
624 }
625 TAILQ_REMOVE(rulequeue, rule, entries);
626 rule->entries.tqe_prev = NULL;
627 rule->nr = -1;
628 }
629
630 if (rule->states_cur > 0 || rule->src_nodes > 0 ||
631 rule->entries.tqe_prev != NULL)
632 return;
633 pf_tag_unref(rule->tag);
634 pf_tag_unref(rule->match_tag);
635 #ifdef ALTQ
636 if (rule->pqid != rule->qid)
637 pf_qid_unref(rule->pqid);
638 pf_qid_unref(rule->qid);
639 #endif
640 pf_rtlabel_remove(&rule->src.addr);
641 pf_rtlabel_remove(&rule->dst.addr);
642 pfi_dynaddr_remove(&rule->src.addr);
643 pfi_dynaddr_remove(&rule->dst.addr);
644 if (rulequeue == NULL) {
645 pf_tbladdr_remove(&rule->src.addr);
646 pf_tbladdr_remove(&rule->dst.addr);
647 if (rule->overload_tbl)
648 pfr_detach_table(rule->overload_tbl);
649 }
650 pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
651 pf_anchor_remove(rule);
652 pf_empty_pool(&rule->rpool.list);
653 #ifdef __FreeBSD__
654 pool_put(&V_pf_rule_pl, rule);
655 #else
656 pool_put(&pf_rule_pl, rule);
657 #endif
658 }
659
660 u_int16_t
tagname2tag(struct pf_tags * head,char * tagname)661 tagname2tag(struct pf_tags *head, char *tagname)
662 {
663 struct pf_tagname *tag, *p = NULL;
664 u_int16_t new_tagid = 1;
665
666 TAILQ_FOREACH(tag, head, entries)
667 if (strcmp(tagname, tag->name) == 0) {
668 tag->ref++;
669 return (tag->tag);
670 }
671
672 /*
673 * to avoid fragmentation, we do a linear search from the beginning
674 * and take the first free slot we find. if there is none or the list
675 * is empty, append a new entry at the end.
676 */
677
678 /* new entry */
679 if (!TAILQ_EMPTY(head))
680 for (p = TAILQ_FIRST(head); p != NULL &&
681 p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
682 new_tagid = p->tag + 1;
683
684 if (new_tagid > TAGID_MAX)
685 return (0);
686
687 /* allocate and fill new struct pf_tagname */
688 tag = malloc(sizeof(*tag), M_TEMP, M_NOWAIT|M_ZERO);
689 if (tag == NULL)
690 return (0);
691 strlcpy(tag->name, tagname, sizeof(tag->name));
692 tag->tag = new_tagid;
693 tag->ref++;
694
695 if (p != NULL) /* insert new entry before p */
696 TAILQ_INSERT_BEFORE(p, tag, entries);
697 else /* either list empty or no free slot in between */
698 TAILQ_INSERT_TAIL(head, tag, entries);
699
700 return (tag->tag);
701 }
702
703 void
tag2tagname(struct pf_tags * head,u_int16_t tagid,char * p)704 tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p)
705 {
706 struct pf_tagname *tag;
707
708 TAILQ_FOREACH(tag, head, entries)
709 if (tag->tag == tagid) {
710 strlcpy(p, tag->name, PF_TAG_NAME_SIZE);
711 return;
712 }
713 }
714
715 void
tag_unref(struct pf_tags * head,u_int16_t tag)716 tag_unref(struct pf_tags *head, u_int16_t tag)
717 {
718 struct pf_tagname *p, *next;
719
720 if (tag == 0)
721 return;
722
723 for (p = TAILQ_FIRST(head); p != NULL; p = next) {
724 next = TAILQ_NEXT(p, entries);
725 if (tag == p->tag) {
726 if (--p->ref == 0) {
727 TAILQ_REMOVE(head, p, entries);
728 free(p, M_TEMP);
729 }
730 break;
731 }
732 }
733 }
734
735 u_int16_t
pf_tagname2tag(char * tagname)736 pf_tagname2tag(char *tagname)
737 {
738 #ifdef __FreeBSD__
739 return (tagname2tag(&V_pf_tags, tagname));
740 #else
741 return (tagname2tag(&pf_tags, tagname));
742 #endif
743 }
744
745 void
pf_tag2tagname(u_int16_t tagid,char * p)746 pf_tag2tagname(u_int16_t tagid, char *p)
747 {
748 #ifdef __FreeBSD__
749 tag2tagname(&V_pf_tags, tagid, p);
750 #else
751 tag2tagname(&pf_tags, tagid, p);
752 #endif
753 }
754
755 void
pf_tag_ref(u_int16_t tag)756 pf_tag_ref(u_int16_t tag)
757 {
758 struct pf_tagname *t;
759
760 #ifdef __FreeBSD__
761 TAILQ_FOREACH(t, &V_pf_tags, entries)
762 #else
763 TAILQ_FOREACH(t, &pf_tags, entries)
764 #endif
765 if (t->tag == tag)
766 break;
767 if (t != NULL)
768 t->ref++;
769 }
770
771 void
pf_tag_unref(u_int16_t tag)772 pf_tag_unref(u_int16_t tag)
773 {
774 #ifdef __FreeBSD__
775 tag_unref(&V_pf_tags, tag);
776 #else
777 tag_unref(&pf_tags, tag);
778 #endif
779 }
780
781 int
pf_rtlabel_add(struct pf_addr_wrap * a)782 pf_rtlabel_add(struct pf_addr_wrap *a)
783 {
784 #ifdef __FreeBSD__
785 /* XXX_IMPORT: later */
786 return (0);
787 #else
788 if (a->type == PF_ADDR_RTLABEL &&
789 (a->v.rtlabel = rtlabel_name2id(a->v.rtlabelname)) == 0)
790 return (-1);
791 return (0);
792 #endif
793 }
794
795 void
pf_rtlabel_remove(struct pf_addr_wrap * a)796 pf_rtlabel_remove(struct pf_addr_wrap *a)
797 {
798 #ifdef __FreeBSD__
799 /* XXX_IMPORT: later */
800 #else
801 if (a->type == PF_ADDR_RTLABEL)
802 rtlabel_unref(a->v.rtlabel);
803 #endif
804 }
805
806 void
pf_rtlabel_copyout(struct pf_addr_wrap * a)807 pf_rtlabel_copyout(struct pf_addr_wrap *a)
808 {
809 #ifdef __FreeBSD__
810 /* XXX_IMPORT: later */
811 if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel)
812 strlcpy(a->v.rtlabelname, "?", sizeof(a->v.rtlabelname));
813 #else
814 const char *name;
815
816 if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) {
817 if ((name = rtlabel_id2name(a->v.rtlabel)) == NULL)
818 strlcpy(a->v.rtlabelname, "?",
819 sizeof(a->v.rtlabelname));
820 else
821 strlcpy(a->v.rtlabelname, name,
822 sizeof(a->v.rtlabelname));
823 }
824 #endif
825 }
826
827 #ifdef ALTQ
828 u_int32_t
pf_qname2qid(char * qname)829 pf_qname2qid(char *qname)
830 {
831 #ifdef __FreeBSD__
832 return ((u_int32_t)tagname2tag(&V_pf_qids, qname));
833 #else
834 return ((u_int32_t)tagname2tag(&pf_qids, qname));
835 #endif
836 }
837
838 void
pf_qid2qname(u_int32_t qid,char * p)839 pf_qid2qname(u_int32_t qid, char *p)
840 {
841 #ifdef __FreeBSD__
842 tag2tagname(&V_pf_qids, (u_int16_t)qid, p);
843 #else
844 tag2tagname(&pf_qids, (u_int16_t)qid, p);
845 #endif
846 }
847
848 void
pf_qid_unref(u_int32_t qid)849 pf_qid_unref(u_int32_t qid)
850 {
851 #ifdef __FreeBSD__
852 tag_unref(&V_pf_qids, (u_int16_t)qid);
853 #else
854 tag_unref(&pf_qids, (u_int16_t)qid);
855 #endif
856 }
857
858 int
pf_begin_altq(u_int32_t * ticket)859 pf_begin_altq(u_int32_t *ticket)
860 {
861 struct pf_altq *altq;
862 int error = 0;
863
864 /* Purge the old altq list */
865 #ifdef __FreeBSD__
866 while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) {
867 TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries);
868 if (altq->qname[0] == 0 &&
869 (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) {
870 #else
871 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
872 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
873 if (altq->qname[0] == 0) {
874 #endif
875 /* detach and destroy the discipline */
876 error = altq_remove(altq);
877 } else
878 pf_qid_unref(altq->qid);
879 #ifdef __FreeBSD__
880 pool_put(&V_pf_altq_pl, altq);
881 #else
882 pool_put(&pf_altq_pl, altq);
883 #endif
884 }
885 if (error)
886 return (error);
887 #ifdef __FreeBSD__
888 *ticket = ++V_ticket_altqs_inactive;
889 V_altqs_inactive_open = 1;
890 #else
891 *ticket = ++ticket_altqs_inactive;
892 altqs_inactive_open = 1;
893 #endif
894 return (0);
895 }
896
897 int
898 pf_rollback_altq(u_int32_t ticket)
899 {
900 struct pf_altq *altq;
901 int error = 0;
902
903 #ifdef __FreeBSD__
904 if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive)
905 return (0);
906 /* Purge the old altq list */
907 while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) {
908 TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries);
909 if (altq->qname[0] == 0 &&
910 (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) {
911 #else
912 if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
913 return (0);
914 /* Purge the old altq list */
915 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
916 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
917 if (altq->qname[0] == 0) {
918 #endif
919 /* detach and destroy the discipline */
920 error = altq_remove(altq);
921 } else
922 pf_qid_unref(altq->qid);
923 #ifdef __FreeBSD__
924 pool_put(&V_pf_altq_pl, altq);
925 #else
926 pool_put(&pf_altq_pl, altq);
927 #endif
928 }
929 #ifdef __FreeBSD__
930 V_altqs_inactive_open = 0;
931 #else
932 altqs_inactive_open = 0;
933 #endif
934 return (error);
935 }
936
937 int
938 pf_commit_altq(u_int32_t ticket)
939 {
940 struct pf_altqqueue *old_altqs;
941 struct pf_altq *altq;
942 int s, err, error = 0;
943
944 #ifdef __FreeBSD__
945 if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive)
946 #else
947 if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
948 #endif
949 return (EBUSY);
950
951 /* swap altqs, keep the old. */
952 s = splsoftnet();
953 #ifdef __FreeBSD__
954 old_altqs = V_pf_altqs_active;
955 V_pf_altqs_active = V_pf_altqs_inactive;
956 V_pf_altqs_inactive = old_altqs;
957 V_ticket_altqs_active = V_ticket_altqs_inactive;
958 #else
959 old_altqs = pf_altqs_active;
960 pf_altqs_active = pf_altqs_inactive;
961 pf_altqs_inactive = old_altqs;
962 ticket_altqs_active = ticket_altqs_inactive;
963 #endif
964
965 /* Attach new disciplines */
966 #ifdef __FreeBSD__
967 TAILQ_FOREACH(altq, V_pf_altqs_active, entries) {
968 if (altq->qname[0] == 0 &&
969 (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) {
970 #else
971 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
972 if (altq->qname[0] == 0) {
973 #endif
974 /* attach the discipline */
975 error = altq_pfattach(altq);
976 #ifdef __FreeBSD__
977 if (error == 0 && V_pf_altq_running)
978 #else
979 if (error == 0 && pf_altq_running)
980 #endif
981 error = pf_enable_altq(altq);
982 if (error != 0) {
983 splx(s);
984 return (error);
985 }
986 }
987 }
988
989 /* Purge the old altq list */
990 #ifdef __FreeBSD__
991 while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) {
992 TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries);
993 if (altq->qname[0] == 0 &&
994 (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) {
995 #else
996 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
997 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
998 if (altq->qname[0] == 0) {
999 #endif
1000 /* detach and destroy the discipline */
1001 #ifdef __FreeBSD__
1002 if (V_pf_altq_running)
1003 #else
1004 if (pf_altq_running)
1005 #endif
1006 error = pf_disable_altq(altq);
1007 err = altq_pfdetach(altq);
1008 if (err != 0 && error == 0)
1009 error = err;
1010 err = altq_remove(altq);
1011 if (err != 0 && error == 0)
1012 error = err;
1013 } else
1014 pf_qid_unref(altq->qid);
1015 #ifdef __FreeBSD__
1016 pool_put(&V_pf_altq_pl, altq);
1017 #else
1018 pool_put(&pf_altq_pl, altq);
1019 #endif
1020 }
1021 splx(s);
1022
1023 #ifdef __FreeBSD__
1024 V_altqs_inactive_open = 0;
1025 #else
1026 altqs_inactive_open = 0;
1027 #endif
1028 return (error);
1029 }
1030
1031 int
1032 pf_enable_altq(struct pf_altq *altq)
1033 {
1034 struct ifnet *ifp;
1035 struct tb_profile tb;
1036 int s, error = 0;
1037
1038 if ((ifp = ifunit(altq->ifname)) == NULL)
1039 return (EINVAL);
1040
1041 if (ifp->if_snd.altq_type != ALTQT_NONE)
1042 error = altq_enable(&ifp->if_snd);
1043
1044 /* set tokenbucket regulator */
1045 if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
1046 tb.rate = altq->ifbandwidth;
1047 tb.depth = altq->tbrsize;
1048 s = splnet();
1049 #ifdef __FreeBSD__
1050 PF_UNLOCK();
1051 #endif
1052 error = tbr_set(&ifp->if_snd, &tb);
1053 #ifdef __FreeBSD__
1054 PF_LOCK();
1055 #endif
1056 splx(s);
1057 }
1058
1059 return (error);
1060 }
1061
1062 int
1063 pf_disable_altq(struct pf_altq *altq)
1064 {
1065 struct ifnet *ifp;
1066 struct tb_profile tb;
1067 int s, error;
1068
1069 if ((ifp = ifunit(altq->ifname)) == NULL)
1070 return (EINVAL);
1071
1072 /*
1073 * when the discipline is no longer referenced, it was overridden
1074 * by a new one. if so, just return.
1075 */
1076 if (altq->altq_disc != ifp->if_snd.altq_disc)
1077 return (0);
1078
1079 error = altq_disable(&ifp->if_snd);
1080
1081 if (error == 0) {
1082 /* clear tokenbucket regulator */
1083 tb.rate = 0;
1084 s = splnet();
1085 #ifdef __FreeBSD__
1086 PF_UNLOCK();
1087 #endif
1088 error = tbr_set(&ifp->if_snd, &tb);
1089 #ifdef __FreeBSD__
1090 PF_LOCK();
1091 #endif
1092 splx(s);
1093 }
1094
1095 return (error);
1096 }
1097
1098 #ifdef __FreeBSD__
1099 void
1100 pf_altq_ifnet_event(struct ifnet *ifp, int remove)
1101 {
1102 struct ifnet *ifp1;
1103 struct pf_altq *a1, *a2, *a3;
1104 u_int32_t ticket;
1105 int error = 0;
1106
1107 /* Interrupt userland queue modifications */
1108 #ifdef __FreeBSD__
1109 if (V_altqs_inactive_open)
1110 pf_rollback_altq(V_ticket_altqs_inactive);
1111 #else
1112 if (altqs_inactive_open)
1113 pf_rollback_altq(ticket_altqs_inactive);
1114 #endif
1115
1116 /* Start new altq ruleset */
1117 if (pf_begin_altq(&ticket))
1118 return;
1119
1120 /* Copy the current active set */
1121 #ifdef __FreeBSD__
1122 TAILQ_FOREACH(a1, V_pf_altqs_active, entries) {
1123 a2 = pool_get(&V_pf_altq_pl, PR_NOWAIT);
1124 #else
1125 TAILQ_FOREACH(a1, pf_altqs_active, entries) {
1126 a2 = pool_get(&pf_altq_pl, PR_NOWAIT);
1127 #endif
1128 if (a2 == NULL) {
1129 error = ENOMEM;
1130 break;
1131 }
1132 bcopy(a1, a2, sizeof(struct pf_altq));
1133
1134 if (a2->qname[0] != 0) {
1135 if ((a2->qid = pf_qname2qid(a2->qname)) == 0) {
1136 error = EBUSY;
1137 #ifdef __FreeBSD__
1138 pool_put(&V_pf_altq_pl, a2);
1139 #else
1140 pool_put(&pf_altq_pl, a2);
1141 #endif
1142 break;
1143 }
1144 a2->altq_disc = NULL;
1145 #ifdef __FreeBSD__
1146 TAILQ_FOREACH(a3, V_pf_altqs_inactive, entries) {
1147 #else
1148 TAILQ_FOREACH(a3, pf_altqs_inactive, entries) {
1149 #endif
1150 if (strncmp(a3->ifname, a2->ifname,
1151 IFNAMSIZ) == 0 && a3->qname[0] == 0) {
1152 a2->altq_disc = a3->altq_disc;
1153 break;
1154 }
1155 }
1156 }
1157 /* Deactivate the interface in question */
1158 a2->local_flags &= ~PFALTQ_FLAG_IF_REMOVED;
1159 if ((ifp1 = ifunit(a2->ifname)) == NULL ||
1160 (remove && ifp1 == ifp)) {
1161 a2->local_flags |= PFALTQ_FLAG_IF_REMOVED;
1162 } else {
1163 PF_UNLOCK();
1164 error = altq_add(a2);
1165 PF_LOCK();
1166
1167 #ifdef __FreeBSD__
1168 if (ticket != V_ticket_altqs_inactive)
1169 #else
1170 if (ticket != ticket_altqs_inactive)
1171 #endif
1172 error = EBUSY;
1173
1174 if (error) {
1175 #ifdef __FreeBSD__
1176 pool_put(&V_pf_altq_pl, a2);
1177 #else
1178 pool_put(&pf_altq_pl, a2);
1179 #endif
1180 break;
1181 }
1182 }
1183
1184 #ifdef __FreeBSD__
1185 TAILQ_INSERT_TAIL(V_pf_altqs_inactive, a2, entries);
1186 #else
1187 TAILQ_INSERT_TAIL(pf_altqs_inactive, a2, entries);
1188 #endif
1189 }
1190
1191 if (error != 0)
1192 pf_rollback_altq(ticket);
1193 else
1194 pf_commit_altq(ticket);
1195 }
1196 #endif
1197 #endif /* ALTQ */
1198
1199 int
1200 pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor)
1201 {
1202 struct pf_ruleset *rs;
1203 struct pf_rule *rule;
1204
1205 if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
1206 return (EINVAL);
1207 rs = pf_find_or_create_ruleset(anchor);
1208 if (rs == NULL)
1209 return (EINVAL);
1210 while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
1211 pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
1212 rs->rules[rs_num].inactive.rcount--;
1213 }
1214 *ticket = ++rs->rules[rs_num].inactive.ticket;
1215 rs->rules[rs_num].inactive.open = 1;
1216 return (0);
1217 }
1218
1219 int
1220 pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor)
1221 {
1222 struct pf_ruleset *rs;
1223 struct pf_rule *rule;
1224
1225 if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
1226 return (EINVAL);
1227 rs = pf_find_ruleset(anchor);
1228 if (rs == NULL || !rs->rules[rs_num].inactive.open ||
1229 rs->rules[rs_num].inactive.ticket != ticket)
1230 return (0);
1231 while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
1232 pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
1233 rs->rules[rs_num].inactive.rcount--;
1234 }
1235 rs->rules[rs_num].inactive.open = 0;
1236 return (0);
1237 }
1238
1239 #define PF_MD5_UPD(st, elm) \
1240 MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm))
1241
1242 #define PF_MD5_UPD_STR(st, elm) \
1243 MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm))
1244
1245 #define PF_MD5_UPD_HTONL(st, elm, stor) do { \
1246 (stor) = htonl((st)->elm); \
1247 MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\
1248 } while (0)
1249
1250 #define PF_MD5_UPD_HTONS(st, elm, stor) do { \
1251 (stor) = htons((st)->elm); \
1252 MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\
1253 } while (0)
1254
1255 void
1256 pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr)
1257 {
1258 PF_MD5_UPD(pfr, addr.type);
1259 switch (pfr->addr.type) {
1260 case PF_ADDR_DYNIFTL:
1261 PF_MD5_UPD(pfr, addr.v.ifname);
1262 PF_MD5_UPD(pfr, addr.iflags);
1263 break;
1264 case PF_ADDR_TABLE:
1265 PF_MD5_UPD(pfr, addr.v.tblname);
1266 break;
1267 case PF_ADDR_ADDRMASK:
1268 /* XXX ignore af? */
1269 PF_MD5_UPD(pfr, addr.v.a.addr.addr32);
1270 PF_MD5_UPD(pfr, addr.v.a.mask.addr32);
1271 break;
1272 case PF_ADDR_RTLABEL:
1273 PF_MD5_UPD(pfr, addr.v.rtlabelname);
1274 break;
1275 }
1276
1277 PF_MD5_UPD(pfr, port[0]);
1278 PF_MD5_UPD(pfr, port[1]);
1279 PF_MD5_UPD(pfr, neg);
1280 PF_MD5_UPD(pfr, port_op);
1281 }
1282
1283 void
1284 pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule)
1285 {
1286 u_int16_t x;
1287 u_int32_t y;
1288
1289 pf_hash_rule_addr(ctx, &rule->src);
1290 pf_hash_rule_addr(ctx, &rule->dst);
1291 PF_MD5_UPD_STR(rule, label);
1292 PF_MD5_UPD_STR(rule, ifname);
1293 PF_MD5_UPD_STR(rule, match_tagname);
1294 PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
1295 PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
1296 PF_MD5_UPD_HTONL(rule, prob, y);
1297 PF_MD5_UPD_HTONL(rule, uid.uid[0], y);
1298 PF_MD5_UPD_HTONL(rule, uid.uid[1], y);
1299 PF_MD5_UPD(rule, uid.op);
1300 PF_MD5_UPD_HTONL(rule, gid.gid[0], y);
1301 PF_MD5_UPD_HTONL(rule, gid.gid[1], y);
1302 PF_MD5_UPD(rule, gid.op);
1303 PF_MD5_UPD_HTONL(rule, rule_flag, y);
1304 PF_MD5_UPD(rule, action);
1305 PF_MD5_UPD(rule, direction);
1306 PF_MD5_UPD(rule, af);
1307 PF_MD5_UPD(rule, quick);
1308 PF_MD5_UPD(rule, ifnot);
1309 PF_MD5_UPD(rule, match_tag_not);
1310 PF_MD5_UPD(rule, natpass);
1311 PF_MD5_UPD(rule, keep_state);
1312 PF_MD5_UPD(rule, proto);
1313 PF_MD5_UPD(rule, type);
1314 PF_MD5_UPD(rule, code);
1315 PF_MD5_UPD(rule, flags);
1316 PF_MD5_UPD(rule, flagset);
1317 PF_MD5_UPD(rule, allow_opts);
1318 PF_MD5_UPD(rule, rt);
1319 PF_MD5_UPD(rule, tos);
1320 }
1321
1322 int
1323 pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
1324 {
1325 struct pf_ruleset *rs;
1326 struct pf_rule *rule, **old_array;
1327 struct pf_rulequeue *old_rules;
1328 int s, error;
1329 u_int32_t old_rcount;
1330
1331 if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
1332 return (EINVAL);
1333 rs = pf_find_ruleset(anchor);
1334 if (rs == NULL || !rs->rules[rs_num].inactive.open ||
1335 ticket != rs->rules[rs_num].inactive.ticket)
1336 return (EBUSY);
1337
1338 /* Calculate checksum for the main ruleset */
1339 if (rs == &pf_main_ruleset) {
1340 error = pf_setup_pfsync_matching(rs);
1341 if (error != 0)
1342 return (error);
1343 }
1344
1345 /* Swap rules, keep the old. */
1346 s = splsoftnet();
1347 old_rules = rs->rules[rs_num].active.ptr;
1348 old_rcount = rs->rules[rs_num].active.rcount;
1349 old_array = rs->rules[rs_num].active.ptr_array;
1350
1351 rs->rules[rs_num].active.ptr =
1352 rs->rules[rs_num].inactive.ptr;
1353 rs->rules[rs_num].active.ptr_array =
1354 rs->rules[rs_num].inactive.ptr_array;
1355 rs->rules[rs_num].active.rcount =
1356 rs->rules[rs_num].inactive.rcount;
1357 rs->rules[rs_num].inactive.ptr = old_rules;
1358 rs->rules[rs_num].inactive.ptr_array = old_array;
1359 rs->rules[rs_num].inactive.rcount = old_rcount;
1360
1361 rs->rules[rs_num].active.ticket =
1362 rs->rules[rs_num].inactive.ticket;
1363 pf_calc_skip_steps(rs->rules[rs_num].active.ptr);
1364
1365
1366 /* Purge the old rule list. */
1367 while ((rule = TAILQ_FIRST(old_rules)) != NULL)
1368 pf_rm_rule(old_rules, rule);
1369 if (rs->rules[rs_num].inactive.ptr_array)
1370 free(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
1371 rs->rules[rs_num].inactive.ptr_array = NULL;
1372 rs->rules[rs_num].inactive.rcount = 0;
1373 rs->rules[rs_num].inactive.open = 0;
1374 pf_remove_if_empty_ruleset(rs);
1375 splx(s);
1376 return (0);
1377 }
1378
1379 int
1380 pf_setup_pfsync_matching(struct pf_ruleset *rs)
1381 {
1382 MD5_CTX ctx;
1383 struct pf_rule *rule;
1384 int rs_cnt;
1385 u_int8_t digest[PF_MD5_DIGEST_LENGTH];
1386
1387 MD5Init(&ctx);
1388 for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) {
1389 /* XXX PF_RULESET_SCRUB as well? */
1390 if (rs_cnt == PF_RULESET_SCRUB)
1391 continue;
1392
1393 if (rs->rules[rs_cnt].inactive.ptr_array)
1394 free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP);
1395 rs->rules[rs_cnt].inactive.ptr_array = NULL;
1396
1397 if (rs->rules[rs_cnt].inactive.rcount) {
1398 rs->rules[rs_cnt].inactive.ptr_array =
1399 malloc(sizeof(caddr_t) *
1400 rs->rules[rs_cnt].inactive.rcount,
1401 M_TEMP, M_NOWAIT);
1402
1403 if (!rs->rules[rs_cnt].inactive.ptr_array)
1404 return (ENOMEM);
1405 }
1406
1407 TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
1408 entries) {
1409 pf_hash_rule(&ctx, rule);
1410 (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
1411 }
1412 }
1413
1414 MD5Final(digest, &ctx);
1415 #ifdef __FreeBSD__
1416 memcpy(V_pf_status.pf_chksum, digest, sizeof(V_pf_status.pf_chksum));
1417 #else
1418 memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum));
1419 #endif
1420 return (0);
1421 }
1422
1423 int
1424 pf_addr_setup(struct pf_ruleset *ruleset, struct pf_addr_wrap *addr,
1425 sa_family_t af)
1426 {
1427 if (pfi_dynaddr_setup(addr, af) ||
1428 pf_tbladdr_setup(ruleset, addr))
1429 return (EINVAL);
1430
1431 return (0);
1432 }
1433
1434 void
1435 pf_addr_copyout(struct pf_addr_wrap *addr)
1436 {
1437 pfi_dynaddr_copyout(addr);
1438 pf_tbladdr_copyout(addr);
1439 pf_rtlabel_copyout(addr);
1440 }
1441
1442 int
1443 #ifdef __FreeBSD__
1444 pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
1445 #else
1446 pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
1447 #endif
1448 {
1449 struct pf_pooladdr *pa = NULL;
1450 struct pf_pool *pool = NULL;
1451 #ifndef __FreeBSD__
1452 int s;
1453 #endif
1454 int error = 0;
1455
1456 CURVNET_SET(TD_TO_VNET(td));
1457
1458 /* XXX keep in sync with switch() below */
1459 #ifdef __FreeBSD__
1460 if (securelevel_gt(td->td_ucred, 2))
1461 #else
1462 if (securelevel > 1)
1463 #endif
1464 switch (cmd) {
1465 case DIOCGETRULES:
1466 case DIOCGETRULE:
1467 case DIOCGETADDRS:
1468 case DIOCGETADDR:
1469 case DIOCGETSTATE:
1470 case DIOCSETSTATUSIF:
1471 case DIOCGETSTATUS:
1472 case DIOCCLRSTATUS:
1473 case DIOCNATLOOK:
1474 case DIOCSETDEBUG:
1475 case DIOCGETSTATES:
1476 case DIOCGETTIMEOUT:
1477 case DIOCCLRRULECTRS:
1478 case DIOCGETLIMIT:
1479 case DIOCGETALTQS:
1480 case DIOCGETALTQ:
1481 case DIOCGETQSTATS:
1482 case DIOCGETRULESETS:
1483 case DIOCGETRULESET:
1484 case DIOCRGETTABLES:
1485 case DIOCRGETTSTATS:
1486 case DIOCRCLRTSTATS:
1487 case DIOCRCLRADDRS:
1488 case DIOCRADDADDRS:
1489 case DIOCRDELADDRS:
1490 case DIOCRSETADDRS:
1491 case DIOCRGETADDRS:
1492 case DIOCRGETASTATS:
1493 case DIOCRCLRASTATS:
1494 case DIOCRTSTADDRS:
1495 case DIOCOSFPGET:
1496 case DIOCGETSRCNODES:
1497 case DIOCCLRSRCNODES:
1498 case DIOCIGETIFACES:
1499 #ifdef __FreeBSD__
1500 case DIOCGIFSPEED:
1501 #endif
1502 case DIOCSETIFFLAG:
1503 case DIOCCLRIFFLAG:
1504 break;
1505 case DIOCRCLRTABLES:
1506 case DIOCRADDTABLES:
1507 case DIOCRDELTABLES:
1508 case DIOCRSETTFLAGS:
1509 if (((struct pfioc_table *)addr)->pfrio_flags &
1510 PFR_FLAG_DUMMY)
1511 break; /* dummy operation ok */
1512 return (EPERM);
1513 default:
1514 return (EPERM);
1515 }
1516
1517 if (!(flags & FWRITE))
1518 switch (cmd) {
1519 case DIOCGETRULES:
1520 case DIOCGETADDRS:
1521 case DIOCGETADDR:
1522 case DIOCGETSTATE:
1523 case DIOCGETSTATUS:
1524 case DIOCGETSTATES:
1525 case DIOCGETTIMEOUT:
1526 case DIOCGETLIMIT:
1527 case DIOCGETALTQS:
1528 case DIOCGETALTQ:
1529 case DIOCGETQSTATS:
1530 case DIOCGETRULESETS:
1531 case DIOCGETRULESET:
1532 case DIOCNATLOOK:
1533 case DIOCRGETTABLES:
1534 case DIOCRGETTSTATS:
1535 case DIOCRGETADDRS:
1536 case DIOCRGETASTATS:
1537 case DIOCRTSTADDRS:
1538 case DIOCOSFPGET:
1539 case DIOCGETSRCNODES:
1540 case DIOCIGETIFACES:
1541 #ifdef __FreeBSD__
1542 case DIOCGIFSPEED:
1543 #endif
1544 break;
1545 case DIOCRCLRTABLES:
1546 case DIOCRADDTABLES:
1547 case DIOCRDELTABLES:
1548 case DIOCRCLRTSTATS:
1549 case DIOCRCLRADDRS:
1550 case DIOCRADDADDRS:
1551 case DIOCRDELADDRS:
1552 case DIOCRSETADDRS:
1553 case DIOCRSETTFLAGS:
1554 if (((struct pfioc_table *)addr)->pfrio_flags &
1555 PFR_FLAG_DUMMY) {
1556 flags |= FWRITE; /* need write lock for dummy */
1557 break; /* dummy operation ok */
1558 }
1559 return (EACCES);
1560 case DIOCGETRULE:
1561 if (((struct pfioc_rule *)addr)->action ==
1562 PF_GET_CLR_CNTR)
1563 return (EACCES);
1564 break;
1565 default:
1566 return (EACCES);
1567 }
1568
1569 if (flags & FWRITE)
1570 #ifdef __FreeBSD__
1571 sx_xlock(&V_pf_consistency_lock);
1572 else
1573 sx_slock(&V_pf_consistency_lock);
1574 #else
1575 rw_enter_write(&pf_consistency_lock);
1576 else
1577 rw_enter_read(&pf_consistency_lock);
1578 #endif
1579
1580 #ifdef __FreeBSD__
1581 PF_LOCK();
1582 #else
1583 s = splsoftnet();
1584 #endif
1585 switch (cmd) {
1586
1587 case DIOCSTART:
1588 #ifdef __FreeBSD__
1589 if (V_pf_status.running)
1590 #else
1591 if (pf_status.running)
1592 #endif
1593 error = EEXIST;
1594 else {
1595 #ifdef __FreeBSD__
1596 PF_UNLOCK();
1597 error = hook_pf();
1598 PF_LOCK();
1599 if (error) {
1600 DPFPRINTF(PF_DEBUG_MISC,
1601 ("pf: pfil registeration fail\n"));
1602 break;
1603 }
1604 V_pf_status.running = 1;
1605 V_pf_status.since = time_second;
1606
1607 if (V_pf_status.stateid == 0) {
1608 V_pf_status.stateid = time_second;
1609 V_pf_status.stateid = V_pf_status.stateid << 32;
1610 }
1611 #else
1612 pf_status.running = 1;
1613 pf_status.since = time_second;
1614
1615 if (pf_status.stateid == 0) {
1616 pf_status.stateid = time_second;
1617 pf_status.stateid = pf_status.stateid << 32;
1618 }
1619 #endif
1620 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
1621 }
1622 break;
1623
1624 case DIOCSTOP:
1625 #ifdef __FreeBSD__
1626 if (!V_pf_status.running)
1627 error = ENOENT;
1628 else {
1629 V_pf_status.running = 0;
1630 PF_UNLOCK();
1631 error = dehook_pf();
1632 PF_LOCK();
1633 if (error) {
1634 V_pf_status.running = 1;
1635 DPFPRINTF(PF_DEBUG_MISC,
1636 ("pf: pfil unregisteration failed\n"));
1637 }
1638 V_pf_status.since = time_second;
1639 #else
1640 if (!pf_status.running)
1641 error = ENOENT;
1642 else {
1643 pf_status.running = 0;
1644 pf_status.since = time_second;
1645 #endif
1646 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
1647 }
1648 break;
1649
1650 case DIOCADDRULE: {
1651 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
1652 struct pf_ruleset *ruleset;
1653 struct pf_rule *rule, *tail;
1654 struct pf_pooladdr *pa;
1655 int rs_num;
1656
1657 pr->anchor[sizeof(pr->anchor) - 1] = 0;
1658 ruleset = pf_find_ruleset(pr->anchor);
1659 if (ruleset == NULL) {
1660 error = EINVAL;
1661 break;
1662 }
1663 rs_num = pf_get_ruleset_number(pr->rule.action);
1664 if (rs_num >= PF_RULESET_MAX) {
1665 error = EINVAL;
1666 break;
1667 }
1668 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
1669 error = EINVAL;
1670 break;
1671 }
1672 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
1673 #ifdef __FreeBSD__
1674 DPFPRINTF(PF_DEBUG_MISC,
1675 ("ticket: %d != [%d]%d\n", pr->ticket, rs_num,
1676 ruleset->rules[rs_num].inactive.ticket));
1677 #endif
1678 error = EBUSY;
1679 break;
1680 }
1681 #ifdef __FreeBSD__
1682 if (pr->pool_ticket != V_ticket_pabuf) {
1683 DPFPRINTF(PF_DEBUG_MISC,
1684 ("pool_ticket: %d != %d\n", pr->pool_ticket,
1685 V_ticket_pabuf));
1686 #else
1687 if (pr->pool_ticket != ticket_pabuf) {
1688 #endif
1689 error = EBUSY;
1690 break;
1691 }
1692 #ifdef __FreeBSD__
1693 rule = pool_get(&V_pf_rule_pl, PR_NOWAIT);
1694 #else
1695 rule = pool_get(&pf_rule_pl, PR_WAITOK|PR_LIMITFAIL);
1696 #endif
1697 if (rule == NULL) {
1698 error = ENOMEM;
1699 break;
1700 }
1701 bcopy(&pr->rule, rule, sizeof(struct pf_rule));
1702 #ifdef __FreeBSD__
1703 rule->cuid = td->td_ucred->cr_ruid;
1704 rule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
1705 #else
1706 rule->cuid = p->p_cred->p_ruid;
1707 rule->cpid = p->p_pid;
1708 #endif
1709 rule->anchor = NULL;
1710 rule->kif = NULL;
1711 TAILQ_INIT(&rule->rpool.list);
1712 /* initialize refcounting */
1713 rule->states_cur = 0;
1714 rule->src_nodes = 0;
1715 rule->entries.tqe_prev = NULL;
1716 #ifndef INET
1717 if (rule->af == AF_INET) {
1718 #ifdef __FreeBSD__
1719 pool_put(&V_pf_rule_pl, rule);
1720 #else
1721 pool_put(&pf_rule_pl, rule);
1722 #endif
1723 error = EAFNOSUPPORT;
1724 break;
1725 }
1726 #endif /* INET */
1727 #ifndef INET6
1728 if (rule->af == AF_INET6) {
1729 #ifdef __FreeBSD__
1730 pool_put(&V_pf_rule_pl, rule);
1731 #else
1732 pool_put(&pf_rule_pl, rule);
1733 #endif
1734 error = EAFNOSUPPORT;
1735 break;
1736 }
1737 #endif /* INET6 */
1738 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
1739 pf_rulequeue);
1740 if (tail)
1741 rule->nr = tail->nr + 1;
1742 else
1743 rule->nr = 0;
1744 if (rule->ifname[0]) {
1745 rule->kif = pfi_kif_get(rule->ifname);
1746 if (rule->kif == NULL) {
1747 #ifdef __FreeBSD__
1748 pool_put(&V_pf_rule_pl, rule);
1749 #else
1750 pool_put(&pf_rule_pl, rule);
1751 #endif
1752 error = EINVAL;
1753 break;
1754 }
1755 pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE);
1756 }
1757
1758 #ifdef __FreeBSD__ /* ROUTING */
1759 if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs)
1760 #else
1761 if (rule->rtableid > 0 && !rtable_exists(rule->rtableid))
1762 #endif
1763 error = EBUSY;
1764
1765 #ifdef ALTQ
1766 /* set queue IDs */
1767 if (rule->qname[0] != 0) {
1768 if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
1769 error = EBUSY;
1770 else if (rule->pqname[0] != 0) {
1771 if ((rule->pqid =
1772 pf_qname2qid(rule->pqname)) == 0)
1773 error = EBUSY;
1774 } else
1775 rule->pqid = rule->qid;
1776 }
1777 #endif
1778 if (rule->tagname[0])
1779 if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
1780 error = EBUSY;
1781 if (rule->match_tagname[0])
1782 if ((rule->match_tag =
1783 pf_tagname2tag(rule->match_tagname)) == 0)
1784 error = EBUSY;
1785 if (rule->rt && !rule->direction)
1786 error = EINVAL;
1787 #if NPFLOG > 0
1788 if (!rule->log)
1789 rule->logif = 0;
1790 if (rule->logif >= PFLOGIFS_MAX)
1791 error = EINVAL;
1792 #endif
1793 if (pf_rtlabel_add(&rule->src.addr) ||
1794 pf_rtlabel_add(&rule->dst.addr))
1795 error = EBUSY;
1796 if (pf_addr_setup(ruleset, &rule->src.addr, rule->af))
1797 error = EINVAL;
1798 if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af))
1799 error = EINVAL;
1800 if (pf_anchor_setup(rule, ruleset, pr->anchor_call))
1801 error = EINVAL;
1802 #ifdef __FreeBSD__
1803 TAILQ_FOREACH(pa, &V_pf_pabuf, entries)
1804 #else
1805 TAILQ_FOREACH(pa, &pf_pabuf, entries)
1806 #endif
1807 if (pf_tbladdr_setup(ruleset, &pa->addr))
1808 error = EINVAL;
1809
1810 if (rule->overload_tblname[0]) {
1811 if ((rule->overload_tbl = pfr_attach_table(ruleset,
1812 rule->overload_tblname, 0)) == NULL)
1813 error = EINVAL;
1814 else
1815 rule->overload_tbl->pfrkt_flags |=
1816 PFR_TFLAG_ACTIVE;
1817 }
1818
1819 #ifdef __FreeBSD__
1820 pf_mv_pool(&V_pf_pabuf, &rule->rpool.list);
1821 #else
1822 pf_mv_pool(&pf_pabuf, &rule->rpool.list);
1823 #endif
1824 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
1825 (rule->action == PF_BINAT)) && rule->anchor == NULL) ||
1826 (rule->rt > PF_FASTROUTE)) &&
1827 (TAILQ_FIRST(&rule->rpool.list) == NULL))
1828 error = EINVAL;
1829
1830 if (error) {
1831 pf_rm_rule(NULL, rule);
1832 break;
1833 }
1834
1835 #ifdef __FreeBSD__
1836 if (!V_debug_pfugidhack && (rule->uid.op || rule->gid.op ||
1837 rule->log & PF_LOG_SOCKET_LOOKUP)) {
1838 DPFPRINTF(PF_DEBUG_MISC,
1839 ("pf: debug.pfugidhack enabled\n"));
1840 V_debug_pfugidhack = 1;
1841 }
1842 #endif
1843 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
1844 rule->evaluations = rule->packets[0] = rule->packets[1] =
1845 rule->bytes[0] = rule->bytes[1] = 0;
1846 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
1847 rule, entries);
1848 ruleset->rules[rs_num].inactive.rcount++;
1849 break;
1850 }
1851
1852 case DIOCGETRULES: {
1853 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
1854 struct pf_ruleset *ruleset;
1855 struct pf_rule *tail;
1856 int rs_num;
1857
1858 pr->anchor[sizeof(pr->anchor) - 1] = 0;
1859 ruleset = pf_find_ruleset(pr->anchor);
1860 if (ruleset == NULL) {
1861 error = EINVAL;
1862 break;
1863 }
1864 rs_num = pf_get_ruleset_number(pr->rule.action);
1865 if (rs_num >= PF_RULESET_MAX) {
1866 error = EINVAL;
1867 break;
1868 }
1869 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
1870 pf_rulequeue);
1871 if (tail)
1872 pr->nr = tail->nr + 1;
1873 else
1874 pr->nr = 0;
1875 pr->ticket = ruleset->rules[rs_num].active.ticket;
1876 break;
1877 }
1878
1879 case DIOCGETRULE: {
1880 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
1881 struct pf_ruleset *ruleset;
1882 struct pf_rule *rule;
1883 int rs_num, i;
1884
1885 pr->anchor[sizeof(pr->anchor) - 1] = 0;
1886 ruleset = pf_find_ruleset(pr->anchor);
1887 if (ruleset == NULL) {
1888 error = EINVAL;
1889 break;
1890 }
1891 rs_num = pf_get_ruleset_number(pr->rule.action);
1892 if (rs_num >= PF_RULESET_MAX) {
1893 error = EINVAL;
1894 break;
1895 }
1896 if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
1897 error = EBUSY;
1898 break;
1899 }
1900 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
1901 while ((rule != NULL) && (rule->nr != pr->nr))
1902 rule = TAILQ_NEXT(rule, entries);
1903 if (rule == NULL) {
1904 error = EBUSY;
1905 break;
1906 }
1907 bcopy(rule, &pr->rule, sizeof(struct pf_rule));
1908 if (pf_anchor_copyout(ruleset, rule, pr)) {
1909 error = EBUSY;
1910 break;
1911 }
1912 pf_addr_copyout(&pr->rule.src.addr);
1913 pf_addr_copyout(&pr->rule.dst.addr);
1914 for (i = 0; i < PF_SKIP_COUNT; ++i)
1915 if (rule->skip[i].ptr == NULL)
1916 pr->rule.skip[i].nr = -1;
1917 else
1918 pr->rule.skip[i].nr =
1919 rule->skip[i].ptr->nr;
1920
1921 if (pr->action == PF_GET_CLR_CNTR) {
1922 rule->evaluations = 0;
1923 rule->packets[0] = rule->packets[1] = 0;
1924 rule->bytes[0] = rule->bytes[1] = 0;
1925 rule->states_tot = 0;
1926 }
1927 break;
1928 }
1929
1930 case DIOCCHANGERULE: {
1931 struct pfioc_rule *pcr = (struct pfioc_rule *)addr;
1932 struct pf_ruleset *ruleset;
1933 struct pf_rule *oldrule = NULL, *newrule = NULL;
1934 u_int32_t nr = 0;
1935 int rs_num;
1936
1937 if (!(pcr->action == PF_CHANGE_REMOVE ||
1938 pcr->action == PF_CHANGE_GET_TICKET) &&
1939 #ifdef __FreeBSD__
1940 pcr->pool_ticket != V_ticket_pabuf) {
1941 #else
1942 pcr->pool_ticket != ticket_pabuf) {
1943 #endif
1944 error = EBUSY;
1945 break;
1946 }
1947
1948 if (pcr->action < PF_CHANGE_ADD_HEAD ||
1949 pcr->action > PF_CHANGE_GET_TICKET) {
1950 error = EINVAL;
1951 break;
1952 }
1953 ruleset = pf_find_ruleset(pcr->anchor);
1954 if (ruleset == NULL) {
1955 error = EINVAL;
1956 break;
1957 }
1958 rs_num = pf_get_ruleset_number(pcr->rule.action);
1959 if (rs_num >= PF_RULESET_MAX) {
1960 error = EINVAL;
1961 break;
1962 }
1963
1964 if (pcr->action == PF_CHANGE_GET_TICKET) {
1965 pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
1966 break;
1967 } else {
1968 if (pcr->ticket !=
1969 ruleset->rules[rs_num].active.ticket) {
1970 error = EINVAL;
1971 break;
1972 }
1973 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
1974 error = EINVAL;
1975 break;
1976 }
1977 }
1978
1979 if (pcr->action != PF_CHANGE_REMOVE) {
1980 #ifdef __FreeBSD__
1981 newrule = pool_get(&V_pf_rule_pl, PR_NOWAIT);
1982 #else
1983 newrule = pool_get(&pf_rule_pl, PR_WAITOK|PR_LIMITFAIL);
1984 #endif
1985 if (newrule == NULL) {
1986 error = ENOMEM;
1987 break;
1988 }
1989 bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
1990 #ifdef __FreeBSD__
1991 newrule->cuid = td->td_ucred->cr_ruid;
1992 newrule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
1993 #else
1994 newrule->cuid = p->p_cred->p_ruid;
1995 newrule->cpid = p->p_pid;
1996 #endif
1997 TAILQ_INIT(&newrule->rpool.list);
1998 /* initialize refcounting */
1999 newrule->states_cur = 0;
2000 newrule->entries.tqe_prev = NULL;
2001 #ifndef INET
2002 if (newrule->af == AF_INET) {
2003 #ifdef __FreeBSD__
2004 pool_put(&V_pf_rule_pl, newrule);
2005 #else
2006 pool_put(&pf_rule_pl, newrule);
2007 #endif
2008 error = EAFNOSUPPORT;
2009 break;
2010 }
2011 #endif /* INET */
2012 #ifndef INET6
2013 if (newrule->af == AF_INET6) {
2014 #ifdef __FreeBSD__
2015 pool_put(&V_pf_rule_pl, newrule);
2016 #else
2017 pool_put(&pf_rule_pl, newrule);
2018 #endif
2019 error = EAFNOSUPPORT;
2020 break;
2021 }
2022 #endif /* INET6 */
2023 if (newrule->ifname[0]) {
2024 newrule->kif = pfi_kif_get(newrule->ifname);
2025 if (newrule->kif == NULL) {
2026 #ifdef __FreeBSD__
2027 pool_put(&V_pf_rule_pl, newrule);
2028 #else
2029 pool_put(&pf_rule_pl, newrule);
2030 #endif
2031 error = EINVAL;
2032 break;
2033 }
2034 pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE);
2035 } else
2036 newrule->kif = NULL;
2037
2038 if (newrule->rtableid > 0 &&
2039 #ifdef __FreeBSD__ /* ROUTING */
2040 newrule->rtableid >= rt_numfibs)
2041 #else
2042 !rtable_exists(newrule->rtableid))
2043 #endif
2044 error = EBUSY;
2045
2046 #ifdef ALTQ
2047 /* set queue IDs */
2048 if (newrule->qname[0] != 0) {
2049 if ((newrule->qid =
2050 pf_qname2qid(newrule->qname)) == 0)
2051 error = EBUSY;
2052 else if (newrule->pqname[0] != 0) {
2053 if ((newrule->pqid =
2054 pf_qname2qid(newrule->pqname)) == 0)
2055 error = EBUSY;
2056 } else
2057 newrule->pqid = newrule->qid;
2058 }
2059 #endif /* ALTQ */
2060 if (newrule->tagname[0])
2061 if ((newrule->tag =
2062 pf_tagname2tag(newrule->tagname)) == 0)
2063 error = EBUSY;
2064 if (newrule->match_tagname[0])
2065 if ((newrule->match_tag = pf_tagname2tag(
2066 newrule->match_tagname)) == 0)
2067 error = EBUSY;
2068 if (newrule->rt && !newrule->direction)
2069 error = EINVAL;
2070 #if NPFLOG > 0
2071 if (!newrule->log)
2072 newrule->logif = 0;
2073 if (newrule->logif >= PFLOGIFS_MAX)
2074 error = EINVAL;
2075 #endif
2076 if (pf_rtlabel_add(&newrule->src.addr) ||
2077 pf_rtlabel_add(&newrule->dst.addr))
2078 error = EBUSY;
2079 if (pf_addr_setup(ruleset, &newrule->src.addr, newrule->af))
2080 error = EINVAL;
2081 if (pf_addr_setup(ruleset, &newrule->dst.addr, newrule->af))
2082 error = EINVAL;
2083 if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call))
2084 error = EINVAL;
2085 #ifdef __FreeBSD__
2086 TAILQ_FOREACH(pa, &V_pf_pabuf, entries)
2087 #else
2088 TAILQ_FOREACH(pa, &pf_pabuf, entries)
2089 #endif
2090 if (pf_tbladdr_setup(ruleset, &pa->addr))
2091 error = EINVAL;
2092
2093 if (newrule->overload_tblname[0]) {
2094 if ((newrule->overload_tbl = pfr_attach_table(
2095 ruleset, newrule->overload_tblname, 0)) ==
2096 NULL)
2097 error = EINVAL;
2098 else
2099 newrule->overload_tbl->pfrkt_flags |=
2100 PFR_TFLAG_ACTIVE;
2101 }
2102
2103 #ifdef __FreeBSD__
2104 pf_mv_pool(&V_pf_pabuf, &newrule->rpool.list);
2105 #else
2106 pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
2107 #endif
2108 if (((((newrule->action == PF_NAT) ||
2109 (newrule->action == PF_RDR) ||
2110 (newrule->action == PF_BINAT) ||
2111 (newrule->rt > PF_FASTROUTE)) &&
2112 !newrule->anchor)) &&
2113 (TAILQ_FIRST(&newrule->rpool.list) == NULL))
2114 error = EINVAL;
2115
2116 if (error) {
2117 pf_rm_rule(NULL, newrule);
2118 break;
2119 }
2120
2121 #ifdef __FreeBSD__
2122 if (!V_debug_pfugidhack && (newrule->uid.op ||
2123 newrule->gid.op ||
2124 newrule->log & PF_LOG_SOCKET_LOOKUP)) {
2125 DPFPRINTF(PF_DEBUG_MISC,
2126 ("pf: debug.pfugidhack enabled\n"));
2127 V_debug_pfugidhack = 1;
2128 }
2129 #endif
2130
2131 newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
2132 newrule->evaluations = 0;
2133 newrule->packets[0] = newrule->packets[1] = 0;
2134 newrule->bytes[0] = newrule->bytes[1] = 0;
2135 }
2136 #ifdef __FreeBSD__
2137 pf_empty_pool(&V_pf_pabuf);
2138 #else
2139 pf_empty_pool(&pf_pabuf);
2140 #endif
2141
2142 if (pcr->action == PF_CHANGE_ADD_HEAD)
2143 oldrule = TAILQ_FIRST(
2144 ruleset->rules[rs_num].active.ptr);
2145 else if (pcr->action == PF_CHANGE_ADD_TAIL)
2146 oldrule = TAILQ_LAST(
2147 ruleset->rules[rs_num].active.ptr, pf_rulequeue);
2148 else {
2149 oldrule = TAILQ_FIRST(
2150 ruleset->rules[rs_num].active.ptr);
2151 while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
2152 oldrule = TAILQ_NEXT(oldrule, entries);
2153 if (oldrule == NULL) {
2154 if (newrule != NULL)
2155 pf_rm_rule(NULL, newrule);
2156 error = EINVAL;
2157 break;
2158 }
2159 }
2160
2161 if (pcr->action == PF_CHANGE_REMOVE) {
2162 pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
2163 ruleset->rules[rs_num].active.rcount--;
2164 } else {
2165 if (oldrule == NULL)
2166 TAILQ_INSERT_TAIL(
2167 ruleset->rules[rs_num].active.ptr,
2168 newrule, entries);
2169 else if (pcr->action == PF_CHANGE_ADD_HEAD ||
2170 pcr->action == PF_CHANGE_ADD_BEFORE)
2171 TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
2172 else
2173 TAILQ_INSERT_AFTER(
2174 ruleset->rules[rs_num].active.ptr,
2175 oldrule, newrule, entries);
2176 ruleset->rules[rs_num].active.rcount++;
2177 }
2178
2179 nr = 0;
2180 TAILQ_FOREACH(oldrule,
2181 ruleset->rules[rs_num].active.ptr, entries)
2182 oldrule->nr = nr++;
2183
2184 ruleset->rules[rs_num].active.ticket++;
2185
2186 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
2187 pf_remove_if_empty_ruleset(ruleset);
2188
2189 break;
2190 }
2191
2192 case DIOCCLRSTATES: {
2193 struct pf_state *s, *nexts;
2194 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
2195 u_int killed = 0;
2196
2197 #ifdef __FreeBSD__
2198 for (s = RB_MIN(pf_state_tree_id, &V_tree_id); s; s = nexts) {
2199 nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, s);
2200 #else
2201 for (s = RB_MIN(pf_state_tree_id, &tree_id); s; s = nexts) {
2202 nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
2203 #endif
2204
2205 if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
2206 s->kif->pfik_name)) {
2207 #if NPFSYNC > 0
2208 /* don't send out individual delete messages */
2209 SET(s->state_flags, PFSTATE_NOSYNC);
2210 #endif
2211 pf_unlink_state(s);
2212 killed++;
2213 }
2214 }
2215 psk->psk_killed = killed;
2216 #if NPFSYNC > 0
2217 #ifdef __FreeBSD__
2218 if (pfsync_clear_states_ptr != NULL)
2219 pfsync_clear_states_ptr(V_pf_status.hostid, psk->psk_ifname);
2220 #else
2221 pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
2222 #endif
2223 #endif
2224 break;
2225 }
2226
2227 case DIOCKILLSTATES: {
2228 struct pf_state *s, *nexts;
2229 struct pf_state_key *sk;
2230 struct pf_addr *srcaddr, *dstaddr;
2231 u_int16_t srcport, dstport;
2232 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
2233 u_int killed = 0;
2234
2235 if (psk->psk_pfcmp.id) {
2236 if (psk->psk_pfcmp.creatorid == 0)
2237 #ifdef __FreeBSD__
2238 psk->psk_pfcmp.creatorid = V_pf_status.hostid;
2239 #else
2240 psk->psk_pfcmp.creatorid = pf_status.hostid;
2241 #endif
2242 if ((s = pf_find_state_byid(&psk->psk_pfcmp))) {
2243 pf_unlink_state(s);
2244 psk->psk_killed = 1;
2245 }
2246 break;
2247 }
2248
2249 #ifdef __FreeBSD__
2250 for (s = RB_MIN(pf_state_tree_id, &V_tree_id); s;
2251 s = nexts) {
2252 nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, s);
2253 #else
2254 for (s = RB_MIN(pf_state_tree_id, &tree_id); s;
2255 s = nexts) {
2256 nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
2257 #endif
2258 sk = s->key[PF_SK_WIRE];
2259
2260 if (s->direction == PF_OUT) {
2261 srcaddr = &sk->addr[1];
2262 dstaddr = &sk->addr[0];
2263 srcport = sk->port[0];
2264 dstport = sk->port[0];
2265 } else {
2266 srcaddr = &sk->addr[0];
2267 dstaddr = &sk->addr[1];
2268 srcport = sk->port[0];
2269 dstport = sk->port[0];
2270 }
2271 if ((!psk->psk_af || sk->af == psk->psk_af)
2272 && (!psk->psk_proto || psk->psk_proto ==
2273 sk->proto) &&
2274 PF_MATCHA(psk->psk_src.neg,
2275 &psk->psk_src.addr.v.a.addr,
2276 &psk->psk_src.addr.v.a.mask,
2277 srcaddr, sk->af) &&
2278 PF_MATCHA(psk->psk_dst.neg,
2279 &psk->psk_dst.addr.v.a.addr,
2280 &psk->psk_dst.addr.v.a.mask,
2281 dstaddr, sk->af) &&
2282 (psk->psk_src.port_op == 0 ||
2283 pf_match_port(psk->psk_src.port_op,
2284 psk->psk_src.port[0], psk->psk_src.port[1],
2285 srcport)) &&
2286 (psk->psk_dst.port_op == 0 ||
2287 pf_match_port(psk->psk_dst.port_op,
2288 psk->psk_dst.port[0], psk->psk_dst.port[1],
2289 dstport)) &&
2290 (!psk->psk_label[0] || (s->rule.ptr->label[0] &&
2291 !strcmp(psk->psk_label, s->rule.ptr->label))) &&
2292 (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
2293 s->kif->pfik_name))) {
2294 pf_unlink_state(s);
2295 killed++;
2296 }
2297 }
2298 psk->psk_killed = killed;
2299 break;
2300 }
2301
2302 case DIOCADDSTATE: {
2303 struct pfioc_state *ps = (struct pfioc_state *)addr;
2304 struct pfsync_state *sp = &ps->state;
2305
2306 if (sp->timeout >= PFTM_MAX &&
2307 sp->timeout != PFTM_UNTIL_PACKET) {
2308 error = EINVAL;
2309 break;
2310 }
2311 #ifdef __FreeBSD__
2312 if (pfsync_state_import_ptr != NULL)
2313 error = pfsync_state_import_ptr(sp, PFSYNC_SI_IOCTL);
2314 #else
2315 error = pfsync_state_import(sp, PFSYNC_SI_IOCTL);
2316 #endif
2317 break;
2318 }
2319
2320 case DIOCGETSTATE: {
2321 struct pfioc_state *ps = (struct pfioc_state *)addr;
2322 struct pf_state *s;
2323 struct pf_state_cmp id_key;
2324
2325 bcopy(ps->state.id, &id_key.id, sizeof(id_key.id));
2326 id_key.creatorid = ps->state.creatorid;
2327
2328 s = pf_find_state_byid(&id_key);
2329 if (s == NULL) {
2330 error = ENOENT;
2331 break;
2332 }
2333
2334 pfsync_state_export(&ps->state, s);
2335 break;
2336 }
2337
2338 case DIOCGETSTATES: {
2339 struct pfioc_states *ps = (struct pfioc_states *)addr;
2340 struct pf_state *state;
2341 struct pfsync_state *p, *pstore;
2342 u_int32_t nr = 0;
2343
2344 if (ps->ps_len == 0) {
2345 #ifdef __FreeBSD__
2346 nr = V_pf_status.states;
2347 #else
2348 nr = pf_status.states;
2349 #endif
2350 ps->ps_len = sizeof(struct pfsync_state) * nr;
2351 break;
2352 }
2353
2354 #ifdef __FreeBSD__
2355 PF_UNLOCK();
2356 #endif
2357 pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK);
2358 #ifdef __FreeBSD__
2359 PF_LOCK();
2360 #endif
2361
2362 p = ps->ps_states;
2363
2364 #ifdef __FreeBSD__
2365 state = TAILQ_FIRST(&V_state_list);
2366 #else
2367 state = TAILQ_FIRST(&state_list);
2368 #endif
2369 while (state) {
2370 if (state->timeout != PFTM_UNLINKED) {
2371 if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len)
2372 break;
2373 pfsync_state_export(pstore, state);
2374 #ifdef __FreeBSD__
2375 PF_COPYOUT(pstore, p, sizeof(*p), error);
2376 #else
2377 error = copyout(pstore, p, sizeof(*p));
2378 #endif
2379 if (error) {
2380 free(pstore, M_TEMP);
2381 goto fail;
2382 }
2383 p++;
2384 nr++;
2385 }
2386 state = TAILQ_NEXT(state, entry_list);
2387 }
2388
2389 ps->ps_len = sizeof(struct pfsync_state) * nr;
2390
2391 free(pstore, M_TEMP);
2392 break;
2393 }
2394
2395 case DIOCGETSTATUS: {
2396 struct pf_status *s = (struct pf_status *)addr;
2397 #ifdef __FreeBSD__
2398 bcopy(&V_pf_status, s, sizeof(struct pf_status));
2399 #else
2400 bcopy(&pf_status, s, sizeof(struct pf_status));
2401 #endif
2402 pfi_update_status(s->ifname, s);
2403 break;
2404 }
2405
2406 case DIOCSETSTATUSIF: {
2407 struct pfioc_if *pi = (struct pfioc_if *)addr;
2408
2409 if (pi->ifname[0] == 0) {
2410 #ifdef __FreeBSD__
2411 bzero(V_pf_status.ifname, IFNAMSIZ);
2412 #else
2413 bzero(pf_status.ifname, IFNAMSIZ);
2414 #endif
2415 break;
2416 }
2417 #ifdef __FreeBSD__
2418 strlcpy(V_pf_status.ifname, pi->ifname, IFNAMSIZ);
2419 #else
2420 strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ);
2421 #endif
2422 break;
2423 }
2424
2425 case DIOCCLRSTATUS: {
2426 #ifdef __FreeBSD__
2427 bzero(V_pf_status.counters, sizeof(V_pf_status.counters));
2428 bzero(V_pf_status.fcounters, sizeof(V_pf_status.fcounters));
2429 bzero(V_pf_status.scounters, sizeof(V_pf_status.scounters));
2430 V_pf_status.since = time_second;
2431 if (*V_pf_status.ifname)
2432 pfi_update_status(V_pf_status.ifname, NULL);
2433 #else
2434 bzero(pf_status.counters, sizeof(pf_status.counters));
2435 bzero(pf_status.fcounters, sizeof(pf_status.fcounters));
2436 bzero(pf_status.scounters, sizeof(pf_status.scounters));
2437 pf_status.since = time_second;
2438 if (*pf_status.ifname)
2439 pfi_update_status(pf_status.ifname, NULL);
2440 #endif
2441 break;
2442 }
2443
2444 case DIOCNATLOOK: {
2445 struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr;
2446 struct pf_state_key *sk;
2447 struct pf_state *state;
2448 struct pf_state_key_cmp key;
2449 int m = 0, direction = pnl->direction;
2450 int sidx, didx;
2451
2452 /* NATLOOK src and dst are reversed, so reverse sidx/didx */
2453 sidx = (direction == PF_IN) ? 1 : 0;
2454 didx = (direction == PF_IN) ? 0 : 1;
2455
2456 if (!pnl->proto ||
2457 PF_AZERO(&pnl->saddr, pnl->af) ||
2458 PF_AZERO(&pnl->daddr, pnl->af) ||
2459 ((pnl->proto == IPPROTO_TCP ||
2460 pnl->proto == IPPROTO_UDP) &&
2461 (!pnl->dport || !pnl->sport)))
2462 error = EINVAL;
2463 else {
2464 key.af = pnl->af;
2465 key.proto = pnl->proto;
2466 PF_ACPY(&key.addr[sidx], &pnl->saddr, pnl->af);
2467 key.port[sidx] = pnl->sport;
2468 PF_ACPY(&key.addr[didx], &pnl->daddr, pnl->af);
2469 key.port[didx] = pnl->dport;
2470
2471 state = pf_find_state_all(&key, direction, &m);
2472
2473 if (m > 1)
2474 error = E2BIG; /* more than one state */
2475 else if (state != NULL) {
2476 sk = state->key[sidx];
2477 PF_ACPY(&pnl->rsaddr, &sk->addr[sidx], sk->af);
2478 pnl->rsport = sk->port[sidx];
2479 PF_ACPY(&pnl->rdaddr, &sk->addr[didx], sk->af);
2480 pnl->rdport = sk->port[didx];
2481 } else
2482 error = ENOENT;
2483 }
2484 break;
2485 }
2486
2487 case DIOCSETTIMEOUT: {
2488 struct pfioc_tm *pt = (struct pfioc_tm *)addr;
2489 int old;
2490
2491 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
2492 pt->seconds < 0) {
2493 error = EINVAL;
2494 goto fail;
2495 }
2496 #ifdef __FreeBSD__
2497 old = V_pf_default_rule.timeout[pt->timeout];
2498 #else
2499 old = pf_default_rule.timeout[pt->timeout];
2500 #endif
2501 if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0)
2502 pt->seconds = 1;
2503 #ifdef __FreeBSD__
2504 V_pf_default_rule.timeout[pt->timeout] = pt->seconds;
2505 #else
2506 pf_default_rule.timeout[pt->timeout] = pt->seconds;
2507 #endif
2508 if (pt->timeout == PFTM_INTERVAL && pt->seconds < old)
2509 wakeup(pf_purge_thread);
2510 pt->seconds = old;
2511 break;
2512 }
2513
2514 case DIOCGETTIMEOUT: {
2515 struct pfioc_tm *pt = (struct pfioc_tm *)addr;
2516
2517 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
2518 error = EINVAL;
2519 goto fail;
2520 }
2521 #ifdef __FreeBSD__
2522 pt->seconds = V_pf_default_rule.timeout[pt->timeout];
2523 #else
2524 pt->seconds = pf_default_rule.timeout[pt->timeout];
2525 #endif
2526 break;
2527 }
2528
2529 case DIOCGETLIMIT: {
2530 struct pfioc_limit *pl = (struct pfioc_limit *)addr;
2531
2532 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
2533 error = EINVAL;
2534 goto fail;
2535 }
2536 #ifdef __FreeBSD__
2537 pl->limit = V_pf_pool_limits[pl->index].limit;
2538 #else
2539 pl->limit = pf_pool_limits[pl->index].limit;
2540 #endif
2541 break;
2542 }
2543
2544 case DIOCSETLIMIT: {
2545 struct pfioc_limit *pl = (struct pfioc_limit *)addr;
2546 int old_limit;
2547
2548 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX ||
2549 #ifdef __FreeBSD__
2550 V_pf_pool_limits[pl->index].pp == NULL) {
2551 #else
2552 pf_pool_limits[pl->index].pp == NULL) {
2553 #endif
2554 error = EINVAL;
2555 goto fail;
2556 }
2557 #ifdef __FreeBSD__
2558 uma_zone_set_max(V_pf_pool_limits[pl->index].pp, pl->limit);
2559 old_limit = V_pf_pool_limits[pl->index].limit;
2560 V_pf_pool_limits[pl->index].limit = pl->limit;
2561 pl->limit = old_limit;
2562 #else
2563 if (pool_sethardlimit(pf_pool_limits[pl->index].pp,
2564 pl->limit, NULL, 0) != 0) {
2565 error = EBUSY;
2566 goto fail;
2567 }
2568 old_limit = pf_pool_limits[pl->index].limit;
2569 pf_pool_limits[pl->index].limit = pl->limit;
2570 pl->limit = old_limit;
2571 #endif
2572 break;
2573 }
2574
2575 case DIOCSETDEBUG: {
2576 u_int32_t *level = (u_int32_t *)addr;
2577
2578 #ifdef __FreeBSD__
2579 V_pf_status.debug = *level;
2580 #else
2581 pf_status.debug = *level;
2582 #endif
2583 break;
2584 }
2585
2586 case DIOCCLRRULECTRS: {
2587 /* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
2588 struct pf_ruleset *ruleset = &pf_main_ruleset;
2589 struct pf_rule *rule;
2590
2591 TAILQ_FOREACH(rule,
2592 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) {
2593 rule->evaluations = 0;
2594 rule->packets[0] = rule->packets[1] = 0;
2595 rule->bytes[0] = rule->bytes[1] = 0;
2596 }
2597 break;
2598 }
2599
2600 #ifdef __FreeBSD__
2601 case DIOCGIFSPEED: {
2602 struct pf_ifspeed *psp = (struct pf_ifspeed *)addr;
2603 struct pf_ifspeed ps;
2604 struct ifnet *ifp;
2605
2606 if (psp->ifname[0] != 0) {
2607 /* Can we completely trust user-land? */
2608 strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
2609 ifp = ifunit(ps.ifname);
2610 if (ifp != NULL)
2611 psp->baudrate = ifp->if_baudrate;
2612 else
2613 error = EINVAL;
2614 } else
2615 error = EINVAL;
2616 break;
2617 }
2618 #endif /* __FreeBSD__ */
2619
2620 #ifdef ALTQ
2621 case DIOCSTARTALTQ: {
2622 struct pf_altq *altq;
2623
2624 /* enable all altq interfaces on active list */
2625 #ifdef __FreeBSD__
2626 TAILQ_FOREACH(altq, V_pf_altqs_active, entries) {
2627 if (altq->qname[0] == 0 && (altq->local_flags &
2628 PFALTQ_FLAG_IF_REMOVED) == 0) {
2629 #else
2630 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2631 if (altq->qname[0] == 0) {
2632 #endif
2633 error = pf_enable_altq(altq);
2634 if (error != 0)
2635 break;
2636 }
2637 }
2638 if (error == 0)
2639 #ifdef __FreeBSD__
2640 V_pf_altq_running = 1;
2641 #else
2642 pf_altq_running = 1;
2643 #endif
2644 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
2645 break;
2646 }
2647
2648 case DIOCSTOPALTQ: {
2649 struct pf_altq *altq;
2650
2651 /* disable all altq interfaces on active list */
2652 #ifdef __FreeBSD__
2653 TAILQ_FOREACH(altq, V_pf_altqs_active, entries) {
2654 if (altq->qname[0] == 0 && (altq->local_flags &
2655 PFALTQ_FLAG_IF_REMOVED) == 0) {
2656 #else
2657 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2658 if (altq->qname[0] == 0) {
2659 #endif
2660 error = pf_disable_altq(altq);
2661 if (error != 0)
2662 break;
2663 }
2664 }
2665 if (error == 0)
2666 #ifdef __FreeBSD__
2667 V_pf_altq_running = 0;
2668 #else
2669 pf_altq_running = 0;
2670 #endif
2671 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
2672 break;
2673 }
2674
2675 case DIOCADDALTQ: {
2676 struct pfioc_altq *pa = (struct pfioc_altq *)addr;
2677 struct pf_altq *altq, *a;
2678
2679 #ifdef __FreeBSD__
2680 if (pa->ticket != V_ticket_altqs_inactive) {
2681 #else
2682 if (pa->ticket != ticket_altqs_inactive) {
2683 #endif
2684 error = EBUSY;
2685 break;
2686 }
2687 #ifdef __FreeBSD__
2688 altq = pool_get(&V_pf_altq_pl, PR_NOWAIT);
2689 #else
2690 altq = pool_get(&pf_altq_pl, PR_WAITOK|PR_LIMITFAIL);
2691 #endif
2692 if (altq == NULL) {
2693 error = ENOMEM;
2694 break;
2695 }
2696 bcopy(&pa->altq, altq, sizeof(struct pf_altq));
2697 #ifdef __FreeBSD__
2698 altq->local_flags = 0;
2699 #endif
2700
2701 /*
2702 * if this is for a queue, find the discipline and
2703 * copy the necessary fields
2704 */
2705 if (altq->qname[0] != 0) {
2706 if ((altq->qid = pf_qname2qid(altq->qname)) == 0) {
2707 error = EBUSY;
2708 #ifdef __FreeBSD__
2709 pool_put(&V_pf_altq_pl, altq);
2710 #else
2711 pool_put(&pf_altq_pl, altq);
2712 #endif
2713 break;
2714 }
2715 altq->altq_disc = NULL;
2716 #ifdef __FreeBSD__
2717 TAILQ_FOREACH(a, V_pf_altqs_inactive, entries) {
2718 #else
2719 TAILQ_FOREACH(a, pf_altqs_inactive, entries) {
2720 #endif
2721 if (strncmp(a->ifname, altq->ifname,
2722 IFNAMSIZ) == 0 && a->qname[0] == 0) {
2723 altq->altq_disc = a->altq_disc;
2724 break;
2725 }
2726 }
2727 }
2728
2729 #ifdef __FreeBSD__
2730 struct ifnet *ifp;
2731
2732 if ((ifp = ifunit(altq->ifname)) == NULL) {
2733 altq->local_flags |= PFALTQ_FLAG_IF_REMOVED;
2734 } else {
2735 PF_UNLOCK();
2736 #endif
2737 error = altq_add(altq);
2738 #ifdef __FreeBSD__
2739 PF_LOCK();
2740 }
2741 #endif
2742 if (error) {
2743 #ifdef __FreeBSD__
2744 pool_put(&V_pf_altq_pl, altq);
2745 #else
2746 pool_put(&pf_altq_pl, altq);
2747 #endif
2748 break;
2749 }
2750
2751 #ifdef __FreeBSD__
2752 TAILQ_INSERT_TAIL(V_pf_altqs_inactive, altq, entries);
2753 #else
2754 TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
2755 #endif
2756 bcopy(altq, &pa->altq, sizeof(struct pf_altq));
2757 break;
2758 }
2759
2760 case DIOCGETALTQS: {
2761 struct pfioc_altq *pa = (struct pfioc_altq *)addr;
2762 struct pf_altq *altq;
2763
2764 pa->nr = 0;
2765 #ifdef __FreeBSD__
2766 TAILQ_FOREACH(altq, V_pf_altqs_active, entries)
2767 pa->nr++;
2768 pa->ticket = V_ticket_altqs_active;
2769 #else
2770 TAILQ_FOREACH(altq, pf_altqs_active, entries)
2771 pa->nr++;
2772 pa->ticket = ticket_altqs_active;
2773 #endif
2774 break;
2775 }
2776
2777 case DIOCGETALTQ: {
2778 struct pfioc_altq *pa = (struct pfioc_altq *)addr;
2779 struct pf_altq *altq;
2780 u_int32_t nr;
2781
2782 #ifdef __FreeBSD__
2783 if (pa->ticket != V_ticket_altqs_active) {
2784 #else
2785 if (pa->ticket != ticket_altqs_active) {
2786 #endif
2787 error = EBUSY;
2788 break;
2789 }
2790 nr = 0;
2791 #ifdef __FreeBSD__
2792 altq = TAILQ_FIRST(V_pf_altqs_active);
2793 #else
2794 altq = TAILQ_FIRST(pf_altqs_active);
2795 #endif
2796 while ((altq != NULL) && (nr < pa->nr)) {
2797 altq = TAILQ_NEXT(altq, entries);
2798 nr++;
2799 }
2800 if (altq == NULL) {
2801 error = EBUSY;
2802 break;
2803 }
2804 bcopy(altq, &pa->altq, sizeof(struct pf_altq));
2805 break;
2806 }
2807
2808 case DIOCCHANGEALTQ:
2809 /* CHANGEALTQ not supported yet! */
2810 error = ENODEV;
2811 break;
2812
2813 case DIOCGETQSTATS: {
2814 struct pfioc_qstats *pq = (struct pfioc_qstats *)addr;
2815 struct pf_altq *altq;
2816 u_int32_t nr;
2817 int nbytes;
2818
2819 #ifdef __FreeBSD__
2820 if (pq->ticket != V_ticket_altqs_active) {
2821 #else
2822 if (pq->ticket != ticket_altqs_active) {
2823 #endif
2824 error = EBUSY;
2825 break;
2826 }
2827 nbytes = pq->nbytes;
2828 nr = 0;
2829 #ifdef __FreeBSD__
2830 altq = TAILQ_FIRST(V_pf_altqs_active);
2831 #else
2832 altq = TAILQ_FIRST(pf_altqs_active);
2833 #endif
2834 while ((altq != NULL) && (nr < pq->nr)) {
2835 altq = TAILQ_NEXT(altq, entries);
2836 nr++;
2837 }
2838 if (altq == NULL) {
2839 error = EBUSY;
2840 break;
2841 }
2842
2843 #ifdef __FreeBSD__
2844 if ((altq->local_flags & PFALTQ_FLAG_IF_REMOVED) != 0) {
2845 error = ENXIO;
2846 break;
2847 }
2848 PF_UNLOCK();
2849 #endif
2850 error = altq_getqstats(altq, pq->buf, &nbytes);
2851 #ifdef __FreeBSD__
2852 PF_LOCK();
2853 #endif
2854 if (error == 0) {
2855 pq->scheduler = altq->scheduler;
2856 pq->nbytes = nbytes;
2857 }
2858 break;
2859 }
2860 #endif /* ALTQ */
2861
2862 case DIOCBEGINADDRS: {
2863 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
2864
2865 #ifdef __FreeBSD__
2866 pf_empty_pool(&V_pf_pabuf);
2867 pp->ticket = ++V_ticket_pabuf;
2868 #else
2869 pf_empty_pool(&pf_pabuf);
2870 pp->ticket = ++ticket_pabuf;
2871 #endif
2872 break;
2873 }
2874
2875 case DIOCADDADDR: {
2876 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
2877
2878 #ifdef __FreeBSD__
2879 if (pp->ticket != V_ticket_pabuf) {
2880 #else
2881 if (pp->ticket != ticket_pabuf) {
2882 #endif
2883 error = EBUSY;
2884 break;
2885 }
2886 #ifndef INET
2887 if (pp->af == AF_INET) {
2888 error = EAFNOSUPPORT;
2889 break;
2890 }
2891 #endif /* INET */
2892 #ifndef INET6
2893 if (pp->af == AF_INET6) {
2894 error = EAFNOSUPPORT;
2895 break;
2896 }
2897 #endif /* INET6 */
2898 if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
2899 pp->addr.addr.type != PF_ADDR_DYNIFTL &&
2900 pp->addr.addr.type != PF_ADDR_TABLE) {
2901 error = EINVAL;
2902 break;
2903 }
2904 #ifdef __FreeBSD__
2905 pa = pool_get(&V_pf_pooladdr_pl, PR_NOWAIT);
2906 #else
2907 pa = pool_get(&pf_pooladdr_pl, PR_WAITOK|PR_LIMITFAIL);
2908 #endif
2909 if (pa == NULL) {
2910 error = ENOMEM;
2911 break;
2912 }
2913 bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
2914 if (pa->ifname[0]) {
2915 pa->kif = pfi_kif_get(pa->ifname);
2916 if (pa->kif == NULL) {
2917 #ifdef __FreeBSD__
2918 pool_put(&V_pf_pooladdr_pl, pa);
2919 #else
2920 pool_put(&pf_pooladdr_pl, pa);
2921 #endif
2922 error = EINVAL;
2923 break;
2924 }
2925 pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE);
2926 }
2927 if (pfi_dynaddr_setup(&pa->addr, pp->af)) {
2928 pfi_dynaddr_remove(&pa->addr);
2929 pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE);
2930 #ifdef __FreeBSD__
2931 pool_put(&V_pf_pooladdr_pl, pa);
2932 #else
2933 pool_put(&pf_pooladdr_pl, pa);
2934 #endif
2935 error = EINVAL;
2936 break;
2937 }
2938 #ifdef __FreeBSD__
2939 TAILQ_INSERT_TAIL(&V_pf_pabuf, pa, entries);
2940 #else
2941 TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
2942 #endif
2943 break;
2944 }
2945
2946 case DIOCGETADDRS: {
2947 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
2948
2949 pp->nr = 0;
2950 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
2951 pp->r_num, 0, 1, 0);
2952 if (pool == NULL) {
2953 error = EBUSY;
2954 break;
2955 }
2956 TAILQ_FOREACH(pa, &pool->list, entries)
2957 pp->nr++;
2958 break;
2959 }
2960
2961 case DIOCGETADDR: {
2962 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
2963 u_int32_t nr = 0;
2964
2965 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
2966 pp->r_num, 0, 1, 1);
2967 if (pool == NULL) {
2968 error = EBUSY;
2969 break;
2970 }
2971 pa = TAILQ_FIRST(&pool->list);
2972 while ((pa != NULL) && (nr < pp->nr)) {
2973 pa = TAILQ_NEXT(pa, entries);
2974 nr++;
2975 }
2976 if (pa == NULL) {
2977 error = EBUSY;
2978 break;
2979 }
2980 bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
2981 pf_addr_copyout(&pp->addr.addr);
2982 break;
2983 }
2984
2985 case DIOCCHANGEADDR: {
2986 struct pfioc_pooladdr *pca = (struct pfioc_pooladdr *)addr;
2987 struct pf_pooladdr *oldpa = NULL, *newpa = NULL;
2988 struct pf_ruleset *ruleset;
2989
2990 if (pca->action < PF_CHANGE_ADD_HEAD ||
2991 pca->action > PF_CHANGE_REMOVE) {
2992 error = EINVAL;
2993 break;
2994 }
2995 if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
2996 pca->addr.addr.type != PF_ADDR_DYNIFTL &&
2997 pca->addr.addr.type != PF_ADDR_TABLE) {
2998 error = EINVAL;
2999 break;
3000 }
3001
3002 ruleset = pf_find_ruleset(pca->anchor);
3003 if (ruleset == NULL) {
3004 error = EBUSY;
3005 break;
3006 }
3007 pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action,
3008 pca->r_num, pca->r_last, 1, 1);
3009 if (pool == NULL) {
3010 error = EBUSY;
3011 break;
3012 }
3013 if (pca->action != PF_CHANGE_REMOVE) {
3014 #ifdef __FreeBSD__
3015 newpa = pool_get(&V_pf_pooladdr_pl,
3016 PR_NOWAIT);
3017 #else
3018 newpa = pool_get(&pf_pooladdr_pl,
3019 PR_WAITOK|PR_LIMITFAIL);
3020 #endif
3021 if (newpa == NULL) {
3022 error = ENOMEM;
3023 break;
3024 }
3025 bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
3026 #ifndef INET
3027 if (pca->af == AF_INET) {
3028 #ifdef __FreeBSD__
3029 pool_put(&V_pf_pooladdr_pl, newpa);
3030 #else
3031 pool_put(&pf_pooladdr_pl, newpa);
3032 #endif
3033 error = EAFNOSUPPORT;
3034 break;
3035 }
3036 #endif /* INET */
3037 #ifndef INET6
3038 if (pca->af == AF_INET6) {
3039 #ifdef __FreeBSD__
3040 pool_put(&V_pf_pooladdr_pl, newpa);
3041 #else
3042 pool_put(&pf_pooladdr_pl, newpa);
3043 #endif
3044 error = EAFNOSUPPORT;
3045 break;
3046 }
3047 #endif /* INET6 */
3048 if (newpa->ifname[0]) {
3049 newpa->kif = pfi_kif_get(newpa->ifname);
3050 if (newpa->kif == NULL) {
3051 #ifdef __FreeBSD__
3052 pool_put(&V_pf_pooladdr_pl, newpa);
3053 #else
3054 pool_put(&pf_pooladdr_pl, newpa);
3055 #endif
3056 error = EINVAL;
3057 break;
3058 }
3059 pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE);
3060 } else
3061 newpa->kif = NULL;
3062 if (pfi_dynaddr_setup(&newpa->addr, pca->af) ||
3063 pf_tbladdr_setup(ruleset, &newpa->addr)) {
3064 pfi_dynaddr_remove(&newpa->addr);
3065 pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE);
3066 #ifdef __FreeBSD__
3067 pool_put(&V_pf_pooladdr_pl, newpa);
3068 #else
3069 pool_put(&pf_pooladdr_pl, newpa);
3070 #endif
3071 error = EINVAL;
3072 break;
3073 }
3074 }
3075
3076 if (pca->action == PF_CHANGE_ADD_HEAD)
3077 oldpa = TAILQ_FIRST(&pool->list);
3078 else if (pca->action == PF_CHANGE_ADD_TAIL)
3079 oldpa = TAILQ_LAST(&pool->list, pf_palist);
3080 else {
3081 int i = 0;
3082
3083 oldpa = TAILQ_FIRST(&pool->list);
3084 while ((oldpa != NULL) && (i < pca->nr)) {
3085 oldpa = TAILQ_NEXT(oldpa, entries);
3086 i++;
3087 }
3088 if (oldpa == NULL) {
3089 error = EINVAL;
3090 break;
3091 }
3092 }
3093
3094 if (pca->action == PF_CHANGE_REMOVE) {
3095 TAILQ_REMOVE(&pool->list, oldpa, entries);
3096 pfi_dynaddr_remove(&oldpa->addr);
3097 pf_tbladdr_remove(&oldpa->addr);
3098 pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE);
3099 #ifdef __FreeBSD__
3100 pool_put(&V_pf_pooladdr_pl, oldpa);
3101 #else
3102 pool_put(&pf_pooladdr_pl, oldpa);
3103 #endif
3104 } else {
3105 if (oldpa == NULL)
3106 TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
3107 else if (pca->action == PF_CHANGE_ADD_HEAD ||
3108 pca->action == PF_CHANGE_ADD_BEFORE)
3109 TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
3110 else
3111 TAILQ_INSERT_AFTER(&pool->list, oldpa,
3112 newpa, entries);
3113 }
3114
3115 pool->cur = TAILQ_FIRST(&pool->list);
3116 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
3117 pca->af);
3118 break;
3119 }
3120
3121 case DIOCGETRULESETS: {
3122 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
3123 struct pf_ruleset *ruleset;
3124 struct pf_anchor *anchor;
3125
3126 pr->path[sizeof(pr->path) - 1] = 0;
3127 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
3128 error = EINVAL;
3129 break;
3130 }
3131 pr->nr = 0;
3132 if (ruleset->anchor == NULL) {
3133 /* XXX kludge for pf_main_ruleset */
3134 #ifdef __FreeBSD__
3135 RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors)
3136 #else
3137 RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
3138 #endif
3139 if (anchor->parent == NULL)
3140 pr->nr++;
3141 } else {
3142 RB_FOREACH(anchor, pf_anchor_node,
3143 &ruleset->anchor->children)
3144 pr->nr++;
3145 }
3146 break;
3147 }
3148
3149 case DIOCGETRULESET: {
3150 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
3151 struct pf_ruleset *ruleset;
3152 struct pf_anchor *anchor;
3153 u_int32_t nr = 0;
3154
3155 pr->path[sizeof(pr->path) - 1] = 0;
3156 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
3157 error = EINVAL;
3158 break;
3159 }
3160 pr->name[0] = 0;
3161 if (ruleset->anchor == NULL) {
3162 /* XXX kludge for pf_main_ruleset */
3163 #ifdef __FreeBSD__
3164 RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors)
3165 #else
3166 RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
3167 #endif
3168 if (anchor->parent == NULL && nr++ == pr->nr) {
3169 strlcpy(pr->name, anchor->name,
3170 sizeof(pr->name));
3171 break;
3172 }
3173 } else {
3174 RB_FOREACH(anchor, pf_anchor_node,
3175 &ruleset->anchor->children)
3176 if (nr++ == pr->nr) {
3177 strlcpy(pr->name, anchor->name,
3178 sizeof(pr->name));
3179 break;
3180 }
3181 }
3182 if (!pr->name[0])
3183 error = EBUSY;
3184 break;
3185 }
3186
3187 case DIOCRCLRTABLES: {
3188 struct pfioc_table *io = (struct pfioc_table *)addr;
3189
3190 if (io->pfrio_esize != 0) {
3191 error = ENODEV;
3192 break;
3193 }
3194 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
3195 io->pfrio_flags | PFR_FLAG_USERIOCTL);
3196 break;
3197 }
3198
3199 case DIOCRADDTABLES: {
3200 struct pfioc_table *io = (struct pfioc_table *)addr;
3201
3202 if (io->pfrio_esize != sizeof(struct pfr_table)) {
3203 error = ENODEV;
3204 break;
3205 }
3206 error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size,
3207 &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3208 break;
3209 }
3210
3211 case DIOCRDELTABLES: {
3212 struct pfioc_table *io = (struct pfioc_table *)addr;
3213
3214 if (io->pfrio_esize != sizeof(struct pfr_table)) {
3215 error = ENODEV;
3216 break;
3217 }
3218 error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size,
3219 &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3220 break;
3221 }
3222
3223 case DIOCRGETTABLES: {
3224 struct pfioc_table *io = (struct pfioc_table *)addr;
3225
3226 if (io->pfrio_esize != sizeof(struct pfr_table)) {
3227 error = ENODEV;
3228 break;
3229 }
3230 error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer,
3231 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3232 break;
3233 }
3234
3235 case DIOCRGETTSTATS: {
3236 struct pfioc_table *io = (struct pfioc_table *)addr;
3237
3238 if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
3239 error = ENODEV;
3240 break;
3241 }
3242 error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer,
3243 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3244 break;
3245 }
3246
3247 case DIOCRCLRTSTATS: {
3248 struct pfioc_table *io = (struct pfioc_table *)addr;
3249
3250 if (io->pfrio_esize != sizeof(struct pfr_table)) {
3251 error = ENODEV;
3252 break;
3253 }
3254 error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size,
3255 &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3256 break;
3257 }
3258
3259 case DIOCRSETTFLAGS: {
3260 struct pfioc_table *io = (struct pfioc_table *)addr;
3261
3262 if (io->pfrio_esize != sizeof(struct pfr_table)) {
3263 error = ENODEV;
3264 break;
3265 }
3266 error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,
3267 io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
3268 &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3269 break;
3270 }
3271
3272 case DIOCRCLRADDRS: {
3273 struct pfioc_table *io = (struct pfioc_table *)addr;
3274
3275 if (io->pfrio_esize != 0) {
3276 error = ENODEV;
3277 break;
3278 }
3279 error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
3280 io->pfrio_flags | PFR_FLAG_USERIOCTL);
3281 break;
3282 }
3283
3284 case DIOCRADDADDRS: {
3285 struct pfioc_table *io = (struct pfioc_table *)addr;
3286
3287 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3288 error = ENODEV;
3289 break;
3290 }
3291 error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer,
3292 io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags |
3293 PFR_FLAG_USERIOCTL);
3294 break;
3295 }
3296
3297 case DIOCRDELADDRS: {
3298 struct pfioc_table *io = (struct pfioc_table *)addr;
3299
3300 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3301 error = ENODEV;
3302 break;
3303 }
3304 error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer,
3305 io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags |
3306 PFR_FLAG_USERIOCTL);
3307 break;
3308 }
3309
3310 case DIOCRSETADDRS: {
3311 struct pfioc_table *io = (struct pfioc_table *)addr;
3312
3313 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3314 error = ENODEV;
3315 break;
3316 }
3317 error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
3318 io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
3319 &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags |
3320 PFR_FLAG_USERIOCTL, 0);
3321 break;
3322 }
3323
3324 case DIOCRGETADDRS: {
3325 struct pfioc_table *io = (struct pfioc_table *)addr;
3326
3327 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3328 error = ENODEV;
3329 break;
3330 }
3331 error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer,
3332 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3333 break;
3334 }
3335
3336 case DIOCRGETASTATS: {
3337 struct pfioc_table *io = (struct pfioc_table *)addr;
3338
3339 if (io->pfrio_esize != sizeof(struct pfr_astats)) {
3340 error = ENODEV;
3341 break;
3342 }
3343 error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer,
3344 &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3345 break;
3346 }
3347
3348 case DIOCRCLRASTATS: {
3349 struct pfioc_table *io = (struct pfioc_table *)addr;
3350
3351 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3352 error = ENODEV;
3353 break;
3354 }
3355 error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer,
3356 io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags |
3357 PFR_FLAG_USERIOCTL);
3358 break;
3359 }
3360
3361 case DIOCRTSTADDRS: {
3362 struct pfioc_table *io = (struct pfioc_table *)addr;
3363
3364 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3365 error = ENODEV;
3366 break;
3367 }
3368 error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer,
3369 io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags |
3370 PFR_FLAG_USERIOCTL);
3371 break;
3372 }
3373
3374 case DIOCRINADEFINE: {
3375 struct pfioc_table *io = (struct pfioc_table *)addr;
3376
3377 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3378 error = ENODEV;
3379 break;
3380 }
3381 error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,
3382 io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
3383 io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3384 break;
3385 }
3386
3387 case DIOCOSFPADD: {
3388 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
3389 error = pf_osfp_add(io);
3390 break;
3391 }
3392
3393 case DIOCOSFPGET: {
3394 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
3395 error = pf_osfp_get(io);
3396 break;
3397 }
3398
3399 case DIOCXBEGIN: {
3400 struct pfioc_trans *io = (struct pfioc_trans *)addr;
3401 struct pfioc_trans_e *ioe;
3402 struct pfr_table *table;
3403 int i;
3404
3405 if (io->esize != sizeof(*ioe)) {
3406 error = ENODEV;
3407 goto fail;
3408 }
3409 #ifdef __FreeBSD__
3410 PF_UNLOCK();
3411 #endif
3412 ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK);
3413 table = malloc(sizeof(*table), M_TEMP, M_WAITOK);
3414 #ifdef __FreeBSD__
3415 PF_LOCK();
3416 #endif
3417 for (i = 0; i < io->size; i++) {
3418 #ifdef __FreeBSD__
3419 PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error);
3420 if (error) {
3421 #else
3422 if (copyin(io->array+i, ioe, sizeof(*ioe))) {
3423 #endif
3424 free(table, M_TEMP);
3425 free(ioe, M_TEMP);
3426 error = EFAULT;
3427 goto fail;
3428 }
3429 switch (ioe->rs_num) {
3430 #ifdef ALTQ
3431 case PF_RULESET_ALTQ:
3432 if (ioe->anchor[0]) {
3433 free(table, M_TEMP);
3434 free(ioe, M_TEMP);
3435 error = EINVAL;
3436 goto fail;
3437 }
3438 if ((error = pf_begin_altq(&ioe->ticket))) {
3439 free(table, M_TEMP);
3440 free(ioe, M_TEMP);
3441 goto fail;
3442 }
3443 break;
3444 #endif /* ALTQ */
3445 case PF_RULESET_TABLE:
3446 bzero(table, sizeof(*table));
3447 strlcpy(table->pfrt_anchor, ioe->anchor,
3448 sizeof(table->pfrt_anchor));
3449 if ((error = pfr_ina_begin(table,
3450 &ioe->ticket, NULL, 0))) {
3451 free(table, M_TEMP);
3452 free(ioe, M_TEMP);
3453 goto fail;
3454 }
3455 break;
3456 default:
3457 if ((error = pf_begin_rules(&ioe->ticket,
3458 ioe->rs_num, ioe->anchor))) {
3459 free(table, M_TEMP);
3460 free(ioe, M_TEMP);
3461 goto fail;
3462 }
3463 break;
3464 }
3465 #ifdef __FreeBSD__
3466 PF_COPYOUT(ioe, io->array+i, sizeof(io->array[i]),
3467 error);
3468 if (error) {
3469 #else
3470 if (copyout(ioe, io->array+i, sizeof(io->array[i]))) {
3471 #endif
3472 free(table, M_TEMP);
3473 free(ioe, M_TEMP);
3474 error = EFAULT;
3475 goto fail;
3476 }
3477 }
3478 free(table, M_TEMP);
3479 free(ioe, M_TEMP);
3480 break;
3481 }
3482
3483 case DIOCXROLLBACK: {
3484 struct pfioc_trans *io = (struct pfioc_trans *)addr;
3485 struct pfioc_trans_e *ioe;
3486 struct pfr_table *table;
3487 int i;
3488
3489 if (io->esize != sizeof(*ioe)) {
3490 error = ENODEV;
3491 goto fail;
3492 }
3493 #ifdef __FreeBSD__
3494 PF_UNLOCK();
3495 #endif
3496 ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK);
3497 table = malloc(sizeof(*table), M_TEMP, M_WAITOK);
3498 #ifdef __FreeBSD__
3499 PF_LOCK();
3500 #endif
3501 for (i = 0; i < io->size; i++) {
3502 #ifdef __FreeBSD__
3503 PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error);
3504 if (error) {
3505 #else
3506 if (copyin(io->array+i, ioe, sizeof(*ioe))) {
3507 #endif
3508 free(table, M_TEMP);
3509 free(ioe, M_TEMP);
3510 error = EFAULT;
3511 goto fail;
3512 }
3513 switch (ioe->rs_num) {
3514 #ifdef ALTQ
3515 case PF_RULESET_ALTQ:
3516 if (ioe->anchor[0]) {
3517 free(table, M_TEMP);
3518 free(ioe, M_TEMP);
3519 error = EINVAL;
3520 goto fail;
3521 }
3522 if ((error = pf_rollback_altq(ioe->ticket))) {
3523 free(table, M_TEMP);
3524 free(ioe, M_TEMP);
3525 goto fail; /* really bad */
3526 }
3527 break;
3528 #endif /* ALTQ */
3529 case PF_RULESET_TABLE:
3530 bzero(table, sizeof(*table));
3531 strlcpy(table->pfrt_anchor, ioe->anchor,
3532 sizeof(table->pfrt_anchor));
3533 if ((error = pfr_ina_rollback(table,
3534 ioe->ticket, NULL, 0))) {
3535 free(table, M_TEMP);
3536 free(ioe, M_TEMP);
3537 goto fail; /* really bad */
3538 }
3539 break;
3540 default:
3541 if ((error = pf_rollback_rules(ioe->ticket,
3542 ioe->rs_num, ioe->anchor))) {
3543 free(table, M_TEMP);
3544 free(ioe, M_TEMP);
3545 goto fail; /* really bad */
3546 }
3547 break;
3548 }
3549 }
3550 free(table, M_TEMP);
3551 free(ioe, M_TEMP);
3552 break;
3553 }
3554
3555 case DIOCXCOMMIT: {
3556 struct pfioc_trans *io = (struct pfioc_trans *)addr;
3557 struct pfioc_trans_e *ioe;
3558 struct pfr_table *table;
3559 struct pf_ruleset *rs;
3560 int i;
3561
3562 if (io->esize != sizeof(*ioe)) {
3563 error = ENODEV;
3564 goto fail;
3565 }
3566 #ifdef __FreeBSD__
3567 PF_UNLOCK();
3568 #endif
3569 ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK);
3570 table = malloc(sizeof(*table), M_TEMP, M_WAITOK);
3571 #ifdef __FreeBSD__
3572 PF_LOCK();
3573 #endif
3574 /* first makes sure everything will succeed */
3575 for (i = 0; i < io->size; i++) {
3576 #ifdef __FreeBSD__
3577 PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error);
3578 if (error) {
3579 #else
3580 if (copyin(io->array+i, ioe, sizeof(*ioe))) {
3581 #endif
3582 free(table, M_TEMP);
3583 free(ioe, M_TEMP);
3584 error = EFAULT;
3585 goto fail;
3586 }
3587 switch (ioe->rs_num) {
3588 #ifdef ALTQ
3589 case PF_RULESET_ALTQ:
3590 if (ioe->anchor[0]) {
3591 free(table, M_TEMP);
3592 free(ioe, M_TEMP);
3593 error = EINVAL;
3594 goto fail;
3595 }
3596 #ifdef __FreeBSD__
3597 if (!V_altqs_inactive_open || ioe->ticket !=
3598 V_ticket_altqs_inactive) {
3599 #else
3600 if (!altqs_inactive_open || ioe->ticket !=
3601 ticket_altqs_inactive) {
3602 #endif
3603 free(table, M_TEMP);
3604 free(ioe, M_TEMP);
3605 error = EBUSY;
3606 goto fail;
3607 }
3608 break;
3609 #endif /* ALTQ */
3610 case PF_RULESET_TABLE:
3611 rs = pf_find_ruleset(ioe->anchor);
3612 if (rs == NULL || !rs->topen || ioe->ticket !=
3613 rs->tticket) {
3614 free(table, M_TEMP);
3615 free(ioe, M_TEMP);
3616 error = EBUSY;
3617 goto fail;
3618 }
3619 break;
3620 default:
3621 if (ioe->rs_num < 0 || ioe->rs_num >=
3622 PF_RULESET_MAX) {
3623 free(table, M_TEMP);
3624 free(ioe, M_TEMP);
3625 error = EINVAL;
3626 goto fail;
3627 }
3628 rs = pf_find_ruleset(ioe->anchor);
3629 if (rs == NULL ||
3630 !rs->rules[ioe->rs_num].inactive.open ||
3631 rs->rules[ioe->rs_num].inactive.ticket !=
3632 ioe->ticket) {
3633 free(table, M_TEMP);
3634 free(ioe, M_TEMP);
3635 error = EBUSY;
3636 goto fail;
3637 }
3638 break;
3639 }
3640 }
3641 /* now do the commit - no errors should happen here */
3642 for (i = 0; i < io->size; i++) {
3643 #ifdef __FreeBSD__
3644 PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error);
3645 if (error) {
3646 #else
3647 if (copyin(io->array+i, ioe, sizeof(*ioe))) {
3648 #endif
3649 free(table, M_TEMP);
3650 free(ioe, M_TEMP);
3651 error = EFAULT;
3652 goto fail;
3653 }
3654 switch (ioe->rs_num) {
3655 #ifdef ALTQ
3656 case PF_RULESET_ALTQ:
3657 if ((error = pf_commit_altq(ioe->ticket))) {
3658 free(table, M_TEMP);
3659 free(ioe, M_TEMP);
3660 goto fail; /* really bad */
3661 }
3662 break;
3663 #endif /* ALTQ */
3664 case PF_RULESET_TABLE:
3665 bzero(table, sizeof(*table));
3666 strlcpy(table->pfrt_anchor, ioe->anchor,
3667 sizeof(table->pfrt_anchor));
3668 if ((error = pfr_ina_commit(table, ioe->ticket,
3669 NULL, NULL, 0))) {
3670 free(table, M_TEMP);
3671 free(ioe, M_TEMP);
3672 goto fail; /* really bad */
3673 }
3674 break;
3675 default:
3676 if ((error = pf_commit_rules(ioe->ticket,
3677 ioe->rs_num, ioe->anchor))) {
3678 free(table, M_TEMP);
3679 free(ioe, M_TEMP);
3680 goto fail; /* really bad */
3681 }
3682 break;
3683 }
3684 }
3685 free(table, M_TEMP);
3686 free(ioe, M_TEMP);
3687 break;
3688 }
3689
3690 case DIOCGETSRCNODES: {
3691 struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr;
3692 struct pf_src_node *n, *p, *pstore;
3693 u_int32_t nr = 0;
3694 int space = psn->psn_len;
3695
3696 if (space == 0) {
3697 #ifdef __FreeBSD__
3698 RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking)
3699 #else
3700 RB_FOREACH(n, pf_src_tree, &tree_src_tracking)
3701 #endif
3702 nr++;
3703 psn->psn_len = sizeof(struct pf_src_node) * nr;
3704 break;
3705 }
3706
3707 #ifdef __FreeBSD__
3708 PF_UNLOCK();
3709 #endif
3710 pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK);
3711 #ifdef __FreeBSD__
3712 PF_LOCK();
3713 #endif
3714 p = psn->psn_src_nodes;
3715 #ifdef __FreeBSD__
3716 RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) {
3717 #else
3718 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
3719 #endif
3720 int secs = time_second, diff;
3721
3722 if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len)
3723 break;
3724
3725 bcopy(n, pstore, sizeof(*pstore));
3726 if (n->rule.ptr != NULL)
3727 pstore->rule.nr = n->rule.ptr->nr;
3728 pstore->creation = secs - pstore->creation;
3729 if (pstore->expire > secs)
3730 pstore->expire -= secs;
3731 else
3732 pstore->expire = 0;
3733
3734 /* adjust the connection rate estimate */
3735 diff = secs - n->conn_rate.last;
3736 if (diff >= n->conn_rate.seconds)
3737 pstore->conn_rate.count = 0;
3738 else
3739 pstore->conn_rate.count -=
3740 n->conn_rate.count * diff /
3741 n->conn_rate.seconds;
3742
3743 #ifdef __FreeBSD__
3744 PF_COPYOUT(pstore, p, sizeof(*p), error);
3745 #else
3746 error = copyout(pstore, p, sizeof(*p));
3747 #endif
3748 if (error) {
3749 free(pstore, M_TEMP);
3750 goto fail;
3751 }
3752 p++;
3753 nr++;
3754 }
3755 psn->psn_len = sizeof(struct pf_src_node) * nr;
3756
3757 free(pstore, M_TEMP);
3758 break;
3759 }
3760
3761 case DIOCCLRSRCNODES: {
3762 struct pf_src_node *n;
3763 struct pf_state *state;
3764
3765 #ifdef __FreeBSD__
3766 RB_FOREACH(state, pf_state_tree_id, &V_tree_id) {
3767 #else
3768 RB_FOREACH(state, pf_state_tree_id, &tree_id) {
3769 #endif
3770 state->src_node = NULL;
3771 state->nat_src_node = NULL;
3772 }
3773 #ifdef __FreeBSD__
3774 RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) {
3775 #else
3776 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
3777 #endif
3778 n->expire = 1;
3779 n->states = 0;
3780 }
3781 pf_purge_expired_src_nodes(1);
3782 #ifdef __FreeBSD__
3783 V_pf_status.src_nodes = 0;
3784 #else
3785 pf_status.src_nodes = 0;
3786 #endif
3787 break;
3788 }
3789
3790 case DIOCKILLSRCNODES: {
3791 struct pf_src_node *sn;
3792 struct pf_state *s;
3793 struct pfioc_src_node_kill *psnk =
3794 (struct pfioc_src_node_kill *)addr;
3795 u_int killed = 0;
3796
3797 #ifdef __FreeBSD__
3798 RB_FOREACH(sn, pf_src_tree, &V_tree_src_tracking) {
3799 #else
3800 RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) {
3801 #endif
3802 if (PF_MATCHA(psnk->psnk_src.neg,
3803 &psnk->psnk_src.addr.v.a.addr,
3804 &psnk->psnk_src.addr.v.a.mask,
3805 &sn->addr, sn->af) &&
3806 PF_MATCHA(psnk->psnk_dst.neg,
3807 &psnk->psnk_dst.addr.v.a.addr,
3808 &psnk->psnk_dst.addr.v.a.mask,
3809 &sn->raddr, sn->af)) {
3810 /* Handle state to src_node linkage */
3811 if (sn->states != 0) {
3812 RB_FOREACH(s, pf_state_tree_id,
3813 #ifdef __FreeBSD__
3814 &V_tree_id) {
3815 #else
3816 &tree_id) {
3817 #endif
3818 if (s->src_node == sn)
3819 s->src_node = NULL;
3820 if (s->nat_src_node == sn)
3821 s->nat_src_node = NULL;
3822 }
3823 sn->states = 0;
3824 }
3825 sn->expire = 1;
3826 killed++;
3827 }
3828 }
3829
3830 if (killed > 0)
3831 pf_purge_expired_src_nodes(1);
3832
3833 psnk->psnk_killed = killed;
3834 break;
3835 }
3836
3837 case DIOCSETHOSTID: {
3838 u_int32_t *hostid = (u_int32_t *)addr;
3839
3840 #ifdef __FreeBSD__
3841 if (*hostid == 0)
3842 V_pf_status.hostid = arc4random();
3843 else
3844 V_pf_status.hostid = *hostid;
3845 #else
3846 if (*hostid == 0)
3847 pf_status.hostid = arc4random();
3848 else
3849 pf_status.hostid = *hostid;
3850 #endif
3851 break;
3852 }
3853
3854 case DIOCOSFPFLUSH:
3855 pf_osfp_flush();
3856 break;
3857
3858 case DIOCIGETIFACES: {
3859 struct pfioc_iface *io = (struct pfioc_iface *)addr;
3860
3861 if (io->pfiio_esize != sizeof(struct pfi_kif)) {
3862 error = ENODEV;
3863 break;
3864 }
3865 error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer,
3866 &io->pfiio_size);
3867 break;
3868 }
3869
3870 case DIOCSETIFFLAG: {
3871 struct pfioc_iface *io = (struct pfioc_iface *)addr;
3872
3873 error = pfi_set_flags(io->pfiio_name, io->pfiio_flags);
3874 break;
3875 }
3876
3877 case DIOCCLRIFFLAG: {
3878 struct pfioc_iface *io = (struct pfioc_iface *)addr;
3879
3880 error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags);
3881 break;
3882 }
3883
3884 default:
3885 error = ENODEV;
3886 break;
3887 }
3888 fail:
3889 #ifdef __FreeBSD__
3890 PF_UNLOCK();
3891
3892 if (flags & FWRITE)
3893 sx_xunlock(&V_pf_consistency_lock);
3894 else
3895 sx_sunlock(&V_pf_consistency_lock);
3896 #else
3897 splx(s);
3898 if (flags & FWRITE)
3899 rw_exit_write(&pf_consistency_lock);
3900 else
3901 rw_exit_read(&pf_consistency_lock);
3902 #endif
3903
3904 CURVNET_RESTORE();
3905
3906 return (error);
3907 }
3908
3909 #ifdef __FreeBSD__
3910 void
3911 pfsync_state_export(struct pfsync_state *sp, struct pf_state *st)
3912 {
3913 bzero(sp, sizeof(struct pfsync_state));
3914
3915 /* copy from state key */
3916 sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
3917 sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
3918 sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
3919 sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
3920 sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
3921 sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
3922 sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
3923 sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
3924 sp->proto = st->key[PF_SK_WIRE]->proto;
3925 sp->af = st->key[PF_SK_WIRE]->af;
3926
3927 /* copy from state */
3928 strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
3929 bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
3930 sp->creation = htonl(time_second - st->creation);
3931 sp->expire = pf_state_expires(st);
3932 if (sp->expire <= time_second)
3933 sp->expire = htonl(0);
3934 else
3935 sp->expire = htonl(sp->expire - time_second);
3936
3937 sp->direction = st->direction;
3938 sp->log = st->log;
3939 sp->timeout = st->timeout;
3940 sp->state_flags = st->state_flags;
3941 if (st->src_node)
3942 sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
3943 if (st->nat_src_node)
3944 sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
3945
3946 bcopy(&st->id, &sp->id, sizeof(sp->id));
3947 sp->creatorid = st->creatorid;
3948 pf_state_peer_hton(&st->src, &sp->src);
3949 pf_state_peer_hton(&st->dst, &sp->dst);
3950
3951 if (st->rule.ptr == NULL)
3952 sp->rule = htonl(-1);
3953 else
3954 sp->rule = htonl(st->rule.ptr->nr);
3955 if (st->anchor.ptr == NULL)
3956 sp->anchor = htonl(-1);
3957 else
3958 sp->anchor = htonl(st->anchor.ptr->nr);
3959 if (st->nat_rule.ptr == NULL)
3960 sp->nat_rule = htonl(-1);
3961 else
3962 sp->nat_rule = htonl(st->nat_rule.ptr->nr);
3963
3964 pf_state_counter_hton(st->packets[0], sp->packets[0]);
3965 pf_state_counter_hton(st->packets[1], sp->packets[1]);
3966 pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
3967 pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
3968
3969 }
3970
3971 /*
3972 * XXX - Check for version missmatch!!!
3973 */
3974 static void
3975 pf_clear_states(void)
3976 {
3977 struct pf_state *state;
3978
3979 #ifdef __FreeBSD__
3980 RB_FOREACH(state, pf_state_tree_id, &V_tree_id) {
3981 #else
3982 RB_FOREACH(state, pf_state_tree_id, &tree_id) {
3983 #endif
3984 state->timeout = PFTM_PURGE;
3985 #if NPFSYNC
3986 /* don't send out individual delete messages */
3987 state->sync_state = PFSTATE_NOSYNC;
3988 #endif
3989 pf_unlink_state(state);
3990 }
3991
3992 #if 0 /* NPFSYNC */
3993 /*
3994 * XXX This is called on module unload, we do not want to sync that over? */
3995 */
3996 pfsync_clear_states(V_pf_status.hostid, psk->psk_ifname);
3997 #endif
3998 }
3999
4000 static int
4001 pf_clear_tables(void)
4002 {
4003 struct pfioc_table io;
4004 int error;
4005
4006 bzero(&io, sizeof(io));
4007
4008 error = pfr_clr_tables(&io.pfrio_table, &io.pfrio_ndel,
4009 io.pfrio_flags);
4010
4011 return (error);
4012 }
4013
4014 static void
4015 pf_clear_srcnodes(void)
4016 {
4017 struct pf_src_node *n;
4018 struct pf_state *state;
4019
4020 #ifdef __FreeBSD__
4021 RB_FOREACH(state, pf_state_tree_id, &V_tree_id) {
4022 #else
4023 RB_FOREACH(state, pf_state_tree_id, &tree_id) {
4024 #endif
4025 state->src_node = NULL;
4026 state->nat_src_node = NULL;
4027 }
4028 #ifdef __FreeBSD__
4029 RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) {
4030 #else
4031 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
4032 #endif
4033 n->expire = 1;
4034 n->states = 0;
4035 }
4036 }
4037 /*
4038 * XXX - Check for version missmatch!!!
4039 */
4040
4041 /*
4042 * Duplicate pfctl -Fa operation to get rid of as much as we can.
4043 */
4044 static int
4045 shutdown_pf(void)
4046 {
4047 int error = 0;
4048 u_int32_t t[5];
4049 char nn = '\0';
4050
4051 V_pf_status.running = 0;
4052 do {
4053 if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn))
4054 != 0) {
4055 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: SCRUB\n"));
4056 break;
4057 }
4058 if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn))
4059 != 0) {
4060 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: FILTER\n"));
4061 break; /* XXX: rollback? */
4062 }
4063 if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn))
4064 != 0) {
4065 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: NAT\n"));
4066 break; /* XXX: rollback? */
4067 }
4068 if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn))
4069 != 0) {
4070 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: BINAT\n"));
4071 break; /* XXX: rollback? */
4072 }
4073 if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn))
4074 != 0) {
4075 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: RDR\n"));
4076 break; /* XXX: rollback? */
4077 }
4078
4079 /* XXX: these should always succeed here */
4080 pf_commit_rules(t[0], PF_RULESET_SCRUB, &nn);
4081 pf_commit_rules(t[1], PF_RULESET_FILTER, &nn);
4082 pf_commit_rules(t[2], PF_RULESET_NAT, &nn);
4083 pf_commit_rules(t[3], PF_RULESET_BINAT, &nn);
4084 pf_commit_rules(t[4], PF_RULESET_RDR, &nn);
4085
4086 if ((error = pf_clear_tables()) != 0)
4087 break;
4088
4089 #ifdef ALTQ
4090 if ((error = pf_begin_altq(&t[0])) != 0) {
4091 DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n"));
4092 break;
4093 }
4094 pf_commit_altq(t[0]);
4095 #endif
4096
4097 pf_clear_states();
4098
4099 pf_clear_srcnodes();
4100
4101 /* status does not use malloced mem so no need to cleanup */
4102 /* fingerprints and interfaces have thier own cleanup code */
4103 } while(0);
4104
4105 return (error);
4106 }
4107
4108 #ifdef INET
4109 static int
4110 pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
4111 struct inpcb *inp)
4112 {
4113 /*
4114 * XXX Wed Jul 9 22:03:16 2003 UTC
4115 * OpenBSD has changed its byte ordering convention on ip_len/ip_off
4116 * in network stack. OpenBSD's network stack have converted
4117 * ip_len/ip_off to host byte order frist as FreeBSD.
4118 * Now this is not true anymore , so we should convert back to network
4119 * byte order.
4120 */
4121 struct ip *h = NULL;
4122 int chk;
4123
4124 if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) {
4125 /* if m_pkthdr.len is less than ip header, pf will handle. */
4126 h = mtod(*m, struct ip *);
4127 HTONS(h->ip_len);
4128 HTONS(h->ip_off);
4129 }
4130 CURVNET_SET(ifp->if_vnet);
4131 chk = pf_test(PF_IN, ifp, m, NULL, inp);
4132 CURVNET_RESTORE();
4133 if (chk && *m) {
4134 m_freem(*m);
4135 *m = NULL;
4136 }
4137 if (*m != NULL) {
4138 /* pf_test can change ip header location */
4139 h = mtod(*m, struct ip *);
4140 NTOHS(h->ip_len);
4141 NTOHS(h->ip_off);
4142 }
4143 return chk;
4144 }
4145
4146 static int
4147 pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
4148 struct inpcb *inp)
4149 {
4150 /*
4151 * XXX Wed Jul 9 22:03:16 2003 UTC
4152 * OpenBSD has changed its byte ordering convention on ip_len/ip_off
4153 * in network stack. OpenBSD's network stack have converted
4154 * ip_len/ip_off to host byte order frist as FreeBSD.
4155 * Now this is not true anymore , so we should convert back to network
4156 * byte order.
4157 */
4158 struct ip *h = NULL;
4159 int chk;
4160
4161 if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) {
4162 /* if m_pkthdr.len is less than ip header, pf will handle. */
4163 h = mtod(*m, struct ip *);
4164 HTONS(h->ip_len);
4165 HTONS(h->ip_off);
4166 }
4167 CURVNET_SET(ifp->if_vnet);
4168 chk = pf_test(PF_OUT, ifp, m, NULL, inp);
4169 CURVNET_RESTORE();
4170 if (chk && *m) {
4171 m_freem(*m);
4172 *m = NULL;
4173 }
4174 if (*m != NULL) {
4175 /* pf_test can change ip header location */
4176 h = mtod(*m, struct ip *);
4177 NTOHS(h->ip_len);
4178 NTOHS(h->ip_off);
4179 }
4180 return chk;
4181 }
4182 #endif
4183
4184 #ifdef INET6
4185 static int
4186 pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
4187 struct inpcb *inp)
4188 {
4189
4190 /*
4191 * IPv6 is not affected by ip_len/ip_off byte order changes.
4192 */
4193 int chk;
4194
4195 /*
4196 * In case of loopback traffic IPv6 uses the real interface in
4197 * order to support scoped addresses. In order to support stateful
4198 * filtering we have change this to lo0 as it is the case in IPv4.
4199 */
4200 CURVNET_SET(ifp->if_vnet);
4201 chk = pf_test6(PF_IN, (*m)->m_flags & M_LOOP ? V_loif : ifp, m,
4202 NULL, inp);
4203 CURVNET_RESTORE();
4204 if (chk && *m) {
4205 m_freem(*m);
4206 *m = NULL;
4207 }
4208 return chk;
4209 }
4210
4211 static int
4212 pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
4213 struct inpcb *inp)
4214 {
4215 /*
4216 * IPv6 does not affected ip_len/ip_off byte order changes.
4217 */
4218 int chk;
4219
4220 CURVNET_SET(ifp->if_vnet);
4221 chk = pf_test6(PF_OUT, ifp, m, NULL, inp);
4222 CURVNET_RESTORE();
4223 if (chk && *m) {
4224 m_freem(*m);
4225 *m = NULL;
4226 }
4227 return chk;
4228 }
4229 #endif /* INET6 */
4230
4231 static int
4232 hook_pf(void)
4233 {
4234 #ifdef INET
4235 struct pfil_head *pfh_inet;
4236 #endif
4237 #ifdef INET6
4238 struct pfil_head *pfh_inet6;
4239 #endif
4240
4241 PF_UNLOCK_ASSERT();
4242
4243 if (V_pf_pfil_hooked)
4244 return (0);
4245
4246 #ifdef INET
4247 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
4248 if (pfh_inet == NULL)
4249 return (ESRCH); /* XXX */
4250 pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
4251 pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
4252 #endif
4253 #ifdef INET6
4254 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
4255 if (pfh_inet6 == NULL) {
4256 #ifdef INET
4257 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
4258 pfh_inet);
4259 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
4260 pfh_inet);
4261 #endif
4262 return (ESRCH); /* XXX */
4263 }
4264 pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
4265 pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
4266 #endif
4267
4268 V_pf_pfil_hooked = 1;
4269 return (0);
4270 }
4271
4272 static int
4273 dehook_pf(void)
4274 {
4275 #ifdef INET
4276 struct pfil_head *pfh_inet;
4277 #endif
4278 #ifdef INET6
4279 struct pfil_head *pfh_inet6;
4280 #endif
4281
4282 PF_UNLOCK_ASSERT();
4283
4284 if (V_pf_pfil_hooked == 0)
4285 return (0);
4286
4287 #ifdef INET
4288 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
4289 if (pfh_inet == NULL)
4290 return (ESRCH); /* XXX */
4291 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
4292 pfh_inet);
4293 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
4294 pfh_inet);
4295 #endif
4296 #ifdef INET6
4297 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
4298 if (pfh_inet6 == NULL)
4299 return (ESRCH); /* XXX */
4300 pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK,
4301 pfh_inet6);
4302 pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK,
4303 pfh_inet6);
4304 #endif
4305
4306 V_pf_pfil_hooked = 0;
4307 return (0);
4308 }
4309
4310 static int
4311 pf_load(void)
4312 {
4313 VNET_ITERATOR_DECL(vnet_iter);
4314
4315 VNET_LIST_RLOCK();
4316 VNET_FOREACH(vnet_iter) {
4317 CURVNET_SET(vnet_iter);
4318 V_pf_pfil_hooked = 0;
4319 V_pf_end_threads = 0;
4320 V_debug_pfugidhack = 0;
4321 TAILQ_INIT(&V_pf_tags);
4322 TAILQ_INIT(&V_pf_qids);
4323 CURVNET_RESTORE();
4324 }
4325 VNET_LIST_RUNLOCK();
4326
4327 init_pf_mutex();
4328 pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME);
4329 init_zone_var();
4330 sx_init(&V_pf_consistency_lock, "pf_statetbl_lock");
4331 if (pfattach() < 0)
4332 return (ENOMEM);
4333
4334 return (0);
4335 }
4336
4337 static int
4338 pf_unload(void)
4339 {
4340 int error = 0;
4341
4342 PF_LOCK();
4343 V_pf_status.running = 0;
4344 PF_UNLOCK();
4345 m_addr_chg_pf_p = NULL;
4346 error = dehook_pf();
4347 if (error) {
4348 /*
4349 * Should not happen!
4350 * XXX Due to error code ESRCH, kldunload will show
4351 * a message like 'No such process'.
4352 */
4353 printf("%s : pfil unregisteration fail\n", __FUNCTION__);
4354 return error;
4355 }
4356 PF_LOCK();
4357 shutdown_pf();
4358 V_pf_end_threads = 1;
4359 while (V_pf_end_threads < 2) {
4360 wakeup_one(pf_purge_thread);
4361 msleep(pf_purge_thread, &pf_task_mtx, 0, "pftmo", hz);
4362 }
4363 pfi_cleanup();
4364 pf_osfp_flush();
4365 pf_osfp_cleanup();
4366 cleanup_pf_zone();
4367 PF_UNLOCK();
4368 destroy_dev(pf_dev);
4369 destroy_pf_mutex();
4370 sx_destroy(&V_pf_consistency_lock);
4371 return error;
4372 }
4373
4374 static int
4375 pf_modevent(module_t mod, int type, void *data)
4376 {
4377 int error = 0;
4378
4379 switch(type) {
4380 case MOD_LOAD:
4381 error = pf_load();
4382 break;
4383 case MOD_QUIESCE:
4384 /*
4385 * Module should not be unloaded due to race conditions.
4386 */
4387 error = EPERM;
4388 break;
4389 case MOD_UNLOAD:
4390 error = pf_unload();
4391 break;
4392 default:
4393 error = EINVAL;
4394 break;
4395 }
4396 return error;
4397 }
4398
4399 static moduledata_t pf_mod = {
4400 "pf",
4401 pf_modevent,
4402 0
4403 };
4404
4405 DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_FIRST);
4406 MODULE_VERSION(pf, PF_MODVER);
4407 #endif /* __FreeBSD__ */
4408