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