1 /*
2 * Copyright (c) 2007-2021 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /* $apfw: git commit b6bf13f8321283cd7ee82b1795e86506084b1b95 $ */
30 /* $OpenBSD: pf_ioctl.c,v 1.175 2007/02/26 22:47:43 deraadt Exp $ */
31
32 /*
33 * Copyright (c) 2001 Daniel Hartmeier
34 * Copyright (c) 2002,2003 Henning Brauer
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 *
41 * - Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * - Redistributions in binary form must reproduce the above
44 * copyright notice, this list of conditions and the following
45 * disclaimer in the documentation and/or other materials provided
46 * with the distribution.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
49 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
50 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
51 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
52 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
53 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
54 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
55 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
56 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
58 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
59 * POSSIBILITY OF SUCH DAMAGE.
60 *
61 * Effort sponsored in part by the Defense Advanced Research Projects
62 * Agency (DARPA) and Air Force Research Laboratory, Air Force
63 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
64 *
65 */
66
67 #include <machine/endian.h>
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/mbuf.h>
71 #include <sys/filio.h>
72 #include <sys/fcntl.h>
73 #include <sys/socket.h>
74 #include <sys/socketvar.h>
75 #include <sys/kernel.h>
76 #include <sys/time.h>
77 #include <sys/proc_internal.h>
78 #include <sys/malloc.h>
79 #include <sys/kauth.h>
80 #include <sys/conf.h>
81 #include <sys/mcache.h>
82 #include <sys/queue.h>
83 #include <os/log.h>
84
85 #include <mach/vm_param.h>
86
87 #include <net/dlil.h>
88 #include <net/if.h>
89 #include <net/if_types.h>
90 #include <net/net_api_stats.h>
91 #include <net/route.h>
92 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
93 #include <skywalk/lib/net_filter_event.h>
94 #endif
95
96 #include <netinet/in.h>
97 #include <netinet/in_var.h>
98 #include <netinet/in_systm.h>
99 #include <netinet/ip.h>
100 #include <netinet/ip_var.h>
101 #include <netinet/ip_icmp.h>
102 #include <netinet/if_ether.h>
103
104 #if DUMMYNET
105 #include <netinet/ip_dummynet.h>
106 #else
107 struct ip_fw_args;
108 #endif /* DUMMYNET */
109
110 #include <libkern/crypto/md5.h>
111
112 #include <machine/machine_routines.h>
113
114 #include <miscfs/devfs/devfs.h>
115
116 #include <net/pfvar.h>
117
118 #if NPFSYNC
119 #include <net/if_pfsync.h>
120 #endif /* NPFSYNC */
121
122 #if PFLOG
123 #include <net/if_pflog.h>
124 #endif /* PFLOG */
125
126 #include <netinet/ip6.h>
127 #include <netinet/in_pcb.h>
128
129 #include <dev/random/randomdev.h>
130
131 #if 0
132 static void pfdetach(void);
133 #endif
134 static int pfopen(dev_t, int, int, struct proc *);
135 static int pfclose(dev_t, int, int, struct proc *);
136 static int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
137 static int pfioctl_ioc_table(u_long, struct pfioc_table_32 *,
138 struct pfioc_table_64 *, struct proc *);
139 static int pfioctl_ioc_tokens(u_long, struct pfioc_tokens_32 *,
140 struct pfioc_tokens_64 *, struct proc *);
141 static int pfioctl_ioc_rule(u_long, int, struct pfioc_rule *, struct proc *);
142 static int pfioctl_ioc_state_kill(u_long, struct pfioc_state_kill *,
143 struct proc *);
144 static int pfioctl_ioc_state(u_long, struct pfioc_state *, struct proc *);
145 static int pfioctl_ioc_states(u_long, struct pfioc_states_32 *,
146 struct pfioc_states_64 *, struct proc *);
147 static int pfioctl_ioc_natlook(u_long, struct pfioc_natlook *, struct proc *);
148 static int pfioctl_ioc_tm(u_long, struct pfioc_tm *, struct proc *);
149 static int pfioctl_ioc_limit(u_long, struct pfioc_limit *, struct proc *);
150 static int pfioctl_ioc_pooladdr(u_long, struct pfioc_pooladdr *, struct proc *);
151 static int pfioctl_ioc_ruleset(u_long, struct pfioc_ruleset *, struct proc *);
152 static int pfioctl_ioc_trans(u_long, struct pfioc_trans_32 *,
153 struct pfioc_trans_64 *, struct proc *);
154 static int pfioctl_ioc_src_nodes(u_long, struct pfioc_src_nodes_32 *,
155 struct pfioc_src_nodes_64 *, struct proc *);
156 static int pfioctl_ioc_src_node_kill(u_long, struct pfioc_src_node_kill *,
157 struct proc *);
158 static int pfioctl_ioc_iface(u_long, struct pfioc_iface_32 *,
159 struct pfioc_iface_64 *, struct proc *);
160 static struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
161 u_int8_t, u_int8_t, u_int8_t);
162 static void pf_mv_pool(struct pf_palist *, struct pf_palist *);
163 static void pf_empty_pool(struct pf_palist *);
164 static int pf_begin_rules(u_int32_t *, int, const char *);
165 static int pf_rollback_rules(u_int32_t, int, char *);
166 static int pf_setup_pfsync_matching(struct pf_ruleset *);
167 static void pf_hash_rule(MD5_CTX *, struct pf_rule *);
168 static void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *, u_int8_t);
169 static int pf_commit_rules(u_int32_t, int, char *);
170 static void pf_rule_copyin(struct pf_rule *, struct pf_rule *, struct proc *,
171 int);
172 static void pf_rule_copyout(struct pf_rule *, struct pf_rule *);
173 static void pf_state_export(struct pfsync_state *, struct pf_state_key *,
174 struct pf_state *);
175 static void pf_state_import(struct pfsync_state *, struct pf_state_key *,
176 struct pf_state *);
177 static void pf_pooladdr_copyin(struct pf_pooladdr *, struct pf_pooladdr *);
178 static void pf_pooladdr_copyout(struct pf_pooladdr *, struct pf_pooladdr *);
179 static void pf_expire_states_and_src_nodes(struct pf_rule *);
180 static void pf_delete_rule_from_ruleset(struct pf_ruleset *,
181 int, struct pf_rule *);
182 static void pf_addrwrap_setup(struct pf_addr_wrap *);
183 static int pf_rule_setup(struct pfioc_rule *, struct pf_rule *,
184 struct pf_ruleset *);
185 static void pf_delete_rule_by_owner(char *, u_int32_t);
186 static int pf_delete_rule_by_ticket(struct pfioc_rule *, u_int32_t);
187 static void pf_ruleset_cleanup(struct pf_ruleset *, int);
188 static void pf_deleterule_anchor_step_out(struct pf_ruleset **,
189 int, struct pf_rule **);
190 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
191 static void pf_process_compatibilities(void);
192 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
193
194 #define PF_CDEV_MAJOR (-1)
195
196 static const struct cdevsw pf_cdevsw = {
197 .d_open = pfopen,
198 .d_close = pfclose,
199 .d_read = eno_rdwrt,
200 .d_write = eno_rdwrt,
201 .d_ioctl = pfioctl,
202 .d_stop = eno_stop,
203 .d_reset = eno_reset,
204 .d_ttys = NULL,
205 .d_select = eno_select,
206 .d_mmap = eno_mmap,
207 .d_strategy = eno_strat,
208 .d_reserved_1 = eno_getc,
209 .d_reserved_2 = eno_putc,
210 .d_type = 0
211 };
212
213 static void pf_attach_hooks(void);
214 #if 0
215 /* currently unused along with pfdetach() */
216 static void pf_detach_hooks(void);
217 #endif
218
219 /*
220 * This is set during DIOCSTART/DIOCSTOP with pf_perim_lock held as writer,
221 * and used in pf_af_hook() for performance optimization, such that packets
222 * will enter pf_test() or pf_test6() only when PF is running.
223 */
224 int pf_is_enabled = 0;
225
226 u_int32_t pf_hash_seed;
227 int16_t pf_nat64_configured = 0;
228
229 /*
230 * These are the pf enabled reference counting variables
231 */
232 #define NR_TOKENS_LIMIT (INT_MAX / sizeof(struct pfioc_token))
233
234 static u_int64_t pf_enabled_ref_count;
235 static u_int32_t nr_tokens = 0;
236 static u_int32_t pffwrules;
237 static u_int32_t pfdevcnt;
238
239 SLIST_HEAD(list_head, pfioc_kernel_token);
240 static struct list_head token_list_head;
241
242 struct pf_rule pf_default_rule;
243
244 typedef struct {
245 char tag_name[PF_TAG_NAME_SIZE];
246 uint16_t tag_id;
247 } pf_reserved_tag_table_t;
248
249 #define NUM_RESERVED_TAGS 2
250 static pf_reserved_tag_table_t pf_reserved_tag_table[NUM_RESERVED_TAGS] = {
251 { PF_TAG_NAME_SYSTEM_SERVICE, PF_TAG_ID_SYSTEM_SERVICE},
252 { PF_TAG_NAME_STACK_DROP, PF_TAG_ID_STACK_DROP},
253 };
254 #define RESERVED_TAG_ID_MIN PF_TAG_ID_SYSTEM_SERVICE
255
256 #define DYNAMIC_TAG_ID_MAX 50000
257 static TAILQ_HEAD(pf_tags, pf_tagname) pf_tags =
258 TAILQ_HEAD_INITIALIZER(pf_tags);
259
260 #if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
261 #error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
262 #endif
263 static u_int16_t tagname2tag(struct pf_tags *, char *);
264 static void tag_unref(struct pf_tags *, u_int16_t);
265 static int pf_rtlabel_add(struct pf_addr_wrap *);
266 static void pf_rtlabel_remove(struct pf_addr_wrap *);
267 static void pf_rtlabel_copyout(struct pf_addr_wrap *);
268
269 #if INET
270 static int pf_inet_hook(struct ifnet *, struct mbuf **, int,
271 struct ip_fw_args *);
272 #endif /* INET */
273 static int pf_inet6_hook(struct ifnet *, struct mbuf **, int,
274 struct ip_fw_args *);
275
276 #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
277
278 /*
279 * Helper macros for ioctl structures which vary in size (32-bit vs. 64-bit)
280 */
281 #define PFIOCX_STRUCT_DECL(s) \
282 struct { \
283 union { \
284 struct s##_32 _s##_32; \
285 struct s##_64 _s##_64; \
286 } _u; \
287 } *s##_un = NULL \
288
289 #define PFIOCX_STRUCT_BEGIN(a, s) { \
290 VERIFY(s##_un == NULL); \
291 s##_un = kalloc_type(typeof(*s##_un), Z_WAITOK_ZERO_NOFAIL); \
292 if (p64) \
293 bcopy(a, &s##_un->_u._s##_64, \
294 sizeof (struct s##_64)); \
295 else \
296 bcopy(a, &s##_un->_u._s##_32, \
297 sizeof (struct s##_32)); \
298 }
299
300 #define PFIOCX_STRUCT_END(s, a) { \
301 VERIFY(s##_un != NULL); \
302 if (p64) \
303 bcopy(&s##_un->_u._s##_64, a, sizeof (struct s##_64)); \
304 else \
305 bcopy(&s##_un->_u._s##_32, a, sizeof (struct s##_32)); \
306 kfree_type(typeof(*s##_un), s##_un); \
307 }
308
309 #define PFIOCX_STRUCT_ADDR32(s) (&s##_un->_u._s##_32)
310 #define PFIOCX_STRUCT_ADDR64(s) (&s##_un->_u._s##_64)
311
312 /*
313 * Helper macros for regular ioctl structures.
314 */
315 #define PFIOC_STRUCT_BEGIN(a, v) { \
316 VERIFY((v) == NULL); \
317 (v) = kalloc_type(typeof(*(v)), Z_WAITOK_ZERO_NOFAIL); \
318 bcopy(a, v, sizeof (*(v))); \
319 }
320
321 #define PFIOC_STRUCT_END(v, a) { \
322 VERIFY((v) != NULL); \
323 bcopy(v, a, sizeof (*(v))); \
324 kfree_type(typeof(*(v)), v); \
325 }
326
327 #define PFIOC_STRUCT_ADDR32(s) (&s##_un->_u._s##_32)
328 #define PFIOC_STRUCT_ADDR64(s) (&s##_un->_u._s##_64)
329
330 struct thread *pf_purge_thread;
331
332 extern void pfi_kifaddr_update(void *);
333
334 /* pf enable ref-counting helper functions */
335 static u_int64_t generate_token(struct proc *);
336 static int remove_token(struct pfioc_remove_token *);
337 static void invalidate_all_tokens(void);
338
339 static u_int64_t
generate_token(struct proc * p)340 generate_token(struct proc *p)
341 {
342 u_int64_t token_value;
343 struct pfioc_kernel_token *new_token;
344
345 if (nr_tokens + 1 > NR_TOKENS_LIMIT) {
346 os_log_error(OS_LOG_DEFAULT, "%s: NR_TOKENS_LIMIT reached", __func__);
347 return 0;
348 }
349
350 new_token = kalloc_type(struct pfioc_kernel_token,
351 Z_WAITOK | Z_ZERO | Z_NOFAIL);
352
353 LCK_MTX_ASSERT(&pf_lock, LCK_MTX_ASSERT_OWNED);
354
355 token_value = VM_KERNEL_ADDRPERM((u_int64_t)(uintptr_t)new_token);
356
357 new_token->token.token_value = token_value;
358 new_token->token.pid = proc_pid(p);
359 proc_name(new_token->token.pid, new_token->token.proc_name,
360 sizeof(new_token->token.proc_name));
361 new_token->token.timestamp = pf_calendar_time_second();
362
363 SLIST_INSERT_HEAD(&token_list_head, new_token, next);
364 nr_tokens++;
365
366 return token_value;
367 }
368
369 static int
remove_token(struct pfioc_remove_token * tok)370 remove_token(struct pfioc_remove_token *tok)
371 {
372 struct pfioc_kernel_token *entry, *tmp;
373
374 LCK_MTX_ASSERT(&pf_lock, LCK_MTX_ASSERT_OWNED);
375
376 SLIST_FOREACH_SAFE(entry, &token_list_head, next, tmp) {
377 if (tok->token_value == entry->token.token_value) {
378 SLIST_REMOVE(&token_list_head, entry,
379 pfioc_kernel_token, next);
380 kfree_type(struct pfioc_kernel_token, entry);
381 nr_tokens--;
382 return 0; /* success */
383 }
384 }
385
386 printf("pf : remove failure\n");
387 return ESRCH; /* failure */
388 }
389
390 static void
invalidate_all_tokens(void)391 invalidate_all_tokens(void)
392 {
393 struct pfioc_kernel_token *entry, *tmp;
394
395 LCK_MTX_ASSERT(&pf_lock, LCK_MTX_ASSERT_OWNED);
396
397 SLIST_FOREACH_SAFE(entry, &token_list_head, next, tmp) {
398 SLIST_REMOVE(&token_list_head, entry, pfioc_kernel_token, next);
399 kfree_type(struct pfioc_kernel_token, entry);
400 }
401
402 nr_tokens = 0;
403 }
404
405 struct pf_reass_tag_container {
406 struct m_tag pf_reass_m_tag;
407 struct pf_fragment_tag pf_reass_fragment_tag;
408 };
409
410 static struct m_tag *
m_tag_kalloc_pf_reass(u_int32_t id,u_int16_t type,uint16_t len,int wait)411 m_tag_kalloc_pf_reass(u_int32_t id, u_int16_t type, uint16_t len, int wait)
412 {
413 struct pf_reass_tag_container *tag_container;
414 struct m_tag *tag = NULL;
415
416 assert3u(id, ==, KERNEL_MODULE_TAG_ID);
417 assert3u(type, ==, KERNEL_TAG_TYPE_PF_REASS);
418 assert3u(len, ==, sizeof(struct pf_fragment_tag));
419
420 if (len != sizeof(struct pf_fragment_tag)) {
421 return NULL;
422 }
423
424 tag_container = kalloc_type(struct pf_reass_tag_container, wait | M_ZERO);
425 if (tag_container != NULL) {
426 tag = &tag_container->pf_reass_m_tag;
427
428 assert3p(tag, ==, tag_container);
429
430 M_TAG_INIT(tag, id, type, len, &tag_container->pf_reass_fragment_tag, NULL);
431 }
432
433 return tag;
434 }
435
436 static void
m_tag_kfree_pf_reass(struct m_tag * tag)437 m_tag_kfree_pf_reass(struct m_tag *tag)
438 {
439 struct pf_reass_tag_container *tag_container = (struct pf_reass_tag_container *)tag;
440
441 assert3u(tag->m_tag_len, ==, sizeof(struct pf_fragment_tag));
442
443 kfree_type(struct pf_reass_tag_container, tag_container);
444 }
445
446 void
pf_register_m_tag(void)447 pf_register_m_tag(void)
448 {
449 int error;
450
451 error = m_register_internal_tag_type(KERNEL_TAG_TYPE_PF_REASS, sizeof(struct pf_fragment_tag),
452 m_tag_kalloc_pf_reass, m_tag_kfree_pf_reass);
453
454 assert3u(error, ==, 0);
455 }
456
457 void
pfinit(void)458 pfinit(void)
459 {
460 u_int32_t *t = pf_default_rule.timeout;
461 int maj;
462
463 pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl",
464 NULL);
465 pool_init(&pf_src_tree_pl, sizeof(struct pf_src_node), 0, 0, 0,
466 "pfsrctrpl", NULL);
467 pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl",
468 NULL);
469 pool_init(&pf_state_key_pl, sizeof(struct pf_state_key), 0, 0, 0,
470 "pfstatekeypl", NULL);
471 pool_init(&pf_app_state_pl, sizeof(struct pf_app_state), 0, 0, 0,
472 "pfappstatepl", NULL);
473 pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0,
474 "pfpooladdrpl", NULL);
475 pfr_initialize();
476 pfi_initialize();
477 pf_osfp_initialize();
478
479 pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp,
480 pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0);
481
482 if (max_mem <= 256 * 1024 * 1024) {
483 pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit =
484 PFR_KENTRY_HIWAT_SMALL;
485 }
486
487 RB_INIT(&tree_src_tracking);
488 RB_INIT(&pf_anchors);
489 pf_init_ruleset(&pf_main_ruleset);
490 TAILQ_INIT(&pf_pabuf);
491 TAILQ_INIT(&state_list);
492
493 _CASSERT((SC_BE & SCIDX_MASK) == SCIDX_BE);
494 _CASSERT((SC_BK_SYS & SCIDX_MASK) == SCIDX_BK_SYS);
495 _CASSERT((SC_BK & SCIDX_MASK) == SCIDX_BK);
496 _CASSERT((SC_RD & SCIDX_MASK) == SCIDX_RD);
497 _CASSERT((SC_OAM & SCIDX_MASK) == SCIDX_OAM);
498 _CASSERT((SC_AV & SCIDX_MASK) == SCIDX_AV);
499 _CASSERT((SC_RV & SCIDX_MASK) == SCIDX_RV);
500 _CASSERT((SC_VI & SCIDX_MASK) == SCIDX_VI);
501 _CASSERT((SC_SIG & SCIDX_MASK) == SCIDX_SIG);
502 _CASSERT((SC_VO & SCIDX_MASK) == SCIDX_VO);
503 _CASSERT((SC_CTL & SCIDX_MASK) == SCIDX_CTL);
504
505 /* default rule should never be garbage collected */
506 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
507 pf_default_rule.action = PF_PASS;
508 pf_default_rule.nr = -1;
509 pf_default_rule.rtableid = IFSCOPE_NONE;
510
511 /* initialize default timeouts */
512 t[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
513 t[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
514 t[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
515 t[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
516 t[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
517 t[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
518 t[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
519 t[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
520 t[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
521 t[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
522 t[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
523 t[PFTM_GREv1_FIRST_PACKET] = PFTM_GREv1_FIRST_PACKET_VAL;
524 t[PFTM_GREv1_INITIATING] = PFTM_GREv1_INITIATING_VAL;
525 t[PFTM_GREv1_ESTABLISHED] = PFTM_GREv1_ESTABLISHED_VAL;
526 t[PFTM_ESP_FIRST_PACKET] = PFTM_ESP_FIRST_PACKET_VAL;
527 t[PFTM_ESP_INITIATING] = PFTM_ESP_INITIATING_VAL;
528 t[PFTM_ESP_ESTABLISHED] = PFTM_ESP_ESTABLISHED_VAL;
529 t[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
530 t[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
531 t[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
532 t[PFTM_FRAG] = PFTM_FRAG_VAL;
533 t[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
534 t[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
535 t[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
536 t[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
537 t[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
538
539 pf_normalize_init();
540 bzero(&pf_status, sizeof(pf_status));
541 pf_status.debug = PF_DEBUG_URGENT;
542 pf_hash_seed = RandomULong();
543
544 /* XXX do our best to avoid a conflict */
545 pf_status.hostid = random();
546
547 if (kernel_thread_start(pf_purge_thread_fn, NULL,
548 &pf_purge_thread) != 0) {
549 printf("%s: unable to start purge thread!", __func__);
550 return;
551 }
552
553 maj = cdevsw_add(PF_CDEV_MAJOR, &pf_cdevsw);
554 if (maj == -1) {
555 printf("%s: failed to allocate major number!\n", __func__);
556 return;
557 }
558 (void) devfs_make_node(makedev(maj, PFDEV_PF), DEVFS_CHAR,
559 UID_ROOT, GID_WHEEL, 0600, "pf");
560
561 (void) devfs_make_node(makedev(maj, PFDEV_PFM), DEVFS_CHAR,
562 UID_ROOT, GID_WHEEL, 0600, "pfm");
563
564 pf_attach_hooks();
565 #if DUMMYNET
566 dummynet_init();
567 #endif
568 }
569
570 #if 0
571 static void
572 pfdetach(void)
573 {
574 struct pf_anchor *anchor;
575 struct pf_state *state;
576 struct pf_src_node *node;
577 struct pfioc_table pt;
578 u_int32_t ticket;
579 int i;
580 char r = '\0';
581
582 pf_detach_hooks();
583
584 pf_status.running = 0;
585 wakeup(pf_purge_thread_fn);
586
587 /* clear the rulesets */
588 for (i = 0; i < PF_RULESET_MAX; i++) {
589 if (pf_begin_rules(&ticket, i, &r) == 0) {
590 pf_commit_rules(ticket, i, &r);
591 }
592 }
593
594 /* clear states */
595 RB_FOREACH(state, pf_state_tree_id, &tree_id) {
596 state->timeout = PFTM_PURGE;
597 #if NPFSYNC
598 state->sync_flags = PFSTATE_NOSYNC;
599 #endif
600 }
601 pf_purge_expired_states(pf_status.states);
602
603 #if NPFSYNC
604 pfsync_clear_states(pf_status.hostid, NULL);
605 #endif
606
607 /* clear source nodes */
608 RB_FOREACH(state, pf_state_tree_id, &tree_id) {
609 state->src_node = NULL;
610 state->nat_src_node = NULL;
611 }
612 RB_FOREACH(node, pf_src_tree, &tree_src_tracking) {
613 node->expire = 1;
614 node->states = 0;
615 }
616 pf_purge_expired_src_nodes();
617
618 /* clear tables */
619 memset(&pt, '\0', sizeof(pt));
620 pfr_clr_tables(&pt.pfrio_table, &pt.pfrio_ndel, pt.pfrio_flags);
621
622 /* destroy anchors */
623 while ((anchor = RB_MIN(pf_anchor_global, &pf_anchors)) != NULL) {
624 for (i = 0; i < PF_RULESET_MAX; i++) {
625 if (pf_begin_rules(&ticket, i, anchor->name) == 0) {
626 pf_commit_rules(ticket, i, anchor->name);
627 }
628 }
629 }
630
631 /* destroy main ruleset */
632 pf_remove_if_empty_ruleset(&pf_main_ruleset);
633
634 /* destroy the pools */
635 pool_destroy(&pf_pooladdr_pl);
636 pool_destroy(&pf_state_pl);
637 pool_destroy(&pf_rule_pl);
638 pool_destroy(&pf_src_tree_pl);
639
640 /* destroy subsystems */
641 pf_normalize_destroy();
642 pf_osfp_destroy();
643 pfr_destroy();
644 pfi_destroy();
645 }
646 #endif
647
648 static int
pfopen(dev_t dev,int flags,int fmt,struct proc * p)649 pfopen(dev_t dev, int flags, int fmt, struct proc *p)
650 {
651 #pragma unused(flags, fmt, p)
652 if (minor(dev) >= PFDEV_MAX) {
653 return ENXIO;
654 }
655
656 if (minor(dev) == PFDEV_PFM) {
657 lck_mtx_lock(&pf_lock);
658 if (pfdevcnt != 0) {
659 lck_mtx_unlock(&pf_lock);
660 return EBUSY;
661 }
662 pfdevcnt++;
663 lck_mtx_unlock(&pf_lock);
664 }
665 return 0;
666 }
667
668 static int
pfclose(dev_t dev,int flags,int fmt,struct proc * p)669 pfclose(dev_t dev, int flags, int fmt, struct proc *p)
670 {
671 #pragma unused(flags, fmt, p)
672 if (minor(dev) >= PFDEV_MAX) {
673 return ENXIO;
674 }
675
676 if (minor(dev) == PFDEV_PFM) {
677 lck_mtx_lock(&pf_lock);
678 VERIFY(pfdevcnt > 0);
679 pfdevcnt--;
680 lck_mtx_unlock(&pf_lock);
681 }
682 return 0;
683 }
684
685 static 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)686 pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action,
687 u_int32_t rule_number, u_int8_t r_last, u_int8_t active,
688 u_int8_t check_ticket)
689 {
690 struct pf_ruleset *ruleset;
691 struct pf_rule *rule;
692 int rs_num;
693 struct pf_pool *p = NULL;
694
695 ruleset = pf_find_ruleset(anchor);
696 if (ruleset == NULL) {
697 goto done;
698 }
699 rs_num = pf_get_ruleset_number(rule_action);
700 if (rs_num >= PF_RULESET_MAX) {
701 goto done;
702 }
703 if (active) {
704 if (check_ticket && ticket !=
705 ruleset->rules[rs_num].active.ticket) {
706 goto done;
707 }
708 if (r_last) {
709 rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
710 pf_rulequeue);
711 } else {
712 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
713 }
714 } else {
715 if (check_ticket && ticket !=
716 ruleset->rules[rs_num].inactive.ticket) {
717 goto done;
718 }
719 if (r_last) {
720 rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
721 pf_rulequeue);
722 } else {
723 rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
724 }
725 }
726 if (!r_last) {
727 while ((rule != NULL) && (rule->nr != rule_number)) {
728 rule = TAILQ_NEXT(rule, entries);
729 }
730 }
731 if (rule == NULL) {
732 goto done;
733 }
734
735 p = &rule->rpool;
736 done:
737
738 if (ruleset) {
739 pf_release_ruleset(ruleset);
740 ruleset = NULL;
741 }
742
743 return p;
744 }
745
746 static void
pf_mv_pool(struct pf_palist * poola,struct pf_palist * poolb)747 pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
748 {
749 struct pf_pooladdr *mv_pool_pa;
750
751 while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
752 TAILQ_REMOVE(poola, mv_pool_pa, entries);
753 TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
754 }
755 }
756
757 static void
pf_empty_pool(struct pf_palist * poola)758 pf_empty_pool(struct pf_palist *poola)
759 {
760 struct pf_pooladdr *empty_pool_pa;
761
762 while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
763 pfi_dynaddr_remove(&empty_pool_pa->addr);
764 pf_tbladdr_remove(&empty_pool_pa->addr);
765 pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE);
766 TAILQ_REMOVE(poola, empty_pool_pa, entries);
767 pool_put(&pf_pooladdr_pl, empty_pool_pa);
768 }
769 }
770
771 void
pf_rm_rule(struct pf_rulequeue * rulequeue,struct pf_rule * rule)772 pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
773 {
774 if (rulequeue != NULL) {
775 if (rule->states <= 0) {
776 /*
777 * XXX - we need to remove the table *before* detaching
778 * the rule to make sure the table code does not delete
779 * the anchor under our feet.
780 */
781 pf_tbladdr_remove(&rule->src.addr);
782 pf_tbladdr_remove(&rule->dst.addr);
783 if (rule->overload_tbl) {
784 pfr_detach_table(rule->overload_tbl);
785 }
786 }
787 TAILQ_REMOVE(rulequeue, rule, entries);
788 rule->entries.tqe_prev = NULL;
789 rule->nr = -1;
790 }
791
792 if (rule->states > 0 || rule->src_nodes > 0 ||
793 rule->entries.tqe_prev != NULL) {
794 return;
795 }
796 pf_tag_unref(rule->tag);
797 pf_tag_unref(rule->match_tag);
798 pf_rtlabel_remove(&rule->src.addr);
799 pf_rtlabel_remove(&rule->dst.addr);
800 pfi_dynaddr_remove(&rule->src.addr);
801 pfi_dynaddr_remove(&rule->dst.addr);
802 if (rulequeue == NULL) {
803 pf_tbladdr_remove(&rule->src.addr);
804 pf_tbladdr_remove(&rule->dst.addr);
805 if (rule->overload_tbl) {
806 pfr_detach_table(rule->overload_tbl);
807 }
808 }
809 pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
810 pf_anchor_remove(rule);
811 pf_empty_pool(&rule->rpool.list);
812 pool_put(&pf_rule_pl, rule);
813 }
814
815 static u_int16_t
tagname2tag(struct pf_tags * head,char * tagname)816 tagname2tag(struct pf_tags *head, char *tagname)
817 {
818 struct pf_tagname *tag, *p = NULL;
819 uint16_t new_tagid = 1;
820 bool reserved_tag = false;
821
822 TAILQ_FOREACH(tag, head, entries)
823 if (strcmp(tagname, tag->name) == 0) {
824 tag->ref++;
825 return tag->tag;
826 }
827
828 /*
829 * check if it is a reserved tag.
830 */
831 _CASSERT(RESERVED_TAG_ID_MIN > DYNAMIC_TAG_ID_MAX);
832 for (int i = 0; i < NUM_RESERVED_TAGS; i++) {
833 if (strncmp(tagname, pf_reserved_tag_table[i].tag_name,
834 PF_TAG_NAME_SIZE) == 0) {
835 new_tagid = pf_reserved_tag_table[i].tag_id;
836 reserved_tag = true;
837 goto skip_dynamic_tag_alloc;
838 }
839 }
840
841 /*
842 * to avoid fragmentation, we do a linear search from the beginning
843 * and take the first free slot we find. if there is none or the list
844 * is empty, append a new entry at the end.
845 */
846
847 /* new entry */
848 if (!TAILQ_EMPTY(head)) {
849 /* skip reserved tags */
850 for (p = TAILQ_FIRST(head); p != NULL &&
851 p->tag >= RESERVED_TAG_ID_MIN;
852 p = TAILQ_NEXT(p, entries)) {
853 ;
854 }
855
856 for (; p != NULL && p->tag == new_tagid;
857 p = TAILQ_NEXT(p, entries)) {
858 new_tagid = p->tag + 1;
859 }
860 }
861
862 if (new_tagid > DYNAMIC_TAG_ID_MAX) {
863 return 0;
864 }
865
866 skip_dynamic_tag_alloc:
867 /* allocate and fill new struct pf_tagname */
868 tag = kalloc_type(struct pf_tagname, Z_WAITOK | Z_ZERO | Z_NOFAIL);
869 strlcpy(tag->name, tagname, sizeof(tag->name));
870 tag->tag = new_tagid;
871 tag->ref++;
872
873 if (reserved_tag) { /* insert reserved tag at the head */
874 TAILQ_INSERT_HEAD(head, tag, entries);
875 } else if (p != NULL) { /* insert new entry before p */
876 TAILQ_INSERT_BEFORE(p, tag, entries);
877 } else { /* either list empty or no free slot in between */
878 TAILQ_INSERT_TAIL(head, tag, entries);
879 }
880
881 return tag->tag;
882 }
883
884 static void
tag_unref(struct pf_tags * head,u_int16_t tag)885 tag_unref(struct pf_tags *head, u_int16_t tag)
886 {
887 struct pf_tagname *p, *next;
888
889 if (tag == 0) {
890 return;
891 }
892
893 for (p = TAILQ_FIRST(head); p != NULL; p = next) {
894 next = TAILQ_NEXT(p, entries);
895 if (tag == p->tag) {
896 if (--p->ref == 0) {
897 TAILQ_REMOVE(head, p, entries);
898 kfree_type(struct pf_tagname, p);
899 }
900 break;
901 }
902 }
903 }
904
905 u_int16_t
pf_tagname2tag(char * tagname)906 pf_tagname2tag(char *tagname)
907 {
908 return tagname2tag(&pf_tags, tagname);
909 }
910
911 u_int16_t
pf_tagname2tag_ext(char * tagname)912 pf_tagname2tag_ext(char *tagname)
913 {
914 u_int16_t tag;
915
916 lck_rw_lock_exclusive(&pf_perim_lock);
917 lck_mtx_lock(&pf_lock);
918 tag = pf_tagname2tag(tagname);
919 lck_mtx_unlock(&pf_lock);
920 lck_rw_done(&pf_perim_lock);
921 return tag;
922 }
923
924 void
pf_tag_ref(u_int16_t tag)925 pf_tag_ref(u_int16_t tag)
926 {
927 struct pf_tagname *t;
928
929 TAILQ_FOREACH(t, &pf_tags, entries)
930 if (t->tag == tag) {
931 break;
932 }
933 if (t != NULL) {
934 t->ref++;
935 }
936 }
937
938 void
pf_tag_unref(u_int16_t tag)939 pf_tag_unref(u_int16_t tag)
940 {
941 tag_unref(&pf_tags, tag);
942 }
943
944 static int
pf_rtlabel_add(struct pf_addr_wrap * a)945 pf_rtlabel_add(struct pf_addr_wrap *a)
946 {
947 #pragma unused(a)
948 return 0;
949 }
950
951 static void
pf_rtlabel_remove(struct pf_addr_wrap * a)952 pf_rtlabel_remove(struct pf_addr_wrap *a)
953 {
954 #pragma unused(a)
955 }
956
957 static void
pf_rtlabel_copyout(struct pf_addr_wrap * a)958 pf_rtlabel_copyout(struct pf_addr_wrap *a)
959 {
960 #pragma unused(a)
961 }
962
963 static int
pf_begin_rules(u_int32_t * ticket,int rs_num,const char * anchor)964 pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor)
965 {
966 struct pf_ruleset *rs;
967 struct pf_rule *rule;
968
969 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) {
970 return EINVAL;
971 }
972 rs = pf_find_or_create_ruleset(anchor);
973 if (rs == NULL) {
974 return EINVAL;
975 }
976 while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
977 pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
978 rs->rules[rs_num].inactive.rcount--;
979 }
980 *ticket = ++rs->rules[rs_num].inactive.ticket;
981 rs->rules[rs_num].inactive.open = 1;
982 pf_release_ruleset(rs);
983 rs = NULL;
984 return 0;
985 }
986
987 static int
pf_rollback_rules(u_int32_t ticket,int rs_num,char * anchor)988 pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor)
989 {
990 struct pf_ruleset *rs = NULL;
991 struct pf_rule *rule;
992 int err = 0;
993
994 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) {
995 err = EINVAL;
996 goto done;
997 }
998 rs = pf_find_ruleset(anchor);
999 if (rs == NULL || !rs->rules[rs_num].inactive.open ||
1000 rs->rules[rs_num].inactive.ticket != ticket) {
1001 goto done;
1002 }
1003 while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
1004 pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
1005 rs->rules[rs_num].inactive.rcount--;
1006 }
1007 rs->rules[rs_num].inactive.open = 0;
1008
1009 done:
1010 if (rs) {
1011 pf_release_ruleset(rs);
1012 rs = NULL;
1013 }
1014 return err;
1015 }
1016
1017 #define PF_MD5_UPD(st, elm) \
1018 MD5Update(ctx, (u_int8_t *)&(st)->elm, sizeof ((st)->elm))
1019
1020 #define PF_MD5_UPD_STR(st, elm) \
1021 MD5Update(ctx, (u_int8_t *)(st)->elm, (unsigned int)strlen((st)->elm))
1022
1023 #define PF_MD5_UPD_HTONL(st, elm, stor) do { \
1024 (stor) = htonl((st)->elm); \
1025 MD5Update(ctx, (u_int8_t *)&(stor), sizeof (u_int32_t)); \
1026 } while (0)
1027
1028 #define PF_MD5_UPD_HTONS(st, elm, stor) do { \
1029 (stor) = htons((st)->elm); \
1030 MD5Update(ctx, (u_int8_t *)&(stor), sizeof (u_int16_t)); \
1031 } while (0)
1032
1033 static void
pf_hash_rule_addr(MD5_CTX * ctx,struct pf_rule_addr * pfr,u_int8_t proto)1034 pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr, u_int8_t proto)
1035 {
1036 PF_MD5_UPD(pfr, addr.type);
1037 switch (pfr->addr.type) {
1038 case PF_ADDR_DYNIFTL:
1039 PF_MD5_UPD(pfr, addr.v.ifname);
1040 PF_MD5_UPD(pfr, addr.iflags);
1041 break;
1042 case PF_ADDR_TABLE:
1043 PF_MD5_UPD(pfr, addr.v.tblname);
1044 break;
1045 case PF_ADDR_ADDRMASK:
1046 /* XXX ignore af? */
1047 PF_MD5_UPD(pfr, addr.v.a.addr.addr32);
1048 PF_MD5_UPD(pfr, addr.v.a.mask.addr32);
1049 break;
1050 case PF_ADDR_RTLABEL:
1051 PF_MD5_UPD(pfr, addr.v.rtlabelname);
1052 break;
1053 }
1054
1055 switch (proto) {
1056 case IPPROTO_TCP:
1057 case IPPROTO_UDP:
1058 PF_MD5_UPD(pfr, xport.range.port[0]);
1059 PF_MD5_UPD(pfr, xport.range.port[1]);
1060 PF_MD5_UPD(pfr, xport.range.op);
1061 break;
1062
1063 default:
1064 break;
1065 }
1066
1067 PF_MD5_UPD(pfr, neg);
1068 }
1069
1070 static void
pf_hash_rule(MD5_CTX * ctx,struct pf_rule * rule)1071 pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule)
1072 {
1073 u_int16_t x;
1074 u_int32_t y;
1075
1076 pf_hash_rule_addr(ctx, &rule->src, rule->proto);
1077 pf_hash_rule_addr(ctx, &rule->dst, rule->proto);
1078 PF_MD5_UPD_STR(rule, label);
1079 PF_MD5_UPD_STR(rule, ifname);
1080 PF_MD5_UPD_STR(rule, match_tagname);
1081 PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
1082 PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
1083 PF_MD5_UPD_HTONL(rule, prob, y);
1084 PF_MD5_UPD_HTONL(rule, uid.uid[0], y);
1085 PF_MD5_UPD_HTONL(rule, uid.uid[1], y);
1086 PF_MD5_UPD(rule, uid.op);
1087 PF_MD5_UPD_HTONL(rule, gid.gid[0], y);
1088 PF_MD5_UPD_HTONL(rule, gid.gid[1], y);
1089 PF_MD5_UPD(rule, gid.op);
1090 PF_MD5_UPD_HTONL(rule, rule_flag, y);
1091 PF_MD5_UPD(rule, action);
1092 PF_MD5_UPD(rule, direction);
1093 PF_MD5_UPD(rule, af);
1094 PF_MD5_UPD(rule, quick);
1095 PF_MD5_UPD(rule, ifnot);
1096 PF_MD5_UPD(rule, match_tag_not);
1097 PF_MD5_UPD(rule, natpass);
1098 PF_MD5_UPD(rule, keep_state);
1099 PF_MD5_UPD(rule, proto);
1100 PF_MD5_UPD(rule, type);
1101 PF_MD5_UPD(rule, code);
1102 PF_MD5_UPD(rule, flags);
1103 PF_MD5_UPD(rule, flagset);
1104 PF_MD5_UPD(rule, allow_opts);
1105 PF_MD5_UPD(rule, rt);
1106 PF_MD5_UPD(rule, tos);
1107 }
1108
1109 static int
pf_commit_rules(u_int32_t ticket,int rs_num,char * anchor)1110 pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
1111 {
1112 struct pf_ruleset *rs = NULL;
1113 struct pf_rule *rule, **old_array, *r;
1114 struct pf_rulequeue *old_rules;
1115 int error = 0;
1116 u_int32_t old_rcount;
1117 u_int32_t old_rsize;
1118
1119 LCK_MTX_ASSERT(&pf_lock, LCK_MTX_ASSERT_OWNED);
1120
1121 if (rs_num < 0 || rs_num >= PF_RULESET_MAX) {
1122 error = EINVAL;
1123 goto done;
1124 }
1125 rs = pf_find_ruleset(anchor);
1126 if (rs == NULL || !rs->rules[rs_num].inactive.open ||
1127 ticket != rs->rules[rs_num].inactive.ticket) {
1128 error = EBUSY;
1129 goto done;
1130 }
1131
1132 /* Calculate checksum for the main ruleset */
1133 if (rs == &pf_main_ruleset) {
1134 error = pf_setup_pfsync_matching(rs);
1135 if (error != 0) {
1136 goto done;
1137 }
1138 }
1139
1140 /* Swap rules, keep the old. */
1141 old_rules = rs->rules[rs_num].active.ptr;
1142 old_rcount = rs->rules[rs_num].active.rcount;
1143 old_rsize = rs->rules[rs_num].active.rsize;
1144 old_array = rs->rules[rs_num].active.ptr_array;
1145
1146 if (old_rcount != 0) {
1147 r = TAILQ_FIRST(rs->rules[rs_num].active.ptr);
1148 while (r) {
1149 if (r->rule_flag & PFRULE_PFM) {
1150 pffwrules--;
1151 }
1152 r = TAILQ_NEXT(r, entries);
1153 }
1154 }
1155
1156
1157 rs->rules[rs_num].active.ptr =
1158 rs->rules[rs_num].inactive.ptr;
1159 rs->rules[rs_num].active.ptr_array =
1160 rs->rules[rs_num].inactive.ptr_array;
1161 rs->rules[rs_num].active.rsize =
1162 rs->rules[rs_num].inactive.rsize;
1163 rs->rules[rs_num].active.rcount =
1164 rs->rules[rs_num].inactive.rcount;
1165 rs->rules[rs_num].inactive.ptr = old_rules;
1166 rs->rules[rs_num].inactive.ptr_array = old_array;
1167 rs->rules[rs_num].inactive.rcount = old_rcount;
1168 rs->rules[rs_num].inactive.rsize = old_rsize;
1169
1170 rs->rules[rs_num].active.ticket =
1171 rs->rules[rs_num].inactive.ticket;
1172 pf_calc_skip_steps(rs->rules[rs_num].active.ptr);
1173
1174
1175 /* Purge the old rule list. */
1176 while ((rule = TAILQ_FIRST(old_rules)) != NULL) {
1177 pf_rm_rule(old_rules, rule);
1178 }
1179 kfree_type(struct pf_rule *, rs->rules[rs_num].inactive.rsize,
1180 rs->rules[rs_num].inactive.ptr_array);
1181 rs->rules[rs_num].inactive.ptr_array = NULL;
1182 rs->rules[rs_num].inactive.rcount = 0;
1183 rs->rules[rs_num].inactive.rsize = 0;
1184 rs->rules[rs_num].inactive.open = 0;
1185
1186 done:
1187 if (rs) {
1188 pf_release_ruleset(rs);
1189 }
1190 return error;
1191 }
1192
1193 static void
pf_rule_copyin(struct pf_rule * src,struct pf_rule * dst,struct proc * p,int minordev)1194 pf_rule_copyin(struct pf_rule *src, struct pf_rule *dst, struct proc *p,
1195 int minordev)
1196 {
1197 bcopy(src, dst, sizeof(struct pf_rule));
1198
1199 dst->label[sizeof(dst->label) - 1] = '\0';
1200 dst->ifname[sizeof(dst->ifname) - 1] = '\0';
1201 dst->qname[sizeof(dst->qname) - 1] = '\0';
1202 dst->pqname[sizeof(dst->pqname) - 1] = '\0';
1203 dst->tagname[sizeof(dst->tagname) - 1] = '\0';
1204 dst->match_tagname[sizeof(dst->match_tagname) - 1] = '\0';
1205 dst->overload_tblname[sizeof(dst->overload_tblname) - 1] = '\0';
1206 dst->owner[sizeof(dst->owner) - 1] = '\0';
1207
1208 dst->cuid = kauth_cred_getuid(kauth_cred_get());
1209 dst->cpid = proc_getpid(p);
1210
1211 dst->anchor = NULL;
1212 dst->kif = NULL;
1213 dst->overload_tbl = NULL;
1214
1215 TAILQ_INIT(&dst->rpool.list);
1216 dst->rpool.cur = NULL;
1217
1218 /* initialize refcounting */
1219 dst->states = 0;
1220 dst->src_nodes = 0;
1221
1222 dst->entries.tqe_prev = NULL;
1223 dst->entries.tqe_next = NULL;
1224 if ((uint8_t)minordev == PFDEV_PFM) {
1225 dst->rule_flag |= PFRULE_PFM;
1226 }
1227 }
1228
1229 static void
pf_rule_copyout(struct pf_rule * src,struct pf_rule * dst)1230 pf_rule_copyout(struct pf_rule *src, struct pf_rule *dst)
1231 {
1232 bcopy(src, dst, sizeof(struct pf_rule));
1233
1234 dst->anchor = NULL;
1235 dst->kif = NULL;
1236 dst->overload_tbl = NULL;
1237
1238 dst->rpool.list.tqh_first = NULL;
1239 dst->rpool.list.tqh_last = NULL;
1240 dst->rpool.cur = NULL;
1241
1242 dst->entries.tqe_prev = NULL;
1243 dst->entries.tqe_next = NULL;
1244 }
1245
1246 static void
pf_state_export(struct pfsync_state * sp,struct pf_state_key * sk,struct pf_state * s)1247 pf_state_export(struct pfsync_state *sp, struct pf_state_key *sk,
1248 struct pf_state *s)
1249 {
1250 uint64_t secs = pf_time_second();
1251 bzero(sp, sizeof(struct pfsync_state));
1252
1253 /* copy from state key */
1254 sp->lan.addr = sk->lan.addr;
1255 sp->lan.xport = sk->lan.xport;
1256 sp->gwy.addr = sk->gwy.addr;
1257 sp->gwy.xport = sk->gwy.xport;
1258 sp->ext_lan.addr = sk->ext_lan.addr;
1259 sp->ext_lan.xport = sk->ext_lan.xport;
1260 sp->ext_gwy.addr = sk->ext_gwy.addr;
1261 sp->ext_gwy.xport = sk->ext_gwy.xport;
1262 sp->proto_variant = sk->proto_variant;
1263 sp->tag = s->tag;
1264 sp->proto = sk->proto;
1265 sp->af_lan = sk->af_lan;
1266 sp->af_gwy = sk->af_gwy;
1267 sp->direction = sk->direction;
1268 sp->flowhash = sk->flowhash;
1269
1270 /* copy from state */
1271 memcpy(&sp->id, &s->id, sizeof(sp->id));
1272 sp->creatorid = s->creatorid;
1273 strlcpy(sp->ifname, s->kif->pfik_name, sizeof(sp->ifname));
1274 pf_state_peer_to_pfsync(&s->src, &sp->src);
1275 pf_state_peer_to_pfsync(&s->dst, &sp->dst);
1276
1277 sp->rule = s->rule.ptr->nr;
1278 sp->nat_rule = (s->nat_rule.ptr == NULL) ?
1279 (unsigned)-1 : s->nat_rule.ptr->nr;
1280 sp->anchor = (s->anchor.ptr == NULL) ?
1281 (unsigned)-1 : s->anchor.ptr->nr;
1282
1283 pf_state_counter_to_pfsync(s->bytes[0], sp->bytes[0]);
1284 pf_state_counter_to_pfsync(s->bytes[1], sp->bytes[1]);
1285 pf_state_counter_to_pfsync(s->packets[0], sp->packets[0]);
1286 pf_state_counter_to_pfsync(s->packets[1], sp->packets[1]);
1287 sp->creation = secs - s->creation;
1288 sp->expire = pf_state_expires(s);
1289 sp->log = s->log;
1290 sp->allow_opts = s->allow_opts;
1291 sp->timeout = s->timeout;
1292
1293 if (s->src_node) {
1294 sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
1295 }
1296 if (s->nat_src_node) {
1297 sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
1298 }
1299
1300 if (sp->expire > secs) {
1301 sp->expire -= secs;
1302 } else {
1303 sp->expire = 0;
1304 }
1305 }
1306
1307 static void
pf_state_import(struct pfsync_state * sp,struct pf_state_key * sk,struct pf_state * s)1308 pf_state_import(struct pfsync_state *sp, struct pf_state_key *sk,
1309 struct pf_state *s)
1310 {
1311 /* copy to state key */
1312 sk->lan.addr = sp->lan.addr;
1313 sk->lan.xport = sp->lan.xport;
1314 sk->gwy.addr = sp->gwy.addr;
1315 sk->gwy.xport = sp->gwy.xport;
1316 sk->ext_lan.addr = sp->ext_lan.addr;
1317 sk->ext_lan.xport = sp->ext_lan.xport;
1318 sk->ext_gwy.addr = sp->ext_gwy.addr;
1319 sk->ext_gwy.xport = sp->ext_gwy.xport;
1320 sk->proto_variant = sp->proto_variant;
1321 s->tag = sp->tag;
1322 sk->proto = sp->proto;
1323 sk->af_lan = sp->af_lan;
1324 sk->af_gwy = sp->af_gwy;
1325 sk->direction = sp->direction;
1326 ASSERT(sk->flowsrc == FLOWSRC_PF);
1327 ASSERT(sk->flowhash != 0);
1328
1329 /* copy to state */
1330 memcpy(&s->id, &sp->id, sizeof(sp->id));
1331 s->creatorid = sp->creatorid;
1332 pf_state_peer_from_pfsync(&sp->src, &s->src);
1333 pf_state_peer_from_pfsync(&sp->dst, &s->dst);
1334
1335 s->rule.ptr = &pf_default_rule;
1336 s->nat_rule.ptr = NULL;
1337 s->anchor.ptr = NULL;
1338 s->rt_kif = NULL;
1339 s->creation = pf_time_second();
1340 s->expire = pf_time_second();
1341 if (sp->expire > 0) {
1342 s->expire -= pf_default_rule.timeout[sp->timeout] - sp->expire;
1343 }
1344 s->pfsync_time = 0;
1345 s->packets[0] = s->packets[1] = 0;
1346 s->bytes[0] = s->bytes[1] = 0;
1347 }
1348
1349 static void
pf_pooladdr_copyin(struct pf_pooladdr * src,struct pf_pooladdr * dst)1350 pf_pooladdr_copyin(struct pf_pooladdr *src, struct pf_pooladdr *dst)
1351 {
1352 bcopy(src, dst, sizeof(struct pf_pooladdr));
1353
1354 dst->entries.tqe_prev = NULL;
1355 dst->entries.tqe_next = NULL;
1356 dst->ifname[sizeof(dst->ifname) - 1] = '\0';
1357 dst->kif = NULL;
1358 }
1359
1360 static void
pf_pooladdr_copyout(struct pf_pooladdr * src,struct pf_pooladdr * dst)1361 pf_pooladdr_copyout(struct pf_pooladdr *src, struct pf_pooladdr *dst)
1362 {
1363 bcopy(src, dst, sizeof(struct pf_pooladdr));
1364
1365 dst->entries.tqe_prev = NULL;
1366 dst->entries.tqe_next = NULL;
1367 dst->kif = NULL;
1368 }
1369
1370 static int
pf_setup_pfsync_matching(struct pf_ruleset * rs)1371 pf_setup_pfsync_matching(struct pf_ruleset *rs)
1372 {
1373 MD5_CTX ctx;
1374 struct pf_rule *rule;
1375 int rs_cnt;
1376 u_int8_t digest[PF_MD5_DIGEST_LENGTH];
1377
1378 MD5Init(&ctx);
1379 for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) {
1380 /* XXX PF_RULESET_SCRUB as well? */
1381 if (rs_cnt == PF_RULESET_SCRUB) {
1382 continue;
1383 }
1384
1385 rs->rules[rs_cnt].inactive.ptr_array = krealloc_type(struct pf_rule *,
1386 rs->rules[rs_cnt].inactive.rsize, rs->rules[rs_cnt].inactive.rcount,
1387 rs->rules[rs_cnt].inactive.ptr_array, Z_WAITOK | Z_REALLOCF);
1388
1389 if (rs->rules[rs_cnt].inactive.rcount &&
1390 !rs->rules[rs_cnt].inactive.ptr_array) {
1391 rs->rules[rs_cnt].inactive.rsize = 0;
1392 return ENOMEM;
1393 }
1394 rs->rules[rs_cnt].inactive.rsize =
1395 rs->rules[rs_cnt].inactive.rcount;
1396
1397 TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
1398 entries) {
1399 pf_hash_rule(&ctx, rule);
1400 (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
1401 }
1402 }
1403
1404 MD5Final(digest, &ctx);
1405 memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum));
1406 return 0;
1407 }
1408
1409 static void
pf_start(void)1410 pf_start(void)
1411 {
1412 LCK_MTX_ASSERT(&pf_lock, LCK_MTX_ASSERT_OWNED);
1413
1414 VERIFY(pf_is_enabled == 0);
1415
1416 pf_is_enabled = 1;
1417 pf_status.running = 1;
1418 pf_status.since = pf_calendar_time_second();
1419 if (pf_status.stateid == 0) {
1420 pf_status.stateid = pf_time_second();
1421 pf_status.stateid = pf_status.stateid << 32;
1422 }
1423 wakeup(pf_purge_thread_fn);
1424 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
1425 pf_process_compatibilities();
1426 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
1427 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
1428 }
1429
1430 static void
pf_stop(void)1431 pf_stop(void)
1432 {
1433 LCK_MTX_ASSERT(&pf_lock, LCK_MTX_ASSERT_OWNED);
1434
1435 VERIFY(pf_is_enabled);
1436
1437 pf_status.running = 0;
1438 pf_is_enabled = 0;
1439 pf_status.since = pf_calendar_time_second();
1440 wakeup(pf_purge_thread_fn);
1441 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
1442 pf_process_compatibilities();
1443 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
1444 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
1445 }
1446
1447 static int
pfioctl(dev_t dev,u_long cmd,caddr_t addr,int flags,struct proc * p)1448 pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
1449 {
1450 #pragma unused(dev)
1451 int p64 = proc_is64bit(p);
1452 int error = 0;
1453 int minordev = minor(dev);
1454
1455 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
1456 return EPERM;
1457 }
1458
1459 /* XXX keep in sync with switch() below */
1460 if (securelevel > 1) {
1461 switch (cmd) {
1462 case DIOCGETRULES:
1463 case DIOCGETRULE:
1464 case DIOCGETADDRS:
1465 case DIOCGETADDR:
1466 case DIOCGETSTATE:
1467 case DIOCSETSTATUSIF:
1468 case DIOCGETSTATUS:
1469 case DIOCCLRSTATUS:
1470 case DIOCNATLOOK:
1471 case DIOCSETDEBUG:
1472 case DIOCGETSTATES:
1473 case DIOCINSERTRULE:
1474 case DIOCDELETERULE:
1475 case DIOCGETTIMEOUT:
1476 case DIOCCLRRULECTRS:
1477 case DIOCGETLIMIT:
1478 case DIOCGETALTQS:
1479 case DIOCGETALTQ:
1480 case DIOCGETQSTATS:
1481 case DIOCGETRULESETS:
1482 case DIOCGETRULESET:
1483 case DIOCRGETTABLES:
1484 case DIOCRGETTSTATS:
1485 case DIOCRCLRTSTATS:
1486 case DIOCRCLRADDRS:
1487 case DIOCRADDADDRS:
1488 case DIOCRDELADDRS:
1489 case DIOCRSETADDRS:
1490 case DIOCRGETADDRS:
1491 case DIOCRGETASTATS:
1492 case DIOCRCLRASTATS:
1493 case DIOCRTSTADDRS:
1494 case DIOCOSFPGET:
1495 case DIOCGETSRCNODES:
1496 case DIOCCLRSRCNODES:
1497 case DIOCIGETIFACES:
1498 case DIOCGIFSPEED:
1499 case DIOCSETIFFLAG:
1500 case DIOCCLRIFFLAG:
1501 break;
1502 case DIOCRCLRTABLES:
1503 case DIOCRADDTABLES:
1504 case DIOCRDELTABLES:
1505 case DIOCRSETTFLAGS: {
1506 int pfrio_flags;
1507
1508 bcopy(&((struct pfioc_table *)(void *)addr)->
1509 pfrio_flags, &pfrio_flags, sizeof(pfrio_flags));
1510
1511 if (pfrio_flags & PFR_FLAG_DUMMY) {
1512 break; /* dummy operation ok */
1513 }
1514 return EPERM;
1515 }
1516 default:
1517 return EPERM;
1518 }
1519 }
1520
1521 if (!(flags & FWRITE)) {
1522 switch (cmd) {
1523 case DIOCSTART:
1524 case DIOCSTARTREF:
1525 case DIOCSTOP:
1526 case DIOCSTOPREF:
1527 case DIOCGETSTARTERS:
1528 case DIOCGETRULES:
1529 case DIOCGETADDRS:
1530 case DIOCGETADDR:
1531 case DIOCGETSTATE:
1532 case DIOCGETSTATUS:
1533 case DIOCGETSTATES:
1534 case DIOCINSERTRULE:
1535 case DIOCDELETERULE:
1536 case DIOCGETTIMEOUT:
1537 case DIOCGETLIMIT:
1538 case DIOCGETALTQS:
1539 case DIOCGETALTQ:
1540 case DIOCGETQSTATS:
1541 case DIOCGETRULESETS:
1542 case DIOCGETRULESET:
1543 case DIOCNATLOOK:
1544 case DIOCRGETTABLES:
1545 case DIOCRGETTSTATS:
1546 case DIOCRGETADDRS:
1547 case DIOCRGETASTATS:
1548 case DIOCRTSTADDRS:
1549 case DIOCOSFPGET:
1550 case DIOCGETSRCNODES:
1551 case DIOCIGETIFACES:
1552 case DIOCGIFSPEED:
1553 break;
1554 case DIOCRCLRTABLES:
1555 case DIOCRADDTABLES:
1556 case DIOCRDELTABLES:
1557 case DIOCRCLRTSTATS:
1558 case DIOCRCLRADDRS:
1559 case DIOCRADDADDRS:
1560 case DIOCRDELADDRS:
1561 case DIOCRSETADDRS:
1562 case DIOCRSETTFLAGS: {
1563 int pfrio_flags;
1564
1565 bcopy(&((struct pfioc_table *)(void *)addr)->
1566 pfrio_flags, &pfrio_flags, sizeof(pfrio_flags));
1567
1568 if (pfrio_flags & PFR_FLAG_DUMMY) {
1569 flags |= FWRITE; /* need write lock for dummy */
1570 break; /* dummy operation ok */
1571 }
1572 return EACCES;
1573 }
1574 case DIOCGETRULE: {
1575 u_int32_t action;
1576
1577 bcopy(&((struct pfioc_rule *)(void *)addr)->action,
1578 &action, sizeof(action));
1579
1580 if (action == PF_GET_CLR_CNTR) {
1581 return EACCES;
1582 }
1583 break;
1584 }
1585 default:
1586 return EACCES;
1587 }
1588 }
1589
1590 if (flags & FWRITE) {
1591 lck_rw_lock_exclusive(&pf_perim_lock);
1592 } else {
1593 lck_rw_lock_shared(&pf_perim_lock);
1594 }
1595
1596 lck_mtx_lock(&pf_lock);
1597
1598 switch (cmd) {
1599 case DIOCSTART:
1600 if (pf_status.running) {
1601 /*
1602 * Increment the reference for a simple -e enable, so
1603 * that even if other processes drop their references,
1604 * pf will still be available to processes that turned
1605 * it on without taking a reference
1606 */
1607 if (nr_tokens == pf_enabled_ref_count) {
1608 pf_enabled_ref_count++;
1609 VERIFY(pf_enabled_ref_count != 0);
1610 }
1611 error = EEXIST;
1612 } else if (pf_purge_thread == NULL) {
1613 error = ENOMEM;
1614 } else {
1615 pf_start();
1616 pf_enabled_ref_count++;
1617 VERIFY(pf_enabled_ref_count != 0);
1618 }
1619 break;
1620
1621 case DIOCSTARTREF: /* u_int64_t */
1622 if (pf_purge_thread == NULL) {
1623 error = ENOMEM;
1624 } else {
1625 u_int64_t token;
1626
1627 /* small enough to be on stack */
1628 if ((token = generate_token(p)) != 0) {
1629 if (pf_is_enabled == 0) {
1630 pf_start();
1631 }
1632 pf_enabled_ref_count++;
1633 VERIFY(pf_enabled_ref_count != 0);
1634 } else {
1635 error = ENOMEM;
1636 DPFPRINTF(PF_DEBUG_URGENT,
1637 ("pf: unable to generate token\n"));
1638 }
1639 bcopy(&token, addr, sizeof(token));
1640 }
1641 break;
1642
1643 case DIOCSTOP:
1644 if (!pf_status.running) {
1645 error = ENOENT;
1646 } else {
1647 pf_stop();
1648 pf_enabled_ref_count = 0;
1649 invalidate_all_tokens();
1650 }
1651 break;
1652
1653 case DIOCSTOPREF: /* struct pfioc_remove_token */
1654 if (!pf_status.running) {
1655 error = ENOENT;
1656 } else {
1657 struct pfioc_remove_token pfrt;
1658
1659 /* small enough to be on stack */
1660 bcopy(addr, &pfrt, sizeof(pfrt));
1661 if ((error = remove_token(&pfrt)) == 0) {
1662 VERIFY(pf_enabled_ref_count != 0);
1663 pf_enabled_ref_count--;
1664 /* return currently held references */
1665 pfrt.refcount = pf_enabled_ref_count;
1666 DPFPRINTF(PF_DEBUG_MISC,
1667 ("pf: enabled refcount decremented\n"));
1668 } else {
1669 error = EINVAL;
1670 DPFPRINTF(PF_DEBUG_URGENT,
1671 ("pf: token mismatch\n"));
1672 }
1673 bcopy(&pfrt, addr, sizeof(pfrt));
1674
1675 if (error == 0 && pf_enabled_ref_count == 0) {
1676 pf_stop();
1677 }
1678 }
1679 break;
1680
1681 case DIOCGETSTARTERS: { /* struct pfioc_tokens */
1682 PFIOCX_STRUCT_DECL(pfioc_tokens);
1683
1684 PFIOCX_STRUCT_BEGIN(addr, pfioc_tokens);
1685 error = pfioctl_ioc_tokens(cmd,
1686 PFIOCX_STRUCT_ADDR32(pfioc_tokens),
1687 PFIOCX_STRUCT_ADDR64(pfioc_tokens), p);
1688 PFIOCX_STRUCT_END(pfioc_tokens, addr);
1689 break;
1690 }
1691
1692 case DIOCADDRULE: /* struct pfioc_rule */
1693 case DIOCGETRULES: /* struct pfioc_rule */
1694 case DIOCGETRULE: /* struct pfioc_rule */
1695 case DIOCCHANGERULE: /* struct pfioc_rule */
1696 case DIOCINSERTRULE: /* struct pfioc_rule */
1697 case DIOCDELETERULE: { /* struct pfioc_rule */
1698 struct pfioc_rule *pr = NULL;
1699
1700 PFIOC_STRUCT_BEGIN(addr, pr);
1701 error = pfioctl_ioc_rule(cmd, minordev, pr, p);
1702 PFIOC_STRUCT_END(pr, addr);
1703 break;
1704 }
1705
1706 case DIOCCLRSTATES: /* struct pfioc_state_kill */
1707 case DIOCKILLSTATES: { /* struct pfioc_state_kill */
1708 struct pfioc_state_kill *psk = NULL;
1709
1710 PFIOC_STRUCT_BEGIN(addr, psk);
1711 error = pfioctl_ioc_state_kill(cmd, psk, p);
1712 PFIOC_STRUCT_END(psk, addr);
1713 break;
1714 }
1715
1716 case DIOCADDSTATE: /* struct pfioc_state */
1717 case DIOCGETSTATE: { /* struct pfioc_state */
1718 struct pfioc_state *ps = NULL;
1719
1720 PFIOC_STRUCT_BEGIN(addr, ps);
1721 error = pfioctl_ioc_state(cmd, ps, p);
1722 PFIOC_STRUCT_END(ps, addr);
1723 break;
1724 }
1725
1726 case DIOCGETSTATES: { /* struct pfioc_states */
1727 PFIOCX_STRUCT_DECL(pfioc_states);
1728
1729 PFIOCX_STRUCT_BEGIN(addr, pfioc_states);
1730 error = pfioctl_ioc_states(cmd,
1731 PFIOCX_STRUCT_ADDR32(pfioc_states),
1732 PFIOCX_STRUCT_ADDR64(pfioc_states), p);
1733 PFIOCX_STRUCT_END(pfioc_states, addr);
1734 break;
1735 }
1736
1737 case DIOCGETSTATUS: { /* struct pf_status */
1738 struct pf_status *s = NULL;
1739
1740 PFIOC_STRUCT_BEGIN(&pf_status, s);
1741 pfi_update_status(s->ifname, s);
1742 PFIOC_STRUCT_END(s, addr);
1743 break;
1744 }
1745
1746 case DIOCSETSTATUSIF: { /* struct pfioc_if */
1747 struct pfioc_if *pi = (struct pfioc_if *)(void *)addr;
1748
1749 /* OK for unaligned accesses */
1750 if (pi->ifname[0] == 0) {
1751 bzero(pf_status.ifname, IFNAMSIZ);
1752 break;
1753 }
1754 strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ);
1755 break;
1756 }
1757
1758 case DIOCCLRSTATUS: {
1759 bzero(pf_status.counters, sizeof(pf_status.counters));
1760 bzero(pf_status.fcounters, sizeof(pf_status.fcounters));
1761 bzero(pf_status.scounters, sizeof(pf_status.scounters));
1762 pf_status.since = pf_calendar_time_second();
1763 if (*pf_status.ifname) {
1764 pfi_update_status(pf_status.ifname, NULL);
1765 }
1766 break;
1767 }
1768
1769 case DIOCNATLOOK: { /* struct pfioc_natlook */
1770 struct pfioc_natlook *pnl = NULL;
1771
1772 PFIOC_STRUCT_BEGIN(addr, pnl);
1773 error = pfioctl_ioc_natlook(cmd, pnl, p);
1774 PFIOC_STRUCT_END(pnl, addr);
1775 break;
1776 }
1777
1778 case DIOCSETTIMEOUT: /* struct pfioc_tm */
1779 case DIOCGETTIMEOUT: { /* struct pfioc_tm */
1780 struct pfioc_tm pt;
1781
1782 /* small enough to be on stack */
1783 bcopy(addr, &pt, sizeof(pt));
1784 error = pfioctl_ioc_tm(cmd, &pt, p);
1785 bcopy(&pt, addr, sizeof(pt));
1786 break;
1787 }
1788
1789 case DIOCGETLIMIT: /* struct pfioc_limit */
1790 case DIOCSETLIMIT: { /* struct pfioc_limit */
1791 struct pfioc_limit pl;
1792
1793 /* small enough to be on stack */
1794 bcopy(addr, &pl, sizeof(pl));
1795 error = pfioctl_ioc_limit(cmd, &pl, p);
1796 bcopy(&pl, addr, sizeof(pl));
1797 break;
1798 }
1799
1800 case DIOCSETDEBUG: { /* u_int32_t */
1801 bcopy(addr, &pf_status.debug, sizeof(u_int32_t));
1802 break;
1803 }
1804
1805 case DIOCCLRRULECTRS: {
1806 /* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
1807 struct pf_ruleset *ruleset = &pf_main_ruleset;
1808 struct pf_rule *rule;
1809
1810 TAILQ_FOREACH(rule,
1811 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) {
1812 rule->evaluations = 0;
1813 rule->packets[0] = rule->packets[1] = 0;
1814 rule->bytes[0] = rule->bytes[1] = 0;
1815 }
1816 break;
1817 }
1818
1819 case DIOCGIFSPEED: {
1820 struct pf_ifspeed *psp = (struct pf_ifspeed *)(void *)addr;
1821 struct pf_ifspeed ps;
1822 struct ifnet *ifp;
1823 u_int64_t baudrate;
1824
1825 if (psp->ifname[0] != '\0') {
1826 /* Can we completely trust user-land? */
1827 strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
1828 ps.ifname[IFNAMSIZ - 1] = '\0';
1829 ifp = ifunit(ps.ifname);
1830 if (ifp != NULL) {
1831 baudrate = ifp->if_output_bw.max_bw;
1832 bcopy(&baudrate, &psp->baudrate,
1833 sizeof(baudrate));
1834 } else {
1835 error = EINVAL;
1836 }
1837 } else {
1838 error = EINVAL;
1839 }
1840 break;
1841 }
1842
1843 case DIOCBEGINADDRS: /* struct pfioc_pooladdr */
1844 case DIOCADDADDR: /* struct pfioc_pooladdr */
1845 case DIOCGETADDRS: /* struct pfioc_pooladdr */
1846 case DIOCGETADDR: /* struct pfioc_pooladdr */
1847 case DIOCCHANGEADDR: { /* struct pfioc_pooladdr */
1848 struct pfioc_pooladdr *pp = NULL;
1849
1850 PFIOC_STRUCT_BEGIN(addr, pp);
1851 error = pfioctl_ioc_pooladdr(cmd, pp, p);
1852 PFIOC_STRUCT_END(pp, addr);
1853 break;
1854 }
1855
1856 case DIOCGETRULESETS: /* struct pfioc_ruleset */
1857 case DIOCGETRULESET: { /* struct pfioc_ruleset */
1858 struct pfioc_ruleset *pr = NULL;
1859
1860 PFIOC_STRUCT_BEGIN(addr, pr);
1861 error = pfioctl_ioc_ruleset(cmd, pr, p);
1862 PFIOC_STRUCT_END(pr, addr);
1863 break;
1864 }
1865
1866 case DIOCRCLRTABLES: /* struct pfioc_table */
1867 case DIOCRADDTABLES: /* struct pfioc_table */
1868 case DIOCRDELTABLES: /* struct pfioc_table */
1869 case DIOCRGETTABLES: /* struct pfioc_table */
1870 case DIOCRGETTSTATS: /* struct pfioc_table */
1871 case DIOCRCLRTSTATS: /* struct pfioc_table */
1872 case DIOCRSETTFLAGS: /* struct pfioc_table */
1873 case DIOCRCLRADDRS: /* struct pfioc_table */
1874 case DIOCRADDADDRS: /* struct pfioc_table */
1875 case DIOCRDELADDRS: /* struct pfioc_table */
1876 case DIOCRSETADDRS: /* struct pfioc_table */
1877 case DIOCRGETADDRS: /* struct pfioc_table */
1878 case DIOCRGETASTATS: /* struct pfioc_table */
1879 case DIOCRCLRASTATS: /* struct pfioc_table */
1880 case DIOCRTSTADDRS: /* struct pfioc_table */
1881 case DIOCRINADEFINE: { /* struct pfioc_table */
1882 PFIOCX_STRUCT_DECL(pfioc_table);
1883
1884 PFIOCX_STRUCT_BEGIN(addr, pfioc_table);
1885 error = pfioctl_ioc_table(cmd,
1886 PFIOCX_STRUCT_ADDR32(pfioc_table),
1887 PFIOCX_STRUCT_ADDR64(pfioc_table), p);
1888 PFIOCX_STRUCT_END(pfioc_table, addr);
1889 break;
1890 }
1891
1892 case DIOCOSFPADD: /* struct pf_osfp_ioctl */
1893 case DIOCOSFPGET: { /* struct pf_osfp_ioctl */
1894 struct pf_osfp_ioctl *io = NULL;
1895
1896 PFIOC_STRUCT_BEGIN(addr, io);
1897 if (cmd == DIOCOSFPADD) {
1898 error = pf_osfp_add(io);
1899 } else {
1900 VERIFY(cmd == DIOCOSFPGET);
1901 error = pf_osfp_get(io);
1902 }
1903 PFIOC_STRUCT_END(io, addr);
1904 break;
1905 }
1906
1907 case DIOCXBEGIN: /* struct pfioc_trans */
1908 case DIOCXROLLBACK: /* struct pfioc_trans */
1909 case DIOCXCOMMIT: { /* struct pfioc_trans */
1910 PFIOCX_STRUCT_DECL(pfioc_trans);
1911
1912 PFIOCX_STRUCT_BEGIN(addr, pfioc_trans);
1913 error = pfioctl_ioc_trans(cmd,
1914 PFIOCX_STRUCT_ADDR32(pfioc_trans),
1915 PFIOCX_STRUCT_ADDR64(pfioc_trans), p);
1916 PFIOCX_STRUCT_END(pfioc_trans, addr);
1917 break;
1918 }
1919
1920 case DIOCGETSRCNODES: { /* struct pfioc_src_nodes */
1921 PFIOCX_STRUCT_DECL(pfioc_src_nodes);
1922
1923 PFIOCX_STRUCT_BEGIN(addr, pfioc_src_nodes);
1924 error = pfioctl_ioc_src_nodes(cmd,
1925 PFIOCX_STRUCT_ADDR32(pfioc_src_nodes),
1926 PFIOCX_STRUCT_ADDR64(pfioc_src_nodes), p);
1927 PFIOCX_STRUCT_END(pfioc_src_nodes, addr);
1928 break;
1929 }
1930
1931 case DIOCCLRSRCNODES: {
1932 struct pf_src_node *n;
1933 struct pf_state *state;
1934
1935 RB_FOREACH(state, pf_state_tree_id, &tree_id) {
1936 state->src_node = NULL;
1937 state->nat_src_node = NULL;
1938 }
1939 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
1940 n->expire = 1;
1941 n->states = 0;
1942 }
1943 pf_purge_expired_src_nodes();
1944 pf_status.src_nodes = 0;
1945 break;
1946 }
1947
1948 case DIOCKILLSRCNODES: { /* struct pfioc_src_node_kill */
1949 struct pfioc_src_node_kill *psnk = NULL;
1950
1951 PFIOC_STRUCT_BEGIN(addr, psnk);
1952 error = pfioctl_ioc_src_node_kill(cmd, psnk, p);
1953 PFIOC_STRUCT_END(psnk, addr);
1954 break;
1955 }
1956
1957 case DIOCSETHOSTID: { /* u_int32_t */
1958 u_int32_t hid;
1959
1960 /* small enough to be on stack */
1961 bcopy(addr, &hid, sizeof(hid));
1962 if (hid == 0) {
1963 pf_status.hostid = random();
1964 } else {
1965 pf_status.hostid = hid;
1966 }
1967 break;
1968 }
1969
1970 case DIOCOSFPFLUSH:
1971 pf_osfp_flush();
1972 break;
1973
1974 case DIOCIGETIFACES: /* struct pfioc_iface */
1975 case DIOCSETIFFLAG: /* struct pfioc_iface */
1976 case DIOCCLRIFFLAG: { /* struct pfioc_iface */
1977 PFIOCX_STRUCT_DECL(pfioc_iface);
1978
1979 PFIOCX_STRUCT_BEGIN(addr, pfioc_iface);
1980 error = pfioctl_ioc_iface(cmd,
1981 PFIOCX_STRUCT_ADDR32(pfioc_iface),
1982 PFIOCX_STRUCT_ADDR64(pfioc_iface), p);
1983 PFIOCX_STRUCT_END(pfioc_iface, addr);
1984 break;
1985 }
1986
1987 default:
1988 error = ENODEV;
1989 break;
1990 }
1991
1992 lck_mtx_unlock(&pf_lock);
1993 lck_rw_done(&pf_perim_lock);
1994
1995 return error;
1996 }
1997
1998 static int
pfioctl_ioc_table(u_long cmd,struct pfioc_table_32 * io32,struct pfioc_table_64 * io64,struct proc * p)1999 pfioctl_ioc_table(u_long cmd, struct pfioc_table_32 *io32,
2000 struct pfioc_table_64 *io64, struct proc *p)
2001 {
2002 int p64 = proc_is64bit(p);
2003 int error = 0;
2004
2005 if (!p64) {
2006 goto struct32;
2007 }
2008
2009 #ifdef __LP64__
2010 /*
2011 * 64-bit structure processing
2012 */
2013 switch (cmd) {
2014 case DIOCRCLRTABLES:
2015 if (io64->pfrio_esize != 0) {
2016 error = ENODEV;
2017 break;
2018 }
2019 pfr_table_copyin_cleanup(&io64->pfrio_table);
2020 error = pfr_clr_tables(&io64->pfrio_table, &io64->pfrio_ndel,
2021 io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2022 break;
2023
2024 case DIOCRADDTABLES:
2025 if (io64->pfrio_esize != sizeof(struct pfr_table)) {
2026 error = ENODEV;
2027 break;
2028 }
2029 error = pfr_add_tables(io64->pfrio_buffer, io64->pfrio_size,
2030 &io64->pfrio_nadd, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2031 break;
2032
2033 case DIOCRDELTABLES:
2034 if (io64->pfrio_esize != sizeof(struct pfr_table)) {
2035 error = ENODEV;
2036 break;
2037 }
2038 error = pfr_del_tables(io64->pfrio_buffer, io64->pfrio_size,
2039 &io64->pfrio_ndel, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2040 break;
2041
2042 case DIOCRGETTABLES:
2043 if (io64->pfrio_esize != sizeof(struct pfr_table)) {
2044 error = ENODEV;
2045 break;
2046 }
2047 pfr_table_copyin_cleanup(&io64->pfrio_table);
2048 error = pfr_get_tables(&io64->pfrio_table, io64->pfrio_buffer,
2049 &io64->pfrio_size, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2050 break;
2051
2052 case DIOCRGETTSTATS:
2053 if (io64->pfrio_esize != sizeof(struct pfr_tstats)) {
2054 error = ENODEV;
2055 break;
2056 }
2057 pfr_table_copyin_cleanup(&io64->pfrio_table);
2058 error = pfr_get_tstats(&io64->pfrio_table, io64->pfrio_buffer,
2059 &io64->pfrio_size, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2060 break;
2061
2062 case DIOCRCLRTSTATS:
2063 if (io64->pfrio_esize != sizeof(struct pfr_table)) {
2064 error = ENODEV;
2065 break;
2066 }
2067 error = pfr_clr_tstats(io64->pfrio_buffer, io64->pfrio_size,
2068 &io64->pfrio_nzero, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2069 break;
2070
2071 case DIOCRSETTFLAGS:
2072 if (io64->pfrio_esize != sizeof(struct pfr_table)) {
2073 error = ENODEV;
2074 break;
2075 }
2076 error = pfr_set_tflags(io64->pfrio_buffer, io64->pfrio_size,
2077 io64->pfrio_setflag, io64->pfrio_clrflag,
2078 &io64->pfrio_nchange, &io64->pfrio_ndel,
2079 io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2080 break;
2081
2082 case DIOCRCLRADDRS:
2083 if (io64->pfrio_esize != 0) {
2084 error = ENODEV;
2085 break;
2086 }
2087 pfr_table_copyin_cleanup(&io64->pfrio_table);
2088 error = pfr_clr_addrs(&io64->pfrio_table, &io64->pfrio_ndel,
2089 io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2090 break;
2091
2092 case DIOCRADDADDRS:
2093 if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2094 error = ENODEV;
2095 break;
2096 }
2097 pfr_table_copyin_cleanup(&io64->pfrio_table);
2098 error = pfr_add_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2099 io64->pfrio_size, &io64->pfrio_nadd, io64->pfrio_flags |
2100 PFR_FLAG_USERIOCTL);
2101 break;
2102
2103 case DIOCRDELADDRS:
2104 if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2105 error = ENODEV;
2106 break;
2107 }
2108 pfr_table_copyin_cleanup(&io64->pfrio_table);
2109 error = pfr_del_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2110 io64->pfrio_size, &io64->pfrio_ndel, io64->pfrio_flags |
2111 PFR_FLAG_USERIOCTL);
2112 break;
2113
2114 case DIOCRSETADDRS:
2115 if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2116 error = ENODEV;
2117 break;
2118 }
2119 pfr_table_copyin_cleanup(&io64->pfrio_table);
2120 error = pfr_set_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2121 io64->pfrio_size, &io64->pfrio_size2, &io64->pfrio_nadd,
2122 &io64->pfrio_ndel, &io64->pfrio_nchange, io64->pfrio_flags |
2123 PFR_FLAG_USERIOCTL, 0);
2124 break;
2125
2126 case DIOCRGETADDRS:
2127 if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2128 error = ENODEV;
2129 break;
2130 }
2131 pfr_table_copyin_cleanup(&io64->pfrio_table);
2132 error = pfr_get_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2133 &io64->pfrio_size, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2134 break;
2135
2136 case DIOCRGETASTATS:
2137 if (io64->pfrio_esize != sizeof(struct pfr_astats)) {
2138 error = ENODEV;
2139 break;
2140 }
2141 pfr_table_copyin_cleanup(&io64->pfrio_table);
2142 error = pfr_get_astats(&io64->pfrio_table, io64->pfrio_buffer,
2143 &io64->pfrio_size, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2144 break;
2145
2146 case DIOCRCLRASTATS:
2147 if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2148 error = ENODEV;
2149 break;
2150 }
2151 pfr_table_copyin_cleanup(&io64->pfrio_table);
2152 error = pfr_clr_astats(&io64->pfrio_table, io64->pfrio_buffer,
2153 io64->pfrio_size, &io64->pfrio_nzero, io64->pfrio_flags |
2154 PFR_FLAG_USERIOCTL);
2155 break;
2156
2157 case DIOCRTSTADDRS:
2158 if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2159 error = ENODEV;
2160 break;
2161 }
2162 pfr_table_copyin_cleanup(&io64->pfrio_table);
2163 error = pfr_tst_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2164 io64->pfrio_size, &io64->pfrio_nmatch, io64->pfrio_flags |
2165 PFR_FLAG_USERIOCTL);
2166 break;
2167
2168 case DIOCRINADEFINE:
2169 if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2170 error = ENODEV;
2171 break;
2172 }
2173 pfr_table_copyin_cleanup(&io64->pfrio_table);
2174 error = pfr_ina_define(&io64->pfrio_table, io64->pfrio_buffer,
2175 io64->pfrio_size, &io64->pfrio_nadd, &io64->pfrio_naddr,
2176 io64->pfrio_ticket, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2177 break;
2178
2179 default:
2180 VERIFY(0);
2181 /* NOTREACHED */
2182 }
2183 goto done;
2184 #else
2185 #pragma unused(io64)
2186 #endif /* __LP64__ */
2187
2188 struct32:
2189 /*
2190 * 32-bit structure processing
2191 */
2192 switch (cmd) {
2193 case DIOCRCLRTABLES:
2194 if (io32->pfrio_esize != 0) {
2195 error = ENODEV;
2196 break;
2197 }
2198 pfr_table_copyin_cleanup(&io32->pfrio_table);
2199 error = pfr_clr_tables(&io32->pfrio_table, &io32->pfrio_ndel,
2200 io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2201 break;
2202
2203 case DIOCRADDTABLES:
2204 if (io32->pfrio_esize != sizeof(struct pfr_table)) {
2205 error = ENODEV;
2206 break;
2207 }
2208 error = pfr_add_tables(io32->pfrio_buffer, io32->pfrio_size,
2209 &io32->pfrio_nadd, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2210 break;
2211
2212 case DIOCRDELTABLES:
2213 if (io32->pfrio_esize != sizeof(struct pfr_table)) {
2214 error = ENODEV;
2215 break;
2216 }
2217 error = pfr_del_tables(io32->pfrio_buffer, io32->pfrio_size,
2218 &io32->pfrio_ndel, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2219 break;
2220
2221 case DIOCRGETTABLES:
2222 if (io32->pfrio_esize != sizeof(struct pfr_table)) {
2223 error = ENODEV;
2224 break;
2225 }
2226 pfr_table_copyin_cleanup(&io32->pfrio_table);
2227 error = pfr_get_tables(&io32->pfrio_table, io32->pfrio_buffer,
2228 &io32->pfrio_size, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2229 break;
2230
2231 case DIOCRGETTSTATS:
2232 if (io32->pfrio_esize != sizeof(struct pfr_tstats)) {
2233 error = ENODEV;
2234 break;
2235 }
2236 pfr_table_copyin_cleanup(&io32->pfrio_table);
2237 error = pfr_get_tstats(&io32->pfrio_table, io32->pfrio_buffer,
2238 &io32->pfrio_size, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2239 break;
2240
2241 case DIOCRCLRTSTATS:
2242 if (io32->pfrio_esize != sizeof(struct pfr_table)) {
2243 error = ENODEV;
2244 break;
2245 }
2246 error = pfr_clr_tstats(io32->pfrio_buffer, io32->pfrio_size,
2247 &io32->pfrio_nzero, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2248 break;
2249
2250 case DIOCRSETTFLAGS:
2251 if (io32->pfrio_esize != sizeof(struct pfr_table)) {
2252 error = ENODEV;
2253 break;
2254 }
2255 error = pfr_set_tflags(io32->pfrio_buffer, io32->pfrio_size,
2256 io32->pfrio_setflag, io32->pfrio_clrflag,
2257 &io32->pfrio_nchange, &io32->pfrio_ndel,
2258 io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2259 break;
2260
2261 case DIOCRCLRADDRS:
2262 if (io32->pfrio_esize != 0) {
2263 error = ENODEV;
2264 break;
2265 }
2266 pfr_table_copyin_cleanup(&io32->pfrio_table);
2267 error = pfr_clr_addrs(&io32->pfrio_table, &io32->pfrio_ndel,
2268 io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2269 break;
2270
2271 case DIOCRADDADDRS:
2272 if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2273 error = ENODEV;
2274 break;
2275 }
2276 pfr_table_copyin_cleanup(&io32->pfrio_table);
2277 error = pfr_add_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2278 io32->pfrio_size, &io32->pfrio_nadd, io32->pfrio_flags |
2279 PFR_FLAG_USERIOCTL);
2280 break;
2281
2282 case DIOCRDELADDRS:
2283 if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2284 error = ENODEV;
2285 break;
2286 }
2287 pfr_table_copyin_cleanup(&io32->pfrio_table);
2288 error = pfr_del_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2289 io32->pfrio_size, &io32->pfrio_ndel, io32->pfrio_flags |
2290 PFR_FLAG_USERIOCTL);
2291 break;
2292
2293 case DIOCRSETADDRS:
2294 if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2295 error = ENODEV;
2296 break;
2297 }
2298 pfr_table_copyin_cleanup(&io32->pfrio_table);
2299 error = pfr_set_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2300 io32->pfrio_size, &io32->pfrio_size2, &io32->pfrio_nadd,
2301 &io32->pfrio_ndel, &io32->pfrio_nchange, io32->pfrio_flags |
2302 PFR_FLAG_USERIOCTL, 0);
2303 break;
2304
2305 case DIOCRGETADDRS:
2306 if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2307 error = ENODEV;
2308 break;
2309 }
2310 pfr_table_copyin_cleanup(&io32->pfrio_table);
2311 error = pfr_get_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2312 &io32->pfrio_size, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2313 break;
2314
2315 case DIOCRGETASTATS:
2316 if (io32->pfrio_esize != sizeof(struct pfr_astats)) {
2317 error = ENODEV;
2318 break;
2319 }
2320 pfr_table_copyin_cleanup(&io32->pfrio_table);
2321 error = pfr_get_astats(&io32->pfrio_table, io32->pfrio_buffer,
2322 &io32->pfrio_size, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2323 break;
2324
2325 case DIOCRCLRASTATS:
2326 if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2327 error = ENODEV;
2328 break;
2329 }
2330 pfr_table_copyin_cleanup(&io32->pfrio_table);
2331 error = pfr_clr_astats(&io32->pfrio_table, io32->pfrio_buffer,
2332 io32->pfrio_size, &io32->pfrio_nzero, io32->pfrio_flags |
2333 PFR_FLAG_USERIOCTL);
2334 break;
2335
2336 case DIOCRTSTADDRS:
2337 if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2338 error = ENODEV;
2339 break;
2340 }
2341 pfr_table_copyin_cleanup(&io32->pfrio_table);
2342 error = pfr_tst_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2343 io32->pfrio_size, &io32->pfrio_nmatch, io32->pfrio_flags |
2344 PFR_FLAG_USERIOCTL);
2345 break;
2346
2347 case DIOCRINADEFINE:
2348 if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2349 error = ENODEV;
2350 break;
2351 }
2352 pfr_table_copyin_cleanup(&io32->pfrio_table);
2353 error = pfr_ina_define(&io32->pfrio_table, io32->pfrio_buffer,
2354 io32->pfrio_size, &io32->pfrio_nadd, &io32->pfrio_naddr,
2355 io32->pfrio_ticket, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2356 break;
2357
2358 default:
2359 VERIFY(0);
2360 /* NOTREACHED */
2361 }
2362 #ifdef __LP64__
2363 done:
2364 #endif
2365 return error;
2366 }
2367
2368 static int
pfioctl_ioc_tokens(u_long cmd,struct pfioc_tokens_32 * tok32,struct pfioc_tokens_64 * tok64,struct proc * p)2369 pfioctl_ioc_tokens(u_long cmd, struct pfioc_tokens_32 *tok32,
2370 struct pfioc_tokens_64 *tok64, struct proc *p)
2371 {
2372 struct pfioc_token *tokens;
2373 struct pfioc_kernel_token *entry, *tmp;
2374 user_addr_t token_buf;
2375 int ocnt, cnt, error = 0, p64 = proc_is64bit(p);
2376 char *ptr;
2377
2378 switch (cmd) {
2379 case DIOCGETSTARTERS: {
2380 int size;
2381
2382 if (nr_tokens == 0) {
2383 error = ENOENT;
2384 break;
2385 }
2386
2387 size = sizeof(struct pfioc_token) * nr_tokens;
2388 if (size / nr_tokens != sizeof(struct pfioc_token)) {
2389 os_log_error(OS_LOG_DEFAULT, "%s: size overflows", __func__);
2390 error = ERANGE;
2391 break;
2392 }
2393 ocnt = cnt = (p64 ? tok64->size : tok32->size);
2394 if (cnt == 0) {
2395 if (p64) {
2396 tok64->size = size;
2397 } else {
2398 tok32->size = size;
2399 }
2400 break;
2401 }
2402
2403 #ifdef __LP64__
2404 token_buf = (p64 ? tok64->pgt_buf : tok32->pgt_buf);
2405 #else
2406 token_buf = tok32->pgt_buf;
2407 #endif
2408 tokens = (struct pfioc_token *)kalloc_data(size, Z_WAITOK | Z_ZERO);
2409 if (tokens == NULL) {
2410 error = ENOMEM;
2411 break;
2412 }
2413
2414 ptr = (void *)tokens;
2415 SLIST_FOREACH_SAFE(entry, &token_list_head, next, tmp) {
2416 struct pfioc_token *t;
2417
2418 if ((unsigned)cnt < sizeof(*tokens)) {
2419 break; /* no more buffer space left */
2420 }
2421 t = (struct pfioc_token *)(void *)ptr;
2422 t->token_value = entry->token.token_value;
2423 t->timestamp = entry->token.timestamp;
2424 t->pid = entry->token.pid;
2425 bcopy(entry->token.proc_name, t->proc_name,
2426 PFTOK_PROCNAME_LEN);
2427 ptr += sizeof(struct pfioc_token);
2428
2429 cnt -= sizeof(struct pfioc_token);
2430 }
2431
2432 if (cnt < ocnt) {
2433 error = copyout(tokens, token_buf, ocnt - cnt);
2434 }
2435
2436 if (p64) {
2437 tok64->size = ocnt - cnt;
2438 } else {
2439 tok32->size = ocnt - cnt;
2440 }
2441
2442 kfree_data(tokens, size);
2443 break;
2444 }
2445
2446 default:
2447 VERIFY(0);
2448 /* NOTREACHED */
2449 }
2450
2451 return error;
2452 }
2453
2454 static void
pf_expire_states_and_src_nodes(struct pf_rule * rule)2455 pf_expire_states_and_src_nodes(struct pf_rule *rule)
2456 {
2457 struct pf_state *state;
2458 struct pf_src_node *sn;
2459 int killed = 0;
2460
2461 /* expire the states */
2462 state = TAILQ_FIRST(&state_list);
2463 while (state) {
2464 if (state->rule.ptr == rule) {
2465 state->timeout = PFTM_PURGE;
2466 }
2467 state = TAILQ_NEXT(state, entry_list);
2468 }
2469 pf_purge_expired_states(pf_status.states);
2470
2471 /* expire the src_nodes */
2472 RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) {
2473 if (sn->rule.ptr != rule) {
2474 continue;
2475 }
2476 if (sn->states != 0) {
2477 RB_FOREACH(state, pf_state_tree_id,
2478 &tree_id) {
2479 if (state->src_node == sn) {
2480 state->src_node = NULL;
2481 }
2482 if (state->nat_src_node == sn) {
2483 state->nat_src_node = NULL;
2484 }
2485 }
2486 sn->states = 0;
2487 }
2488 sn->expire = 1;
2489 killed++;
2490 }
2491 if (killed) {
2492 pf_purge_expired_src_nodes();
2493 }
2494 }
2495
2496 static void
pf_delete_rule_from_ruleset(struct pf_ruleset * ruleset,int rs_num,struct pf_rule * rule)2497 pf_delete_rule_from_ruleset(struct pf_ruleset *ruleset, int rs_num,
2498 struct pf_rule *rule)
2499 {
2500 struct pf_rule *r;
2501 int nr = 0;
2502
2503 pf_expire_states_and_src_nodes(rule);
2504
2505 pf_rm_rule(ruleset->rules[rs_num].active.ptr, rule);
2506 if (ruleset->rules[rs_num].active.rcount-- == 0) {
2507 panic("%s: rcount value broken!", __func__);
2508 }
2509 r = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
2510
2511 while (r) {
2512 r->nr = nr++;
2513 r = TAILQ_NEXT(r, entries);
2514 }
2515 }
2516
2517
2518 static void
pf_ruleset_cleanup(struct pf_ruleset * ruleset,int rs)2519 pf_ruleset_cleanup(struct pf_ruleset *ruleset, int rs)
2520 {
2521 pf_calc_skip_steps(ruleset->rules[rs].active.ptr);
2522 ruleset->rules[rs].active.ticket =
2523 ++ruleset->rules[rs].inactive.ticket;
2524 }
2525
2526 /*
2527 * req_dev encodes the PF interface. Currently, possible values are
2528 * 0 or PFRULE_PFM
2529 */
2530 static int
pf_delete_rule_by_ticket(struct pfioc_rule * pr,u_int32_t req_dev)2531 pf_delete_rule_by_ticket(struct pfioc_rule *pr, u_int32_t req_dev)
2532 {
2533 struct pf_ruleset *ruleset;
2534 struct pf_rule *rule = NULL;
2535 int is_anchor;
2536 int error = 0;
2537 int i;
2538
2539 is_anchor = (pr->anchor_call[0] != '\0');
2540 if ((ruleset = pf_find_ruleset_with_owner(pr->anchor,
2541 pr->rule.owner, is_anchor, &error)) == NULL) {
2542 goto done;
2543 }
2544
2545 for (i = 0; i < PF_RULESET_MAX && rule == NULL; i++) {
2546 rule = TAILQ_FIRST(ruleset->rules[i].active.ptr);
2547 while (rule && (rule->ticket != pr->rule.ticket)) {
2548 rule = TAILQ_NEXT(rule, entries);
2549 }
2550 }
2551 if (rule == NULL) {
2552 error = ENOENT;
2553 goto done;
2554 } else {
2555 i--;
2556 }
2557
2558 if (strcmp(rule->owner, pr->rule.owner)) {
2559 error = EACCES;
2560 goto done;
2561 }
2562
2563 delete_rule:
2564 if (rule->anchor && (ruleset != &pf_main_ruleset) &&
2565 ((strcmp(ruleset->anchor->owner, "")) == 0) &&
2566 ((ruleset->rules[i].active.rcount - 1) == 0)) {
2567 /* set rule & ruleset to parent and repeat */
2568 struct pf_rule *delete_rule = rule;
2569 struct pf_ruleset *delete_ruleset = ruleset;
2570
2571 #define parent_ruleset ruleset->anchor->parent->ruleset
2572 if (ruleset->anchor->parent == NULL) {
2573 ruleset = &pf_main_ruleset;
2574 } else {
2575 ruleset = &parent_ruleset;
2576 }
2577
2578 rule = TAILQ_FIRST(ruleset->rules[i].active.ptr);
2579 while (rule &&
2580 (rule->anchor != delete_ruleset->anchor)) {
2581 rule = TAILQ_NEXT(rule, entries);
2582 }
2583 if (rule == NULL) {
2584 panic("%s: rule not found!", __func__);
2585 }
2586
2587 /*
2588 * if reqest device != rule's device, bail :
2589 * with error if ticket matches;
2590 * without error if ticket doesn't match (i.e. its just cleanup)
2591 */
2592 if ((rule->rule_flag & PFRULE_PFM) ^ req_dev) {
2593 if (rule->ticket != pr->rule.ticket) {
2594 goto done;
2595 } else {
2596 error = EACCES;
2597 goto done;
2598 }
2599 }
2600
2601 if (delete_rule->rule_flag & PFRULE_PFM) {
2602 pffwrules--;
2603 }
2604
2605 pf_delete_rule_from_ruleset(delete_ruleset,
2606 i, delete_rule);
2607 delete_ruleset->rules[i].active.ticket =
2608 ++delete_ruleset->rules[i].inactive.ticket;
2609 goto delete_rule;
2610 } else {
2611 /*
2612 * process deleting rule only if device that added the
2613 * rule matches device that issued the request
2614 */
2615 if ((rule->rule_flag & PFRULE_PFM) ^ req_dev) {
2616 error = EACCES;
2617 goto done;
2618 }
2619 if (rule->rule_flag & PFRULE_PFM) {
2620 pffwrules--;
2621 }
2622 pf_delete_rule_from_ruleset(ruleset, i,
2623 rule);
2624 pf_ruleset_cleanup(ruleset, i);
2625 }
2626
2627 done:
2628 if (ruleset) {
2629 pf_release_ruleset(ruleset);
2630 ruleset = NULL;
2631 }
2632 return error;
2633 }
2634
2635 /*
2636 * req_dev encodes the PF interface. Currently, possible values are
2637 * 0 or PFRULE_PFM
2638 */
2639 static void
pf_delete_rule_by_owner(char * owner,u_int32_t req_dev)2640 pf_delete_rule_by_owner(char *owner, u_int32_t req_dev)
2641 {
2642 struct pf_ruleset *ruleset;
2643 struct pf_rule *rule, *next;
2644 int deleted = 0;
2645
2646 for (int rs = 0; rs < PF_RULESET_MAX; rs++) {
2647 rule = TAILQ_FIRST(pf_main_ruleset.rules[rs].active.ptr);
2648 ruleset = &pf_main_ruleset;
2649 while (rule) {
2650 next = TAILQ_NEXT(rule, entries);
2651 /*
2652 * process deleting rule only if device that added the
2653 * rule matches device that issued the request
2654 */
2655 if ((rule->rule_flag & PFRULE_PFM) ^ req_dev) {
2656 rule = next;
2657 } else if (rule->anchor) {
2658 if (((strcmp(rule->owner, owner)) == 0) ||
2659 ((strcmp(rule->owner, "")) == 0)) {
2660 if (rule->anchor->ruleset.rules[rs].active.rcount > 0) {
2661 if (deleted) {
2662 pf_ruleset_cleanup(ruleset, rs);
2663 deleted = 0;
2664 }
2665 /* step into anchor */
2666 ruleset =
2667 &rule->anchor->ruleset;
2668 rule = TAILQ_FIRST(ruleset->rules[rs].active.ptr);
2669 continue;
2670 } else {
2671 if (rule->rule_flag &
2672 PFRULE_PFM) {
2673 pffwrules--;
2674 }
2675 pf_delete_rule_from_ruleset(ruleset, rs, rule);
2676 deleted = 1;
2677 rule = next;
2678 }
2679 } else {
2680 rule = next;
2681 }
2682 } else {
2683 if (((strcmp(rule->owner, owner)) == 0)) {
2684 /* delete rule */
2685 if (rule->rule_flag & PFRULE_PFM) {
2686 pffwrules--;
2687 }
2688 pf_delete_rule_from_ruleset(ruleset,
2689 rs, rule);
2690 deleted = 1;
2691 }
2692 rule = next;
2693 }
2694 if (rule == NULL) {
2695 if (deleted) {
2696 pf_ruleset_cleanup(ruleset, rs);
2697 deleted = 0;
2698 }
2699 if (ruleset != &pf_main_ruleset) {
2700 pf_deleterule_anchor_step_out(&ruleset,
2701 rs, &rule);
2702 }
2703 }
2704 }
2705 }
2706 }
2707
2708 static void
pf_deleterule_anchor_step_out(struct pf_ruleset ** ruleset_ptr,int rs,struct pf_rule ** rule_ptr)2709 pf_deleterule_anchor_step_out(struct pf_ruleset **ruleset_ptr,
2710 int rs, struct pf_rule **rule_ptr)
2711 {
2712 struct pf_ruleset *ruleset = *ruleset_ptr;
2713 struct pf_rule *rule = *rule_ptr;
2714
2715 /* step out of anchor */
2716 struct pf_ruleset *rs_copy = ruleset;
2717 ruleset = ruleset->anchor->parent?
2718 &ruleset->anchor->parent->ruleset:&pf_main_ruleset;
2719
2720 rule = TAILQ_FIRST(ruleset->rules[rs].active.ptr);
2721 while (rule && (rule->anchor != rs_copy->anchor)) {
2722 rule = TAILQ_NEXT(rule, entries);
2723 }
2724 if (rule == NULL) {
2725 panic("%s: parent rule of anchor not found!", __func__);
2726 }
2727 if (rule->anchor->ruleset.rules[rs].active.rcount > 0) {
2728 rule = TAILQ_NEXT(rule, entries);
2729 }
2730
2731 *ruleset_ptr = ruleset;
2732 *rule_ptr = rule;
2733 }
2734
2735 static void
pf_addrwrap_setup(struct pf_addr_wrap * aw)2736 pf_addrwrap_setup(struct pf_addr_wrap *aw)
2737 {
2738 VERIFY(aw);
2739 bzero(&aw->p, sizeof aw->p);
2740 }
2741
2742 static int
pf_rule_setup(struct pfioc_rule * pr,struct pf_rule * rule,struct pf_ruleset * ruleset)2743 pf_rule_setup(struct pfioc_rule *pr, struct pf_rule *rule,
2744 struct pf_ruleset *ruleset)
2745 {
2746 struct pf_pooladdr *apa;
2747 int error = 0;
2748
2749 if (rule->ifname[0]) {
2750 rule->kif = pfi_kif_get(rule->ifname);
2751 if (rule->kif == NULL) {
2752 pool_put(&pf_rule_pl, rule);
2753 return EINVAL;
2754 }
2755 pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE);
2756 }
2757 if (rule->tagname[0]) {
2758 if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) {
2759 error = EBUSY;
2760 }
2761 }
2762 if (rule->match_tagname[0]) {
2763 if ((rule->match_tag =
2764 pf_tagname2tag(rule->match_tagname)) == 0) {
2765 error = EBUSY;
2766 }
2767 }
2768 if (rule->rt && !rule->direction) {
2769 error = EINVAL;
2770 }
2771 #if PFLOG
2772 if (!rule->log) {
2773 rule->logif = 0;
2774 }
2775 if (rule->logif >= PFLOGIFS_MAX) {
2776 error = EINVAL;
2777 }
2778 #endif /* PFLOG */
2779 pf_addrwrap_setup(&rule->src.addr);
2780 pf_addrwrap_setup(&rule->dst.addr);
2781 if (pf_rtlabel_add(&rule->src.addr) ||
2782 pf_rtlabel_add(&rule->dst.addr)) {
2783 error = EBUSY;
2784 }
2785 if (pfi_dynaddr_setup(&rule->src.addr, rule->af)) {
2786 error = EINVAL;
2787 }
2788 if (pfi_dynaddr_setup(&rule->dst.addr, rule->af)) {
2789 error = EINVAL;
2790 }
2791 if (pf_tbladdr_setup(ruleset, &rule->src.addr)) {
2792 error = EINVAL;
2793 }
2794 if (pf_tbladdr_setup(ruleset, &rule->dst.addr)) {
2795 error = EINVAL;
2796 }
2797 if (pf_anchor_setup(rule, ruleset, pr->anchor_call)) {
2798 error = EINVAL;
2799 }
2800 TAILQ_FOREACH(apa, &pf_pabuf, entries)
2801 if (pf_tbladdr_setup(ruleset, &apa->addr)) {
2802 error = EINVAL;
2803 }
2804
2805 if (rule->overload_tblname[0]) {
2806 if ((rule->overload_tbl = pfr_attach_table(ruleset,
2807 rule->overload_tblname)) == NULL) {
2808 error = EINVAL;
2809 } else {
2810 rule->overload_tbl->pfrkt_flags |=
2811 PFR_TFLAG_ACTIVE;
2812 }
2813 }
2814
2815 pf_mv_pool(&pf_pabuf, &rule->rpool.list);
2816
2817 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
2818 (rule->action == PF_BINAT) || (rule->action == PF_NAT64)) &&
2819 rule->anchor == NULL) ||
2820 (rule->rt > PF_FASTROUTE)) &&
2821 (TAILQ_FIRST(&rule->rpool.list) == NULL)) {
2822 error = EINVAL;
2823 }
2824
2825 if (error) {
2826 pf_rm_rule(NULL, rule);
2827 return error;
2828 }
2829 /* For a NAT64 rule the rule's address family is AF_INET6 whereas
2830 * the address pool's family will be AF_INET
2831 */
2832 rule->rpool.af = (rule->action == PF_NAT64) ? AF_INET: rule->af;
2833 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
2834 rule->evaluations = rule->packets[0] = rule->packets[1] =
2835 rule->bytes[0] = rule->bytes[1] = 0;
2836
2837 return 0;
2838 }
2839
2840 static int
pfioctl_ioc_rule(u_long cmd,int minordev,struct pfioc_rule * pr,struct proc * p)2841 pfioctl_ioc_rule(u_long cmd, int minordev, struct pfioc_rule *pr, struct proc *p)
2842 {
2843 int error = 0;
2844 u_int32_t req_dev = 0;
2845 struct pf_ruleset *ruleset = NULL;
2846
2847 switch (cmd) {
2848 case DIOCADDRULE: {
2849 struct pf_rule *rule, *tail;
2850 int rs_num;
2851
2852 pr->anchor[sizeof(pr->anchor) - 1] = '\0';
2853 pr->anchor_call[sizeof(pr->anchor_call) - 1] = '\0';
2854 ruleset = pf_find_ruleset(pr->anchor);
2855 if (ruleset == NULL) {
2856 error = EINVAL;
2857 break;
2858 }
2859 rs_num = pf_get_ruleset_number(pr->rule.action);
2860 if (rs_num >= PF_RULESET_MAX) {
2861 error = EINVAL;
2862 break;
2863 }
2864 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
2865 error = EINVAL;
2866 break;
2867 }
2868 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
2869 error = EBUSY;
2870 break;
2871 }
2872 if (pr->pool_ticket != ticket_pabuf) {
2873 error = EBUSY;
2874 break;
2875 }
2876 rule = pool_get(&pf_rule_pl, PR_WAITOK);
2877 if (rule == NULL) {
2878 error = ENOMEM;
2879 break;
2880 }
2881 pf_rule_copyin(&pr->rule, rule, p, minordev);
2882 #if !INET
2883 if (rule->af == AF_INET) {
2884 pool_put(&pf_rule_pl, rule);
2885 error = EAFNOSUPPORT;
2886 break;
2887 }
2888 #endif /* INET */
2889 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
2890 pf_rulequeue);
2891 if (tail) {
2892 rule->nr = tail->nr + 1;
2893 } else {
2894 rule->nr = 0;
2895 }
2896
2897 if ((error = pf_rule_setup(pr, rule, ruleset))) {
2898 break;
2899 }
2900
2901 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
2902 rule, entries);
2903 ruleset->rules[rs_num].inactive.rcount++;
2904 if (rule->rule_flag & PFRULE_PFM) {
2905 pffwrules++;
2906 }
2907
2908 if (rule->action == PF_NAT64) {
2909 os_atomic_inc(&pf_nat64_configured, relaxed);
2910 }
2911
2912 if (pr->anchor_call[0] == '\0') {
2913 INC_ATOMIC_INT64_LIM(net_api_stats.nas_pf_addrule_total);
2914 if (rule->rule_flag & PFRULE_PFM) {
2915 INC_ATOMIC_INT64_LIM(net_api_stats.nas_pf_addrule_os);
2916 }
2917 }
2918
2919 #if DUMMYNET
2920 if (rule->action == PF_DUMMYNET) {
2921 struct dummynet_event dn_event;
2922 uint32_t direction = DN_INOUT;
2923 bzero(&dn_event, sizeof(dn_event));
2924
2925 dn_event.dn_event_code = DUMMYNET_RULE_CONFIG;
2926
2927 if (rule->direction == PF_IN) {
2928 direction = DN_IN;
2929 } else if (rule->direction == PF_OUT) {
2930 direction = DN_OUT;
2931 }
2932
2933 dn_event.dn_event_rule_config.dir = direction;
2934 dn_event.dn_event_rule_config.af = rule->af;
2935 dn_event.dn_event_rule_config.proto = rule->proto;
2936 dn_event.dn_event_rule_config.src_port = rule->src.xport.range.port[0];
2937 dn_event.dn_event_rule_config.dst_port = rule->dst.xport.range.port[0];
2938 strlcpy(dn_event.dn_event_rule_config.ifname, rule->ifname,
2939 sizeof(dn_event.dn_event_rule_config.ifname));
2940
2941 dummynet_event_enqueue_nwk_wq_entry(&dn_event);
2942 }
2943 #endif
2944 break;
2945 }
2946
2947 case DIOCGETRULES: {
2948 struct pf_rule *tail;
2949 int rs_num;
2950
2951 pr->anchor[sizeof(pr->anchor) - 1] = '\0';
2952 pr->anchor_call[sizeof(pr->anchor_call) - 1] = '\0';
2953 ruleset = pf_find_ruleset(pr->anchor);
2954 if (ruleset == NULL) {
2955 error = EINVAL;
2956 break;
2957 }
2958 rs_num = pf_get_ruleset_number(pr->rule.action);
2959 if (rs_num >= PF_RULESET_MAX) {
2960 error = EINVAL;
2961 break;
2962 }
2963 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
2964 pf_rulequeue);
2965 if (tail) {
2966 pr->nr = tail->nr + 1;
2967 } else {
2968 pr->nr = 0;
2969 }
2970 pr->ticket = ruleset->rules[rs_num].active.ticket;
2971 break;
2972 }
2973
2974 case DIOCGETRULE: {
2975 struct pf_rule *rule;
2976 int rs_num, i;
2977
2978 pr->anchor[sizeof(pr->anchor) - 1] = '\0';
2979 pr->anchor_call[sizeof(pr->anchor_call) - 1] = '\0';
2980 ruleset = pf_find_ruleset(pr->anchor);
2981 if (ruleset == NULL) {
2982 error = EINVAL;
2983 break;
2984 }
2985 rs_num = pf_get_ruleset_number(pr->rule.action);
2986 if (rs_num >= PF_RULESET_MAX) {
2987 error = EINVAL;
2988 break;
2989 }
2990 if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
2991 error = EBUSY;
2992 break;
2993 }
2994 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
2995 while ((rule != NULL) && (rule->nr != pr->nr)) {
2996 rule = TAILQ_NEXT(rule, entries);
2997 }
2998 if (rule == NULL) {
2999 error = EBUSY;
3000 break;
3001 }
3002 pf_rule_copyout(rule, &pr->rule);
3003 if (pf_anchor_copyout(ruleset, rule, pr)) {
3004 error = EBUSY;
3005 break;
3006 }
3007 pfi_dynaddr_copyout(&pr->rule.src.addr);
3008 pfi_dynaddr_copyout(&pr->rule.dst.addr);
3009 pf_tbladdr_copyout(&pr->rule.src.addr);
3010 pf_tbladdr_copyout(&pr->rule.dst.addr);
3011 pf_rtlabel_copyout(&pr->rule.src.addr);
3012 pf_rtlabel_copyout(&pr->rule.dst.addr);
3013 for (i = 0; i < PF_SKIP_COUNT; ++i) {
3014 if (rule->skip[i].ptr == NULL) {
3015 pr->rule.skip[i].nr = -1;
3016 } else {
3017 pr->rule.skip[i].nr =
3018 rule->skip[i].ptr->nr;
3019 }
3020 }
3021
3022 if (pr->action == PF_GET_CLR_CNTR) {
3023 rule->evaluations = 0;
3024 rule->packets[0] = rule->packets[1] = 0;
3025 rule->bytes[0] = rule->bytes[1] = 0;
3026 }
3027 break;
3028 }
3029
3030 case DIOCCHANGERULE: {
3031 struct pfioc_rule *pcr = pr;
3032 struct pf_rule *oldrule = NULL, *newrule = NULL;
3033 struct pf_pooladdr *pa;
3034 u_int32_t nr = 0;
3035 int rs_num;
3036
3037 if (!(pcr->action == PF_CHANGE_REMOVE ||
3038 pcr->action == PF_CHANGE_GET_TICKET) &&
3039 pcr->pool_ticket != ticket_pabuf) {
3040 error = EBUSY;
3041 break;
3042 }
3043
3044 if (pcr->action < PF_CHANGE_ADD_HEAD ||
3045 pcr->action > PF_CHANGE_GET_TICKET) {
3046 error = EINVAL;
3047 break;
3048 }
3049 pcr->anchor[sizeof(pcr->anchor) - 1] = '\0';
3050 pcr->anchor_call[sizeof(pcr->anchor_call) - 1] = '\0';
3051 ruleset = pf_find_ruleset(pcr->anchor);
3052 if (ruleset == NULL) {
3053 error = EINVAL;
3054 break;
3055 }
3056 rs_num = pf_get_ruleset_number(pcr->rule.action);
3057 if (rs_num >= PF_RULESET_MAX) {
3058 error = EINVAL;
3059 break;
3060 }
3061
3062 if (pcr->action == PF_CHANGE_GET_TICKET) {
3063 pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
3064 break;
3065 } else {
3066 if (pcr->ticket !=
3067 ruleset->rules[rs_num].active.ticket) {
3068 error = EINVAL;
3069 break;
3070 }
3071 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
3072 error = EINVAL;
3073 break;
3074 }
3075 }
3076
3077 if (pcr->action != PF_CHANGE_REMOVE) {
3078 newrule = pool_get(&pf_rule_pl, PR_WAITOK);
3079 if (newrule == NULL) {
3080 error = ENOMEM;
3081 break;
3082 }
3083 pf_rule_copyin(&pcr->rule, newrule, p, minordev);
3084 #if !INET
3085 if (newrule->af == AF_INET) {
3086 pool_put(&pf_rule_pl, newrule);
3087 error = EAFNOSUPPORT;
3088 break;
3089 }
3090 #endif /* INET */
3091 if (newrule->ifname[0]) {
3092 newrule->kif = pfi_kif_get(newrule->ifname);
3093 if (newrule->kif == NULL) {
3094 pool_put(&pf_rule_pl, newrule);
3095 error = EINVAL;
3096 break;
3097 }
3098 pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE);
3099 } else {
3100 newrule->kif = NULL;
3101 }
3102
3103 if (newrule->tagname[0]) {
3104 if ((newrule->tag =
3105 pf_tagname2tag(newrule->tagname)) == 0) {
3106 error = EBUSY;
3107 }
3108 }
3109 if (newrule->match_tagname[0]) {
3110 if ((newrule->match_tag = pf_tagname2tag(
3111 newrule->match_tagname)) == 0) {
3112 error = EBUSY;
3113 }
3114 }
3115 if (newrule->rt && !newrule->direction) {
3116 error = EINVAL;
3117 }
3118 #if PFLOG
3119 if (!newrule->log) {
3120 newrule->logif = 0;
3121 }
3122 if (newrule->logif >= PFLOGIFS_MAX) {
3123 error = EINVAL;
3124 }
3125 #endif /* PFLOG */
3126 pf_addrwrap_setup(&newrule->src.addr);
3127 pf_addrwrap_setup(&newrule->dst.addr);
3128 if (pf_rtlabel_add(&newrule->src.addr) ||
3129 pf_rtlabel_add(&newrule->dst.addr)) {
3130 error = EBUSY;
3131 }
3132 if (pfi_dynaddr_setup(&newrule->src.addr, newrule->af)) {
3133 error = EINVAL;
3134 }
3135 if (pfi_dynaddr_setup(&newrule->dst.addr, newrule->af)) {
3136 error = EINVAL;
3137 }
3138 if (pf_tbladdr_setup(ruleset, &newrule->src.addr)) {
3139 error = EINVAL;
3140 }
3141 if (pf_tbladdr_setup(ruleset, &newrule->dst.addr)) {
3142 error = EINVAL;
3143 }
3144 if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call)) {
3145 error = EINVAL;
3146 }
3147 TAILQ_FOREACH(pa, &pf_pabuf, entries)
3148 if (pf_tbladdr_setup(ruleset, &pa->addr)) {
3149 error = EINVAL;
3150 }
3151
3152 if (newrule->overload_tblname[0]) {
3153 if ((newrule->overload_tbl = pfr_attach_table(
3154 ruleset, newrule->overload_tblname)) ==
3155 NULL) {
3156 error = EINVAL;
3157 } else {
3158 newrule->overload_tbl->pfrkt_flags |=
3159 PFR_TFLAG_ACTIVE;
3160 }
3161 }
3162
3163 pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
3164 if (((((newrule->action == PF_NAT) ||
3165 (newrule->action == PF_RDR) ||
3166 (newrule->action == PF_BINAT) ||
3167 (newrule->rt > PF_FASTROUTE)) &&
3168 !newrule->anchor)) &&
3169 (TAILQ_FIRST(&newrule->rpool.list) == NULL)) {
3170 error = EINVAL;
3171 }
3172
3173 if (error) {
3174 pf_rm_rule(NULL, newrule);
3175 break;
3176 }
3177 newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
3178 newrule->evaluations = 0;
3179 newrule->packets[0] = newrule->packets[1] = 0;
3180 newrule->bytes[0] = newrule->bytes[1] = 0;
3181 }
3182 pf_empty_pool(&pf_pabuf);
3183
3184 if (pcr->action == PF_CHANGE_ADD_HEAD) {
3185 oldrule = TAILQ_FIRST(
3186 ruleset->rules[rs_num].active.ptr);
3187 } else if (pcr->action == PF_CHANGE_ADD_TAIL) {
3188 oldrule = TAILQ_LAST(
3189 ruleset->rules[rs_num].active.ptr, pf_rulequeue);
3190 } else {
3191 oldrule = TAILQ_FIRST(
3192 ruleset->rules[rs_num].active.ptr);
3193 while ((oldrule != NULL) && (oldrule->nr != pcr->nr)) {
3194 oldrule = TAILQ_NEXT(oldrule, entries);
3195 }
3196 if (oldrule == NULL) {
3197 if (newrule != NULL) {
3198 pf_rm_rule(NULL, newrule);
3199 }
3200 error = EINVAL;
3201 break;
3202 }
3203 }
3204
3205 if (pcr->action == PF_CHANGE_REMOVE) {
3206 pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
3207 ruleset->rules[rs_num].active.rcount--;
3208 } else {
3209 if (oldrule == NULL) {
3210 TAILQ_INSERT_TAIL(
3211 ruleset->rules[rs_num].active.ptr,
3212 newrule, entries);
3213 } else if (pcr->action == PF_CHANGE_ADD_HEAD ||
3214 pcr->action == PF_CHANGE_ADD_BEFORE) {
3215 TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
3216 } else {
3217 TAILQ_INSERT_AFTER(
3218 ruleset->rules[rs_num].active.ptr,
3219 oldrule, newrule, entries);
3220 }
3221 ruleset->rules[rs_num].active.rcount++;
3222 }
3223
3224 nr = 0;
3225 TAILQ_FOREACH(oldrule,
3226 ruleset->rules[rs_num].active.ptr, entries)
3227 oldrule->nr = nr++;
3228
3229 ruleset->rules[rs_num].active.ticket++;
3230
3231 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
3232 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
3233 pf_process_compatibilities();
3234 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
3235 break;
3236 }
3237
3238 case DIOCINSERTRULE: {
3239 struct pf_rule *rule, *tail, *r;
3240 int rs_num;
3241 int is_anchor;
3242
3243 pr->anchor[sizeof(pr->anchor) - 1] = '\0';
3244 pr->anchor_call[sizeof(pr->anchor_call) - 1] = '\0';
3245 is_anchor = (pr->anchor_call[0] != '\0');
3246
3247 if ((ruleset = pf_find_ruleset_with_owner(pr->anchor,
3248 pr->rule.owner, is_anchor, &error)) == NULL) {
3249 break;
3250 }
3251
3252 rs_num = pf_get_ruleset_number(pr->rule.action);
3253 if (rs_num >= PF_RULESET_MAX) {
3254 error = EINVAL;
3255 break;
3256 }
3257 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
3258 error = EINVAL;
3259 break;
3260 }
3261
3262 /* make sure this anchor rule doesn't exist already */
3263 if (is_anchor) {
3264 r = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
3265 while (r) {
3266 if (r->anchor &&
3267 ((strcmp(r->anchor->name,
3268 pr->anchor_call)) == 0)) {
3269 if (((strcmp(pr->rule.owner,
3270 r->owner)) == 0) ||
3271 ((strcmp(r->owner, "")) == 0)) {
3272 error = EEXIST;
3273 } else {
3274 error = EPERM;
3275 }
3276 break;
3277 }
3278 r = TAILQ_NEXT(r, entries);
3279 }
3280 if (error != 0) {
3281 break;
3282 }
3283 }
3284
3285 rule = pool_get(&pf_rule_pl, PR_WAITOK);
3286 if (rule == NULL) {
3287 error = ENOMEM;
3288 break;
3289 }
3290 pf_rule_copyin(&pr->rule, rule, p, minordev);
3291 #if !INET
3292 if (rule->af == AF_INET) {
3293 pool_put(&pf_rule_pl, rule);
3294 error = EAFNOSUPPORT;
3295 break;
3296 }
3297 #endif /* INET */
3298 r = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
3299 while ((r != NULL) && (rule->priority >= (unsigned)r->priority)) {
3300 r = TAILQ_NEXT(r, entries);
3301 }
3302 if (r == NULL) {
3303 if ((tail =
3304 TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
3305 pf_rulequeue)) != NULL) {
3306 rule->nr = tail->nr + 1;
3307 } else {
3308 rule->nr = 0;
3309 }
3310 } else {
3311 rule->nr = r->nr;
3312 }
3313
3314 if ((error = pf_rule_setup(pr, rule, ruleset))) {
3315 break;
3316 }
3317
3318 if (rule->anchor != NULL) {
3319 strlcpy(rule->anchor->owner, rule->owner,
3320 PF_OWNER_NAME_SIZE);
3321 }
3322
3323 if (r) {
3324 TAILQ_INSERT_BEFORE(r, rule, entries);
3325 while (r && ++r->nr) {
3326 r = TAILQ_NEXT(r, entries);
3327 }
3328 } else {
3329 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].active.ptr,
3330 rule, entries);
3331 }
3332 ruleset->rules[rs_num].active.rcount++;
3333
3334 /* Calculate checksum for the main ruleset */
3335 if (ruleset == &pf_main_ruleset) {
3336 error = pf_setup_pfsync_matching(ruleset);
3337 }
3338
3339 pf_ruleset_cleanup(ruleset, rs_num);
3340 rule->ticket = VM_KERNEL_ADDRPERM((u_int64_t)(uintptr_t)rule);
3341
3342 pr->rule.ticket = rule->ticket;
3343 pf_rule_copyout(rule, &pr->rule);
3344 if (rule->rule_flag & PFRULE_PFM) {
3345 pffwrules++;
3346 }
3347 if (rule->action == PF_NAT64) {
3348 os_atomic_inc(&pf_nat64_configured, relaxed);
3349 }
3350
3351 if (pr->anchor_call[0] == '\0') {
3352 INC_ATOMIC_INT64_LIM(net_api_stats.nas_pf_addrule_total);
3353 if (rule->rule_flag & PFRULE_PFM) {
3354 INC_ATOMIC_INT64_LIM(net_api_stats.nas_pf_addrule_os);
3355 }
3356 }
3357 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
3358 pf_process_compatibilities();
3359 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
3360 break;
3361 }
3362
3363 case DIOCDELETERULE: {
3364 ASSERT(ruleset == NULL);
3365 pr->anchor[sizeof(pr->anchor) - 1] = '\0';
3366 pr->anchor_call[sizeof(pr->anchor_call) - 1] = '\0';
3367
3368 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
3369 error = EINVAL;
3370 break;
3371 }
3372
3373 /* get device through which request is made */
3374 if ((uint8_t)minordev == PFDEV_PFM) {
3375 req_dev |= PFRULE_PFM;
3376 }
3377
3378 if (pr->rule.ticket) {
3379 if ((error = pf_delete_rule_by_ticket(pr, req_dev))) {
3380 break;
3381 }
3382 } else {
3383 pf_delete_rule_by_owner(pr->rule.owner, req_dev);
3384 }
3385 pr->nr = pffwrules;
3386 if (pr->rule.action == PF_NAT64) {
3387 os_atomic_dec(&pf_nat64_configured, relaxed);
3388 }
3389 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
3390 pf_process_compatibilities();
3391 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
3392 break;
3393 }
3394
3395 default:
3396 VERIFY(0);
3397 /* NOTREACHED */
3398 }
3399 if (ruleset != NULL) {
3400 pf_release_ruleset(ruleset);
3401 ruleset = NULL;
3402 }
3403
3404 return error;
3405 }
3406
3407 static int
pfioctl_ioc_state_kill(u_long cmd,struct pfioc_state_kill * psk,struct proc * p)3408 pfioctl_ioc_state_kill(u_long cmd, struct pfioc_state_kill *psk, struct proc *p)
3409 {
3410 #pragma unused(p)
3411 int error = 0;
3412
3413 psk->psk_ifname[sizeof(psk->psk_ifname) - 1] = '\0';
3414 psk->psk_ownername[sizeof(psk->psk_ownername) - 1] = '\0';
3415
3416 bool ifname_matched = true;
3417 bool owner_matched = true;
3418
3419 switch (cmd) {
3420 case DIOCCLRSTATES: {
3421 struct pf_state *s, *nexts;
3422 int killed = 0;
3423
3424 for (s = RB_MIN(pf_state_tree_id, &tree_id); s; s = nexts) {
3425 nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
3426 /*
3427 * Purge all states only when neither ifname
3428 * or owner is provided. If any of these are provided
3429 * we purge only the states with meta data that match
3430 */
3431 bool unlink_state = false;
3432 ifname_matched = true;
3433 owner_matched = true;
3434
3435 if (psk->psk_ifname[0] &&
3436 strcmp(psk->psk_ifname, s->kif->pfik_name)) {
3437 ifname_matched = false;
3438 }
3439
3440 if (psk->psk_ownername[0] &&
3441 ((NULL == s->rule.ptr) ||
3442 strcmp(psk->psk_ownername, s->rule.ptr->owner))) {
3443 owner_matched = false;
3444 }
3445
3446 unlink_state = ifname_matched && owner_matched;
3447
3448 if (unlink_state) {
3449 #if NPFSYNC
3450 /* don't send out individual delete messages */
3451 s->sync_flags = PFSTATE_NOSYNC;
3452 #endif
3453 pf_unlink_state(s);
3454 killed++;
3455 }
3456 }
3457 psk->psk_af = (sa_family_t)killed;
3458 #if NPFSYNC
3459 pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
3460 #endif
3461 break;
3462 }
3463
3464 case DIOCKILLSTATES: {
3465 struct pf_state *s, *nexts;
3466 struct pf_state_key *sk;
3467 struct pf_state_host *src, *dst;
3468 int killed = 0;
3469
3470 for (s = RB_MIN(pf_state_tree_id, &tree_id); s;
3471 s = nexts) {
3472 nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
3473 sk = s->state_key;
3474 ifname_matched = true;
3475 owner_matched = true;
3476
3477 if (psk->psk_ifname[0] &&
3478 strcmp(psk->psk_ifname, s->kif->pfik_name)) {
3479 ifname_matched = false;
3480 }
3481
3482 if (psk->psk_ownername[0] &&
3483 ((NULL == s->rule.ptr) ||
3484 strcmp(psk->psk_ownername, s->rule.ptr->owner))) {
3485 owner_matched = false;
3486 }
3487
3488 if (sk->direction == PF_OUT) {
3489 src = &sk->lan;
3490 dst = &sk->ext_lan;
3491 } else {
3492 src = &sk->ext_lan;
3493 dst = &sk->lan;
3494 }
3495 if ((!psk->psk_af || sk->af_lan == psk->psk_af) &&
3496 (!psk->psk_proto || psk->psk_proto == sk->proto) &&
3497 PF_MATCHA(psk->psk_src.neg,
3498 &psk->psk_src.addr.v.a.addr,
3499 &psk->psk_src.addr.v.a.mask,
3500 &src->addr, sk->af_lan) &&
3501 PF_MATCHA(psk->psk_dst.neg,
3502 &psk->psk_dst.addr.v.a.addr,
3503 &psk->psk_dst.addr.v.a.mask,
3504 &dst->addr, sk->af_lan) &&
3505 (pf_match_xport(psk->psk_proto,
3506 psk->psk_proto_variant, &psk->psk_src.xport,
3507 &src->xport)) &&
3508 (pf_match_xport(psk->psk_proto,
3509 psk->psk_proto_variant, &psk->psk_dst.xport,
3510 &dst->xport)) &&
3511 ifname_matched &&
3512 owner_matched) {
3513 #if NPFSYNC
3514 /* send immediate delete of state */
3515 pfsync_delete_state(s);
3516 s->sync_flags |= PFSTATE_NOSYNC;
3517 #endif
3518 pf_unlink_state(s);
3519 killed++;
3520 }
3521 }
3522 psk->psk_af = (sa_family_t)killed;
3523 break;
3524 }
3525
3526 default:
3527 VERIFY(0);
3528 /* NOTREACHED */
3529 }
3530
3531 return error;
3532 }
3533
3534 static int
pfioctl_ioc_state(u_long cmd,struct pfioc_state * ps,struct proc * p)3535 pfioctl_ioc_state(u_long cmd, struct pfioc_state *ps, struct proc *p)
3536 {
3537 #pragma unused(p)
3538 int error = 0;
3539
3540 switch (cmd) {
3541 case DIOCADDSTATE: {
3542 struct pfsync_state *sp = &ps->state;
3543 struct pf_state *s;
3544 struct pf_state_key *sk;
3545 struct pfi_kif *kif;
3546
3547 if (sp->timeout >= PFTM_MAX) {
3548 error = EINVAL;
3549 break;
3550 }
3551 s = pool_get(&pf_state_pl, PR_WAITOK);
3552 if (s == NULL) {
3553 error = ENOMEM;
3554 break;
3555 }
3556 bzero(s, sizeof(struct pf_state));
3557 if ((sk = pf_alloc_state_key(s, NULL)) == NULL) {
3558 pool_put(&pf_state_pl, s);
3559 error = ENOMEM;
3560 break;
3561 }
3562 pf_state_import(sp, sk, s);
3563 kif = pfi_kif_get(sp->ifname);
3564 if (kif == NULL) {
3565 pf_detach_state(s, 0);
3566 pool_put(&pf_state_pl, s);
3567 error = ENOENT;
3568 break;
3569 }
3570 TAILQ_INIT(&s->unlink_hooks);
3571 s->state_key->app_state = 0;
3572 if (pf_insert_state(kif, s)) {
3573 pfi_kif_unref(kif, PFI_KIF_REF_NONE);
3574 pool_put(&pf_state_pl, s);
3575 error = EEXIST;
3576 break;
3577 }
3578 pf_default_rule.states++;
3579 VERIFY(pf_default_rule.states != 0);
3580 break;
3581 }
3582
3583 case DIOCGETSTATE: {
3584 struct pf_state *s;
3585 struct pf_state_cmp id_key;
3586
3587 bcopy(ps->state.id, &id_key.id, sizeof(id_key.id));
3588 id_key.creatorid = ps->state.creatorid;
3589
3590 s = pf_find_state_byid(&id_key);
3591 if (s == NULL) {
3592 error = ENOENT;
3593 break;
3594 }
3595
3596 pf_state_export(&ps->state, s->state_key, s);
3597 break;
3598 }
3599
3600 default:
3601 VERIFY(0);
3602 /* NOTREACHED */
3603 }
3604
3605 return error;
3606 }
3607
3608 static int
pfioctl_ioc_states(u_long cmd,struct pfioc_states_32 * ps32,struct pfioc_states_64 * ps64,struct proc * p)3609 pfioctl_ioc_states(u_long cmd, struct pfioc_states_32 *ps32,
3610 struct pfioc_states_64 *ps64, struct proc *p)
3611 {
3612 int p64 = proc_is64bit(p);
3613 int error = 0;
3614
3615 switch (cmd) {
3616 case DIOCGETSTATES: { /* struct pfioc_states */
3617 struct pf_state *state;
3618 struct pfsync_state *pstore;
3619 user_addr_t buf;
3620 u_int32_t nr = 0;
3621 int len, size;
3622
3623 len = (p64 ? ps64->ps_len : ps32->ps_len);
3624 if (len == 0) {
3625 size = sizeof(struct pfsync_state) * pf_status.states;
3626 if (p64) {
3627 ps64->ps_len = size;
3628 } else {
3629 ps32->ps_len = size;
3630 }
3631 break;
3632 }
3633
3634 pstore = kalloc_type(struct pfsync_state,
3635 Z_WAITOK | Z_ZERO | Z_NOFAIL);
3636 #ifdef __LP64__
3637 buf = (p64 ? ps64->ps_buf : ps32->ps_buf);
3638 #else
3639 buf = ps32->ps_buf;
3640 #endif
3641
3642 state = TAILQ_FIRST(&state_list);
3643 while (state) {
3644 if (state->timeout != PFTM_UNLINKED) {
3645 if ((nr + 1) * sizeof(*pstore) > (unsigned)len) {
3646 break;
3647 }
3648
3649 pf_state_export(pstore,
3650 state->state_key, state);
3651 error = copyout(pstore, buf, sizeof(*pstore));
3652 if (error) {
3653 kfree_type(struct pfsync_state, pstore);
3654 goto fail;
3655 }
3656 buf += sizeof(*pstore);
3657 nr++;
3658 }
3659 state = TAILQ_NEXT(state, entry_list);
3660 }
3661
3662 size = sizeof(struct pfsync_state) * nr;
3663 if (p64) {
3664 ps64->ps_len = size;
3665 } else {
3666 ps32->ps_len = size;
3667 }
3668
3669 kfree_type(struct pfsync_state, pstore);
3670 break;
3671 }
3672
3673 default:
3674 VERIFY(0);
3675 /* NOTREACHED */
3676 }
3677 fail:
3678 return error;
3679 }
3680
3681 static int
pfioctl_ioc_natlook(u_long cmd,struct pfioc_natlook * pnl,struct proc * p)3682 pfioctl_ioc_natlook(u_long cmd, struct pfioc_natlook *pnl, struct proc *p)
3683 {
3684 #pragma unused(p)
3685 int error = 0;
3686
3687 switch (cmd) {
3688 case DIOCNATLOOK: {
3689 struct pf_state_key *sk;
3690 struct pf_state *state;
3691 struct pf_state_key_cmp key;
3692 int m = 0, direction = pnl->direction;
3693
3694 key.proto = pnl->proto;
3695 key.proto_variant = pnl->proto_variant;
3696
3697 if (!pnl->proto ||
3698 PF_AZERO(&pnl->saddr, pnl->af) ||
3699 PF_AZERO(&pnl->daddr, pnl->af) ||
3700 ((pnl->proto == IPPROTO_TCP ||
3701 pnl->proto == IPPROTO_UDP) &&
3702 (!pnl->dxport.port || !pnl->sxport.port))) {
3703 error = EINVAL;
3704 } else {
3705 /*
3706 * userland gives us source and dest of connection,
3707 * reverse the lookup so we ask for what happens with
3708 * the return traffic, enabling us to find it in the
3709 * state tree.
3710 */
3711 if (direction == PF_IN) {
3712 key.af_gwy = pnl->af;
3713 PF_ACPY(&key.ext_gwy.addr, &pnl->daddr,
3714 pnl->af);
3715 memcpy(&key.ext_gwy.xport, &pnl->dxport,
3716 sizeof(key.ext_gwy.xport));
3717 PF_ACPY(&key.gwy.addr, &pnl->saddr, pnl->af);
3718 memcpy(&key.gwy.xport, &pnl->sxport,
3719 sizeof(key.gwy.xport));
3720 state = pf_find_state_all(&key, PF_IN, &m);
3721 } else {
3722 key.af_lan = pnl->af;
3723 PF_ACPY(&key.lan.addr, &pnl->daddr, pnl->af);
3724 memcpy(&key.lan.xport, &pnl->dxport,
3725 sizeof(key.lan.xport));
3726 PF_ACPY(&key.ext_lan.addr, &pnl->saddr,
3727 pnl->af);
3728 memcpy(&key.ext_lan.xport, &pnl->sxport,
3729 sizeof(key.ext_lan.xport));
3730 state = pf_find_state_all(&key, PF_OUT, &m);
3731 }
3732 if (m > 1) {
3733 error = E2BIG; /* more than one state */
3734 } else if (state != NULL) {
3735 sk = state->state_key;
3736 if (direction == PF_IN) {
3737 PF_ACPY(&pnl->rsaddr, &sk->lan.addr,
3738 sk->af_lan);
3739 memcpy(&pnl->rsxport, &sk->lan.xport,
3740 sizeof(pnl->rsxport));
3741 PF_ACPY(&pnl->rdaddr, &pnl->daddr,
3742 pnl->af);
3743 memcpy(&pnl->rdxport, &pnl->dxport,
3744 sizeof(pnl->rdxport));
3745 } else {
3746 PF_ACPY(&pnl->rdaddr, &sk->gwy.addr,
3747 sk->af_gwy);
3748 memcpy(&pnl->rdxport, &sk->gwy.xport,
3749 sizeof(pnl->rdxport));
3750 PF_ACPY(&pnl->rsaddr, &pnl->saddr,
3751 pnl->af);
3752 memcpy(&pnl->rsxport, &pnl->sxport,
3753 sizeof(pnl->rsxport));
3754 }
3755 } else {
3756 error = ENOENT;
3757 }
3758 }
3759 break;
3760 }
3761
3762 default:
3763 VERIFY(0);
3764 /* NOTREACHED */
3765 }
3766
3767 return error;
3768 }
3769
3770 static int
pfioctl_ioc_tm(u_long cmd,struct pfioc_tm * pt,struct proc * p)3771 pfioctl_ioc_tm(u_long cmd, struct pfioc_tm *pt, struct proc *p)
3772 {
3773 #pragma unused(p)
3774 int error = 0;
3775
3776 switch (cmd) {
3777 case DIOCSETTIMEOUT: {
3778 int old;
3779
3780 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
3781 pt->seconds < 0) {
3782 error = EINVAL;
3783 goto fail;
3784 }
3785 old = pf_default_rule.timeout[pt->timeout];
3786 if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0) {
3787 pt->seconds = 1;
3788 }
3789 pf_default_rule.timeout[pt->timeout] = pt->seconds;
3790 if (pt->timeout == PFTM_INTERVAL && pt->seconds < old) {
3791 wakeup(pf_purge_thread_fn);
3792 }
3793 pt->seconds = old;
3794 break;
3795 }
3796
3797 case DIOCGETTIMEOUT: {
3798 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
3799 error = EINVAL;
3800 goto fail;
3801 }
3802 pt->seconds = pf_default_rule.timeout[pt->timeout];
3803 break;
3804 }
3805
3806 default:
3807 VERIFY(0);
3808 /* NOTREACHED */
3809 }
3810 fail:
3811 return error;
3812 }
3813
3814 static int
pfioctl_ioc_limit(u_long cmd,struct pfioc_limit * pl,struct proc * p)3815 pfioctl_ioc_limit(u_long cmd, struct pfioc_limit *pl, struct proc *p)
3816 {
3817 #pragma unused(p)
3818 int error = 0;
3819
3820 switch (cmd) {
3821 case DIOCGETLIMIT: {
3822 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
3823 error = EINVAL;
3824 goto fail;
3825 }
3826 pl->limit = pf_pool_limits[pl->index].limit;
3827 break;
3828 }
3829
3830 case DIOCSETLIMIT: {
3831 int old_limit;
3832
3833 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX ||
3834 pf_pool_limits[pl->index].pp == NULL) {
3835 error = EINVAL;
3836 goto fail;
3837 }
3838 pool_sethardlimit(pf_pool_limits[pl->index].pp,
3839 pl->limit, NULL, 0);
3840 old_limit = pf_pool_limits[pl->index].limit;
3841 pf_pool_limits[pl->index].limit = pl->limit;
3842 pl->limit = old_limit;
3843 break;
3844 }
3845
3846 default:
3847 VERIFY(0);
3848 /* NOTREACHED */
3849 }
3850 fail:
3851 return error;
3852 }
3853
3854 static int
pfioctl_ioc_pooladdr(u_long cmd,struct pfioc_pooladdr * pp,struct proc * p)3855 pfioctl_ioc_pooladdr(u_long cmd, struct pfioc_pooladdr *pp, struct proc *p)
3856 {
3857 #pragma unused(p)
3858 struct pf_pooladdr *pa = NULL;
3859 struct pf_pool *pool = NULL;
3860 int error = 0;
3861 struct pf_ruleset *ruleset = NULL;
3862
3863 switch (cmd) {
3864 case DIOCBEGINADDRS: {
3865 pf_empty_pool(&pf_pabuf);
3866 pp->ticket = ++ticket_pabuf;
3867 break;
3868 }
3869
3870 case DIOCADDADDR: {
3871 pp->anchor[sizeof(pp->anchor) - 1] = '\0';
3872 if (pp->ticket != ticket_pabuf) {
3873 error = EBUSY;
3874 break;
3875 }
3876 #if !INET
3877 if (pp->af == AF_INET) {
3878 error = EAFNOSUPPORT;
3879 break;
3880 }
3881 #endif /* INET */
3882 if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
3883 pp->addr.addr.type != PF_ADDR_DYNIFTL &&
3884 pp->addr.addr.type != PF_ADDR_TABLE) {
3885 error = EINVAL;
3886 break;
3887 }
3888 pa = pool_get(&pf_pooladdr_pl, PR_WAITOK);
3889 if (pa == NULL) {
3890 error = ENOMEM;
3891 break;
3892 }
3893 pf_pooladdr_copyin(&pp->addr, pa);
3894 if (pa->ifname[0]) {
3895 pa->kif = pfi_kif_get(pa->ifname);
3896 if (pa->kif == NULL) {
3897 pool_put(&pf_pooladdr_pl, pa);
3898 error = EINVAL;
3899 break;
3900 }
3901 pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE);
3902 }
3903 pf_addrwrap_setup(&pa->addr);
3904 if (pfi_dynaddr_setup(&pa->addr, pp->af)) {
3905 pfi_dynaddr_remove(&pa->addr);
3906 pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE);
3907 pool_put(&pf_pooladdr_pl, pa);
3908 error = EINVAL;
3909 break;
3910 }
3911 TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
3912 break;
3913 }
3914
3915 case DIOCGETADDRS: {
3916 pp->nr = 0;
3917 pp->anchor[sizeof(pp->anchor) - 1] = '\0';
3918 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
3919 pp->r_num, 0, 1, 0);
3920 if (pool == NULL) {
3921 error = EBUSY;
3922 break;
3923 }
3924 TAILQ_FOREACH(pa, &pool->list, entries)
3925 pp->nr++;
3926 break;
3927 }
3928
3929 case DIOCGETADDR: {
3930 u_int32_t nr = 0;
3931
3932 pp->anchor[sizeof(pp->anchor) - 1] = '\0';
3933 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
3934 pp->r_num, 0, 1, 1);
3935 if (pool == NULL) {
3936 error = EBUSY;
3937 break;
3938 }
3939 pa = TAILQ_FIRST(&pool->list);
3940 while ((pa != NULL) && (nr < pp->nr)) {
3941 pa = TAILQ_NEXT(pa, entries);
3942 nr++;
3943 }
3944 if (pa == NULL) {
3945 error = EBUSY;
3946 break;
3947 }
3948 pf_pooladdr_copyout(pa, &pp->addr);
3949 pfi_dynaddr_copyout(&pp->addr.addr);
3950 pf_tbladdr_copyout(&pp->addr.addr);
3951 pf_rtlabel_copyout(&pp->addr.addr);
3952 break;
3953 }
3954
3955 case DIOCCHANGEADDR: {
3956 struct pfioc_pooladdr *pca = pp;
3957 struct pf_pooladdr *oldpa = NULL, *newpa = NULL;
3958
3959 if (pca->action < PF_CHANGE_ADD_HEAD ||
3960 pca->action > PF_CHANGE_REMOVE) {
3961 error = EINVAL;
3962 break;
3963 }
3964 if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
3965 pca->addr.addr.type != PF_ADDR_DYNIFTL &&
3966 pca->addr.addr.type != PF_ADDR_TABLE) {
3967 error = EINVAL;
3968 break;
3969 }
3970
3971 pca->anchor[sizeof(pca->anchor) - 1] = '\0';
3972 ruleset = pf_find_ruleset(pca->anchor);
3973 if (ruleset == NULL) {
3974 error = EBUSY;
3975 break;
3976 }
3977 pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action,
3978 pca->r_num, pca->r_last, 1, 1);
3979 if (pool == NULL) {
3980 error = EBUSY;
3981 break;
3982 }
3983 if (pca->action != PF_CHANGE_REMOVE) {
3984 newpa = pool_get(&pf_pooladdr_pl, PR_WAITOK);
3985 if (newpa == NULL) {
3986 error = ENOMEM;
3987 break;
3988 }
3989 pf_pooladdr_copyin(&pca->addr, newpa);
3990 #if !INET
3991 if (pca->af == AF_INET) {
3992 pool_put(&pf_pooladdr_pl, newpa);
3993 error = EAFNOSUPPORT;
3994 break;
3995 }
3996 #endif /* INET */
3997 if (newpa->ifname[0]) {
3998 newpa->kif = pfi_kif_get(newpa->ifname);
3999 if (newpa->kif == NULL) {
4000 pool_put(&pf_pooladdr_pl, newpa);
4001 error = EINVAL;
4002 break;
4003 }
4004 pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE);
4005 } else {
4006 newpa->kif = NULL;
4007 }
4008 pf_addrwrap_setup(&newpa->addr);
4009 if (pfi_dynaddr_setup(&newpa->addr, pca->af) ||
4010 pf_tbladdr_setup(ruleset, &newpa->addr)) {
4011 pfi_dynaddr_remove(&newpa->addr);
4012 pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE);
4013 pool_put(&pf_pooladdr_pl, newpa);
4014 error = EINVAL;
4015 break;
4016 }
4017 }
4018
4019 if (pca->action == PF_CHANGE_ADD_HEAD) {
4020 oldpa = TAILQ_FIRST(&pool->list);
4021 } else if (pca->action == PF_CHANGE_ADD_TAIL) {
4022 oldpa = TAILQ_LAST(&pool->list, pf_palist);
4023 } else {
4024 int i = 0;
4025
4026 oldpa = TAILQ_FIRST(&pool->list);
4027 while ((oldpa != NULL) && (i < (int)pca->nr)) {
4028 oldpa = TAILQ_NEXT(oldpa, entries);
4029 i++;
4030 }
4031 if (oldpa == NULL) {
4032 error = EINVAL;
4033 break;
4034 }
4035 }
4036
4037 if (pca->action == PF_CHANGE_REMOVE) {
4038 TAILQ_REMOVE(&pool->list, oldpa, entries);
4039 pfi_dynaddr_remove(&oldpa->addr);
4040 pf_tbladdr_remove(&oldpa->addr);
4041 pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE);
4042 pool_put(&pf_pooladdr_pl, oldpa);
4043 } else {
4044 if (oldpa == NULL) {
4045 TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
4046 } else if (pca->action == PF_CHANGE_ADD_HEAD ||
4047 pca->action == PF_CHANGE_ADD_BEFORE) {
4048 TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
4049 } else {
4050 TAILQ_INSERT_AFTER(&pool->list, oldpa,
4051 newpa, entries);
4052 }
4053 }
4054
4055 pool->cur = TAILQ_FIRST(&pool->list);
4056 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
4057 pca->af);
4058 break;
4059 }
4060
4061 default:
4062 VERIFY(0);
4063 /* NOTREACHED */
4064 }
4065
4066 if (ruleset) {
4067 pf_release_ruleset(ruleset);
4068 ruleset = NULL;
4069 }
4070
4071 return error;
4072 }
4073
4074 static int
pfioctl_ioc_ruleset(u_long cmd,struct pfioc_ruleset * pr,struct proc * p)4075 pfioctl_ioc_ruleset(u_long cmd, struct pfioc_ruleset *pr, struct proc *p)
4076 {
4077 #pragma unused(p)
4078 int error = 0;
4079 struct pf_ruleset *ruleset = NULL;
4080
4081 switch (cmd) {
4082 case DIOCGETRULESETS: {
4083 struct pf_anchor *anchor;
4084
4085 pr->path[sizeof(pr->path) - 1] = '\0';
4086 pr->name[sizeof(pr->name) - 1] = '\0';
4087 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
4088 error = EINVAL;
4089 break;
4090 }
4091 pr->nr = 0;
4092 if (ruleset->anchor == NULL) {
4093 /* XXX kludge for pf_main_ruleset */
4094 RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
4095 if (anchor->parent == NULL) {
4096 pr->nr++;
4097 }
4098 } else {
4099 RB_FOREACH(anchor, pf_anchor_node,
4100 &ruleset->anchor->children)
4101 pr->nr++;
4102 }
4103 break;
4104 }
4105
4106 case DIOCGETRULESET: {
4107 struct pf_anchor *anchor;
4108 u_int32_t nr = 0;
4109
4110 pr->path[sizeof(pr->path) - 1] = '\0';
4111 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
4112 error = EINVAL;
4113 break;
4114 }
4115 pr->name[0] = 0;
4116 if (ruleset->anchor == NULL) {
4117 /* XXX kludge for pf_main_ruleset */
4118 RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
4119 if (anchor->parent == NULL && nr++ == pr->nr) {
4120 strlcpy(pr->name, anchor->name,
4121 sizeof(pr->name));
4122 break;
4123 }
4124 } else {
4125 RB_FOREACH(anchor, pf_anchor_node,
4126 &ruleset->anchor->children)
4127 if (nr++ == pr->nr) {
4128 strlcpy(pr->name, anchor->name,
4129 sizeof(pr->name));
4130 break;
4131 }
4132 }
4133 if (!pr->name[0]) {
4134 error = EBUSY;
4135 }
4136 break;
4137 }
4138
4139 default:
4140 VERIFY(0);
4141 /* NOTREACHED */
4142 }
4143
4144 if (ruleset) {
4145 pf_release_ruleset(ruleset);
4146 ruleset = NULL;
4147 }
4148 return error;
4149 }
4150
4151 static int
pfioctl_ioc_trans(u_long cmd,struct pfioc_trans_32 * io32,struct pfioc_trans_64 * io64,struct proc * p)4152 pfioctl_ioc_trans(u_long cmd, struct pfioc_trans_32 *io32,
4153 struct pfioc_trans_64 *io64, struct proc *p)
4154 {
4155 int error = 0, esize, size;
4156 user_addr_t buf;
4157 struct pf_ruleset *rs = NULL;
4158
4159 #ifdef __LP64__
4160 int p64 = proc_is64bit(p);
4161
4162 esize = (p64 ? io64->esize : io32->esize);
4163 size = (p64 ? io64->size : io32->size);
4164 buf = (p64 ? io64->array : io32->array);
4165 #else
4166 #pragma unused(io64, p)
4167 esize = io32->esize;
4168 size = io32->size;
4169 buf = io32->array;
4170 #endif
4171
4172 switch (cmd) {
4173 case DIOCXBEGIN: {
4174 struct pfioc_trans_e *ioe;
4175 struct pfr_table *table;
4176 int i;
4177
4178 if (esize != sizeof(*ioe)) {
4179 error = ENODEV;
4180 goto fail;
4181 }
4182 ioe = kalloc_type(struct pfioc_trans_e, Z_WAITOK);
4183 table = kalloc_type(struct pfr_table, Z_WAITOK);
4184 for (i = 0; i < size; i++, buf += sizeof(*ioe)) {
4185 if (copyin(buf, ioe, sizeof(*ioe))) {
4186 kfree_type(struct pfr_table, table);
4187 kfree_type(struct pfioc_trans_e, ioe);
4188 error = EFAULT;
4189 goto fail;
4190 }
4191 ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
4192 switch (ioe->rs_num) {
4193 case PF_RULESET_ALTQ:
4194 break;
4195 case PF_RULESET_TABLE:
4196 bzero(table, sizeof(*table));
4197 strlcpy(table->pfrt_anchor, ioe->anchor,
4198 sizeof(table->pfrt_anchor));
4199 if ((error = pfr_ina_begin(table,
4200 &ioe->ticket, NULL, 0))) {
4201 kfree_type(struct pfr_table, table);
4202 kfree_type(struct pfioc_trans_e, ioe);
4203 goto fail;
4204 }
4205 break;
4206 default:
4207 if ((error = pf_begin_rules(&ioe->ticket,
4208 ioe->rs_num, ioe->anchor))) {
4209 kfree_type(struct pfr_table, table);
4210 kfree_type(struct pfioc_trans_e, ioe);
4211 goto fail;
4212 }
4213 break;
4214 }
4215 if (copyout(ioe, buf, sizeof(*ioe))) {
4216 kfree_type(struct pfr_table, table);
4217 kfree_type(struct pfioc_trans_e, ioe);
4218 error = EFAULT;
4219 goto fail;
4220 }
4221 }
4222 kfree_type(struct pfr_table, table);
4223 kfree_type(struct pfioc_trans_e, ioe);
4224 break;
4225 }
4226
4227 case DIOCXROLLBACK: {
4228 struct pfioc_trans_e *ioe;
4229 struct pfr_table *table;
4230 int i;
4231
4232 if (esize != sizeof(*ioe)) {
4233 error = ENODEV;
4234 goto fail;
4235 }
4236 ioe = kalloc_type(struct pfioc_trans_e, Z_WAITOK);
4237 table = kalloc_type(struct pfr_table, Z_WAITOK);
4238 for (i = 0; i < size; i++, buf += sizeof(*ioe)) {
4239 if (copyin(buf, ioe, sizeof(*ioe))) {
4240 kfree_type(struct pfr_table, table);
4241 kfree_type(struct pfioc_trans_e, ioe);
4242 error = EFAULT;
4243 goto fail;
4244 }
4245 ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
4246 switch (ioe->rs_num) {
4247 case PF_RULESET_ALTQ:
4248 break;
4249 case PF_RULESET_TABLE:
4250 bzero(table, sizeof(*table));
4251 strlcpy(table->pfrt_anchor, ioe->anchor,
4252 sizeof(table->pfrt_anchor));
4253 if ((error = pfr_ina_rollback(table,
4254 ioe->ticket, NULL, 0))) {
4255 kfree_type(struct pfr_table, table);
4256 kfree_type(struct pfioc_trans_e, ioe);
4257 goto fail; /* really bad */
4258 }
4259 break;
4260 default:
4261 if ((error = pf_rollback_rules(ioe->ticket,
4262 ioe->rs_num, ioe->anchor))) {
4263 kfree_type(struct pfr_table, table);
4264 kfree_type(struct pfioc_trans_e, ioe);
4265 goto fail; /* really bad */
4266 }
4267 break;
4268 }
4269 }
4270 kfree_type(struct pfr_table, table);
4271 kfree_type(struct pfioc_trans_e, ioe);
4272 break;
4273 }
4274
4275 case DIOCXCOMMIT: {
4276 struct pfioc_trans_e *ioe;
4277 struct pfr_table *table;
4278 user_addr_t _buf = buf;
4279 int i;
4280
4281 if (esize != sizeof(*ioe)) {
4282 error = ENODEV;
4283 goto fail;
4284 }
4285 ioe = kalloc_type(struct pfioc_trans_e, Z_WAITOK);
4286 table = kalloc_type(struct pfr_table, Z_WAITOK);
4287 /* first makes sure everything will succeed */
4288 for (i = 0; i < size; i++, buf += sizeof(*ioe)) {
4289 if (copyin(buf, ioe, sizeof(*ioe))) {
4290 kfree_type(struct pfr_table, table);
4291 kfree_type(struct pfioc_trans_e, ioe);
4292 error = EFAULT;
4293 goto fail;
4294 }
4295 ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
4296 switch (ioe->rs_num) {
4297 case PF_RULESET_ALTQ:
4298 break;
4299 case PF_RULESET_TABLE:
4300 rs = pf_find_ruleset(ioe->anchor);
4301 if (rs == NULL || !rs->topen || ioe->ticket !=
4302 rs->tticket) {
4303 kfree_type(struct pfr_table, table);
4304 kfree_type(struct pfioc_trans_e, ioe);
4305 error = EBUSY;
4306 goto fail;
4307 }
4308 break;
4309 default:
4310 if (ioe->rs_num < 0 || ioe->rs_num >=
4311 PF_RULESET_MAX) {
4312 kfree_type(struct pfr_table, table);
4313 kfree_type(struct pfioc_trans_e, ioe);
4314 error = EINVAL;
4315 goto fail;
4316 }
4317 rs = pf_find_ruleset(ioe->anchor);
4318 if (rs == NULL ||
4319 !rs->rules[ioe->rs_num].inactive.open ||
4320 rs->rules[ioe->rs_num].inactive.ticket !=
4321 ioe->ticket) {
4322 kfree_type(struct pfr_table, table);
4323 kfree_type(struct pfioc_trans_e, ioe);
4324 error = EBUSY;
4325 goto fail;
4326 }
4327 break;
4328 }
4329 }
4330 buf = _buf;
4331 /* now do the commit - no errors should happen here */
4332 for (i = 0; i < size; i++, buf += sizeof(*ioe)) {
4333 if (copyin(buf, ioe, sizeof(*ioe))) {
4334 kfree_type(struct pfr_table, table);
4335 kfree_type(struct pfioc_trans_e, ioe);
4336 error = EFAULT;
4337 goto fail;
4338 }
4339 ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
4340 switch (ioe->rs_num) {
4341 case PF_RULESET_ALTQ:
4342 break;
4343 case PF_RULESET_TABLE:
4344 bzero(table, sizeof(*table));
4345 strlcpy(table->pfrt_anchor, ioe->anchor,
4346 sizeof(table->pfrt_anchor));
4347 if ((error = pfr_ina_commit(table, ioe->ticket,
4348 NULL, NULL, 0))) {
4349 kfree_type(struct pfr_table, table);
4350 kfree_type(struct pfioc_trans_e, ioe);
4351 goto fail;
4352 }
4353 break;
4354 default:
4355 if ((error = pf_commit_rules(ioe->ticket,
4356 ioe->rs_num, ioe->anchor))) {
4357 kfree_type(struct pfr_table, table);
4358 kfree_type(struct pfioc_trans_e, ioe);
4359 goto fail;
4360 }
4361 break;
4362 }
4363 }
4364 kfree_type(struct pfr_table, table);
4365 kfree_type(struct pfioc_trans_e, ioe);
4366 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
4367 pf_process_compatibilities();
4368 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
4369 break;
4370 }
4371
4372 default:
4373 VERIFY(0);
4374 /* NOTREACHED */
4375 }
4376 fail:
4377 if (rs) {
4378 pf_release_ruleset(rs);
4379 rs = NULL;
4380 }
4381 return error;
4382 }
4383
4384 static int
pfioctl_ioc_src_nodes(u_long cmd,struct pfioc_src_nodes_32 * psn32,struct pfioc_src_nodes_64 * psn64,struct proc * p)4385 pfioctl_ioc_src_nodes(u_long cmd, struct pfioc_src_nodes_32 *psn32,
4386 struct pfioc_src_nodes_64 *psn64, struct proc *p)
4387 {
4388 int p64 = proc_is64bit(p);
4389 int error = 0;
4390
4391 switch (cmd) {
4392 case DIOCGETSRCNODES: {
4393 struct pf_src_node *n, *pstore;
4394 user_addr_t buf;
4395 u_int32_t nr = 0;
4396 int space, size;
4397
4398 space = (p64 ? psn64->psn_len : psn32->psn_len);
4399 if (space == 0) {
4400 RB_FOREACH(n, pf_src_tree, &tree_src_tracking)
4401 nr++;
4402
4403 size = sizeof(struct pf_src_node) * nr;
4404 if (p64) {
4405 psn64->psn_len = size;
4406 } else {
4407 psn32->psn_len = size;
4408 }
4409 break;
4410 }
4411
4412 pstore = kalloc_type(struct pf_src_node, Z_WAITOK | Z_NOFAIL);
4413 #ifdef __LP64__
4414 buf = (p64 ? psn64->psn_buf : psn32->psn_buf);
4415 #else
4416 buf = psn32->psn_buf;
4417 #endif
4418
4419 RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
4420 uint64_t secs = pf_time_second(), diff;
4421
4422 if ((nr + 1) * sizeof(*pstore) > (unsigned)space) {
4423 break;
4424 }
4425
4426 bcopy(n, pstore, sizeof(*pstore));
4427 if (n->rule.ptr != NULL) {
4428 pstore->rule.nr = n->rule.ptr->nr;
4429 }
4430 pstore->creation = secs - pstore->creation;
4431 if (pstore->expire > secs) {
4432 pstore->expire -= secs;
4433 } else {
4434 pstore->expire = 0;
4435 }
4436
4437 /* adjust the connection rate estimate */
4438 diff = secs - n->conn_rate.last;
4439 if (diff >= n->conn_rate.seconds) {
4440 pstore->conn_rate.count = 0;
4441 } else {
4442 pstore->conn_rate.count -=
4443 n->conn_rate.count * diff /
4444 n->conn_rate.seconds;
4445 }
4446
4447 _RB_PARENT(pstore, entry) = NULL;
4448 RB_LEFT(pstore, entry) = RB_RIGHT(pstore, entry) = NULL;
4449 pstore->kif = NULL;
4450
4451 error = copyout(pstore, buf, sizeof(*pstore));
4452 if (error) {
4453 kfree_type(struct pf_src_node, pstore);
4454 goto fail;
4455 }
4456 buf += sizeof(*pstore);
4457 nr++;
4458 }
4459
4460 size = sizeof(struct pf_src_node) * nr;
4461 if (p64) {
4462 psn64->psn_len = size;
4463 } else {
4464 psn32->psn_len = size;
4465 }
4466
4467 kfree_type(struct pf_src_node, pstore);
4468 break;
4469 }
4470
4471 default:
4472 VERIFY(0);
4473 /* NOTREACHED */
4474 }
4475 fail:
4476 return error;
4477 }
4478
4479 static int
pfioctl_ioc_src_node_kill(u_long cmd,struct pfioc_src_node_kill * psnk,struct proc * p)4480 pfioctl_ioc_src_node_kill(u_long cmd, struct pfioc_src_node_kill *psnk,
4481 struct proc *p)
4482 {
4483 #pragma unused(p)
4484 int error = 0;
4485
4486 switch (cmd) {
4487 case DIOCKILLSRCNODES: {
4488 struct pf_src_node *sn;
4489 struct pf_state *s;
4490 int killed = 0;
4491
4492 RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) {
4493 if (PF_MATCHA(psnk->psnk_src.neg,
4494 &psnk->psnk_src.addr.v.a.addr,
4495 &psnk->psnk_src.addr.v.a.mask,
4496 &sn->addr, sn->af) &&
4497 PF_MATCHA(psnk->psnk_dst.neg,
4498 &psnk->psnk_dst.addr.v.a.addr,
4499 &psnk->psnk_dst.addr.v.a.mask,
4500 &sn->raddr, sn->af)) {
4501 /* Handle state to src_node linkage */
4502 if (sn->states != 0) {
4503 RB_FOREACH(s, pf_state_tree_id,
4504 &tree_id) {
4505 if (s->src_node == sn) {
4506 s->src_node = NULL;
4507 }
4508 if (s->nat_src_node == sn) {
4509 s->nat_src_node = NULL;
4510 }
4511 }
4512 sn->states = 0;
4513 }
4514 sn->expire = 1;
4515 killed++;
4516 }
4517 }
4518
4519 if (killed > 0) {
4520 pf_purge_expired_src_nodes();
4521 }
4522
4523 psnk->psnk_af = (sa_family_t)killed;
4524 break;
4525 }
4526
4527 default:
4528 VERIFY(0);
4529 /* NOTREACHED */
4530 }
4531
4532 return error;
4533 }
4534
4535 static int
pfioctl_ioc_iface(u_long cmd,struct pfioc_iface_32 * io32,struct pfioc_iface_64 * io64,struct proc * p)4536 pfioctl_ioc_iface(u_long cmd, struct pfioc_iface_32 *io32,
4537 struct pfioc_iface_64 *io64, struct proc *p)
4538 {
4539 int p64 = proc_is64bit(p);
4540 int error = 0;
4541
4542 switch (cmd) {
4543 case DIOCIGETIFACES: {
4544 user_addr_t buf;
4545 int esize;
4546
4547 #ifdef __LP64__
4548 buf = (p64 ? io64->pfiio_buffer : io32->pfiio_buffer);
4549 esize = (p64 ? io64->pfiio_esize : io32->pfiio_esize);
4550 #else
4551 buf = io32->pfiio_buffer;
4552 esize = io32->pfiio_esize;
4553 #endif
4554
4555 /* esize must be that of the user space version of pfi_kif */
4556 if (esize != sizeof(struct pfi_uif)) {
4557 error = ENODEV;
4558 break;
4559 }
4560 if (p64) {
4561 io64->pfiio_name[sizeof(io64->pfiio_name) - 1] = '\0';
4562 } else {
4563 io32->pfiio_name[sizeof(io32->pfiio_name) - 1] = '\0';
4564 }
4565 error = pfi_get_ifaces(
4566 p64 ? io64->pfiio_name : io32->pfiio_name, buf,
4567 p64 ? &io64->pfiio_size : &io32->pfiio_size);
4568 break;
4569 }
4570
4571 case DIOCSETIFFLAG: {
4572 if (p64) {
4573 io64->pfiio_name[sizeof(io64->pfiio_name) - 1] = '\0';
4574 } else {
4575 io32->pfiio_name[sizeof(io32->pfiio_name) - 1] = '\0';
4576 }
4577
4578 error = pfi_set_flags(
4579 p64 ? io64->pfiio_name : io32->pfiio_name,
4580 p64 ? io64->pfiio_flags : io32->pfiio_flags);
4581 break;
4582 }
4583
4584 case DIOCCLRIFFLAG: {
4585 if (p64) {
4586 io64->pfiio_name[sizeof(io64->pfiio_name) - 1] = '\0';
4587 } else {
4588 io32->pfiio_name[sizeof(io32->pfiio_name) - 1] = '\0';
4589 }
4590
4591 error = pfi_clear_flags(
4592 p64 ? io64->pfiio_name : io32->pfiio_name,
4593 p64 ? io64->pfiio_flags : io32->pfiio_flags);
4594 break;
4595 }
4596
4597 default:
4598 VERIFY(0);
4599 /* NOTREACHED */
4600 }
4601
4602 return error;
4603 }
4604
4605 int
pf_af_hook(struct ifnet * ifp,struct mbuf ** mppn,struct mbuf ** mp,unsigned int af,int input,struct ip_fw_args * fwa)4606 pf_af_hook(struct ifnet *ifp, struct mbuf **mppn, struct mbuf **mp,
4607 unsigned int af, int input, struct ip_fw_args *fwa)
4608 {
4609 int error = 0;
4610 struct mbuf *nextpkt;
4611 net_thread_marks_t marks;
4612 struct ifnet * pf_ifp = ifp;
4613
4614 /* Always allow traffic on co-processor and management interfaces. */
4615 if (ifp != NULL &&
4616 ((!intcoproc_unrestricted && IFNET_IS_INTCOPROC(ifp)) ||
4617 (!management_data_unrestricted && IFNET_IS_MANAGEMENT(ifp)))) {
4618 return 0;
4619 }
4620
4621 marks = net_thread_marks_push(NET_THREAD_HELD_PF);
4622
4623 if (marks != net_thread_marks_none) {
4624 lck_rw_lock_shared(&pf_perim_lock);
4625 if (!pf_is_enabled) {
4626 goto done;
4627 }
4628 lck_mtx_lock(&pf_lock);
4629 }
4630
4631 if (mppn != NULL && *mppn != NULL) {
4632 VERIFY(*mppn == *mp);
4633 }
4634 if ((nextpkt = (*mp)->m_nextpkt) != NULL) {
4635 (*mp)->m_nextpkt = NULL;
4636 }
4637
4638 /*
4639 * For packets destined to locally hosted IP address
4640 * ip_output_list sets Mbuf's pkt header's rcvif to
4641 * the interface hosting the IP address.
4642 * While on the output path ifp passed to pf_af_hook
4643 * to such local communication is the loopback interface,
4644 * the input path derives ifp from mbuf packet header's
4645 * rcvif.
4646 * This asymmetry caues issues with PF.
4647 * To handle that case, we have a limited change here to
4648 * pass interface as loopback if packets are looped in.
4649 */
4650 if (input && ((*mp)->m_pkthdr.pkt_flags & PKTF_LOOP)) {
4651 pf_ifp = lo_ifp;
4652 }
4653
4654 switch (af) {
4655 #if INET
4656 case AF_INET: {
4657 error = pf_inet_hook(pf_ifp, mp, input, fwa);
4658 break;
4659 }
4660 #endif /* INET */
4661 case AF_INET6:
4662 error = pf_inet6_hook(pf_ifp, mp, input, fwa);
4663 break;
4664 default:
4665 break;
4666 }
4667
4668 /* When packet valid, link to the next packet */
4669 if (*mp != NULL && nextpkt != NULL) {
4670 struct mbuf *m = *mp;
4671 while (m->m_nextpkt != NULL) {
4672 m = m->m_nextpkt;
4673 }
4674 m->m_nextpkt = nextpkt;
4675 }
4676 /* Fix up linkage of previous packet in the chain */
4677 if (mppn != NULL) {
4678 if (*mp != NULL) {
4679 *mppn = *mp;
4680 } else {
4681 *mppn = nextpkt;
4682 }
4683 }
4684
4685 if (marks != net_thread_marks_none) {
4686 lck_mtx_unlock(&pf_lock);
4687 }
4688
4689 done:
4690 if (marks != net_thread_marks_none) {
4691 lck_rw_done(&pf_perim_lock);
4692 }
4693
4694 net_thread_marks_pop(marks);
4695 return error;
4696 }
4697
4698
4699 #if INET
4700 static __attribute__((noinline)) int
pf_inet_hook(struct ifnet * ifp,struct mbuf ** mp,int input,struct ip_fw_args * fwa)4701 pf_inet_hook(struct ifnet *ifp, struct mbuf **mp, int input,
4702 struct ip_fw_args *fwa)
4703 {
4704 struct mbuf *m = *mp;
4705 #if BYTE_ORDER != BIG_ENDIAN
4706 struct ip *ip = mtod(m, struct ip *);
4707 #endif
4708 int error = 0;
4709
4710 /*
4711 * If the packet is outbound, is originated locally, is flagged for
4712 * delayed UDP/TCP checksum calculation, and is about to be processed
4713 * for an interface that doesn't support the appropriate checksum
4714 * offloading, then calculated the checksum here so that PF can adjust
4715 * it properly.
4716 */
4717 if (!input && m->m_pkthdr.rcvif == NULL) {
4718 static const int mask = CSUM_DELAY_DATA;
4719 const int flags = m->m_pkthdr.csum_flags &
4720 ~IF_HWASSIST_CSUM_FLAGS(ifp->if_hwassist);
4721
4722 if (flags & mask) {
4723 in_delayed_cksum(m);
4724 m->m_pkthdr.csum_flags &= ~mask;
4725 }
4726 }
4727
4728 #if BYTE_ORDER != BIG_ENDIAN
4729 HTONS(ip->ip_len);
4730 HTONS(ip->ip_off);
4731 #endif
4732 if (pf_test_mbuf(input ? PF_IN : PF_OUT, ifp, mp, NULL, fwa) != PF_PASS) {
4733 if (*mp != NULL) {
4734 m_freem(*mp);
4735 *mp = NULL;
4736 error = EHOSTUNREACH;
4737 } else {
4738 error = EJUSTRETURN;
4739 }
4740 }
4741 #if BYTE_ORDER != BIG_ENDIAN
4742 else {
4743 if (*mp != NULL) {
4744 ip = mtod(*mp, struct ip *);
4745 NTOHS(ip->ip_len);
4746 NTOHS(ip->ip_off);
4747 }
4748 }
4749 #endif
4750 return error;
4751 }
4752 #endif /* INET */
4753
4754 int __attribute__((noinline))
pf_inet6_hook(struct ifnet * ifp,struct mbuf ** mp,int input,struct ip_fw_args * fwa)4755 pf_inet6_hook(struct ifnet *ifp, struct mbuf **mp, int input,
4756 struct ip_fw_args *fwa)
4757 {
4758 int error = 0;
4759
4760 /*
4761 * If the packet is outbound, is originated locally, is flagged for
4762 * delayed UDP/TCP checksum calculation, and is about to be processed
4763 * for an interface that doesn't support the appropriate checksum
4764 * offloading, then calculated the checksum here so that PF can adjust
4765 * it properly.
4766 */
4767 if (!input && (*mp)->m_pkthdr.rcvif == NULL) {
4768 static const int mask = CSUM_DELAY_IPV6_DATA;
4769 const int flags = (*mp)->m_pkthdr.csum_flags &
4770 ~IF_HWASSIST_CSUM_FLAGS(ifp->if_hwassist);
4771
4772 if (flags & mask) {
4773 /*
4774 * Checksum offload should not have been enabled
4775 * when extension headers exist, thus 0 for optlen.
4776 */
4777 in6_delayed_cksum(*mp);
4778 (*mp)->m_pkthdr.csum_flags &= ~mask;
4779 }
4780 }
4781
4782 if (pf_test6_mbuf(input ? PF_IN : PF_OUT, ifp, mp, NULL, fwa) != PF_PASS) {
4783 if (*mp != NULL) {
4784 m_freem(*mp);
4785 *mp = NULL;
4786 error = EHOSTUNREACH;
4787 } else {
4788 error = EJUSTRETURN;
4789 }
4790 }
4791 return error;
4792 }
4793
4794 int
pf_ifaddr_hook(struct ifnet * ifp)4795 pf_ifaddr_hook(struct ifnet *ifp)
4796 {
4797 struct pfi_kif *kif = ifp->if_pf_kif;
4798
4799 if (kif != NULL) {
4800 lck_rw_lock_shared(&pf_perim_lock);
4801 lck_mtx_lock(&pf_lock);
4802
4803 pfi_kifaddr_update(kif);
4804
4805 lck_mtx_unlock(&pf_lock);
4806 lck_rw_done(&pf_perim_lock);
4807 }
4808 return 0;
4809 }
4810
4811 /*
4812 * Caller acquires dlil lock as writer (exclusive)
4813 */
4814 void
pf_ifnet_hook(struct ifnet * ifp,int attach)4815 pf_ifnet_hook(struct ifnet *ifp, int attach)
4816 {
4817 lck_rw_lock_shared(&pf_perim_lock);
4818 lck_mtx_lock(&pf_lock);
4819 if (attach) {
4820 pfi_attach_ifnet(ifp);
4821 } else {
4822 pfi_detach_ifnet(ifp);
4823 }
4824 lck_mtx_unlock(&pf_lock);
4825 lck_rw_done(&pf_perim_lock);
4826 }
4827
4828 static void
pf_attach_hooks(void)4829 pf_attach_hooks(void)
4830 {
4831 ifnet_head_lock_shared();
4832 /*
4833 * Check against ifnet_addrs[] before proceeding, in case this
4834 * is called very early on, e.g. during dlil_init() before any
4835 * network interface is attached.
4836 */
4837 if (ifnet_addrs != NULL) {
4838 int i;
4839
4840 for (i = 0; i <= if_index; i++) {
4841 struct ifnet *ifp = ifindex2ifnet[i];
4842 if (ifp != NULL) {
4843 pfi_attach_ifnet(ifp);
4844 }
4845 }
4846 }
4847 ifnet_head_done();
4848 }
4849
4850 #if 0
4851 /* currently unused along with pfdetach() */
4852 static void
4853 pf_detach_hooks(void)
4854 {
4855 ifnet_head_lock_shared();
4856 if (ifnet_addrs != NULL) {
4857 for (i = 0; i <= if_index; i++) {
4858 int i;
4859
4860 struct ifnet *ifp = ifindex2ifnet[i];
4861 if (ifp != NULL && ifp->if_pf_kif != NULL) {
4862 pfi_detach_ifnet(ifp);
4863 }
4864 }
4865 }
4866 ifnet_head_done();
4867 }
4868 #endif
4869
4870 /*
4871 * 'D' group ioctls.
4872 *
4873 * The switch statement below does nothing at runtime, as it serves as a
4874 * compile time check to ensure that all of the socket 'D' ioctls (those
4875 * in the 'D' group going thru soo_ioctl) that are made available by the
4876 * networking stack is unique. This works as long as this routine gets
4877 * updated each time a new interface ioctl gets added.
4878 *
4879 * Any failures at compile time indicates duplicated ioctl values.
4880 */
4881 static __attribute__((unused)) void
pfioctl_cassert(void)4882 pfioctl_cassert(void)
4883 {
4884 /*
4885 * This is equivalent to _CASSERT() and the compiler wouldn't
4886 * generate any instructions, thus for compile time only.
4887 */
4888 switch ((u_long)0) {
4889 case 0:
4890
4891 /* bsd/net/pfvar.h */
4892 case DIOCSTART:
4893 case DIOCSTOP:
4894 case DIOCADDRULE:
4895 case DIOCGETSTARTERS:
4896 case DIOCGETRULES:
4897 case DIOCGETRULE:
4898 case DIOCSTARTREF:
4899 case DIOCSTOPREF:
4900 case DIOCCLRSTATES:
4901 case DIOCGETSTATE:
4902 case DIOCSETSTATUSIF:
4903 case DIOCGETSTATUS:
4904 case DIOCCLRSTATUS:
4905 case DIOCNATLOOK:
4906 case DIOCSETDEBUG:
4907 case DIOCGETSTATES:
4908 case DIOCCHANGERULE:
4909 case DIOCINSERTRULE:
4910 case DIOCDELETERULE:
4911 case DIOCSETTIMEOUT:
4912 case DIOCGETTIMEOUT:
4913 case DIOCADDSTATE:
4914 case DIOCCLRRULECTRS:
4915 case DIOCGETLIMIT:
4916 case DIOCSETLIMIT:
4917 case DIOCKILLSTATES:
4918 case DIOCSTARTALTQ:
4919 case DIOCSTOPALTQ:
4920 case DIOCADDALTQ:
4921 case DIOCGETALTQS:
4922 case DIOCGETALTQ:
4923 case DIOCCHANGEALTQ:
4924 case DIOCGETQSTATS:
4925 case DIOCBEGINADDRS:
4926 case DIOCADDADDR:
4927 case DIOCGETADDRS:
4928 case DIOCGETADDR:
4929 case DIOCCHANGEADDR:
4930 case DIOCGETRULESETS:
4931 case DIOCGETRULESET:
4932 case DIOCRCLRTABLES:
4933 case DIOCRADDTABLES:
4934 case DIOCRDELTABLES:
4935 case DIOCRGETTABLES:
4936 case DIOCRGETTSTATS:
4937 case DIOCRCLRTSTATS:
4938 case DIOCRCLRADDRS:
4939 case DIOCRADDADDRS:
4940 case DIOCRDELADDRS:
4941 case DIOCRSETADDRS:
4942 case DIOCRGETADDRS:
4943 case DIOCRGETASTATS:
4944 case DIOCRCLRASTATS:
4945 case DIOCRTSTADDRS:
4946 case DIOCRSETTFLAGS:
4947 case DIOCRINADEFINE:
4948 case DIOCOSFPFLUSH:
4949 case DIOCOSFPADD:
4950 case DIOCOSFPGET:
4951 case DIOCXBEGIN:
4952 case DIOCXCOMMIT:
4953 case DIOCXROLLBACK:
4954 case DIOCGETSRCNODES:
4955 case DIOCCLRSRCNODES:
4956 case DIOCSETHOSTID:
4957 case DIOCIGETIFACES:
4958 case DIOCSETIFFLAG:
4959 case DIOCCLRIFFLAG:
4960 case DIOCKILLSRCNODES:
4961 case DIOCGIFSPEED:
4962 ;
4963 }
4964 }
4965
4966 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
4967 static void
pf_process_compatibilities(void)4968 pf_process_compatibilities(void)
4969 {
4970 uint32_t compat_bitmap = pf_check_compatible_rules();
4971
4972 net_filter_event_mark(NET_FILTER_EVENT_PF,
4973 (compat_bitmap &
4974 (PF_COMPATIBLE_FLAGS_CUSTOM_ANCHORS_PRESENT |
4975 PF_COMPATIBLE_FLAGS_CUSTOM_RULES_PRESENT)) == 0);
4976
4977 net_filter_event_mark(NET_FILTER_EVENT_PF_PRIVATE_PROXY,
4978 ((compat_bitmap & PF_COMPATIBLE_FLAGS_PF_ENABLED) == 0) ||
4979 (compat_bitmap & PF_COMPATIBLE_FLAGS_CUSTOM_RULES_PRESENT) == 0);
4980 }
4981 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
4982