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