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
107struct 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
132static void pfdetach(void);
133#endif
134static int pfopen(dev_t, int, int, struct proc *);
135static int pfclose(dev_t, int, int, struct proc *);
136static int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
137static int pfioctl_ioc_table(u_long, struct pfioc_table_32 *,
138 struct pfioc_table_64 *, struct proc *);
139static int pfioctl_ioc_tokens(u_long, struct pfioc_tokens_32 *,
140 struct pfioc_tokens_64 *, struct proc *);
141static int pfioctl_ioc_rule(u_long, int, struct pfioc_rule *, struct proc *);
142static int pfioctl_ioc_state_kill(u_long, struct pfioc_state_kill *,
143 struct proc *);
144static int pfioctl_ioc_state(u_long, struct pfioc_state *, struct proc *);
145static int pfioctl_ioc_states(u_long, struct pfioc_states_32 *,
146 struct pfioc_states_64 *, struct proc *);
147static int pfioctl_ioc_natlook(u_long, struct pfioc_natlook *, struct proc *);
148static int pfioctl_ioc_tm(u_long, struct pfioc_tm *, struct proc *);
149static int pfioctl_ioc_limit(u_long, struct pfioc_limit *, struct proc *);
150static int pfioctl_ioc_pooladdr(u_long, struct pfioc_pooladdr *, struct proc *);
151static int pfioctl_ioc_ruleset(u_long, struct pfioc_ruleset *, struct proc *);
152static int pfioctl_ioc_trans(u_long, struct pfioc_trans_32 *,
153 struct pfioc_trans_64 *, struct proc *);
154static int pfioctl_ioc_src_nodes(u_long, struct pfioc_src_nodes_32 *,
155 struct pfioc_src_nodes_64 *, struct proc *);
156static int pfioctl_ioc_src_node_kill(u_long, struct pfioc_src_node_kill *,
157 struct proc *);
158static int pfioctl_ioc_iface(u_long, struct pfioc_iface_32 *,
159 struct pfioc_iface_64 *, struct proc *);
160static 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);
162static void pf_mv_pool(struct pf_palist *, struct pf_palist *);
163static void pf_empty_pool(struct pf_palist *);
164static int pf_begin_rules(u_int32_t *, int, const char *);
165static int pf_rollback_rules(u_int32_t, int, char *);
166static int pf_setup_pfsync_matching(struct pf_ruleset *);
167static void pf_hash_rule(MD5_CTX *, struct pf_rule *);
168static void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *, u_int8_t);
169static int pf_commit_rules(u_int32_t, int, char *);
170static void pf_rule_copyin(struct pf_rule *, struct pf_rule *, struct proc *,
171 int);
172static void pf_rule_copyout(struct pf_rule *, struct pf_rule *);
173static void pf_state_export(struct pfsync_state *, struct pf_state_key *,
174 struct pf_state *);
175static void pf_state_import(struct pfsync_state *, struct pf_state_key *,
176 struct pf_state *);
177static void pf_pooladdr_copyin(struct pf_pooladdr *, struct pf_pooladdr *);
178static void pf_pooladdr_copyout(struct pf_pooladdr *, struct pf_pooladdr *);
179static void pf_expire_states_and_src_nodes(struct pf_rule *);
180static void pf_delete_rule_from_ruleset(struct pf_ruleset *,
181 int, struct pf_rule *);
182static void pf_addrwrap_setup(struct pf_addr_wrap *);
183static int pf_rule_setup(struct pfioc_rule *, struct pf_rule *,
184 struct pf_ruleset *);
185static void pf_delete_rule_by_owner(char *, u_int32_t);
186static int pf_delete_rule_by_ticket(struct pfioc_rule *, u_int32_t);
187static void pf_ruleset_cleanup(struct pf_ruleset *, int);
188static void pf_deleterule_anchor_step_out(struct pf_ruleset **,
189 int, struct pf_rule **);
190#if SKYWALK && defined(XNU_TARGET_OS_OSX)
191static void pf_process_compatibilities(void);
192#endif // SKYWALK && defined(XNU_TARGET_OS_OSX)
193
194#define PF_CDEV_MAJOR (-1)
195
196static 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
213static void pf_attach_hooks(void);
214#if 0
215/* currently unused along with pfdetach() */
216static 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 */
224int pf_is_enabled = 0;
225
226u_int32_t pf_hash_seed;
227int16_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
234static u_int64_t pf_enabled_ref_count;
235static u_int32_t nr_tokens = 0;
236static u_int32_t pffwrules;
237static u_int32_t pfdevcnt;
238
239SLIST_HEAD(list_head, pfioc_kernel_token);
240static struct list_head token_list_head;
241
242struct pf_rule pf_default_rule;
243
244typedef 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
250static 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
257static 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
263static u_int16_t tagname2tag(struct pf_tags *, char *);
264static void tag_unref(struct pf_tags *, u_int16_t);
265static int pf_rtlabel_add(struct pf_addr_wrap *);
266static void pf_rtlabel_remove(struct pf_addr_wrap *);
267static void pf_rtlabel_copyout(struct pf_addr_wrap *);
268
269#if INET
270static int pf_inet_hook(struct ifnet *, struct mbuf **, int,
271 struct ip_fw_args *);
272#endif /* INET */
273static 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) \
282struct { \
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
330struct thread *pf_purge_thread;
331
332extern void pfi_kifaddr_update(void *);
333
334/* pf enable ref-counting helper functions */
335static u_int64_t generate_token(struct proc *);
336static int remove_token(struct pfioc_remove_token *);
337static void invalidate_all_tokens(void);
338
339static u_int64_t
340generate_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(pid: new_token->token.pid, buf: new_token->token.proc_name,
360 size: 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
369static int
370remove_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
390static void
391invalidate_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
405struct pf_reass_tag_container {
406 struct m_tag pf_reass_m_tag;
407 struct pf_fragment_tag pf_reass_fragment_tag;
408};
409
410static struct m_tag *
411m_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
436static void
437m_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
446void
447pf_register_m_tag(void)
448{
449 int error;
450
451 error = m_register_internal_tag_type(type: KERNEL_TAG_TYPE_PF_REASS, len: sizeof(struct pf_fragment_tag),
452 alloc_func: m_tag_kalloc_pf_reass, free_func: m_tag_kfree_pf_reass);
453
454 assert3u(error, ==, 0);
455}
456
457void
458pfinit(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(s: &pf_status, n: 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(continuation: pf_purge_thread_fn, NULL,
548 new_thread: &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, perms: 0600, fmt: "pf");
560
561 (void) devfs_make_node(makedev(maj, PFDEV_PFM), DEVFS_CHAR,
562 UID_ROOT, GID_WHEEL, perms: 0600, fmt: "pfm");
563
564 pf_attach_hooks();
565#if DUMMYNET
566 dummynet_init();
567#endif
568}
569
570#if 0
571static void
572pfdetach(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
648static int
649pfopen(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(lck: &pf_lock);
658 if (pfdevcnt != 0) {
659 lck_mtx_unlock(lck: &pf_lock);
660 return EBUSY;
661 }
662 pfdevcnt++;
663 lck_mtx_unlock(lck: &pf_lock);
664 }
665 return 0;
666}
667
668static int
669pfclose(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(lck: &pf_lock);
678 VERIFY(pfdevcnt > 0);
679 pfdevcnt--;
680 lck_mtx_unlock(lck: &pf_lock);
681 }
682 return 0;
683}
684
685static struct pf_pool *
686pf_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;
736done:
737
738 if (ruleset) {
739 pf_release_ruleset(r: ruleset);
740 ruleset = NULL;
741 }
742
743 return p;
744}
745
746static void
747pf_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
757static void
758pf_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
771void
772pf_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(poola: &rule->rpool.list);
812 pool_put(&pf_rule_pl, rule);
813}
814
815static u_int16_t
816tagname2tag(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(s1: tagname, s2: 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(s1: tagname, s2: 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
866skip_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(dst: tag->name, src: tagname, n: 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
884static void
885tag_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
905u_int16_t
906pf_tagname2tag(char *tagname)
907{
908 return tagname2tag(head: &pf_tags, tagname);
909}
910
911u_int16_t
912pf_tagname2tag_ext(char *tagname)
913{
914 u_int16_t tag;
915
916 lck_rw_lock_exclusive(lck: &pf_perim_lock);
917 lck_mtx_lock(lck: &pf_lock);
918 tag = pf_tagname2tag(tagname);
919 lck_mtx_unlock(lck: &pf_lock);
920 lck_rw_done(lck: &pf_perim_lock);
921 return tag;
922}
923
924void
925pf_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
938void
939pf_tag_unref(u_int16_t tag)
940{
941 tag_unref(head: &pf_tags, tag);
942}
943
944static int
945pf_rtlabel_add(struct pf_addr_wrap *a)
946{
947#pragma unused(a)
948 return 0;
949}
950
951static void
952pf_rtlabel_remove(struct pf_addr_wrap *a)
953{
954#pragma unused(a)
955}
956
957static void
958pf_rtlabel_copyout(struct pf_addr_wrap *a)
959{
960#pragma unused(a)
961}
962
963static int
964pf_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(rulequeue: 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(r: rs);
983 rs = NULL;
984 return 0;
985}
986
987static int
988pf_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(rulequeue: rs->rules[rs_num].inactive.ptr, rule);
1005 rs->rules[rs_num].inactive.rcount--;
1006 }
1007 rs->rules[rs_num].inactive.open = 0;
1008
1009done:
1010 if (rs) {
1011 pf_release_ruleset(r: 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
1033static void
1034pf_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
1070static void
1071pf_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, pfr: &rule->src, proto: rule->proto);
1077 pf_hash_rule_addr(ctx, pfr: &rule->dst, proto: 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
1109static int
1110pf_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(rulequeue: 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
1186done:
1187 if (rs) {
1188 pf_release_ruleset(r: rs);
1189 }
1190 return error;
1191}
1192
1193static void
1194pf_rule_copyin(struct pf_rule *src, struct pf_rule *dst, struct proc *p,
1195 int minordev)
1196{
1197 bcopy(src, dst, n: 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(cred: 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
1236static void
1237pf_rule_copyout(struct pf_rule *src, struct pf_rule *dst)
1238{
1239 bcopy(src, dst, n: 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
1260static void
1261pf_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(s: sp, n: 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(dst: &sp->id, src: &s->id, n: sizeof(sp->id));
1286 sp->creatorid = s->creatorid;
1287 strlcpy(dst: sp->ifname, src: s->kif->pfik_name, n: 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
1321static void
1322pf_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(dst: &s->id, src: &sp->id, n: 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
1363static void
1364pf_pooladdr_copyin(struct pf_pooladdr *src, struct pf_pooladdr *dst)
1365{
1366 bcopy(src, dst, n: 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
1374static void
1375pf_pooladdr_copyout(struct pf_pooladdr *src, struct pf_pooladdr *dst)
1376{
1377 bcopy(src, dst, n: sizeof(struct pf_pooladdr));
1378
1379 dst->entries.tqe_prev = NULL;
1380 dst->entries.tqe_next = NULL;
1381 dst->kif = NULL;
1382}
1383
1384static int
1385pf_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: &ctx, rule);
1414 (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
1415 }
1416 }
1417
1418 MD5Final(digest, &ctx);
1419 memcpy(dst: pf_status.pf_chksum, src: digest, n: sizeof(pf_status.pf_chksum));
1420 return 0;
1421}
1422
1423static void
1424pf_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(chan: 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
1444static void
1445pf_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(chan: 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
1461static int
1462pfioctl(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(cred: 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(src: &((struct pfioc_table *)(void *)addr)->
1523 pfrio_flags, dst: &pfrio_flags, n: 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(src: &((struct pfioc_table *)(void *)addr)->
1580 pfrio_flags, dst: &pfrio_flags, n: 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(src: &((struct pfioc_rule *)(void *)addr)->action,
1592 dst: &action, n: 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(lck: &pf_perim_lock);
1606 } else {
1607 lck_rw_lock_shared(lck: &pf_perim_lock);
1608 }
1609
1610 lck_mtx_lock(lck: &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(src: &token, dst: addr, n: 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(src: addr, dst: &pfrt, n: sizeof(pfrt));
1675 if ((error = remove_token(tok: &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(src: &pfrt, dst: addr, n: 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(s: pf_status.ifname, IFNAMSIZ);
1766 break;
1767 }
1768 strlcpy(dst: pf_status.ifname, src: pi->ifname, IFNAMSIZ);
1769 break;
1770 }
1771
1772 case DIOCCLRSTATUS: {
1773 bzero(s: pf_status.counters, n: sizeof(pf_status.counters));
1774 bzero(s: pf_status.fcounters, n: sizeof(pf_status.fcounters));
1775 bzero(s: pf_status.scounters, n: 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(src: addr, dst: &pt, n: sizeof(pt));
1798 error = pfioctl_ioc_tm(cmd, &pt, p);
1799 bcopy(src: &pt, dst: addr, n: 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(src: addr, dst: &pl, n: sizeof(pl));
1809 error = pfioctl_ioc_limit(cmd, &pl, p);
1810 bcopy(src: &pl, dst: addr, n: sizeof(pl));
1811 break;
1812 }
1813
1814 case DIOCSETDEBUG: { /* u_int32_t */
1815 bcopy(src: addr, dst: &pf_status.debug, n: 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(dst: ps.ifname, src: 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(src: &baudrate, dst: &psp->baudrate,
1847 n: 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(src: addr, dst: &hid, n: 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(lck: &pf_lock);
2007 lck_rw_done(lck: &pf_perim_lock);
2008
2009 return error;
2010}
2011
2012static int
2013pfioctl_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
2202struct32:
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__
2377done:
2378#endif
2379 return error;
2380}
2381
2382static int
2383pfioctl_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(src: entry->token.proc_name, dst: 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
2468static void
2469pf_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
2510static void
2511pf_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(rulequeue: 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
2532static void
2533pf_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 */
2544static int
2545pf_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(s1: rule->owner, s2: pr->rule.owner)) {
2573 error = EACCES;
2574 goto done;
2575 }
2576
2577delete_rule:
2578 if (rule->anchor && (ruleset != &pf_main_ruleset) &&
2579 ((strcmp(s1: ruleset->anchor->owner, s2: "")) == 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(ruleset: delete_ruleset,
2620 rs_num: i, rule: 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, rs_num: i,
2637 rule);
2638 pf_ruleset_cleanup(ruleset, rs: i);
2639 }
2640
2641done:
2642 if (ruleset) {
2643 pf_release_ruleset(r: 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 */
2653static void
2654pf_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(s1: rule->owner, s2: owner)) == 0) ||
2673 ((strcmp(s1: rule->owner, s2: "")) == 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_num: rs, rule);
2690 deleted = 1;
2691 rule = next;
2692 }
2693 } else {
2694 rule = next;
2695 }
2696 } else {
2697 if (((strcmp(s1: rule->owner, s2: owner)) == 0)) {
2698 /* delete rule */
2699 if (rule->rule_flag & PFRULE_PFM) {
2700 pffwrules--;
2701 }
2702 pf_delete_rule_from_ruleset(ruleset,
2703 rs_num: 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
2722static void
2723pf_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
2749static void
2750pf_addrwrap_setup(struct pf_addr_wrap *aw)
2751{
2752 VERIFY(aw);
2753 bzero(s: &aw->p, n: sizeof aw->p);
2754}
2755
2756static int
2757pf_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(tagname: rule->tagname)) == 0) {
2773 error = EBUSY;
2774 }
2775 }
2776 if (rule->match_tagname[0]) {
2777 if ((rule->match_tag =
2778 pf_tagname2tag(tagname: 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(aw: &rule->src.addr);
2794 pf_addrwrap_setup(aw: &rule->dst.addr);
2795 if (pf_rtlabel_add(a: &rule->src.addr) ||
2796 pf_rtlabel_add(a: &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(poola: &pf_pabuf, poolb: &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
2854static int
2855pfioctl_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(src: &pr->rule, dst: 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(s: &dn_event, n: 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(dst: dn_event.dn_event_rule_config.ifname, src: rule->ifname,
2953 n: 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(src: rule, dst: &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(a: &pr->rule.src.addr);
3026 pf_rtlabel_copyout(a: &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(src: &pcr->rule, dst: 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(tagname: newrule->tagname)) == 0) {
3120 error = EBUSY;
3121 }
3122 }
3123 if (newrule->match_tagname[0]) {
3124 if ((newrule->match_tag = pf_tagname2tag(
3125 tagname: 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(aw: &newrule->src.addr);
3141 pf_addrwrap_setup(aw: &newrule->dst.addr);
3142 if (pf_rtlabel_add(a: &newrule->src.addr) ||
3143 pf_rtlabel_add(a: &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(poola: &pf_pabuf, poolb: &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, rule: 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(poola: &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, rule: newrule);
3213 }
3214 error = EINVAL;
3215 break;
3216 }
3217 }
3218
3219 if (pcr->action == PF_CHANGE_REMOVE) {
3220 pf_rm_rule(rulequeue: ruleset->rules[rs_num].active.ptr, rule: 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(s1: r->anchor->name,
3282 s2: pr->anchor_call)) == 0)) {
3283 if (((strcmp(s1: pr->rule.owner,
3284 s2: r->owner)) == 0) ||
3285 ((strcmp(s1: r->owner, s2: "")) == 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(src: &pr->rule, dst: 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(dst: rule->anchor->owner, src: 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(rs: ruleset);
3351 }
3352
3353 pf_ruleset_cleanup(ruleset, rs: 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(src: rule, dst: &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(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(r: ruleset);
3415 ruleset = NULL;
3416 }
3417
3418 return error;
3419}
3420
3421static int
3422pfioctl_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(s1: psk->psk_ifname, s2: s->kif->pfik_name)) {
3451 ifname_matched = false;
3452 }
3453
3454 if (psk->psk_ownername[0] &&
3455 ((NULL == s->rule.ptr) ||
3456 strcmp(s1: psk->psk_ownername, s2: 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(s1: psk->psk_ifname, s2: s->kif->pfik_name)) {
3493 ifname_matched = false;
3494 }
3495
3496 if (psk->psk_ownername[0] &&
3497 ((NULL == s->rule.ptr) ||
3498 strcmp(s1: psk->psk_ownername, s2: 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
3548static int
3549pfioctl_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, n: 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(src: ps->state.id, dst: &id_key.id, n: 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(sp: &ps->state, sk: s->state_key, s);
3611 break;
3612 }
3613
3614 default:
3615 VERIFY(0);
3616 /* NOTREACHED */
3617 }
3618
3619 return error;
3620}
3621
3622static int
3623pfioctl_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(sp: pstore,
3664 sk: state->state_key, s: 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 }
3691fail:
3692 return error;
3693}
3694
3695static int
3696pfioctl_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(dst: &key.ext_gwy.xport, src: &pnl->dxport,
3730 n: sizeof(key.ext_gwy.xport));
3731 PF_ACPY(&key.gwy.addr, &pnl->saddr, pnl->af);
3732 memcpy(dst: &key.gwy.xport, src: &pnl->sxport,
3733 n: 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(dst: &key.lan.xport, src: &pnl->dxport,
3739 n: sizeof(key.lan.xport));
3740 PF_ACPY(&key.ext_lan.addr, &pnl->saddr,
3741 pnl->af);
3742 memcpy(dst: &key.ext_lan.xport, src: &pnl->sxport,
3743 n: 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(dst: &pnl->rsxport, src: &sk->lan.xport,
3754 n: sizeof(pnl->rsxport));
3755 PF_ACPY(&pnl->rdaddr, &pnl->daddr,
3756 pnl->af);
3757 memcpy(dst: &pnl->rdxport, src: &pnl->dxport,
3758 n: sizeof(pnl->rdxport));
3759 } else {
3760 PF_ACPY(&pnl->rdaddr, &sk->gwy.addr,
3761 sk->af_gwy);
3762 memcpy(dst: &pnl->rdxport, src: &sk->gwy.xport,
3763 n: sizeof(pnl->rdxport));
3764 PF_ACPY(&pnl->rsaddr, &pnl->saddr,
3765 pnl->af);
3766 memcpy(dst: &pnl->rsxport, src: &pnl->sxport,
3767 n: 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
3784static int
3785pfioctl_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(chan: 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 }
3824fail:
3825 return error;
3826}
3827
3828static int
3829pfioctl_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 }
3864fail:
3865 return error;
3866}
3867
3868static int
3869pfioctl_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(poola: &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(src: &pp->addr, dst: 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(aw: &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(anchor: pp->anchor, ticket: pp->ticket, rule_action: pp->r_action,
3933 rule_number: pp->r_num, r_last: 0, active: 1, check_ticket: 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(anchor: pp->anchor, ticket: pp->ticket, rule_action: pp->r_action,
3948 rule_number: pp->r_num, r_last: 0, active: 1, check_ticket: 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(src: pa, dst: &pp->addr);
3963 pfi_dynaddr_copyout(&pp->addr.addr);
3964 pf_tbladdr_copyout(&pp->addr.addr);
3965 pf_rtlabel_copyout(a: &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(anchor: pca->anchor, ticket: pca->ticket, rule_action: pca->r_action,
3992 rule_number: pca->r_num, r_last: pca->r_last, active: 1, check_ticket: 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(src: &pca->addr, dst: 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(aw: &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(r: ruleset);
4082 ruleset = NULL;
4083 }
4084
4085 return error;
4086}
4087
4088static int
4089pfioctl_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(dst: pr->name, src: anchor->name,
4135 n: 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(dst: pr->name, src: anchor->name,
4143 n: 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(r: ruleset);
4160 ruleset = NULL;
4161 }
4162 return error;
4163}
4164
4165static int
4166pfioctl_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(s: table, n: sizeof(*table));
4211 strlcpy(dst: table->pfrt_anchor, src: ioe->anchor,
4212 n: 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(ticket: &ioe->ticket,
4222 rs_num: ioe->rs_num, anchor: 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(s: table, n: sizeof(*table));
4265 strlcpy(dst: table->pfrt_anchor, src: ioe->anchor,
4266 n: 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(ticket: ioe->ticket,
4276 rs_num: ioe->rs_num, anchor: 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(s: table, n: sizeof(*table));
4359 strlcpy(dst: table->pfrt_anchor, src: ioe->anchor,
4360 n: 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(ticket: ioe->ticket,
4370 rs_num: ioe->rs_num, anchor: 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 }
4390fail:
4391 if (rs) {
4392 pf_release_ruleset(r: rs);
4393 rs = NULL;
4394 }
4395 return error;
4396}
4397
4398static int
4399pfioctl_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(src: n, dst: pstore, n: 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 }
4489fail:
4490 return error;
4491}
4492
4493static int
4494pfioctl_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
4549static int
4550pfioctl_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
4619int
4620pf_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(lck: &pf_perim_lock);
4639 if (!pf_is_enabled) {
4640 goto done;
4641 }
4642 lck_mtx_lock(lck: &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(lck: &pf_lock);
4701 }
4702
4703done:
4704 if (marks != net_thread_marks_none) {
4705 lck_rw_done(lck: &pf_perim_lock);
4706 }
4707
4708 net_thread_marks_pop(marks);
4709 return error;
4710}
4711
4712
4713#if INET
4714static __attribute__((noinline)) int
4715pf_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
4768int __attribute__((noinline))
4769pf_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
4808int
4809pf_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(lck: &pf_perim_lock);
4815 lck_mtx_lock(lck: &pf_lock);
4816
4817 pfi_kifaddr_update(kif);
4818
4819 lck_mtx_unlock(lck: &pf_lock);
4820 lck_rw_done(lck: &pf_perim_lock);
4821 }
4822 return 0;
4823}
4824
4825/*
4826 * Caller acquires dlil lock as writer (exclusive)
4827 */
4828void
4829pf_ifnet_hook(struct ifnet *ifp, int attach)
4830{
4831 lck_rw_lock_shared(lck: &pf_perim_lock);
4832 lck_mtx_lock(lck: &pf_lock);
4833 if (attach) {
4834 pfi_attach_ifnet(ifp);
4835 } else {
4836 pfi_detach_ifnet(ifp);
4837 }
4838 lck_mtx_unlock(lck: &pf_lock);
4839 lck_rw_done(lck: &pf_perim_lock);
4840}
4841
4842static void
4843pf_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() */
4866static void
4867pf_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 */
4895static __attribute__((unused)) void
4896pfioctl_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)
4981static void
4982pf_process_compatibilities(void)
4983{
4984 uint32_t compat_bitmap = pf_check_compatible_rules();
4985
4986 net_filter_event_mark(subsystem: NET_FILTER_EVENT_PF,
4987 compatible: (compat_bitmap &
4988 (PF_COMPATIBLE_FLAGS_CUSTOM_ANCHORS_PRESENT |
4989 PF_COMPATIBLE_FLAGS_CUSTOM_RULES_PRESENT)) == 0);
4990
4991 net_filter_event_mark(subsystem: NET_FILTER_EVENT_PF_PRIVATE_PROXY,
4992 compatible: ((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