Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netpfil/pf/pf_nl.c
108653 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2023 Alexander V. Chernikov <[email protected]>
5
* Copyright (c) 2023 Rubicon Communications, LLC (Netgate)
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
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*
28
*/
29
#include <sys/cdefs.h>
30
#include "opt_inet.h"
31
#include "opt_inet6.h"
32
33
#include <sys/param.h>
34
#include <sys/malloc.h>
35
#include <sys/mbuf.h>
36
#include <sys/priv.h>
37
#include <sys/socket.h>
38
#include <sys/ucred.h>
39
40
#include <net/pfvar.h>
41
42
#include <netlink/netlink.h>
43
#include <netlink/netlink_ctl.h>
44
#include <netlink/netlink_generic.h>
45
#include <netlink/netlink_message_writer.h>
46
47
#include <netpfil/pf/pf_nl.h>
48
49
#define DEBUG_MOD_NAME nl_pf
50
#define DEBUG_MAX_LEVEL LOG_DEBUG3
51
#include <netlink/netlink_debug.h>
52
_DECLARE_DEBUG(LOG_DEBUG);
53
54
static bool nlattr_add_pf_threshold(struct nl_writer *, int,
55
struct pf_kthreshold *);
56
57
struct nl_parsed_state {
58
uint8_t version;
59
uint32_t id;
60
uint32_t creatorid;
61
char ifname[IFNAMSIZ];
62
uint16_t proto;
63
sa_family_t af;
64
struct pf_addr addr;
65
struct pf_addr mask;
66
};
67
68
#define _IN(_field) offsetof(struct genlmsghdr, _field)
69
#define _OUT(_field) offsetof(struct nl_parsed_state, _field)
70
static const struct nlattr_parser nla_p_state[] = {
71
{ .type = PF_ST_ID, .off = _OUT(id), .cb = nlattr_get_uint32 },
72
{ .type = PF_ST_CREATORID, .off = _OUT(creatorid), .cb = nlattr_get_uint32 },
73
{ .type = PF_ST_IFNAME, .arg = (const void *)IFNAMSIZ, .off = _OUT(ifname), .cb = nlattr_get_chara },
74
{ .type = PF_ST_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
75
{ .type = PF_ST_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint16 },
76
{ .type = PF_ST_FILTER_ADDR, .off = _OUT(addr), .cb = nlattr_get_in6_addr },
77
{ .type = PF_ST_FILTER_MASK, .off = _OUT(mask), .cb = nlattr_get_in6_addr },
78
};
79
static const struct nlfield_parser nlf_p_generic[] = {
80
{ .off_in = _IN(version), .off_out = _OUT(version), .cb = nlf_get_u8 },
81
};
82
#undef _IN
83
#undef _OUT
84
NL_DECLARE_PARSER(state_parser, struct genlmsghdr, nlf_p_generic, nla_p_state);
85
86
static void
87
dump_addr(struct nl_writer *nw, int attr, const struct pf_addr *addr, int af)
88
{
89
switch (af) {
90
case AF_INET:
91
nlattr_add(nw, attr, 4, &addr->v4);
92
break;
93
case AF_INET6:
94
nlattr_add(nw, attr, 16, &addr->v6);
95
break;
96
};
97
}
98
99
static bool
100
dump_state_peer(struct nl_writer *nw, int attr, const struct pf_state_peer *peer)
101
{
102
int off = nlattr_add_nested(nw, attr);
103
104
if (off == 0)
105
return (false);
106
107
nlattr_add_u32(nw, PF_STP_SEQLO, peer->seqlo);
108
nlattr_add_u32(nw, PF_STP_SEQHI, peer->seqhi);
109
nlattr_add_u32(nw, PF_STP_SEQDIFF, peer->seqdiff);
110
nlattr_add_u16(nw, PF_STP_MAX_WIN, peer->max_win);
111
nlattr_add_u16(nw, PF_STP_MSS, peer->mss);
112
nlattr_add_u8(nw, PF_STP_STATE, peer->state);
113
nlattr_add_u8(nw, PF_STP_WSCALE, peer->wscale);
114
115
if (peer->scrub != NULL) {
116
struct pf_state_scrub *sc = peer->scrub;
117
uint16_t pfss_flags = sc->pfss_flags & PFSS_TIMESTAMP;
118
119
nlattr_add_u16(nw, PF_STP_PFSS_FLAGS, pfss_flags);
120
nlattr_add_u32(nw, PF_STP_PFSS_TS_MOD, sc->pfss_ts_mod);
121
nlattr_add_u8(nw, PF_STP_PFSS_TTL, sc->pfss_ttl);
122
nlattr_add_u8(nw, PF_STP_SCRUB_FLAG, PF_SCRUB_FLAG_VALID);
123
}
124
nlattr_set_len(nw, off);
125
126
return (true);
127
}
128
129
static bool
130
dump_state_key(struct nl_writer *nw, int attr, const struct pf_state_key *key)
131
{
132
int off = nlattr_add_nested(nw, attr);
133
134
if (off == 0)
135
return (false);
136
137
dump_addr(nw, PF_STK_ADDR0, &key->addr[0], key->af);
138
dump_addr(nw, PF_STK_ADDR1, &key->addr[1], key->af);
139
nlattr_add_u16(nw, PF_STK_PORT0, key->port[0]);
140
nlattr_add_u16(nw, PF_STK_PORT1, key->port[1]);
141
nlattr_add_u8(nw, PF_STK_AF, key->af);
142
nlattr_add_u16(nw, PF_STK_PROTO, key->proto);
143
144
nlattr_set_len(nw, off);
145
146
return (true);
147
}
148
149
static int
150
dump_state(struct nlpcb *nlp, const struct nlmsghdr *hdr, struct pf_kstate *s,
151
struct nl_pstate *npt)
152
{
153
struct nl_writer *nw = npt->nw;
154
int error = 0;
155
int af;
156
struct pf_state_key *key;
157
158
PF_STATE_LOCK_ASSERT(s);
159
160
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
161
goto enomem;
162
163
struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
164
ghdr_new->cmd = PFNL_CMD_GETSTATES;
165
166
nlattr_add_u64(nw, PF_ST_VERSION, PF_STATE_VERSION);
167
168
key = s->key[PF_SK_WIRE];
169
if (!dump_state_key(nw, PF_ST_KEY_WIRE, key))
170
goto enomem;
171
key = s->key[PF_SK_STACK];
172
if (!dump_state_key(nw, PF_ST_KEY_STACK, key))
173
goto enomem;
174
175
af = s->key[PF_SK_WIRE]->af;
176
nlattr_add_u8(nw, PF_ST_PROTO, s->key[PF_SK_WIRE]->proto);
177
nlattr_add_u8(nw, PF_ST_AF, af);
178
179
nlattr_add_string(nw, PF_ST_IFNAME, s->kif->pfik_name);
180
nlattr_add_string(nw, PF_ST_ORIG_IFNAME, s->orig_kif->pfik_name);
181
dump_addr(nw, PF_ST_RT_ADDR, &s->act.rt_addr, s->act.rt_af);
182
nlattr_add_u32(nw, PF_ST_CREATION, time_uptime - (s->creation / 1000));
183
uint32_t expire = pf_state_expires(s);
184
if (expire > time_uptime)
185
expire = expire - time_uptime;
186
nlattr_add_u32(nw, PF_ST_EXPIRE, expire);
187
nlattr_add_u8(nw, PF_ST_DIRECTION, s->direction);
188
nlattr_add_u8(nw, PF_ST_LOG, s->act.log);
189
nlattr_add_u8(nw, PF_ST_TIMEOUT, s->timeout);
190
nlattr_add_u16(nw, PF_ST_STATE_FLAGS, s->state_flags);
191
uint8_t sync_flags = 0;
192
if (s->sns[PF_SN_LIMIT] != NULL)
193
sync_flags |= PFSYNC_FLAG_SRCNODE;
194
if (s->sns[PF_SN_NAT] != NULL || s->sns[PF_SN_ROUTE])
195
sync_flags |= PFSYNC_FLAG_NATSRCNODE;
196
nlattr_add_u8(nw, PF_ST_SYNC_FLAGS, sync_flags);
197
nlattr_add_u64(nw, PF_ST_ID, s->id);
198
nlattr_add_u32(nw, PF_ST_CREATORID, htonl(s->creatorid));
199
200
nlattr_add_u32(nw, PF_ST_RULE, s->rule ? s->rule->nr : -1);
201
nlattr_add_u32(nw, PF_ST_ANCHOR, s->anchor ? s->anchor->nr : -1);
202
nlattr_add_u32(nw, PF_ST_NAT_RULE, s->nat_rule ? s->nat_rule->nr : -1);
203
204
nlattr_add_u64(nw, PF_ST_PACKETS0, s->packets[0]);
205
nlattr_add_u64(nw, PF_ST_PACKETS1, s->packets[1]);
206
nlattr_add_u64(nw, PF_ST_BYTES0, s->bytes[0]);
207
nlattr_add_u64(nw, PF_ST_BYTES1, s->bytes[1]);
208
nlattr_add_u32(nw, PF_ST_RTABLEID, s->act.rtableid);
209
nlattr_add_u8(nw, PF_ST_MIN_TTL, s->act.min_ttl);
210
nlattr_add_u16(nw, PF_ST_MAX_MSS, s->act.max_mss);
211
nlattr_add_u16(nw, PF_ST_DNPIPE, s->act.dnpipe);
212
nlattr_add_u16(nw, PF_ST_DNRPIPE, s->act.dnrpipe);
213
nlattr_add_u8(nw, PF_ST_RT, s->act.rt);
214
if (s->act.rt_kif != NULL)
215
nlattr_add_string(nw, PF_ST_RT_IFNAME, s->act.rt_kif->pfik_name);
216
uint8_t src_node_flags = 0;
217
if (s->sns[PF_SN_LIMIT] != NULL) {
218
src_node_flags |= PFSTATE_SRC_NODE_LIMIT;
219
if (s->sns[PF_SN_LIMIT]->rule == &V_pf_default_rule)
220
src_node_flags |= PFSTATE_SRC_NODE_LIMIT_GLOBAL;
221
}
222
if (s->sns[PF_SN_NAT] != NULL)
223
src_node_flags |= PFSTATE_SRC_NODE_NAT;
224
if (s->sns[PF_SN_ROUTE] != NULL)
225
src_node_flags |= PFSTATE_SRC_NODE_ROUTE;
226
nlattr_add_u8(nw, PF_ST_SRC_NODE_FLAGS, src_node_flags);
227
nlattr_add_u8(nw, PF_ST_RT_AF, s->act.rt_af);
228
229
if (!dump_state_peer(nw, PF_ST_PEER_SRC, &s->src))
230
goto enomem;
231
if (!dump_state_peer(nw, PF_ST_PEER_DST, &s->dst))
232
goto enomem;
233
234
if (nlmsg_end(nw))
235
return (0);
236
237
enomem:
238
error = ENOMEM;
239
nlmsg_abort(nw);
240
return (error);
241
}
242
243
static int
244
handle_dumpstates(struct nlpcb *nlp, struct nl_parsed_state *attrs,
245
struct nlmsghdr *hdr, struct nl_pstate *npt)
246
{
247
int error = 0;
248
249
hdr->nlmsg_flags |= NLM_F_MULTI;
250
251
for (int i = 0; i <= V_pf_hashmask; i++) {
252
struct pf_idhash *ih = &V_pf_idhash[i];
253
struct pf_kstate *s;
254
255
if (LIST_EMPTY(&ih->states))
256
continue;
257
258
PF_HASHROW_LOCK(ih);
259
LIST_FOREACH(s, &ih->states, entry) {
260
sa_family_t af = s->key[PF_SK_WIRE]->af;
261
262
if (s->timeout == PFTM_UNLINKED)
263
continue;
264
265
/* Filter */
266
if (attrs->creatorid != 0 && s->creatorid != attrs->creatorid)
267
continue;
268
if (attrs->ifname[0] != 0 &&
269
strncmp(attrs->ifname, s->kif->pfik_name, IFNAMSIZ) != 0)
270
continue;
271
if (attrs->proto != 0 && s->key[PF_SK_WIRE]->proto != attrs->proto)
272
continue;
273
if (attrs->af != 0 && af != attrs->af)
274
continue;
275
if (pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[0],
276
&attrs->mask, &attrs->addr, af) &&
277
pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[1],
278
&attrs->mask, &attrs->addr, af) &&
279
pf_match_addr(1, &s->key[PF_SK_STACK]->addr[0],
280
&attrs->mask, &attrs->addr, af) &&
281
pf_match_addr(1, &s->key[PF_SK_STACK]->addr[1],
282
&attrs->mask, &attrs->addr, af))
283
continue;
284
285
error = dump_state(nlp, hdr, s, npt);
286
if (error != 0)
287
break;
288
}
289
PF_HASHROW_UNLOCK(ih);
290
}
291
292
if (!nlmsg_end_dump(npt->nw, error, hdr)) {
293
NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
294
return (ENOMEM);
295
}
296
297
return (error);
298
}
299
300
static int
301
handle_getstate(struct nlpcb *nlp, struct nl_parsed_state *attrs,
302
struct nlmsghdr *hdr, struct nl_pstate *npt)
303
{
304
struct pf_kstate *s;
305
int ret;
306
307
s = pf_find_state_byid(attrs->id, attrs->creatorid);
308
if (s == NULL)
309
return (ENOENT);
310
ret = dump_state(nlp, hdr, s, npt);
311
PF_STATE_UNLOCK(s);
312
313
return (ret);
314
}
315
316
static int
317
dump_creatorid(struct nlpcb *nlp, const struct nlmsghdr *hdr, uint32_t creator,
318
struct nl_pstate *npt)
319
{
320
struct nl_writer *nw = npt->nw;
321
322
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
323
goto enomem;
324
325
struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
326
ghdr_new->cmd = PFNL_CMD_GETCREATORS;
327
328
nlattr_add_u32(nw, PF_ST_CREATORID, htonl(creator));
329
330
if (nlmsg_end(nw))
331
return (0);
332
333
enomem:
334
nlmsg_abort(nw);
335
return (ENOMEM);
336
}
337
338
static int
339
pf_handle_getstates(struct nlmsghdr *hdr, struct nl_pstate *npt)
340
{
341
int error;
342
343
struct nl_parsed_state attrs = {};
344
error = nl_parse_nlmsg(hdr, &state_parser, npt, &attrs);
345
if (error != 0)
346
return (error);
347
348
if (attrs.id != 0)
349
error = handle_getstate(npt->nlp, &attrs, hdr, npt);
350
else
351
error = handle_dumpstates(npt->nlp, &attrs, hdr, npt);
352
353
return (error);
354
}
355
356
static int
357
pf_handle_getcreators(struct nlmsghdr *hdr, struct nl_pstate *npt)
358
{
359
uint32_t creators[16];
360
int error = 0;
361
362
bzero(creators, sizeof(creators));
363
364
for (int i = 0; i <= V_pf_hashmask; i++) {
365
struct pf_idhash *ih = &V_pf_idhash[i];
366
struct pf_kstate *s;
367
368
if (LIST_EMPTY(&ih->states))
369
continue;
370
371
PF_HASHROW_LOCK(ih);
372
LIST_FOREACH(s, &ih->states, entry) {
373
int j;
374
if (s->timeout == PFTM_UNLINKED)
375
continue;
376
377
for (j = 0; j < nitems(creators); j++) {
378
if (creators[j] == s->creatorid)
379
break;
380
if (creators[j] == 0) {
381
creators[j] = s->creatorid;
382
break;
383
}
384
}
385
if (j == nitems(creators))
386
printf("Warning: too many creators!\n");
387
}
388
PF_HASHROW_UNLOCK(ih);
389
}
390
391
hdr->nlmsg_flags |= NLM_F_MULTI;
392
for (int i = 0; i < nitems(creators); i++) {
393
if (creators[i] == 0)
394
break;
395
error = dump_creatorid(npt->nlp, hdr, creators[i], npt);
396
}
397
398
if (!nlmsg_end_dump(npt->nw, error, hdr)) {
399
NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
400
return (ENOMEM);
401
}
402
403
return (error);
404
}
405
406
static int
407
pf_handle_start(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
408
{
409
return (pf_start());
410
}
411
412
static int
413
pf_handle_stop(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
414
{
415
return (pf_stop());
416
}
417
418
#define _OUT(_field) offsetof(struct pf_addr_wrap, _field)
419
static const struct nlattr_parser nla_p_addr_wrap[] = {
420
{ .type = PF_AT_ADDR, .off = _OUT(v.a.addr), .cb = nlattr_get_in6_addr },
421
{ .type = PF_AT_MASK, .off = _OUT(v.a.mask), .cb = nlattr_get_in6_addr },
422
{ .type = PF_AT_IFNAME, .off = _OUT(v.ifname), .arg = (void *)IFNAMSIZ,.cb = nlattr_get_chara },
423
{ .type = PF_AT_TABLENAME, .off = _OUT(v.tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
424
{ .type = PF_AT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
425
{ .type = PF_AT_IFLAGS, .off = _OUT(iflags), .cb = nlattr_get_uint8 },
426
};
427
NL_DECLARE_ATTR_PARSER(addr_wrap_parser, nla_p_addr_wrap);
428
#undef _OUT
429
430
static bool
431
nlattr_add_addr_wrap(struct nl_writer *nw, int attrtype, struct pf_addr_wrap *a)
432
{
433
int off = nlattr_add_nested(nw, attrtype);
434
435
if (off == 0)
436
return (false);
437
438
nlattr_add_in6_addr(nw, PF_AT_ADDR, &a->v.a.addr.v6);
439
nlattr_add_in6_addr(nw, PF_AT_MASK, &a->v.a.mask.v6);
440
nlattr_add_u8(nw, PF_AT_TYPE, a->type);
441
nlattr_add_u8(nw, PF_AT_IFLAGS, a->iflags);
442
443
if (a->type == PF_ADDR_DYNIFTL) {
444
nlattr_add_string(nw, PF_AT_IFNAME, a->v.ifname);
445
nlattr_add_u32(nw, PF_AT_DYNCNT, a->p.dyncnt);
446
} else if (a->type == PF_ADDR_TABLE) {
447
nlattr_add_string(nw, PF_AT_TABLENAME, a->v.tblname);
448
nlattr_add_u32(nw, PF_AT_TBLCNT, a->p.tblcnt);
449
}
450
451
nlattr_set_len(nw, off);
452
453
return (true);
454
}
455
456
#define _OUT(_field) offsetof(struct pf_rule_addr, _field)
457
static const struct nlattr_parser nla_p_ruleaddr[] = {
458
{ .type = PF_RAT_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
459
{ .type = PF_RAT_SRC_PORT, .off = _OUT(port[0]), .cb = nlattr_get_uint16 },
460
{ .type = PF_RAT_DST_PORT, .off = _OUT(port[1]), .cb = nlattr_get_uint16 },
461
{ .type = PF_RAT_NEG, .off = _OUT(neg), .cb = nlattr_get_uint8 },
462
{ .type = PF_RAT_OP, .off = _OUT(port_op), .cb = nlattr_get_uint8 },
463
};
464
NL_DECLARE_ATTR_PARSER(rule_addr_parser, nla_p_ruleaddr);
465
#undef _OUT
466
467
static bool
468
nlattr_add_rule_addr(struct nl_writer *nw, int attrtype, struct pf_rule_addr *r)
469
{
470
struct pf_addr_wrap aw = {0};
471
int off = nlattr_add_nested(nw, attrtype);
472
473
if (off == 0)
474
return (false);
475
476
bcopy(&(r->addr), &aw, sizeof(struct pf_addr_wrap));
477
pf_addr_copyout(&aw);
478
479
nlattr_add_addr_wrap(nw, PF_RAT_ADDR, &aw);
480
nlattr_add_u16(nw, PF_RAT_SRC_PORT, r->port[0]);
481
nlattr_add_u16(nw, PF_RAT_DST_PORT, r->port[1]);
482
nlattr_add_u8(nw, PF_RAT_NEG, r->neg);
483
nlattr_add_u8(nw, PF_RAT_OP, r->port_op);
484
485
nlattr_set_len(nw, off);
486
487
return (true);
488
}
489
490
#define _OUT(_field) offsetof(struct pf_mape_portset, _field)
491
static const struct nlattr_parser nla_p_mape_portset[] = {
492
{ .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = nlattr_get_uint8 },
493
{ .type = PF_MET_PSID_LEN, .off = _OUT(psidlen), .cb = nlattr_get_uint8 },
494
{. type = PF_MET_PSID, .off = _OUT(psid), .cb = nlattr_get_uint16 },
495
};
496
NL_DECLARE_ATTR_PARSER(mape_portset_parser, nla_p_mape_portset);
497
#undef _OUT
498
499
static bool
500
nlattr_add_mape_portset(struct nl_writer *nw, int attrtype, const struct pf_mape_portset *m)
501
{
502
int off = nlattr_add_nested(nw, attrtype);
503
504
if (off == 0)
505
return (false);
506
507
nlattr_add_u8(nw, PF_MET_OFFSET, m->offset);
508
nlattr_add_u8(nw, PF_MET_PSID_LEN, m->psidlen);
509
nlattr_add_u16(nw, PF_MET_PSID, m->psid);
510
511
nlattr_set_len(nw, off);
512
513
return (true);
514
}
515
516
struct nl_parsed_labels
517
{
518
char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
519
uint32_t i;
520
};
521
522
static int
523
nlattr_get_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt,
524
const void *arg, void *target)
525
{
526
struct nl_parsed_labels *l = (struct nl_parsed_labels *)target;
527
int ret;
528
529
if (l->i >= PF_RULE_MAX_LABEL_COUNT)
530
return (E2BIG);
531
532
ret = nlattr_get_chara(nla, npt, (void *)PF_RULE_LABEL_SIZE,
533
l->labels[l->i]);
534
if (ret == 0)
535
l->i++;
536
537
return (ret);
538
}
539
540
#define _OUT(_field) offsetof(struct nl_parsed_labels, _field)
541
static const struct nlattr_parser nla_p_labels[] = {
542
{ .type = PF_LT_LABEL, .off = 0, .cb = nlattr_get_pf_rule_labels },
543
};
544
NL_DECLARE_ATTR_PARSER(rule_labels_parser, nla_p_labels);
545
#undef _OUT
546
547
static int
548
nlattr_get_nested_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
549
{
550
struct nl_parsed_labels parsed_labels = { };
551
int error;
552
553
/* Assumes target points to the beginning of the structure */
554
error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &rule_labels_parser, npt, &parsed_labels);
555
if (error != 0)
556
return (error);
557
558
memcpy(target, parsed_labels.labels, sizeof(parsed_labels.labels));
559
560
return (0);
561
}
562
563
static bool
564
nlattr_add_labels(struct nl_writer *nw, int attrtype, const struct pf_krule *r)
565
{
566
int off = nlattr_add_nested(nw, attrtype);
567
int i = 0;
568
569
if (off == 0)
570
return (false);
571
572
while (r->label[i][0] != 0
573
&& i < PF_RULE_MAX_LABEL_COUNT) {
574
nlattr_add_string(nw, PF_LT_LABEL, r->label[i]);
575
i++;
576
}
577
578
nlattr_set_len(nw, off);
579
580
return (true);
581
}
582
583
#define _OUT(_field) offsetof(struct pf_kpool, _field)
584
static const struct nlattr_parser nla_p_pool[] = {
585
{ .type = PF_PT_KEY, .off = _OUT(key), .arg = (void *)sizeof(struct pf_poolhashkey), .cb = nlattr_get_bytes },
586
{ .type = PF_PT_COUNTER, .off = _OUT(counter), .cb = nlattr_get_in6_addr },
587
{ .type = PF_PT_TBLIDX, .off = _OUT(tblidx), .cb = nlattr_get_uint32 },
588
{ .type = PF_PT_PROXY_SRC_PORT, .off = _OUT(proxy_port[0]), .cb = nlattr_get_uint16 },
589
{ .type = PF_PT_PROXY_DST_PORT, .off = _OUT(proxy_port[1]), .cb = nlattr_get_uint16 },
590
{ .type = PF_PT_OPTS, .off = _OUT(opts), .cb = nlattr_get_uint8 },
591
{ .type = PF_PT_MAPE, .off = _OUT(mape), .arg = &mape_portset_parser, .cb = nlattr_get_nested },
592
};
593
NL_DECLARE_ATTR_PARSER(pool_parser, nla_p_pool);
594
#undef _OUT
595
596
static bool
597
nlattr_add_pool(struct nl_writer *nw, int attrtype, const struct pf_kpool *pool)
598
{
599
int off = nlattr_add_nested(nw, attrtype);
600
601
if (off == 0)
602
return (false);
603
604
nlattr_add(nw, PF_PT_KEY, sizeof(struct pf_poolhashkey), &pool->key);
605
nlattr_add_in6_addr(nw, PF_PT_COUNTER, (const struct in6_addr *)&pool->counter);
606
nlattr_add_u32(nw, PF_PT_TBLIDX, pool->tblidx);
607
nlattr_add_u16(nw, PF_PT_PROXY_SRC_PORT, pool->proxy_port[0]);
608
nlattr_add_u16(nw, PF_PT_PROXY_DST_PORT, pool->proxy_port[1]);
609
nlattr_add_u8(nw, PF_PT_OPTS, pool->opts);
610
nlattr_add_mape_portset(nw, PF_PT_MAPE, &pool->mape);
611
612
nlattr_set_len(nw, off);
613
614
return (true);
615
}
616
617
#define _OUT(_field) offsetof(struct pf_rule_uid, _field)
618
static const struct nlattr_parser nla_p_rule_uid[] = {
619
{ .type = PF_RUT_UID_LOW, .off = _OUT(uid[0]), .cb = nlattr_get_uint32 },
620
{ .type = PF_RUT_UID_HIGH, .off = _OUT(uid[1]), .cb = nlattr_get_uint32 },
621
{ .type = PF_RUT_OP, .off = _OUT(op), .cb = nlattr_get_uint8 },
622
};
623
NL_DECLARE_ATTR_PARSER(rule_uid_parser, nla_p_rule_uid);
624
#undef _OUT
625
626
static bool
627
nlattr_add_rule_uid(struct nl_writer *nw, int attrtype, const struct pf_rule_uid *u)
628
{
629
int off = nlattr_add_nested(nw, attrtype);
630
631
if (off == 0)
632
return (false);
633
634
nlattr_add_u32(nw, PF_RUT_UID_LOW, u->uid[0]);
635
nlattr_add_u32(nw, PF_RUT_UID_HIGH, u->uid[1]);
636
nlattr_add_u8(nw, PF_RUT_OP, u->op);
637
638
nlattr_set_len(nw, off);
639
640
return (true);
641
}
642
643
struct nl_parsed_timeouts
644
{
645
uint32_t timeouts[PFTM_MAX];
646
uint32_t i;
647
};
648
649
static int
650
nlattr_get_pf_timeout(struct nlattr *nla, struct nl_pstate *npt,
651
const void *arg, void *target)
652
{
653
struct nl_parsed_timeouts *t = (struct nl_parsed_timeouts *)target;
654
int ret;
655
656
if (t->i >= PFTM_MAX)
657
return (E2BIG);
658
659
ret = nlattr_get_uint32(nla, npt, NULL, &t->timeouts[t->i]);
660
if (ret == 0)
661
t->i++;
662
663
return (ret);
664
}
665
666
#define _OUT(_field) offsetof(struct nl_parsed_timeout, _field)
667
static const struct nlattr_parser nla_p_timeouts[] = {
668
{ .type = PF_TT_TIMEOUT, .off = 0, .cb = nlattr_get_pf_timeout },
669
};
670
NL_DECLARE_ATTR_PARSER(timeout_parser, nla_p_timeouts);
671
#undef _OUT
672
673
static int
674
nlattr_get_nested_timeouts(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
675
{
676
struct nl_parsed_timeouts parsed_timeouts = { };
677
int error;
678
679
/* Assumes target points to the beginning of the structure */
680
error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &timeout_parser, npt, &parsed_timeouts);
681
if (error != 0)
682
return (error);
683
684
memcpy(target, parsed_timeouts.timeouts, sizeof(parsed_timeouts.timeouts));
685
686
return (0);
687
}
688
689
static bool
690
nlattr_add_timeout(struct nl_writer *nw, int attrtype, uint32_t *timeout)
691
{
692
int off = nlattr_add_nested(nw, attrtype);
693
694
if (off == 0)
695
return (false);
696
697
for (int i = 0; i < PFTM_MAX; i++)
698
nlattr_add_u32(nw, PF_RT_TIMEOUT, timeout[i]);
699
700
nlattr_set_len(nw, off);
701
702
return (true);
703
}
704
705
#define _OUT(_field) offsetof(struct pf_kthreshold, _field)
706
static const struct nlattr_parser nla_p_threshold[] = {
707
{ .type = PF_TH_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
708
{ .type = PF_TH_SECONDS, .off = _OUT(seconds), .cb = nlattr_get_uint32 },
709
};
710
NL_DECLARE_ATTR_PARSER(threshold_parser, nla_p_threshold);
711
#undef _OUT
712
713
#define _OUT(_field) offsetof(struct pf_krule, _field)
714
static const struct nlattr_parser nla_p_rule[] = {
715
{ .type = PF_RT_SRC, .off = _OUT(src), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
716
{ .type = PF_RT_DST, .off = _OUT(dst), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
717
{ .type = PF_RT_RIDENTIFIER, .off = _OUT(ridentifier), .cb = nlattr_get_uint32 },
718
{ .type = PF_RT_LABELS, .off = _OUT(label), .arg = &rule_labels_parser,.cb = nlattr_get_nested_pf_rule_labels },
719
{ .type = PF_RT_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
720
{ .type = PF_RT_QNAME, .off = _OUT(qname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
721
{ .type = PF_RT_PQNAME, .off = _OUT(pqname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
722
{ .type = PF_RT_TAGNAME, .off = _OUT(tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
723
{ .type = PF_RT_MATCH_TAGNAME, .off = _OUT(match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
724
{ .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
725
{ .type = PF_RT_RPOOL_RDR, .off = _OUT(rdr), .arg = &pool_parser, .cb = nlattr_get_nested },
726
{ .type = PF_RT_OS_FINGERPRINT, .off = _OUT(os_fingerprint), .cb = nlattr_get_uint32 },
727
{ .type = PF_RT_RTABLEID, .off = _OUT(rtableid), .cb = nlattr_get_uint32 },
728
{ .type = PF_RT_TIMEOUT, .off = _OUT(timeout), .arg = &timeout_parser, .cb = nlattr_get_nested_timeouts },
729
{ .type = PF_RT_MAX_STATES, .off = _OUT(max_states), .cb = nlattr_get_uint32 },
730
{ .type = PF_RT_MAX_SRC_NODES, .off = _OUT(max_src_nodes), .cb = nlattr_get_uint32 },
731
{ .type = PF_RT_MAX_SRC_STATES, .off = _OUT(max_src_states), .cb = nlattr_get_uint32 },
732
{ .type = PF_RT_MAX_SRC_CONN_RATE_LIMIT, .off = _OUT(max_src_conn_rate.limit), .cb = nlattr_get_uint32 },
733
{ .type = PF_RT_MAX_SRC_CONN_RATE_SECS, .off = _OUT(max_src_conn_rate.seconds), .cb = nlattr_get_uint32 },
734
{ .type = PF_RT_DNPIPE, .off = _OUT(dnpipe), .cb = nlattr_get_uint16 },
735
{ .type = PF_RT_DNRPIPE, .off = _OUT(dnrpipe), .cb = nlattr_get_uint16 },
736
{ .type = PF_RT_DNFLAGS, .off = _OUT(free_flags), .cb = nlattr_get_uint32 },
737
{ .type = PF_RT_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
738
{ .type = PF_RT_PROB, .off = _OUT(prob), .cb = nlattr_get_uint32 },
739
{ .type = PF_RT_CUID, .off = _OUT(cuid), .cb = nlattr_get_uint32 },
740
{. type = PF_RT_CPID, .off = _OUT(cpid), .cb = nlattr_get_uint32 },
741
{ .type = PF_RT_RETURN_ICMP, .off = _OUT(return_icmp), .cb = nlattr_get_uint16 },
742
{ .type = PF_RT_RETURN_ICMP6, .off = _OUT(return_icmp6), .cb = nlattr_get_uint16 },
743
{ .type = PF_RT_MAX_MSS, .off = _OUT(max_mss), .cb = nlattr_get_uint16 },
744
{ .type = PF_RT_SCRUB_FLAGS, .off = _OUT(scrub_flags), .cb = nlattr_get_uint16 },
745
{ .type = PF_RT_UID, .off = _OUT(uid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
746
{ .type = PF_RT_GID, .off = _OUT(gid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
747
{ .type = PF_RT_RULE_FLAG, .off = _OUT(rule_flag), .cb = nlattr_get_uint32 },
748
{ .type = PF_RT_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
749
{ .type = PF_RT_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
750
{ .type = PF_RT_LOG, .off = _OUT(log), .cb = nlattr_get_uint8 },
751
{ .type = PF_RT_LOGIF, .off = _OUT(logif), .cb = nlattr_get_uint8 },
752
{ .type = PF_RT_QUICK, .off = _OUT(quick), .cb = nlattr_get_uint8 },
753
{ .type = PF_RT_IF_NOT, .off = _OUT(ifnot), .cb = nlattr_get_uint8 },
754
{ .type = PF_RT_MATCH_TAG_NOT, .off = _OUT(match_tag_not), .cb = nlattr_get_uint8 },
755
{ .type = PF_RT_NATPASS, .off = _OUT(natpass), .cb = nlattr_get_uint8 },
756
{ .type = PF_RT_KEEP_STATE, .off = _OUT(keep_state), .cb = nlattr_get_uint8 },
757
{ .type = PF_RT_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
758
{ .type = PF_RT_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
759
{ .type = PF_RT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
760
{ .type = PF_RT_CODE, .off = _OUT(code), .cb = nlattr_get_uint8 },
761
{ .type = PF_RT_FLAGS, .off = _OUT(flags), .cb = nlattr_get_uint8 },
762
{ .type = PF_RT_FLAGSET, .off = _OUT(flagset), .cb = nlattr_get_uint8 },
763
{ .type = PF_RT_MIN_TTL, .off = _OUT(min_ttl), .cb = nlattr_get_uint8 },
764
{ .type = PF_RT_ALLOW_OPTS, .off = _OUT(allow_opts), .cb = nlattr_get_uint8 },
765
{ .type = PF_RT_RT, .off = _OUT(rt), .cb = nlattr_get_uint8 },
766
{ .type = PF_RT_RETURN_TTL, .off = _OUT(return_ttl), .cb = nlattr_get_uint8 },
767
{ .type = PF_RT_TOS, .off = _OUT(tos), .cb = nlattr_get_uint8 },
768
{ .type = PF_RT_SET_TOS, .off = _OUT(set_tos), .cb = nlattr_get_uint8 },
769
{ .type = PF_RT_ANCHOR_RELATIVE, .off = _OUT(anchor_relative), .cb = nlattr_get_uint8 },
770
{ .type = PF_RT_ANCHOR_WILDCARD, .off = _OUT(anchor_wildcard), .cb = nlattr_get_uint8 },
771
{ .type = PF_RT_FLUSH, .off = _OUT(flush), .cb = nlattr_get_uint8 },
772
{ .type = PF_RT_PRIO, .off = _OUT(prio), .cb = nlattr_get_uint8 },
773
{ .type = PF_RT_SET_PRIO, .off = _OUT(set_prio[0]), .cb = nlattr_get_uint8 },
774
{ .type = PF_RT_SET_PRIO_REPLY, .off = _OUT(set_prio[1]), .cb = nlattr_get_uint8 },
775
{ .type = PF_RT_DIVERT_ADDRESS, .off = _OUT(divert.addr), .cb = nlattr_get_in6_addr },
776
{ .type = PF_RT_DIVERT_PORT, .off = _OUT(divert.port), .cb = nlattr_get_uint16 },
777
{ .type = PF_RT_RCV_IFNAME, .off = _OUT(rcv_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
778
{ .type = PF_RT_MAX_SRC_CONN, .off = _OUT(max_src_conn), .cb = nlattr_get_uint32 },
779
{ .type = PF_RT_RPOOL_NAT, .off = _OUT(nat), .arg = &pool_parser, .cb = nlattr_get_nested },
780
{ .type = PF_RT_NAF, .off = _OUT(naf), .cb = nlattr_get_uint8 },
781
{ .type = PF_RT_RPOOL_RT, .off = _OUT(route), .arg = &pool_parser, .cb = nlattr_get_nested },
782
{ .type = PF_RT_RCV_IFNOT, .off = _OUT(rcvifnot), .cb = nlattr_get_bool },
783
{ .type = PF_RT_PKTRATE, .off = _OUT(pktrate), .arg = &threshold_parser, .cb = nlattr_get_nested },
784
{ .type = PF_RT_MAX_PKT_SIZE, .off = _OUT(max_pkt_size), .cb = nlattr_get_uint16 },
785
{ .type = PF_RT_TYPE_2, .off = _OUT(type), .cb = nlattr_get_uint16 },
786
{ .type = PF_RT_CODE_2, .off = _OUT(code), .cb = nlattr_get_uint16 },
787
{ .type = PF_RT_STATE_LIMIT, .off = _OUT(statelim.id), .cb = nlattr_get_uint8 },
788
{ .type = PF_RT_SOURCE_LIMIT, .off = _OUT(sourcelim.id), .cb = nlattr_get_uint8 },
789
{ .type = PF_RT_STATE_LIMIT_ACTION, .off = _OUT(statelim.limiter_action), .cb = nlattr_get_uint32 },
790
{ .type = PF_RT_SOURCE_LIMIT_ACTION, .off = _OUT(sourcelim.limiter_action), .cb = nlattr_get_uint32 },
791
};
792
NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule);
793
#undef _OUT
794
struct nl_parsed_addrule {
795
struct pf_krule *rule;
796
uint32_t ticket;
797
uint32_t pool_ticket;
798
char *anchor;
799
char *anchor_call;
800
};
801
#define _OUT(_field) offsetof(struct nl_parsed_addrule, _field)
802
static const struct nlattr_parser nla_p_addrule[] = {
803
{ .type = PF_ART_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
804
{ .type = PF_ART_POOL_TICKET, .off = _OUT(pool_ticket), .cb = nlattr_get_uint32 },
805
{ .type = PF_ART_ANCHOR, .off = _OUT(anchor), .cb = nlattr_get_string },
806
{ .type = PF_ART_ANCHOR_CALL, .off = _OUT(anchor_call), .cb = nlattr_get_string },
807
{ .type = PF_ART_RULE, .off = _OUT(rule), .arg = &rule_parser, .cb = nlattr_get_nested_ptr }
808
};
809
#undef _OUT
810
NL_DECLARE_PARSER(addrule_parser, struct genlmsghdr, nlf_p_empty, nla_p_addrule);
811
812
static int
813
pf_handle_addrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
814
{
815
int error;
816
struct nl_parsed_addrule attrs = {};
817
818
attrs.rule = pf_krule_alloc();
819
820
error = nl_parse_nlmsg(hdr, &addrule_parser, npt, &attrs);
821
if (error != 0) {
822
pf_free_rule(attrs.rule);
823
return (error);
824
}
825
826
error = pf_ioctl_addrule(attrs.rule, attrs.ticket, attrs.pool_ticket,
827
attrs.anchor, attrs.anchor_call, nlp_get_cred(npt->nlp)->cr_uid,
828
hdr->nlmsg_pid);
829
830
return (error);
831
}
832
833
#define _OUT(_field) offsetof(struct pfioc_rule, _field)
834
static const struct nlattr_parser nla_p_getrules[] = {
835
{ .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
836
{ .type = PF_GR_ACTION, .off = _OUT(rule.action), .cb = nlattr_get_uint8 },
837
};
838
#undef _OUT
839
NL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, nlf_p_empty, nla_p_getrules);
840
841
static int
842
pf_handle_getrules(struct nlmsghdr *hdr, struct nl_pstate *npt)
843
{
844
struct pfioc_rule attrs = {};
845
int error;
846
struct nl_writer *nw = npt->nw;
847
struct genlmsghdr *ghdr_new;
848
849
error = nl_parse_nlmsg(hdr, &getrules_parser, npt, &attrs);
850
if (error != 0)
851
return (error);
852
853
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
854
return (ENOMEM);
855
856
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
857
ghdr_new->cmd = PFNL_CMD_GETRULES;
858
859
error = pf_ioctl_getrules(&attrs);
860
if (error != 0)
861
goto out;
862
863
nlattr_add_u32(nw, PF_GR_NR, attrs.nr);
864
nlattr_add_u32(nw, PF_GR_TICKET, attrs.ticket);
865
866
if (!nlmsg_end(nw)) {
867
error = ENOMEM;
868
goto out;
869
}
870
871
return (0);
872
873
out:
874
nlmsg_abort(nw);
875
return (error);
876
}
877
878
struct nl_parsed_get_rule {
879
char anchor[MAXPATHLEN];
880
uint8_t action;
881
uint32_t nr;
882
uint32_t ticket;
883
uint8_t clear;
884
};
885
#define _OUT(_field) offsetof(struct nl_parsed_get_rule, _field)
886
static const struct nlattr_parser nla_p_getrule[] = {
887
{ .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
888
{ .type = PF_GR_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
889
{ .type = PF_GR_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
890
{ .type = PF_GR_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
891
{ .type = PF_GR_CLEAR, .off = _OUT(clear), .cb = nlattr_get_uint8 },
892
};
893
#undef _OUT
894
NL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, nlf_p_empty, nla_p_getrule);
895
896
static int
897
pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
898
{
899
char anchor_call[MAXPATHLEN];
900
struct nl_parsed_get_rule attrs = {};
901
struct nl_writer *nw = npt->nw;
902
struct genlmsghdr *ghdr_new;
903
struct pf_kruleset *ruleset;
904
struct pf_krule *rule;
905
u_int64_t src_nodes_total = 0;
906
int rs_num;
907
int error;
908
909
error = nl_parse_nlmsg(hdr, &getrule_parser, npt, &attrs);
910
if (error != 0)
911
return (error);
912
913
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
914
return (ENOMEM);
915
916
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
917
ghdr_new->cmd = PFNL_CMD_GETRULE;
918
919
PF_RULES_WLOCK();
920
ruleset = pf_find_kruleset(attrs.anchor);
921
if (ruleset == NULL) {
922
PF_RULES_WUNLOCK();
923
error = ENOENT;
924
goto out;
925
}
926
927
rs_num = pf_get_ruleset_number(attrs.action);
928
if (rs_num >= PF_RULESET_MAX) {
929
PF_RULES_WUNLOCK();
930
error = EINVAL;
931
goto out;
932
}
933
934
if (attrs.ticket != ruleset->rules[rs_num].active.ticket) {
935
PF_RULES_WUNLOCK();
936
error = EBUSY;
937
goto out;
938
}
939
940
rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
941
while ((rule != NULL) && (rule->nr != attrs.nr))
942
rule = TAILQ_NEXT(rule, entries);
943
if (rule == NULL) {
944
PF_RULES_WUNLOCK();
945
error = EBUSY;
946
goto out;
947
}
948
949
nlattr_add_rule_addr(nw, PF_RT_SRC, &rule->src);
950
nlattr_add_rule_addr(nw, PF_RT_DST, &rule->dst);
951
nlattr_add_u32(nw, PF_RT_RIDENTIFIER, rule->ridentifier);
952
nlattr_add_labels(nw, PF_RT_LABELS, rule);
953
nlattr_add_string(nw, PF_RT_IFNAME, rule->ifname);
954
nlattr_add_string(nw, PF_RT_QNAME, rule->qname);
955
nlattr_add_string(nw, PF_RT_PQNAME, rule->pqname);
956
nlattr_add_string(nw, PF_RT_TAGNAME, rule->tagname);
957
nlattr_add_string(nw, PF_RT_MATCH_TAGNAME, rule->match_tagname);
958
nlattr_add_string(nw, PF_RT_OVERLOAD_TBLNAME, rule->overload_tblname);
959
nlattr_add_pool(nw, PF_RT_RPOOL_RDR, &rule->rdr);
960
nlattr_add_pool(nw, PF_RT_RPOOL_NAT, &rule->nat);
961
nlattr_add_pool(nw, PF_RT_RPOOL_RT, &rule->route);
962
nlattr_add_u32(nw, PF_RT_OS_FINGERPRINT, rule->os_fingerprint);
963
nlattr_add_u32(nw, PF_RT_RTABLEID, rule->rtableid);
964
nlattr_add_timeout(nw, PF_RT_TIMEOUT, rule->timeout);
965
nlattr_add_u32(nw, PF_RT_MAX_STATES, rule->max_states);
966
nlattr_add_u32(nw, PF_RT_MAX_SRC_NODES, rule->max_src_nodes);
967
nlattr_add_u32(nw, PF_RT_MAX_SRC_STATES, rule->max_src_states);
968
nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN, rule->max_src_conn);
969
nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_LIMIT, rule->max_src_conn_rate.limit);
970
nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_SECS, rule->max_src_conn_rate.seconds);
971
nlattr_add_u16(nw, PF_RT_MAX_PKT_SIZE, rule->max_pkt_size);
972
973
nlattr_add_u16(nw, PF_RT_DNPIPE, rule->dnpipe);
974
nlattr_add_u16(nw, PF_RT_DNRPIPE, rule->dnrpipe);
975
nlattr_add_u32(nw, PF_RT_DNFLAGS, rule->free_flags);
976
977
nlattr_add_u32(nw, PF_RT_NR, rule->nr);
978
nlattr_add_u32(nw, PF_RT_PROB, rule->prob);
979
nlattr_add_u32(nw, PF_RT_CUID, rule->cuid);
980
nlattr_add_u32(nw, PF_RT_CPID, rule->cpid);
981
982
nlattr_add_u16(nw, PF_RT_RETURN_ICMP, rule->return_icmp);
983
nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
984
nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
985
nlattr_add_u16(nw, PF_RT_MAX_MSS, rule->max_mss);
986
nlattr_add_u16(nw, PF_RT_SCRUB_FLAGS, rule->scrub_flags);
987
988
nlattr_add_rule_uid(nw, PF_RT_UID, &rule->uid);
989
nlattr_add_rule_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&rule->gid);
990
991
nlattr_add_string(nw, PF_RT_RCV_IFNAME, rule->rcv_ifname);
992
nlattr_add_bool(nw, PF_RT_RCV_IFNOT, rule->rcvifnot);
993
994
nlattr_add_u32(nw, PF_RT_RULE_FLAG, rule->rule_flag);
995
nlattr_add_u8(nw, PF_RT_ACTION, rule->action);
996
nlattr_add_u8(nw, PF_RT_DIRECTION, rule->direction);
997
nlattr_add_u8(nw, PF_RT_LOG, rule->log);
998
nlattr_add_u8(nw, PF_RT_LOGIF, rule->logif);
999
nlattr_add_u8(nw, PF_RT_QUICK, rule->quick);
1000
nlattr_add_u8(nw, PF_RT_IF_NOT, rule->ifnot);
1001
nlattr_add_u8(nw, PF_RT_MATCH_TAG_NOT, rule->match_tag_not);
1002
nlattr_add_u8(nw, PF_RT_NATPASS, rule->natpass);
1003
nlattr_add_u8(nw, PF_RT_KEEP_STATE, rule->keep_state);
1004
1005
nlattr_add_u8(nw, PF_RT_AF, rule->af);
1006
nlattr_add_u8(nw, PF_RT_NAF, rule->naf);
1007
nlattr_add_u8(nw, PF_RT_PROTO, rule->proto);
1008
1009
nlattr_add_u8(nw, PF_RT_TYPE, rule->type);
1010
nlattr_add_u8(nw, PF_RT_CODE, rule->code);
1011
nlattr_add_u16(nw, PF_RT_TYPE_2, rule->type);
1012
nlattr_add_u16(nw, PF_RT_CODE_2, rule->code);
1013
1014
nlattr_add_u8(nw, PF_RT_FLAGS, rule->flags);
1015
nlattr_add_u8(nw, PF_RT_FLAGSET, rule->flagset);
1016
nlattr_add_u8(nw, PF_RT_MIN_TTL, rule->min_ttl);
1017
nlattr_add_u8(nw, PF_RT_ALLOW_OPTS, rule->allow_opts);
1018
nlattr_add_u8(nw, PF_RT_RT, rule->rt);
1019
nlattr_add_u8(nw, PF_RT_RETURN_TTL, rule->return_ttl);
1020
nlattr_add_u8(nw, PF_RT_TOS, rule->tos);
1021
nlattr_add_u8(nw, PF_RT_SET_TOS, rule->set_tos);
1022
nlattr_add_u8(nw, PF_RT_ANCHOR_RELATIVE, rule->anchor_relative);
1023
nlattr_add_u8(nw, PF_RT_ANCHOR_WILDCARD, rule->anchor_wildcard);
1024
nlattr_add_u8(nw, PF_RT_FLUSH, rule->flush);
1025
nlattr_add_u8(nw, PF_RT_PRIO, rule->prio);
1026
nlattr_add_u8(nw, PF_RT_SET_PRIO, rule->set_prio[0]);
1027
nlattr_add_u8(nw, PF_RT_SET_PRIO_REPLY, rule->set_prio[1]);
1028
1029
nlattr_add_in6_addr(nw, PF_RT_DIVERT_ADDRESS, &rule->divert.addr.v6);
1030
nlattr_add_u16(nw, PF_RT_DIVERT_PORT, rule->divert.port);
1031
1032
nlattr_add_u64(nw, PF_RT_PACKETS_IN, pf_counter_u64_fetch(&rule->packets[0]));
1033
nlattr_add_u64(nw, PF_RT_PACKETS_OUT, pf_counter_u64_fetch(&rule->packets[1]));
1034
nlattr_add_u64(nw, PF_RT_BYTES_IN, pf_counter_u64_fetch(&rule->bytes[0]));
1035
nlattr_add_u64(nw, PF_RT_BYTES_OUT, pf_counter_u64_fetch(&rule->bytes[1]));
1036
nlattr_add_u64(nw, PF_RT_EVALUATIONS, pf_counter_u64_fetch(&rule->evaluations));
1037
nlattr_add_u64(nw, PF_RT_TIMESTAMP, pf_get_timestamp(rule));
1038
nlattr_add_u64(nw, PF_RT_STATES_CUR, counter_u64_fetch(rule->states_cur));
1039
nlattr_add_u64(nw, PF_RT_STATES_TOTAL, counter_u64_fetch(rule->states_tot));
1040
for (pf_sn_types_t sn_type=0; sn_type<PF_SN_MAX; sn_type++)
1041
src_nodes_total += counter_u64_fetch(rule->src_nodes[sn_type]);
1042
nlattr_add_u64(nw, PF_RT_SRC_NODES, src_nodes_total);
1043
nlattr_add_u64(nw, PF_RT_SRC_NODES_LIMIT, counter_u64_fetch(rule->src_nodes[PF_SN_LIMIT]));
1044
nlattr_add_u64(nw, PF_RT_SRC_NODES_NAT, counter_u64_fetch(rule->src_nodes[PF_SN_NAT]));
1045
nlattr_add_u64(nw, PF_RT_SRC_NODES_ROUTE, counter_u64_fetch(rule->src_nodes[PF_SN_ROUTE]));
1046
nlattr_add_pf_threshold(nw, PF_RT_PKTRATE, &rule->pktrate);
1047
nlattr_add_time_t(nw, PF_RT_EXPTIME, time_second - (time_uptime - rule->exptime));
1048
nlattr_add_u8(nw, PF_RT_STATE_LIMIT, rule->statelim.id);
1049
nlattr_add_u32(nw, PF_RT_STATE_LIMIT_ACTION, rule->statelim.limiter_action);
1050
nlattr_add_u8(nw, PF_RT_SOURCE_LIMIT, rule->sourcelim.id);
1051
nlattr_add_u32(nw, PF_RT_SOURCE_LIMIT_ACTION, rule->sourcelim.limiter_action);
1052
1053
error = pf_kanchor_copyout(ruleset, rule, anchor_call, sizeof(anchor_call));
1054
MPASS(error == 0);
1055
1056
nlattr_add_string(nw, PF_RT_ANCHOR_CALL, anchor_call);
1057
1058
if (attrs.clear)
1059
pf_krule_clear_counters(rule);
1060
1061
PF_RULES_WUNLOCK();
1062
1063
if (!nlmsg_end(nw)) {
1064
error = ENOMEM;
1065
goto out;
1066
}
1067
1068
return (0);
1069
out:
1070
nlmsg_abort(nw);
1071
return (error);
1072
}
1073
1074
#define _OUT(_field) offsetof(struct pf_kstate_kill, _field)
1075
static const struct nlattr_parser nla_p_clear_states[] = {
1076
{ .type = PF_CS_CMP_ID, .off = _OUT(psk_pfcmp.id), .cb = nlattr_get_uint64 },
1077
{ .type = PF_CS_CMP_CREATORID, .off = _OUT(psk_pfcmp.creatorid), .cb = nlattr_get_uint32 },
1078
{ .type = PF_CS_CMP_DIR, .off = _OUT(psk_pfcmp.direction), .cb = nlattr_get_uint8 },
1079
{ .type = PF_CS_AF, .off = _OUT(psk_af), .cb = nlattr_get_uint8 },
1080
{ .type = PF_CS_PROTO, .off = _OUT(psk_proto), .cb = nlattr_get_uint8 },
1081
{ .type = PF_CS_SRC, .off = _OUT(psk_src), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1082
{ .type = PF_CS_DST, .off = _OUT(psk_dst), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1083
{ .type = PF_CS_RT_ADDR, .off = _OUT(psk_rt_addr), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1084
{ .type = PF_CS_IFNAME, .off = _OUT(psk_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
1085
{ .type = PF_CS_LABEL, .off = _OUT(psk_label), .arg = (void *)PF_RULE_LABEL_SIZE, .cb = nlattr_get_chara },
1086
{ .type = PF_CS_KILL_MATCH, .off = _OUT(psk_kill_match), .cb = nlattr_get_bool },
1087
{ .type = PF_CS_NAT, .off = _OUT(psk_nat), .cb = nlattr_get_bool },
1088
};
1089
#undef _OUT
1090
NL_DECLARE_PARSER(clear_states_parser, struct genlmsghdr, nlf_p_empty, nla_p_clear_states);
1091
1092
static int
1093
pf_handle_killclear_states(struct nlmsghdr *hdr, struct nl_pstate *npt, int cmd)
1094
{
1095
struct pf_kstate_kill kill = {};
1096
struct epoch_tracker et;
1097
struct nl_writer *nw = npt->nw;
1098
struct genlmsghdr *ghdr_new;
1099
int error;
1100
unsigned int killed = 0;
1101
1102
error = nl_parse_nlmsg(hdr, &clear_states_parser, npt, &kill);
1103
if (error != 0)
1104
return (error);
1105
1106
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1107
return (ENOMEM);
1108
1109
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1110
ghdr_new->cmd = cmd;
1111
1112
NET_EPOCH_ENTER(et);
1113
if (cmd == PFNL_CMD_KILLSTATES)
1114
pf_killstates(&kill, &killed);
1115
else
1116
killed = pf_clear_states(&kill);
1117
NET_EPOCH_EXIT(et);
1118
1119
nlattr_add_u32(nw, PF_CS_KILLED, killed);
1120
1121
if (! nlmsg_end(nw)) {
1122
error = ENOMEM;
1123
goto out;
1124
}
1125
1126
return (0);
1127
1128
out:
1129
nlmsg_abort(nw);
1130
return (error);
1131
}
1132
1133
static int
1134
pf_handle_clear_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
1135
{
1136
return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_CLRSTATES));
1137
}
1138
1139
static int
1140
pf_handle_kill_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
1141
{
1142
return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_KILLSTATES));
1143
}
1144
1145
struct nl_parsed_set_statusif {
1146
char ifname[IFNAMSIZ];
1147
};
1148
#define _OUT(_field) offsetof(struct nl_parsed_set_statusif, _field)
1149
static const struct nlattr_parser nla_p_set_statusif[] = {
1150
{ .type = PF_SS_IFNAME, .off = _OUT(ifname), .arg = (const void *)IFNAMSIZ, .cb = nlattr_get_chara },
1151
};
1152
#undef _OUT
1153
NL_DECLARE_PARSER(set_statusif_parser, struct genlmsghdr, nlf_p_empty, nla_p_set_statusif);
1154
1155
static int
1156
pf_handle_set_statusif(struct nlmsghdr *hdr, struct nl_pstate *npt)
1157
{
1158
int error;
1159
struct nl_parsed_set_statusif attrs = {};
1160
1161
error = nl_parse_nlmsg(hdr, &set_statusif_parser, npt, &attrs);
1162
if (error != 0)
1163
return (error);
1164
1165
PF_RULES_WLOCK();
1166
strlcpy(V_pf_status.ifname, attrs.ifname, IFNAMSIZ);
1167
PF_RULES_WUNLOCK();
1168
1169
return (0);
1170
}
1171
1172
static bool
1173
nlattr_add_counters(struct nl_writer *nw, int attr, size_t number, char **names,
1174
counter_u64_t *counters)
1175
{
1176
for (int i = 0; i < number; i++) {
1177
int off = nlattr_add_nested(nw, attr);
1178
1179
if (off == 0)
1180
return (false);
1181
1182
nlattr_add_u32(nw, PF_C_ID, i);
1183
nlattr_add_string(nw, PF_C_NAME, names[i]);
1184
nlattr_add_u64(nw, PF_C_COUNTER, counter_u64_fetch(counters[i]));
1185
nlattr_set_len(nw, off);
1186
}
1187
1188
return (true);
1189
}
1190
1191
static bool
1192
nlattr_add_fcounters(struct nl_writer *nw, int attr, size_t number, char **names,
1193
struct pf_counter_u64 *counters)
1194
{
1195
for (int i = 0; i < number; i++) {
1196
int off = nlattr_add_nested(nw, attr);
1197
1198
if (off == 0)
1199
return (false);
1200
1201
nlattr_add_u32(nw, PF_C_ID, i);
1202
nlattr_add_string(nw, PF_C_NAME, names[i]);
1203
nlattr_add_u64(nw, PF_C_COUNTER, pf_counter_u64_fetch(&counters[i]));
1204
nlattr_set_len(nw, off);
1205
}
1206
1207
return (true);
1208
}
1209
1210
static bool
1211
nlattr_add_u64_array(struct nl_writer *nw, int attr, size_t number, const uint64_t *array)
1212
{
1213
int off = nlattr_add_nested(nw, attr);
1214
1215
if (off == 0)
1216
return (false);
1217
1218
for (size_t i = 0; i < number; i++)
1219
nlattr_add_u64(nw, 0, array[i]);
1220
1221
nlattr_set_len(nw, off);
1222
1223
return (true);
1224
}
1225
1226
static int
1227
pf_handle_get_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
1228
{
1229
struct pf_status s;
1230
struct nl_writer *nw = npt->nw;
1231
struct genlmsghdr *ghdr_new;
1232
char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
1233
char *pf_lcounter[KLCNT_MAX+1] = KLCNT_NAMES;
1234
char *pf_fcounter[FCNT_MAX+1] = FCNT_NAMES;
1235
time_t since;
1236
int error;
1237
1238
PF_RULES_RLOCK_TRACKER;
1239
1240
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1241
return (ENOMEM);
1242
1243
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1244
ghdr_new->cmd = PFNL_CMD_GET_STATUS;
1245
1246
since = time_second - (time_uptime - V_pf_status.since);
1247
1248
PF_RULES_RLOCK();
1249
1250
nlattr_add_string(nw, PF_GS_IFNAME, V_pf_status.ifname);
1251
nlattr_add_bool(nw, PF_GS_RUNNING, V_pf_status.running);
1252
nlattr_add_u32(nw, PF_GS_SINCE, since);
1253
nlattr_add_u32(nw, PF_GS_DEBUG, V_pf_status.debug);
1254
nlattr_add_u32(nw, PF_GS_HOSTID, ntohl(V_pf_status.hostid));
1255
nlattr_add_u32(nw, PF_GS_STATES, V_pf_status.states);
1256
nlattr_add_u32(nw, PF_GS_SRC_NODES, V_pf_status.src_nodes);
1257
nlattr_add_u32(nw, PF_GS_REASSEMBLE, V_pf_status.reass);
1258
nlattr_add_u32(nw, PF_GS_SYNCOOKIES_ACTIVE, V_pf_status.syncookies_active);
1259
1260
nlattr_add_counters(nw, PF_GS_COUNTERS, PFRES_MAX, pf_reasons,
1261
V_pf_status.counters);
1262
nlattr_add_counters(nw, PF_GS_LCOUNTERS, KLCNT_MAX, pf_lcounter,
1263
V_pf_status.lcounters);
1264
nlattr_add_fcounters(nw, PF_GS_FCOUNTERS, FCNT_MAX, pf_fcounter,
1265
V_pf_status.fcounters);
1266
nlattr_add_counters(nw, PF_GS_SCOUNTERS, SCNT_MAX, pf_fcounter,
1267
V_pf_status.scounters);
1268
nlattr_add_counters(nw, PF_GS_NCOUNTERS, NCNT_MAX, pf_fcounter,
1269
V_pf_status.ncounters);
1270
nlattr_add_u64(nw, PF_GS_FRAGMENTS, pf_normalize_get_frag_count());
1271
1272
pfi_update_status(V_pf_status.ifname, &s);
1273
nlattr_add_u64_array(nw, PF_GS_BCOUNTERS, 2 * 2, (uint64_t *)s.bcounters);
1274
nlattr_add_u64_array(nw, PF_GS_PCOUNTERS, 2 * 2 * 2, (uint64_t *)s.pcounters);
1275
1276
nlattr_add(nw, PF_GS_CHKSUM, PF_MD5_DIGEST_LENGTH, V_pf_status.pf_chksum);
1277
1278
PF_RULES_RUNLOCK();
1279
1280
if (!nlmsg_end(nw)) {
1281
error = ENOMEM;
1282
goto out;
1283
}
1284
1285
return (0);
1286
1287
out:
1288
nlmsg_abort(nw);
1289
return (error);
1290
}
1291
1292
static int
1293
pf_handle_clear_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
1294
{
1295
pf_ioctl_clear_status();
1296
1297
return (0);
1298
}
1299
1300
#define _OUT(_field) offsetof(struct pfioc_natlook, _field)
1301
static const struct nlattr_parser nla_p_natlook[] = {
1302
{ .type = PF_NL_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
1303
{ .type = PF_NL_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
1304
{ .type = PF_NL_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
1305
{ .type = PF_NL_SRC_ADDR, .off = _OUT(saddr), .cb = nlattr_get_in6_addr },
1306
{ .type = PF_NL_DST_ADDR, .off = _OUT(daddr), .cb = nlattr_get_in6_addr },
1307
{ .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = nlattr_get_uint16 },
1308
{ .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = nlattr_get_uint16 },
1309
};
1310
#undef _OUT
1311
NL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, nlf_p_empty, nla_p_natlook);
1312
1313
static int
1314
pf_handle_natlook(struct nlmsghdr *hdr, struct nl_pstate *npt)
1315
{
1316
struct pfioc_natlook attrs = {};
1317
struct nl_writer *nw = npt->nw;
1318
struct genlmsghdr *ghdr_new;
1319
int error;
1320
1321
error = nl_parse_nlmsg(hdr, &natlook_parser, npt, &attrs);
1322
if (error != 0)
1323
return (error);
1324
1325
error = pf_ioctl_natlook(&attrs);
1326
if (error != 0)
1327
return (error);
1328
1329
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1330
return (ENOMEM);
1331
1332
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1333
ghdr_new->cmd = PFNL_CMD_NATLOOK;
1334
1335
nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &attrs.rsaddr.v6);
1336
nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &attrs.rdaddr.v6);
1337
nlattr_add_u16(nw, PF_NL_SRC_PORT, attrs.rsport);
1338
nlattr_add_u16(nw, PF_NL_DST_PORT, attrs.rdport);
1339
1340
if (!nlmsg_end(nw)) {
1341
nlmsg_abort(nw);
1342
return (ENOMEM);
1343
}
1344
1345
return (0);
1346
}
1347
1348
struct pf_nl_set_debug
1349
{
1350
uint32_t level;
1351
};
1352
#define _OUT(_field) offsetof(struct pf_nl_set_debug, _field)
1353
static const struct nlattr_parser nla_p_set_debug[] = {
1354
{ .type = PF_SD_LEVEL, .off = _OUT(level), .cb = nlattr_get_uint32 },
1355
};
1356
#undef _OUT
1357
NL_DECLARE_PARSER(set_debug_parser, struct genlmsghdr, nlf_p_empty, nla_p_set_debug);
1358
1359
static int
1360
pf_handle_set_debug(struct nlmsghdr *hdr, struct nl_pstate *npt)
1361
{
1362
struct pf_nl_set_debug attrs = {};
1363
int error;
1364
1365
error = nl_parse_nlmsg(hdr, &set_debug_parser, npt, &attrs);
1366
if (error != 0)
1367
return (error);
1368
1369
PF_RULES_WLOCK();
1370
V_pf_status.debug = attrs.level;
1371
PF_RULES_WUNLOCK();
1372
1373
return (0);
1374
}
1375
1376
struct pf_nl_set_timeout
1377
{
1378
uint32_t timeout;
1379
uint32_t seconds;
1380
};
1381
#define _OUT(_field) offsetof(struct pf_nl_set_timeout, _field)
1382
static const struct nlattr_parser nla_p_set_timeout[] = {
1383
{ .type = PF_TO_TIMEOUT, .off = _OUT(timeout), .cb = nlattr_get_uint32 },
1384
{ .type = PF_TO_SECONDS, .off = _OUT(seconds), .cb = nlattr_get_uint32 },
1385
};
1386
#undef _OUT
1387
NL_DECLARE_PARSER(set_timeout_parser, struct genlmsghdr, nlf_p_empty, nla_p_set_timeout);
1388
1389
static int
1390
pf_handle_set_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
1391
{
1392
struct pf_nl_set_timeout attrs = {};
1393
int error;
1394
1395
error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
1396
if (error != 0)
1397
return (error);
1398
1399
return (pf_ioctl_set_timeout(attrs.timeout, attrs.seconds, NULL));
1400
}
1401
1402
static int
1403
pf_handle_get_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
1404
{
1405
struct pf_nl_set_timeout attrs = {};
1406
struct nl_writer *nw = npt->nw;
1407
struct genlmsghdr *ghdr_new;
1408
int error;
1409
1410
error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
1411
if (error != 0)
1412
return (error);
1413
1414
error = pf_ioctl_get_timeout(attrs.timeout, &attrs.seconds);
1415
if (error != 0)
1416
return (error);
1417
1418
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1419
return (ENOMEM);
1420
1421
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1422
ghdr_new->cmd = PFNL_CMD_GET_TIMEOUT;
1423
1424
nlattr_add_u32(nw, PF_TO_SECONDS, attrs.seconds);
1425
1426
if (!nlmsg_end(nw)) {
1427
nlmsg_abort(nw);
1428
return (ENOMEM);
1429
}
1430
1431
return (0);
1432
}
1433
1434
struct pf_nl_set_limit
1435
{
1436
uint32_t index;
1437
uint32_t limit;
1438
};
1439
#define _OUT(_field) offsetof(struct pf_nl_set_limit, _field)
1440
static const struct nlattr_parser nla_p_set_limit[] = {
1441
{ .type = PF_LI_INDEX, .off = _OUT(index), .cb = nlattr_get_uint32 },
1442
{ .type = PF_LI_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
1443
};
1444
#undef _OUT
1445
NL_DECLARE_PARSER(set_limit_parser, struct genlmsghdr, nlf_p_empty, nla_p_set_limit);
1446
1447
static int
1448
pf_handle_set_limit(struct nlmsghdr *hdr, struct nl_pstate *npt)
1449
{
1450
struct pf_nl_set_limit attrs = {};
1451
int error;
1452
1453
error = nl_parse_nlmsg(hdr, &set_limit_parser, npt, &attrs);
1454
if (error != 0)
1455
return (error);
1456
1457
return (pf_ioctl_set_limit(attrs.index, attrs.limit, NULL));
1458
}
1459
1460
static int
1461
pf_handle_get_limit(struct nlmsghdr *hdr, struct nl_pstate *npt)
1462
{
1463
struct pf_nl_set_limit attrs = {};
1464
struct nl_writer *nw = npt->nw;
1465
struct genlmsghdr *ghdr_new;
1466
int error;
1467
1468
error = nl_parse_nlmsg(hdr, &set_limit_parser, npt, &attrs);
1469
if (error != 0)
1470
return (error);
1471
1472
error = pf_ioctl_get_limit(attrs.index, &attrs.limit);
1473
if (error != 0)
1474
return (error);
1475
1476
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1477
return (ENOMEM);
1478
1479
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1480
ghdr_new->cmd = PFNL_CMD_GET_LIMIT;
1481
1482
nlattr_add_u32(nw, PF_LI_LIMIT, attrs.limit);
1483
1484
if (!nlmsg_end(nw)) {
1485
nlmsg_abort(nw);
1486
return (ENOMEM);
1487
}
1488
1489
return (0);
1490
}
1491
1492
static int
1493
pf_handle_begin_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
1494
{
1495
struct nl_writer *nw = npt->nw;
1496
struct genlmsghdr *ghdr_new;
1497
uint32_t ticket;
1498
int error;
1499
1500
error = pf_ioctl_begin_addrs(&ticket);
1501
if (error != 0)
1502
return (error);
1503
1504
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1505
return (ENOMEM);
1506
1507
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1508
ghdr_new->cmd = PFNL_CMD_BEGIN_ADDRS;
1509
1510
nlattr_add_u32(nw, PF_BA_TICKET, ticket);
1511
1512
if (!nlmsg_end(nw)) {
1513
nlmsg_abort(nw);
1514
return (ENOMEM);
1515
}
1516
1517
return (0);
1518
}
1519
1520
static bool
1521
nlattr_add_pool_addr(struct nl_writer *nw, int attrtype, struct pf_pooladdr *a)
1522
{
1523
int off;
1524
1525
off = nlattr_add_nested(nw, attrtype);
1526
1527
if (off == 0)
1528
return (false);
1529
1530
nlattr_add_addr_wrap(nw, PF_PA_ADDR, &a->addr);
1531
nlattr_add_string(nw, PF_PA_IFNAME, a->ifname);
1532
1533
nlattr_set_len(nw, off);
1534
1535
return (true);
1536
}
1537
1538
#define _OUT(_field) offsetof(struct pf_pooladdr, _field)
1539
static const struct nlattr_parser nla_p_pool_addr[] = {
1540
{ .type = PF_PA_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
1541
{ .type = PF_PA_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
1542
};
1543
NL_DECLARE_ATTR_PARSER(pool_addr_parser, nla_p_pool_addr);
1544
#undef _OUT
1545
1546
#define _OUT(_field) offsetof(struct pf_nl_pooladdr, _field)
1547
static const struct nlattr_parser nla_p_add_addr[] = {
1548
{ .type = PF_AA_ACTION, .off = _OUT(action), .cb = nlattr_get_uint32 },
1549
{ .type = PF_AA_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
1550
{ .type = PF_AA_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
1551
{ .type = PF_AA_R_NUM, .off = _OUT(r_num), .cb = nlattr_get_uint32 },
1552
{ .type = PF_AA_R_ACTION, .off = _OUT(r_action), .cb = nlattr_get_uint8 },
1553
{ .type = PF_AA_R_LAST, .off = _OUT(r_last), .cb = nlattr_get_uint8 },
1554
{ .type = PF_AA_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
1555
{ .type = PF_AA_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
1556
{ .type = PF_AA_ADDR, .off = _OUT(addr), .arg = &pool_addr_parser, .cb = nlattr_get_nested },
1557
{ .type = PF_AA_WHICH, .off = _OUT(which), .cb = nlattr_get_uint32 },
1558
};
1559
#undef _OUT
1560
NL_DECLARE_PARSER(add_addr_parser, struct genlmsghdr, nlf_p_empty, nla_p_add_addr);
1561
1562
static int
1563
pf_handle_add_addr(struct nlmsghdr *hdr, struct nl_pstate *npt)
1564
{
1565
struct pf_nl_pooladdr attrs = { 0 };
1566
int error;
1567
1568
error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
1569
if (error != 0)
1570
return (error);
1571
1572
if (attrs.which == 0)
1573
attrs.which = PF_RDR;
1574
1575
error = pf_ioctl_add_addr(&attrs);
1576
1577
return (error);
1578
}
1579
1580
static int
1581
pf_handle_get_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
1582
{
1583
struct pf_nl_pooladdr attrs = { 0 };
1584
struct nl_writer *nw = npt->nw;
1585
struct genlmsghdr *ghdr_new;
1586
int error;
1587
1588
error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
1589
if (error != 0)
1590
return (error);
1591
1592
if (attrs.which == 0)
1593
attrs.which = PF_RDR;
1594
1595
error = pf_ioctl_get_addrs(&attrs);
1596
if (error != 0)
1597
return (error);
1598
1599
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1600
return (ENOMEM);
1601
1602
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1603
ghdr_new->cmd = PFNL_CMD_GET_ADDRS;
1604
1605
nlattr_add_u32(nw, PF_AA_NR, attrs.nr);
1606
1607
if (!nlmsg_end(nw)) {
1608
nlmsg_abort(nw);
1609
return (ENOMEM);
1610
}
1611
1612
return (error);
1613
}
1614
1615
static int
1616
pf_handle_get_addr(struct nlmsghdr *hdr, struct nl_pstate *npt)
1617
{
1618
struct pf_nl_pooladdr attrs = { 0 };
1619
struct nl_writer *nw = npt->nw;
1620
struct genlmsghdr *ghdr_new;
1621
int error;
1622
1623
error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
1624
if (error != 0)
1625
return (error);
1626
1627
if (attrs.which == 0)
1628
attrs.which = PF_RDR;
1629
1630
error = pf_ioctl_get_addr(&attrs);
1631
if (error != 0)
1632
return (error);
1633
1634
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1635
return (ENOMEM);
1636
1637
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1638
ghdr_new->cmd = PFNL_CMD_GET_ADDR;
1639
1640
nlattr_add_u32(nw, PF_AA_ACTION, attrs.action);
1641
nlattr_add_u32(nw, PF_AA_TICKET, attrs.ticket);
1642
nlattr_add_u32(nw, PF_AA_NR, attrs.nr);
1643
nlattr_add_u32(nw, PF_AA_R_NUM, attrs.r_num);
1644
nlattr_add_u8(nw, PF_AA_R_ACTION, attrs.r_action);
1645
nlattr_add_u8(nw, PF_AA_R_LAST, attrs.r_last);
1646
nlattr_add_u8(nw, PF_AA_AF, attrs.af);
1647
nlattr_add_string(nw, PF_AA_ANCHOR, attrs.anchor);
1648
nlattr_add_pool_addr(nw, PF_AA_ADDR, &attrs.addr);
1649
1650
if (!nlmsg_end(nw)) {
1651
nlmsg_abort(nw);
1652
return (ENOMEM);
1653
}
1654
1655
return (0);
1656
}
1657
1658
#define _OUT(_field) offsetof(struct pfioc_ruleset, _field)
1659
static const struct nlattr_parser nla_p_ruleset[] = {
1660
{ .type = PF_RS_PATH, .off = _OUT(path), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
1661
{ .type = PF_RS_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
1662
};
1663
NL_DECLARE_PARSER(ruleset_parser, struct genlmsghdr, nlf_p_empty, nla_p_ruleset);
1664
#undef _OUT
1665
1666
static int
1667
pf_handle_get_rulesets(struct nlmsghdr *hdr, struct nl_pstate *npt)
1668
{
1669
struct pfioc_ruleset attrs = { 0 };
1670
struct nl_writer *nw = npt->nw;
1671
struct genlmsghdr *ghdr_new;
1672
int error;
1673
1674
error = nl_parse_nlmsg(hdr, &ruleset_parser, npt, &attrs);
1675
if (error != 0)
1676
return (error);
1677
1678
error = pf_ioctl_get_rulesets(&attrs);
1679
if (error != 0)
1680
return (error);
1681
1682
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1683
return (ENOMEM);
1684
1685
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1686
ghdr_new->cmd = PFNL_CMD_GET_RULESETS;
1687
1688
nlattr_add_u32(nw, PF_RS_NR, attrs.nr);
1689
1690
if (!nlmsg_end(nw)) {
1691
nlmsg_abort(nw);
1692
return (ENOMEM);
1693
}
1694
1695
return (0);
1696
}
1697
1698
static int
1699
pf_handle_get_ruleset(struct nlmsghdr *hdr, struct nl_pstate *npt)
1700
{
1701
struct pfioc_ruleset attrs = { 0 };
1702
struct nl_writer *nw = npt->nw;
1703
struct genlmsghdr *ghdr_new;
1704
int error;
1705
1706
error = nl_parse_nlmsg(hdr, &ruleset_parser, npt, &attrs);
1707
if (error)
1708
return (error);
1709
1710
error = pf_ioctl_get_ruleset(&attrs);
1711
if (error != 0)
1712
return (error);
1713
1714
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1715
return (ENOMEM);
1716
1717
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1718
ghdr_new->cmd = PFNL_CMD_GET_RULESET;
1719
1720
nlattr_add_string(nw, PF_RS_NAME, attrs.name);
1721
1722
if (!nlmsg_end(nw)) {
1723
nlmsg_abort(nw);
1724
return (ENOMEM);
1725
}
1726
1727
return (0);
1728
}
1729
1730
static bool
1731
nlattr_add_pf_threshold(struct nl_writer *nw, int attrtype,
1732
struct pf_kthreshold *t)
1733
{
1734
int off = nlattr_add_nested(nw, attrtype);
1735
int conn_rate_count = 0;
1736
1737
if (off == 0)
1738
return (false);
1739
1740
/* Adjust the connection rate estimate. */
1741
if (t->cr != NULL)
1742
conn_rate_count = counter_rate_get(t->cr);
1743
1744
nlattr_add_u32(nw, PF_TH_LIMIT, t->limit);
1745
nlattr_add_u32(nw, PF_TH_SECONDS, t->seconds);
1746
nlattr_add_u32(nw, PF_TH_COUNT, conn_rate_count);
1747
1748
nlattr_set_len(nw, off);
1749
1750
return (true);
1751
}
1752
1753
static int
1754
pf_handle_get_srcnodes(struct nlmsghdr *hdr, struct nl_pstate *npt)
1755
{
1756
struct nl_writer *nw = npt->nw;
1757
struct genlmsghdr *ghdr_new;
1758
struct pf_ksrc_node *n;
1759
struct pf_srchash *sh;
1760
int i;
1761
int secs;
1762
1763
hdr->nlmsg_flags |= NLM_F_MULTI;
1764
1765
for (i = 0, sh = V_pf_srchash; i <= V_pf_srchashmask;
1766
i++, sh++) {
1767
/* Avoid locking empty rows. */
1768
if (LIST_EMPTY(&sh->nodes))
1769
continue;
1770
1771
PF_HASHROW_LOCK(sh);
1772
secs = time_uptime;
1773
1774
LIST_FOREACH(n, &sh->nodes, entry) {
1775
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
1776
nlmsg_abort(nw);
1777
return (ENOMEM);
1778
}
1779
1780
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1781
ghdr_new->cmd = PFNL_CMD_GET_SRCNODES;
1782
1783
nlattr_add_in6_addr(nw, PF_SN_ADDR, &n->addr.v6);
1784
nlattr_add_in6_addr(nw, PF_SN_RADDR, &n->raddr.v6);
1785
nlattr_add_u32(nw, PF_SN_RULE_NR, n->rule->nr);
1786
nlattr_add_u64(nw, PF_SN_BYTES_IN, counter_u64_fetch(n->bytes[0]));
1787
nlattr_add_u64(nw, PF_SN_BYTES_OUT, counter_u64_fetch(n->bytes[1]));
1788
nlattr_add_u64(nw, PF_SN_PACKETS_IN, counter_u64_fetch(n->packets[0]));
1789
nlattr_add_u64(nw, PF_SN_PACKETS_OUT, counter_u64_fetch(n->packets[1]));
1790
nlattr_add_u32(nw, PF_SN_STATES, n->states);
1791
nlattr_add_u32(nw, PF_SN_CONNECTIONS, n->conn);
1792
nlattr_add_u8(nw, PF_SN_AF, n->af);
1793
nlattr_add_u8(nw, PF_SN_RAF, n->raf);
1794
nlattr_add_u8(nw, PF_SN_RULE_TYPE, n->ruletype);
1795
1796
nlattr_add_u64(nw, PF_SN_CREATION, secs - n->creation);
1797
if (n->expire > secs)
1798
nlattr_add_u64(nw, PF_SN_EXPIRE, n->expire - secs);
1799
else
1800
nlattr_add_u64(nw, PF_SN_EXPIRE, 0);
1801
1802
nlattr_add_pf_threshold(nw, PF_SN_CONNECTION_RATE,
1803
&n->conn_rate);
1804
1805
nlattr_add_u8(nw, PF_SN_NODE_TYPE, n->type);
1806
1807
if (!nlmsg_end(nw)) {
1808
PF_HASHROW_UNLOCK(sh);
1809
nlmsg_abort(nw);
1810
return (ENOMEM);
1811
}
1812
}
1813
PF_HASHROW_UNLOCK(sh);
1814
}
1815
1816
return (0);
1817
}
1818
1819
#define _OUT(_field) offsetof(struct pfioc_table, _field)
1820
static const struct nlattr_parser nla_p_table[] = {
1821
{ .type = PF_T_ANCHOR, .off = _OUT(pfrio_table.pfrt_anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
1822
{ .type = PF_T_NAME, .off = _OUT(pfrio_table.pfrt_name), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
1823
{ .type = PF_T_TABLE_FLAGS, .off = _OUT(pfrio_table.pfrt_flags), .cb = nlattr_get_uint32 },
1824
{ .type = PF_T_FLAGS, .off = _OUT(pfrio_flags), .cb = nlattr_get_uint32 },
1825
};
1826
static const struct nlfield_parser nlf_p_table[] = {};
1827
NL_DECLARE_PARSER(table_parser, struct genlmsghdr, nlf_p_table, nla_p_table);
1828
#undef _OUT
1829
static int
1830
pf_handle_clear_tables(struct nlmsghdr *hdr, struct nl_pstate *npt)
1831
{
1832
struct pfioc_table attrs = { 0 };
1833
struct nl_writer *nw = npt->nw;
1834
struct genlmsghdr *ghdr_new;
1835
int ndel = 0;
1836
int error;
1837
1838
error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
1839
if (error != 0)
1840
return (error);
1841
1842
PF_RULES_WLOCK();
1843
error = pfr_clr_tables(&attrs.pfrio_table, &ndel, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
1844
PF_RULES_WUNLOCK();
1845
if (error != 0)
1846
return (error);
1847
1848
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1849
return (ENOMEM);
1850
1851
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1852
ghdr_new->cmd = PFNL_CMD_CLEAR_TABLES;
1853
1854
nlattr_add_u32(nw, PF_T_NBR_DELETED, ndel);
1855
1856
if (!nlmsg_end(nw)) {
1857
nlmsg_abort(nw);
1858
return (ENOMEM);
1859
}
1860
1861
return (0);
1862
}
1863
1864
static int
1865
pf_handle_add_table(struct nlmsghdr *hdr, struct nl_pstate *npt)
1866
{
1867
struct pfioc_table attrs = { 0 };
1868
struct nl_writer *nw = npt->nw;
1869
struct genlmsghdr *ghdr_new;
1870
int error;
1871
1872
error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
1873
if (error != 0)
1874
return (error);
1875
1876
PF_RULES_WLOCK();
1877
error = pfr_add_tables(&attrs.pfrio_table, 1, &attrs.pfrio_nadd,
1878
attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
1879
PF_RULES_WUNLOCK();
1880
if (error != 0)
1881
return (error);
1882
1883
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1884
return (ENOMEM);
1885
1886
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1887
ghdr_new->cmd = PFNL_CMD_ADD_TABLE;
1888
1889
nlattr_add_u32(nw, PF_T_NBR_ADDED, attrs.pfrio_nadd);
1890
1891
if (!nlmsg_end(nw)) {
1892
nlmsg_abort(nw);
1893
return (ENOMEM);
1894
}
1895
1896
return (0);
1897
}
1898
1899
static int
1900
pf_handle_del_table(struct nlmsghdr *hdr, struct nl_pstate *npt)
1901
{
1902
struct pfioc_table attrs = { 0 };
1903
struct nl_writer *nw = npt->nw;
1904
struct genlmsghdr *ghdr_new;
1905
int error;
1906
1907
error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
1908
if (error != 0)
1909
return (error);
1910
1911
PF_RULES_WLOCK();
1912
error = pfr_del_tables(&attrs.pfrio_table, 1, &attrs.pfrio_ndel,
1913
attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
1914
PF_RULES_WUNLOCK();
1915
if (error != 0)
1916
return (error);
1917
1918
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1919
return (ENOMEM);
1920
1921
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1922
ghdr_new->cmd = PFNL_CMD_DEL_TABLE;
1923
1924
nlattr_add_u32(nw, PF_T_NBR_DELETED, attrs.pfrio_ndel);
1925
1926
if (!nlmsg_end(nw)) {
1927
nlmsg_abort(nw);
1928
return (ENOMEM);
1929
}
1930
1931
return (0);
1932
}
1933
1934
static bool
1935
nlattr_add_pfr_table(struct nl_writer *nw, int attrtype,
1936
struct pfr_table *t)
1937
{
1938
int off = nlattr_add_nested(nw, attrtype);
1939
1940
if (off == 0)
1941
return (false);
1942
1943
nlattr_add_string(nw, PF_T_ANCHOR, t->pfrt_anchor);
1944
nlattr_add_string(nw, PF_T_NAME, t->pfrt_name);
1945
nlattr_add_u32(nw, PF_T_TABLE_FLAGS, t->pfrt_flags);
1946
1947
nlattr_set_len(nw, off);
1948
1949
return (true);
1950
}
1951
1952
static int
1953
pf_handle_get_tstats(struct nlmsghdr *hdr, struct nl_pstate *npt)
1954
{
1955
struct pfioc_table attrs = { 0 };
1956
struct nl_writer *nw = npt->nw;
1957
struct genlmsghdr *ghdr_new;
1958
struct pfr_tstats *pfrtstats;
1959
int error;
1960
int n;
1961
1962
PF_RULES_RLOCK_TRACKER;
1963
1964
error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
1965
if (error != 0)
1966
return (error);
1967
1968
PF_TABLE_STATS_LOCK();
1969
PF_RULES_RLOCK();
1970
1971
n = pfr_table_count(&attrs.pfrio_table, attrs.pfrio_flags);
1972
if (n < 0) {
1973
PF_RULES_RUNLOCK();
1974
PF_TABLE_STATS_UNLOCK();
1975
return (EINVAL);
1976
}
1977
pfrtstats = mallocarray(n,
1978
sizeof(struct pfr_tstats), M_PF, M_NOWAIT | M_ZERO);
1979
if (pfrtstats == NULL) {
1980
PF_RULES_RUNLOCK();
1981
PF_TABLE_STATS_UNLOCK();
1982
return (ENOMEM);
1983
}
1984
1985
error = pfr_get_tstats(&attrs.pfrio_table, pfrtstats,
1986
&n, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
1987
1988
PF_RULES_RUNLOCK();
1989
PF_TABLE_STATS_UNLOCK();
1990
1991
if (error == 0) {
1992
hdr->nlmsg_flags |= NLM_F_MULTI;
1993
1994
for (int i = 0; i < n; i++) {
1995
uint64_t refcnt[PFR_REFCNT_MAX];
1996
1997
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
1998
error = ENOMEM;
1999
break;
2000
}
2001
2002
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2003
ghdr_new->cmd = PFNL_CMD_GET_TSTATS;
2004
2005
nlattr_add_pfr_table(nw, PF_TS_TABLE,
2006
&pfrtstats[i].pfrts_t);
2007
nlattr_add_u64_array(nw, PF_TS_PACKETS,
2008
PFR_DIR_MAX * PFR_OP_TABLE_MAX,
2009
(uint64_t *)pfrtstats[i].pfrts_packets);
2010
nlattr_add_u64_array(nw, PF_TS_BYTES,
2011
PFR_DIR_MAX * PFR_OP_TABLE_MAX,
2012
(uint64_t *)pfrtstats[i].pfrts_bytes);
2013
nlattr_add_u64(nw, PF_TS_MATCH,
2014
pfrtstats[i].pfrts_match);
2015
nlattr_add_u64(nw, PF_TS_NOMATCH,
2016
pfrtstats[i].pfrts_nomatch);
2017
nlattr_add_u64(nw, PF_TS_TZERO,
2018
pfrtstats[i].pfrts_tzero);
2019
nlattr_add_u64(nw, PF_TS_CNT, pfrtstats[i].pfrts_cnt);
2020
2021
for (int j = 0; j < PFR_REFCNT_MAX; j++)
2022
refcnt[j] = pfrtstats[i].pfrts_refcnt[j];
2023
2024
nlattr_add_u64_array(nw, PF_TS_REFCNT, PFR_REFCNT_MAX,
2025
refcnt);
2026
2027
if (! nlmsg_end(nw)) {
2028
error = ENOMEM;
2029
break;
2030
}
2031
}
2032
}
2033
free(pfrtstats, M_PF);
2034
2035
if (!nlmsg_end_dump(npt->nw, error, hdr)) {
2036
NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
2037
return (ENOMEM);
2038
}
2039
2040
return (error);
2041
}
2042
2043
static int
2044
pf_handle_clear_tstats(struct nlmsghdr *hdr, struct nl_pstate *npt)
2045
{
2046
struct pfioc_table attrs = { 0 };
2047
struct nl_writer *nw = npt->nw;
2048
struct genlmsghdr *ghdr_new;
2049
int error;
2050
int nzero;
2051
2052
PF_RULES_RLOCK_TRACKER;
2053
2054
error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
2055
if (error != 0)
2056
return (error);
2057
2058
PF_TABLE_STATS_LOCK();
2059
PF_RULES_RLOCK();
2060
error = pfr_clr_tstats(&attrs.pfrio_table, 1,
2061
&nzero, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
2062
PF_RULES_RUNLOCK();
2063
PF_TABLE_STATS_UNLOCK();
2064
2065
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2066
return (ENOMEM);
2067
2068
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2069
ghdr_new->cmd = PFNL_CMD_CLR_TSTATS;
2070
2071
nlattr_add_u64(nw, PF_TS_NZERO, nzero);
2072
2073
if (! nlmsg_end(nw))
2074
error = ENOMEM;
2075
2076
return (error);
2077
}
2078
2079
static int
2080
pf_handle_clear_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
2081
{
2082
struct pfioc_table attrs = { 0 };
2083
struct nl_writer *nw = npt->nw;
2084
struct genlmsghdr *ghdr_new;
2085
int error;
2086
int ndel;
2087
2088
error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
2089
if (error != 0)
2090
return (error);
2091
2092
PF_RULES_WLOCK();
2093
error = pfr_clr_addrs(&attrs.pfrio_table, &ndel,
2094
attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
2095
PF_RULES_WUNLOCK();
2096
2097
if (error)
2098
return (error);
2099
2100
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2101
return (ENOMEM);
2102
2103
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2104
ghdr_new->cmd = PFNL_CMD_CLR_ADDRS;
2105
2106
nlattr_add_u64(nw, PF_T_NBR_DELETED, ndel);
2107
2108
if (!nlmsg_end(nw))
2109
return (ENOMEM);
2110
2111
return (error);
2112
}
2113
2114
TAILQ_HEAD(pfr_addrq, pfr_addr_item);
2115
struct nl_parsed_table_addrs {
2116
struct pfr_table table;
2117
uint32_t flags;
2118
struct pfr_addr addrs[256];
2119
size_t addr_count;
2120
int nadd;
2121
int ndel;
2122
int nchange;
2123
};
2124
#define _OUT(_field) offsetof(struct pfr_addr, _field)
2125
static const struct nlattr_parser nla_p_pfr_addr[] = {
2126
{ .type = PFR_A_AF, .off = _OUT(pfra_af), .cb = nlattr_get_uint8 },
2127
{ .type = PFR_A_NET, .off = _OUT(pfra_net), .cb = nlattr_get_uint8 },
2128
{ .type = PFR_A_NOT, .off = _OUT(pfra_not), .cb = nlattr_get_bool },
2129
{ .type = PFR_A_ADDR, .off = _OUT(pfra_u), .cb = nlattr_get_in6_addr },
2130
};
2131
#undef _OUT
2132
NL_DECLARE_ATTR_PARSER(pfra_addr_parser, nla_p_pfr_addr);
2133
2134
static int
2135
nlattr_get_pfr_addr(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
2136
void *target)
2137
{
2138
struct nl_parsed_table_addrs *attrs = target;
2139
struct pfr_addr addr = { 0 };
2140
int error;
2141
2142
if (attrs->addr_count >= nitems(attrs->addrs))
2143
return (E2BIG);
2144
2145
error = nlattr_get_nested(nla, npt, &pfra_addr_parser, &addr);
2146
if (error != 0)
2147
return (error);
2148
2149
memcpy(&attrs->addrs[attrs->addr_count], &addr, sizeof(addr));
2150
attrs->addr_count++;
2151
2152
return (0);
2153
}
2154
2155
NL_DECLARE_ATTR_PARSER(nested_table_parser, nla_p_table);
2156
2157
#define _OUT(_field) offsetof(struct nl_parsed_table_addrs, _field)
2158
static const struct nlattr_parser nla_p_table_addr[] = {
2159
{ .type = PF_TA_TABLE, .off = _OUT(table), .arg = &nested_table_parser, .cb = nlattr_get_nested },
2160
{ .type = PF_TA_ADDR, .cb = nlattr_get_pfr_addr },
2161
{ .type = PF_TA_FLAGS, .off = _OUT(flags), .cb = nlattr_get_uint32 },
2162
};
2163
NL_DECLARE_PARSER(table_addr_parser, struct genlmsghdr, nlf_p_empty, nla_p_table_addr);
2164
#undef _OUT
2165
2166
static int
2167
pf_handle_table_add_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
2168
{
2169
struct nl_parsed_table_addrs attrs = { 0 };
2170
struct nl_writer *nw = npt->nw;
2171
struct genlmsghdr *ghdr_new;
2172
int error;
2173
2174
error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs);
2175
if (error != 0)
2176
return (error);
2177
2178
PF_RULES_WLOCK();
2179
error = pfr_add_addrs(&attrs.table, &attrs.addrs[0],
2180
attrs.addr_count, &attrs.nadd, attrs.flags | PFR_FLAG_USERIOCTL);
2181
PF_RULES_WUNLOCK();
2182
2183
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2184
return (ENOMEM);
2185
2186
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2187
ghdr_new->cmd = PFNL_CMD_TABLE_ADD_ADDR;
2188
2189
nlattr_add_u32(nw, PF_TA_NBR_ADDED, attrs.nadd);
2190
2191
if (!nlmsg_end(nw))
2192
return (ENOMEM);
2193
2194
return (error);
2195
}
2196
2197
static int
2198
pf_handle_table_del_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
2199
{
2200
struct nl_parsed_table_addrs attrs = { 0 };
2201
struct nl_writer *nw = npt->nw;
2202
struct genlmsghdr *ghdr_new;
2203
int error;
2204
2205
error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs);
2206
if (error != 0)
2207
return (error);
2208
2209
PF_RULES_WLOCK();
2210
error = pfr_del_addrs(&attrs.table, &attrs.addrs[0],
2211
attrs.addr_count, &attrs.ndel, attrs.flags | PFR_FLAG_USERIOCTL);
2212
PF_RULES_WUNLOCK();
2213
2214
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2215
return (ENOMEM);
2216
2217
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2218
ghdr_new->cmd = PFNL_CMD_TABLE_DEL_ADDR;
2219
2220
nlattr_add_u32(nw, PF_TA_NBR_DELETED, attrs.ndel);
2221
2222
if (!nlmsg_end(nw))
2223
return (ENOMEM);
2224
2225
return (error);
2226
}
2227
2228
static int
2229
pf_handle_table_set_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
2230
{
2231
struct nl_parsed_table_addrs attrs = { 0 };
2232
struct nl_writer *nw = npt->nw;
2233
struct genlmsghdr *ghdr_new;
2234
int error;
2235
2236
error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs);
2237
if (error != 0)
2238
return (error);
2239
2240
PF_RULES_WLOCK();
2241
error = pfr_set_addrs(&attrs.table, &attrs.addrs[0],
2242
attrs.addr_count, NULL, &attrs.nadd, &attrs.ndel, &attrs.nchange,
2243
attrs.flags | PFR_FLAG_USERIOCTL, 0);
2244
PF_RULES_WUNLOCK();
2245
2246
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2247
return (ENOMEM);
2248
2249
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2250
ghdr_new->cmd = PFNL_CMD_TABLE_SET_ADDR;
2251
2252
nlattr_add_u32(nw, PF_TA_NBR_ADDED, attrs.nadd);
2253
nlattr_add_u32(nw, PF_TA_NBR_DELETED, attrs.ndel);
2254
nlattr_add_u32(nw, PF_TA_NBR_CHANGED, attrs.nchange);
2255
2256
if (!nlmsg_end(nw))
2257
return (ENOMEM);
2258
2259
return (error);
2260
}
2261
2262
static int
2263
nlattr_add_pfr_addr(struct nl_writer *nw, int attr, const struct pfr_addr *a)
2264
{
2265
int off = nlattr_add_nested(nw, attr);
2266
2267
if (off == 0)
2268
return (false);
2269
2270
nlattr_add_u32(nw, PFR_A_AF, a->pfra_af);
2271
nlattr_add_u8(nw, PFR_A_NET, a->pfra_net);
2272
nlattr_add_bool(nw, PFR_A_NOT, a->pfra_not);
2273
nlattr_add_in6_addr(nw, PFR_A_ADDR, &a->pfra_u._pfra_ip6addr);
2274
2275
nlattr_set_len(nw, off);
2276
2277
return (true);
2278
}
2279
2280
static int
2281
pf_handle_table_get_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
2282
{
2283
struct pfioc_table attrs = { 0 };
2284
struct pfr_addr *pfras;
2285
struct nl_writer *nw = npt->nw;
2286
struct genlmsghdr *ghdr_new;
2287
int size = 0;
2288
int error;
2289
2290
PF_RULES_RLOCK_TRACKER;
2291
2292
error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs);
2293
if (error != 0)
2294
return (error);
2295
2296
PF_RULES_RLOCK();
2297
/* Get required size. */
2298
error = pfr_get_addrs(&attrs.pfrio_table, NULL,
2299
&size, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
2300
if (error != 0) {
2301
PF_RULES_RUNLOCK();
2302
return (error);
2303
}
2304
pfras = mallocarray(size, sizeof(struct pfr_addr), M_PF,
2305
M_NOWAIT | M_ZERO);
2306
if (pfras == NULL) {
2307
PF_RULES_RUNLOCK();
2308
return (ENOMEM);
2309
}
2310
/* Now get the addresses. */
2311
error = pfr_get_addrs(&attrs.pfrio_table, pfras,
2312
&size, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
2313
PF_RULES_RUNLOCK();
2314
if (error != 0)
2315
goto out;
2316
2317
for (int i = 0; i < size; i++) {
2318
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
2319
nlmsg_abort(nw);
2320
error = ENOMEM;
2321
goto out;
2322
}
2323
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2324
ghdr_new->cmd = PFNL_CMD_TABLE_GET_ADDR;
2325
2326
if (i == 0)
2327
nlattr_add_u32(nw, PF_TA_ADDR_COUNT, size);
2328
2329
nlattr_add_pfr_addr(nw, PF_TA_ADDR, &pfras[i]);
2330
if (!nlmsg_end(nw)) {
2331
nlmsg_abort(nw);
2332
error = ENOMEM;
2333
goto out;
2334
}
2335
}
2336
2337
out:
2338
free(pfras, M_PF);
2339
return (error);
2340
}
2341
2342
static int
2343
nlattr_add_pfr_astats(struct nl_writer *nw, int attr, const struct pfr_astats *a)
2344
{
2345
int off = nlattr_add_nested(nw, attr);
2346
2347
if (off == 0)
2348
return (false);
2349
2350
nlattr_add_pfr_addr(nw, PF_AS_ADDR, &a->pfras_a);
2351
nlattr_add_u64_array(nw, PF_AS_PACKETS, PFR_DIR_MAX * PFR_OP_ADDR_MAX,
2352
(const uint64_t *)a->pfras_packets);
2353
nlattr_add_u64_array(nw,PF_AS_BYTES, PFR_DIR_MAX * PFR_OP_ADDR_MAX,
2354
(const uint64_t *)a->pfras_bytes);
2355
nlattr_add_time_t(nw, PF_AS_TZERO, a->pfras_tzero);
2356
2357
nlattr_set_len(nw, off);
2358
2359
return (true);
2360
}
2361
2362
struct nl_parsed_table_astats {
2363
struct pfr_table table;
2364
uint32_t flags;
2365
};
2366
#define _OUT(_field) offsetof(struct nl_parsed_table_astats, _field)
2367
static const struct nlattr_parser nla_p_table_astats[] = {
2368
{ .type = PF_TAS_TABLE, .off = _OUT(table), .arg = &nested_table_parser, .cb = nlattr_get_nested },
2369
{ .type = PF_TAS_FLAGS, .off = _OUT(flags), .cb = nlattr_get_uint32 },
2370
};
2371
NL_DECLARE_PARSER(table_astats_parser, struct genlmsghdr, nlf_p_empty, nla_p_table_astats);
2372
#undef _OUT
2373
2374
static int
2375
pf_handle_table_get_astats(struct nlmsghdr *hdr, struct nl_pstate *npt)
2376
{
2377
struct nl_parsed_table_astats attrs = { 0 };
2378
struct nl_writer *nw = npt->nw;
2379
struct pfr_astats *pfrastats;
2380
struct genlmsghdr *ghdr_new;
2381
int size = 0;
2382
int error;
2383
2384
PF_RULES_RLOCK_TRACKER;
2385
2386
error = nl_parse_nlmsg(hdr, &table_astats_parser, npt, &attrs);
2387
if (error != 0)
2388
return (error);
2389
2390
PF_RULES_RLOCK();
2391
2392
/* Get required size. */
2393
error = pfr_get_astats(&attrs.table, NULL,
2394
&size, attrs.flags | PFR_FLAG_USERIOCTL);
2395
if (error != 0) {
2396
PF_RULES_RUNLOCK();
2397
return (error);
2398
}
2399
2400
pfrastats = mallocarray(size, sizeof(struct pfr_astats), M_PF,
2401
M_NOWAIT | M_ZERO);
2402
if (pfrastats == NULL) {
2403
PF_RULES_RUNLOCK();
2404
return (ENOMEM);
2405
}
2406
2407
/* Now get the astats. */
2408
error = pfr_get_astats(&attrs.table, pfrastats,
2409
&size, attrs.flags | PFR_FLAG_USERIOCTL);
2410
PF_RULES_RUNLOCK();
2411
if (error != 0)
2412
goto out;
2413
2414
for (int i = 0; i < size; i++) {
2415
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
2416
nlmsg_abort(nw);
2417
error = ENOMEM;
2418
goto out;
2419
}
2420
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2421
ghdr_new->cmd = PFNL_CMD_TABLE_GET_ASTATS;
2422
2423
if (i == 0)
2424
nlattr_add_u32(nw, PF_TAS_ASTATS_COUNT, size);
2425
2426
nlattr_add_pfr_astats(nw, PF_TAS_ASTATS, &pfrastats[i]);
2427
if (!nlmsg_end(nw)) {
2428
nlmsg_abort(nw);
2429
error = ENOMEM;
2430
goto out;
2431
}
2432
}
2433
2434
out:
2435
free(pfrastats, M_PF);
2436
return (error);
2437
}
2438
static int
2439
pf_handle_table_clear_astats(struct nlmsghdr *hdr, struct nl_pstate *npt)
2440
{
2441
struct nl_parsed_table_addrs attrs = { 0 };
2442
struct nl_writer *nw = npt->nw;
2443
struct genlmsghdr *ghdr_new;
2444
int error;
2445
2446
error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs);
2447
if (error != 0)
2448
return (error);
2449
2450
PF_RULES_WLOCK();
2451
error = pfr_clr_astats(&attrs.table, &attrs.addrs[0],
2452
attrs.addr_count, &attrs.nchange,
2453
attrs.flags | PFR_FLAG_USERIOCTL);
2454
PF_RULES_WUNLOCK();
2455
2456
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2457
return (ENOMEM);
2458
2459
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2460
ghdr_new->cmd = PFNL_CMD_TABLE_CLEAR_ASTATS;
2461
2462
nlattr_add_u32(nw, PF_TAS_ASTATS_ZEROED, attrs.nchange);
2463
2464
if (!nlmsg_end(nw))
2465
return (ENOMEM);
2466
2467
return (error);
2468
}
2469
2470
static int
2471
pf_handle_table_test_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
2472
{
2473
struct nl_parsed_table_addrs attrs = { 0 };
2474
struct nl_writer *nw = npt->nw;
2475
struct genlmsghdr *ghdr_new;
2476
int error;
2477
2478
PF_RULES_RLOCK_TRACKER;
2479
2480
error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs);
2481
if (error != 0)
2482
return (error);
2483
2484
PF_RULES_RLOCK();
2485
error = pfr_tst_addrs(&attrs.table, &attrs.addrs[0],
2486
attrs.addr_count, &attrs.nchange,
2487
attrs.flags | PFR_FLAG_USERIOCTL);
2488
PF_RULES_RUNLOCK();
2489
2490
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2491
return (ENOMEM);
2492
2493
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2494
ghdr_new->cmd = PFNL_CMD_TABLE_TEST_ADDRS;
2495
2496
nlattr_add_u32(nw, PF_TAS_ASTATS_COUNT, attrs.nchange);
2497
2498
if (!nlmsg_end(nw))
2499
return (ENOMEM);
2500
2501
return (error);
2502
}
2503
2504
static const struct nlattr_parser nla_p_rate[] = {
2505
{ .type = PF_LR_LIMIT, .off = 0, .cb = nlattr_get_uint32 },
2506
{ .type = PF_LR_SECONDS, .off = sizeof(unsigned int), .cb = nlattr_get_uint32 },
2507
};
2508
NL_DECLARE_ATTR_PARSER(rate_parser, nla_p_rate);
2509
2510
#define _OUT(_field) offsetof(struct pfioc_statelim, _field)
2511
static const struct nlattr_parser nla_p_state_limiter[] = {
2512
{ .type = PF_SL_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
2513
{ .type = PF_SL_NAME, .off = _OUT(name), .arg = (void *)PF_STATELIM_NAME_LEN, .cb = nlattr_get_chara },
2514
{ .type = PF_SL_ID, .off = _OUT(id), .cb = nlattr_get_uint32 },
2515
{ .type = PF_SL_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
2516
{ .type = PF_SL_RATE, .off = _OUT(rate), .arg = &rate_parser, .cb = nlattr_get_nested },
2517
{ .type = PF_SL_DESCR, .off = _OUT(description), .arg = (void *)PF_STATELIM_DESCR_LEN, .cb = nlattr_get_chara },
2518
};
2519
NL_DECLARE_PARSER(state_limiter_parser, struct genlmsghdr, nlf_p_empty, nla_p_state_limiter);
2520
#undef _OUT
2521
2522
static int
2523
pf_handle_state_limiter_add(struct nlmsghdr *hdr, struct nl_pstate *npt)
2524
{
2525
struct pfioc_statelim attrs = { 0 };
2526
struct nl_writer *nw = npt->nw;
2527
struct genlmsghdr *ghdr_new;
2528
int error;
2529
2530
error = nl_parse_nlmsg(hdr, &state_limiter_parser, npt, &attrs);
2531
if (error != 0)
2532
return (error);
2533
2534
error = pf_statelim_add(&attrs);
2535
if (error != 0)
2536
return (error);
2537
2538
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2539
return (ENOMEM);
2540
2541
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2542
ghdr_new->cmd = PFNL_CMD_STATE_LIMITER_ADD;
2543
2544
nlattr_add_u32(nw, PF_SL_ID, attrs.id);
2545
2546
if (!nlmsg_end(nw))
2547
return (ENOMEM);
2548
2549
return (error);
2550
}
2551
2552
static bool
2553
nlattr_add_limiter_rate(struct nl_writer *nw, int attrtype,
2554
const struct pf_limiter_rate *rate)
2555
{
2556
int off = nlattr_add_nested(nw, attrtype);
2557
if (off == 0)
2558
return (false);
2559
2560
nlattr_add_u32(nw, PF_LR_LIMIT, rate->limit);
2561
nlattr_add_u32(nw, PF_LR_SECONDS, rate->seconds);
2562
2563
nlattr_set_len(nw, off);
2564
2565
return (true);
2566
}
2567
2568
static int
2569
pf_handle_state_limiter_get(struct nlmsghdr *hdr, struct nl_pstate *npt)
2570
{
2571
struct pfioc_statelim attrs = { 0 };
2572
struct nl_writer *nw = npt->nw;
2573
struct genlmsghdr *ghdr = (struct genlmsghdr *)(hdr + 1);
2574
struct genlmsghdr *ghdr_new;
2575
int error;
2576
2577
error = nl_parse_nlmsg(hdr, &state_limiter_parser, npt, &attrs);
2578
if (error != 0)
2579
return (error);
2580
2581
error = pf_statelim_get(&attrs,
2582
ghdr->cmd == PFNL_CMD_STATE_LIMITER_GET ? pf_statelim_rb_find :
2583
pf_statelim_rb_nfind);
2584
if (error != 0)
2585
return (error);
2586
2587
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2588
return (ENOMEM);
2589
2590
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2591
ghdr_new->cmd = PFNL_CMD_STATE_LIMITER_GET;
2592
2593
nlattr_add_string(nw, PF_SL_NAME, attrs.name);
2594
nlattr_add_u32(nw, PF_SL_ID, attrs.id);
2595
nlattr_add_u32(nw, PF_SL_LIMIT, attrs.limit);
2596
nlattr_add_limiter_rate(nw, PF_SL_RATE, &attrs.rate);
2597
nlattr_add_string(nw, PF_SL_DESCR, attrs.description);
2598
nlattr_add_u32(nw, PF_SL_INUSE, attrs.inuse);
2599
nlattr_add_u64(nw, PF_SL_ADMITTED, attrs.admitted);
2600
nlattr_add_u64(nw, PF_SL_HARDLIMITED, attrs.hardlimited);
2601
nlattr_add_u64(nw, PF_SL_RATELIMITED, attrs.ratelimited);
2602
2603
if (!nlmsg_end(nw))
2604
return (ENOMEM);
2605
2606
return (error);
2607
}
2608
2609
#define _OUT(_field) offsetof(struct pfioc_sourcelim, _field)
2610
static const struct nlattr_parser nla_p_source_limiter[] = {
2611
{ .type = PF_SCL_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
2612
{ .type = PF_SCL_NAME, .off = _OUT(name), .arg = (void *)PF_STATELIM_NAME_LEN, .cb = nlattr_get_chara },
2613
{ .type = PF_SCL_ID, .off = _OUT(id), .cb = nlattr_get_uint32 },
2614
{ .type = PF_SCL_ENTRIES, .off = _OUT(entries), .cb = nlattr_get_uint32 },
2615
{ .type = PF_SCL_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
2616
{ .type = PF_SCL_RATE, .off = _OUT(rate), .arg = &rate_parser, .cb = nlattr_get_nested },
2617
{ .type = PF_SCL_OVERLOAD_TBL_NAME, .off = _OUT(overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
2618
{ .type = PF_SCL_OVERLOAD_HIGH_WM, .off = _OUT(overload_hwm), .cb = nlattr_get_uint32 },
2619
{ .type = PF_SCL_OVERLOAD_LOW_WM, .off = _OUT(overload_lwm), .cb = nlattr_get_uint32 },
2620
{ .type = PF_SCL_INET_PREFIX, .off = _OUT(inet_prefix), .cb = nlattr_get_uint32 },
2621
{ .type = PF_SCL_INET6_PREFIX, .off = _OUT(inet6_prefix), .cb = nlattr_get_uint32 },
2622
{ .type = PF_SCL_DESCR, .off = _OUT(description), .arg = (void *)PF_STATELIM_DESCR_LEN, .cb = nlattr_get_chara },
2623
};
2624
#undef _OUT
2625
NL_DECLARE_PARSER(source_limiter_parser, struct genlmsghdr, nlf_p_empty, nla_p_source_limiter);
2626
2627
static int
2628
pf_handle_source_limiter_add(struct nlmsghdr *hdr, struct nl_pstate *npt)
2629
{
2630
struct pfioc_sourcelim attrs = { 0 };
2631
struct nl_writer *nw = npt->nw;
2632
struct genlmsghdr *ghdr_new;
2633
int error;
2634
2635
error = nl_parse_nlmsg(hdr, &source_limiter_parser, npt, &attrs);
2636
if (error != 0)
2637
return (error);
2638
2639
error = pf_sourcelim_add(&attrs);
2640
if (error != 0)
2641
return (error);
2642
2643
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2644
return (ENOMEM);
2645
2646
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2647
ghdr_new->cmd = PFNL_CMD_SOURCE_LIMITER_ADD;
2648
2649
nlattr_add_u32(nw, PF_SCL_ID, attrs.id);
2650
2651
if (!nlmsg_end(nw))
2652
return (ENOMEM);
2653
2654
return (error);
2655
}
2656
2657
static int
2658
pf_handle_source_limiter_get(struct nlmsghdr *hdr, struct nl_pstate *npt)
2659
{
2660
struct pfioc_sourcelim attrs = { 0 };
2661
struct nl_writer *nw = npt->nw;
2662
struct genlmsghdr *ghdr = (struct genlmsghdr *)(hdr + 1);
2663
struct genlmsghdr *ghdr_new;
2664
int error;
2665
2666
error = nl_parse_nlmsg(hdr, &source_limiter_parser, npt, &attrs);
2667
if (error != 0)
2668
return (error);
2669
2670
error = pf_sourcelim_get(&attrs,
2671
ghdr->cmd == PFNL_CMD_SOURCE_LIMITER_GET ? pf_sourcelim_rb_find :
2672
pf_sourcelim_rb_nfind);
2673
if (error != 0)
2674
return (error);
2675
2676
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2677
return (ENOMEM);
2678
2679
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2680
ghdr_new->cmd = ghdr->cmd;
2681
2682
nlattr_add_string(nw, PF_SCL_NAME, attrs.name);
2683
nlattr_add_u32(nw, PF_SCL_ID, attrs.id);
2684
nlattr_add_u32(nw, PF_SCL_ENTRIES, attrs.entries);
2685
nlattr_add_u32(nw, PF_SCL_LIMIT, attrs.limit);
2686
nlattr_add_limiter_rate(nw, PF_SCL_RATE, &attrs.rate);
2687
nlattr_add_string(nw, PF_SCL_OVERLOAD_TBL_NAME, attrs.overload_tblname);
2688
nlattr_add_u32(nw, PF_SCL_OVERLOAD_HIGH_WM, attrs.overload_hwm);
2689
nlattr_add_u32(nw, PF_SCL_OVERLOAD_LOW_WM, attrs.overload_lwm);
2690
nlattr_add_u32(nw, PF_SCL_INET_PREFIX, attrs.inet_prefix);
2691
nlattr_add_u32(nw, PF_SCL_INET6_PREFIX, attrs.inet6_prefix);
2692
nlattr_add_string(nw, PF_SCL_DESCR, attrs.description);
2693
nlattr_add_u32(nw, PF_SCL_NENTRIES, attrs.nentries);
2694
nlattr_add_u32(nw, PF_SCL_INUSE, attrs.inuse);
2695
nlattr_add_u64(nw, PF_SCL_ADDR_ALLOCS, attrs.addrallocs);
2696
nlattr_add_u64(nw, PF_SCL_ADDR_NOMEM, attrs.addrnomem);
2697
nlattr_add_u64(nw, PF_SCL_ADMITTED, attrs.admitted);
2698
nlattr_add_u64(nw, PF_SCL_ADDRLIMITED, attrs.addrlimited);
2699
nlattr_add_u64(nw, PF_SCL_HARDLIMITED, attrs.hardlimited);
2700
nlattr_add_u64(nw, PF_SCL_RATELIMITED, attrs.ratelimited);
2701
2702
if (!nlmsg_end(nw))
2703
return (ENOMEM);
2704
2705
return (error);
2706
}
2707
2708
struct nlattr_source {
2709
char name[PF_SOURCELIM_NAME_LEN];
2710
uint32_t id;
2711
sa_family_t af;
2712
unsigned int rdomain;
2713
struct pf_addr addr;
2714
};
2715
#define _OUT(_field) offsetof(struct nlattr_source, _field)
2716
static const struct nlattr_parser nla_p_source[] = {
2717
{ .type = PF_SRC_NAME, .off = _OUT(name), .arg = (void *)PF_SOURCELIM_NAME_LEN, .cb = nlattr_get_chara },
2718
{ .type = PF_SRC_ID, .off = _OUT(id), .cb = nlattr_get_uint32 },
2719
{ .type = PF_SRC_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
2720
{ .type = PF_SRC_RDOMAIN, .off = _OUT(rdomain), .cb = nlattr_get_uint32 },
2721
{ .type = PF_SRC_ADDR, .off = _OUT(addr), .cb = nlattr_get_in6_addr },
2722
};
2723
#undef _OUT
2724
NL_DECLARE_PARSER(source_parser, struct genlmsghdr, nlf_p_empty, nla_p_source);
2725
2726
static int
2727
pf_handle_source_get(struct nlmsghdr *hdr, struct nl_pstate *npt)
2728
{
2729
struct nlattr_source attrs = { 0 };
2730
struct pf_source key;
2731
struct pf_sourcelim plkey;
2732
struct nl_writer *nw = npt->nw;
2733
struct genlmsghdr *ghdr = (struct genlmsghdr *)(hdr + 1);
2734
struct genlmsghdr *ghdr_new;
2735
struct pf_sourcelim *pfsrlim;
2736
struct pf_source *pfsr;
2737
int error;
2738
PF_RULES_RLOCK_TRACKER;
2739
2740
error = nl_parse_nlmsg(hdr, &source_parser, npt, &attrs);
2741
if (error != 0)
2742
return (error);
2743
2744
PF_RULES_RLOCK();
2745
plkey.pfsrlim_id = attrs.id;
2746
pfsrlim = pf_sourcelim_rb_find(&V_pf_sourcelim_id_tree_active, &plkey);
2747
if (pfsrlim == NULL) {
2748
error = ESRCH;
2749
goto out;
2750
}
2751
2752
key.pfsr_af = attrs.af;
2753
key.pfsr_rdomain = attrs.rdomain;
2754
key.pfsr_addr = attrs.addr;
2755
2756
pfsr = (ghdr->cmd == PFNL_CMD_SOURCE_GET ? pf_source_rb_find :
2757
pf_source_rb_nfind)(&pfsrlim->pfsrlim_ioc_sources, &key);
2758
if (pfsr == NULL) {
2759
error = ENOENT;
2760
goto out;
2761
}
2762
2763
for (;;) {
2764
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
2765
error = ENOMEM;
2766
goto out;
2767
}
2768
2769
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2770
ghdr_new->cmd = ghdr->cmd;
2771
2772
nlattr_add_u8(nw, PF_SRC_AF, pfsr->pfsr_af);
2773
nlattr_add_u32(nw, PF_SRC_RDOMAIN, pfsr->pfsr_rdomain);
2774
nlattr_add_in6_addr(nw, PF_SRC_ADDR, &pfsr->pfsr_addr.v6);
2775
2776
nlattr_add_u32(nw, PF_SRC_INUSE, pfsr->pfsr_inuse);
2777
nlattr_add_u64(nw, PF_SRC_ADMITTED, pfsr->pfsr_counters.admitted);
2778
nlattr_add_u64(nw, PF_SRC_HARDLIMITED, pfsr->pfsr_counters.hardlimited);
2779
nlattr_add_u64(nw, PF_SRC_RATELIMITED, pfsr->pfsr_counters.ratelimited);
2780
2781
nlattr_add_u32(nw, PF_SRC_LIMIT, pfsrlim->pfsrlim_limit);
2782
nlattr_add_u32(nw, PF_SRC_INET_PREFIX, pfsrlim->pfsrlim_ipv4_prefix);
2783
nlattr_add_u32(nw, PF_SRC_INET6_PREFIX, pfsrlim->pfsrlim_ipv6_prefix);
2784
2785
if (!nlmsg_end(nw)) {
2786
nlmsg_abort(nw);
2787
error = ENOMEM;
2788
goto out;
2789
}
2790
2791
pfsr = RB_NEXT(pf_source_ioc_tree, srlim->pfsrlim_ioc_sources, pfsr);
2792
if (pfsr == NULL)
2793
break;
2794
}
2795
2796
out:
2797
PF_RULES_RUNLOCK();
2798
return (error);
2799
}
2800
2801
2802
#define _OUT(_field) offsetof(struct pfioc_source_kill, _field)
2803
static const struct nlattr_parser nla_p_source_clear[] = {
2804
{ .type = PF_SC_NAME, .off = _OUT(name), .arg = (void *)PF_SOURCELIM_NAME_LEN, .cb = nlattr_get_chara },
2805
{ .type = PF_SC_ID, .off = _OUT(id), .cb = nlattr_get_uint32 },
2806
{ .type = PF_SC_RDOMAIN, .off = _OUT(rdomain), .cb = nlattr_get_uint32 },
2807
{ .type = PF_SC_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
2808
{ .type = PF_SC_ADDR, .off = _OUT(addr), .cb = nlattr_get_in6_addr },
2809
};
2810
#undef _OUT
2811
NL_DECLARE_PARSER(source_clear_parser, struct genlmsghdr, nlf_p_empty, nla_p_source_clear);
2812
2813
static int
2814
pf_handle_source_clear(struct nlmsghdr *hdr, struct nl_pstate *npt)
2815
{
2816
struct pfioc_source_kill attrs = { 0 };
2817
struct nl_writer *nw = npt->nw;
2818
struct genlmsghdr *ghdr = (struct genlmsghdr *)(hdr + 1);
2819
struct genlmsghdr *ghdr_new;
2820
int error;
2821
2822
error = nl_parse_nlmsg(hdr, &source_clear_parser, npt, &attrs);
2823
if (error != 0)
2824
return (error);
2825
2826
error = pf_source_clr(&attrs);
2827
if (error != 0)
2828
return (error);
2829
2830
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2831
return (ENOMEM);
2832
2833
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2834
ghdr_new->cmd = ghdr->cmd;
2835
2836
nlattr_add_string(nw, PF_SCL_NAME, attrs.name);
2837
2838
if (!nlmsg_end(nw))
2839
return (ENOMEM);
2840
2841
return (error);
2842
}
2843
2844
static const struct nlhdr_parser *all_parsers[] = {
2845
&state_parser,
2846
&addrule_parser,
2847
&getrules_parser,
2848
&clear_states_parser,
2849
&set_statusif_parser,
2850
&natlook_parser,
2851
&set_debug_parser,
2852
&set_timeout_parser,
2853
&set_limit_parser,
2854
&pool_addr_parser,
2855
&add_addr_parser,
2856
&ruleset_parser,
2857
&table_parser,
2858
&table_addr_parser,
2859
&table_astats_parser,
2860
&state_limiter_parser,
2861
&source_limiter_parser,
2862
&source_parser,
2863
&source_clear_parser,
2864
};
2865
2866
static uint16_t family_id;
2867
2868
static const struct genl_cmd pf_cmds[] = {
2869
{
2870
.cmd_num = PFNL_CMD_GETSTATES,
2871
.cmd_name = "GETSTATES",
2872
.cmd_cb = pf_handle_getstates,
2873
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2874
.cmd_priv = PRIV_NETINET_PF,
2875
},
2876
{
2877
.cmd_num = PFNL_CMD_GETCREATORS,
2878
.cmd_name = "GETCREATORS",
2879
.cmd_cb = pf_handle_getcreators,
2880
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2881
.cmd_priv = PRIV_NETINET_PF,
2882
},
2883
{
2884
.cmd_num = PFNL_CMD_START,
2885
.cmd_name = "START",
2886
.cmd_cb = pf_handle_start,
2887
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2888
.cmd_priv = PRIV_NETINET_PF,
2889
},
2890
{
2891
.cmd_num = PFNL_CMD_STOP,
2892
.cmd_name = "STOP",
2893
.cmd_cb = pf_handle_stop,
2894
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2895
.cmd_priv = PRIV_NETINET_PF,
2896
},
2897
{
2898
.cmd_num = PFNL_CMD_ADDRULE,
2899
.cmd_name = "ADDRULE",
2900
.cmd_cb = pf_handle_addrule,
2901
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2902
.cmd_priv = PRIV_NETINET_PF,
2903
},
2904
{
2905
.cmd_num = PFNL_CMD_GETRULES,
2906
.cmd_name = "GETRULES",
2907
.cmd_cb = pf_handle_getrules,
2908
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2909
.cmd_priv = PRIV_NETINET_PF,
2910
},
2911
{
2912
.cmd_num = PFNL_CMD_GETRULE,
2913
.cmd_name = "GETRULE",
2914
.cmd_cb = pf_handle_getrule,
2915
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2916
.cmd_priv = PRIV_NETINET_PF,
2917
},
2918
{
2919
.cmd_num = PFNL_CMD_CLRSTATES,
2920
.cmd_name = "CLRSTATES",
2921
.cmd_cb = pf_handle_clear_states,
2922
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2923
.cmd_priv = PRIV_NETINET_PF,
2924
},
2925
{
2926
.cmd_num = PFNL_CMD_KILLSTATES,
2927
.cmd_name = "KILLSTATES",
2928
.cmd_cb = pf_handle_kill_states,
2929
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2930
.cmd_priv = PRIV_NETINET_PF,
2931
},
2932
{
2933
.cmd_num = PFNL_CMD_SET_STATUSIF,
2934
.cmd_name = "SETSTATUSIF",
2935
.cmd_cb = pf_handle_set_statusif,
2936
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2937
.cmd_priv = PRIV_NETINET_PF,
2938
},
2939
{
2940
.cmd_num = PFNL_CMD_GET_STATUS,
2941
.cmd_name = "GETSTATUS",
2942
.cmd_cb = pf_handle_get_status,
2943
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2944
.cmd_priv = PRIV_NETINET_PF,
2945
},
2946
{
2947
.cmd_num = PFNL_CMD_CLEAR_STATUS,
2948
.cmd_name = "CLEARSTATUS",
2949
.cmd_cb = pf_handle_clear_status,
2950
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2951
.cmd_priv = PRIV_NETINET_PF,
2952
},
2953
{
2954
.cmd_num = PFNL_CMD_NATLOOK,
2955
.cmd_name = "NATLOOK",
2956
.cmd_cb = pf_handle_natlook,
2957
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2958
.cmd_priv = PRIV_NETINET_PF,
2959
},
2960
{
2961
.cmd_num = PFNL_CMD_SET_DEBUG,
2962
.cmd_name = "SET_DEBUG",
2963
.cmd_cb = pf_handle_set_debug,
2964
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2965
.cmd_priv = PRIV_NETINET_PF,
2966
},
2967
{
2968
.cmd_num = PFNL_CMD_SET_TIMEOUT,
2969
.cmd_name = "SET_TIMEOUT",
2970
.cmd_cb = pf_handle_set_timeout,
2971
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2972
.cmd_priv = PRIV_NETINET_PF,
2973
},
2974
{
2975
.cmd_num = PFNL_CMD_GET_TIMEOUT,
2976
.cmd_name = "GET_TIMEOUT",
2977
.cmd_cb = pf_handle_get_timeout,
2978
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2979
.cmd_priv = PRIV_NETINET_PF,
2980
},
2981
{
2982
.cmd_num = PFNL_CMD_SET_LIMIT,
2983
.cmd_name = "SET_LIMIT",
2984
.cmd_cb = pf_handle_set_limit,
2985
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2986
.cmd_priv = PRIV_NETINET_PF,
2987
},
2988
{
2989
.cmd_num = PFNL_CMD_GET_LIMIT,
2990
.cmd_name = "GET_LIMIT",
2991
.cmd_cb = pf_handle_get_limit,
2992
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2993
.cmd_priv = PRIV_NETINET_PF,
2994
},
2995
{
2996
.cmd_num = PFNL_CMD_BEGIN_ADDRS,
2997
.cmd_name = "BEGIN_ADDRS",
2998
.cmd_cb = pf_handle_begin_addrs,
2999
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3000
.cmd_priv = PRIV_NETINET_PF,
3001
},
3002
{
3003
.cmd_num = PFNL_CMD_ADD_ADDR,
3004
.cmd_name = "ADD_ADDR",
3005
.cmd_cb = pf_handle_add_addr,
3006
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3007
.cmd_priv = PRIV_NETINET_PF,
3008
},
3009
{
3010
.cmd_num = PFNL_CMD_GET_ADDRS,
3011
.cmd_name = "GET_ADDRS",
3012
.cmd_cb = pf_handle_get_addrs,
3013
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3014
.cmd_priv = PRIV_NETINET_PF,
3015
},
3016
{
3017
.cmd_num = PFNL_CMD_GET_ADDR,
3018
.cmd_name = "GET_ADDRS",
3019
.cmd_cb = pf_handle_get_addr,
3020
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3021
.cmd_priv = PRIV_NETINET_PF,
3022
},
3023
{
3024
.cmd_num = PFNL_CMD_GET_RULESETS,
3025
.cmd_name = "GET_RULESETS",
3026
.cmd_cb = pf_handle_get_rulesets,
3027
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3028
.cmd_priv = PRIV_NETINET_PF,
3029
},
3030
{
3031
.cmd_num = PFNL_CMD_GET_RULESET,
3032
.cmd_name = "GET_RULESET",
3033
.cmd_cb = pf_handle_get_ruleset,
3034
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3035
.cmd_priv = PRIV_NETINET_PF,
3036
},
3037
{
3038
.cmd_num = PFNL_CMD_GET_SRCNODES,
3039
.cmd_name = "GET_SRCNODES",
3040
.cmd_cb = pf_handle_get_srcnodes,
3041
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3042
.cmd_priv = PRIV_NETINET_PF,
3043
},
3044
{
3045
.cmd_num = PFNL_CMD_CLEAR_TABLES,
3046
.cmd_name = "CLEAR_TABLES",
3047
.cmd_cb = pf_handle_clear_tables,
3048
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3049
.cmd_priv = PRIV_NETINET_PF,
3050
},
3051
{
3052
.cmd_num = PFNL_CMD_ADD_TABLE,
3053
.cmd_name = "ADD_TABLE",
3054
.cmd_cb = pf_handle_add_table,
3055
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3056
.cmd_priv = PRIV_NETINET_PF,
3057
},
3058
{
3059
.cmd_num = PFNL_CMD_DEL_TABLE,
3060
.cmd_name = "DEL_TABLE",
3061
.cmd_cb = pf_handle_del_table,
3062
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3063
.cmd_priv = PRIV_NETINET_PF,
3064
},
3065
{
3066
.cmd_num = PFNL_CMD_GET_TSTATS,
3067
.cmd_name = "GET_TSTATS",
3068
.cmd_cb = pf_handle_get_tstats,
3069
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3070
.cmd_priv = PRIV_NETINET_PF,
3071
},
3072
{
3073
.cmd_num = PFNL_CMD_CLR_TSTATS,
3074
.cmd_name = "CLR_TSTATS",
3075
.cmd_cb = pf_handle_clear_tstats,
3076
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3077
.cmd_priv = PRIV_NETINET_PF,
3078
},
3079
{
3080
.cmd_num = PFNL_CMD_CLR_ADDRS,
3081
.cmd_name = "CRL_ADDRS",
3082
.cmd_cb = pf_handle_clear_addrs,
3083
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3084
.cmd_priv = PRIV_NETINET_PF,
3085
},
3086
{
3087
.cmd_num = PFNL_CMD_TABLE_ADD_ADDR,
3088
.cmd_name = "TABLE_ADD_ADDRS",
3089
.cmd_cb = pf_handle_table_add_addrs,
3090
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3091
.cmd_priv = PRIV_NETINET_PF,
3092
},
3093
{
3094
.cmd_num = PFNL_CMD_TABLE_DEL_ADDR,
3095
.cmd_name = "TABLE_DEL_ADDRS",
3096
.cmd_cb = pf_handle_table_del_addrs,
3097
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3098
.cmd_priv = PRIV_NETINET_PF,
3099
},
3100
{
3101
.cmd_num = PFNL_CMD_TABLE_SET_ADDR,
3102
.cmd_name = "TABLE_SET_ADDRS",
3103
.cmd_cb = pf_handle_table_set_addrs,
3104
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3105
.cmd_priv = PRIV_NETINET_PF,
3106
},
3107
{
3108
.cmd_num = PFNL_CMD_TABLE_GET_ADDR,
3109
.cmd_name = "TABLE_GET_ADDRS",
3110
.cmd_cb = pf_handle_table_get_addrs,
3111
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3112
.cmd_priv = PRIV_NETINET_PF,
3113
},
3114
{
3115
.cmd_num = PFNL_CMD_TABLE_GET_ASTATS,
3116
.cmd_name = "TABLE_GET_ASTATS",
3117
.cmd_cb = pf_handle_table_get_astats,
3118
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3119
.cmd_priv = PRIV_NETINET_PF,
3120
},
3121
{
3122
.cmd_num = PFNL_CMD_TABLE_CLEAR_ASTATS,
3123
.cmd_name = "TABLE_CLEAR_ASTATS",
3124
.cmd_cb = pf_handle_table_clear_astats,
3125
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3126
.cmd_priv = PRIV_NETINET_PF,
3127
},
3128
{
3129
.cmd_num = PFNL_CMD_STATE_LIMITER_ADD,
3130
.cmd_name = "STATE_LIMITER_ADD",
3131
.cmd_cb = pf_handle_state_limiter_add,
3132
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3133
.cmd_priv = PRIV_NETINET_PF,
3134
},
3135
{
3136
.cmd_num = PFNL_CMD_STATE_LIMITER_GET,
3137
.cmd_name = "STATE_LIMITER_GET",
3138
.cmd_cb = pf_handle_state_limiter_get,
3139
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3140
.cmd_priv = PRIV_NETINET_PF,
3141
},
3142
{
3143
.cmd_num = PFNL_CMD_STATE_LIMITER_NGET,
3144
.cmd_name = "STATE_LIMITER_NGET",
3145
.cmd_cb = pf_handle_state_limiter_get,
3146
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3147
.cmd_priv = PRIV_NETINET_PF,
3148
},
3149
{
3150
.cmd_num = PFNL_CMD_SOURCE_LIMITER_ADD,
3151
.cmd_name = "SOURCE_LIMITER_ADD",
3152
.cmd_cb = pf_handle_source_limiter_add,
3153
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3154
.cmd_priv = PRIV_NETINET_PF,
3155
},
3156
{
3157
.cmd_num = PFNL_CMD_SOURCE_LIMITER_GET,
3158
.cmd_name = "SOURCE_LIMITER_GET",
3159
.cmd_cb = pf_handle_source_limiter_get,
3160
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3161
.cmd_priv = PRIV_NETINET_PF,
3162
},
3163
{
3164
.cmd_num = PFNL_CMD_SOURCE_LIMITER_NGET,
3165
.cmd_name = "SOURCE_LIMITER_NGET",
3166
.cmd_cb = pf_handle_source_limiter_get,
3167
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3168
.cmd_priv = PRIV_NETINET_PF,
3169
},
3170
{
3171
.cmd_num = PFNL_CMD_SOURCE_GET,
3172
.cmd_name = "SOURCE_GET",
3173
.cmd_cb = pf_handle_source_get,
3174
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3175
.cmd_priv = PRIV_NETINET_PF,
3176
},
3177
{
3178
.cmd_num = PFNL_CMD_SOURCE_NGET,
3179
.cmd_name = "SOURCE_NGET",
3180
.cmd_cb = pf_handle_source_get,
3181
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3182
.cmd_priv = PRIV_NETINET_PF,
3183
},
3184
{
3185
.cmd_num = PFNL_CMD_SOURCE_CLEAR,
3186
.cmd_name = "SOURCE_CLEAR",
3187
.cmd_cb = pf_handle_source_clear,
3188
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3189
.cmd_priv = PRIV_NETINET_PF,
3190
},
3191
{
3192
.cmd_num = PFNL_CMD_TABLE_TEST_ADDRS,
3193
.cmd_name = "TABLE_TEST_ADDRS",
3194
.cmd_cb = pf_handle_table_test_addrs,
3195
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3196
.cmd_priv = PRIV_NETINET_PF,
3197
},
3198
};
3199
3200
void
3201
pf_nl_register(void)
3202
{
3203
NL_VERIFY_PARSERS(all_parsers);
3204
3205
family_id = genl_register_family(PFNL_FAMILY_NAME, 0, 2, PFNL_CMD_MAX);
3206
genl_register_cmds(family_id, pf_cmds, nitems(pf_cmds));
3207
}
3208
3209
void
3210
pf_nl_unregister(void)
3211
{
3212
genl_unregister_family(family_id);
3213
}
3214
3215