xref: /netbsd/sys/dist/pf/net/pf_table.c (revision cf57e410)
1 /*	$NetBSD: pf_table.c,v 1.19 2020/12/04 00:41:10 thorpej Exp $	*/
2 /*	$OpenBSD: pf_table.c,v 1.70 2007/05/23 11:53:45 markus Exp $	*/
3 
4 /*
5  * Copyright (c) 2002 Cedric Berger
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  *    - Redistributions of source code must retain the above copyright
13  *      notice, this list of conditions and the following disclaimer.
14  *    - Redistributions in binary form must reproduce the above
15  *      copyright notice, this list of conditions and the following
16  *      disclaimer in the documentation and/or other materials provided
17  *      with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: pf_table.c,v 1.19 2020/12/04 00:41:10 thorpej Exp $");
36 
37 #ifdef _KERNEL_OPT
38 #include "opt_inet.h"
39 #endif
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/socket.h>
44 #include <sys/mbuf.h>
45 #include <sys/kernel.h>
46 
47 #include <net/if.h>
48 #include <net/route.h>
49 #include <netinet/in.h>
50 #ifndef __NetBSD__
51 #include <netinet/ip_ipsp.h>
52 #endif /* !__NetBSD__ */
53 #include <net/pfvar.h>
54 
55 #define ACCEPT_FLAGS(flags, oklist)		\
56 	do {					\
57 		if ((flags & ~(oklist)) &	\
58 		    PFR_FLAG_ALLMASK)		\
59 			return (EINVAL);	\
60 	} while (0)
61 
62 #define COPYIN(from, to, size, flags)		\
63 	((flags & PFR_FLAG_USERIOCTL) ?		\
64 	copyin((from), (to), (size)) :		\
65 	(bcopy((from), (to), (size)), 0))
66 
67 #define COPYOUT(from, to, size, flags)		\
68 	((flags & PFR_FLAG_USERIOCTL) ?		\
69 	copyout((from), (to), (size)) :		\
70 	(bcopy((from), (to), (size)), 0))
71 
72 #define	FILLIN_SIN(sin, addr)			\
73 	do {					\
74 		(sin).sin_len = sizeof(sin);	\
75 		(sin).sin_family = AF_INET;	\
76 		(sin).sin_addr = (addr);	\
77 	} while (0)
78 
79 #define	FILLIN_SIN6(sin6, addr)			\
80 	do {					\
81 		(sin6).sin6_len = sizeof(sin6);	\
82 		(sin6).sin6_family = AF_INET6;	\
83 		(sin6).sin6_addr = (addr);	\
84 	} while (0)
85 
86 #define SWAP(type, a1, a2)			\
87 	do {					\
88 		type tmp = a1;			\
89 		a1 = a2;			\
90 		a2 = tmp;			\
91 	} while (0)
92 
93 #define SUNION2PF(su, af) (((af)==AF_INET) ?	\
94     (struct pf_addr *)&(su)->sin.sin_addr :	\
95     (struct pf_addr *)&(su)->sin6.sin6_addr)
96 
97 #define	AF_BITS(af)		(((af)==AF_INET)?32:128)
98 #define	ADDR_NETWORK(ad)	((ad)->pfra_net < AF_BITS((ad)->pfra_af))
99 #define	KENTRY_NETWORK(ke)	((ke)->pfrke_net < AF_BITS((ke)->pfrke_af))
100 #define KENTRY_RNF_ROOT(ke) \
101 		((((struct radix_node *)(ke))->rn_flags & RNF_ROOT) != 0)
102 
103 #define NO_ADDRESSES		(-1)
104 #define ENQUEUE_UNMARKED_ONLY	(1)
105 #define INVERT_NEG_FLAG		(1)
106 
107 struct pfr_walktree {
108 	enum pfrw_op {
109 		PFRW_MARK,
110 		PFRW_SWEEP,
111 		PFRW_ENQUEUE,
112 		PFRW_GET_ADDRS,
113 		PFRW_GET_ASTATS,
114 		PFRW_POOL_GET,
115 		PFRW_DYNADDR_UPDATE
116 	}	 pfrw_op;
117 	union {
118 		struct pfr_addr		*pfrw1_addr;
119 		struct pfr_astats	*pfrw1_astats;
120 		struct pfr_kentryworkq	*pfrw1_workq;
121 		struct pfr_kentry	*pfrw1_kentry;
122 		struct pfi_dynaddr	*pfrw1_dyn;
123 	}	 pfrw_1;
124 	int	 pfrw_free;
125 	int	 pfrw_flags;
126 };
127 #define pfrw_addr	pfrw_1.pfrw1_addr
128 #define pfrw_astats	pfrw_1.pfrw1_astats
129 #define pfrw_workq	pfrw_1.pfrw1_workq
130 #define pfrw_kentry	pfrw_1.pfrw1_kentry
131 #define pfrw_dyn	pfrw_1.pfrw1_dyn
132 #define pfrw_cnt	pfrw_free
133 
134 #define senderr(e)	do { rv = (e); goto _bad; } while (0)
135 
136 struct pool		 pfr_ktable_pl;
137 struct pool		 pfr_kentry_pl;
138 struct pool		 pfr_kentry_pl2;
139 struct sockaddr_in	 pfr_sin;
140 struct sockaddr_in6	 pfr_sin6;
141 union sockaddr_union	 pfr_mask;
142 struct pf_addr		 pfr_ffaddr;
143 
144 void			 pfr_copyout_addr(struct pfr_addr *,
145 			    struct pfr_kentry *ke);
146 int			 pfr_validate_addr(struct pfr_addr *);
147 void			 pfr_enqueue_addrs(struct pfr_ktable *,
148 			    struct pfr_kentryworkq *, int *, int);
149 void			 pfr_mark_addrs(struct pfr_ktable *);
150 struct pfr_kentry	*pfr_lookup_addr(struct pfr_ktable *,
151 			    struct pfr_addr *, int);
152 struct pfr_kentry	*pfr_create_kentry(struct pfr_addr *, int);
153 void			 pfr_destroy_kentries(struct pfr_kentryworkq *);
154 void			 pfr_destroy_kentry(struct pfr_kentry *);
155 void			 pfr_insert_kentries(struct pfr_ktable *,
156 			    struct pfr_kentryworkq *, long);
157 void			 pfr_remove_kentries(struct pfr_ktable *,
158 			    struct pfr_kentryworkq *);
159 void			 pfr_clstats_kentries(struct pfr_kentryworkq *, long,
160 			    int);
161 void			 pfr_reset_feedback(struct pfr_addr *, int, int);
162 void			 pfr_prepare_network(union sockaddr_union *, int, int);
163 int			 pfr_route_kentry(struct pfr_ktable *,
164 			    struct pfr_kentry *);
165 int			 pfr_unroute_kentry(struct pfr_ktable *,
166 			    struct pfr_kentry *);
167 int			 pfr_walktree(struct radix_node *, void *);
168 int			 pfr_validate_table(struct pfr_table *, int, int);
169 int			 pfr_fix_anchor(char *);
170 void			 pfr_commit_ktable(struct pfr_ktable *, long);
171 void			 pfr_insert_ktables(struct pfr_ktableworkq *);
172 void			 pfr_insert_ktable(struct pfr_ktable *);
173 void			 pfr_setflags_ktables(struct pfr_ktableworkq *);
174 void			 pfr_setflags_ktable(struct pfr_ktable *, int);
175 void			 pfr_clstats_ktables(struct pfr_ktableworkq *, long,
176 			    int);
177 void			 pfr_clstats_ktable(struct pfr_ktable *, long, int);
178 struct pfr_ktable	*pfr_create_ktable(struct pfr_table *, long, int);
179 void			 pfr_destroy_ktables(struct pfr_ktableworkq *, int);
180 void			 pfr_destroy_ktable(struct pfr_ktable *, int);
181 int			 pfr_ktable_compare(struct pfr_ktable *,
182 			    struct pfr_ktable *);
183 struct pfr_ktable	*pfr_lookup_table(struct pfr_table *);
184 void			 pfr_clean_node_mask(struct pfr_ktable *,
185 			    struct pfr_kentryworkq *);
186 int			 pfr_table_count(struct pfr_table *, int);
187 int			 pfr_skip_table(struct pfr_table *,
188 			    struct pfr_ktable *, int);
189 struct pfr_kentry	*pfr_kentry_byidx(struct pfr_ktable *, int, int);
190 
191 RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
192 RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
193 
194 struct pfr_ktablehead	 pfr_ktables;
195 struct pfr_table	 pfr_nulltable;
196 int			 pfr_ktable_cnt;
197 
198 void
pfr_initialize(void)199 pfr_initialize(void)
200 {
201 #ifdef __NetBSD__
202 	pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0,
203 	    "pfrktable", &pool_allocator_nointr, IPL_NET);
204 	pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0,
205 	    "pfrkentry", &pool_allocator_nointr, IPL_NET);
206 	pool_init(&pfr_kentry_pl2, sizeof(struct pfr_kentry), 0, 0, 0,
207 	    "pfrkentry2", NULL, IPL_SOFTNET);
208 #else
209 	pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0,
210 	    "pfrktable", &pool_allocator_oldnointr);
211 	pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0,
212 	    "pfrkentry", &pool_allocator_oldnointr);
213 	pool_init(&pfr_kentry_pl2, sizeof(struct pfr_kentry), 0, 0, 0,
214 	    "pfrkentry2", NULL);
215 #endif /* !__NetBSD__ */
216 
217 	pfr_sin.sin_len = sizeof(pfr_sin);
218 	pfr_sin.sin_family = AF_INET;
219 	pfr_sin6.sin6_len = sizeof(pfr_sin6);
220 	pfr_sin6.sin6_family = AF_INET6;
221 
222 	memset(&pfr_ffaddr, 0xff, sizeof(pfr_ffaddr));
223 }
224 
225 #ifdef _MODULE
226 void
pfr_destroy(void)227 pfr_destroy(void)
228 {
229 	pool_destroy(&pfr_ktable_pl);
230 	pool_destroy(&pfr_kentry_pl);
231 	pool_destroy(&pfr_kentry_pl2);
232 }
233 #endif /* _MODULE */
234 
235 int
pfr_clr_addrs(struct pfr_table * tbl,int * ndel,int flags)236 pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
237 {
238 	struct pfr_ktable	*kt;
239 	struct pfr_kentryworkq	 workq;
240 	int			 s = 0;
241 
242 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
243 	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
244 		return (EINVAL);
245 	kt = pfr_lookup_table(tbl);
246 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
247 		return (ESRCH);
248 	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
249 		return (EPERM);
250 	pfr_enqueue_addrs(kt, &workq, ndel, 0);
251 
252 	if (!(flags & PFR_FLAG_DUMMY)) {
253 		if (flags & PFR_FLAG_ATOMIC)
254 			s = splsoftnet();
255 		pfr_remove_kentries(kt, &workq);
256 		if (flags & PFR_FLAG_ATOMIC)
257 			splx(s);
258 		if (kt->pfrkt_cnt) {
259 			printf("pfr_clr_addrs: corruption detected (%d).\n",
260 			    kt->pfrkt_cnt);
261 			kt->pfrkt_cnt = 0;
262 		}
263 	}
264 	return (0);
265 }
266 
267 int
pfr_add_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int flags)268 pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
269     int *nadd, int flags)
270 {
271 	struct pfr_ktable	*kt, *tmpkt;
272 	struct pfr_kentryworkq	 workq;
273 	struct pfr_kentry	*p, *q;
274 	struct pfr_addr		 ad;
275 	int			 i, rv, s = 0 /* XXX gcc */, xadd = 0;
276 	long			 tzero = time_second;
277 
278 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
279 	    PFR_FLAG_FEEDBACK);
280 	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
281 		return (EINVAL);
282 	kt = pfr_lookup_table(tbl);
283 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
284 		return (ESRCH);
285 	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
286 		return (EPERM);
287 	tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0);
288 	if (tmpkt == NULL)
289 		return (ENOMEM);
290 	SLIST_INIT(&workq);
291 	for (i = 0; i < size; i++) {
292 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
293 			senderr(EFAULT);
294 		if (pfr_validate_addr(&ad))
295 			senderr(EINVAL);
296 		p = pfr_lookup_addr(kt, &ad, 1);
297 		q = pfr_lookup_addr(tmpkt, &ad, 1);
298 		if (flags & PFR_FLAG_FEEDBACK) {
299 			if (q != NULL)
300 				ad.pfra_fback = PFR_FB_DUPLICATE;
301 			else if (p == NULL)
302 				ad.pfra_fback = PFR_FB_ADDED;
303 			else if (p->pfrke_not != ad.pfra_not)
304 				ad.pfra_fback = PFR_FB_CONFLICT;
305 			else
306 				ad.pfra_fback = PFR_FB_NONE;
307 		}
308 		if (p == NULL && q == NULL) {
309 			p = pfr_create_kentry(&ad,
310 			    !(flags & PFR_FLAG_USERIOCTL));
311 			if (p == NULL)
312 				senderr(ENOMEM);
313 			if (pfr_route_kentry(tmpkt, p)) {
314 				pfr_destroy_kentry(p);
315 				ad.pfra_fback = PFR_FB_NONE;
316 			} else {
317 				SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
318 				xadd++;
319 			}
320 		}
321 		if (flags & PFR_FLAG_FEEDBACK)
322 			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
323 				senderr(EFAULT);
324 	}
325 	pfr_clean_node_mask(tmpkt, &workq);
326 	if (!(flags & PFR_FLAG_DUMMY)) {
327 		if (flags & PFR_FLAG_ATOMIC)
328 			s = splsoftnet();
329 		pfr_insert_kentries(kt, &workq, tzero);
330 		if (flags & PFR_FLAG_ATOMIC)
331 			splx(s);
332 	} else
333 		pfr_destroy_kentries(&workq);
334 	if (nadd != NULL)
335 		*nadd = xadd;
336 	pfr_destroy_ktable(tmpkt, 0);
337 	return (0);
338 _bad:
339 	pfr_clean_node_mask(tmpkt, &workq);
340 	pfr_destroy_kentries(&workq);
341 	if (flags & PFR_FLAG_FEEDBACK)
342 		pfr_reset_feedback(addr, size, flags);
343 	pfr_destroy_ktable(tmpkt, 0);
344 	return (rv);
345 }
346 
347 int
pfr_del_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * ndel,int flags)348 pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
349     int *ndel, int flags)
350 {
351 	struct pfr_ktable	*kt;
352 	struct pfr_kentryworkq	 workq;
353 	struct pfr_kentry	*p;
354 	struct pfr_addr		 ad;
355 	int			 i, rv, s = 0 /* XXX gcc */, xdel = 0, log = 1;
356 
357 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
358 	    PFR_FLAG_FEEDBACK);
359 	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
360 		return (EINVAL);
361 	kt = pfr_lookup_table(tbl);
362 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
363 		return (ESRCH);
364 	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
365 		return (EPERM);
366 	/*
367 	 * there are two algorithms to choose from here.
368 	 * with:
369 	 *   n: number of addresses to delete
370 	 *   N: number of addresses in the table
371 	 *
372 	 * one is O(N) and is better for large 'n'
373 	 * one is O(n*LOG(N)) and is better for small 'n'
374 	 *
375 	 * following code try to decide which one is best.
376 	 */
377 	for (i = kt->pfrkt_cnt; i > 0; i >>= 1)
378 		log++;
379 	if (size > kt->pfrkt_cnt/log) {
380 		/* full table scan */
381 		pfr_mark_addrs(kt);
382 	} else {
383 		/* iterate over addresses to delete */
384 		for (i = 0; i < size; i++) {
385 			if (COPYIN(addr+i, &ad, sizeof(ad), flags))
386 				return (EFAULT);
387 			if (pfr_validate_addr(&ad))
388 				return (EINVAL);
389 			p = pfr_lookup_addr(kt, &ad, 1);
390 			if (p != NULL)
391 				p->pfrke_mark = 0;
392 		}
393 	}
394 	SLIST_INIT(&workq);
395 	for (i = 0; i < size; i++) {
396 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
397 			senderr(EFAULT);
398 		if (pfr_validate_addr(&ad))
399 			senderr(EINVAL);
400 		p = pfr_lookup_addr(kt, &ad, 1);
401 		if (flags & PFR_FLAG_FEEDBACK) {
402 			if (p == NULL)
403 				ad.pfra_fback = PFR_FB_NONE;
404 			else if (p->pfrke_not != ad.pfra_not)
405 				ad.pfra_fback = PFR_FB_CONFLICT;
406 			else if (p->pfrke_mark)
407 				ad.pfra_fback = PFR_FB_DUPLICATE;
408 			else
409 				ad.pfra_fback = PFR_FB_DELETED;
410 		}
411 		if (p != NULL && p->pfrke_not == ad.pfra_not &&
412 		    !p->pfrke_mark) {
413 			p->pfrke_mark = 1;
414 			SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
415 			xdel++;
416 		}
417 		if (flags & PFR_FLAG_FEEDBACK)
418 			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
419 				senderr(EFAULT);
420 	}
421 	if (!(flags & PFR_FLAG_DUMMY)) {
422 		if (flags & PFR_FLAG_ATOMIC)
423 			s = splsoftnet();
424 		pfr_remove_kentries(kt, &workq);
425 		if (flags & PFR_FLAG_ATOMIC)
426 			splx(s);
427 	}
428 	if (ndel != NULL)
429 		*ndel = xdel;
430 	return (0);
431 _bad:
432 	if (flags & PFR_FLAG_FEEDBACK)
433 		pfr_reset_feedback(addr, size, flags);
434 	return (rv);
435 }
436 
437 int
pfr_set_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * size2,int * nadd,int * ndel,int * nchange,int flags,u_int32_t ignore_pfrt_flags)438 pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
439     int *size2, int *nadd, int *ndel, int *nchange, int flags,
440     u_int32_t ignore_pfrt_flags)
441 {
442 	struct pfr_ktable	*kt, *tmpkt;
443 	struct pfr_kentryworkq	 addq, delq, changeq;
444 	struct pfr_kentry	*p, *q;
445 	struct pfr_addr		 ad;
446 	int			 i, rv, s = 0 /* XXX gcc */, xadd = 0, xdel = 0,
447 				 xchange = 0;
448 	long			 tzero = time_second;
449 
450 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
451 	    PFR_FLAG_FEEDBACK);
452 	if (pfr_validate_table(tbl, ignore_pfrt_flags, flags &
453 	    PFR_FLAG_USERIOCTL))
454 		return (EINVAL);
455 	kt = pfr_lookup_table(tbl);
456 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
457 		return (ESRCH);
458 	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
459 		return (EPERM);
460 	tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0);
461 	if (tmpkt == NULL)
462 		return (ENOMEM);
463 	pfr_mark_addrs(kt);
464 	SLIST_INIT(&addq);
465 	SLIST_INIT(&delq);
466 	SLIST_INIT(&changeq);
467 	for (i = 0; i < size; i++) {
468 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
469 			senderr(EFAULT);
470 		if (pfr_validate_addr(&ad))
471 			senderr(EINVAL);
472 		ad.pfra_fback = PFR_FB_NONE;
473 		p = pfr_lookup_addr(kt, &ad, 1);
474 		if (p != NULL) {
475 			if (p->pfrke_mark) {
476 				ad.pfra_fback = PFR_FB_DUPLICATE;
477 				goto _skip;
478 			}
479 			p->pfrke_mark = 1;
480 			if (p->pfrke_not != ad.pfra_not) {
481 				SLIST_INSERT_HEAD(&changeq, p, pfrke_workq);
482 				ad.pfra_fback = PFR_FB_CHANGED;
483 				xchange++;
484 			}
485 		} else {
486 			q = pfr_lookup_addr(tmpkt, &ad, 1);
487 			if (q != NULL) {
488 				ad.pfra_fback = PFR_FB_DUPLICATE;
489 				goto _skip;
490 			}
491 			p = pfr_create_kentry(&ad,
492 			    !(flags & PFR_FLAG_USERIOCTL));
493 			if (p == NULL)
494 				senderr(ENOMEM);
495 			if (pfr_route_kentry(tmpkt, p)) {
496 				pfr_destroy_kentry(p);
497 				ad.pfra_fback = PFR_FB_NONE;
498 			} else {
499 				SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
500 				ad.pfra_fback = PFR_FB_ADDED;
501 				xadd++;
502 			}
503 		}
504 _skip:
505 		if (flags & PFR_FLAG_FEEDBACK)
506 			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
507 				senderr(EFAULT);
508 	}
509 	pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY);
510 	if ((flags & PFR_FLAG_FEEDBACK) && *size2) {
511 		if (*size2 < size+xdel) {
512 			*size2 = size+xdel;
513 			senderr(0);
514 		}
515 		i = 0;
516 		SLIST_FOREACH(p, &delq, pfrke_workq) {
517 			pfr_copyout_addr(&ad, p);
518 			ad.pfra_fback = PFR_FB_DELETED;
519 			if (COPYOUT(&ad, addr+size+i, sizeof(ad), flags))
520 				senderr(EFAULT);
521 			i++;
522 		}
523 	}
524 	pfr_clean_node_mask(tmpkt, &addq);
525 	if (!(flags & PFR_FLAG_DUMMY)) {
526 		if (flags & PFR_FLAG_ATOMIC)
527 			s = splsoftnet();
528 		pfr_insert_kentries(kt, &addq, tzero);
529 		pfr_remove_kentries(kt, &delq);
530 		pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG);
531 		if (flags & PFR_FLAG_ATOMIC)
532 			splx(s);
533 	} else
534 		pfr_destroy_kentries(&addq);
535 	if (nadd != NULL)
536 		*nadd = xadd;
537 	if (ndel != NULL)
538 		*ndel = xdel;
539 	if (nchange != NULL)
540 		*nchange = xchange;
541 	if ((flags & PFR_FLAG_FEEDBACK) && size2)
542 		*size2 = size+xdel;
543 	pfr_destroy_ktable(tmpkt, 0);
544 	return (0);
545 _bad:
546 	pfr_clean_node_mask(tmpkt, &addq);
547 	pfr_destroy_kentries(&addq);
548 	if (flags & PFR_FLAG_FEEDBACK)
549 		pfr_reset_feedback(addr, size, flags);
550 	pfr_destroy_ktable(tmpkt, 0);
551 	return (rv);
552 }
553 
554 int
pfr_tst_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nmatch,int flags)555 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
556 	int *nmatch, int flags)
557 {
558 	struct pfr_ktable	*kt;
559 	struct pfr_kentry	*p;
560 	struct pfr_addr		 ad;
561 	int			 i, xmatch = 0;
562 
563 	ACCEPT_FLAGS(flags, PFR_FLAG_REPLACE);
564 	if (pfr_validate_table(tbl, 0, 0))
565 		return (EINVAL);
566 	kt = pfr_lookup_table(tbl);
567 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
568 		return (ESRCH);
569 
570 	for (i = 0; i < size; i++) {
571 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
572 			return (EFAULT);
573 		if (pfr_validate_addr(&ad))
574 			return (EINVAL);
575 		if (ADDR_NETWORK(&ad))
576 			return (EINVAL);
577 		p = pfr_lookup_addr(kt, &ad, 0);
578 		if (flags & PFR_FLAG_REPLACE)
579 			pfr_copyout_addr(&ad, p);
580 		ad.pfra_fback = (p == NULL) ? PFR_FB_NONE :
581 		    (p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH);
582 		if (p != NULL && !p->pfrke_not)
583 			xmatch++;
584 		if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
585 			return (EFAULT);
586 	}
587 	if (nmatch != NULL)
588 		*nmatch = xmatch;
589 	return (0);
590 }
591 
592 int
pfr_get_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int * size,int flags)593 pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
594 	int flags)
595 {
596 	struct pfr_ktable	*kt;
597 	struct pfr_walktree	 w;
598 	int			 rv;
599 
600 	ACCEPT_FLAGS(flags, 0);
601 	if (pfr_validate_table(tbl, 0, 0))
602 		return (EINVAL);
603 	kt = pfr_lookup_table(tbl);
604 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
605 		return (ESRCH);
606 	if (kt->pfrkt_cnt > *size) {
607 		*size = kt->pfrkt_cnt;
608 		return (0);
609 	}
610 
611 	bzero(&w, sizeof(w));
612 	w.pfrw_op = PFRW_GET_ADDRS;
613 	w.pfrw_addr = addr;
614 	w.pfrw_free = kt->pfrkt_cnt;
615 	w.pfrw_flags = flags;
616 	rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
617 	if (!rv)
618 		rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
619 	if (rv)
620 		return (rv);
621 
622 	if (w.pfrw_free) {
623 		printf("pfr_get_addrs: corruption detected (%d).\n",
624 		    w.pfrw_free);
625 		return (ENOTTY);
626 	}
627 	*size = kt->pfrkt_cnt;
628 	return (0);
629 }
630 
631 int
pfr_get_astats(struct pfr_table * tbl,struct pfr_astats * addr,int * size,int flags)632 pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
633 	int flags)
634 {
635 	struct pfr_ktable	*kt;
636 	struct pfr_walktree	 w;
637 	struct pfr_kentryworkq	 workq;
638 	int			 rv, s = 0 /* XXX gcc */;
639 	long			 tzero = time_second;
640 
641 	/* XXX PFR_FLAG_CLSTATS disabled */
642 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC);
643 	if (pfr_validate_table(tbl, 0, 0))
644 		return (EINVAL);
645 	kt = pfr_lookup_table(tbl);
646 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
647 		return (ESRCH);
648 	if (kt->pfrkt_cnt > *size) {
649 		*size = kt->pfrkt_cnt;
650 		return (0);
651 	}
652 
653 	bzero(&w, sizeof(w));
654 	w.pfrw_op = PFRW_GET_ASTATS;
655 	w.pfrw_astats = addr;
656 	w.pfrw_free = kt->pfrkt_cnt;
657 	w.pfrw_flags = flags;
658 	if (flags & PFR_FLAG_ATOMIC)
659 		s = splsoftnet();
660 	rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
661 	if (!rv)
662 		rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
663 	if (!rv && (flags & PFR_FLAG_CLSTATS)) {
664 		pfr_enqueue_addrs(kt, &workq, NULL, 0);
665 		pfr_clstats_kentries(&workq, tzero, 0);
666 	}
667 	if (flags & PFR_FLAG_ATOMIC)
668 		splx(s);
669 	if (rv)
670 		return (rv);
671 
672 	if (w.pfrw_free) {
673 		printf("pfr_get_astats: corruption detected (%d).\n",
674 		    w.pfrw_free);
675 		return (ENOTTY);
676 	}
677 	*size = kt->pfrkt_cnt;
678 	return (0);
679 }
680 
681 int
pfr_clr_astats(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nzero,int flags)682 pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
683     int *nzero, int flags)
684 {
685 	struct pfr_ktable	*kt;
686 	struct pfr_kentryworkq	 workq;
687 	struct pfr_kentry	*p;
688 	struct pfr_addr		 ad;
689 	int			 i, rv, s = 0, xzero = 0;
690 
691 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
692 	    PFR_FLAG_FEEDBACK);
693 	if (pfr_validate_table(tbl, 0, 0))
694 		return (EINVAL);
695 	kt = pfr_lookup_table(tbl);
696 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
697 		return (ESRCH);
698 	SLIST_INIT(&workq);
699 	for (i = 0; i < size; i++) {
700 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
701 			senderr(EFAULT);
702 		if (pfr_validate_addr(&ad))
703 			senderr(EINVAL);
704 		p = pfr_lookup_addr(kt, &ad, 1);
705 		if (flags & PFR_FLAG_FEEDBACK) {
706 			ad.pfra_fback = (p != NULL) ?
707 			    PFR_FB_CLEARED : PFR_FB_NONE;
708 			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
709 				senderr(EFAULT);
710 		}
711 		if (p != NULL) {
712 			SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
713 			xzero++;
714 		}
715 	}
716 
717 	if (!(flags & PFR_FLAG_DUMMY)) {
718 		if (flags & PFR_FLAG_ATOMIC)
719 			s = splsoftnet();
720 		pfr_clstats_kentries(&workq, 0, 0);
721 		if (flags & PFR_FLAG_ATOMIC)
722 			splx(s);
723 	}
724 	if (nzero != NULL)
725 		*nzero = xzero;
726 	return (0);
727 _bad:
728 	if (flags & PFR_FLAG_FEEDBACK)
729 		pfr_reset_feedback(addr, size, flags);
730 	return (rv);
731 }
732 
733 int
pfr_validate_addr(struct pfr_addr * ad)734 pfr_validate_addr(struct pfr_addr *ad)
735 {
736 	int i;
737 
738 	switch (ad->pfra_af) {
739 #ifdef INET
740 	case AF_INET:
741 		if (ad->pfra_net > 32)
742 			return (-1);
743 		break;
744 #endif /* INET */
745 #ifdef INET6
746 	case AF_INET6:
747 		if (ad->pfra_net > 128)
748 			return (-1);
749 		break;
750 #endif /* INET6 */
751 	default:
752 		return (-1);
753 	}
754 	if (ad->pfra_net < 128 &&
755 		(((char *)ad)[ad->pfra_net/8] & (0xFF >> (ad->pfra_net%8))))
756 			return (-1);
757 	for (i = (ad->pfra_net+7)/8; i < sizeof(ad->pfra_u); i++)
758 		if (((char *)ad)[i])
759 			return (-1);
760 	if (ad->pfra_not && ad->pfra_not != 1)
761 		return (-1);
762 	if (ad->pfra_fback)
763 		return (-1);
764 	return (0);
765 }
766 
767 void
pfr_enqueue_addrs(struct pfr_ktable * kt,struct pfr_kentryworkq * workq,int * naddr,int sweep)768 pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq,
769 	int *naddr, int sweep)
770 {
771 	struct pfr_walktree	w;
772 
773 	SLIST_INIT(workq);
774 	bzero(&w, sizeof(w));
775 	w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE;
776 	w.pfrw_workq = workq;
777 	if (kt->pfrkt_ip4 != NULL)
778 		if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
779 			printf("pfr_enqueue_addrs: IPv4 walktree failed.\n");
780 	if (kt->pfrkt_ip6 != NULL)
781 		if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
782 			printf("pfr_enqueue_addrs: IPv6 walktree failed.\n");
783 	if (naddr != NULL)
784 		*naddr = w.pfrw_cnt;
785 }
786 
787 void
pfr_mark_addrs(struct pfr_ktable * kt)788 pfr_mark_addrs(struct pfr_ktable *kt)
789 {
790 	struct pfr_walktree	w;
791 
792 	bzero(&w, sizeof(w));
793 	w.pfrw_op = PFRW_MARK;
794 	if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
795 		printf("pfr_mark_addrs: IPv4 walktree failed.\n");
796 	if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
797 		printf("pfr_mark_addrs: IPv6 walktree failed.\n");
798 }
799 
800 
801 struct pfr_kentry *
pfr_lookup_addr(struct pfr_ktable * kt,struct pfr_addr * ad,int exact)802 pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
803 {
804 	union sockaddr_union	 sa, mask;
805 	struct radix_node_head	*head = (void *)0xdeadb;
806 	struct pfr_kentry	*ke;
807 	int			 s;
808 
809 	bzero(&sa, sizeof(sa));
810 	if (ad->pfra_af == AF_INET) {
811 		FILLIN_SIN(sa.sin, ad->pfra_ip4addr);
812 		head = kt->pfrkt_ip4;
813 	} else if ( ad->pfra_af == AF_INET6 ) {
814 		FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr);
815 		head = kt->pfrkt_ip6;
816 	}
817 	if (ADDR_NETWORK(ad)) {
818 		pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net);
819 		s = splsoftnet(); /* rn_lookup makes use of globals */
820 		ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head);
821 		splx(s);
822 		if (ke && KENTRY_RNF_ROOT(ke))
823 			ke = NULL;
824 	} else {
825 		ke = (struct pfr_kentry *)rn_match(&sa, head);
826 		if (ke && KENTRY_RNF_ROOT(ke))
827 			ke = NULL;
828 		if (exact && ke && KENTRY_NETWORK(ke))
829 			ke = NULL;
830 	}
831 	return (ke);
832 }
833 
834 struct pfr_kentry *
pfr_create_kentry(struct pfr_addr * ad,int intr)835 pfr_create_kentry(struct pfr_addr *ad, int intr)
836 {
837 	struct pfr_kentry	*ke;
838 
839 	if (intr)
840 		ke = pool_get(&pfr_kentry_pl2, PR_NOWAIT);
841 	else
842 		ke = pool_get(&pfr_kentry_pl, PR_NOWAIT);
843 	if (ke == NULL)
844 		return (NULL);
845 	bzero(ke, sizeof(*ke));
846 
847 	if (ad->pfra_af == AF_INET)
848 		FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr);
849 	else if (ad->pfra_af == AF_INET6)
850 		FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr);
851 	ke->pfrke_af = ad->pfra_af;
852 	ke->pfrke_net = ad->pfra_net;
853 	ke->pfrke_not = ad->pfra_not;
854 	ke->pfrke_intrpool = intr;
855 	return (ke);
856 }
857 
858 void
pfr_destroy_kentries(struct pfr_kentryworkq * workq)859 pfr_destroy_kentries(struct pfr_kentryworkq *workq)
860 {
861 	struct pfr_kentry	*p, *q;
862 
863 	for (p = SLIST_FIRST(workq); p != NULL; p = q) {
864 		q = SLIST_NEXT(p, pfrke_workq);
865 		pfr_destroy_kentry(p);
866 	}
867 }
868 
869 void
pfr_destroy_kentry(struct pfr_kentry * ke)870 pfr_destroy_kentry(struct pfr_kentry *ke)
871 {
872 	if (ke->pfrke_intrpool)
873 		pool_put(&pfr_kentry_pl2, ke);
874 	else
875 		pool_put(&pfr_kentry_pl, ke);
876 }
877 
878 void
pfr_insert_kentries(struct pfr_ktable * kt,struct pfr_kentryworkq * workq,long tzero)879 pfr_insert_kentries(struct pfr_ktable *kt,
880     struct pfr_kentryworkq *workq, long tzero)
881 {
882 	struct pfr_kentry	*p;
883 	int			 rv, n = 0;
884 
885 	SLIST_FOREACH(p, workq, pfrke_workq) {
886 		rv = pfr_route_kentry(kt, p);
887 		if (rv) {
888 			printf("pfr_insert_kentries: cannot route entry "
889 			    "(code=%d).\n", rv);
890 			break;
891 		}
892 		p->pfrke_tzero = tzero;
893 		n++;
894 	}
895 	kt->pfrkt_cnt += n;
896 }
897 
898 int
pfr_insert_kentry(struct pfr_ktable * kt,struct pfr_addr * ad,long tzero)899 pfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, long tzero)
900 {
901 	struct pfr_kentry	*p;
902 	int			 rv;
903 
904 	p = pfr_lookup_addr(kt, ad, 1);
905 	if (p != NULL)
906 		return (0);
907 	p = pfr_create_kentry(ad, 1);
908 	if (p == NULL)
909 		return (EINVAL);
910 
911 	rv = pfr_route_kentry(kt, p);
912 	if (rv)
913 		return (rv);
914 
915 	p->pfrke_tzero = tzero;
916 	kt->pfrkt_cnt++;
917 
918 	return (0);
919 }
920 
921 void
pfr_remove_kentries(struct pfr_ktable * kt,struct pfr_kentryworkq * workq)922 pfr_remove_kentries(struct pfr_ktable *kt,
923     struct pfr_kentryworkq *workq)
924 {
925 	struct pfr_kentry	*p;
926 	int			 n = 0;
927 
928 	SLIST_FOREACH(p, workq, pfrke_workq) {
929 		pfr_unroute_kentry(kt, p);
930 		n++;
931 	}
932 	kt->pfrkt_cnt -= n;
933 	pfr_destroy_kentries(workq);
934 }
935 
936 void
pfr_clean_node_mask(struct pfr_ktable * kt,struct pfr_kentryworkq * workq)937 pfr_clean_node_mask(struct pfr_ktable *kt,
938     struct pfr_kentryworkq *workq)
939 {
940 	struct pfr_kentry	*p;
941 
942 	SLIST_FOREACH(p, workq, pfrke_workq)
943 		pfr_unroute_kentry(kt, p);
944 }
945 
946 void
pfr_clstats_kentries(struct pfr_kentryworkq * workq,long tzero,int negchange)947 pfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange)
948 {
949 	struct pfr_kentry	*p;
950 	int			 s;
951 
952 	SLIST_FOREACH(p, workq, pfrke_workq) {
953 		s = splsoftnet();
954 		if (negchange)
955 			p->pfrke_not = !p->pfrke_not;
956 		bzero(p->pfrke_packets, sizeof(p->pfrke_packets));
957 		bzero(p->pfrke_bytes, sizeof(p->pfrke_bytes));
958 		splx(s);
959 		p->pfrke_tzero = tzero;
960 	}
961 }
962 
963 void
pfr_reset_feedback(struct pfr_addr * addr,int size,int flags)964 pfr_reset_feedback(struct pfr_addr *addr, int size, int flags)
965 {
966 	struct pfr_addr	ad;
967 	int		i;
968 
969 	for (i = 0; i < size; i++) {
970 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
971 			break;
972 		ad.pfra_fback = PFR_FB_NONE;
973 		if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
974 			break;
975 	}
976 }
977 
978 void
pfr_prepare_network(union sockaddr_union * sa,int af,int net)979 pfr_prepare_network(union sockaddr_union *sa, int af, int net)
980 {
981 	int	i;
982 
983 	bzero(sa, sizeof(*sa));
984 	if (af == AF_INET) {
985 		sa->sin.sin_len = sizeof(sa->sin);
986 		sa->sin.sin_family = AF_INET;
987 		sa->sin.sin_addr.s_addr = net ? htonl(~0U << (32-net)) : 0;
988 	} else if (af == AF_INET6) {
989 		sa->sin6.sin6_len = sizeof(sa->sin6);
990 		sa->sin6.sin6_family = AF_INET6;
991 		for (i = 0; i < 4; i++) {
992 			if (net <= 32) {
993 				sa->sin6.sin6_addr.s6_addr32[i] =
994 				    net ? htonl(~0U << (32-net)) : 0;
995 				break;
996 			}
997 			sa->sin6.sin6_addr.s6_addr32[i] = 0xFFFFFFFF;
998 			net -= 32;
999 		}
1000 	}
1001 }
1002 
1003 int
pfr_route_kentry(struct pfr_ktable * kt,struct pfr_kentry * ke)1004 pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
1005 {
1006 	union sockaddr_union	 mask;
1007 	struct radix_node	*rn;
1008 	struct radix_node_head	*head = (void *)0xdeadb;
1009 	int			 s;
1010 
1011 	bzero(ke->pfrke_node, sizeof(ke->pfrke_node));
1012 	if (ke->pfrke_af == AF_INET)
1013 		head = kt->pfrkt_ip4;
1014 	else if (ke->pfrke_af == AF_INET6)
1015 		head = kt->pfrkt_ip6;
1016 
1017 	s = splsoftnet();
1018 	if (KENTRY_NETWORK(ke)) {
1019 		pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
1020 		rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node);
1021 	} else
1022 		rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node);
1023 	splx(s);
1024 
1025 	return (rn == NULL ? -1 : 0);
1026 }
1027 
1028 int
pfr_unroute_kentry(struct pfr_ktable * kt,struct pfr_kentry * ke)1029 pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
1030 {
1031 	union sockaddr_union	 mask;
1032 	struct radix_node	*rn;
1033 	struct radix_node_head	*head = (void *)0xdeadb;
1034 	int			 s;
1035 
1036 	if (ke->pfrke_af == AF_INET)
1037 		head = kt->pfrkt_ip4;
1038 	else if (ke->pfrke_af == AF_INET6)
1039 		head = kt->pfrkt_ip6;
1040 
1041 	s = splsoftnet();
1042 	if (KENTRY_NETWORK(ke)) {
1043 		pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
1044 		rn = rn_delete(&ke->pfrke_sa, &mask, head);
1045 	} else
1046 		rn = rn_delete(&ke->pfrke_sa, NULL, head);
1047 	splx(s);
1048 
1049 	if (rn == NULL) {
1050 		printf("pfr_unroute_kentry: delete failed.\n");
1051 		return (-1);
1052 	}
1053 	return (0);
1054 }
1055 
1056 void
pfr_copyout_addr(struct pfr_addr * ad,struct pfr_kentry * ke)1057 pfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke)
1058 {
1059 	bzero(ad, sizeof(*ad));
1060 	if (ke == NULL)
1061 		return;
1062 	ad->pfra_af = ke->pfrke_af;
1063 	ad->pfra_net = ke->pfrke_net;
1064 	ad->pfra_not = ke->pfrke_not;
1065 	if (ad->pfra_af == AF_INET)
1066 		ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr;
1067 	else if (ad->pfra_af == AF_INET6)
1068 		ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr;
1069 }
1070 
1071 int
pfr_walktree(struct radix_node * rn,void * arg)1072 pfr_walktree(struct radix_node *rn, void *arg)
1073 {
1074 	struct pfr_kentry	*ke = (struct pfr_kentry *)rn;
1075 	struct pfr_walktree	*w = arg;
1076 	int			 s, flags = w->pfrw_flags;
1077 
1078 	switch (w->pfrw_op) {
1079 	case PFRW_MARK:
1080 		ke->pfrke_mark = 0;
1081 		break;
1082 	case PFRW_SWEEP:
1083 		if (ke->pfrke_mark)
1084 			break;
1085 		/* FALLTHROUGH */
1086 	case PFRW_ENQUEUE:
1087 		SLIST_INSERT_HEAD(w->pfrw_workq, ke, pfrke_workq);
1088 		w->pfrw_cnt++;
1089 		break;
1090 	case PFRW_GET_ADDRS:
1091 		if (w->pfrw_free-- > 0) {
1092 			struct pfr_addr ad;
1093 
1094 			pfr_copyout_addr(&ad, ke);
1095 			if (copyout(&ad, w->pfrw_addr, sizeof(ad)))
1096 				return (EFAULT);
1097 			w->pfrw_addr++;
1098 		}
1099 		break;
1100 	case PFRW_GET_ASTATS:
1101 		if (w->pfrw_free-- > 0) {
1102 			struct pfr_astats as;
1103 
1104 			pfr_copyout_addr(&as.pfras_a, ke);
1105 
1106 			s = splsoftnet();
1107 			bcopy(ke->pfrke_packets, as.pfras_packets,
1108 			    sizeof(as.pfras_packets));
1109 			bcopy(ke->pfrke_bytes, as.pfras_bytes,
1110 			    sizeof(as.pfras_bytes));
1111 			splx(s);
1112 			as.pfras_tzero = ke->pfrke_tzero;
1113 
1114 			if (COPYOUT(&as, w->pfrw_astats, sizeof(as), flags))
1115 				return (EFAULT);
1116 			w->pfrw_astats++;
1117 		}
1118 		break;
1119 	case PFRW_POOL_GET:
1120 		if (ke->pfrke_not)
1121 			break; /* negative entries are ignored */
1122 		if (!w->pfrw_cnt--) {
1123 			w->pfrw_kentry = ke;
1124 			return (1); /* finish search */
1125 		}
1126 		break;
1127 	case PFRW_DYNADDR_UPDATE:
1128 		if (ke->pfrke_af == AF_INET) {
1129 			if (w->pfrw_dyn->pfid_acnt4++ > 0)
1130 				break;
1131 			pfr_prepare_network(&pfr_mask, AF_INET, ke->pfrke_net);
1132 			w->pfrw_dyn->pfid_addr4 = *SUNION2PF(
1133 			    &ke->pfrke_sa, AF_INET);
1134 			w->pfrw_dyn->pfid_mask4 = *SUNION2PF(
1135 			    &pfr_mask, AF_INET);
1136 		} else if (ke->pfrke_af == AF_INET6){
1137 			if (w->pfrw_dyn->pfid_acnt6++ > 0)
1138 				break;
1139 			pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net);
1140 			w->pfrw_dyn->pfid_addr6 = *SUNION2PF(
1141 			    &ke->pfrke_sa, AF_INET6);
1142 			w->pfrw_dyn->pfid_mask6 = *SUNION2PF(
1143 			    &pfr_mask, AF_INET6);
1144 		}
1145 		break;
1146 	}
1147 	return (0);
1148 }
1149 
1150 int
pfr_clr_tables(struct pfr_table * filter,int * ndel,int flags)1151 pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
1152 {
1153 	struct pfr_ktableworkq	 workq;
1154 	struct pfr_ktable	*p;
1155 	int			 s = 0, xdel = 0;
1156 
1157 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
1158 	    PFR_FLAG_ALLRSETS);
1159 	if (pfr_fix_anchor(filter->pfrt_anchor))
1160 		return (EINVAL);
1161 	if (pfr_table_count(filter, flags) < 0)
1162 		return (ENOENT);
1163 
1164 	SLIST_INIT(&workq);
1165 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1166 		if (pfr_skip_table(filter, p, flags))
1167 			continue;
1168 		if (!strcmp(p->pfrkt_anchor, PF_RESERVED_ANCHOR))
1169 			continue;
1170 		if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE))
1171 			continue;
1172 		p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE;
1173 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1174 		xdel++;
1175 	}
1176 	if (!(flags & PFR_FLAG_DUMMY)) {
1177 		if (flags & PFR_FLAG_ATOMIC)
1178 			s = splsoftnet();
1179 		pfr_setflags_ktables(&workq);
1180 		if (flags & PFR_FLAG_ATOMIC)
1181 			splx(s);
1182 	}
1183 	if (ndel != NULL)
1184 		*ndel = xdel;
1185 	return (0);
1186 }
1187 
1188 int
pfr_add_tables(struct pfr_table * tbl,int size,int * nadd,int flags)1189 pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
1190 {
1191 	struct pfr_ktableworkq	 addq, changeq;
1192 	struct pfr_ktable	*p, *q, *r, key;
1193 	int			 i, rv, s = 0 /* XXX gcc */, xadd = 0;
1194 	long			 tzero = time_second;
1195 
1196 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
1197 	SLIST_INIT(&addq);
1198 	SLIST_INIT(&changeq);
1199 	for (i = 0; i < size; i++) {
1200 		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
1201 			senderr(EFAULT);
1202 		if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK,
1203 		    flags & PFR_FLAG_USERIOCTL))
1204 			senderr(EINVAL);
1205 		key.pfrkt_flags |= PFR_TFLAG_ACTIVE;
1206 		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1207 		if (p == NULL) {
1208 			p = pfr_create_ktable(&key.pfrkt_t, tzero, 1);
1209 			if (p == NULL)
1210 				senderr(ENOMEM);
1211 			SLIST_FOREACH(q, &addq, pfrkt_workq) {
1212 				if (!pfr_ktable_compare(p, q))
1213 					goto _skip;
1214 			}
1215 			SLIST_INSERT_HEAD(&addq, p, pfrkt_workq);
1216 			xadd++;
1217 			if (!key.pfrkt_anchor[0])
1218 				goto _skip;
1219 
1220 			/* find or create root table */
1221 			bzero(key.pfrkt_anchor, sizeof(key.pfrkt_anchor));
1222 			r = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1223 			if (r != NULL) {
1224 				p->pfrkt_root = r;
1225 				goto _skip;
1226 			}
1227 			SLIST_FOREACH(q, &addq, pfrkt_workq) {
1228 				if (!pfr_ktable_compare(&key, q)) {
1229 					p->pfrkt_root = q;
1230 					goto _skip;
1231 				}
1232 			}
1233 			key.pfrkt_flags = 0;
1234 			r = pfr_create_ktable(&key.pfrkt_t, 0, 1);
1235 			if (r == NULL)
1236 				senderr(ENOMEM);
1237 			SLIST_INSERT_HEAD(&addq, r, pfrkt_workq);
1238 			p->pfrkt_root = r;
1239 		} else if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
1240 			SLIST_FOREACH(q, &changeq, pfrkt_workq)
1241 				if (!pfr_ktable_compare(&key, q))
1242 					goto _skip;
1243 			p->pfrkt_nflags = (p->pfrkt_flags &
1244 			    ~PFR_TFLAG_USRMASK) | key.pfrkt_flags;
1245 			SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq);
1246 			xadd++;
1247 		}
1248 _skip:
1249 	;
1250 	}
1251 	if (!(flags & PFR_FLAG_DUMMY)) {
1252 		if (flags & PFR_FLAG_ATOMIC)
1253 			s = splsoftnet();
1254 		pfr_insert_ktables(&addq);
1255 		pfr_setflags_ktables(&changeq);
1256 		if (flags & PFR_FLAG_ATOMIC)
1257 			splx(s);
1258 	} else
1259 		 pfr_destroy_ktables(&addq, 0);
1260 	if (nadd != NULL)
1261 		*nadd = xadd;
1262 	return (0);
1263 _bad:
1264 	pfr_destroy_ktables(&addq, 0);
1265 	return (rv);
1266 }
1267 
1268 int
pfr_del_tables(struct pfr_table * tbl,int size,int * ndel,int flags)1269 pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
1270 {
1271 	struct pfr_ktableworkq	 workq;
1272 	struct pfr_ktable	*p, *q, key;
1273 	int			 i, s = 0, xdel = 0;
1274 
1275 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
1276 	SLIST_INIT(&workq);
1277 	for (i = 0; i < size; i++) {
1278 		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
1279 			return (EFAULT);
1280 		if (pfr_validate_table(&key.pfrkt_t, 0,
1281 		    flags & PFR_FLAG_USERIOCTL))
1282 			return (EINVAL);
1283 		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1284 		if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
1285 			SLIST_FOREACH(q, &workq, pfrkt_workq)
1286 				if (!pfr_ktable_compare(p, q))
1287 					goto _skip;
1288 			p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE;
1289 			SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1290 			xdel++;
1291 		}
1292 _skip:
1293 	;
1294 	}
1295 
1296 	if (!(flags & PFR_FLAG_DUMMY)) {
1297 		if (flags & PFR_FLAG_ATOMIC)
1298 			s = splsoftnet();
1299 		pfr_setflags_ktables(&workq);
1300 		if (flags & PFR_FLAG_ATOMIC)
1301 			splx(s);
1302 	}
1303 	if (ndel != NULL)
1304 		*ndel = xdel;
1305 	return (0);
1306 }
1307 
1308 int
pfr_get_tables(struct pfr_table * filter,struct pfr_table * tbl,int * size,int flags)1309 pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
1310 	int flags)
1311 {
1312 	struct pfr_ktable	*p;
1313 	int			 n, nn;
1314 
1315 	ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS);
1316 	if (pfr_fix_anchor(filter->pfrt_anchor))
1317 		return (EINVAL);
1318 	n = nn = pfr_table_count(filter, flags);
1319 	if (n < 0)
1320 		return (ENOENT);
1321 	if (n > *size) {
1322 		*size = n;
1323 		return (0);
1324 	}
1325 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1326 		if (pfr_skip_table(filter, p, flags))
1327 			continue;
1328 		if (n-- <= 0)
1329 			continue;
1330 		if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl), flags))
1331 			return (EFAULT);
1332 	}
1333 	if (n) {
1334 		printf("pfr_get_tables: corruption detected (%d).\n", n);
1335 		return (ENOTTY);
1336 	}
1337 	*size = nn;
1338 	return (0);
1339 }
1340 
1341 int
pfr_get_tstats(struct pfr_table * filter,struct pfr_tstats * tbl,int * size,int flags)1342 pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
1343 	int flags)
1344 {
1345 	struct pfr_ktable	*p;
1346 	struct pfr_ktableworkq	 workq;
1347 	int			 s = 0 /* XXX gcc */, n, nn;
1348 	long			 tzero = time_second;
1349 
1350 	/* XXX PFR_FLAG_CLSTATS disabled */
1351 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_ALLRSETS);
1352 	if (pfr_fix_anchor(filter->pfrt_anchor))
1353 		return (EINVAL);
1354 	n = nn = pfr_table_count(filter, flags);
1355 	if (n < 0)
1356 		return (ENOENT);
1357 	if (n > *size) {
1358 		*size = n;
1359 		return (0);
1360 	}
1361 	SLIST_INIT(&workq);
1362 	if (flags & PFR_FLAG_ATOMIC)
1363 		s = splsoftnet();
1364 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1365 		if (pfr_skip_table(filter, p, flags))
1366 			continue;
1367 		if (n-- <= 0)
1368 			continue;
1369 		if (!(flags & PFR_FLAG_ATOMIC))
1370 			s = splsoftnet();
1371 		if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl), flags)) {
1372 			splx(s);
1373 			return (EFAULT);
1374 		}
1375 		if (!(flags & PFR_FLAG_ATOMIC))
1376 			splx(s);
1377 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1378 	}
1379 	if (flags & PFR_FLAG_CLSTATS)
1380 		pfr_clstats_ktables(&workq, tzero,
1381 		    flags & PFR_FLAG_ADDRSTOO);
1382 	if (flags & PFR_FLAG_ATOMIC)
1383 		splx(s);
1384 	if (n) {
1385 		printf("pfr_get_tstats: corruption detected (%d).\n", n);
1386 		return (ENOTTY);
1387 	}
1388 	*size = nn;
1389 	return (0);
1390 }
1391 
1392 int
pfr_clr_tstats(struct pfr_table * tbl,int size,int * nzero,int flags)1393 pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
1394 {
1395 	struct pfr_ktableworkq	 workq;
1396 	struct pfr_ktable	*p, key;
1397 	int			 i, s = 0 /* XXX gcc */, xzero = 0;
1398 	long			 tzero = time_second;
1399 
1400 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
1401 	    PFR_FLAG_ADDRSTOO);
1402 	SLIST_INIT(&workq);
1403 	for (i = 0; i < size; i++) {
1404 		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
1405 			return (EFAULT);
1406 		if (pfr_validate_table(&key.pfrkt_t, 0, 0))
1407 			return (EINVAL);
1408 		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1409 		if (p != NULL) {
1410 			SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1411 			xzero++;
1412 		}
1413 	}
1414 	if (!(flags & PFR_FLAG_DUMMY)) {
1415 		if (flags & PFR_FLAG_ATOMIC)
1416 			s = splsoftnet();
1417 		pfr_clstats_ktables(&workq, tzero, flags & PFR_FLAG_ADDRSTOO);
1418 		if (flags & PFR_FLAG_ATOMIC)
1419 			splx(s);
1420 	}
1421 	if (nzero != NULL)
1422 		*nzero = xzero;
1423 	return (0);
1424 }
1425 
1426 int
pfr_set_tflags(struct pfr_table * tbl,int size,int setflag,int clrflag,int * nchange,int * ndel,int flags)1427 pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
1428 	int *nchange, int *ndel, int flags)
1429 {
1430 	struct pfr_ktableworkq	 workq;
1431 	struct pfr_ktable	*p, *q, key;
1432 	int			 i, s = 0, xchange = 0, xdel = 0;
1433 
1434 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
1435 	if ((setflag & ~PFR_TFLAG_USRMASK) ||
1436 	    (clrflag & ~PFR_TFLAG_USRMASK) ||
1437 	    (setflag & clrflag))
1438 		return (EINVAL);
1439 	SLIST_INIT(&workq);
1440 	for (i = 0; i < size; i++) {
1441 		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
1442 			return (EFAULT);
1443 		if (pfr_validate_table(&key.pfrkt_t, 0,
1444 		    flags & PFR_FLAG_USERIOCTL))
1445 			return (EINVAL);
1446 		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1447 		if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
1448 			p->pfrkt_nflags = (p->pfrkt_flags | setflag) &
1449 			    ~clrflag;
1450 			if (p->pfrkt_nflags == p->pfrkt_flags)
1451 				goto _skip;
1452 			SLIST_FOREACH(q, &workq, pfrkt_workq)
1453 				if (!pfr_ktable_compare(p, q))
1454 					goto _skip;
1455 			SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1456 			if ((p->pfrkt_flags & PFR_TFLAG_PERSIST) &&
1457 			    (clrflag & PFR_TFLAG_PERSIST) &&
1458 			    !(p->pfrkt_flags & PFR_TFLAG_REFERENCED))
1459 				xdel++;
1460 			else
1461 				xchange++;
1462 		}
1463 _skip:
1464 	;
1465 	}
1466 	if (!(flags & PFR_FLAG_DUMMY)) {
1467 		if (flags & PFR_FLAG_ATOMIC)
1468 			s = splsoftnet();
1469 		pfr_setflags_ktables(&workq);
1470 		if (flags & PFR_FLAG_ATOMIC)
1471 			splx(s);
1472 	}
1473 	if (nchange != NULL)
1474 		*nchange = xchange;
1475 	if (ndel != NULL)
1476 		*ndel = xdel;
1477 	return (0);
1478 }
1479 
1480 int
pfr_ina_begin(struct pfr_table * trs,u_int32_t * ticket,int * ndel,int flags)1481 pfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags)
1482 {
1483 	struct pfr_ktableworkq	 workq;
1484 	struct pfr_ktable	*p;
1485 	struct pf_ruleset	*rs;
1486 	int			 xdel = 0;
1487 
1488 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
1489 	rs = pf_find_or_create_ruleset(trs->pfrt_anchor);
1490 	if (rs == NULL)
1491 		return (ENOMEM);
1492 	SLIST_INIT(&workq);
1493 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1494 		if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
1495 		    pfr_skip_table(trs, p, 0))
1496 			continue;
1497 		p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
1498 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1499 		xdel++;
1500 	}
1501 	if (!(flags & PFR_FLAG_DUMMY)) {
1502 		pfr_setflags_ktables(&workq);
1503 		if (ticket != NULL)
1504 			*ticket = ++rs->tticket;
1505 		rs->topen = 1;
1506 	} else
1507 		pf_remove_if_empty_ruleset(rs);
1508 	if (ndel != NULL)
1509 		*ndel = xdel;
1510 	return (0);
1511 }
1512 
1513 int
pfr_ina_define(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int * naddr,u_int32_t ticket,int flags)1514 pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
1515     int *nadd, int *naddr, u_int32_t ticket, int flags)
1516 {
1517 	struct pfr_ktableworkq	 tableq;
1518 	struct pfr_kentryworkq	 addrq;
1519 	struct pfr_ktable	*kt, *rt, *shadow, key;
1520 	struct pfr_kentry	*p;
1521 	struct pfr_addr		 ad;
1522 	struct pf_ruleset	*rs;
1523 	int			 i, rv, xadd = 0, xaddr = 0;
1524 
1525 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ADDRSTOO);
1526 	if (size && !(flags & PFR_FLAG_ADDRSTOO))
1527 		return (EINVAL);
1528 	if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK,
1529 	    flags & PFR_FLAG_USERIOCTL))
1530 		return (EINVAL);
1531 	rs = pf_find_ruleset(tbl->pfrt_anchor);
1532 	if (rs == NULL || !rs->topen || ticket != rs->tticket)
1533 		return (EBUSY);
1534 	tbl->pfrt_flags |= PFR_TFLAG_INACTIVE;
1535 	SLIST_INIT(&tableq);
1536 	kt = RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl);
1537 	if (kt == NULL) {
1538 		kt = pfr_create_ktable(tbl, 0, 1);
1539 		if (kt == NULL)
1540 			return (ENOMEM);
1541 		SLIST_INSERT_HEAD(&tableq, kt, pfrkt_workq);
1542 		xadd++;
1543 		if (!tbl->pfrt_anchor[0])
1544 			goto _skip;
1545 
1546 		/* find or create root table */
1547 		bzero(&key, sizeof(key));
1548 		strlcpy(key.pfrkt_name, tbl->pfrt_name, sizeof(key.pfrkt_name));
1549 		rt = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1550 		if (rt != NULL) {
1551 			kt->pfrkt_root = rt;
1552 			goto _skip;
1553 		}
1554 		rt = pfr_create_ktable(&key.pfrkt_t, 0, 1);
1555 		if (rt == NULL) {
1556 			pfr_destroy_ktables(&tableq, 0);
1557 			return (ENOMEM);
1558 		}
1559 		SLIST_INSERT_HEAD(&tableq, rt, pfrkt_workq);
1560 		kt->pfrkt_root = rt;
1561 	} else if (!(kt->pfrkt_flags & PFR_TFLAG_INACTIVE))
1562 		xadd++;
1563 _skip:
1564 	shadow = pfr_create_ktable(tbl, 0, 0);
1565 	if (shadow == NULL) {
1566 		pfr_destroy_ktables(&tableq, 0);
1567 		return (ENOMEM);
1568 	}
1569 	SLIST_INIT(&addrq);
1570 	for (i = 0; i < size; i++) {
1571 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
1572 			senderr(EFAULT);
1573 		if (pfr_validate_addr(&ad))
1574 			senderr(EINVAL);
1575 		if (pfr_lookup_addr(shadow, &ad, 1) != NULL)
1576 			continue;
1577 		p = pfr_create_kentry(&ad, 0);
1578 		if (p == NULL)
1579 			senderr(ENOMEM);
1580 		if (pfr_route_kentry(shadow, p)) {
1581 			pfr_destroy_kentry(p);
1582 			continue;
1583 		}
1584 		SLIST_INSERT_HEAD(&addrq, p, pfrke_workq);
1585 		xaddr++;
1586 	}
1587 	if (!(flags & PFR_FLAG_DUMMY)) {
1588 		if (kt->pfrkt_shadow != NULL)
1589 			pfr_destroy_ktable(kt->pfrkt_shadow, 1);
1590 		kt->pfrkt_flags |= PFR_TFLAG_INACTIVE;
1591 		pfr_insert_ktables(&tableq);
1592 		shadow->pfrkt_cnt = (flags & PFR_FLAG_ADDRSTOO) ?
1593 		    xaddr : NO_ADDRESSES;
1594 		kt->pfrkt_shadow = shadow;
1595 	} else {
1596 		pfr_clean_node_mask(shadow, &addrq);
1597 		pfr_destroy_ktable(shadow, 0);
1598 		pfr_destroy_ktables(&tableq, 0);
1599 		pfr_destroy_kentries(&addrq);
1600 	}
1601 	if (nadd != NULL)
1602 		*nadd = xadd;
1603 	if (naddr != NULL)
1604 		*naddr = xaddr;
1605 	return (0);
1606 _bad:
1607 	pfr_destroy_ktable(shadow, 0);
1608 	pfr_destroy_ktables(&tableq, 0);
1609 	pfr_destroy_kentries(&addrq);
1610 	return (rv);
1611 }
1612 
1613 int
pfr_ina_rollback(struct pfr_table * trs,u_int32_t ticket,int * ndel,int flags)1614 pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags)
1615 {
1616 	struct pfr_ktableworkq	 workq;
1617 	struct pfr_ktable	*p;
1618 	struct pf_ruleset	*rs;
1619 	int			 xdel = 0;
1620 
1621 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
1622 	rs = pf_find_ruleset(trs->pfrt_anchor);
1623 	if (rs == NULL || !rs->topen || ticket != rs->tticket)
1624 		return (0);
1625 	SLIST_INIT(&workq);
1626 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1627 		if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
1628 		    pfr_skip_table(trs, p, 0))
1629 			continue;
1630 		p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
1631 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1632 		xdel++;
1633 	}
1634 	if (!(flags & PFR_FLAG_DUMMY)) {
1635 		pfr_setflags_ktables(&workq);
1636 		rs->topen = 0;
1637 		pf_remove_if_empty_ruleset(rs);
1638 	}
1639 	if (ndel != NULL)
1640 		*ndel = xdel;
1641 	return (0);
1642 }
1643 
1644 int
pfr_ina_commit(struct pfr_table * trs,u_int32_t ticket,int * nadd,int * nchange,int flags)1645 pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
1646     int *nchange, int flags)
1647 {
1648 	struct pfr_ktable	*p, *q;
1649 	struct pfr_ktableworkq	 workq;
1650 	struct pf_ruleset	*rs;
1651 	int			 s = 0 /* XXX gcc */, xadd = 0, xchange = 0;
1652 	long			 tzero = time_second;
1653 
1654 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
1655 	rs = pf_find_ruleset(trs->pfrt_anchor);
1656 	if (rs == NULL || !rs->topen || ticket != rs->tticket)
1657 		return (EBUSY);
1658 
1659 	SLIST_INIT(&workq);
1660 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1661 		if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
1662 		    pfr_skip_table(trs, p, 0))
1663 			continue;
1664 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1665 		if (p->pfrkt_flags & PFR_TFLAG_ACTIVE)
1666 			xchange++;
1667 		else
1668 			xadd++;
1669 	}
1670 
1671 	if (!(flags & PFR_FLAG_DUMMY)) {
1672 		if (flags & PFR_FLAG_ATOMIC)
1673 			s = splsoftnet();
1674 		for (p = SLIST_FIRST(&workq); p != NULL; p = q) {
1675 			q = SLIST_NEXT(p, pfrkt_workq);
1676 			pfr_commit_ktable(p, tzero);
1677 		}
1678 		if (flags & PFR_FLAG_ATOMIC)
1679 			splx(s);
1680 		rs->topen = 0;
1681 		pf_remove_if_empty_ruleset(rs);
1682 	}
1683 	if (nadd != NULL)
1684 		*nadd = xadd;
1685 	if (nchange != NULL)
1686 		*nchange = xchange;
1687 
1688 	return (0);
1689 }
1690 
1691 void
pfr_commit_ktable(struct pfr_ktable * kt,long tzero)1692 pfr_commit_ktable(struct pfr_ktable *kt, long tzero)
1693 {
1694 	struct pfr_ktable	*shadow = kt->pfrkt_shadow;
1695 	int			 nflags;
1696 
1697 	if (shadow->pfrkt_cnt == NO_ADDRESSES) {
1698 		if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
1699 			pfr_clstats_ktable(kt, tzero, 1);
1700 	} else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) {
1701 		/* kt might contain addresses */
1702 		struct pfr_kentryworkq	 addrq, addq, changeq, delq, garbageq;
1703 		struct pfr_kentry	*p, *q, *next;
1704 		struct pfr_addr		 ad;
1705 
1706 		pfr_enqueue_addrs(shadow, &addrq, NULL, 0);
1707 		pfr_mark_addrs(kt);
1708 		SLIST_INIT(&addq);
1709 		SLIST_INIT(&changeq);
1710 		SLIST_INIT(&delq);
1711 		SLIST_INIT(&garbageq);
1712 		pfr_clean_node_mask(shadow, &addrq);
1713 		for (p = SLIST_FIRST(&addrq); p != NULL; p = next) {
1714 			next = SLIST_NEXT(p, pfrke_workq);	/* XXX */
1715 			pfr_copyout_addr(&ad, p);
1716 			q = pfr_lookup_addr(kt, &ad, 1);
1717 			if (q != NULL) {
1718 				if (q->pfrke_not != p->pfrke_not)
1719 					SLIST_INSERT_HEAD(&changeq, q,
1720 					    pfrke_workq);
1721 				q->pfrke_mark = 1;
1722 				SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq);
1723 			} else {
1724 				p->pfrke_tzero = tzero;
1725 				SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
1726 			}
1727 		}
1728 		pfr_enqueue_addrs(kt, &delq, NULL, ENQUEUE_UNMARKED_ONLY);
1729 		pfr_insert_kentries(kt, &addq, tzero);
1730 		pfr_remove_kentries(kt, &delq);
1731 		pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG);
1732 		pfr_destroy_kentries(&garbageq);
1733 	} else {
1734 		/* kt cannot contain addresses */
1735 		SWAP(struct radix_node_head *, kt->pfrkt_ip4,
1736 		    shadow->pfrkt_ip4);
1737 		SWAP(struct radix_node_head *, kt->pfrkt_ip6,
1738 		    shadow->pfrkt_ip6);
1739 		SWAP(int, kt->pfrkt_cnt, shadow->pfrkt_cnt);
1740 		pfr_clstats_ktable(kt, tzero, 1);
1741 	}
1742 	nflags = ((shadow->pfrkt_flags & PFR_TFLAG_USRMASK) |
1743 	    (kt->pfrkt_flags & PFR_TFLAG_SETMASK) | PFR_TFLAG_ACTIVE)
1744 		& ~PFR_TFLAG_INACTIVE;
1745 	pfr_destroy_ktable(shadow, 0);
1746 	kt->pfrkt_shadow = NULL;
1747 	pfr_setflags_ktable(kt, nflags);
1748 }
1749 
1750 int
pfr_validate_table(struct pfr_table * tbl,int allowedflags,int no_reserved)1751 pfr_validate_table(struct pfr_table *tbl, int allowedflags, int no_reserved)
1752 {
1753 	int i;
1754 
1755 	if (!tbl->pfrt_name[0])
1756 		return (-1);
1757 	if (no_reserved && !strcmp(tbl->pfrt_anchor, PF_RESERVED_ANCHOR))
1758 		 return (-1);
1759 	if (tbl->pfrt_name[PF_TABLE_NAME_SIZE-1])
1760 		return (-1);
1761 	for (i = strlen(tbl->pfrt_name); i < PF_TABLE_NAME_SIZE; i++)
1762 		if (tbl->pfrt_name[i])
1763 			return (-1);
1764 	if (pfr_fix_anchor(tbl->pfrt_anchor))
1765 		return (-1);
1766 	if (tbl->pfrt_flags & ~allowedflags)
1767 		return (-1);
1768 	return (0);
1769 }
1770 
1771 /*
1772  * Rewrite anchors referenced by tables to remove slashes
1773  * and check for validity.
1774  */
1775 int
pfr_fix_anchor(char * anchor)1776 pfr_fix_anchor(char *anchor)
1777 {
1778 	size_t siz = MAXPATHLEN;
1779 	int i;
1780 
1781 	if (anchor[0] == '/') {
1782 		char *path;
1783 		int off;
1784 
1785 		path = anchor;
1786 		off = 1;
1787 		while (*++path == '/')
1788 			off++;
1789 		memmove(anchor, path, siz - off);
1790 		memset(anchor + siz - off, 0, off);
1791 	}
1792 	if (anchor[siz - 1])
1793 		return (-1);
1794 	for (i = strlen(anchor); i < siz; i++)
1795 		if (anchor[i])
1796 			return (-1);
1797 	return (0);
1798 }
1799 
1800 int
pfr_table_count(struct pfr_table * filter,int flags)1801 pfr_table_count(struct pfr_table *filter, int flags)
1802 {
1803 	struct pf_ruleset *rs;
1804 
1805 	if (flags & PFR_FLAG_ALLRSETS)
1806 		return (pfr_ktable_cnt);
1807 	if (filter->pfrt_anchor[0]) {
1808 		rs = pf_find_ruleset(filter->pfrt_anchor);
1809 		return ((rs != NULL) ? rs->tables : -1);
1810 	}
1811 	return (pf_main_ruleset.tables);
1812 }
1813 
1814 int
pfr_skip_table(struct pfr_table * filter,struct pfr_ktable * kt,int flags)1815 pfr_skip_table(struct pfr_table *filter, struct pfr_ktable *kt, int flags)
1816 {
1817 	if (flags & PFR_FLAG_ALLRSETS)
1818 		return (0);
1819 	if (strcmp(filter->pfrt_anchor, kt->pfrkt_anchor))
1820 		return (1);
1821 	return (0);
1822 }
1823 
1824 void
pfr_insert_ktables(struct pfr_ktableworkq * workq)1825 pfr_insert_ktables(struct pfr_ktableworkq *workq)
1826 {
1827 	struct pfr_ktable	*p;
1828 
1829 	SLIST_FOREACH(p, workq, pfrkt_workq)
1830 		pfr_insert_ktable(p);
1831 }
1832 
1833 void
pfr_insert_ktable(struct pfr_ktable * kt)1834 pfr_insert_ktable(struct pfr_ktable *kt)
1835 {
1836 	RB_INSERT(pfr_ktablehead, &pfr_ktables, kt);
1837 	pfr_ktable_cnt++;
1838 	if (kt->pfrkt_root != NULL)
1839 		if (!kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]++)
1840 			pfr_setflags_ktable(kt->pfrkt_root,
1841 			    kt->pfrkt_root->pfrkt_flags|PFR_TFLAG_REFDANCHOR);
1842 }
1843 
1844 void
pfr_setflags_ktables(struct pfr_ktableworkq * workq)1845 pfr_setflags_ktables(struct pfr_ktableworkq *workq)
1846 {
1847 	struct pfr_ktable	*p, *q;
1848 
1849 	for (p = SLIST_FIRST(workq); p; p = q) {
1850 		q = SLIST_NEXT(p, pfrkt_workq);
1851 		pfr_setflags_ktable(p, p->pfrkt_nflags);
1852 	}
1853 }
1854 
1855 void
pfr_setflags_ktable(struct pfr_ktable * kt,int newf)1856 pfr_setflags_ktable(struct pfr_ktable *kt, int newf)
1857 {
1858 	struct pfr_kentryworkq	addrq;
1859 
1860 	if (!(newf & PFR_TFLAG_REFERENCED) &&
1861 	    !(newf & PFR_TFLAG_PERSIST))
1862 		newf &= ~PFR_TFLAG_ACTIVE;
1863 	if (!(newf & PFR_TFLAG_ACTIVE))
1864 		newf &= ~PFR_TFLAG_USRMASK;
1865 	if (!(newf & PFR_TFLAG_SETMASK)) {
1866 		RB_REMOVE(pfr_ktablehead, &pfr_ktables, kt);
1867 		if (kt->pfrkt_root != NULL)
1868 			if (!--kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR])
1869 				pfr_setflags_ktable(kt->pfrkt_root,
1870 				    kt->pfrkt_root->pfrkt_flags &
1871 					~PFR_TFLAG_REFDANCHOR);
1872 		pfr_destroy_ktable(kt, 1);
1873 		pfr_ktable_cnt--;
1874 		return;
1875 	}
1876 	if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) {
1877 		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
1878 		pfr_remove_kentries(kt, &addrq);
1879 	}
1880 	if (!(newf & PFR_TFLAG_INACTIVE) && kt->pfrkt_shadow != NULL) {
1881 		pfr_destroy_ktable(kt->pfrkt_shadow, 1);
1882 		kt->pfrkt_shadow = NULL;
1883 	}
1884 	kt->pfrkt_flags = newf;
1885 }
1886 
1887 void
pfr_clstats_ktables(struct pfr_ktableworkq * workq,long tzero,int recurse)1888 pfr_clstats_ktables(struct pfr_ktableworkq *workq, long tzero, int recurse)
1889 {
1890 	struct pfr_ktable	*p;
1891 
1892 	SLIST_FOREACH(p, workq, pfrkt_workq)
1893 		pfr_clstats_ktable(p, tzero, recurse);
1894 }
1895 
1896 void
pfr_clstats_ktable(struct pfr_ktable * kt,long tzero,int recurse)1897 pfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse)
1898 {
1899 	struct pfr_kentryworkq	 addrq;
1900 	int			 s;
1901 
1902 	if (recurse) {
1903 		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
1904 		pfr_clstats_kentries(&addrq, tzero, 0);
1905 	}
1906 	s = splsoftnet();
1907 	bzero(kt->pfrkt_packets, sizeof(kt->pfrkt_packets));
1908 	bzero(kt->pfrkt_bytes, sizeof(kt->pfrkt_bytes));
1909 	kt->pfrkt_match = kt->pfrkt_nomatch = 0;
1910 	splx(s);
1911 	kt->pfrkt_tzero = tzero;
1912 }
1913 
1914 struct pfr_ktable *
pfr_create_ktable(struct pfr_table * tbl,long tzero,int attachruleset)1915 pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset)
1916 {
1917 	struct pfr_ktable	*kt;
1918 	struct pf_ruleset	*rs;
1919 	void			*h4 = NULL, *h6 = NULL;
1920 
1921 	kt = pool_get(&pfr_ktable_pl, PR_NOWAIT);
1922 	if (kt == NULL)
1923 		return (NULL);
1924 	bzero(kt, sizeof(*kt));
1925 	kt->pfrkt_t = *tbl;
1926 
1927 	if (attachruleset) {
1928 		rs = pf_find_or_create_ruleset(tbl->pfrt_anchor);
1929 		if (!rs) {
1930 			pfr_destroy_ktable(kt, 0);
1931 			return (NULL);
1932 		}
1933 		kt->pfrkt_rs = rs;
1934 		rs->tables++;
1935 	}
1936 
1937 	if (!rn_inithead(&h4, offsetof(struct sockaddr_in, sin_addr) * 8))
1938 		goto out;
1939 
1940 	if (!rn_inithead(&h6, offsetof(struct sockaddr_in6, sin6_addr) * 8)) {
1941 		Free(h4);
1942 		goto out;
1943 	}
1944 	kt->pfrkt_ip4 = h4;
1945 	kt->pfrkt_ip6 = h6;
1946 	kt->pfrkt_tzero = tzero;
1947 
1948 	return (kt);
1949 out:
1950 	pfr_destroy_ktable(kt, 0);
1951 	return (NULL);
1952 }
1953 
1954 void
pfr_destroy_ktables(struct pfr_ktableworkq * workq,int flushaddr)1955 pfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr)
1956 {
1957 	struct pfr_ktable	*p, *q;
1958 
1959 	for (p = SLIST_FIRST(workq); p; p = q) {
1960 		q = SLIST_NEXT(p, pfrkt_workq);
1961 		pfr_destroy_ktable(p, flushaddr);
1962 	}
1963 }
1964 
1965 void
pfr_destroy_ktable(struct pfr_ktable * kt,int flushaddr)1966 pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr)
1967 {
1968 	struct pfr_kentryworkq	 addrq;
1969 
1970 	if (flushaddr) {
1971 		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
1972 		pfr_clean_node_mask(kt, &addrq);
1973 		pfr_destroy_kentries(&addrq);
1974 	}
1975 	if (kt->pfrkt_ip4 != NULL)
1976 		free((void *)kt->pfrkt_ip4, M_RTABLE);
1977 	if (kt->pfrkt_ip6 != NULL)
1978 		free((void *)kt->pfrkt_ip6, M_RTABLE);
1979 	if (kt->pfrkt_shadow != NULL)
1980 		pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr);
1981 	if (kt->pfrkt_rs != NULL) {
1982 		kt->pfrkt_rs->tables--;
1983 		pf_remove_if_empty_ruleset(kt->pfrkt_rs);
1984 	}
1985 	pool_put(&pfr_ktable_pl, kt);
1986 }
1987 
1988 int
pfr_ktable_compare(struct pfr_ktable * p,struct pfr_ktable * q)1989 pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q)
1990 {
1991 	int d;
1992 
1993 	if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE)))
1994 		return (d);
1995 	return (strcmp(p->pfrkt_anchor, q->pfrkt_anchor));
1996 }
1997 
1998 struct pfr_ktable *
pfr_lookup_table(struct pfr_table * tbl)1999 pfr_lookup_table(struct pfr_table *tbl)
2000 {
2001 	/* struct pfr_ktable start like a struct pfr_table */
2002 	return (RB_FIND(pfr_ktablehead, &pfr_ktables,
2003 	    (struct pfr_ktable *)tbl));
2004 }
2005 
2006 int
pfr_match_addr(struct pfr_ktable * kt,struct pf_addr * a,sa_family_t af)2007 pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
2008 {
2009 	struct pfr_kentry	*ke = NULL;
2010 	int			 match;
2011 
2012 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
2013 		kt = kt->pfrkt_root;
2014 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
2015 		return (0);
2016 
2017 	switch (af) {
2018 #ifdef INET
2019 	case AF_INET:
2020 		pfr_sin.sin_addr.s_addr = a->addr32[0];
2021 		ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
2022 		if (ke && KENTRY_RNF_ROOT(ke))
2023 			ke = NULL;
2024 		break;
2025 #endif /* INET */
2026 #ifdef INET6
2027 	case AF_INET6:
2028 		bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
2029 		ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
2030 		if (ke && KENTRY_RNF_ROOT(ke))
2031 			ke = NULL;
2032 		break;
2033 #endif /* INET6 */
2034 	}
2035 	match = (ke && !ke->pfrke_not);
2036 	if (match)
2037 		kt->pfrkt_match++;
2038 	else
2039 		kt->pfrkt_nomatch++;
2040 	return (match);
2041 }
2042 
2043 void
pfr_update_stats(struct pfr_ktable * kt,struct pf_addr * a,sa_family_t af,u_int64_t len,int dir_out,int op_pass,int notrule)2044 pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
2045     u_int64_t len, int dir_out, int op_pass, int notrule)
2046 {
2047 	struct pfr_kentry	*ke = NULL;
2048 
2049 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
2050 		kt = kt->pfrkt_root;
2051 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
2052 		return;
2053 
2054 	switch (af) {
2055 #ifdef INET
2056 	case AF_INET:
2057 		pfr_sin.sin_addr.s_addr = a->addr32[0];
2058 		ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
2059 		if (ke && KENTRY_RNF_ROOT(ke))
2060 			ke = NULL;
2061 		break;
2062 #endif /* INET */
2063 #ifdef INET6
2064 	case AF_INET6:
2065 		bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
2066 		ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
2067 		if (ke && KENTRY_RNF_ROOT(ke))
2068 			ke = NULL;
2069 		break;
2070 #endif /* INET6 */
2071 	default:
2072 		;
2073 	}
2074 	if ((ke == NULL || ke->pfrke_not) != notrule) {
2075 		if (op_pass != PFR_OP_PASS)
2076 			printf("pfr_update_stats: assertion failed.\n");
2077 		op_pass = PFR_OP_XPASS;
2078 	}
2079 	kt->pfrkt_packets[dir_out][op_pass]++;
2080 	kt->pfrkt_bytes[dir_out][op_pass] += len;
2081 	if (ke != NULL && op_pass != PFR_OP_XPASS) {
2082 		ke->pfrke_packets[dir_out][op_pass]++;
2083 		ke->pfrke_bytes[dir_out][op_pass] += len;
2084 	}
2085 }
2086 
2087 struct pfr_ktable *
pfr_attach_table(struct pf_ruleset * rs,char * name)2088 pfr_attach_table(struct pf_ruleset *rs, char *name)
2089 {
2090 	struct pfr_ktable	*kt, *rt;
2091 	struct pfr_table	 tbl;
2092 	struct pf_anchor	*ac = rs->anchor;
2093 
2094 	bzero(&tbl, sizeof(tbl));
2095 	strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
2096 	if (ac != NULL)
2097 		strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor));
2098 	kt = pfr_lookup_table(&tbl);
2099 	if (kt == NULL) {
2100 		kt = pfr_create_ktable(&tbl, time_second, 1);
2101 		if (kt == NULL)
2102 			return (NULL);
2103 		if (ac != NULL) {
2104 			bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor));
2105 			rt = pfr_lookup_table(&tbl);
2106 			if (rt == NULL) {
2107 				rt = pfr_create_ktable(&tbl, 0, 1);
2108 				if (rt == NULL) {
2109 					pfr_destroy_ktable(kt, 0);
2110 					return (NULL);
2111 				}
2112 				pfr_insert_ktable(rt);
2113 			}
2114 			kt->pfrkt_root = rt;
2115 		}
2116 		pfr_insert_ktable(kt);
2117 	}
2118 	if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++)
2119 		pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED);
2120 	return (kt);
2121 }
2122 
2123 void
pfr_detach_table(struct pfr_ktable * kt)2124 pfr_detach_table(struct pfr_ktable *kt)
2125 {
2126 	if (kt->pfrkt_refcnt[PFR_REFCNT_RULE] <= 0)
2127 		printf("pfr_detach_table: refcount = %d.\n",
2128 		    kt->pfrkt_refcnt[PFR_REFCNT_RULE]);
2129 	else if (!--kt->pfrkt_refcnt[PFR_REFCNT_RULE])
2130 		pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED);
2131 }
2132 
2133 int
pfr_pool_get(struct pfr_ktable * kt,int * pidx,struct pf_addr * counter,struct pf_addr ** raddr,struct pf_addr ** rmask,sa_family_t af)2134 pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter,
2135     struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af)
2136 {
2137 	struct pfr_kentry	*ke, *ke2 = (void *)0xdeadb;
2138 	struct pf_addr		*addr = (void *)0xdeadb;
2139 	union sockaddr_union	 mask;
2140 	int			 idx = -1, use_counter = 0;
2141 
2142 	if (af == AF_INET)
2143 		addr = (struct pf_addr *)&pfr_sin.sin_addr;
2144 	else if (af == AF_INET6)
2145 		addr = (struct pf_addr *)&pfr_sin6.sin6_addr;
2146 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
2147 		kt = kt->pfrkt_root;
2148 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
2149 		return (-1);
2150 
2151 	if (pidx != NULL)
2152 		idx = *pidx;
2153 	if (counter != NULL && idx >= 0)
2154 		use_counter = 1;
2155 	if (idx < 0)
2156 		idx = 0;
2157 
2158 _next_block:
2159 	ke = pfr_kentry_byidx(kt, idx, af);
2160 	if (ke == NULL)
2161 		return (1);
2162 	pfr_prepare_network(&pfr_mask, af, ke->pfrke_net);
2163 	*raddr = SUNION2PF(&ke->pfrke_sa, af);
2164 	*rmask = SUNION2PF(&pfr_mask, af);
2165 
2166 	if (use_counter) {
2167 		/* is supplied address within block? */
2168 		if (!PF_MATCHA(0, *raddr, *rmask, counter, af)) {
2169 			/* no, go to next block in table */
2170 			idx++;
2171 			use_counter = 0;
2172 			goto _next_block;
2173 		}
2174 		PF_ACPY(addr, counter, af);
2175 	} else {
2176 		/* use first address of block */
2177 		PF_ACPY(addr, *raddr, af);
2178 	}
2179 
2180 	if (!KENTRY_NETWORK(ke)) {
2181 		/* this is a single IP address - no possible nested block */
2182 		PF_ACPY(counter, addr, af);
2183 		*pidx = idx;
2184 		return (0);
2185 	}
2186 	for (;;) {
2187 		/* we don't want to use a nested block */
2188 		if (af == AF_INET)
2189 			ke2 = (struct pfr_kentry *)rn_match(&pfr_sin,
2190 			    kt->pfrkt_ip4);
2191 		else if (af == AF_INET6)
2192 			ke2 = (struct pfr_kentry *)rn_match(&pfr_sin6,
2193 			    kt->pfrkt_ip6);
2194 		/* no need to check KENTRY_RNF_ROOT() here */
2195 		if (ke2 == ke) {
2196 			/* lookup return the same block - perfect */
2197 			PF_ACPY(counter, addr, af);
2198 			*pidx = idx;
2199 			return (0);
2200 		}
2201 
2202 		/* we need to increase the counter past the nested block */
2203 		pfr_prepare_network(&mask, AF_INET, ke2->pfrke_net);
2204 		PF_POOLMASK(addr, addr, SUNION2PF(&mask, af), &pfr_ffaddr, af);
2205 		PF_AINC(addr, af);
2206 		if (!PF_MATCHA(0, *raddr, *rmask, addr, af)) {
2207 			/* ok, we reached the end of our main block */
2208 			/* go to next block in table */
2209 			idx++;
2210 			use_counter = 0;
2211 			goto _next_block;
2212 		}
2213 	}
2214 }
2215 
2216 struct pfr_kentry *
pfr_kentry_byidx(struct pfr_ktable * kt,int idx,int af)2217 pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af)
2218 {
2219 	struct pfr_walktree	w;
2220 
2221 	bzero(&w, sizeof(w));
2222 	w.pfrw_op = PFRW_POOL_GET;
2223 	w.pfrw_cnt = idx;
2224 
2225 	switch (af) {
2226 #ifdef INET
2227 	case AF_INET:
2228 		rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
2229 		return (w.pfrw_kentry);
2230 #endif /* INET */
2231 #ifdef INET6
2232 	case AF_INET6:
2233 		rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
2234 		return (w.pfrw_kentry);
2235 #endif /* INET6 */
2236 	default:
2237 		return (NULL);
2238 	}
2239 }
2240 
2241 void
pfr_dynaddr_update(struct pfr_ktable * kt,struct pfi_dynaddr * dyn)2242 pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn)
2243 {
2244 	struct pfr_walktree	w;
2245 	int			s;
2246 
2247 	bzero(&w, sizeof(w));
2248 	w.pfrw_op = PFRW_DYNADDR_UPDATE;
2249 	w.pfrw_dyn = dyn;
2250 
2251 	s = splsoftnet();
2252 	dyn->pfid_acnt4 = 0;
2253 	dyn->pfid_acnt6 = 0;
2254 	if (!dyn->pfid_af || dyn->pfid_af == AF_INET)
2255 		rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
2256 	if (!dyn->pfid_af || dyn->pfid_af == AF_INET6)
2257 		rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
2258 	splx(s);
2259 }
2260