1 /* $NetBSD: pf_table.c,v 1.17 2011/05/11 12:22:34 hauke 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.17 2011/05/11 12:22:34 hauke 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(-1 << (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(-1 << (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 bcopy(path, anchor, 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