xref: /xnu-10063.121.3/bsd/net/pf_ioctl.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
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_ADDRHASH((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 	 * userland should not pass any skip pointers to us
1230 	 */
1231 	for (uint32_t i = 0; i < PF_SKIP_COUNT; ++i) {
1232 		dst->skip[i].ptr = 0;
1233 	}
1234 }
1235 
1236 static void
pf_rule_copyout(struct pf_rule * src,struct pf_rule * dst)1237 pf_rule_copyout(struct pf_rule *src, struct pf_rule *dst)
1238 {
1239 	bcopy(src, dst, sizeof(struct pf_rule));
1240 
1241 	dst->anchor = NULL;
1242 	dst->kif = NULL;
1243 	dst->overload_tbl = NULL;
1244 
1245 	dst->rpool.list.tqh_first = NULL;
1246 	dst->rpool.list.tqh_last = NULL;
1247 	dst->rpool.cur = NULL;
1248 
1249 	dst->entries.tqe_prev = NULL;
1250 	dst->entries.tqe_next = NULL;
1251 
1252 	/*
1253 	 * redact skip pointers for security
1254 	 */
1255 	for (uint32_t i = 0; i < PF_SKIP_COUNT; ++i) {
1256 		dst->skip[i].ptr = 0;
1257 	}
1258 }
1259 
1260 static void
pf_state_export(struct pfsync_state * sp,struct pf_state_key * sk,struct pf_state * s)1261 pf_state_export(struct pfsync_state *sp, struct pf_state_key *sk,
1262     struct pf_state *s)
1263 {
1264 	uint64_t secs = pf_time_second();
1265 	bzero(sp, sizeof(struct pfsync_state));
1266 
1267 	/* copy from state key */
1268 	sp->lan.addr = sk->lan.addr;
1269 	sp->lan.xport = sk->lan.xport;
1270 	sp->gwy.addr = sk->gwy.addr;
1271 	sp->gwy.xport = sk->gwy.xport;
1272 	sp->ext_lan.addr = sk->ext_lan.addr;
1273 	sp->ext_lan.xport = sk->ext_lan.xport;
1274 	sp->ext_gwy.addr = sk->ext_gwy.addr;
1275 	sp->ext_gwy.xport = sk->ext_gwy.xport;
1276 	sp->proto_variant = sk->proto_variant;
1277 	sp->tag = s->tag;
1278 	sp->proto = sk->proto;
1279 	sp->af_lan = sk->af_lan;
1280 	sp->af_gwy = sk->af_gwy;
1281 	sp->direction = sk->direction;
1282 	sp->flowhash = sk->flowhash;
1283 
1284 	/* copy from state */
1285 	memcpy(&sp->id, &s->id, sizeof(sp->id));
1286 	sp->creatorid = s->creatorid;
1287 	strlcpy(sp->ifname, s->kif->pfik_name, sizeof(sp->ifname));
1288 	pf_state_peer_to_pfsync(&s->src, &sp->src);
1289 	pf_state_peer_to_pfsync(&s->dst, &sp->dst);
1290 
1291 	sp->rule = s->rule.ptr->nr;
1292 	sp->nat_rule = (s->nat_rule.ptr == NULL) ?
1293 	    (unsigned)-1 : s->nat_rule.ptr->nr;
1294 	sp->anchor = (s->anchor.ptr == NULL) ?
1295 	    (unsigned)-1 : s->anchor.ptr->nr;
1296 
1297 	pf_state_counter_to_pfsync(s->bytes[0], sp->bytes[0]);
1298 	pf_state_counter_to_pfsync(s->bytes[1], sp->bytes[1]);
1299 	pf_state_counter_to_pfsync(s->packets[0], sp->packets[0]);
1300 	pf_state_counter_to_pfsync(s->packets[1], sp->packets[1]);
1301 	sp->creation = secs - s->creation;
1302 	sp->expire = pf_state_expires(s);
1303 	sp->log = s->log;
1304 	sp->allow_opts = s->allow_opts;
1305 	sp->timeout = s->timeout;
1306 
1307 	if (s->src_node) {
1308 		sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
1309 	}
1310 	if (s->nat_src_node) {
1311 		sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
1312 	}
1313 
1314 	if (sp->expire > secs) {
1315 		sp->expire -= secs;
1316 	} else {
1317 		sp->expire = 0;
1318 	}
1319 }
1320 
1321 static void
pf_state_import(struct pfsync_state * sp,struct pf_state_key * sk,struct pf_state * s)1322 pf_state_import(struct pfsync_state *sp, struct pf_state_key *sk,
1323     struct pf_state *s)
1324 {
1325 	/* copy to state key */
1326 	sk->lan.addr = sp->lan.addr;
1327 	sk->lan.xport = sp->lan.xport;
1328 	sk->gwy.addr = sp->gwy.addr;
1329 	sk->gwy.xport = sp->gwy.xport;
1330 	sk->ext_lan.addr = sp->ext_lan.addr;
1331 	sk->ext_lan.xport = sp->ext_lan.xport;
1332 	sk->ext_gwy.addr = sp->ext_gwy.addr;
1333 	sk->ext_gwy.xport = sp->ext_gwy.xport;
1334 	sk->proto_variant = sp->proto_variant;
1335 	s->tag = sp->tag;
1336 	sk->proto = sp->proto;
1337 	sk->af_lan = sp->af_lan;
1338 	sk->af_gwy = sp->af_gwy;
1339 	sk->direction = sp->direction;
1340 	ASSERT(sk->flowsrc == FLOWSRC_PF);
1341 	ASSERT(sk->flowhash != 0);
1342 
1343 	/* copy to state */
1344 	memcpy(&s->id, &sp->id, sizeof(sp->id));
1345 	s->creatorid = sp->creatorid;
1346 	pf_state_peer_from_pfsync(&sp->src, &s->src);
1347 	pf_state_peer_from_pfsync(&sp->dst, &s->dst);
1348 
1349 	s->rule.ptr = &pf_default_rule;
1350 	s->nat_rule.ptr = NULL;
1351 	s->anchor.ptr = NULL;
1352 	s->rt_kif = NULL;
1353 	s->creation = pf_time_second();
1354 	s->expire = pf_time_second();
1355 	if (sp->expire > 0) {
1356 		s->expire -= pf_default_rule.timeout[sp->timeout] - sp->expire;
1357 	}
1358 	s->pfsync_time = 0;
1359 	s->packets[0] = s->packets[1] = 0;
1360 	s->bytes[0] = s->bytes[1] = 0;
1361 }
1362 
1363 static void
pf_pooladdr_copyin(struct pf_pooladdr * src,struct pf_pooladdr * dst)1364 pf_pooladdr_copyin(struct pf_pooladdr *src, struct pf_pooladdr *dst)
1365 {
1366 	bcopy(src, dst, sizeof(struct pf_pooladdr));
1367 
1368 	dst->entries.tqe_prev = NULL;
1369 	dst->entries.tqe_next = NULL;
1370 	dst->ifname[sizeof(dst->ifname) - 1] = '\0';
1371 	dst->kif = NULL;
1372 }
1373 
1374 static void
pf_pooladdr_copyout(struct pf_pooladdr * src,struct pf_pooladdr * dst)1375 pf_pooladdr_copyout(struct pf_pooladdr *src, struct pf_pooladdr *dst)
1376 {
1377 	bcopy(src, dst, sizeof(struct pf_pooladdr));
1378 
1379 	dst->entries.tqe_prev = NULL;
1380 	dst->entries.tqe_next = NULL;
1381 	dst->kif = NULL;
1382 }
1383 
1384 static int
pf_setup_pfsync_matching(struct pf_ruleset * rs)1385 pf_setup_pfsync_matching(struct pf_ruleset *rs)
1386 {
1387 	MD5_CTX                  ctx;
1388 	struct pf_rule          *rule;
1389 	int                      rs_cnt;
1390 	u_int8_t                 digest[PF_MD5_DIGEST_LENGTH];
1391 
1392 	MD5Init(&ctx);
1393 	for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) {
1394 		/* XXX PF_RULESET_SCRUB as well? */
1395 		if (rs_cnt == PF_RULESET_SCRUB) {
1396 			continue;
1397 		}
1398 
1399 		rs->rules[rs_cnt].inactive.ptr_array = krealloc_type(struct pf_rule *,
1400 		    rs->rules[rs_cnt].inactive.rsize, rs->rules[rs_cnt].inactive.rcount,
1401 		    rs->rules[rs_cnt].inactive.ptr_array, Z_WAITOK | Z_REALLOCF);
1402 
1403 		if (rs->rules[rs_cnt].inactive.rcount &&
1404 		    !rs->rules[rs_cnt].inactive.ptr_array) {
1405 			rs->rules[rs_cnt].inactive.rsize = 0;
1406 			return ENOMEM;
1407 		}
1408 		rs->rules[rs_cnt].inactive.rsize =
1409 		    rs->rules[rs_cnt].inactive.rcount;
1410 
1411 		TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
1412 		    entries) {
1413 			pf_hash_rule(&ctx, rule);
1414 			(rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
1415 		}
1416 	}
1417 
1418 	MD5Final(digest, &ctx);
1419 	memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum));
1420 	return 0;
1421 }
1422 
1423 static void
pf_start(void)1424 pf_start(void)
1425 {
1426 	LCK_MTX_ASSERT(&pf_lock, LCK_MTX_ASSERT_OWNED);
1427 
1428 	VERIFY(pf_is_enabled == 0);
1429 
1430 	pf_is_enabled = 1;
1431 	pf_status.running = 1;
1432 	pf_status.since = pf_calendar_time_second();
1433 	if (pf_status.stateid == 0) {
1434 		pf_status.stateid = pf_time_second();
1435 		pf_status.stateid = pf_status.stateid << 32;
1436 	}
1437 	wakeup(pf_purge_thread_fn);
1438 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
1439 	pf_process_compatibilities();
1440 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
1441 	DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
1442 }
1443 
1444 static void
pf_stop(void)1445 pf_stop(void)
1446 {
1447 	LCK_MTX_ASSERT(&pf_lock, LCK_MTX_ASSERT_OWNED);
1448 
1449 	VERIFY(pf_is_enabled);
1450 
1451 	pf_status.running = 0;
1452 	pf_is_enabled = 0;
1453 	pf_status.since = pf_calendar_time_second();
1454 	wakeup(pf_purge_thread_fn);
1455 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
1456 	pf_process_compatibilities();
1457 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
1458 	DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
1459 }
1460 
1461 static int
pfioctl(dev_t dev,u_long cmd,caddr_t addr,int flags,struct proc * p)1462 pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
1463 {
1464 #pragma unused(dev)
1465 	int p64 = proc_is64bit(p);
1466 	int error = 0;
1467 	int minordev = minor(dev);
1468 
1469 	if (kauth_cred_issuser(kauth_cred_get()) == 0) {
1470 		return EPERM;
1471 	}
1472 
1473 	/* XXX keep in sync with switch() below */
1474 	if (securelevel > 1) {
1475 		switch (cmd) {
1476 		case DIOCGETRULES:
1477 		case DIOCGETRULE:
1478 		case DIOCGETADDRS:
1479 		case DIOCGETADDR:
1480 		case DIOCGETSTATE:
1481 		case DIOCSETSTATUSIF:
1482 		case DIOCGETSTATUS:
1483 		case DIOCCLRSTATUS:
1484 		case DIOCNATLOOK:
1485 		case DIOCSETDEBUG:
1486 		case DIOCGETSTATES:
1487 		case DIOCINSERTRULE:
1488 		case DIOCDELETERULE:
1489 		case DIOCGETTIMEOUT:
1490 		case DIOCCLRRULECTRS:
1491 		case DIOCGETLIMIT:
1492 		case DIOCGETALTQS:
1493 		case DIOCGETALTQ:
1494 		case DIOCGETQSTATS:
1495 		case DIOCGETRULESETS:
1496 		case DIOCGETRULESET:
1497 		case DIOCRGETTABLES:
1498 		case DIOCRGETTSTATS:
1499 		case DIOCRCLRTSTATS:
1500 		case DIOCRCLRADDRS:
1501 		case DIOCRADDADDRS:
1502 		case DIOCRDELADDRS:
1503 		case DIOCRSETADDRS:
1504 		case DIOCRGETADDRS:
1505 		case DIOCRGETASTATS:
1506 		case DIOCRCLRASTATS:
1507 		case DIOCRTSTADDRS:
1508 		case DIOCOSFPGET:
1509 		case DIOCGETSRCNODES:
1510 		case DIOCCLRSRCNODES:
1511 		case DIOCIGETIFACES:
1512 		case DIOCGIFSPEED:
1513 		case DIOCSETIFFLAG:
1514 		case DIOCCLRIFFLAG:
1515 			break;
1516 		case DIOCRCLRTABLES:
1517 		case DIOCRADDTABLES:
1518 		case DIOCRDELTABLES:
1519 		case DIOCRSETTFLAGS: {
1520 			int pfrio_flags;
1521 
1522 			bcopy(&((struct pfioc_table *)(void *)addr)->
1523 			    pfrio_flags, &pfrio_flags, sizeof(pfrio_flags));
1524 
1525 			if (pfrio_flags & PFR_FLAG_DUMMY) {
1526 				break; /* dummy operation ok */
1527 			}
1528 			return EPERM;
1529 		}
1530 		default:
1531 			return EPERM;
1532 		}
1533 	}
1534 
1535 	if (!(flags & FWRITE)) {
1536 		switch (cmd) {
1537 		case DIOCSTART:
1538 		case DIOCSTARTREF:
1539 		case DIOCSTOP:
1540 		case DIOCSTOPREF:
1541 		case DIOCGETSTARTERS:
1542 		case DIOCGETRULES:
1543 		case DIOCGETADDRS:
1544 		case DIOCGETADDR:
1545 		case DIOCGETSTATE:
1546 		case DIOCGETSTATUS:
1547 		case DIOCGETSTATES:
1548 		case DIOCINSERTRULE:
1549 		case DIOCDELETERULE:
1550 		case DIOCGETTIMEOUT:
1551 		case DIOCGETLIMIT:
1552 		case DIOCGETALTQS:
1553 		case DIOCGETALTQ:
1554 		case DIOCGETQSTATS:
1555 		case DIOCGETRULESETS:
1556 		case DIOCGETRULESET:
1557 		case DIOCNATLOOK:
1558 		case DIOCRGETTABLES:
1559 		case DIOCRGETTSTATS:
1560 		case DIOCRGETADDRS:
1561 		case DIOCRGETASTATS:
1562 		case DIOCRTSTADDRS:
1563 		case DIOCOSFPGET:
1564 		case DIOCGETSRCNODES:
1565 		case DIOCIGETIFACES:
1566 		case DIOCGIFSPEED:
1567 			break;
1568 		case DIOCRCLRTABLES:
1569 		case DIOCRADDTABLES:
1570 		case DIOCRDELTABLES:
1571 		case DIOCRCLRTSTATS:
1572 		case DIOCRCLRADDRS:
1573 		case DIOCRADDADDRS:
1574 		case DIOCRDELADDRS:
1575 		case DIOCRSETADDRS:
1576 		case DIOCRSETTFLAGS: {
1577 			int pfrio_flags;
1578 
1579 			bcopy(&((struct pfioc_table *)(void *)addr)->
1580 			    pfrio_flags, &pfrio_flags, sizeof(pfrio_flags));
1581 
1582 			if (pfrio_flags & PFR_FLAG_DUMMY) {
1583 				flags |= FWRITE; /* need write lock for dummy */
1584 				break; /* dummy operation ok */
1585 			}
1586 			return EACCES;
1587 		}
1588 		case DIOCGETRULE: {
1589 			u_int32_t action;
1590 
1591 			bcopy(&((struct pfioc_rule *)(void *)addr)->action,
1592 			    &action, sizeof(action));
1593 
1594 			if (action == PF_GET_CLR_CNTR) {
1595 				return EACCES;
1596 			}
1597 			break;
1598 		}
1599 		default:
1600 			return EACCES;
1601 		}
1602 	}
1603 
1604 	if (flags & FWRITE) {
1605 		lck_rw_lock_exclusive(&pf_perim_lock);
1606 	} else {
1607 		lck_rw_lock_shared(&pf_perim_lock);
1608 	}
1609 
1610 	lck_mtx_lock(&pf_lock);
1611 
1612 	switch (cmd) {
1613 	case DIOCSTART:
1614 		if (pf_status.running) {
1615 			/*
1616 			 * Increment the reference for a simple -e enable, so
1617 			 * that even if other processes drop their references,
1618 			 * pf will still be available to processes that turned
1619 			 * it on without taking a reference
1620 			 */
1621 			if (nr_tokens == pf_enabled_ref_count) {
1622 				pf_enabled_ref_count++;
1623 				VERIFY(pf_enabled_ref_count != 0);
1624 			}
1625 			error = EEXIST;
1626 		} else if (pf_purge_thread == NULL) {
1627 			error = ENOMEM;
1628 		} else {
1629 			pf_start();
1630 			pf_enabled_ref_count++;
1631 			VERIFY(pf_enabled_ref_count != 0);
1632 		}
1633 		break;
1634 
1635 	case DIOCSTARTREF:              /* u_int64_t */
1636 		if (pf_purge_thread == NULL) {
1637 			error = ENOMEM;
1638 		} else {
1639 			u_int64_t token;
1640 
1641 			/* small enough to be on stack */
1642 			if ((token = generate_token(p)) != 0) {
1643 				if (pf_is_enabled == 0) {
1644 					pf_start();
1645 				}
1646 				pf_enabled_ref_count++;
1647 				VERIFY(pf_enabled_ref_count != 0);
1648 			} else {
1649 				error = ENOMEM;
1650 				DPFPRINTF(PF_DEBUG_URGENT,
1651 				    ("pf: unable to generate token\n"));
1652 			}
1653 			bcopy(&token, addr, sizeof(token));
1654 		}
1655 		break;
1656 
1657 	case DIOCSTOP:
1658 		if (!pf_status.running) {
1659 			error = ENOENT;
1660 		} else {
1661 			pf_stop();
1662 			pf_enabled_ref_count = 0;
1663 			invalidate_all_tokens();
1664 		}
1665 		break;
1666 
1667 	case DIOCSTOPREF:               /* struct pfioc_remove_token */
1668 		if (!pf_status.running) {
1669 			error = ENOENT;
1670 		} else {
1671 			struct pfioc_remove_token pfrt;
1672 
1673 			/* small enough to be on stack */
1674 			bcopy(addr, &pfrt, sizeof(pfrt));
1675 			if ((error = remove_token(&pfrt)) == 0) {
1676 				VERIFY(pf_enabled_ref_count != 0);
1677 				pf_enabled_ref_count--;
1678 				/* return currently held references */
1679 				pfrt.refcount = pf_enabled_ref_count;
1680 				DPFPRINTF(PF_DEBUG_MISC,
1681 				    ("pf: enabled refcount decremented\n"));
1682 			} else {
1683 				error = EINVAL;
1684 				DPFPRINTF(PF_DEBUG_URGENT,
1685 				    ("pf: token mismatch\n"));
1686 			}
1687 			bcopy(&pfrt, addr, sizeof(pfrt));
1688 
1689 			if (error == 0 && pf_enabled_ref_count == 0) {
1690 				pf_stop();
1691 			}
1692 		}
1693 		break;
1694 
1695 	case DIOCGETSTARTERS: {         /* struct pfioc_tokens */
1696 		PFIOCX_STRUCT_DECL(pfioc_tokens);
1697 
1698 		PFIOCX_STRUCT_BEGIN(addr, pfioc_tokens);
1699 		error = pfioctl_ioc_tokens(cmd,
1700 		    PFIOCX_STRUCT_ADDR32(pfioc_tokens),
1701 		    PFIOCX_STRUCT_ADDR64(pfioc_tokens), p);
1702 		PFIOCX_STRUCT_END(pfioc_tokens, addr);
1703 		break;
1704 	}
1705 
1706 	case DIOCADDRULE:               /* struct pfioc_rule */
1707 	case DIOCGETRULES:              /* struct pfioc_rule */
1708 	case DIOCGETRULE:               /* struct pfioc_rule */
1709 	case DIOCCHANGERULE:            /* struct pfioc_rule */
1710 	case DIOCINSERTRULE:            /* struct pfioc_rule */
1711 	case DIOCDELETERULE: {          /* struct pfioc_rule */
1712 		struct pfioc_rule *pr = NULL;
1713 
1714 		PFIOC_STRUCT_BEGIN(addr, pr);
1715 		error = pfioctl_ioc_rule(cmd, minordev, pr, p);
1716 		PFIOC_STRUCT_END(pr, addr);
1717 		break;
1718 	}
1719 
1720 	case DIOCCLRSTATES:             /* struct pfioc_state_kill */
1721 	case DIOCKILLSTATES: {          /* struct pfioc_state_kill */
1722 		struct pfioc_state_kill *psk = NULL;
1723 
1724 		PFIOC_STRUCT_BEGIN(addr, psk);
1725 		error = pfioctl_ioc_state_kill(cmd, psk, p);
1726 		PFIOC_STRUCT_END(psk, addr);
1727 		break;
1728 	}
1729 
1730 	case DIOCADDSTATE:              /* struct pfioc_state */
1731 	case DIOCGETSTATE: {            /* struct pfioc_state */
1732 		struct pfioc_state *ps = NULL;
1733 
1734 		PFIOC_STRUCT_BEGIN(addr, ps);
1735 		error = pfioctl_ioc_state(cmd, ps, p);
1736 		PFIOC_STRUCT_END(ps, addr);
1737 		break;
1738 	}
1739 
1740 	case DIOCGETSTATES: {           /* struct pfioc_states */
1741 		PFIOCX_STRUCT_DECL(pfioc_states);
1742 
1743 		PFIOCX_STRUCT_BEGIN(addr, pfioc_states);
1744 		error = pfioctl_ioc_states(cmd,
1745 		    PFIOCX_STRUCT_ADDR32(pfioc_states),
1746 		    PFIOCX_STRUCT_ADDR64(pfioc_states), p);
1747 		PFIOCX_STRUCT_END(pfioc_states, addr);
1748 		break;
1749 	}
1750 
1751 	case DIOCGETSTATUS: {           /* struct pf_status */
1752 		struct pf_status *s = NULL;
1753 
1754 		PFIOC_STRUCT_BEGIN(&pf_status, s);
1755 		pfi_update_status(s->ifname, s);
1756 		PFIOC_STRUCT_END(s, addr);
1757 		break;
1758 	}
1759 
1760 	case DIOCSETSTATUSIF: {         /* struct pfioc_if */
1761 		struct pfioc_if *pi = (struct pfioc_if *)(void *)addr;
1762 
1763 		/* OK for unaligned accesses */
1764 		if (pi->ifname[0] == 0) {
1765 			bzero(pf_status.ifname, IFNAMSIZ);
1766 			break;
1767 		}
1768 		strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ);
1769 		break;
1770 	}
1771 
1772 	case DIOCCLRSTATUS: {
1773 		bzero(pf_status.counters, sizeof(pf_status.counters));
1774 		bzero(pf_status.fcounters, sizeof(pf_status.fcounters));
1775 		bzero(pf_status.scounters, sizeof(pf_status.scounters));
1776 		pf_status.since = pf_calendar_time_second();
1777 		if (*pf_status.ifname) {
1778 			pfi_update_status(pf_status.ifname, NULL);
1779 		}
1780 		break;
1781 	}
1782 
1783 	case DIOCNATLOOK: {             /* struct pfioc_natlook */
1784 		struct pfioc_natlook *pnl = NULL;
1785 
1786 		PFIOC_STRUCT_BEGIN(addr, pnl);
1787 		error = pfioctl_ioc_natlook(cmd, pnl, p);
1788 		PFIOC_STRUCT_END(pnl, addr);
1789 		break;
1790 	}
1791 
1792 	case DIOCSETTIMEOUT:            /* struct pfioc_tm */
1793 	case DIOCGETTIMEOUT: {          /* struct pfioc_tm */
1794 		struct pfioc_tm pt;
1795 
1796 		/* small enough to be on stack */
1797 		bcopy(addr, &pt, sizeof(pt));
1798 		error = pfioctl_ioc_tm(cmd, &pt, p);
1799 		bcopy(&pt, addr, sizeof(pt));
1800 		break;
1801 	}
1802 
1803 	case DIOCGETLIMIT:              /* struct pfioc_limit */
1804 	case DIOCSETLIMIT: {            /* struct pfioc_limit */
1805 		struct pfioc_limit pl;
1806 
1807 		/* small enough to be on stack */
1808 		bcopy(addr, &pl, sizeof(pl));
1809 		error = pfioctl_ioc_limit(cmd, &pl, p);
1810 		bcopy(&pl, addr, sizeof(pl));
1811 		break;
1812 	}
1813 
1814 	case DIOCSETDEBUG: {            /* u_int32_t */
1815 		bcopy(addr, &pf_status.debug, sizeof(u_int32_t));
1816 		break;
1817 	}
1818 
1819 	case DIOCCLRRULECTRS: {
1820 		/* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
1821 		struct pf_ruleset       *ruleset = &pf_main_ruleset;
1822 		struct pf_rule          *rule;
1823 
1824 		TAILQ_FOREACH(rule,
1825 		    ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) {
1826 			rule->evaluations = 0;
1827 			rule->packets[0] = rule->packets[1] = 0;
1828 			rule->bytes[0] = rule->bytes[1] = 0;
1829 		}
1830 		break;
1831 	}
1832 
1833 	case DIOCGIFSPEED: {
1834 		struct pf_ifspeed *psp = (struct pf_ifspeed *)(void *)addr;
1835 		struct pf_ifspeed ps;
1836 		struct ifnet *ifp;
1837 		u_int64_t baudrate;
1838 
1839 		if (psp->ifname[0] != '\0') {
1840 			/* Can we completely trust user-land? */
1841 			strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
1842 			ps.ifname[IFNAMSIZ - 1] = '\0';
1843 			ifp = ifunit(ps.ifname);
1844 			if (ifp != NULL) {
1845 				baudrate = ifp->if_output_bw.max_bw;
1846 				bcopy(&baudrate, &psp->baudrate,
1847 				    sizeof(baudrate));
1848 			} else {
1849 				error = EINVAL;
1850 			}
1851 		} else {
1852 			error = EINVAL;
1853 		}
1854 		break;
1855 	}
1856 
1857 	case DIOCBEGINADDRS:            /* struct pfioc_pooladdr */
1858 	case DIOCADDADDR:               /* struct pfioc_pooladdr */
1859 	case DIOCGETADDRS:              /* struct pfioc_pooladdr */
1860 	case DIOCGETADDR:               /* struct pfioc_pooladdr */
1861 	case DIOCCHANGEADDR: {          /* struct pfioc_pooladdr */
1862 		struct pfioc_pooladdr *pp = NULL;
1863 
1864 		PFIOC_STRUCT_BEGIN(addr, pp);
1865 		error = pfioctl_ioc_pooladdr(cmd, pp, p);
1866 		PFIOC_STRUCT_END(pp, addr);
1867 		break;
1868 	}
1869 
1870 	case DIOCGETRULESETS:           /* struct pfioc_ruleset */
1871 	case DIOCGETRULESET: {          /* struct pfioc_ruleset */
1872 		struct pfioc_ruleset *pr = NULL;
1873 
1874 		PFIOC_STRUCT_BEGIN(addr, pr);
1875 		error = pfioctl_ioc_ruleset(cmd, pr, p);
1876 		PFIOC_STRUCT_END(pr, addr);
1877 		break;
1878 	}
1879 
1880 	case DIOCRCLRTABLES:            /* struct pfioc_table */
1881 	case DIOCRADDTABLES:            /* struct pfioc_table */
1882 	case DIOCRDELTABLES:            /* struct pfioc_table */
1883 	case DIOCRGETTABLES:            /* struct pfioc_table */
1884 	case DIOCRGETTSTATS:            /* struct pfioc_table */
1885 	case DIOCRCLRTSTATS:            /* struct pfioc_table */
1886 	case DIOCRSETTFLAGS:            /* struct pfioc_table */
1887 	case DIOCRCLRADDRS:             /* struct pfioc_table */
1888 	case DIOCRADDADDRS:             /* struct pfioc_table */
1889 	case DIOCRDELADDRS:             /* struct pfioc_table */
1890 	case DIOCRSETADDRS:             /* struct pfioc_table */
1891 	case DIOCRGETADDRS:             /* struct pfioc_table */
1892 	case DIOCRGETASTATS:            /* struct pfioc_table */
1893 	case DIOCRCLRASTATS:            /* struct pfioc_table */
1894 	case DIOCRTSTADDRS:             /* struct pfioc_table */
1895 	case DIOCRINADEFINE: {          /* struct pfioc_table */
1896 		PFIOCX_STRUCT_DECL(pfioc_table);
1897 
1898 		PFIOCX_STRUCT_BEGIN(addr, pfioc_table);
1899 		error = pfioctl_ioc_table(cmd,
1900 		    PFIOCX_STRUCT_ADDR32(pfioc_table),
1901 		    PFIOCX_STRUCT_ADDR64(pfioc_table), p);
1902 		PFIOCX_STRUCT_END(pfioc_table, addr);
1903 		break;
1904 	}
1905 
1906 	case DIOCOSFPADD:               /* struct pf_osfp_ioctl */
1907 	case DIOCOSFPGET: {             /* struct pf_osfp_ioctl */
1908 		struct pf_osfp_ioctl *io = NULL;
1909 
1910 		PFIOC_STRUCT_BEGIN(addr, io);
1911 		if (cmd == DIOCOSFPADD) {
1912 			error = pf_osfp_add(io);
1913 		} else {
1914 			VERIFY(cmd == DIOCOSFPGET);
1915 			error = pf_osfp_get(io);
1916 		}
1917 		PFIOC_STRUCT_END(io, addr);
1918 		break;
1919 	}
1920 
1921 	case DIOCXBEGIN:                /* struct pfioc_trans */
1922 	case DIOCXROLLBACK:             /* struct pfioc_trans */
1923 	case DIOCXCOMMIT: {             /* struct pfioc_trans */
1924 		PFIOCX_STRUCT_DECL(pfioc_trans);
1925 
1926 		PFIOCX_STRUCT_BEGIN(addr, pfioc_trans);
1927 		error = pfioctl_ioc_trans(cmd,
1928 		    PFIOCX_STRUCT_ADDR32(pfioc_trans),
1929 		    PFIOCX_STRUCT_ADDR64(pfioc_trans), p);
1930 		PFIOCX_STRUCT_END(pfioc_trans, addr);
1931 		break;
1932 	}
1933 
1934 	case DIOCGETSRCNODES: {         /* struct pfioc_src_nodes */
1935 		PFIOCX_STRUCT_DECL(pfioc_src_nodes);
1936 
1937 		PFIOCX_STRUCT_BEGIN(addr, pfioc_src_nodes);
1938 		error = pfioctl_ioc_src_nodes(cmd,
1939 		    PFIOCX_STRUCT_ADDR32(pfioc_src_nodes),
1940 		    PFIOCX_STRUCT_ADDR64(pfioc_src_nodes), p);
1941 		PFIOCX_STRUCT_END(pfioc_src_nodes, addr);
1942 		break;
1943 	}
1944 
1945 	case DIOCCLRSRCNODES: {
1946 		struct pf_src_node      *n;
1947 		struct pf_state         *state;
1948 
1949 		RB_FOREACH(state, pf_state_tree_id, &tree_id) {
1950 			state->src_node = NULL;
1951 			state->nat_src_node = NULL;
1952 		}
1953 		RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
1954 			n->expire = 1;
1955 			n->states = 0;
1956 		}
1957 		pf_purge_expired_src_nodes();
1958 		pf_status.src_nodes = 0;
1959 		break;
1960 	}
1961 
1962 	case DIOCKILLSRCNODES: {        /* struct pfioc_src_node_kill */
1963 		struct pfioc_src_node_kill *psnk = NULL;
1964 
1965 		PFIOC_STRUCT_BEGIN(addr, psnk);
1966 		error = pfioctl_ioc_src_node_kill(cmd, psnk, p);
1967 		PFIOC_STRUCT_END(psnk, addr);
1968 		break;
1969 	}
1970 
1971 	case DIOCSETHOSTID: {           /* u_int32_t */
1972 		u_int32_t hid;
1973 
1974 		/* small enough to be on stack */
1975 		bcopy(addr, &hid, sizeof(hid));
1976 		if (hid == 0) {
1977 			pf_status.hostid = random();
1978 		} else {
1979 			pf_status.hostid = hid;
1980 		}
1981 		break;
1982 	}
1983 
1984 	case DIOCOSFPFLUSH:
1985 		pf_osfp_flush();
1986 		break;
1987 
1988 	case DIOCIGETIFACES:            /* struct pfioc_iface */
1989 	case DIOCSETIFFLAG:             /* struct pfioc_iface */
1990 	case DIOCCLRIFFLAG: {           /* struct pfioc_iface */
1991 		PFIOCX_STRUCT_DECL(pfioc_iface);
1992 
1993 		PFIOCX_STRUCT_BEGIN(addr, pfioc_iface);
1994 		error = pfioctl_ioc_iface(cmd,
1995 		    PFIOCX_STRUCT_ADDR32(pfioc_iface),
1996 		    PFIOCX_STRUCT_ADDR64(pfioc_iface), p);
1997 		PFIOCX_STRUCT_END(pfioc_iface, addr);
1998 		break;
1999 	}
2000 
2001 	default:
2002 		error = ENODEV;
2003 		break;
2004 	}
2005 
2006 	lck_mtx_unlock(&pf_lock);
2007 	lck_rw_done(&pf_perim_lock);
2008 
2009 	return error;
2010 }
2011 
2012 static int
pfioctl_ioc_table(u_long cmd,struct pfioc_table_32 * io32,struct pfioc_table_64 * io64,struct proc * p)2013 pfioctl_ioc_table(u_long cmd, struct pfioc_table_32 *io32,
2014     struct pfioc_table_64 *io64, struct proc *p)
2015 {
2016 	int p64 = proc_is64bit(p);
2017 	int error = 0;
2018 
2019 	if (!p64) {
2020 		goto struct32;
2021 	}
2022 
2023 #ifdef __LP64__
2024 	/*
2025 	 * 64-bit structure processing
2026 	 */
2027 	switch (cmd) {
2028 	case DIOCRCLRTABLES:
2029 		if (io64->pfrio_esize != 0) {
2030 			error = ENODEV;
2031 			break;
2032 		}
2033 		pfr_table_copyin_cleanup(&io64->pfrio_table);
2034 		error = pfr_clr_tables(&io64->pfrio_table, &io64->pfrio_ndel,
2035 		    io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2036 		break;
2037 
2038 	case DIOCRADDTABLES:
2039 		if (io64->pfrio_esize != sizeof(struct pfr_table)) {
2040 			error = ENODEV;
2041 			break;
2042 		}
2043 		error = pfr_add_tables(io64->pfrio_buffer, io64->pfrio_size,
2044 		    &io64->pfrio_nadd, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2045 		break;
2046 
2047 	case DIOCRDELTABLES:
2048 		if (io64->pfrio_esize != sizeof(struct pfr_table)) {
2049 			error = ENODEV;
2050 			break;
2051 		}
2052 		error = pfr_del_tables(io64->pfrio_buffer, io64->pfrio_size,
2053 		    &io64->pfrio_ndel, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2054 		break;
2055 
2056 	case DIOCRGETTABLES:
2057 		if (io64->pfrio_esize != sizeof(struct pfr_table)) {
2058 			error = ENODEV;
2059 			break;
2060 		}
2061 		pfr_table_copyin_cleanup(&io64->pfrio_table);
2062 		error = pfr_get_tables(&io64->pfrio_table, io64->pfrio_buffer,
2063 		    &io64->pfrio_size, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2064 		break;
2065 
2066 	case DIOCRGETTSTATS:
2067 		if (io64->pfrio_esize != sizeof(struct pfr_tstats)) {
2068 			error = ENODEV;
2069 			break;
2070 		}
2071 		pfr_table_copyin_cleanup(&io64->pfrio_table);
2072 		error = pfr_get_tstats(&io64->pfrio_table, io64->pfrio_buffer,
2073 		    &io64->pfrio_size, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2074 		break;
2075 
2076 	case DIOCRCLRTSTATS:
2077 		if (io64->pfrio_esize != sizeof(struct pfr_table)) {
2078 			error = ENODEV;
2079 			break;
2080 		}
2081 		error = pfr_clr_tstats(io64->pfrio_buffer, io64->pfrio_size,
2082 		    &io64->pfrio_nzero, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2083 		break;
2084 
2085 	case DIOCRSETTFLAGS:
2086 		if (io64->pfrio_esize != sizeof(struct pfr_table)) {
2087 			error = ENODEV;
2088 			break;
2089 		}
2090 		error = pfr_set_tflags(io64->pfrio_buffer, io64->pfrio_size,
2091 		    io64->pfrio_setflag, io64->pfrio_clrflag,
2092 		    &io64->pfrio_nchange, &io64->pfrio_ndel,
2093 		    io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2094 		break;
2095 
2096 	case DIOCRCLRADDRS:
2097 		if (io64->pfrio_esize != 0) {
2098 			error = ENODEV;
2099 			break;
2100 		}
2101 		pfr_table_copyin_cleanup(&io64->pfrio_table);
2102 		error = pfr_clr_addrs(&io64->pfrio_table, &io64->pfrio_ndel,
2103 		    io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2104 		break;
2105 
2106 	case DIOCRADDADDRS:
2107 		if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2108 			error = ENODEV;
2109 			break;
2110 		}
2111 		pfr_table_copyin_cleanup(&io64->pfrio_table);
2112 		error = pfr_add_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2113 		    io64->pfrio_size, &io64->pfrio_nadd, io64->pfrio_flags |
2114 		    PFR_FLAG_USERIOCTL);
2115 		break;
2116 
2117 	case DIOCRDELADDRS:
2118 		if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2119 			error = ENODEV;
2120 			break;
2121 		}
2122 		pfr_table_copyin_cleanup(&io64->pfrio_table);
2123 		error = pfr_del_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2124 		    io64->pfrio_size, &io64->pfrio_ndel, io64->pfrio_flags |
2125 		    PFR_FLAG_USERIOCTL);
2126 		break;
2127 
2128 	case DIOCRSETADDRS:
2129 		if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2130 			error = ENODEV;
2131 			break;
2132 		}
2133 		pfr_table_copyin_cleanup(&io64->pfrio_table);
2134 		error = pfr_set_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2135 		    io64->pfrio_size, &io64->pfrio_size2, &io64->pfrio_nadd,
2136 		    &io64->pfrio_ndel, &io64->pfrio_nchange, io64->pfrio_flags |
2137 		    PFR_FLAG_USERIOCTL, 0);
2138 		break;
2139 
2140 	case DIOCRGETADDRS:
2141 		if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2142 			error = ENODEV;
2143 			break;
2144 		}
2145 		pfr_table_copyin_cleanup(&io64->pfrio_table);
2146 		error = pfr_get_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2147 		    &io64->pfrio_size, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2148 		break;
2149 
2150 	case DIOCRGETASTATS:
2151 		if (io64->pfrio_esize != sizeof(struct pfr_astats)) {
2152 			error = ENODEV;
2153 			break;
2154 		}
2155 		pfr_table_copyin_cleanup(&io64->pfrio_table);
2156 		error = pfr_get_astats(&io64->pfrio_table, io64->pfrio_buffer,
2157 		    &io64->pfrio_size, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2158 		break;
2159 
2160 	case DIOCRCLRASTATS:
2161 		if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2162 			error = ENODEV;
2163 			break;
2164 		}
2165 		pfr_table_copyin_cleanup(&io64->pfrio_table);
2166 		error = pfr_clr_astats(&io64->pfrio_table, io64->pfrio_buffer,
2167 		    io64->pfrio_size, &io64->pfrio_nzero, io64->pfrio_flags |
2168 		    PFR_FLAG_USERIOCTL);
2169 		break;
2170 
2171 	case DIOCRTSTADDRS:
2172 		if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2173 			error = ENODEV;
2174 			break;
2175 		}
2176 		pfr_table_copyin_cleanup(&io64->pfrio_table);
2177 		error = pfr_tst_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2178 		    io64->pfrio_size, &io64->pfrio_nmatch, io64->pfrio_flags |
2179 		    PFR_FLAG_USERIOCTL);
2180 		break;
2181 
2182 	case DIOCRINADEFINE:
2183 		if (io64->pfrio_esize != sizeof(struct pfr_addr)) {
2184 			error = ENODEV;
2185 			break;
2186 		}
2187 		pfr_table_copyin_cleanup(&io64->pfrio_table);
2188 		error = pfr_ina_define(&io64->pfrio_table, io64->pfrio_buffer,
2189 		    io64->pfrio_size, &io64->pfrio_nadd, &io64->pfrio_naddr,
2190 		    io64->pfrio_ticket, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2191 		break;
2192 
2193 	default:
2194 		VERIFY(0);
2195 		/* NOTREACHED */
2196 	}
2197 	goto done;
2198 #else
2199 #pragma unused(io64)
2200 #endif /* __LP64__ */
2201 
2202 struct32:
2203 	/*
2204 	 * 32-bit structure processing
2205 	 */
2206 	switch (cmd) {
2207 	case DIOCRCLRTABLES:
2208 		if (io32->pfrio_esize != 0) {
2209 			error = ENODEV;
2210 			break;
2211 		}
2212 		pfr_table_copyin_cleanup(&io32->pfrio_table);
2213 		error = pfr_clr_tables(&io32->pfrio_table, &io32->pfrio_ndel,
2214 		    io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2215 		break;
2216 
2217 	case DIOCRADDTABLES:
2218 		if (io32->pfrio_esize != sizeof(struct pfr_table)) {
2219 			error = ENODEV;
2220 			break;
2221 		}
2222 		error = pfr_add_tables(io32->pfrio_buffer, io32->pfrio_size,
2223 		    &io32->pfrio_nadd, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2224 		break;
2225 
2226 	case DIOCRDELTABLES:
2227 		if (io32->pfrio_esize != sizeof(struct pfr_table)) {
2228 			error = ENODEV;
2229 			break;
2230 		}
2231 		error = pfr_del_tables(io32->pfrio_buffer, io32->pfrio_size,
2232 		    &io32->pfrio_ndel, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2233 		break;
2234 
2235 	case DIOCRGETTABLES:
2236 		if (io32->pfrio_esize != sizeof(struct pfr_table)) {
2237 			error = ENODEV;
2238 			break;
2239 		}
2240 		pfr_table_copyin_cleanup(&io32->pfrio_table);
2241 		error = pfr_get_tables(&io32->pfrio_table, io32->pfrio_buffer,
2242 		    &io32->pfrio_size, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2243 		break;
2244 
2245 	case DIOCRGETTSTATS:
2246 		if (io32->pfrio_esize != sizeof(struct pfr_tstats)) {
2247 			error = ENODEV;
2248 			break;
2249 		}
2250 		pfr_table_copyin_cleanup(&io32->pfrio_table);
2251 		error = pfr_get_tstats(&io32->pfrio_table, io32->pfrio_buffer,
2252 		    &io32->pfrio_size, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2253 		break;
2254 
2255 	case DIOCRCLRTSTATS:
2256 		if (io32->pfrio_esize != sizeof(struct pfr_table)) {
2257 			error = ENODEV;
2258 			break;
2259 		}
2260 		error = pfr_clr_tstats(io32->pfrio_buffer, io32->pfrio_size,
2261 		    &io32->pfrio_nzero, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2262 		break;
2263 
2264 	case DIOCRSETTFLAGS:
2265 		if (io32->pfrio_esize != sizeof(struct pfr_table)) {
2266 			error = ENODEV;
2267 			break;
2268 		}
2269 		error = pfr_set_tflags(io32->pfrio_buffer, io32->pfrio_size,
2270 		    io32->pfrio_setflag, io32->pfrio_clrflag,
2271 		    &io32->pfrio_nchange, &io32->pfrio_ndel,
2272 		    io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2273 		break;
2274 
2275 	case DIOCRCLRADDRS:
2276 		if (io32->pfrio_esize != 0) {
2277 			error = ENODEV;
2278 			break;
2279 		}
2280 		pfr_table_copyin_cleanup(&io32->pfrio_table);
2281 		error = pfr_clr_addrs(&io32->pfrio_table, &io32->pfrio_ndel,
2282 		    io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2283 		break;
2284 
2285 	case DIOCRADDADDRS:
2286 		if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2287 			error = ENODEV;
2288 			break;
2289 		}
2290 		pfr_table_copyin_cleanup(&io32->pfrio_table);
2291 		error = pfr_add_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2292 		    io32->pfrio_size, &io32->pfrio_nadd, io32->pfrio_flags |
2293 		    PFR_FLAG_USERIOCTL);
2294 		break;
2295 
2296 	case DIOCRDELADDRS:
2297 		if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2298 			error = ENODEV;
2299 			break;
2300 		}
2301 		pfr_table_copyin_cleanup(&io32->pfrio_table);
2302 		error = pfr_del_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2303 		    io32->pfrio_size, &io32->pfrio_ndel, io32->pfrio_flags |
2304 		    PFR_FLAG_USERIOCTL);
2305 		break;
2306 
2307 	case DIOCRSETADDRS:
2308 		if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2309 			error = ENODEV;
2310 			break;
2311 		}
2312 		pfr_table_copyin_cleanup(&io32->pfrio_table);
2313 		error = pfr_set_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2314 		    io32->pfrio_size, &io32->pfrio_size2, &io32->pfrio_nadd,
2315 		    &io32->pfrio_ndel, &io32->pfrio_nchange, io32->pfrio_flags |
2316 		    PFR_FLAG_USERIOCTL, 0);
2317 		break;
2318 
2319 	case DIOCRGETADDRS:
2320 		if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2321 			error = ENODEV;
2322 			break;
2323 		}
2324 		pfr_table_copyin_cleanup(&io32->pfrio_table);
2325 		error = pfr_get_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2326 		    &io32->pfrio_size, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2327 		break;
2328 
2329 	case DIOCRGETASTATS:
2330 		if (io32->pfrio_esize != sizeof(struct pfr_astats)) {
2331 			error = ENODEV;
2332 			break;
2333 		}
2334 		pfr_table_copyin_cleanup(&io32->pfrio_table);
2335 		error = pfr_get_astats(&io32->pfrio_table, io32->pfrio_buffer,
2336 		    &io32->pfrio_size, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2337 		break;
2338 
2339 	case DIOCRCLRASTATS:
2340 		if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2341 			error = ENODEV;
2342 			break;
2343 		}
2344 		pfr_table_copyin_cleanup(&io32->pfrio_table);
2345 		error = pfr_clr_astats(&io32->pfrio_table, io32->pfrio_buffer,
2346 		    io32->pfrio_size, &io32->pfrio_nzero, io32->pfrio_flags |
2347 		    PFR_FLAG_USERIOCTL);
2348 		break;
2349 
2350 	case DIOCRTSTADDRS:
2351 		if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2352 			error = ENODEV;
2353 			break;
2354 		}
2355 		pfr_table_copyin_cleanup(&io32->pfrio_table);
2356 		error = pfr_tst_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2357 		    io32->pfrio_size, &io32->pfrio_nmatch, io32->pfrio_flags |
2358 		    PFR_FLAG_USERIOCTL);
2359 		break;
2360 
2361 	case DIOCRINADEFINE:
2362 		if (io32->pfrio_esize != sizeof(struct pfr_addr)) {
2363 			error = ENODEV;
2364 			break;
2365 		}
2366 		pfr_table_copyin_cleanup(&io32->pfrio_table);
2367 		error = pfr_ina_define(&io32->pfrio_table, io32->pfrio_buffer,
2368 		    io32->pfrio_size, &io32->pfrio_nadd, &io32->pfrio_naddr,
2369 		    io32->pfrio_ticket, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2370 		break;
2371 
2372 	default:
2373 		VERIFY(0);
2374 		/* NOTREACHED */
2375 	}
2376 #ifdef __LP64__
2377 done:
2378 #endif
2379 	return error;
2380 }
2381 
2382 static int
pfioctl_ioc_tokens(u_long cmd,struct pfioc_tokens_32 * tok32,struct pfioc_tokens_64 * tok64,struct proc * p)2383 pfioctl_ioc_tokens(u_long cmd, struct pfioc_tokens_32 *tok32,
2384     struct pfioc_tokens_64 *tok64, struct proc *p)
2385 {
2386 	struct pfioc_token *tokens;
2387 	struct pfioc_kernel_token *entry, *tmp;
2388 	user_addr_t token_buf;
2389 	int ocnt, cnt, error = 0, p64 = proc_is64bit(p);
2390 	char *ptr;
2391 
2392 	switch (cmd) {
2393 	case DIOCGETSTARTERS: {
2394 		int size;
2395 
2396 		if (nr_tokens == 0) {
2397 			error = ENOENT;
2398 			break;
2399 		}
2400 
2401 		size = sizeof(struct pfioc_token) * nr_tokens;
2402 		if (size / nr_tokens != sizeof(struct pfioc_token)) {
2403 			os_log_error(OS_LOG_DEFAULT, "%s: size overflows", __func__);
2404 			error = ERANGE;
2405 			break;
2406 		}
2407 		ocnt = cnt = (p64 ? tok64->size : tok32->size);
2408 		if (cnt == 0) {
2409 			if (p64) {
2410 				tok64->size = size;
2411 			} else {
2412 				tok32->size = size;
2413 			}
2414 			break;
2415 		}
2416 
2417 #ifdef __LP64__
2418 		token_buf = (p64 ? tok64->pgt_buf : tok32->pgt_buf);
2419 #else
2420 		token_buf = tok32->pgt_buf;
2421 #endif
2422 		tokens = (struct pfioc_token *)kalloc_data(size, Z_WAITOK | Z_ZERO);
2423 		if (tokens == NULL) {
2424 			error = ENOMEM;
2425 			break;
2426 		}
2427 
2428 		ptr = (void *)tokens;
2429 		SLIST_FOREACH_SAFE(entry, &token_list_head, next, tmp) {
2430 			struct pfioc_token *t;
2431 
2432 			if ((unsigned)cnt < sizeof(*tokens)) {
2433 				break;    /* no more buffer space left */
2434 			}
2435 			t = (struct pfioc_token *)(void *)ptr;
2436 			t->token_value  = entry->token.token_value;
2437 			t->timestamp    = entry->token.timestamp;
2438 			t->pid          = entry->token.pid;
2439 			bcopy(entry->token.proc_name, t->proc_name,
2440 			    PFTOK_PROCNAME_LEN);
2441 			ptr += sizeof(struct pfioc_token);
2442 
2443 			cnt -= sizeof(struct pfioc_token);
2444 		}
2445 
2446 		if (cnt < ocnt) {
2447 			error = copyout(tokens, token_buf, ocnt - cnt);
2448 		}
2449 
2450 		if (p64) {
2451 			tok64->size = ocnt - cnt;
2452 		} else {
2453 			tok32->size = ocnt - cnt;
2454 		}
2455 
2456 		kfree_data(tokens, size);
2457 		break;
2458 	}
2459 
2460 	default:
2461 		VERIFY(0);
2462 		/* NOTREACHED */
2463 	}
2464 
2465 	return error;
2466 }
2467 
2468 static void
pf_expire_states_and_src_nodes(struct pf_rule * rule)2469 pf_expire_states_and_src_nodes(struct pf_rule *rule)
2470 {
2471 	struct pf_state         *state;
2472 	struct pf_src_node      *sn;
2473 	int                      killed = 0;
2474 
2475 	/* expire the states */
2476 	state = TAILQ_FIRST(&state_list);
2477 	while (state) {
2478 		if (state->rule.ptr == rule) {
2479 			state->timeout = PFTM_PURGE;
2480 		}
2481 		state = TAILQ_NEXT(state, entry_list);
2482 	}
2483 	pf_purge_expired_states(pf_status.states);
2484 
2485 	/* expire the src_nodes */
2486 	RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) {
2487 		if (sn->rule.ptr != rule) {
2488 			continue;
2489 		}
2490 		if (sn->states != 0) {
2491 			RB_FOREACH(state, pf_state_tree_id,
2492 			    &tree_id) {
2493 				if (state->src_node == sn) {
2494 					state->src_node = NULL;
2495 				}
2496 				if (state->nat_src_node == sn) {
2497 					state->nat_src_node = NULL;
2498 				}
2499 			}
2500 			sn->states = 0;
2501 		}
2502 		sn->expire = 1;
2503 		killed++;
2504 	}
2505 	if (killed) {
2506 		pf_purge_expired_src_nodes();
2507 	}
2508 }
2509 
2510 static void
pf_delete_rule_from_ruleset(struct pf_ruleset * ruleset,int rs_num,struct pf_rule * rule)2511 pf_delete_rule_from_ruleset(struct pf_ruleset *ruleset, int rs_num,
2512     struct pf_rule *rule)
2513 {
2514 	struct pf_rule *r;
2515 	int nr = 0;
2516 
2517 	pf_expire_states_and_src_nodes(rule);
2518 
2519 	pf_rm_rule(ruleset->rules[rs_num].active.ptr, rule);
2520 	if (ruleset->rules[rs_num].active.rcount-- == 0) {
2521 		panic("%s: rcount value broken!", __func__);
2522 	}
2523 	r = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
2524 
2525 	while (r) {
2526 		r->nr = nr++;
2527 		r = TAILQ_NEXT(r, entries);
2528 	}
2529 }
2530 
2531 
2532 static void
pf_ruleset_cleanup(struct pf_ruleset * ruleset,int rs)2533 pf_ruleset_cleanup(struct pf_ruleset *ruleset, int rs)
2534 {
2535 	pf_calc_skip_steps(ruleset->rules[rs].active.ptr);
2536 	ruleset->rules[rs].active.ticket =
2537 	    ++ruleset->rules[rs].inactive.ticket;
2538 }
2539 
2540 /*
2541  * req_dev encodes the PF interface. Currently, possible values are
2542  * 0 or PFRULE_PFM
2543  */
2544 static int
pf_delete_rule_by_ticket(struct pfioc_rule * pr,u_int32_t req_dev)2545 pf_delete_rule_by_ticket(struct pfioc_rule *pr, u_int32_t req_dev)
2546 {
2547 	struct pf_ruleset       *ruleset;
2548 	struct pf_rule          *rule = NULL;
2549 	int                      is_anchor;
2550 	int                      error = 0;
2551 	int                      i;
2552 
2553 	is_anchor = (pr->anchor_call[0] != '\0');
2554 	if ((ruleset = pf_find_ruleset_with_owner(pr->anchor,
2555 	    pr->rule.owner, is_anchor, &error)) == NULL) {
2556 		goto done;
2557 	}
2558 
2559 	for (i = 0; i < PF_RULESET_MAX && rule == NULL; i++) {
2560 		rule = TAILQ_FIRST(ruleset->rules[i].active.ptr);
2561 		while (rule && (rule->ticket != pr->rule.ticket)) {
2562 			rule = TAILQ_NEXT(rule, entries);
2563 		}
2564 	}
2565 	if (rule == NULL) {
2566 		error = ENOENT;
2567 		goto done;
2568 	} else {
2569 		i--;
2570 	}
2571 
2572 	if (strcmp(rule->owner, pr->rule.owner)) {
2573 		error = EACCES;
2574 		goto done;
2575 	}
2576 
2577 delete_rule:
2578 	if (rule->anchor && (ruleset != &pf_main_ruleset) &&
2579 	    ((strcmp(ruleset->anchor->owner, "")) == 0) &&
2580 	    ((ruleset->rules[i].active.rcount - 1) == 0)) {
2581 		/* set rule & ruleset to parent and repeat */
2582 		struct pf_rule *delete_rule = rule;
2583 		struct pf_ruleset *delete_ruleset = ruleset;
2584 
2585 #define parent_ruleset          ruleset->anchor->parent->ruleset
2586 		if (ruleset->anchor->parent == NULL) {
2587 			ruleset = &pf_main_ruleset;
2588 		} else {
2589 			ruleset = &parent_ruleset;
2590 		}
2591 
2592 		rule = TAILQ_FIRST(ruleset->rules[i].active.ptr);
2593 		while (rule &&
2594 		    (rule->anchor != delete_ruleset->anchor)) {
2595 			rule = TAILQ_NEXT(rule, entries);
2596 		}
2597 		if (rule == NULL) {
2598 			panic("%s: rule not found!", __func__);
2599 		}
2600 
2601 		/*
2602 		 * if reqest device != rule's device, bail :
2603 		 * with error if ticket matches;
2604 		 * without error if ticket doesn't match (i.e. its just cleanup)
2605 		 */
2606 		if ((rule->rule_flag & PFRULE_PFM) ^ req_dev) {
2607 			if (rule->ticket != pr->rule.ticket) {
2608 				goto done;
2609 			} else {
2610 				error = EACCES;
2611 				goto done;
2612 			}
2613 		}
2614 
2615 		if (delete_rule->rule_flag & PFRULE_PFM) {
2616 			pffwrules--;
2617 		}
2618 
2619 		pf_delete_rule_from_ruleset(delete_ruleset,
2620 		    i, delete_rule);
2621 		delete_ruleset->rules[i].active.ticket =
2622 		    ++delete_ruleset->rules[i].inactive.ticket;
2623 		goto delete_rule;
2624 	} else {
2625 		/*
2626 		 * process deleting rule only if device that added the
2627 		 * rule matches device that issued the request
2628 		 */
2629 		if ((rule->rule_flag & PFRULE_PFM) ^ req_dev) {
2630 			error = EACCES;
2631 			goto done;
2632 		}
2633 		if (rule->rule_flag & PFRULE_PFM) {
2634 			pffwrules--;
2635 		}
2636 		pf_delete_rule_from_ruleset(ruleset, i,
2637 		    rule);
2638 		pf_ruleset_cleanup(ruleset, i);
2639 	}
2640 
2641 done:
2642 	if (ruleset) {
2643 		pf_release_ruleset(ruleset);
2644 		ruleset = NULL;
2645 	}
2646 	return error;
2647 }
2648 
2649 /*
2650  * req_dev encodes the PF interface. Currently, possible values are
2651  * 0 or PFRULE_PFM
2652  */
2653 static void
pf_delete_rule_by_owner(char * owner,u_int32_t req_dev)2654 pf_delete_rule_by_owner(char *owner, u_int32_t req_dev)
2655 {
2656 	struct pf_ruleset       *ruleset;
2657 	struct pf_rule          *rule, *next;
2658 	int                      deleted = 0;
2659 
2660 	for (int rs = 0; rs < PF_RULESET_MAX; rs++) {
2661 		rule = TAILQ_FIRST(pf_main_ruleset.rules[rs].active.ptr);
2662 		ruleset = &pf_main_ruleset;
2663 		while (rule) {
2664 			next = TAILQ_NEXT(rule, entries);
2665 			/*
2666 			 * process deleting rule only if device that added the
2667 			 * rule matches device that issued the request
2668 			 */
2669 			if ((rule->rule_flag & PFRULE_PFM) ^ req_dev) {
2670 				rule = next;
2671 			} else if (rule->anchor) {
2672 				if (((strcmp(rule->owner, owner)) == 0) ||
2673 				    ((strcmp(rule->owner, "")) == 0)) {
2674 					if (rule->anchor->ruleset.rules[rs].active.rcount > 0) {
2675 						if (deleted) {
2676 							pf_ruleset_cleanup(ruleset, rs);
2677 							deleted = 0;
2678 						}
2679 						/* step into anchor */
2680 						ruleset =
2681 						    &rule->anchor->ruleset;
2682 						rule = TAILQ_FIRST(ruleset->rules[rs].active.ptr);
2683 						continue;
2684 					} else {
2685 						if (rule->rule_flag &
2686 						    PFRULE_PFM) {
2687 							pffwrules--;
2688 						}
2689 						pf_delete_rule_from_ruleset(ruleset, rs, rule);
2690 						deleted = 1;
2691 						rule = next;
2692 					}
2693 				} else {
2694 					rule = next;
2695 				}
2696 			} else {
2697 				if (((strcmp(rule->owner, owner)) == 0)) {
2698 					/* delete rule */
2699 					if (rule->rule_flag & PFRULE_PFM) {
2700 						pffwrules--;
2701 					}
2702 					pf_delete_rule_from_ruleset(ruleset,
2703 					    rs, rule);
2704 					deleted = 1;
2705 				}
2706 				rule = next;
2707 			}
2708 			if (rule == NULL) {
2709 				if (deleted) {
2710 					pf_ruleset_cleanup(ruleset, rs);
2711 					deleted = 0;
2712 				}
2713 				if (ruleset != &pf_main_ruleset) {
2714 					pf_deleterule_anchor_step_out(&ruleset,
2715 					    rs, &rule);
2716 				}
2717 			}
2718 		}
2719 	}
2720 }
2721 
2722 static void
pf_deleterule_anchor_step_out(struct pf_ruleset ** ruleset_ptr,int rs,struct pf_rule ** rule_ptr)2723 pf_deleterule_anchor_step_out(struct pf_ruleset **ruleset_ptr,
2724     int rs, struct pf_rule **rule_ptr)
2725 {
2726 	struct pf_ruleset *ruleset = *ruleset_ptr;
2727 	struct pf_rule *rule = *rule_ptr;
2728 
2729 	/* step out of anchor */
2730 	struct pf_ruleset *rs_copy = ruleset;
2731 	ruleset = ruleset->anchor->parent?
2732 	    &ruleset->anchor->parent->ruleset:&pf_main_ruleset;
2733 
2734 	rule = TAILQ_FIRST(ruleset->rules[rs].active.ptr);
2735 	while (rule && (rule->anchor != rs_copy->anchor)) {
2736 		rule = TAILQ_NEXT(rule, entries);
2737 	}
2738 	if (rule == NULL) {
2739 		panic("%s: parent rule of anchor not found!", __func__);
2740 	}
2741 	if (rule->anchor->ruleset.rules[rs].active.rcount > 0) {
2742 		rule = TAILQ_NEXT(rule, entries);
2743 	}
2744 
2745 	*ruleset_ptr = ruleset;
2746 	*rule_ptr = rule;
2747 }
2748 
2749 static void
pf_addrwrap_setup(struct pf_addr_wrap * aw)2750 pf_addrwrap_setup(struct pf_addr_wrap *aw)
2751 {
2752 	VERIFY(aw);
2753 	bzero(&aw->p, sizeof aw->p);
2754 }
2755 
2756 static int
pf_rule_setup(struct pfioc_rule * pr,struct pf_rule * rule,struct pf_ruleset * ruleset)2757 pf_rule_setup(struct pfioc_rule *pr, struct pf_rule *rule,
2758     struct pf_ruleset *ruleset)
2759 {
2760 	struct pf_pooladdr      *apa;
2761 	int                      error = 0;
2762 
2763 	if (rule->ifname[0]) {
2764 		rule->kif = pfi_kif_get(rule->ifname);
2765 		if (rule->kif == NULL) {
2766 			pool_put(&pf_rule_pl, rule);
2767 			return EINVAL;
2768 		}
2769 		pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE);
2770 	}
2771 	if (rule->tagname[0]) {
2772 		if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) {
2773 			error = EBUSY;
2774 		}
2775 	}
2776 	if (rule->match_tagname[0]) {
2777 		if ((rule->match_tag =
2778 		    pf_tagname2tag(rule->match_tagname)) == 0) {
2779 			error = EBUSY;
2780 		}
2781 	}
2782 	if (rule->rt && !rule->direction) {
2783 		error = EINVAL;
2784 	}
2785 #if PFLOG
2786 	if (!rule->log) {
2787 		rule->logif = 0;
2788 	}
2789 	if (rule->logif >= PFLOGIFS_MAX) {
2790 		error = EINVAL;
2791 	}
2792 #endif /* PFLOG */
2793 	pf_addrwrap_setup(&rule->src.addr);
2794 	pf_addrwrap_setup(&rule->dst.addr);
2795 	if (pf_rtlabel_add(&rule->src.addr) ||
2796 	    pf_rtlabel_add(&rule->dst.addr)) {
2797 		error = EBUSY;
2798 	}
2799 	if (pfi_dynaddr_setup(&rule->src.addr, rule->af)) {
2800 		error = EINVAL;
2801 	}
2802 	if (pfi_dynaddr_setup(&rule->dst.addr, rule->af)) {
2803 		error = EINVAL;
2804 	}
2805 	if (pf_tbladdr_setup(ruleset, &rule->src.addr)) {
2806 		error = EINVAL;
2807 	}
2808 	if (pf_tbladdr_setup(ruleset, &rule->dst.addr)) {
2809 		error = EINVAL;
2810 	}
2811 	if (pf_anchor_setup(rule, ruleset, pr->anchor_call)) {
2812 		error = EINVAL;
2813 	}
2814 	TAILQ_FOREACH(apa, &pf_pabuf, entries)
2815 	if (pf_tbladdr_setup(ruleset, &apa->addr)) {
2816 		error = EINVAL;
2817 	}
2818 
2819 	if (rule->overload_tblname[0]) {
2820 		if ((rule->overload_tbl = pfr_attach_table(ruleset,
2821 		    rule->overload_tblname)) == NULL) {
2822 			error = EINVAL;
2823 		} else {
2824 			rule->overload_tbl->pfrkt_flags |=
2825 			    PFR_TFLAG_ACTIVE;
2826 		}
2827 	}
2828 
2829 	pf_mv_pool(&pf_pabuf, &rule->rpool.list);
2830 
2831 	if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
2832 	    (rule->action == PF_BINAT) || (rule->action == PF_NAT64)) &&
2833 	    rule->anchor == NULL) ||
2834 	    (rule->rt > PF_FASTROUTE)) &&
2835 	    (TAILQ_FIRST(&rule->rpool.list) == NULL)) {
2836 		error = EINVAL;
2837 	}
2838 
2839 	if (error) {
2840 		pf_rm_rule(NULL, rule);
2841 		return error;
2842 	}
2843 	/* For a NAT64 rule the rule's address family is AF_INET6 whereas
2844 	 * the address pool's family will be AF_INET
2845 	 */
2846 	rule->rpool.af = (rule->action == PF_NAT64) ? AF_INET: rule->af;
2847 	rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
2848 	rule->evaluations = rule->packets[0] = rule->packets[1] =
2849 	    rule->bytes[0] = rule->bytes[1] = 0;
2850 
2851 	return 0;
2852 }
2853 
2854 static int
pfioctl_ioc_rule(u_long cmd,int minordev,struct pfioc_rule * pr,struct proc * p)2855 pfioctl_ioc_rule(u_long cmd, int minordev, struct pfioc_rule *pr, struct proc *p)
2856 {
2857 	int error = 0;
2858 	u_int32_t req_dev = 0;
2859 	struct pf_ruleset *ruleset = NULL;
2860 
2861 	switch (cmd) {
2862 	case DIOCADDRULE: {
2863 		struct pf_rule          *rule, *tail;
2864 		int                     rs_num;
2865 
2866 		pr->anchor[sizeof(pr->anchor) - 1] = '\0';
2867 		pr->anchor_call[sizeof(pr->anchor_call) - 1] = '\0';
2868 		ruleset = pf_find_ruleset(pr->anchor);
2869 		if (ruleset == NULL) {
2870 			error = EINVAL;
2871 			break;
2872 		}
2873 		rs_num = pf_get_ruleset_number(pr->rule.action);
2874 		if (rs_num >= PF_RULESET_MAX) {
2875 			error = EINVAL;
2876 			break;
2877 		}
2878 		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
2879 			error = EINVAL;
2880 			break;
2881 		}
2882 		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
2883 			error = EBUSY;
2884 			break;
2885 		}
2886 		if (pr->pool_ticket != ticket_pabuf) {
2887 			error = EBUSY;
2888 			break;
2889 		}
2890 		rule = pool_get(&pf_rule_pl, PR_WAITOK);
2891 		if (rule == NULL) {
2892 			error = ENOMEM;
2893 			break;
2894 		}
2895 		pf_rule_copyin(&pr->rule, rule, p, minordev);
2896 #if !INET
2897 		if (rule->af == AF_INET) {
2898 			pool_put(&pf_rule_pl, rule);
2899 			error = EAFNOSUPPORT;
2900 			break;
2901 		}
2902 #endif /* INET */
2903 		tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
2904 		    pf_rulequeue);
2905 		if (tail) {
2906 			rule->nr = tail->nr + 1;
2907 		} else {
2908 			rule->nr = 0;
2909 		}
2910 
2911 		if ((error = pf_rule_setup(pr, rule, ruleset))) {
2912 			break;
2913 		}
2914 
2915 		TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
2916 		    rule, entries);
2917 		ruleset->rules[rs_num].inactive.rcount++;
2918 		if (rule->rule_flag & PFRULE_PFM) {
2919 			pffwrules++;
2920 		}
2921 
2922 		if (rule->action == PF_NAT64) {
2923 			os_atomic_inc(&pf_nat64_configured, relaxed);
2924 		}
2925 
2926 		if (pr->anchor_call[0] == '\0') {
2927 			INC_ATOMIC_INT64_LIM(net_api_stats.nas_pf_addrule_total);
2928 			if (rule->rule_flag & PFRULE_PFM) {
2929 				INC_ATOMIC_INT64_LIM(net_api_stats.nas_pf_addrule_os);
2930 			}
2931 		}
2932 
2933 #if DUMMYNET
2934 		if (rule->action == PF_DUMMYNET) {
2935 			struct dummynet_event dn_event;
2936 			uint32_t direction = DN_INOUT;
2937 			bzero(&dn_event, sizeof(dn_event));
2938 
2939 			dn_event.dn_event_code = DUMMYNET_RULE_CONFIG;
2940 
2941 			if (rule->direction == PF_IN) {
2942 				direction = DN_IN;
2943 			} else if (rule->direction == PF_OUT) {
2944 				direction = DN_OUT;
2945 			}
2946 
2947 			dn_event.dn_event_rule_config.dir = direction;
2948 			dn_event.dn_event_rule_config.af = rule->af;
2949 			dn_event.dn_event_rule_config.proto = rule->proto;
2950 			dn_event.dn_event_rule_config.src_port = rule->src.xport.range.port[0];
2951 			dn_event.dn_event_rule_config.dst_port = rule->dst.xport.range.port[0];
2952 			strlcpy(dn_event.dn_event_rule_config.ifname, rule->ifname,
2953 			    sizeof(dn_event.dn_event_rule_config.ifname));
2954 
2955 			dummynet_event_enqueue_nwk_wq_entry(&dn_event);
2956 		}
2957 #endif
2958 		break;
2959 	}
2960 
2961 	case DIOCGETRULES: {
2962 		struct pf_rule          *tail;
2963 		int                      rs_num;
2964 
2965 		pr->anchor[sizeof(pr->anchor) - 1] = '\0';
2966 		pr->anchor_call[sizeof(pr->anchor_call) - 1] = '\0';
2967 		ruleset = pf_find_ruleset(pr->anchor);
2968 		if (ruleset == NULL) {
2969 			error = EINVAL;
2970 			break;
2971 		}
2972 		rs_num = pf_get_ruleset_number(pr->rule.action);
2973 		if (rs_num >= PF_RULESET_MAX) {
2974 			error = EINVAL;
2975 			break;
2976 		}
2977 		tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
2978 		    pf_rulequeue);
2979 		if (tail) {
2980 			pr->nr = tail->nr + 1;
2981 		} else {
2982 			pr->nr = 0;
2983 		}
2984 		pr->ticket = ruleset->rules[rs_num].active.ticket;
2985 		break;
2986 	}
2987 
2988 	case DIOCGETRULE: {
2989 		struct pf_rule          *rule;
2990 		int                      rs_num, i;
2991 
2992 		pr->anchor[sizeof(pr->anchor) - 1] = '\0';
2993 		pr->anchor_call[sizeof(pr->anchor_call) - 1] = '\0';
2994 		ruleset = pf_find_ruleset(pr->anchor);
2995 		if (ruleset == NULL) {
2996 			error = EINVAL;
2997 			break;
2998 		}
2999 		rs_num = pf_get_ruleset_number(pr->rule.action);
3000 		if (rs_num >= PF_RULESET_MAX) {
3001 			error = EINVAL;
3002 			break;
3003 		}
3004 		if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
3005 			error = EBUSY;
3006 			break;
3007 		}
3008 		rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
3009 		while ((rule != NULL) && (rule->nr != pr->nr)) {
3010 			rule = TAILQ_NEXT(rule, entries);
3011 		}
3012 		if (rule == NULL) {
3013 			error = EBUSY;
3014 			break;
3015 		}
3016 		pf_rule_copyout(rule, &pr->rule);
3017 		if (pf_anchor_copyout(ruleset, rule, pr)) {
3018 			error = EBUSY;
3019 			break;
3020 		}
3021 		pfi_dynaddr_copyout(&pr->rule.src.addr);
3022 		pfi_dynaddr_copyout(&pr->rule.dst.addr);
3023 		pf_tbladdr_copyout(&pr->rule.src.addr);
3024 		pf_tbladdr_copyout(&pr->rule.dst.addr);
3025 		pf_rtlabel_copyout(&pr->rule.src.addr);
3026 		pf_rtlabel_copyout(&pr->rule.dst.addr);
3027 		for (i = 0; i < PF_SKIP_COUNT; ++i) {
3028 			if (rule->skip[i].ptr == NULL) {
3029 				pr->rule.skip[i].nr = -1;
3030 			} else {
3031 				pr->rule.skip[i].nr =
3032 				    rule->skip[i].ptr->nr;
3033 			}
3034 		}
3035 
3036 		if (pr->action == PF_GET_CLR_CNTR) {
3037 			rule->evaluations = 0;
3038 			rule->packets[0] = rule->packets[1] = 0;
3039 			rule->bytes[0] = rule->bytes[1] = 0;
3040 		}
3041 		break;
3042 	}
3043 
3044 	case DIOCCHANGERULE: {
3045 		struct pfioc_rule       *pcr = pr;
3046 		struct pf_rule          *oldrule = NULL, *newrule = NULL;
3047 		struct pf_pooladdr      *pa;
3048 		u_int32_t                nr = 0;
3049 		int                      rs_num;
3050 
3051 		if (!(pcr->action == PF_CHANGE_REMOVE ||
3052 		    pcr->action == PF_CHANGE_GET_TICKET) &&
3053 		    pcr->pool_ticket != ticket_pabuf) {
3054 			error = EBUSY;
3055 			break;
3056 		}
3057 
3058 		if (pcr->action < PF_CHANGE_ADD_HEAD ||
3059 		    pcr->action > PF_CHANGE_GET_TICKET) {
3060 			error = EINVAL;
3061 			break;
3062 		}
3063 		pcr->anchor[sizeof(pcr->anchor) - 1] = '\0';
3064 		pcr->anchor_call[sizeof(pcr->anchor_call) - 1] = '\0';
3065 		ruleset = pf_find_ruleset(pcr->anchor);
3066 		if (ruleset == NULL) {
3067 			error = EINVAL;
3068 			break;
3069 		}
3070 		rs_num = pf_get_ruleset_number(pcr->rule.action);
3071 		if (rs_num >= PF_RULESET_MAX) {
3072 			error = EINVAL;
3073 			break;
3074 		}
3075 
3076 		if (pcr->action == PF_CHANGE_GET_TICKET) {
3077 			pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
3078 			break;
3079 		} else {
3080 			if (pcr->ticket !=
3081 			    ruleset->rules[rs_num].active.ticket) {
3082 				error = EINVAL;
3083 				break;
3084 			}
3085 			if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
3086 				error = EINVAL;
3087 				break;
3088 			}
3089 		}
3090 
3091 		if (pcr->action != PF_CHANGE_REMOVE) {
3092 			newrule = pool_get(&pf_rule_pl, PR_WAITOK);
3093 			if (newrule == NULL) {
3094 				error = ENOMEM;
3095 				break;
3096 			}
3097 			pf_rule_copyin(&pcr->rule, newrule, p, minordev);
3098 #if !INET
3099 			if (newrule->af == AF_INET) {
3100 				pool_put(&pf_rule_pl, newrule);
3101 				error = EAFNOSUPPORT;
3102 				break;
3103 			}
3104 #endif /* INET */
3105 			if (newrule->ifname[0]) {
3106 				newrule->kif = pfi_kif_get(newrule->ifname);
3107 				if (newrule->kif == NULL) {
3108 					pool_put(&pf_rule_pl, newrule);
3109 					error = EINVAL;
3110 					break;
3111 				}
3112 				pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE);
3113 			} else {
3114 				newrule->kif = NULL;
3115 			}
3116 
3117 			if (newrule->tagname[0]) {
3118 				if ((newrule->tag =
3119 				    pf_tagname2tag(newrule->tagname)) == 0) {
3120 					error = EBUSY;
3121 				}
3122 			}
3123 			if (newrule->match_tagname[0]) {
3124 				if ((newrule->match_tag = pf_tagname2tag(
3125 					    newrule->match_tagname)) == 0) {
3126 					error = EBUSY;
3127 				}
3128 			}
3129 			if (newrule->rt && !newrule->direction) {
3130 				error = EINVAL;
3131 			}
3132 #if PFLOG
3133 			if (!newrule->log) {
3134 				newrule->logif = 0;
3135 			}
3136 			if (newrule->logif >= PFLOGIFS_MAX) {
3137 				error = EINVAL;
3138 			}
3139 #endif /* PFLOG */
3140 			pf_addrwrap_setup(&newrule->src.addr);
3141 			pf_addrwrap_setup(&newrule->dst.addr);
3142 			if (pf_rtlabel_add(&newrule->src.addr) ||
3143 			    pf_rtlabel_add(&newrule->dst.addr)) {
3144 				error = EBUSY;
3145 			}
3146 			if (pfi_dynaddr_setup(&newrule->src.addr, newrule->af)) {
3147 				error = EINVAL;
3148 			}
3149 			if (pfi_dynaddr_setup(&newrule->dst.addr, newrule->af)) {
3150 				error = EINVAL;
3151 			}
3152 			if (pf_tbladdr_setup(ruleset, &newrule->src.addr)) {
3153 				error = EINVAL;
3154 			}
3155 			if (pf_tbladdr_setup(ruleset, &newrule->dst.addr)) {
3156 				error = EINVAL;
3157 			}
3158 			if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call)) {
3159 				error = EINVAL;
3160 			}
3161 			TAILQ_FOREACH(pa, &pf_pabuf, entries)
3162 			if (pf_tbladdr_setup(ruleset, &pa->addr)) {
3163 				error = EINVAL;
3164 			}
3165 
3166 			if (newrule->overload_tblname[0]) {
3167 				if ((newrule->overload_tbl = pfr_attach_table(
3168 					    ruleset, newrule->overload_tblname)) ==
3169 				    NULL) {
3170 					error = EINVAL;
3171 				} else {
3172 					newrule->overload_tbl->pfrkt_flags |=
3173 					    PFR_TFLAG_ACTIVE;
3174 				}
3175 			}
3176 
3177 			pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
3178 			if (((((newrule->action == PF_NAT) ||
3179 			    (newrule->action == PF_RDR) ||
3180 			    (newrule->action == PF_BINAT) ||
3181 			    (newrule->rt > PF_FASTROUTE)) &&
3182 			    !newrule->anchor)) &&
3183 			    (TAILQ_FIRST(&newrule->rpool.list) == NULL)) {
3184 				error = EINVAL;
3185 			}
3186 
3187 			if (error) {
3188 				pf_rm_rule(NULL, newrule);
3189 				break;
3190 			}
3191 			newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
3192 			newrule->evaluations = 0;
3193 			newrule->packets[0] = newrule->packets[1] = 0;
3194 			newrule->bytes[0] = newrule->bytes[1] = 0;
3195 		}
3196 		pf_empty_pool(&pf_pabuf);
3197 
3198 		if (pcr->action == PF_CHANGE_ADD_HEAD) {
3199 			oldrule = TAILQ_FIRST(
3200 				ruleset->rules[rs_num].active.ptr);
3201 		} else if (pcr->action == PF_CHANGE_ADD_TAIL) {
3202 			oldrule = TAILQ_LAST(
3203 				ruleset->rules[rs_num].active.ptr, pf_rulequeue);
3204 		} else {
3205 			oldrule = TAILQ_FIRST(
3206 				ruleset->rules[rs_num].active.ptr);
3207 			while ((oldrule != NULL) && (oldrule->nr != pcr->nr)) {
3208 				oldrule = TAILQ_NEXT(oldrule, entries);
3209 			}
3210 			if (oldrule == NULL) {
3211 				if (newrule != NULL) {
3212 					pf_rm_rule(NULL, newrule);
3213 				}
3214 				error = EINVAL;
3215 				break;
3216 			}
3217 		}
3218 
3219 		if (pcr->action == PF_CHANGE_REMOVE) {
3220 			pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
3221 			ruleset->rules[rs_num].active.rcount--;
3222 		} else {
3223 			if (oldrule == NULL) {
3224 				TAILQ_INSERT_TAIL(
3225 					ruleset->rules[rs_num].active.ptr,
3226 					newrule, entries);
3227 			} else if (pcr->action == PF_CHANGE_ADD_HEAD ||
3228 			    pcr->action == PF_CHANGE_ADD_BEFORE) {
3229 				TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
3230 			} else {
3231 				TAILQ_INSERT_AFTER(
3232 					ruleset->rules[rs_num].active.ptr,
3233 					oldrule, newrule, entries);
3234 			}
3235 			ruleset->rules[rs_num].active.rcount++;
3236 		}
3237 
3238 		nr = 0;
3239 		TAILQ_FOREACH(oldrule,
3240 		    ruleset->rules[rs_num].active.ptr, entries)
3241 		oldrule->nr = nr++;
3242 
3243 		ruleset->rules[rs_num].active.ticket++;
3244 
3245 		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
3246 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
3247 		pf_process_compatibilities();
3248 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
3249 		break;
3250 	}
3251 
3252 	case DIOCINSERTRULE: {
3253 		struct pf_rule          *rule, *tail, *r;
3254 		int                     rs_num;
3255 		int                     is_anchor;
3256 
3257 		pr->anchor[sizeof(pr->anchor) - 1] = '\0';
3258 		pr->anchor_call[sizeof(pr->anchor_call) - 1] = '\0';
3259 		is_anchor = (pr->anchor_call[0] != '\0');
3260 
3261 		if ((ruleset = pf_find_ruleset_with_owner(pr->anchor,
3262 		    pr->rule.owner, is_anchor, &error)) == NULL) {
3263 			break;
3264 		}
3265 
3266 		rs_num = pf_get_ruleset_number(pr->rule.action);
3267 		if (rs_num >= PF_RULESET_MAX) {
3268 			error = EINVAL;
3269 			break;
3270 		}
3271 		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
3272 			error = EINVAL;
3273 			break;
3274 		}
3275 
3276 		/* make sure this anchor rule doesn't exist already */
3277 		if (is_anchor) {
3278 			r = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
3279 			while (r) {
3280 				if (r->anchor &&
3281 				    ((strcmp(r->anchor->name,
3282 				    pr->anchor_call)) == 0)) {
3283 					if (((strcmp(pr->rule.owner,
3284 					    r->owner)) == 0) ||
3285 					    ((strcmp(r->owner, "")) == 0)) {
3286 						error = EEXIST;
3287 					} else {
3288 						error = EPERM;
3289 					}
3290 					break;
3291 				}
3292 				r = TAILQ_NEXT(r, entries);
3293 			}
3294 			if (error != 0) {
3295 				break;
3296 			}
3297 		}
3298 
3299 		rule = pool_get(&pf_rule_pl, PR_WAITOK);
3300 		if (rule == NULL) {
3301 			error = ENOMEM;
3302 			break;
3303 		}
3304 		pf_rule_copyin(&pr->rule, rule, p, minordev);
3305 #if !INET
3306 		if (rule->af == AF_INET) {
3307 			pool_put(&pf_rule_pl, rule);
3308 			error = EAFNOSUPPORT;
3309 			break;
3310 		}
3311 #endif /* INET */
3312 		r = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
3313 		while ((r != NULL) && (rule->priority >= (unsigned)r->priority)) {
3314 			r = TAILQ_NEXT(r, entries);
3315 		}
3316 		if (r == NULL) {
3317 			if ((tail =
3318 			    TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
3319 			    pf_rulequeue)) != NULL) {
3320 				rule->nr = tail->nr + 1;
3321 			} else {
3322 				rule->nr = 0;
3323 			}
3324 		} else {
3325 			rule->nr = r->nr;
3326 		}
3327 
3328 		if ((error = pf_rule_setup(pr, rule, ruleset))) {
3329 			break;
3330 		}
3331 
3332 		if (rule->anchor != NULL) {
3333 			strlcpy(rule->anchor->owner, rule->owner,
3334 			    PF_OWNER_NAME_SIZE);
3335 		}
3336 
3337 		if (r) {
3338 			TAILQ_INSERT_BEFORE(r, rule, entries);
3339 			while (r && ++r->nr) {
3340 				r = TAILQ_NEXT(r, entries);
3341 			}
3342 		} else {
3343 			TAILQ_INSERT_TAIL(ruleset->rules[rs_num].active.ptr,
3344 			    rule, entries);
3345 		}
3346 		ruleset->rules[rs_num].active.rcount++;
3347 
3348 		/* Calculate checksum for the main ruleset */
3349 		if (ruleset == &pf_main_ruleset) {
3350 			error = pf_setup_pfsync_matching(ruleset);
3351 		}
3352 
3353 		pf_ruleset_cleanup(ruleset, rs_num);
3354 		rule->ticket = VM_KERNEL_ADDRHASH((u_int64_t)(uintptr_t)rule);
3355 
3356 		pr->rule.ticket = rule->ticket;
3357 		pf_rule_copyout(rule, &pr->rule);
3358 		if (rule->rule_flag & PFRULE_PFM) {
3359 			pffwrules++;
3360 		}
3361 		if (rule->action == PF_NAT64) {
3362 			os_atomic_inc(&pf_nat64_configured, relaxed);
3363 		}
3364 
3365 		if (pr->anchor_call[0] == '\0') {
3366 			INC_ATOMIC_INT64_LIM(net_api_stats.nas_pf_addrule_total);
3367 			if (rule->rule_flag & PFRULE_PFM) {
3368 				INC_ATOMIC_INT64_LIM(net_api_stats.nas_pf_addrule_os);
3369 			}
3370 		}
3371 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
3372 		pf_process_compatibilities();
3373 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
3374 		break;
3375 	}
3376 
3377 	case DIOCDELETERULE: {
3378 		ASSERT(ruleset == NULL);
3379 		pr->anchor[sizeof(pr->anchor) - 1] = '\0';
3380 		pr->anchor_call[sizeof(pr->anchor_call) - 1] = '\0';
3381 
3382 		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
3383 			error = EINVAL;
3384 			break;
3385 		}
3386 
3387 		/* get device through which request is made */
3388 		if ((uint8_t)minordev == PFDEV_PFM) {
3389 			req_dev |= PFRULE_PFM;
3390 		}
3391 
3392 		if (pr->rule.ticket) {
3393 			if ((error = pf_delete_rule_by_ticket(pr, req_dev))) {
3394 				break;
3395 			}
3396 		} else {
3397 			pf_delete_rule_by_owner(pr->rule.owner, req_dev);
3398 		}
3399 		pr->nr = pffwrules;
3400 		if (pr->rule.action == PF_NAT64) {
3401 			os_atomic_dec(&pf_nat64_configured, relaxed);
3402 		}
3403 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
3404 		pf_process_compatibilities();
3405 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
3406 		break;
3407 	}
3408 
3409 	default:
3410 		VERIFY(0);
3411 		/* NOTREACHED */
3412 	}
3413 	if (ruleset != NULL) {
3414 		pf_release_ruleset(ruleset);
3415 		ruleset = NULL;
3416 	}
3417 
3418 	return error;
3419 }
3420 
3421 static int
pfioctl_ioc_state_kill(u_long cmd,struct pfioc_state_kill * psk,struct proc * p)3422 pfioctl_ioc_state_kill(u_long cmd, struct pfioc_state_kill *psk, struct proc *p)
3423 {
3424 #pragma unused(p)
3425 	int error = 0;
3426 
3427 	psk->psk_ifname[sizeof(psk->psk_ifname) - 1] = '\0';
3428 	psk->psk_ownername[sizeof(psk->psk_ownername) - 1] = '\0';
3429 
3430 	bool ifname_matched = true;
3431 	bool owner_matched = true;
3432 
3433 	switch (cmd) {
3434 	case DIOCCLRSTATES: {
3435 		struct pf_state         *s, *nexts;
3436 		int                      killed = 0;
3437 
3438 		for (s = RB_MIN(pf_state_tree_id, &tree_id); s; s = nexts) {
3439 			nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
3440 			/*
3441 			 * Purge all states only when neither ifname
3442 			 * or owner is provided. If any of these are provided
3443 			 * we purge only the states with meta data that match
3444 			 */
3445 			bool unlink_state = false;
3446 			ifname_matched = true;
3447 			owner_matched = true;
3448 
3449 			if (psk->psk_ifname[0] &&
3450 			    strcmp(psk->psk_ifname, s->kif->pfik_name)) {
3451 				ifname_matched = false;
3452 			}
3453 
3454 			if (psk->psk_ownername[0] &&
3455 			    ((NULL == s->rule.ptr) ||
3456 			    strcmp(psk->psk_ownername, s->rule.ptr->owner))) {
3457 				owner_matched = false;
3458 			}
3459 
3460 			unlink_state = ifname_matched && owner_matched;
3461 
3462 			if (unlink_state) {
3463 #if NPFSYNC
3464 				/* don't send out individual delete messages */
3465 				s->sync_flags = PFSTATE_NOSYNC;
3466 #endif
3467 				pf_unlink_state(s);
3468 				killed++;
3469 			}
3470 		}
3471 		psk->psk_af = (sa_family_t)killed;
3472 #if NPFSYNC
3473 		pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
3474 #endif
3475 		break;
3476 	}
3477 
3478 	case DIOCKILLSTATES: {
3479 		struct pf_state         *s, *nexts;
3480 		struct pf_state_key     *sk;
3481 		struct pf_state_host    *src, *dst;
3482 		int                      killed = 0;
3483 
3484 		for (s = RB_MIN(pf_state_tree_id, &tree_id); s;
3485 		    s = nexts) {
3486 			nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
3487 			sk = s->state_key;
3488 			ifname_matched = true;
3489 			owner_matched = true;
3490 
3491 			if (psk->psk_ifname[0] &&
3492 			    strcmp(psk->psk_ifname, s->kif->pfik_name)) {
3493 				ifname_matched = false;
3494 			}
3495 
3496 			if (psk->psk_ownername[0] &&
3497 			    ((NULL == s->rule.ptr) ||
3498 			    strcmp(psk->psk_ownername, s->rule.ptr->owner))) {
3499 				owner_matched = false;
3500 			}
3501 
3502 			if (sk->direction == PF_OUT) {
3503 				src = &sk->lan;
3504 				dst = &sk->ext_lan;
3505 			} else {
3506 				src = &sk->ext_lan;
3507 				dst = &sk->lan;
3508 			}
3509 			if ((!psk->psk_af || sk->af_lan == psk->psk_af) &&
3510 			    (!psk->psk_proto || psk->psk_proto == sk->proto) &&
3511 			    PF_MATCHA(psk->psk_src.neg,
3512 			    &psk->psk_src.addr.v.a.addr,
3513 			    &psk->psk_src.addr.v.a.mask,
3514 			    &src->addr, sk->af_lan) &&
3515 			    PF_MATCHA(psk->psk_dst.neg,
3516 			    &psk->psk_dst.addr.v.a.addr,
3517 			    &psk->psk_dst.addr.v.a.mask,
3518 			    &dst->addr, sk->af_lan) &&
3519 			    (pf_match_xport(psk->psk_proto,
3520 			    psk->psk_proto_variant, &psk->psk_src.xport,
3521 			    &src->xport)) &&
3522 			    (pf_match_xport(psk->psk_proto,
3523 			    psk->psk_proto_variant, &psk->psk_dst.xport,
3524 			    &dst->xport)) &&
3525 			    ifname_matched &&
3526 			    owner_matched) {
3527 #if NPFSYNC
3528 				/* send immediate delete of state */
3529 				pfsync_delete_state(s);
3530 				s->sync_flags |= PFSTATE_NOSYNC;
3531 #endif
3532 				pf_unlink_state(s);
3533 				killed++;
3534 			}
3535 		}
3536 		psk->psk_af = (sa_family_t)killed;
3537 		break;
3538 	}
3539 
3540 	default:
3541 		VERIFY(0);
3542 		/* NOTREACHED */
3543 	}
3544 
3545 	return error;
3546 }
3547 
3548 static int
pfioctl_ioc_state(u_long cmd,struct pfioc_state * ps,struct proc * p)3549 pfioctl_ioc_state(u_long cmd, struct pfioc_state *ps, struct proc *p)
3550 {
3551 #pragma unused(p)
3552 	int error = 0;
3553 
3554 	switch (cmd) {
3555 	case DIOCADDSTATE: {
3556 		struct pfsync_state     *sp = &ps->state;
3557 		struct pf_state         *s;
3558 		struct pf_state_key     *sk;
3559 		struct pfi_kif          *kif;
3560 
3561 		if (sp->timeout >= PFTM_MAX) {
3562 			error = EINVAL;
3563 			break;
3564 		}
3565 		s = pool_get(&pf_state_pl, PR_WAITOK);
3566 		if (s == NULL) {
3567 			error = ENOMEM;
3568 			break;
3569 		}
3570 		bzero(s, sizeof(struct pf_state));
3571 		if ((sk = pf_alloc_state_key(s, NULL)) == NULL) {
3572 			pool_put(&pf_state_pl, s);
3573 			error = ENOMEM;
3574 			break;
3575 		}
3576 		pf_state_import(sp, sk, s);
3577 		kif = pfi_kif_get(sp->ifname);
3578 		if (kif == NULL) {
3579 			pf_detach_state(s, 0);
3580 			pool_put(&pf_state_pl, s);
3581 			error = ENOENT;
3582 			break;
3583 		}
3584 		TAILQ_INIT(&s->unlink_hooks);
3585 		s->state_key->app_state = 0;
3586 		if (pf_insert_state(kif, s)) {
3587 			pfi_kif_unref(kif, PFI_KIF_REF_NONE);
3588 			pool_put(&pf_state_pl, s);
3589 			error = EEXIST;
3590 			break;
3591 		}
3592 		pf_default_rule.states++;
3593 		VERIFY(pf_default_rule.states != 0);
3594 		break;
3595 	}
3596 
3597 	case DIOCGETSTATE: {
3598 		struct pf_state         *s;
3599 		struct pf_state_cmp      id_key;
3600 
3601 		bcopy(ps->state.id, &id_key.id, sizeof(id_key.id));
3602 		id_key.creatorid = ps->state.creatorid;
3603 
3604 		s = pf_find_state_byid(&id_key);
3605 		if (s == NULL) {
3606 			error = ENOENT;
3607 			break;
3608 		}
3609 
3610 		pf_state_export(&ps->state, s->state_key, s);
3611 		break;
3612 	}
3613 
3614 	default:
3615 		VERIFY(0);
3616 		/* NOTREACHED */
3617 	}
3618 
3619 	return error;
3620 }
3621 
3622 static int
pfioctl_ioc_states(u_long cmd,struct pfioc_states_32 * ps32,struct pfioc_states_64 * ps64,struct proc * p)3623 pfioctl_ioc_states(u_long cmd, struct pfioc_states_32 *ps32,
3624     struct pfioc_states_64 *ps64, struct proc *p)
3625 {
3626 	int p64 = proc_is64bit(p);
3627 	int error = 0;
3628 
3629 	switch (cmd) {
3630 	case DIOCGETSTATES: {           /* struct pfioc_states */
3631 		struct pf_state         *state;
3632 		struct pfsync_state     *pstore;
3633 		user_addr_t              buf;
3634 		u_int32_t                nr = 0;
3635 		int                      len, size;
3636 
3637 		len = (p64 ? ps64->ps_len : ps32->ps_len);
3638 		if (len == 0) {
3639 			size = sizeof(struct pfsync_state) * pf_status.states;
3640 			if (p64) {
3641 				ps64->ps_len = size;
3642 			} else {
3643 				ps32->ps_len = size;
3644 			}
3645 			break;
3646 		}
3647 
3648 		pstore = kalloc_type(struct pfsync_state,
3649 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
3650 #ifdef __LP64__
3651 		buf = (p64 ? ps64->ps_buf : ps32->ps_buf);
3652 #else
3653 		buf = ps32->ps_buf;
3654 #endif
3655 
3656 		state = TAILQ_FIRST(&state_list);
3657 		while (state) {
3658 			if (state->timeout != PFTM_UNLINKED) {
3659 				if ((nr + 1) * sizeof(*pstore) > (unsigned)len) {
3660 					break;
3661 				}
3662 
3663 				pf_state_export(pstore,
3664 				    state->state_key, state);
3665 				error = copyout(pstore, buf, sizeof(*pstore));
3666 				if (error) {
3667 					kfree_type(struct pfsync_state, pstore);
3668 					goto fail;
3669 				}
3670 				buf += sizeof(*pstore);
3671 				nr++;
3672 			}
3673 			state = TAILQ_NEXT(state, entry_list);
3674 		}
3675 
3676 		size = sizeof(struct pfsync_state) * nr;
3677 		if (p64) {
3678 			ps64->ps_len = size;
3679 		} else {
3680 			ps32->ps_len = size;
3681 		}
3682 
3683 		kfree_type(struct pfsync_state, pstore);
3684 		break;
3685 	}
3686 
3687 	default:
3688 		VERIFY(0);
3689 		/* NOTREACHED */
3690 	}
3691 fail:
3692 	return error;
3693 }
3694 
3695 static int
pfioctl_ioc_natlook(u_long cmd,struct pfioc_natlook * pnl,struct proc * p)3696 pfioctl_ioc_natlook(u_long cmd, struct pfioc_natlook *pnl, struct proc *p)
3697 {
3698 #pragma unused(p)
3699 	int error = 0;
3700 
3701 	switch (cmd) {
3702 	case DIOCNATLOOK: {
3703 		struct pf_state_key     *sk;
3704 		struct pf_state         *state;
3705 		struct pf_state_key_cmp  key;
3706 		int                      m = 0, direction = pnl->direction;
3707 
3708 		key.proto = pnl->proto;
3709 		key.proto_variant = pnl->proto_variant;
3710 
3711 		if (!pnl->proto ||
3712 		    PF_AZERO(&pnl->saddr, pnl->af) ||
3713 		    PF_AZERO(&pnl->daddr, pnl->af) ||
3714 		    ((pnl->proto == IPPROTO_TCP ||
3715 		    pnl->proto == IPPROTO_UDP) &&
3716 		    (!pnl->dxport.port || !pnl->sxport.port))) {
3717 			error = EINVAL;
3718 		} else {
3719 			/*
3720 			 * userland gives us source and dest of connection,
3721 			 * reverse the lookup so we ask for what happens with
3722 			 * the return traffic, enabling us to find it in the
3723 			 * state tree.
3724 			 */
3725 			if (direction == PF_IN) {
3726 				key.af_gwy = pnl->af;
3727 				PF_ACPY(&key.ext_gwy.addr, &pnl->daddr,
3728 				    pnl->af);
3729 				memcpy(&key.ext_gwy.xport, &pnl->dxport,
3730 				    sizeof(key.ext_gwy.xport));
3731 				PF_ACPY(&key.gwy.addr, &pnl->saddr, pnl->af);
3732 				memcpy(&key.gwy.xport, &pnl->sxport,
3733 				    sizeof(key.gwy.xport));
3734 				state = pf_find_state_all(&key, PF_IN, &m);
3735 			} else {
3736 				key.af_lan = pnl->af;
3737 				PF_ACPY(&key.lan.addr, &pnl->daddr, pnl->af);
3738 				memcpy(&key.lan.xport, &pnl->dxport,
3739 				    sizeof(key.lan.xport));
3740 				PF_ACPY(&key.ext_lan.addr, &pnl->saddr,
3741 				    pnl->af);
3742 				memcpy(&key.ext_lan.xport, &pnl->sxport,
3743 				    sizeof(key.ext_lan.xport));
3744 				state = pf_find_state_all(&key, PF_OUT, &m);
3745 			}
3746 			if (m > 1) {
3747 				error = E2BIG;  /* more than one state */
3748 			} else if (state != NULL) {
3749 				sk = state->state_key;
3750 				if (direction == PF_IN) {
3751 					PF_ACPY(&pnl->rsaddr, &sk->lan.addr,
3752 					    sk->af_lan);
3753 					memcpy(&pnl->rsxport, &sk->lan.xport,
3754 					    sizeof(pnl->rsxport));
3755 					PF_ACPY(&pnl->rdaddr, &pnl->daddr,
3756 					    pnl->af);
3757 					memcpy(&pnl->rdxport, &pnl->dxport,
3758 					    sizeof(pnl->rdxport));
3759 				} else {
3760 					PF_ACPY(&pnl->rdaddr, &sk->gwy.addr,
3761 					    sk->af_gwy);
3762 					memcpy(&pnl->rdxport, &sk->gwy.xport,
3763 					    sizeof(pnl->rdxport));
3764 					PF_ACPY(&pnl->rsaddr, &pnl->saddr,
3765 					    pnl->af);
3766 					memcpy(&pnl->rsxport, &pnl->sxport,
3767 					    sizeof(pnl->rsxport));
3768 				}
3769 			} else {
3770 				error = ENOENT;
3771 			}
3772 		}
3773 		break;
3774 	}
3775 
3776 	default:
3777 		VERIFY(0);
3778 		/* NOTREACHED */
3779 	}
3780 
3781 	return error;
3782 }
3783 
3784 static int
pfioctl_ioc_tm(u_long cmd,struct pfioc_tm * pt,struct proc * p)3785 pfioctl_ioc_tm(u_long cmd, struct pfioc_tm *pt, struct proc *p)
3786 {
3787 #pragma unused(p)
3788 	int error = 0;
3789 
3790 	switch (cmd) {
3791 	case DIOCSETTIMEOUT: {
3792 		int old;
3793 
3794 		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
3795 		    pt->seconds < 0) {
3796 			error = EINVAL;
3797 			goto fail;
3798 		}
3799 		old = pf_default_rule.timeout[pt->timeout];
3800 		if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0) {
3801 			pt->seconds = 1;
3802 		}
3803 		pf_default_rule.timeout[pt->timeout] = pt->seconds;
3804 		if (pt->timeout == PFTM_INTERVAL && pt->seconds < old) {
3805 			wakeup(pf_purge_thread_fn);
3806 		}
3807 		pt->seconds = old;
3808 		break;
3809 	}
3810 
3811 	case DIOCGETTIMEOUT: {
3812 		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
3813 			error = EINVAL;
3814 			goto fail;
3815 		}
3816 		pt->seconds = pf_default_rule.timeout[pt->timeout];
3817 		break;
3818 	}
3819 
3820 	default:
3821 		VERIFY(0);
3822 		/* NOTREACHED */
3823 	}
3824 fail:
3825 	return error;
3826 }
3827 
3828 static int
pfioctl_ioc_limit(u_long cmd,struct pfioc_limit * pl,struct proc * p)3829 pfioctl_ioc_limit(u_long cmd, struct pfioc_limit *pl, struct proc *p)
3830 {
3831 #pragma unused(p)
3832 	int error = 0;
3833 
3834 	switch (cmd) {
3835 	case DIOCGETLIMIT: {
3836 		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
3837 			error = EINVAL;
3838 			goto fail;
3839 		}
3840 		pl->limit = pf_pool_limits[pl->index].limit;
3841 		break;
3842 	}
3843 
3844 	case DIOCSETLIMIT: {
3845 		int old_limit;
3846 
3847 		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX ||
3848 		    pf_pool_limits[pl->index].pp == NULL) {
3849 			error = EINVAL;
3850 			goto fail;
3851 		}
3852 		pool_sethardlimit(pf_pool_limits[pl->index].pp,
3853 		    pl->limit, NULL, 0);
3854 		old_limit = pf_pool_limits[pl->index].limit;
3855 		pf_pool_limits[pl->index].limit = pl->limit;
3856 		pl->limit = old_limit;
3857 		break;
3858 	}
3859 
3860 	default:
3861 		VERIFY(0);
3862 		/* NOTREACHED */
3863 	}
3864 fail:
3865 	return error;
3866 }
3867 
3868 static int
pfioctl_ioc_pooladdr(u_long cmd,struct pfioc_pooladdr * pp,struct proc * p)3869 pfioctl_ioc_pooladdr(u_long cmd, struct pfioc_pooladdr *pp, struct proc *p)
3870 {
3871 #pragma unused(p)
3872 	struct pf_pooladdr *pa = NULL;
3873 	struct pf_pool *pool = NULL;
3874 	int error = 0;
3875 	struct pf_ruleset *ruleset = NULL;
3876 
3877 	switch (cmd) {
3878 	case DIOCBEGINADDRS: {
3879 		pf_empty_pool(&pf_pabuf);
3880 		pp->ticket = ++ticket_pabuf;
3881 		break;
3882 	}
3883 
3884 	case DIOCADDADDR: {
3885 		pp->anchor[sizeof(pp->anchor) - 1] = '\0';
3886 		if (pp->ticket != ticket_pabuf) {
3887 			error = EBUSY;
3888 			break;
3889 		}
3890 #if !INET
3891 		if (pp->af == AF_INET) {
3892 			error = EAFNOSUPPORT;
3893 			break;
3894 		}
3895 #endif /* INET */
3896 		if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
3897 		    pp->addr.addr.type != PF_ADDR_DYNIFTL &&
3898 		    pp->addr.addr.type != PF_ADDR_TABLE) {
3899 			error = EINVAL;
3900 			break;
3901 		}
3902 		pa = pool_get(&pf_pooladdr_pl, PR_WAITOK);
3903 		if (pa == NULL) {
3904 			error = ENOMEM;
3905 			break;
3906 		}
3907 		pf_pooladdr_copyin(&pp->addr, pa);
3908 		if (pa->ifname[0]) {
3909 			pa->kif = pfi_kif_get(pa->ifname);
3910 			if (pa->kif == NULL) {
3911 				pool_put(&pf_pooladdr_pl, pa);
3912 				error = EINVAL;
3913 				break;
3914 			}
3915 			pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE);
3916 		}
3917 		pf_addrwrap_setup(&pa->addr);
3918 		if (pfi_dynaddr_setup(&pa->addr, pp->af)) {
3919 			pfi_dynaddr_remove(&pa->addr);
3920 			pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE);
3921 			pool_put(&pf_pooladdr_pl, pa);
3922 			error = EINVAL;
3923 			break;
3924 		}
3925 		TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
3926 		break;
3927 	}
3928 
3929 	case DIOCGETADDRS: {
3930 		pp->nr = 0;
3931 		pp->anchor[sizeof(pp->anchor) - 1] = '\0';
3932 		pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
3933 		    pp->r_num, 0, 1, 0);
3934 		if (pool == NULL) {
3935 			error = EBUSY;
3936 			break;
3937 		}
3938 		TAILQ_FOREACH(pa, &pool->list, entries)
3939 		pp->nr++;
3940 		break;
3941 	}
3942 
3943 	case DIOCGETADDR: {
3944 		u_int32_t                nr = 0;
3945 
3946 		pp->anchor[sizeof(pp->anchor) - 1] = '\0';
3947 		pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
3948 		    pp->r_num, 0, 1, 1);
3949 		if (pool == NULL) {
3950 			error = EBUSY;
3951 			break;
3952 		}
3953 		pa = TAILQ_FIRST(&pool->list);
3954 		while ((pa != NULL) && (nr < pp->nr)) {
3955 			pa = TAILQ_NEXT(pa, entries);
3956 			nr++;
3957 		}
3958 		if (pa == NULL) {
3959 			error = EBUSY;
3960 			break;
3961 		}
3962 		pf_pooladdr_copyout(pa, &pp->addr);
3963 		pfi_dynaddr_copyout(&pp->addr.addr);
3964 		pf_tbladdr_copyout(&pp->addr.addr);
3965 		pf_rtlabel_copyout(&pp->addr.addr);
3966 		break;
3967 	}
3968 
3969 	case DIOCCHANGEADDR: {
3970 		struct pfioc_pooladdr   *pca = pp;
3971 		struct pf_pooladdr      *oldpa = NULL, *newpa = NULL;
3972 
3973 		if (pca->action < PF_CHANGE_ADD_HEAD ||
3974 		    pca->action > PF_CHANGE_REMOVE) {
3975 			error = EINVAL;
3976 			break;
3977 		}
3978 		if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
3979 		    pca->addr.addr.type != PF_ADDR_DYNIFTL &&
3980 		    pca->addr.addr.type != PF_ADDR_TABLE) {
3981 			error = EINVAL;
3982 			break;
3983 		}
3984 
3985 		pca->anchor[sizeof(pca->anchor) - 1] = '\0';
3986 		ruleset = pf_find_ruleset(pca->anchor);
3987 		if (ruleset == NULL) {
3988 			error = EBUSY;
3989 			break;
3990 		}
3991 		pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action,
3992 		    pca->r_num, pca->r_last, 1, 1);
3993 		if (pool == NULL) {
3994 			error = EBUSY;
3995 			break;
3996 		}
3997 		if (pca->action != PF_CHANGE_REMOVE) {
3998 			newpa = pool_get(&pf_pooladdr_pl, PR_WAITOK);
3999 			if (newpa == NULL) {
4000 				error = ENOMEM;
4001 				break;
4002 			}
4003 			pf_pooladdr_copyin(&pca->addr, newpa);
4004 #if !INET
4005 			if (pca->af == AF_INET) {
4006 				pool_put(&pf_pooladdr_pl, newpa);
4007 				error = EAFNOSUPPORT;
4008 				break;
4009 			}
4010 #endif /* INET */
4011 			if (newpa->ifname[0]) {
4012 				newpa->kif = pfi_kif_get(newpa->ifname);
4013 				if (newpa->kif == NULL) {
4014 					pool_put(&pf_pooladdr_pl, newpa);
4015 					error = EINVAL;
4016 					break;
4017 				}
4018 				pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE);
4019 			} else {
4020 				newpa->kif = NULL;
4021 			}
4022 			pf_addrwrap_setup(&newpa->addr);
4023 			if (pfi_dynaddr_setup(&newpa->addr, pca->af) ||
4024 			    pf_tbladdr_setup(ruleset, &newpa->addr)) {
4025 				pfi_dynaddr_remove(&newpa->addr);
4026 				pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE);
4027 				pool_put(&pf_pooladdr_pl, newpa);
4028 				error = EINVAL;
4029 				break;
4030 			}
4031 		}
4032 
4033 		if (pca->action == PF_CHANGE_ADD_HEAD) {
4034 			oldpa = TAILQ_FIRST(&pool->list);
4035 		} else if (pca->action == PF_CHANGE_ADD_TAIL) {
4036 			oldpa = TAILQ_LAST(&pool->list, pf_palist);
4037 		} else {
4038 			int     i = 0;
4039 
4040 			oldpa = TAILQ_FIRST(&pool->list);
4041 			while ((oldpa != NULL) && (i < (int)pca->nr)) {
4042 				oldpa = TAILQ_NEXT(oldpa, entries);
4043 				i++;
4044 			}
4045 			if (oldpa == NULL) {
4046 				error = EINVAL;
4047 				break;
4048 			}
4049 		}
4050 
4051 		if (pca->action == PF_CHANGE_REMOVE) {
4052 			TAILQ_REMOVE(&pool->list, oldpa, entries);
4053 			pfi_dynaddr_remove(&oldpa->addr);
4054 			pf_tbladdr_remove(&oldpa->addr);
4055 			pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE);
4056 			pool_put(&pf_pooladdr_pl, oldpa);
4057 		} else {
4058 			if (oldpa == NULL) {
4059 				TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
4060 			} else if (pca->action == PF_CHANGE_ADD_HEAD ||
4061 			    pca->action == PF_CHANGE_ADD_BEFORE) {
4062 				TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
4063 			} else {
4064 				TAILQ_INSERT_AFTER(&pool->list, oldpa,
4065 				    newpa, entries);
4066 			}
4067 		}
4068 
4069 		pool->cur = TAILQ_FIRST(&pool->list);
4070 		PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
4071 		    pca->af);
4072 		break;
4073 	}
4074 
4075 	default:
4076 		VERIFY(0);
4077 		/* NOTREACHED */
4078 	}
4079 
4080 	if (ruleset) {
4081 		pf_release_ruleset(ruleset);
4082 		ruleset = NULL;
4083 	}
4084 
4085 	return error;
4086 }
4087 
4088 static int
pfioctl_ioc_ruleset(u_long cmd,struct pfioc_ruleset * pr,struct proc * p)4089 pfioctl_ioc_ruleset(u_long cmd, struct pfioc_ruleset *pr, struct proc *p)
4090 {
4091 #pragma unused(p)
4092 	int error = 0;
4093 	struct pf_ruleset *ruleset = NULL;
4094 
4095 	switch (cmd) {
4096 	case DIOCGETRULESETS: {
4097 		struct pf_anchor        *anchor;
4098 
4099 		pr->path[sizeof(pr->path) - 1] = '\0';
4100 		pr->name[sizeof(pr->name) - 1] = '\0';
4101 		if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
4102 			error = EINVAL;
4103 			break;
4104 		}
4105 		pr->nr = 0;
4106 		if (ruleset->anchor == NULL) {
4107 			/* XXX kludge for pf_main_ruleset */
4108 			RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
4109 			if (anchor->parent == NULL) {
4110 				pr->nr++;
4111 			}
4112 		} else {
4113 			RB_FOREACH(anchor, pf_anchor_node,
4114 			    &ruleset->anchor->children)
4115 			pr->nr++;
4116 		}
4117 		break;
4118 	}
4119 
4120 	case DIOCGETRULESET: {
4121 		struct pf_anchor        *anchor;
4122 		u_int32_t                nr = 0;
4123 
4124 		pr->path[sizeof(pr->path) - 1] = '\0';
4125 		if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
4126 			error = EINVAL;
4127 			break;
4128 		}
4129 		pr->name[0] = 0;
4130 		if (ruleset->anchor == NULL) {
4131 			/* XXX kludge for pf_main_ruleset */
4132 			RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
4133 			if (anchor->parent == NULL && nr++ == pr->nr) {
4134 				strlcpy(pr->name, anchor->name,
4135 				    sizeof(pr->name));
4136 				break;
4137 			}
4138 		} else {
4139 			RB_FOREACH(anchor, pf_anchor_node,
4140 			    &ruleset->anchor->children)
4141 			if (nr++ == pr->nr) {
4142 				strlcpy(pr->name, anchor->name,
4143 				    sizeof(pr->name));
4144 				break;
4145 			}
4146 		}
4147 		if (!pr->name[0]) {
4148 			error = EBUSY;
4149 		}
4150 		break;
4151 	}
4152 
4153 	default:
4154 		VERIFY(0);
4155 		/* NOTREACHED */
4156 	}
4157 
4158 	if (ruleset) {
4159 		pf_release_ruleset(ruleset);
4160 		ruleset = NULL;
4161 	}
4162 	return error;
4163 }
4164 
4165 static int
pfioctl_ioc_trans(u_long cmd,struct pfioc_trans_32 * io32,struct pfioc_trans_64 * io64,struct proc * p)4166 pfioctl_ioc_trans(u_long cmd, struct pfioc_trans_32 *io32,
4167     struct pfioc_trans_64 *io64, struct proc *p)
4168 {
4169 	int error = 0, esize, size;
4170 	user_addr_t buf;
4171 	struct pf_ruleset *rs = NULL;
4172 
4173 #ifdef __LP64__
4174 	int p64 = proc_is64bit(p);
4175 
4176 	esize = (p64 ? io64->esize : io32->esize);
4177 	size = (p64 ? io64->size : io32->size);
4178 	buf = (p64 ? io64->array : io32->array);
4179 #else
4180 #pragma unused(io64, p)
4181 	esize = io32->esize;
4182 	size = io32->size;
4183 	buf = io32->array;
4184 #endif
4185 
4186 	switch (cmd) {
4187 	case DIOCXBEGIN: {
4188 		struct pfioc_trans_e    *ioe;
4189 		struct pfr_table        *table;
4190 		int                      i;
4191 
4192 		if (esize != sizeof(*ioe)) {
4193 			error = ENODEV;
4194 			goto fail;
4195 		}
4196 		ioe = kalloc_type(struct pfioc_trans_e, Z_WAITOK);
4197 		table = kalloc_type(struct pfr_table, Z_WAITOK);
4198 		for (i = 0; i < size; i++, buf += sizeof(*ioe)) {
4199 			if (copyin(buf, ioe, sizeof(*ioe))) {
4200 				kfree_type(struct pfr_table, table);
4201 				kfree_type(struct pfioc_trans_e, ioe);
4202 				error = EFAULT;
4203 				goto fail;
4204 			}
4205 			ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
4206 			switch (ioe->rs_num) {
4207 			case PF_RULESET_ALTQ:
4208 				break;
4209 			case PF_RULESET_TABLE:
4210 				bzero(table, sizeof(*table));
4211 				strlcpy(table->pfrt_anchor, ioe->anchor,
4212 				    sizeof(table->pfrt_anchor));
4213 				if ((error = pfr_ina_begin(table,
4214 				    &ioe->ticket, NULL, 0))) {
4215 					kfree_type(struct pfr_table, table);
4216 					kfree_type(struct pfioc_trans_e, ioe);
4217 					goto fail;
4218 				}
4219 				break;
4220 			default:
4221 				if ((error = pf_begin_rules(&ioe->ticket,
4222 				    ioe->rs_num, ioe->anchor))) {
4223 					kfree_type(struct pfr_table, table);
4224 					kfree_type(struct pfioc_trans_e, ioe);
4225 					goto fail;
4226 				}
4227 				break;
4228 			}
4229 			if (copyout(ioe, buf, sizeof(*ioe))) {
4230 				kfree_type(struct pfr_table, table);
4231 				kfree_type(struct pfioc_trans_e, ioe);
4232 				error = EFAULT;
4233 				goto fail;
4234 			}
4235 		}
4236 		kfree_type(struct pfr_table, table);
4237 		kfree_type(struct pfioc_trans_e, ioe);
4238 		break;
4239 	}
4240 
4241 	case DIOCXROLLBACK: {
4242 		struct pfioc_trans_e    *ioe;
4243 		struct pfr_table        *table;
4244 		int                      i;
4245 
4246 		if (esize != sizeof(*ioe)) {
4247 			error = ENODEV;
4248 			goto fail;
4249 		}
4250 		ioe = kalloc_type(struct pfioc_trans_e, Z_WAITOK);
4251 		table = kalloc_type(struct pfr_table, Z_WAITOK);
4252 		for (i = 0; i < size; i++, buf += sizeof(*ioe)) {
4253 			if (copyin(buf, ioe, sizeof(*ioe))) {
4254 				kfree_type(struct pfr_table, table);
4255 				kfree_type(struct pfioc_trans_e, ioe);
4256 				error = EFAULT;
4257 				goto fail;
4258 			}
4259 			ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
4260 			switch (ioe->rs_num) {
4261 			case PF_RULESET_ALTQ:
4262 				break;
4263 			case PF_RULESET_TABLE:
4264 				bzero(table, sizeof(*table));
4265 				strlcpy(table->pfrt_anchor, ioe->anchor,
4266 				    sizeof(table->pfrt_anchor));
4267 				if ((error = pfr_ina_rollback(table,
4268 				    ioe->ticket, NULL, 0))) {
4269 					kfree_type(struct pfr_table, table);
4270 					kfree_type(struct pfioc_trans_e, ioe);
4271 					goto fail; /* really bad */
4272 				}
4273 				break;
4274 			default:
4275 				if ((error = pf_rollback_rules(ioe->ticket,
4276 				    ioe->rs_num, ioe->anchor))) {
4277 					kfree_type(struct pfr_table, table);
4278 					kfree_type(struct pfioc_trans_e, ioe);
4279 					goto fail; /* really bad */
4280 				}
4281 				break;
4282 			}
4283 		}
4284 		kfree_type(struct pfr_table, table);
4285 		kfree_type(struct pfioc_trans_e, ioe);
4286 		break;
4287 	}
4288 
4289 	case DIOCXCOMMIT: {
4290 		struct pfioc_trans_e    *ioe;
4291 		struct pfr_table        *table;
4292 		user_addr_t              _buf = buf;
4293 		int                      i;
4294 
4295 		if (esize != sizeof(*ioe)) {
4296 			error = ENODEV;
4297 			goto fail;
4298 		}
4299 		ioe = kalloc_type(struct pfioc_trans_e, Z_WAITOK);
4300 		table = kalloc_type(struct pfr_table, Z_WAITOK);
4301 		/* first makes sure everything will succeed */
4302 		for (i = 0; i < size; i++, buf += sizeof(*ioe)) {
4303 			if (copyin(buf, ioe, sizeof(*ioe))) {
4304 				kfree_type(struct pfr_table, table);
4305 				kfree_type(struct pfioc_trans_e, ioe);
4306 				error = EFAULT;
4307 				goto fail;
4308 			}
4309 			ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
4310 			switch (ioe->rs_num) {
4311 			case PF_RULESET_ALTQ:
4312 				break;
4313 			case PF_RULESET_TABLE:
4314 				rs = pf_find_ruleset(ioe->anchor);
4315 				if (rs == NULL || !rs->topen || ioe->ticket !=
4316 				    rs->tticket) {
4317 					kfree_type(struct pfr_table, table);
4318 					kfree_type(struct pfioc_trans_e, ioe);
4319 					error = EBUSY;
4320 					goto fail;
4321 				}
4322 				break;
4323 			default:
4324 				if (ioe->rs_num < 0 || ioe->rs_num >=
4325 				    PF_RULESET_MAX) {
4326 					kfree_type(struct pfr_table, table);
4327 					kfree_type(struct pfioc_trans_e, ioe);
4328 					error = EINVAL;
4329 					goto fail;
4330 				}
4331 				rs = pf_find_ruleset(ioe->anchor);
4332 				if (rs == NULL ||
4333 				    !rs->rules[ioe->rs_num].inactive.open ||
4334 				    rs->rules[ioe->rs_num].inactive.ticket !=
4335 				    ioe->ticket) {
4336 					kfree_type(struct pfr_table, table);
4337 					kfree_type(struct pfioc_trans_e, ioe);
4338 					error = EBUSY;
4339 					goto fail;
4340 				}
4341 				break;
4342 			}
4343 		}
4344 		buf = _buf;
4345 		/* now do the commit - no errors should happen here */
4346 		for (i = 0; i < size; i++, buf += sizeof(*ioe)) {
4347 			if (copyin(buf, ioe, sizeof(*ioe))) {
4348 				kfree_type(struct pfr_table, table);
4349 				kfree_type(struct pfioc_trans_e, ioe);
4350 				error = EFAULT;
4351 				goto fail;
4352 			}
4353 			ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
4354 			switch (ioe->rs_num) {
4355 			case PF_RULESET_ALTQ:
4356 				break;
4357 			case PF_RULESET_TABLE:
4358 				bzero(table, sizeof(*table));
4359 				strlcpy(table->pfrt_anchor, ioe->anchor,
4360 				    sizeof(table->pfrt_anchor));
4361 				if ((error = pfr_ina_commit(table, ioe->ticket,
4362 				    NULL, NULL, 0))) {
4363 					kfree_type(struct pfr_table, table);
4364 					kfree_type(struct pfioc_trans_e, ioe);
4365 					goto fail;
4366 				}
4367 				break;
4368 			default:
4369 				if ((error = pf_commit_rules(ioe->ticket,
4370 				    ioe->rs_num, ioe->anchor))) {
4371 					kfree_type(struct pfr_table, table);
4372 					kfree_type(struct pfioc_trans_e, ioe);
4373 					goto fail;
4374 				}
4375 				break;
4376 			}
4377 		}
4378 		kfree_type(struct pfr_table, table);
4379 		kfree_type(struct pfioc_trans_e, ioe);
4380 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
4381 		pf_process_compatibilities();
4382 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
4383 		break;
4384 	}
4385 
4386 	default:
4387 		VERIFY(0);
4388 		/* NOTREACHED */
4389 	}
4390 fail:
4391 	if (rs) {
4392 		pf_release_ruleset(rs);
4393 		rs = NULL;
4394 	}
4395 	return error;
4396 }
4397 
4398 static int
pfioctl_ioc_src_nodes(u_long cmd,struct pfioc_src_nodes_32 * psn32,struct pfioc_src_nodes_64 * psn64,struct proc * p)4399 pfioctl_ioc_src_nodes(u_long cmd, struct pfioc_src_nodes_32 *psn32,
4400     struct pfioc_src_nodes_64 *psn64, struct proc *p)
4401 {
4402 	int p64 = proc_is64bit(p);
4403 	int error = 0;
4404 
4405 	switch (cmd) {
4406 	case DIOCGETSRCNODES: {
4407 		struct pf_src_node      *n, *pstore;
4408 		user_addr_t              buf;
4409 		u_int32_t                nr = 0;
4410 		int                      space, size;
4411 
4412 		space = (p64 ? psn64->psn_len : psn32->psn_len);
4413 		if (space == 0) {
4414 			RB_FOREACH(n, pf_src_tree, &tree_src_tracking)
4415 			nr++;
4416 
4417 			size = sizeof(struct pf_src_node) * nr;
4418 			if (p64) {
4419 				psn64->psn_len = size;
4420 			} else {
4421 				psn32->psn_len = size;
4422 			}
4423 			break;
4424 		}
4425 
4426 		pstore = kalloc_type(struct pf_src_node, Z_WAITOK | Z_NOFAIL);
4427 #ifdef __LP64__
4428 		buf = (p64 ? psn64->psn_buf : psn32->psn_buf);
4429 #else
4430 		buf = psn32->psn_buf;
4431 #endif
4432 
4433 		RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
4434 			uint64_t secs = pf_time_second(), diff;
4435 
4436 			if ((nr + 1) * sizeof(*pstore) > (unsigned)space) {
4437 				break;
4438 			}
4439 
4440 			bcopy(n, pstore, sizeof(*pstore));
4441 			if (n->rule.ptr != NULL) {
4442 				pstore->rule.nr = n->rule.ptr->nr;
4443 			}
4444 			pstore->creation = secs - pstore->creation;
4445 			if (pstore->expire > secs) {
4446 				pstore->expire -= secs;
4447 			} else {
4448 				pstore->expire = 0;
4449 			}
4450 
4451 			/* adjust the connection rate estimate */
4452 			diff = secs - n->conn_rate.last;
4453 			if (diff >= n->conn_rate.seconds) {
4454 				pstore->conn_rate.count = 0;
4455 			} else {
4456 				pstore->conn_rate.count -=
4457 				    n->conn_rate.count * diff /
4458 				    n->conn_rate.seconds;
4459 			}
4460 
4461 			_RB_PARENT(pstore, entry) = NULL;
4462 			RB_LEFT(pstore, entry) = RB_RIGHT(pstore, entry) = NULL;
4463 			pstore->kif = NULL;
4464 
4465 			error = copyout(pstore, buf, sizeof(*pstore));
4466 			if (error) {
4467 				kfree_type(struct pf_src_node, pstore);
4468 				goto fail;
4469 			}
4470 			buf += sizeof(*pstore);
4471 			nr++;
4472 		}
4473 
4474 		size = sizeof(struct pf_src_node) * nr;
4475 		if (p64) {
4476 			psn64->psn_len = size;
4477 		} else {
4478 			psn32->psn_len = size;
4479 		}
4480 
4481 		kfree_type(struct pf_src_node, pstore);
4482 		break;
4483 	}
4484 
4485 	default:
4486 		VERIFY(0);
4487 		/* NOTREACHED */
4488 	}
4489 fail:
4490 	return error;
4491 }
4492 
4493 static int
pfioctl_ioc_src_node_kill(u_long cmd,struct pfioc_src_node_kill * psnk,struct proc * p)4494 pfioctl_ioc_src_node_kill(u_long cmd, struct pfioc_src_node_kill *psnk,
4495     struct proc *p)
4496 {
4497 #pragma unused(p)
4498 	int error = 0;
4499 
4500 	switch (cmd) {
4501 	case DIOCKILLSRCNODES: {
4502 		struct pf_src_node      *sn;
4503 		struct pf_state         *s;
4504 		int                     killed = 0;
4505 
4506 		RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) {
4507 			if (PF_MATCHA(psnk->psnk_src.neg,
4508 			    &psnk->psnk_src.addr.v.a.addr,
4509 			    &psnk->psnk_src.addr.v.a.mask,
4510 			    &sn->addr, sn->af) &&
4511 			    PF_MATCHA(psnk->psnk_dst.neg,
4512 			    &psnk->psnk_dst.addr.v.a.addr,
4513 			    &psnk->psnk_dst.addr.v.a.mask,
4514 			    &sn->raddr, sn->af)) {
4515 				/* Handle state to src_node linkage */
4516 				if (sn->states != 0) {
4517 					RB_FOREACH(s, pf_state_tree_id,
4518 					    &tree_id) {
4519 						if (s->src_node == sn) {
4520 							s->src_node = NULL;
4521 						}
4522 						if (s->nat_src_node == sn) {
4523 							s->nat_src_node = NULL;
4524 						}
4525 					}
4526 					sn->states = 0;
4527 				}
4528 				sn->expire = 1;
4529 				killed++;
4530 			}
4531 		}
4532 
4533 		if (killed > 0) {
4534 			pf_purge_expired_src_nodes();
4535 		}
4536 
4537 		psnk->psnk_af = (sa_family_t)killed;
4538 		break;
4539 	}
4540 
4541 	default:
4542 		VERIFY(0);
4543 		/* NOTREACHED */
4544 	}
4545 
4546 	return error;
4547 }
4548 
4549 static int
pfioctl_ioc_iface(u_long cmd,struct pfioc_iface_32 * io32,struct pfioc_iface_64 * io64,struct proc * p)4550 pfioctl_ioc_iface(u_long cmd, struct pfioc_iface_32 *io32,
4551     struct pfioc_iface_64 *io64, struct proc *p)
4552 {
4553 	int p64 = proc_is64bit(p);
4554 	int error = 0;
4555 
4556 	switch (cmd) {
4557 	case DIOCIGETIFACES: {
4558 		user_addr_t buf;
4559 		int esize;
4560 
4561 #ifdef __LP64__
4562 		buf = (p64 ? io64->pfiio_buffer : io32->pfiio_buffer);
4563 		esize = (p64 ? io64->pfiio_esize : io32->pfiio_esize);
4564 #else
4565 		buf = io32->pfiio_buffer;
4566 		esize = io32->pfiio_esize;
4567 #endif
4568 
4569 		/* esize must be that of the user space version of pfi_kif */
4570 		if (esize != sizeof(struct pfi_uif)) {
4571 			error = ENODEV;
4572 			break;
4573 		}
4574 		if (p64) {
4575 			io64->pfiio_name[sizeof(io64->pfiio_name) - 1] = '\0';
4576 		} else {
4577 			io32->pfiio_name[sizeof(io32->pfiio_name) - 1] = '\0';
4578 		}
4579 		error = pfi_get_ifaces(
4580 			p64 ? io64->pfiio_name : io32->pfiio_name, buf,
4581 			p64 ? &io64->pfiio_size : &io32->pfiio_size);
4582 		break;
4583 	}
4584 
4585 	case DIOCSETIFFLAG: {
4586 		if (p64) {
4587 			io64->pfiio_name[sizeof(io64->pfiio_name) - 1] = '\0';
4588 		} else {
4589 			io32->pfiio_name[sizeof(io32->pfiio_name) - 1] = '\0';
4590 		}
4591 
4592 		error = pfi_set_flags(
4593 			p64 ? io64->pfiio_name : io32->pfiio_name,
4594 			p64 ? io64->pfiio_flags : io32->pfiio_flags);
4595 		break;
4596 	}
4597 
4598 	case DIOCCLRIFFLAG: {
4599 		if (p64) {
4600 			io64->pfiio_name[sizeof(io64->pfiio_name) - 1] = '\0';
4601 		} else {
4602 			io32->pfiio_name[sizeof(io32->pfiio_name) - 1] = '\0';
4603 		}
4604 
4605 		error = pfi_clear_flags(
4606 			p64 ? io64->pfiio_name : io32->pfiio_name,
4607 			p64 ? io64->pfiio_flags : io32->pfiio_flags);
4608 		break;
4609 	}
4610 
4611 	default:
4612 		VERIFY(0);
4613 		/* NOTREACHED */
4614 	}
4615 
4616 	return error;
4617 }
4618 
4619 int
pf_af_hook(struct ifnet * ifp,struct mbuf ** mppn,struct mbuf ** mp,unsigned int af,int input,struct ip_fw_args * fwa)4620 pf_af_hook(struct ifnet *ifp, struct mbuf **mppn, struct mbuf **mp,
4621     unsigned int af, int input, struct ip_fw_args *fwa)
4622 {
4623 	int error = 0;
4624 	struct mbuf *nextpkt;
4625 	net_thread_marks_t marks;
4626 	struct ifnet * pf_ifp = ifp;
4627 
4628 	/* Always allow traffic on co-processor and management interfaces. */
4629 	if (ifp != NULL &&
4630 	    ((!intcoproc_unrestricted && IFNET_IS_INTCOPROC(ifp)) ||
4631 	    (!management_data_unrestricted && IFNET_IS_MANAGEMENT(ifp)))) {
4632 		return 0;
4633 	}
4634 
4635 	marks = net_thread_marks_push(NET_THREAD_HELD_PF);
4636 
4637 	if (marks != net_thread_marks_none) {
4638 		lck_rw_lock_shared(&pf_perim_lock);
4639 		if (!pf_is_enabled) {
4640 			goto done;
4641 		}
4642 		lck_mtx_lock(&pf_lock);
4643 	}
4644 
4645 	if (mppn != NULL && *mppn != NULL) {
4646 		VERIFY(*mppn == *mp);
4647 	}
4648 	if ((nextpkt = (*mp)->m_nextpkt) != NULL) {
4649 		(*mp)->m_nextpkt = NULL;
4650 	}
4651 
4652 	/*
4653 	 * For packets destined to locally hosted IP address
4654 	 * ip_output_list sets Mbuf's pkt header's rcvif to
4655 	 * the interface hosting the IP address.
4656 	 * While on the output path ifp passed to pf_af_hook
4657 	 * to such local communication is the loopback interface,
4658 	 * the input path derives ifp from mbuf packet header's
4659 	 * rcvif.
4660 	 * This asymmetry caues issues with PF.
4661 	 * To handle that case, we have a limited change here to
4662 	 * pass interface as loopback if packets are looped in.
4663 	 */
4664 	if (input && ((*mp)->m_pkthdr.pkt_flags & PKTF_LOOP)) {
4665 		pf_ifp = lo_ifp;
4666 	}
4667 
4668 	switch (af) {
4669 #if INET
4670 	case AF_INET: {
4671 		error = pf_inet_hook(pf_ifp, mp, input, fwa);
4672 		break;
4673 	}
4674 #endif /* INET */
4675 	case AF_INET6:
4676 		error = pf_inet6_hook(pf_ifp, mp, input, fwa);
4677 		break;
4678 	default:
4679 		break;
4680 	}
4681 
4682 	/* When packet valid, link to the next packet */
4683 	if (*mp != NULL && nextpkt != NULL) {
4684 		struct mbuf *m = *mp;
4685 		while (m->m_nextpkt != NULL) {
4686 			m = m->m_nextpkt;
4687 		}
4688 		m->m_nextpkt = nextpkt;
4689 	}
4690 	/* Fix up linkage of previous packet in the chain */
4691 	if (mppn != NULL) {
4692 		if (*mp != NULL) {
4693 			*mppn = *mp;
4694 		} else {
4695 			*mppn = nextpkt;
4696 		}
4697 	}
4698 
4699 	if (marks != net_thread_marks_none) {
4700 		lck_mtx_unlock(&pf_lock);
4701 	}
4702 
4703 done:
4704 	if (marks != net_thread_marks_none) {
4705 		lck_rw_done(&pf_perim_lock);
4706 	}
4707 
4708 	net_thread_marks_pop(marks);
4709 	return error;
4710 }
4711 
4712 
4713 #if INET
4714 static __attribute__((noinline)) int
pf_inet_hook(struct ifnet * ifp,struct mbuf ** mp,int input,struct ip_fw_args * fwa)4715 pf_inet_hook(struct ifnet *ifp, struct mbuf **mp, int input,
4716     struct ip_fw_args *fwa)
4717 {
4718 	struct mbuf *m = *mp;
4719 #if BYTE_ORDER != BIG_ENDIAN
4720 	struct ip *ip = mtod(m, struct ip *);
4721 #endif
4722 	int error = 0;
4723 
4724 	/*
4725 	 * If the packet is outbound, is originated locally, is flagged for
4726 	 * delayed UDP/TCP checksum calculation, and is about to be processed
4727 	 * for an interface that doesn't support the appropriate checksum
4728 	 * offloading, then calculated the checksum here so that PF can adjust
4729 	 * it properly.
4730 	 */
4731 	if (!input && m->m_pkthdr.rcvif == NULL) {
4732 		static const int mask = CSUM_DELAY_DATA;
4733 		const int flags = m->m_pkthdr.csum_flags &
4734 		    ~IF_HWASSIST_CSUM_FLAGS(ifp->if_hwassist);
4735 
4736 		if (flags & mask) {
4737 			in_delayed_cksum(m);
4738 			m->m_pkthdr.csum_flags &= ~mask;
4739 		}
4740 	}
4741 
4742 #if BYTE_ORDER != BIG_ENDIAN
4743 	HTONS(ip->ip_len);
4744 	HTONS(ip->ip_off);
4745 #endif
4746 	if (pf_test_mbuf(input ? PF_IN : PF_OUT, ifp, mp, NULL, fwa) != PF_PASS) {
4747 		if (*mp != NULL) {
4748 			m_freem(*mp);
4749 			*mp = NULL;
4750 			error = EHOSTUNREACH;
4751 		} else {
4752 			error = EJUSTRETURN;
4753 		}
4754 	}
4755 #if BYTE_ORDER != BIG_ENDIAN
4756 	else {
4757 		if (*mp != NULL) {
4758 			ip = mtod(*mp, struct ip *);
4759 			NTOHS(ip->ip_len);
4760 			NTOHS(ip->ip_off);
4761 		}
4762 	}
4763 #endif
4764 	return error;
4765 }
4766 #endif /* INET */
4767 
4768 int __attribute__((noinline))
pf_inet6_hook(struct ifnet * ifp,struct mbuf ** mp,int input,struct ip_fw_args * fwa)4769 pf_inet6_hook(struct ifnet *ifp, struct mbuf **mp, int input,
4770     struct ip_fw_args *fwa)
4771 {
4772 	int error = 0;
4773 
4774 	/*
4775 	 * If the packet is outbound, is originated locally, is flagged for
4776 	 * delayed UDP/TCP checksum calculation, and is about to be processed
4777 	 * for an interface that doesn't support the appropriate checksum
4778 	 * offloading, then calculated the checksum here so that PF can adjust
4779 	 * it properly.
4780 	 */
4781 	if (!input && (*mp)->m_pkthdr.rcvif == NULL) {
4782 		static const int mask = CSUM_DELAY_IPV6_DATA;
4783 		const int flags = (*mp)->m_pkthdr.csum_flags &
4784 		    ~IF_HWASSIST_CSUM_FLAGS(ifp->if_hwassist);
4785 
4786 		if (flags & mask) {
4787 			/*
4788 			 * Checksum offload should not have been enabled
4789 			 * when extension headers exist, thus 0 for optlen.
4790 			 */
4791 			in6_delayed_cksum(*mp);
4792 			(*mp)->m_pkthdr.csum_flags &= ~mask;
4793 		}
4794 	}
4795 
4796 	if (pf_test6_mbuf(input ? PF_IN : PF_OUT, ifp, mp, NULL, fwa) != PF_PASS) {
4797 		if (*mp != NULL) {
4798 			m_freem(*mp);
4799 			*mp = NULL;
4800 			error = EHOSTUNREACH;
4801 		} else {
4802 			error = EJUSTRETURN;
4803 		}
4804 	}
4805 	return error;
4806 }
4807 
4808 int
pf_ifaddr_hook(struct ifnet * ifp)4809 pf_ifaddr_hook(struct ifnet *ifp)
4810 {
4811 	struct pfi_kif *kif = ifp->if_pf_kif;
4812 
4813 	if (kif != NULL) {
4814 		lck_rw_lock_shared(&pf_perim_lock);
4815 		lck_mtx_lock(&pf_lock);
4816 
4817 		pfi_kifaddr_update(kif);
4818 
4819 		lck_mtx_unlock(&pf_lock);
4820 		lck_rw_done(&pf_perim_lock);
4821 	}
4822 	return 0;
4823 }
4824 
4825 /*
4826  * Caller acquires dlil lock as writer (exclusive)
4827  */
4828 void
pf_ifnet_hook(struct ifnet * ifp,int attach)4829 pf_ifnet_hook(struct ifnet *ifp, int attach)
4830 {
4831 	lck_rw_lock_shared(&pf_perim_lock);
4832 	lck_mtx_lock(&pf_lock);
4833 	if (attach) {
4834 		pfi_attach_ifnet(ifp);
4835 	} else {
4836 		pfi_detach_ifnet(ifp);
4837 	}
4838 	lck_mtx_unlock(&pf_lock);
4839 	lck_rw_done(&pf_perim_lock);
4840 }
4841 
4842 static void
pf_attach_hooks(void)4843 pf_attach_hooks(void)
4844 {
4845 	ifnet_head_lock_shared();
4846 	/*
4847 	 * Check against ifnet_addrs[] before proceeding, in case this
4848 	 * is called very early on, e.g. during dlil_init() before any
4849 	 * network interface is attached.
4850 	 */
4851 	if (ifnet_addrs != NULL) {
4852 		int i;
4853 
4854 		for (i = 0; i <= if_index; i++) {
4855 			struct ifnet *ifp = ifindex2ifnet[i];
4856 			if (ifp != NULL) {
4857 				pfi_attach_ifnet(ifp);
4858 			}
4859 		}
4860 	}
4861 	ifnet_head_done();
4862 }
4863 
4864 #if 0
4865 /* currently unused along with pfdetach() */
4866 static void
4867 pf_detach_hooks(void)
4868 {
4869 	ifnet_head_lock_shared();
4870 	if (ifnet_addrs != NULL) {
4871 		for (i = 0; i <= if_index; i++) {
4872 			int i;
4873 
4874 			struct ifnet *ifp = ifindex2ifnet[i];
4875 			if (ifp != NULL && ifp->if_pf_kif != NULL) {
4876 				pfi_detach_ifnet(ifp);
4877 			}
4878 		}
4879 	}
4880 	ifnet_head_done();
4881 }
4882 #endif
4883 
4884 /*
4885  * 'D' group ioctls.
4886  *
4887  * The switch statement below does nothing at runtime, as it serves as a
4888  * compile time check to ensure that all of the socket 'D' ioctls (those
4889  * in the 'D' group going thru soo_ioctl) that are made available by the
4890  * networking stack is unique.  This works as long as this routine gets
4891  * updated each time a new interface ioctl gets added.
4892  *
4893  * Any failures at compile time indicates duplicated ioctl values.
4894  */
4895 static __attribute__((unused)) void
pfioctl_cassert(void)4896 pfioctl_cassert(void)
4897 {
4898 	/*
4899 	 * This is equivalent to _CASSERT() and the compiler wouldn't
4900 	 * generate any instructions, thus for compile time only.
4901 	 */
4902 	switch ((u_long)0) {
4903 	case 0:
4904 
4905 	/* bsd/net/pfvar.h */
4906 	case DIOCSTART:
4907 	case DIOCSTOP:
4908 	case DIOCADDRULE:
4909 	case DIOCGETSTARTERS:
4910 	case DIOCGETRULES:
4911 	case DIOCGETRULE:
4912 	case DIOCSTARTREF:
4913 	case DIOCSTOPREF:
4914 	case DIOCCLRSTATES:
4915 	case DIOCGETSTATE:
4916 	case DIOCSETSTATUSIF:
4917 	case DIOCGETSTATUS:
4918 	case DIOCCLRSTATUS:
4919 	case DIOCNATLOOK:
4920 	case DIOCSETDEBUG:
4921 	case DIOCGETSTATES:
4922 	case DIOCCHANGERULE:
4923 	case DIOCINSERTRULE:
4924 	case DIOCDELETERULE:
4925 	case DIOCSETTIMEOUT:
4926 	case DIOCGETTIMEOUT:
4927 	case DIOCADDSTATE:
4928 	case DIOCCLRRULECTRS:
4929 	case DIOCGETLIMIT:
4930 	case DIOCSETLIMIT:
4931 	case DIOCKILLSTATES:
4932 	case DIOCSTARTALTQ:
4933 	case DIOCSTOPALTQ:
4934 	case DIOCADDALTQ:
4935 	case DIOCGETALTQS:
4936 	case DIOCGETALTQ:
4937 	case DIOCCHANGEALTQ:
4938 	case DIOCGETQSTATS:
4939 	case DIOCBEGINADDRS:
4940 	case DIOCADDADDR:
4941 	case DIOCGETADDRS:
4942 	case DIOCGETADDR:
4943 	case DIOCCHANGEADDR:
4944 	case DIOCGETRULESETS:
4945 	case DIOCGETRULESET:
4946 	case DIOCRCLRTABLES:
4947 	case DIOCRADDTABLES:
4948 	case DIOCRDELTABLES:
4949 	case DIOCRGETTABLES:
4950 	case DIOCRGETTSTATS:
4951 	case DIOCRCLRTSTATS:
4952 	case DIOCRCLRADDRS:
4953 	case DIOCRADDADDRS:
4954 	case DIOCRDELADDRS:
4955 	case DIOCRSETADDRS:
4956 	case DIOCRGETADDRS:
4957 	case DIOCRGETASTATS:
4958 	case DIOCRCLRASTATS:
4959 	case DIOCRTSTADDRS:
4960 	case DIOCRSETTFLAGS:
4961 	case DIOCRINADEFINE:
4962 	case DIOCOSFPFLUSH:
4963 	case DIOCOSFPADD:
4964 	case DIOCOSFPGET:
4965 	case DIOCXBEGIN:
4966 	case DIOCXCOMMIT:
4967 	case DIOCXROLLBACK:
4968 	case DIOCGETSRCNODES:
4969 	case DIOCCLRSRCNODES:
4970 	case DIOCSETHOSTID:
4971 	case DIOCIGETIFACES:
4972 	case DIOCSETIFFLAG:
4973 	case DIOCCLRIFFLAG:
4974 	case DIOCKILLSRCNODES:
4975 	case DIOCGIFSPEED:
4976 		;
4977 	}
4978 }
4979 
4980 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
4981 static void
pf_process_compatibilities(void)4982 pf_process_compatibilities(void)
4983 {
4984 	uint32_t compat_bitmap = pf_check_compatible_rules();
4985 
4986 	net_filter_event_mark(NET_FILTER_EVENT_PF,
4987 	    (compat_bitmap &
4988 	    (PF_COMPATIBLE_FLAGS_CUSTOM_ANCHORS_PRESENT |
4989 	    PF_COMPATIBLE_FLAGS_CUSTOM_RULES_PRESENT)) == 0);
4990 
4991 	net_filter_event_mark(NET_FILTER_EVENT_PF_PRIVATE_PROXY,
4992 	    ((compat_bitmap & PF_COMPATIBLE_FLAGS_PF_ENABLED) == 0) ||
4993 	    (compat_bitmap & PF_COMPATIBLE_FLAGS_CUSTOM_RULES_PRESENT) == 0);
4994 }
4995 #endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
4996