Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netpfil/pf/pf_nl.c
39481 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
if (off == 0)
104
return (false);
105
106
nlattr_add_u32(nw, PF_STP_SEQLO, peer->seqlo);
107
nlattr_add_u32(nw, PF_STP_SEQHI, peer->seqhi);
108
nlattr_add_u32(nw, PF_STP_SEQDIFF, peer->seqdiff);
109
nlattr_add_u16(nw, PF_STP_MAX_WIN, peer->max_win);
110
nlattr_add_u16(nw, PF_STP_MSS, peer->mss);
111
nlattr_add_u8(nw, PF_STP_STATE, peer->state);
112
nlattr_add_u8(nw, PF_STP_WSCALE, peer->wscale);
113
114
if (peer->scrub != NULL) {
115
struct pf_state_scrub *sc = peer->scrub;
116
uint16_t pfss_flags = sc->pfss_flags & PFSS_TIMESTAMP;
117
118
nlattr_add_u16(nw, PF_STP_PFSS_FLAGS, pfss_flags);
119
nlattr_add_u32(nw, PF_STP_PFSS_TS_MOD, sc->pfss_ts_mod);
120
nlattr_add_u8(nw, PF_STP_PFSS_TTL, sc->pfss_ttl);
121
nlattr_add_u8(nw, PF_STP_SCRUB_FLAG, PF_SCRUB_FLAG_VALID);
122
}
123
nlattr_set_len(nw, off);
124
125
return (true);
126
}
127
128
static bool
129
dump_state_key(struct nl_writer *nw, int attr, const struct pf_state_key *key)
130
{
131
int off = nlattr_add_nested(nw, attr);
132
if (off == 0)
133
return (false);
134
135
dump_addr(nw, PF_STK_ADDR0, &key->addr[0], key->af);
136
dump_addr(nw, PF_STK_ADDR1, &key->addr[1], key->af);
137
nlattr_add_u16(nw, PF_STK_PORT0, key->port[0]);
138
nlattr_add_u16(nw, PF_STK_PORT1, key->port[1]);
139
nlattr_add_u8(nw, PF_STK_AF, key->af);
140
nlattr_add_u16(nw, PF_STK_PROTO, key->proto);
141
142
nlattr_set_len(nw, off);
143
144
return (true);
145
}
146
147
static int
148
dump_state(struct nlpcb *nlp, const struct nlmsghdr *hdr, struct pf_kstate *s,
149
struct nl_pstate *npt)
150
{
151
struct nl_writer *nw = npt->nw;
152
int error = 0;
153
int af;
154
struct pf_state_key *key;
155
156
PF_STATE_LOCK_ASSERT(s);
157
158
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
159
goto enomem;
160
161
struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
162
ghdr_new->cmd = PFNL_CMD_GETSTATES;
163
ghdr_new->version = 0;
164
ghdr_new->reserved = 0;
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
ghdr_new->version = 0;
328
ghdr_new->reserved = 0;
329
330
nlattr_add_u32(nw, PF_ST_CREATORID, htonl(creator));
331
332
if (nlmsg_end(nw))
333
return (0);
334
335
enomem:
336
nlmsg_abort(nw);
337
return (ENOMEM);
338
}
339
340
static int
341
pf_handle_getstates(struct nlmsghdr *hdr, struct nl_pstate *npt)
342
{
343
int error;
344
345
struct nl_parsed_state attrs = {};
346
error = nl_parse_nlmsg(hdr, &state_parser, npt, &attrs);
347
if (error != 0)
348
return (error);
349
350
if (attrs.id != 0)
351
error = handle_getstate(npt->nlp, &attrs, hdr, npt);
352
else
353
error = handle_dumpstates(npt->nlp, &attrs, hdr, npt);
354
355
return (error);
356
}
357
358
static int
359
pf_handle_getcreators(struct nlmsghdr *hdr, struct nl_pstate *npt)
360
{
361
uint32_t creators[16];
362
int error = 0;
363
364
bzero(creators, sizeof(creators));
365
366
for (int i = 0; i < V_pf_hashmask; i++) {
367
struct pf_idhash *ih = &V_pf_idhash[i];
368
struct pf_kstate *s;
369
370
if (LIST_EMPTY(&ih->states))
371
continue;
372
373
PF_HASHROW_LOCK(ih);
374
LIST_FOREACH(s, &ih->states, entry) {
375
int j;
376
if (s->timeout == PFTM_UNLINKED)
377
continue;
378
379
for (j = 0; j < nitems(creators); j++) {
380
if (creators[j] == s->creatorid)
381
break;
382
if (creators[j] == 0) {
383
creators[j] = s->creatorid;
384
break;
385
}
386
}
387
if (j == nitems(creators))
388
printf("Warning: too many creators!\n");
389
}
390
PF_HASHROW_UNLOCK(ih);
391
}
392
393
hdr->nlmsg_flags |= NLM_F_MULTI;
394
for (int i = 0; i < nitems(creators); i++) {
395
if (creators[i] == 0)
396
break;
397
error = dump_creatorid(npt->nlp, hdr, creators[i], npt);
398
}
399
400
if (!nlmsg_end_dump(npt->nw, error, hdr)) {
401
NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
402
return (ENOMEM);
403
}
404
405
return (error);
406
}
407
408
static int
409
pf_handle_start(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
410
{
411
return (pf_start());
412
}
413
414
static int
415
pf_handle_stop(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
416
{
417
return (pf_stop());
418
}
419
420
#define _OUT(_field) offsetof(struct pf_addr_wrap, _field)
421
static const struct nlattr_parser nla_p_addr_wrap[] = {
422
{ .type = PF_AT_ADDR, .off = _OUT(v.a.addr), .cb = nlattr_get_in6_addr },
423
{ .type = PF_AT_MASK, .off = _OUT(v.a.mask), .cb = nlattr_get_in6_addr },
424
{ .type = PF_AT_IFNAME, .off = _OUT(v.ifname), .arg = (void *)IFNAMSIZ,.cb = nlattr_get_chara },
425
{ .type = PF_AT_TABLENAME, .off = _OUT(v.tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
426
{ .type = PF_AT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
427
{ .type = PF_AT_IFLAGS, .off = _OUT(iflags), .cb = nlattr_get_uint8 },
428
};
429
NL_DECLARE_ATTR_PARSER(addr_wrap_parser, nla_p_addr_wrap);
430
#undef _OUT
431
432
static bool
433
nlattr_add_addr_wrap(struct nl_writer *nw, int attrtype, struct pf_addr_wrap *a)
434
{
435
int off = nlattr_add_nested(nw, attrtype);
436
437
nlattr_add_in6_addr(nw, PF_AT_ADDR, &a->v.a.addr.v6);
438
nlattr_add_in6_addr(nw, PF_AT_MASK, &a->v.a.mask.v6);
439
nlattr_add_u8(nw, PF_AT_TYPE, a->type);
440
nlattr_add_u8(nw, PF_AT_IFLAGS, a->iflags);
441
442
if (a->type == PF_ADDR_DYNIFTL) {
443
nlattr_add_string(nw, PF_AT_IFNAME, a->v.ifname);
444
nlattr_add_u32(nw, PF_AT_DYNCNT, a->p.dyncnt);
445
} else if (a->type == PF_ADDR_TABLE) {
446
nlattr_add_string(nw, PF_AT_TABLENAME, a->v.tblname);
447
nlattr_add_u32(nw, PF_AT_TBLCNT, a->p.tblcnt);
448
}
449
450
nlattr_set_len(nw, off);
451
452
return (true);
453
}
454
455
#define _OUT(_field) offsetof(struct pf_rule_addr, _field)
456
static const struct nlattr_parser nla_p_ruleaddr[] = {
457
{ .type = PF_RAT_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
458
{ .type = PF_RAT_SRC_PORT, .off = _OUT(port[0]), .cb = nlattr_get_uint16 },
459
{ .type = PF_RAT_DST_PORT, .off = _OUT(port[1]), .cb = nlattr_get_uint16 },
460
{ .type = PF_RAT_NEG, .off = _OUT(neg), .cb = nlattr_get_uint8 },
461
{ .type = PF_RAT_OP, .off = _OUT(port_op), .cb = nlattr_get_uint8 },
462
};
463
NL_DECLARE_ATTR_PARSER(rule_addr_parser, nla_p_ruleaddr);
464
#undef _OUT
465
466
static bool
467
nlattr_add_rule_addr(struct nl_writer *nw, int attrtype, struct pf_rule_addr *r)
468
{
469
struct pf_addr_wrap aw = {0};
470
int off = nlattr_add_nested(nw, attrtype);
471
472
bcopy(&(r->addr), &aw, sizeof(struct pf_addr_wrap));
473
pf_addr_copyout(&aw);
474
475
nlattr_add_addr_wrap(nw, PF_RAT_ADDR, &aw);
476
nlattr_add_u16(nw, PF_RAT_SRC_PORT, r->port[0]);
477
nlattr_add_u16(nw, PF_RAT_DST_PORT, r->port[1]);
478
nlattr_add_u8(nw, PF_RAT_NEG, r->neg);
479
nlattr_add_u8(nw, PF_RAT_OP, r->port_op);
480
481
nlattr_set_len(nw, off);
482
483
return (true);
484
}
485
486
#define _OUT(_field) offsetof(struct pf_mape_portset, _field)
487
static const struct nlattr_parser nla_p_mape_portset[] = {
488
{ .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = nlattr_get_uint8 },
489
{ .type = PF_MET_PSID_LEN, .off = _OUT(psidlen), .cb = nlattr_get_uint8 },
490
{. type = PF_MET_PSID, .off = _OUT(psid), .cb = nlattr_get_uint16 },
491
};
492
NL_DECLARE_ATTR_PARSER(mape_portset_parser, nla_p_mape_portset);
493
#undef _OUT
494
495
static bool
496
nlattr_add_mape_portset(struct nl_writer *nw, int attrtype, const struct pf_mape_portset *m)
497
{
498
int off = nlattr_add_nested(nw, attrtype);
499
500
nlattr_add_u8(nw, PF_MET_OFFSET, m->offset);
501
nlattr_add_u8(nw, PF_MET_PSID_LEN, m->psidlen);
502
nlattr_add_u16(nw, PF_MET_PSID, m->psid);
503
504
nlattr_set_len(nw, off);
505
506
return (true);
507
}
508
509
struct nl_parsed_labels
510
{
511
char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
512
uint32_t i;
513
};
514
515
static int
516
nlattr_get_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt,
517
const void *arg, void *target)
518
{
519
struct nl_parsed_labels *l = (struct nl_parsed_labels *)target;
520
int ret;
521
522
if (l->i >= PF_RULE_MAX_LABEL_COUNT)
523
return (E2BIG);
524
525
ret = nlattr_get_chara(nla, npt, (void *)PF_RULE_LABEL_SIZE,
526
l->labels[l->i]);
527
if (ret == 0)
528
l->i++;
529
530
return (ret);
531
}
532
533
#define _OUT(_field) offsetof(struct nl_parsed_labels, _field)
534
static const struct nlattr_parser nla_p_labels[] = {
535
{ .type = PF_LT_LABEL, .off = 0, .cb = nlattr_get_pf_rule_labels },
536
};
537
NL_DECLARE_ATTR_PARSER(rule_labels_parser, nla_p_labels);
538
#undef _OUT
539
540
static int
541
nlattr_get_nested_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
542
{
543
struct nl_parsed_labels parsed_labels = { };
544
int error;
545
546
/* Assumes target points to the beginning of the structure */
547
error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &rule_labels_parser, npt, &parsed_labels);
548
if (error != 0)
549
return (error);
550
551
memcpy(target, parsed_labels.labels, sizeof(parsed_labels.labels));
552
553
return (0);
554
}
555
556
static bool
557
nlattr_add_labels(struct nl_writer *nw, int attrtype, const struct pf_krule *r)
558
{
559
int off = nlattr_add_nested(nw, attrtype);
560
int i = 0;
561
562
while (r->label[i][0] != 0
563
&& i < PF_RULE_MAX_LABEL_COUNT) {
564
nlattr_add_string(nw, PF_LT_LABEL, r->label[i]);
565
i++;
566
}
567
568
nlattr_set_len(nw, off);
569
570
return (true);
571
}
572
573
#define _OUT(_field) offsetof(struct pf_kpool, _field)
574
static const struct nlattr_parser nla_p_pool[] = {
575
{ .type = PF_PT_KEY, .off = _OUT(key), .arg = (void *)sizeof(struct pf_poolhashkey), .cb = nlattr_get_bytes },
576
{ .type = PF_PT_COUNTER, .off = _OUT(counter), .cb = nlattr_get_in6_addr },
577
{ .type = PF_PT_TBLIDX, .off = _OUT(tblidx), .cb = nlattr_get_uint32 },
578
{ .type = PF_PT_PROXY_SRC_PORT, .off = _OUT(proxy_port[0]), .cb = nlattr_get_uint16 },
579
{ .type = PF_PT_PROXY_DST_PORT, .off = _OUT(proxy_port[1]), .cb = nlattr_get_uint16 },
580
{ .type = PF_PT_OPTS, .off = _OUT(opts), .cb = nlattr_get_uint8 },
581
{ .type = PF_PT_MAPE, .off = _OUT(mape), .arg = &mape_portset_parser, .cb = nlattr_get_nested },
582
};
583
NL_DECLARE_ATTR_PARSER(pool_parser, nla_p_pool);
584
#undef _OUT
585
586
static bool
587
nlattr_add_pool(struct nl_writer *nw, int attrtype, const struct pf_kpool *pool)
588
{
589
int off = nlattr_add_nested(nw, attrtype);
590
591
nlattr_add(nw, PF_PT_KEY, sizeof(struct pf_poolhashkey), &pool->key);
592
nlattr_add_in6_addr(nw, PF_PT_COUNTER, (const struct in6_addr *)&pool->counter);
593
nlattr_add_u32(nw, PF_PT_TBLIDX, pool->tblidx);
594
nlattr_add_u16(nw, PF_PT_PROXY_SRC_PORT, pool->proxy_port[0]);
595
nlattr_add_u16(nw, PF_PT_PROXY_DST_PORT, pool->proxy_port[1]);
596
nlattr_add_u8(nw, PF_PT_OPTS, pool->opts);
597
nlattr_add_mape_portset(nw, PF_PT_MAPE, &pool->mape);
598
599
nlattr_set_len(nw, off);
600
601
return (true);
602
}
603
604
#define _OUT(_field) offsetof(struct pf_rule_uid, _field)
605
static const struct nlattr_parser nla_p_rule_uid[] = {
606
{ .type = PF_RUT_UID_LOW, .off = _OUT(uid[0]), .cb = nlattr_get_uint32 },
607
{ .type = PF_RUT_UID_HIGH, .off = _OUT(uid[1]), .cb = nlattr_get_uint32 },
608
{ .type = PF_RUT_OP, .off = _OUT(op), .cb = nlattr_get_uint8 },
609
};
610
NL_DECLARE_ATTR_PARSER(rule_uid_parser, nla_p_rule_uid);
611
#undef _OUT
612
613
static bool
614
nlattr_add_rule_uid(struct nl_writer *nw, int attrtype, const struct pf_rule_uid *u)
615
{
616
int off = nlattr_add_nested(nw, attrtype);
617
618
nlattr_add_u32(nw, PF_RUT_UID_LOW, u->uid[0]);
619
nlattr_add_u32(nw, PF_RUT_UID_HIGH, u->uid[1]);
620
nlattr_add_u8(nw, PF_RUT_OP, u->op);
621
622
nlattr_set_len(nw, off);
623
624
return (true);
625
}
626
627
struct nl_parsed_timeouts
628
{
629
uint32_t timeouts[PFTM_MAX];
630
uint32_t i;
631
};
632
633
static int
634
nlattr_get_pf_timeout(struct nlattr *nla, struct nl_pstate *npt,
635
const void *arg, void *target)
636
{
637
struct nl_parsed_timeouts *t = (struct nl_parsed_timeouts *)target;
638
int ret;
639
640
if (t->i >= PFTM_MAX)
641
return (E2BIG);
642
643
ret = nlattr_get_uint32(nla, npt, NULL, &t->timeouts[t->i]);
644
if (ret == 0)
645
t->i++;
646
647
return (ret);
648
}
649
650
#define _OUT(_field) offsetof(struct nl_parsed_timeout, _field)
651
static const struct nlattr_parser nla_p_timeouts[] = {
652
{ .type = PF_TT_TIMEOUT, .off = 0, .cb = nlattr_get_pf_timeout },
653
};
654
NL_DECLARE_ATTR_PARSER(timeout_parser, nla_p_timeouts);
655
#undef _OUT
656
657
static int
658
nlattr_get_nested_timeouts(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
659
{
660
struct nl_parsed_timeouts parsed_timeouts = { };
661
int error;
662
663
/* Assumes target points to the beginning of the structure */
664
error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &timeout_parser, npt, &parsed_timeouts);
665
if (error != 0)
666
return (error);
667
668
memcpy(target, parsed_timeouts.timeouts, sizeof(parsed_timeouts.timeouts));
669
670
return (0);
671
}
672
673
static bool
674
nlattr_add_timeout(struct nl_writer *nw, int attrtype, uint32_t *timeout)
675
{
676
int off = nlattr_add_nested(nw, attrtype);
677
678
for (int i = 0; i < PFTM_MAX; i++)
679
nlattr_add_u32(nw, PF_RT_TIMEOUT, timeout[i]);
680
681
nlattr_set_len(nw, off);
682
683
return (true);
684
}
685
686
#define _OUT(_field) offsetof(struct pf_kthreshold, _field)
687
static const struct nlattr_parser nla_p_threshold[] = {
688
{ .type = PF_TH_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
689
{ .type = PF_TH_SECONDS, .off = _OUT(seconds), .cb = nlattr_get_uint32 },
690
};
691
NL_DECLARE_ATTR_PARSER(threshold_parser, nla_p_threshold);
692
#undef _OUT
693
694
#define _OUT(_field) offsetof(struct pf_krule, _field)
695
static const struct nlattr_parser nla_p_rule[] = {
696
{ .type = PF_RT_SRC, .off = _OUT(src), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
697
{ .type = PF_RT_DST, .off = _OUT(dst), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
698
{ .type = PF_RT_RIDENTIFIER, .off = _OUT(ridentifier), .cb = nlattr_get_uint32 },
699
{ .type = PF_RT_LABELS, .off = _OUT(label), .arg = &rule_labels_parser,.cb = nlattr_get_nested_pf_rule_labels },
700
{ .type = PF_RT_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
701
{ .type = PF_RT_QNAME, .off = _OUT(qname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
702
{ .type = PF_RT_PQNAME, .off = _OUT(pqname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
703
{ .type = PF_RT_TAGNAME, .off = _OUT(tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
704
{ .type = PF_RT_MATCH_TAGNAME, .off = _OUT(match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
705
{ .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
706
{ .type = PF_RT_RPOOL_RDR, .off = _OUT(rdr), .arg = &pool_parser, .cb = nlattr_get_nested },
707
{ .type = PF_RT_OS_FINGERPRINT, .off = _OUT(os_fingerprint), .cb = nlattr_get_uint32 },
708
{ .type = PF_RT_RTABLEID, .off = _OUT(rtableid), .cb = nlattr_get_uint32 },
709
{ .type = PF_RT_TIMEOUT, .off = _OUT(timeout), .arg = &timeout_parser, .cb = nlattr_get_nested_timeouts },
710
{ .type = PF_RT_MAX_STATES, .off = _OUT(max_states), .cb = nlattr_get_uint32 },
711
{ .type = PF_RT_MAX_SRC_NODES, .off = _OUT(max_src_nodes), .cb = nlattr_get_uint32 },
712
{ .type = PF_RT_MAX_SRC_STATES, .off = _OUT(max_src_states), .cb = nlattr_get_uint32 },
713
{ .type = PF_RT_MAX_SRC_CONN_RATE_LIMIT, .off = _OUT(max_src_conn_rate.limit), .cb = nlattr_get_uint32 },
714
{ .type = PF_RT_MAX_SRC_CONN_RATE_SECS, .off = _OUT(max_src_conn_rate.seconds), .cb = nlattr_get_uint32 },
715
{ .type = PF_RT_DNPIPE, .off = _OUT(dnpipe), .cb = nlattr_get_uint16 },
716
{ .type = PF_RT_DNRPIPE, .off = _OUT(dnrpipe), .cb = nlattr_get_uint16 },
717
{ .type = PF_RT_DNFLAGS, .off = _OUT(free_flags), .cb = nlattr_get_uint32 },
718
{ .type = PF_RT_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
719
{ .type = PF_RT_PROB, .off = _OUT(prob), .cb = nlattr_get_uint32 },
720
{ .type = PF_RT_CUID, .off = _OUT(cuid), .cb = nlattr_get_uint32 },
721
{. type = PF_RT_CPID, .off = _OUT(cpid), .cb = nlattr_get_uint32 },
722
{ .type = PF_RT_RETURN_ICMP, .off = _OUT(return_icmp), .cb = nlattr_get_uint16 },
723
{ .type = PF_RT_RETURN_ICMP6, .off = _OUT(return_icmp6), .cb = nlattr_get_uint16 },
724
{ .type = PF_RT_MAX_MSS, .off = _OUT(max_mss), .cb = nlattr_get_uint16 },
725
{ .type = PF_RT_SCRUB_FLAGS, .off = _OUT(scrub_flags), .cb = nlattr_get_uint16 },
726
{ .type = PF_RT_UID, .off = _OUT(uid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
727
{ .type = PF_RT_GID, .off = _OUT(gid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
728
{ .type = PF_RT_RULE_FLAG, .off = _OUT(rule_flag), .cb = nlattr_get_uint32 },
729
{ .type = PF_RT_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
730
{ .type = PF_RT_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
731
{ .type = PF_RT_LOG, .off = _OUT(log), .cb = nlattr_get_uint8 },
732
{ .type = PF_RT_LOGIF, .off = _OUT(logif), .cb = nlattr_get_uint8 },
733
{ .type = PF_RT_QUICK, .off = _OUT(quick), .cb = nlattr_get_uint8 },
734
{ .type = PF_RT_IF_NOT, .off = _OUT(ifnot), .cb = nlattr_get_uint8 },
735
{ .type = PF_RT_MATCH_TAG_NOT, .off = _OUT(match_tag_not), .cb = nlattr_get_uint8 },
736
{ .type = PF_RT_NATPASS, .off = _OUT(natpass), .cb = nlattr_get_uint8 },
737
{ .type = PF_RT_KEEP_STATE, .off = _OUT(keep_state), .cb = nlattr_get_uint8 },
738
{ .type = PF_RT_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
739
{ .type = PF_RT_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
740
{ .type = PF_RT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
741
{ .type = PF_RT_CODE, .off = _OUT(code), .cb = nlattr_get_uint8 },
742
{ .type = PF_RT_FLAGS, .off = _OUT(flags), .cb = nlattr_get_uint8 },
743
{ .type = PF_RT_FLAGSET, .off = _OUT(flagset), .cb = nlattr_get_uint8 },
744
{ .type = PF_RT_MIN_TTL, .off = _OUT(min_ttl), .cb = nlattr_get_uint8 },
745
{ .type = PF_RT_ALLOW_OPTS, .off = _OUT(allow_opts), .cb = nlattr_get_uint8 },
746
{ .type = PF_RT_RT, .off = _OUT(rt), .cb = nlattr_get_uint8 },
747
{ .type = PF_RT_RETURN_TTL, .off = _OUT(return_ttl), .cb = nlattr_get_uint8 },
748
{ .type = PF_RT_TOS, .off = _OUT(tos), .cb = nlattr_get_uint8 },
749
{ .type = PF_RT_SET_TOS, .off = _OUT(set_tos), .cb = nlattr_get_uint8 },
750
{ .type = PF_RT_ANCHOR_RELATIVE, .off = _OUT(anchor_relative), .cb = nlattr_get_uint8 },
751
{ .type = PF_RT_ANCHOR_WILDCARD, .off = _OUT(anchor_wildcard), .cb = nlattr_get_uint8 },
752
{ .type = PF_RT_FLUSH, .off = _OUT(flush), .cb = nlattr_get_uint8 },
753
{ .type = PF_RT_PRIO, .off = _OUT(prio), .cb = nlattr_get_uint8 },
754
{ .type = PF_RT_SET_PRIO, .off = _OUT(set_prio[0]), .cb = nlattr_get_uint8 },
755
{ .type = PF_RT_SET_PRIO_REPLY, .off = _OUT(set_prio[1]), .cb = nlattr_get_uint8 },
756
{ .type = PF_RT_DIVERT_ADDRESS, .off = _OUT(divert.addr), .cb = nlattr_get_in6_addr },
757
{ .type = PF_RT_DIVERT_PORT, .off = _OUT(divert.port), .cb = nlattr_get_uint16 },
758
{ .type = PF_RT_RCV_IFNAME, .off = _OUT(rcv_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
759
{ .type = PF_RT_MAX_SRC_CONN, .off = _OUT(max_src_conn), .cb = nlattr_get_uint32 },
760
{ .type = PF_RT_RPOOL_NAT, .off = _OUT(nat), .arg = &pool_parser, .cb = nlattr_get_nested },
761
{ .type = PF_RT_NAF, .off = _OUT(naf), .cb = nlattr_get_uint8 },
762
{ .type = PF_RT_RPOOL_RT, .off = _OUT(route), .arg = &pool_parser, .cb = nlattr_get_nested },
763
{ .type = PF_RT_RCV_IFNOT, .off = _OUT(rcvifnot), .cb = nlattr_get_bool },
764
{ .type = PF_RT_PKTRATE, .off = _OUT(pktrate), .arg = &threshold_parser, .cb = nlattr_get_nested },
765
{ .type = PF_RT_MAX_PKT_SIZE, .off = _OUT(max_pkt_size), .cb = nlattr_get_uint16 },
766
{ .type = PF_RT_TYPE_2, .off = _OUT(type), .cb = nlattr_get_uint16 },
767
{ .type = PF_RT_CODE_2, .off = _OUT(code), .cb = nlattr_get_uint16 },
768
};
769
NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule);
770
#undef _OUT
771
struct nl_parsed_addrule {
772
struct pf_krule *rule;
773
uint32_t ticket;
774
uint32_t pool_ticket;
775
char *anchor;
776
char *anchor_call;
777
};
778
#define _OUT(_field) offsetof(struct nl_parsed_addrule, _field)
779
static const struct nlattr_parser nla_p_addrule[] = {
780
{ .type = PF_ART_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
781
{ .type = PF_ART_POOL_TICKET, .off = _OUT(pool_ticket), .cb = nlattr_get_uint32 },
782
{ .type = PF_ART_ANCHOR, .off = _OUT(anchor), .cb = nlattr_get_string },
783
{ .type = PF_ART_ANCHOR_CALL, .off = _OUT(anchor_call), .cb = nlattr_get_string },
784
{ .type = PF_ART_RULE, .off = _OUT(rule), .arg = &rule_parser, .cb = nlattr_get_nested_ptr }
785
};
786
#undef _OUT
787
NL_DECLARE_PARSER(addrule_parser, struct genlmsghdr, nlf_p_empty, nla_p_addrule);
788
789
static int
790
pf_handle_addrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
791
{
792
int error;
793
struct nl_parsed_addrule attrs = {};
794
795
attrs.rule = pf_krule_alloc();
796
797
error = nl_parse_nlmsg(hdr, &addrule_parser, npt, &attrs);
798
if (error != 0) {
799
pf_free_rule(attrs.rule);
800
return (error);
801
}
802
803
error = pf_ioctl_addrule(attrs.rule, attrs.ticket, attrs.pool_ticket,
804
attrs.anchor, attrs.anchor_call, nlp_get_cred(npt->nlp)->cr_uid,
805
hdr->nlmsg_pid);
806
807
return (error);
808
}
809
810
#define _OUT(_field) offsetof(struct pfioc_rule, _field)
811
static const struct nlattr_parser nla_p_getrules[] = {
812
{ .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
813
{ .type = PF_GR_ACTION, .off = _OUT(rule.action), .cb = nlattr_get_uint8 },
814
};
815
#undef _OUT
816
NL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, nlf_p_empty, nla_p_getrules);
817
818
static int
819
pf_handle_getrules(struct nlmsghdr *hdr, struct nl_pstate *npt)
820
{
821
struct pfioc_rule attrs = {};
822
int error;
823
struct nl_writer *nw = npt->nw;
824
struct genlmsghdr *ghdr_new;
825
826
error = nl_parse_nlmsg(hdr, &getrules_parser, npt, &attrs);
827
if (error != 0)
828
return (error);
829
830
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
831
return (ENOMEM);
832
833
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
834
ghdr_new->cmd = PFNL_CMD_GETRULES;
835
ghdr_new->version = 0;
836
ghdr_new->reserved = 0;
837
838
error = pf_ioctl_getrules(&attrs);
839
if (error != 0)
840
goto out;
841
842
nlattr_add_u32(nw, PF_GR_NR, attrs.nr);
843
nlattr_add_u32(nw, PF_GR_TICKET, attrs.ticket);
844
845
if (!nlmsg_end(nw)) {
846
error = ENOMEM;
847
goto out;
848
}
849
850
return (0);
851
852
out:
853
nlmsg_abort(nw);
854
return (error);
855
}
856
857
struct nl_parsed_get_rule {
858
char anchor[MAXPATHLEN];
859
uint8_t action;
860
uint32_t nr;
861
uint32_t ticket;
862
uint8_t clear;
863
};
864
#define _OUT(_field) offsetof(struct nl_parsed_get_rule, _field)
865
static const struct nlattr_parser nla_p_getrule[] = {
866
{ .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
867
{ .type = PF_GR_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
868
{ .type = PF_GR_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
869
{ .type = PF_GR_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
870
{ .type = PF_GR_CLEAR, .off = _OUT(clear), .cb = nlattr_get_uint8 },
871
};
872
#undef _OUT
873
NL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, nlf_p_empty, nla_p_getrule);
874
875
static int
876
pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
877
{
878
char anchor_call[MAXPATHLEN];
879
struct nl_parsed_get_rule attrs = {};
880
struct nl_writer *nw = npt->nw;
881
struct genlmsghdr *ghdr_new;
882
struct pf_kruleset *ruleset;
883
struct pf_krule *rule;
884
u_int64_t src_nodes_total = 0;
885
int rs_num;
886
int error;
887
888
error = nl_parse_nlmsg(hdr, &getrule_parser, npt, &attrs);
889
if (error != 0)
890
return (error);
891
892
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
893
return (ENOMEM);
894
895
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
896
ghdr_new->cmd = PFNL_CMD_GETRULE;
897
ghdr_new->version = 0;
898
ghdr_new->reserved = 0;
899
900
PF_RULES_WLOCK();
901
ruleset = pf_find_kruleset(attrs.anchor);
902
if (ruleset == NULL) {
903
PF_RULES_WUNLOCK();
904
error = ENOENT;
905
goto out;
906
}
907
908
rs_num = pf_get_ruleset_number(attrs.action);
909
if (rs_num >= PF_RULESET_MAX) {
910
PF_RULES_WUNLOCK();
911
error = EINVAL;
912
goto out;
913
}
914
915
if (attrs.ticket != ruleset->rules[rs_num].active.ticket) {
916
PF_RULES_WUNLOCK();
917
error = EBUSY;
918
goto out;
919
}
920
921
rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
922
while ((rule != NULL) && (rule->nr != attrs.nr))
923
rule = TAILQ_NEXT(rule, entries);
924
if (rule == NULL) {
925
PF_RULES_WUNLOCK();
926
error = EBUSY;
927
goto out;
928
}
929
930
nlattr_add_rule_addr(nw, PF_RT_SRC, &rule->src);
931
nlattr_add_rule_addr(nw, PF_RT_DST, &rule->dst);
932
nlattr_add_u32(nw, PF_RT_RIDENTIFIER, rule->ridentifier);
933
nlattr_add_labels(nw, PF_RT_LABELS, rule);
934
nlattr_add_string(nw, PF_RT_IFNAME, rule->ifname);
935
nlattr_add_string(nw, PF_RT_QNAME, rule->qname);
936
nlattr_add_string(nw, PF_RT_PQNAME, rule->pqname);
937
nlattr_add_string(nw, PF_RT_TAGNAME, rule->tagname);
938
nlattr_add_string(nw, PF_RT_MATCH_TAGNAME, rule->match_tagname);
939
nlattr_add_string(nw, PF_RT_OVERLOAD_TBLNAME, rule->overload_tblname);
940
nlattr_add_pool(nw, PF_RT_RPOOL_RDR, &rule->rdr);
941
nlattr_add_pool(nw, PF_RT_RPOOL_NAT, &rule->nat);
942
nlattr_add_pool(nw, PF_RT_RPOOL_RT, &rule->route);
943
nlattr_add_u32(nw, PF_RT_OS_FINGERPRINT, rule->os_fingerprint);
944
nlattr_add_u32(nw, PF_RT_RTABLEID, rule->rtableid);
945
nlattr_add_timeout(nw, PF_RT_TIMEOUT, rule->timeout);
946
nlattr_add_u32(nw, PF_RT_MAX_STATES, rule->max_states);
947
nlattr_add_u32(nw, PF_RT_MAX_SRC_NODES, rule->max_src_nodes);
948
nlattr_add_u32(nw, PF_RT_MAX_SRC_STATES, rule->max_src_states);
949
nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN, rule->max_src_conn);
950
nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_LIMIT, rule->max_src_conn_rate.limit);
951
nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_SECS, rule->max_src_conn_rate.seconds);
952
nlattr_add_u16(nw, PF_RT_MAX_PKT_SIZE, rule->max_pkt_size);
953
954
nlattr_add_u16(nw, PF_RT_DNPIPE, rule->dnpipe);
955
nlattr_add_u16(nw, PF_RT_DNRPIPE, rule->dnrpipe);
956
nlattr_add_u32(nw, PF_RT_DNFLAGS, rule->free_flags);
957
958
nlattr_add_u32(nw, PF_RT_NR, rule->nr);
959
nlattr_add_u32(nw, PF_RT_PROB, rule->prob);
960
nlattr_add_u32(nw, PF_RT_CUID, rule->cuid);
961
nlattr_add_u32(nw, PF_RT_CPID, rule->cpid);
962
963
nlattr_add_u16(nw, PF_RT_RETURN_ICMP, rule->return_icmp);
964
nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
965
nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
966
nlattr_add_u16(nw, PF_RT_MAX_MSS, rule->max_mss);
967
nlattr_add_u16(nw, PF_RT_SCRUB_FLAGS, rule->scrub_flags);
968
969
nlattr_add_rule_uid(nw, PF_RT_UID, &rule->uid);
970
nlattr_add_rule_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&rule->gid);
971
972
nlattr_add_string(nw, PF_RT_RCV_IFNAME, rule->rcv_ifname);
973
nlattr_add_bool(nw, PF_RT_RCV_IFNOT, rule->rcvifnot);
974
975
nlattr_add_u32(nw, PF_RT_RULE_FLAG, rule->rule_flag);
976
nlattr_add_u8(nw, PF_RT_ACTION, rule->action);
977
nlattr_add_u8(nw, PF_RT_DIRECTION, rule->direction);
978
nlattr_add_u8(nw, PF_RT_LOG, rule->log);
979
nlattr_add_u8(nw, PF_RT_LOGIF, rule->logif);
980
nlattr_add_u8(nw, PF_RT_QUICK, rule->quick);
981
nlattr_add_u8(nw, PF_RT_IF_NOT, rule->ifnot);
982
nlattr_add_u8(nw, PF_RT_MATCH_TAG_NOT, rule->match_tag_not);
983
nlattr_add_u8(nw, PF_RT_NATPASS, rule->natpass);
984
nlattr_add_u8(nw, PF_RT_KEEP_STATE, rule->keep_state);
985
986
nlattr_add_u8(nw, PF_RT_AF, rule->af);
987
nlattr_add_u8(nw, PF_RT_NAF, rule->naf);
988
nlattr_add_u8(nw, PF_RT_PROTO, rule->proto);
989
990
nlattr_add_u8(nw, PF_RT_TYPE, rule->type);
991
nlattr_add_u8(nw, PF_RT_CODE, rule->code);
992
nlattr_add_u16(nw, PF_RT_TYPE_2, rule->type);
993
nlattr_add_u16(nw, PF_RT_CODE_2, rule->code);
994
995
nlattr_add_u8(nw, PF_RT_FLAGS, rule->flags);
996
nlattr_add_u8(nw, PF_RT_FLAGSET, rule->flagset);
997
nlattr_add_u8(nw, PF_RT_MIN_TTL, rule->min_ttl);
998
nlattr_add_u8(nw, PF_RT_ALLOW_OPTS, rule->allow_opts);
999
nlattr_add_u8(nw, PF_RT_RT, rule->rt);
1000
nlattr_add_u8(nw, PF_RT_RETURN_TTL, rule->return_ttl);
1001
nlattr_add_u8(nw, PF_RT_TOS, rule->tos);
1002
nlattr_add_u8(nw, PF_RT_SET_TOS, rule->set_tos);
1003
nlattr_add_u8(nw, PF_RT_ANCHOR_RELATIVE, rule->anchor_relative);
1004
nlattr_add_u8(nw, PF_RT_ANCHOR_WILDCARD, rule->anchor_wildcard);
1005
nlattr_add_u8(nw, PF_RT_FLUSH, rule->flush);
1006
nlattr_add_u8(nw, PF_RT_PRIO, rule->prio);
1007
nlattr_add_u8(nw, PF_RT_SET_PRIO, rule->set_prio[0]);
1008
nlattr_add_u8(nw, PF_RT_SET_PRIO_REPLY, rule->set_prio[1]);
1009
1010
nlattr_add_in6_addr(nw, PF_RT_DIVERT_ADDRESS, &rule->divert.addr.v6);
1011
nlattr_add_u16(nw, PF_RT_DIVERT_PORT, rule->divert.port);
1012
1013
nlattr_add_u64(nw, PF_RT_PACKETS_IN, pf_counter_u64_fetch(&rule->packets[0]));
1014
nlattr_add_u64(nw, PF_RT_PACKETS_OUT, pf_counter_u64_fetch(&rule->packets[1]));
1015
nlattr_add_u64(nw, PF_RT_BYTES_IN, pf_counter_u64_fetch(&rule->bytes[0]));
1016
nlattr_add_u64(nw, PF_RT_BYTES_OUT, pf_counter_u64_fetch(&rule->bytes[1]));
1017
nlattr_add_u64(nw, PF_RT_EVALUATIONS, pf_counter_u64_fetch(&rule->evaluations));
1018
nlattr_add_u64(nw, PF_RT_TIMESTAMP, pf_get_timestamp(rule));
1019
nlattr_add_u64(nw, PF_RT_STATES_CUR, counter_u64_fetch(rule->states_cur));
1020
nlattr_add_u64(nw, PF_RT_STATES_TOTAL, counter_u64_fetch(rule->states_tot));
1021
for (pf_sn_types_t sn_type=0; sn_type<PF_SN_MAX; sn_type++)
1022
src_nodes_total += counter_u64_fetch(rule->src_nodes[sn_type]);
1023
nlattr_add_u64(nw, PF_RT_SRC_NODES, src_nodes_total);
1024
nlattr_add_u64(nw, PF_RT_SRC_NODES_LIMIT, counter_u64_fetch(rule->src_nodes[PF_SN_LIMIT]));
1025
nlattr_add_u64(nw, PF_RT_SRC_NODES_NAT, counter_u64_fetch(rule->src_nodes[PF_SN_NAT]));
1026
nlattr_add_u64(nw, PF_RT_SRC_NODES_ROUTE, counter_u64_fetch(rule->src_nodes[PF_SN_ROUTE]));
1027
nlattr_add_pf_threshold(nw, PF_RT_PKTRATE, &rule->pktrate);
1028
nlattr_add_time_t(nw, PF_RT_EXPTIME, time_second - (time_uptime - rule->exptime));
1029
1030
error = pf_kanchor_copyout(ruleset, rule, anchor_call, sizeof(anchor_call));
1031
MPASS(error == 0);
1032
1033
nlattr_add_string(nw, PF_RT_ANCHOR_CALL, anchor_call);
1034
1035
if (attrs.clear)
1036
pf_krule_clear_counters(rule);
1037
1038
PF_RULES_WUNLOCK();
1039
1040
if (!nlmsg_end(nw)) {
1041
error = ENOMEM;
1042
goto out;
1043
}
1044
1045
return (0);
1046
out:
1047
nlmsg_abort(nw);
1048
return (error);
1049
}
1050
1051
#define _OUT(_field) offsetof(struct pf_kstate_kill, _field)
1052
static const struct nlattr_parser nla_p_clear_states[] = {
1053
{ .type = PF_CS_CMP_ID, .off = _OUT(psk_pfcmp.id), .cb = nlattr_get_uint64 },
1054
{ .type = PF_CS_CMP_CREATORID, .off = _OUT(psk_pfcmp.creatorid), .cb = nlattr_get_uint32 },
1055
{ .type = PF_CS_CMP_DIR, .off = _OUT(psk_pfcmp.direction), .cb = nlattr_get_uint8 },
1056
{ .type = PF_CS_AF, .off = _OUT(psk_af), .cb = nlattr_get_uint8 },
1057
{ .type = PF_CS_PROTO, .off = _OUT(psk_proto), .cb = nlattr_get_uint8 },
1058
{ .type = PF_CS_SRC, .off = _OUT(psk_src), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1059
{ .type = PF_CS_DST, .off = _OUT(psk_dst), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1060
{ .type = PF_CS_RT_ADDR, .off = _OUT(psk_rt_addr), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1061
{ .type = PF_CS_IFNAME, .off = _OUT(psk_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
1062
{ .type = PF_CS_LABEL, .off = _OUT(psk_label), .arg = (void *)PF_RULE_LABEL_SIZE, .cb = nlattr_get_chara },
1063
{ .type = PF_CS_KILL_MATCH, .off = _OUT(psk_kill_match), .cb = nlattr_get_bool },
1064
{ .type = PF_CS_NAT, .off = _OUT(psk_nat), .cb = nlattr_get_bool },
1065
};
1066
#undef _OUT
1067
NL_DECLARE_PARSER(clear_states_parser, struct genlmsghdr, nlf_p_empty, nla_p_clear_states);
1068
1069
static int
1070
pf_handle_killclear_states(struct nlmsghdr *hdr, struct nl_pstate *npt, int cmd)
1071
{
1072
struct pf_kstate_kill kill = {};
1073
struct epoch_tracker et;
1074
struct nl_writer *nw = npt->nw;
1075
struct genlmsghdr *ghdr_new;
1076
int error;
1077
unsigned int killed = 0;
1078
1079
error = nl_parse_nlmsg(hdr, &clear_states_parser, npt, &kill);
1080
if (error != 0)
1081
return (error);
1082
1083
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1084
return (ENOMEM);
1085
1086
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1087
ghdr_new->cmd = cmd;
1088
ghdr_new->version = 0;
1089
ghdr_new->reserved = 0;
1090
1091
NET_EPOCH_ENTER(et);
1092
if (cmd == PFNL_CMD_KILLSTATES)
1093
pf_killstates(&kill, &killed);
1094
else
1095
killed = pf_clear_states(&kill);
1096
NET_EPOCH_EXIT(et);
1097
1098
nlattr_add_u32(nw, PF_CS_KILLED, killed);
1099
1100
if (! nlmsg_end(nw)) {
1101
error = ENOMEM;
1102
goto out;
1103
}
1104
1105
return (0);
1106
1107
out:
1108
nlmsg_abort(nw);
1109
return (error);
1110
}
1111
1112
static int
1113
pf_handle_clear_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
1114
{
1115
return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_CLRSTATES));
1116
}
1117
1118
static int
1119
pf_handle_kill_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
1120
{
1121
return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_KILLSTATES));
1122
}
1123
1124
struct nl_parsed_set_statusif {
1125
char ifname[IFNAMSIZ];
1126
};
1127
#define _OUT(_field) offsetof(struct nl_parsed_set_statusif, _field)
1128
static const struct nlattr_parser nla_p_set_statusif[] = {
1129
{ .type = PF_SS_IFNAME, .off = _OUT(ifname), .arg = (const void *)IFNAMSIZ, .cb = nlattr_get_chara },
1130
};
1131
#undef _OUT
1132
NL_DECLARE_PARSER(set_statusif_parser, struct genlmsghdr, nlf_p_empty, nla_p_set_statusif);
1133
1134
static int
1135
pf_handle_set_statusif(struct nlmsghdr *hdr, struct nl_pstate *npt)
1136
{
1137
int error;
1138
struct nl_parsed_set_statusif attrs = {};
1139
1140
error = nl_parse_nlmsg(hdr, &set_statusif_parser, npt, &attrs);
1141
if (error != 0)
1142
return (error);
1143
1144
PF_RULES_WLOCK();
1145
strlcpy(V_pf_status.ifname, attrs.ifname, IFNAMSIZ);
1146
PF_RULES_WUNLOCK();
1147
1148
return (0);
1149
}
1150
1151
static bool
1152
nlattr_add_counters(struct nl_writer *nw, int attr, size_t number, char **names,
1153
counter_u64_t *counters)
1154
{
1155
for (int i = 0; i < number; i++) {
1156
int off = nlattr_add_nested(nw, attr);
1157
nlattr_add_u32(nw, PF_C_ID, i);
1158
nlattr_add_string(nw, PF_C_NAME, names[i]);
1159
nlattr_add_u64(nw, PF_C_COUNTER, counter_u64_fetch(counters[i]));
1160
nlattr_set_len(nw, off);
1161
}
1162
1163
return (true);
1164
}
1165
1166
static bool
1167
nlattr_add_fcounters(struct nl_writer *nw, int attr, size_t number, char **names,
1168
struct pf_counter_u64 *counters)
1169
{
1170
for (int i = 0; i < number; i++) {
1171
int off = nlattr_add_nested(nw, attr);
1172
nlattr_add_u32(nw, PF_C_ID, i);
1173
nlattr_add_string(nw, PF_C_NAME, names[i]);
1174
nlattr_add_u64(nw, PF_C_COUNTER, pf_counter_u64_fetch(&counters[i]));
1175
nlattr_set_len(nw, off);
1176
}
1177
1178
return (true);
1179
}
1180
1181
static bool
1182
nlattr_add_u64_array(struct nl_writer *nw, int attr, size_t number, uint64_t *array)
1183
{
1184
int off = nlattr_add_nested(nw, attr);
1185
1186
for (size_t i = 0; i < number; i++)
1187
nlattr_add_u64(nw, 0, array[i]);
1188
1189
nlattr_set_len(nw, off);
1190
1191
return (true);
1192
}
1193
1194
static int
1195
pf_handle_get_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
1196
{
1197
struct pf_status s;
1198
struct nl_writer *nw = npt->nw;
1199
struct genlmsghdr *ghdr_new;
1200
char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
1201
char *pf_lcounter[KLCNT_MAX+1] = KLCNT_NAMES;
1202
char *pf_fcounter[FCNT_MAX+1] = FCNT_NAMES;
1203
time_t since;
1204
int error;
1205
1206
PF_RULES_RLOCK_TRACKER;
1207
1208
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1209
return (ENOMEM);
1210
1211
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1212
ghdr_new->cmd = PFNL_CMD_GET_STATUS;
1213
ghdr_new->version = 0;
1214
ghdr_new->reserved = 0;
1215
1216
since = time_second - (time_uptime - V_pf_status.since);
1217
1218
PF_RULES_RLOCK();
1219
1220
nlattr_add_string(nw, PF_GS_IFNAME, V_pf_status.ifname);
1221
nlattr_add_bool(nw, PF_GS_RUNNING, V_pf_status.running);
1222
nlattr_add_u32(nw, PF_GS_SINCE, since);
1223
nlattr_add_u32(nw, PF_GS_DEBUG, V_pf_status.debug);
1224
nlattr_add_u32(nw, PF_GS_HOSTID, ntohl(V_pf_status.hostid));
1225
nlattr_add_u32(nw, PF_GS_STATES, V_pf_status.states);
1226
nlattr_add_u32(nw, PF_GS_SRC_NODES, V_pf_status.src_nodes);
1227
nlattr_add_u32(nw, PF_GS_REASSEMBLE, V_pf_status.reass);
1228
nlattr_add_u32(nw, PF_GS_SYNCOOKIES_ACTIVE, V_pf_status.syncookies_active);
1229
1230
nlattr_add_counters(nw, PF_GS_COUNTERS, PFRES_MAX, pf_reasons,
1231
V_pf_status.counters);
1232
nlattr_add_counters(nw, PF_GS_LCOUNTERS, KLCNT_MAX, pf_lcounter,
1233
V_pf_status.lcounters);
1234
nlattr_add_fcounters(nw, PF_GS_FCOUNTERS, FCNT_MAX, pf_fcounter,
1235
V_pf_status.fcounters);
1236
nlattr_add_counters(nw, PF_GS_SCOUNTERS, SCNT_MAX, pf_fcounter,
1237
V_pf_status.scounters);
1238
nlattr_add_counters(nw, PF_GS_NCOUNTERS, NCNT_MAX, pf_fcounter,
1239
V_pf_status.ncounters);
1240
nlattr_add_u64(nw, PF_GS_FRAGMENTS, pf_normalize_get_frag_count());
1241
1242
pfi_update_status(V_pf_status.ifname, &s);
1243
nlattr_add_u64_array(nw, PF_GS_BCOUNTERS, 2 * 2, (uint64_t *)s.bcounters);
1244
nlattr_add_u64_array(nw, PF_GS_PCOUNTERS, 2 * 2 * 2, (uint64_t *)s.pcounters);
1245
1246
nlattr_add(nw, PF_GS_CHKSUM, PF_MD5_DIGEST_LENGTH, V_pf_status.pf_chksum);
1247
1248
PF_RULES_RUNLOCK();
1249
1250
if (!nlmsg_end(nw)) {
1251
error = ENOMEM;
1252
goto out;
1253
}
1254
1255
return (0);
1256
1257
out:
1258
nlmsg_abort(nw);
1259
return (error);
1260
}
1261
1262
static int
1263
pf_handle_clear_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
1264
{
1265
pf_ioctl_clear_status();
1266
1267
return (0);
1268
}
1269
1270
#define _OUT(_field) offsetof(struct pfioc_natlook, _field)
1271
static const struct nlattr_parser nla_p_natlook[] = {
1272
{ .type = PF_NL_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
1273
{ .type = PF_NL_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
1274
{ .type = PF_NL_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
1275
{ .type = PF_NL_SRC_ADDR, .off = _OUT(saddr), .cb = nlattr_get_in6_addr },
1276
{ .type = PF_NL_DST_ADDR, .off = _OUT(daddr), .cb = nlattr_get_in6_addr },
1277
{ .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = nlattr_get_uint16 },
1278
{ .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = nlattr_get_uint16 },
1279
};
1280
#undef _OUT
1281
NL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, nlf_p_empty, nla_p_natlook);
1282
1283
static int
1284
pf_handle_natlook(struct nlmsghdr *hdr, struct nl_pstate *npt)
1285
{
1286
struct pfioc_natlook attrs = {};
1287
struct nl_writer *nw = npt->nw;
1288
struct genlmsghdr *ghdr_new;
1289
int error;
1290
1291
error = nl_parse_nlmsg(hdr, &natlook_parser, npt, &attrs);
1292
if (error != 0)
1293
return (error);
1294
1295
error = pf_ioctl_natlook(&attrs);
1296
if (error != 0)
1297
return (error);
1298
1299
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1300
return (ENOMEM);
1301
1302
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1303
ghdr_new->cmd = PFNL_CMD_NATLOOK;
1304
ghdr_new->version = 0;
1305
ghdr_new->reserved = 0;
1306
1307
nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &attrs.rsaddr.v6);
1308
nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &attrs.rdaddr.v6);
1309
nlattr_add_u16(nw, PF_NL_SRC_PORT, attrs.rsport);
1310
nlattr_add_u16(nw, PF_NL_DST_PORT, attrs.rdport);
1311
1312
if (!nlmsg_end(nw)) {
1313
nlmsg_abort(nw);
1314
return (ENOMEM);
1315
}
1316
1317
return (0);
1318
}
1319
1320
struct pf_nl_set_debug
1321
{
1322
uint32_t level;
1323
};
1324
#define _OUT(_field) offsetof(struct pf_nl_set_debug, _field)
1325
static const struct nlattr_parser nla_p_set_debug[] = {
1326
{ .type = PF_SD_LEVEL, .off = _OUT(level), .cb = nlattr_get_uint32 },
1327
};
1328
#undef _OUT
1329
NL_DECLARE_PARSER(set_debug_parser, struct genlmsghdr, nlf_p_empty, nla_p_set_debug);
1330
1331
static int
1332
pf_handle_set_debug(struct nlmsghdr *hdr, struct nl_pstate *npt)
1333
{
1334
struct pf_nl_set_debug attrs = {};
1335
int error;
1336
1337
error = nl_parse_nlmsg(hdr, &set_debug_parser, npt, &attrs);
1338
if (error != 0)
1339
return (error);
1340
1341
PF_RULES_WLOCK();
1342
V_pf_status.debug = attrs.level;
1343
PF_RULES_WUNLOCK();
1344
1345
return (0);
1346
}
1347
1348
struct pf_nl_set_timeout
1349
{
1350
uint32_t timeout;
1351
uint32_t seconds;
1352
};
1353
#define _OUT(_field) offsetof(struct pf_nl_set_timeout, _field)
1354
static const struct nlattr_parser nla_p_set_timeout[] = {
1355
{ .type = PF_TO_TIMEOUT, .off = _OUT(timeout), .cb = nlattr_get_uint32 },
1356
{ .type = PF_TO_SECONDS, .off = _OUT(seconds), .cb = nlattr_get_uint32 },
1357
};
1358
#undef _OUT
1359
NL_DECLARE_PARSER(set_timeout_parser, struct genlmsghdr, nlf_p_empty, nla_p_set_timeout);
1360
1361
static int
1362
pf_handle_set_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
1363
{
1364
struct pf_nl_set_timeout attrs = {};
1365
int error;
1366
1367
error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
1368
if (error != 0)
1369
return (error);
1370
1371
return (pf_ioctl_set_timeout(attrs.timeout, attrs.seconds, NULL));
1372
}
1373
1374
static int
1375
pf_handle_get_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
1376
{
1377
struct pf_nl_set_timeout attrs = {};
1378
struct nl_writer *nw = npt->nw;
1379
struct genlmsghdr *ghdr_new;
1380
int error;
1381
1382
error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
1383
if (error != 0)
1384
return (error);
1385
1386
error = pf_ioctl_get_timeout(attrs.timeout, &attrs.seconds);
1387
if (error != 0)
1388
return (error);
1389
1390
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1391
return (ENOMEM);
1392
1393
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1394
ghdr_new->cmd = PFNL_CMD_GET_TIMEOUT;
1395
ghdr_new->version = 0;
1396
ghdr_new->reserved = 0;
1397
1398
nlattr_add_u32(nw, PF_TO_SECONDS, attrs.seconds);
1399
1400
if (!nlmsg_end(nw)) {
1401
nlmsg_abort(nw);
1402
return (ENOMEM);
1403
}
1404
1405
return (0);
1406
}
1407
1408
struct pf_nl_set_limit
1409
{
1410
uint32_t index;
1411
uint32_t limit;
1412
};
1413
#define _OUT(_field) offsetof(struct pf_nl_set_limit, _field)
1414
static const struct nlattr_parser nla_p_set_limit[] = {
1415
{ .type = PF_LI_INDEX, .off = _OUT(index), .cb = nlattr_get_uint32 },
1416
{ .type = PF_LI_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
1417
};
1418
#undef _OUT
1419
NL_DECLARE_PARSER(set_limit_parser, struct genlmsghdr, nlf_p_empty, nla_p_set_limit);
1420
1421
static int
1422
pf_handle_set_limit(struct nlmsghdr *hdr, struct nl_pstate *npt)
1423
{
1424
struct pf_nl_set_limit attrs = {};
1425
int error;
1426
1427
error = nl_parse_nlmsg(hdr, &set_limit_parser, npt, &attrs);
1428
if (error != 0)
1429
return (error);
1430
1431
return (pf_ioctl_set_limit(attrs.index, attrs.limit, NULL));
1432
}
1433
1434
static int
1435
pf_handle_get_limit(struct nlmsghdr *hdr, struct nl_pstate *npt)
1436
{
1437
struct pf_nl_set_limit attrs = {};
1438
struct nl_writer *nw = npt->nw;
1439
struct genlmsghdr *ghdr_new;
1440
int error;
1441
1442
error = nl_parse_nlmsg(hdr, &set_limit_parser, npt, &attrs);
1443
if (error != 0)
1444
return (error);
1445
1446
error = pf_ioctl_get_limit(attrs.index, &attrs.limit);
1447
if (error != 0)
1448
return (error);
1449
1450
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1451
return (ENOMEM);
1452
1453
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1454
ghdr_new->cmd = PFNL_CMD_GET_LIMIT;
1455
ghdr_new->version = 0;
1456
ghdr_new->reserved = 0;
1457
1458
nlattr_add_u32(nw, PF_LI_LIMIT, attrs.limit);
1459
1460
if (!nlmsg_end(nw)) {
1461
nlmsg_abort(nw);
1462
return (ENOMEM);
1463
}
1464
1465
return (0);
1466
}
1467
1468
static int
1469
pf_handle_begin_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
1470
{
1471
struct nl_writer *nw = npt->nw;
1472
struct genlmsghdr *ghdr_new;
1473
uint32_t ticket;
1474
int error;
1475
1476
error = pf_ioctl_begin_addrs(&ticket);
1477
if (error != 0)
1478
return (error);
1479
1480
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1481
return (ENOMEM);
1482
1483
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1484
ghdr_new->cmd = PFNL_CMD_BEGIN_ADDRS;
1485
ghdr_new->version = 0;
1486
ghdr_new->reserved = 0;
1487
1488
nlattr_add_u32(nw, PF_BA_TICKET, ticket);
1489
1490
if (!nlmsg_end(nw)) {
1491
nlmsg_abort(nw);
1492
return (ENOMEM);
1493
}
1494
1495
return (0);
1496
}
1497
1498
static bool
1499
nlattr_add_pool_addr(struct nl_writer *nw, int attrtype, struct pf_pooladdr *a)
1500
{
1501
int off;
1502
1503
off = nlattr_add_nested(nw, attrtype);
1504
1505
nlattr_add_addr_wrap(nw, PF_PA_ADDR, &a->addr);
1506
nlattr_add_string(nw, PF_PA_IFNAME, a->ifname);
1507
1508
nlattr_set_len(nw, off);
1509
1510
return (true);
1511
}
1512
1513
#define _OUT(_field) offsetof(struct pf_pooladdr, _field)
1514
static const struct nlattr_parser nla_p_pool_addr[] = {
1515
{ .type = PF_PA_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
1516
{ .type = PF_PA_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
1517
};
1518
NL_DECLARE_ATTR_PARSER(pool_addr_parser, nla_p_pool_addr);
1519
#undef _OUT
1520
1521
#define _OUT(_field) offsetof(struct pf_nl_pooladdr, _field)
1522
static const struct nlattr_parser nla_p_add_addr[] = {
1523
{ .type = PF_AA_ACTION, .off = _OUT(action), .cb = nlattr_get_uint32 },
1524
{ .type = PF_AA_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
1525
{ .type = PF_AA_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
1526
{ .type = PF_AA_R_NUM, .off = _OUT(r_num), .cb = nlattr_get_uint32 },
1527
{ .type = PF_AA_R_ACTION, .off = _OUT(r_action), .cb = nlattr_get_uint8 },
1528
{ .type = PF_AA_R_LAST, .off = _OUT(r_last), .cb = nlattr_get_uint8 },
1529
{ .type = PF_AA_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
1530
{ .type = PF_AA_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
1531
{ .type = PF_AA_ADDR, .off = _OUT(addr), .arg = &pool_addr_parser, .cb = nlattr_get_nested },
1532
{ .type = PF_AA_WHICH, .off = _OUT(which), .cb = nlattr_get_uint32 },
1533
};
1534
#undef _OUT
1535
NL_DECLARE_PARSER(add_addr_parser, struct genlmsghdr, nlf_p_empty, nla_p_add_addr);
1536
1537
static int
1538
pf_handle_add_addr(struct nlmsghdr *hdr, struct nl_pstate *npt)
1539
{
1540
struct pf_nl_pooladdr attrs = { 0 };
1541
int error;
1542
1543
error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
1544
if (error != 0)
1545
return (error);
1546
1547
if (attrs.which == 0)
1548
attrs.which = PF_RDR;
1549
1550
error = pf_ioctl_add_addr(&attrs);
1551
1552
return (error);
1553
}
1554
1555
static int
1556
pf_handle_get_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
1557
{
1558
struct pf_nl_pooladdr attrs = { 0 };
1559
struct nl_writer *nw = npt->nw;
1560
struct genlmsghdr *ghdr_new;
1561
int error;
1562
1563
error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
1564
if (error != 0)
1565
return (error);
1566
1567
if (attrs.which == 0)
1568
attrs.which = PF_RDR;
1569
1570
error = pf_ioctl_get_addrs(&attrs);
1571
if (error != 0)
1572
return (error);
1573
1574
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1575
return (ENOMEM);
1576
1577
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1578
ghdr_new->cmd = PFNL_CMD_GET_ADDRS;
1579
ghdr_new->version = 0;
1580
ghdr_new->reserved = 0;
1581
1582
nlattr_add_u32(nw, PF_AA_NR, attrs.nr);
1583
1584
if (!nlmsg_end(nw)) {
1585
nlmsg_abort(nw);
1586
return (ENOMEM);
1587
}
1588
1589
return (error);
1590
}
1591
1592
static int
1593
pf_handle_get_addr(struct nlmsghdr *hdr, struct nl_pstate *npt)
1594
{
1595
struct pf_nl_pooladdr attrs = { 0 };
1596
struct nl_writer *nw = npt->nw;
1597
struct genlmsghdr *ghdr_new;
1598
int error;
1599
1600
error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
1601
if (error != 0)
1602
return (error);
1603
1604
if (attrs.which == 0)
1605
attrs.which = PF_RDR;
1606
1607
error = pf_ioctl_get_addr(&attrs);
1608
if (error != 0)
1609
return (error);
1610
1611
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1612
return (ENOMEM);
1613
1614
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1615
ghdr_new->cmd = PFNL_CMD_GET_ADDR;
1616
ghdr_new->version = 0;
1617
ghdr_new->reserved = 0;
1618
1619
nlattr_add_u32(nw, PF_AA_ACTION, attrs.action);
1620
nlattr_add_u32(nw, PF_AA_TICKET, attrs.ticket);
1621
nlattr_add_u32(nw, PF_AA_NR, attrs.nr);
1622
nlattr_add_u32(nw, PF_AA_R_NUM, attrs.r_num);
1623
nlattr_add_u8(nw, PF_AA_R_ACTION, attrs.r_action);
1624
nlattr_add_u8(nw, PF_AA_R_LAST, attrs.r_last);
1625
nlattr_add_u8(nw, PF_AA_AF, attrs.af);
1626
nlattr_add_string(nw, PF_AA_ANCHOR, attrs.anchor);
1627
nlattr_add_pool_addr(nw, PF_AA_ADDR, &attrs.addr);
1628
1629
if (!nlmsg_end(nw)) {
1630
nlmsg_abort(nw);
1631
return (ENOMEM);
1632
}
1633
1634
return (0);
1635
}
1636
1637
#define _OUT(_field) offsetof(struct pfioc_ruleset, _field)
1638
static const struct nlattr_parser nla_p_ruleset[] = {
1639
{ .type = PF_RS_PATH, .off = _OUT(path), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
1640
{ .type = PF_RS_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
1641
};
1642
NL_DECLARE_PARSER(ruleset_parser, struct genlmsghdr, nlf_p_empty, nla_p_ruleset);
1643
#undef _OUT
1644
1645
static int
1646
pf_handle_get_rulesets(struct nlmsghdr *hdr, struct nl_pstate *npt)
1647
{
1648
struct pfioc_ruleset attrs = { 0 };
1649
struct nl_writer *nw = npt->nw;
1650
struct genlmsghdr *ghdr_new;
1651
int error;
1652
1653
error = nl_parse_nlmsg(hdr, &ruleset_parser, npt, &attrs);
1654
if (error != 0)
1655
return (error);
1656
1657
error = pf_ioctl_get_rulesets(&attrs);
1658
if (error != 0)
1659
return (error);
1660
1661
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1662
return (ENOMEM);
1663
1664
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1665
ghdr_new->cmd = PFNL_CMD_GET_RULESETS;
1666
ghdr_new->version = 0;
1667
ghdr_new->reserved = 0;
1668
1669
nlattr_add_u32(nw, PF_RS_NR, attrs.nr);
1670
1671
if (!nlmsg_end(nw)) {
1672
nlmsg_abort(nw);
1673
return (ENOMEM);
1674
}
1675
1676
return (0);
1677
}
1678
1679
static int
1680
pf_handle_get_ruleset(struct nlmsghdr *hdr, struct nl_pstate *npt)
1681
{
1682
struct pfioc_ruleset attrs = { 0 };
1683
struct nl_writer *nw = npt->nw;
1684
struct genlmsghdr *ghdr_new;
1685
int error;
1686
1687
error = nl_parse_nlmsg(hdr, &ruleset_parser, npt, &attrs);
1688
if (error)
1689
return (error);
1690
1691
error = pf_ioctl_get_ruleset(&attrs);
1692
if (error != 0)
1693
return (error);
1694
1695
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1696
return (ENOMEM);
1697
1698
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1699
ghdr_new->cmd = PFNL_CMD_GET_RULESET;
1700
ghdr_new->version = 0;
1701
ghdr_new->reserved = 0;
1702
1703
nlattr_add_string(nw, PF_RS_NAME, attrs.name);
1704
1705
if (!nlmsg_end(nw)) {
1706
nlmsg_abort(nw);
1707
return (ENOMEM);
1708
}
1709
1710
return (0);
1711
}
1712
1713
static bool
1714
nlattr_add_pf_threshold(struct nl_writer *nw, int attrtype,
1715
struct pf_kthreshold *t)
1716
{
1717
int off = nlattr_add_nested(nw, attrtype);
1718
int conn_rate_count = 0;
1719
1720
/* Adjust the connection rate estimate. */
1721
if (t->cr != NULL)
1722
conn_rate_count = counter_rate_get(t->cr);
1723
1724
nlattr_add_u32(nw, PF_TH_LIMIT, t->limit);
1725
nlattr_add_u32(nw, PF_TH_SECONDS, t->seconds);
1726
nlattr_add_u32(nw, PF_TH_COUNT, conn_rate_count);
1727
1728
nlattr_set_len(nw, off);
1729
1730
return (true);
1731
}
1732
1733
static int
1734
pf_handle_get_srcnodes(struct nlmsghdr *hdr, struct nl_pstate *npt)
1735
{
1736
struct nl_writer *nw = npt->nw;
1737
struct genlmsghdr *ghdr_new;
1738
struct pf_ksrc_node *n;
1739
struct pf_srchash *sh;
1740
int i;
1741
int secs;
1742
1743
hdr->nlmsg_flags |= NLM_F_MULTI;
1744
1745
for (i = 0, sh = V_pf_srchash; i <= V_pf_srchashmask;
1746
i++, sh++) {
1747
/* Avoid locking empty rows. */
1748
if (LIST_EMPTY(&sh->nodes))
1749
continue;
1750
1751
PF_HASHROW_LOCK(sh);
1752
secs = time_uptime;
1753
1754
LIST_FOREACH(n, &sh->nodes, entry) {
1755
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
1756
nlmsg_abort(nw);
1757
return (ENOMEM);
1758
}
1759
1760
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1761
ghdr_new->cmd = PFNL_CMD_GET_SRCNODES;
1762
ghdr_new->version = 0;
1763
ghdr_new->reserved = 0;
1764
1765
nlattr_add_in6_addr(nw, PF_SN_ADDR, &n->addr.v6);
1766
nlattr_add_in6_addr(nw, PF_SN_RADDR, &n->raddr.v6);
1767
nlattr_add_u32(nw, PF_SN_RULE_NR, n->rule->nr);
1768
nlattr_add_u64(nw, PF_SN_BYTES_IN, counter_u64_fetch(n->bytes[0]));
1769
nlattr_add_u64(nw, PF_SN_BYTES_OUT, counter_u64_fetch(n->bytes[1]));
1770
nlattr_add_u64(nw, PF_SN_PACKETS_IN, counter_u64_fetch(n->packets[0]));
1771
nlattr_add_u64(nw, PF_SN_PACKETS_OUT, counter_u64_fetch(n->packets[1]));
1772
nlattr_add_u32(nw, PF_SN_STATES, n->states);
1773
nlattr_add_u32(nw, PF_SN_CONNECTIONS, n->conn);
1774
nlattr_add_u8(nw, PF_SN_AF, n->af);
1775
nlattr_add_u8(nw, PF_SN_RAF, n->raf);
1776
nlattr_add_u8(nw, PF_SN_RULE_TYPE, n->ruletype);
1777
1778
nlattr_add_u64(nw, PF_SN_CREATION, secs - n->creation);
1779
if (n->expire > secs)
1780
nlattr_add_u64(nw, PF_SN_EXPIRE, n->expire - secs);
1781
else
1782
nlattr_add_u64(nw, PF_SN_EXPIRE, 0);
1783
1784
nlattr_add_pf_threshold(nw, PF_SN_CONNECTION_RATE,
1785
&n->conn_rate);
1786
1787
nlattr_add_u8(nw, PF_SN_NODE_TYPE, n->type);
1788
1789
if (!nlmsg_end(nw)) {
1790
PF_HASHROW_UNLOCK(sh);
1791
nlmsg_abort(nw);
1792
return (ENOMEM);
1793
}
1794
}
1795
PF_HASHROW_UNLOCK(sh);
1796
}
1797
1798
return (0);
1799
}
1800
1801
#define _OUT(_field) offsetof(struct pfioc_table, _field)
1802
static const struct nlattr_parser nla_p_table[] = {
1803
{ .type = PF_T_ANCHOR, .off = _OUT(pfrio_table.pfrt_anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
1804
{ .type = PF_T_NAME, .off = _OUT(pfrio_table.pfrt_name), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
1805
{ .type = PF_T_TABLE_FLAGS, .off = _OUT(pfrio_table.pfrt_flags), .cb = nlattr_get_uint32 },
1806
{ .type = PF_T_FLAGS, .off = _OUT(pfrio_flags), .cb = nlattr_get_uint32 },
1807
};
1808
static const struct nlfield_parser nlf_p_table[] = {};
1809
NL_DECLARE_PARSER(table_parser, struct genlmsghdr, nlf_p_table, nla_p_table);
1810
#undef _OUT
1811
static int
1812
pf_handle_clear_tables(struct nlmsghdr *hdr, struct nl_pstate *npt)
1813
{
1814
struct pfioc_table attrs = { 0 };
1815
struct nl_writer *nw = npt->nw;
1816
struct genlmsghdr *ghdr_new;
1817
int ndel = 0;
1818
int error;
1819
1820
error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
1821
if (error != 0)
1822
return (error);
1823
1824
PF_RULES_WLOCK();
1825
error = pfr_clr_tables(&attrs.pfrio_table, &ndel, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
1826
PF_RULES_WUNLOCK();
1827
if (error != 0)
1828
return (error);
1829
1830
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1831
return (ENOMEM);
1832
1833
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1834
ghdr_new->cmd = PFNL_CMD_CLEAR_TABLES;
1835
ghdr_new->version = 0;
1836
ghdr_new->reserved = 0;
1837
1838
nlattr_add_u32(nw, PF_T_NBR_DELETED, ndel);
1839
1840
if (!nlmsg_end(nw)) {
1841
nlmsg_abort(nw);
1842
return (ENOMEM);
1843
}
1844
1845
return (0);
1846
}
1847
1848
static int
1849
pf_handle_add_table(struct nlmsghdr *hdr, struct nl_pstate *npt)
1850
{
1851
struct pfioc_table attrs = { 0 };
1852
struct nl_writer *nw = npt->nw;
1853
struct genlmsghdr *ghdr_new;
1854
int error;
1855
1856
error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
1857
if (error != 0)
1858
return (error);
1859
1860
PF_RULES_WLOCK();
1861
error = pfr_add_tables(&attrs.pfrio_table, 1, &attrs.pfrio_nadd,
1862
attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
1863
PF_RULES_WUNLOCK();
1864
if (error != 0)
1865
return (error);
1866
1867
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1868
return (ENOMEM);
1869
1870
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1871
ghdr_new->cmd = PFNL_CMD_ADD_TABLE;
1872
ghdr_new->version = 0;
1873
ghdr_new->reserved = 0;
1874
1875
nlattr_add_u32(nw, PF_T_NBR_ADDED, attrs.pfrio_nadd);
1876
1877
if (!nlmsg_end(nw)) {
1878
nlmsg_abort(nw);
1879
return (ENOMEM);
1880
}
1881
1882
return (0);
1883
}
1884
1885
static int
1886
pf_handle_del_table(struct nlmsghdr *hdr, struct nl_pstate *npt)
1887
{
1888
struct pfioc_table attrs = { 0 };
1889
struct nl_writer *nw = npt->nw;
1890
struct genlmsghdr *ghdr_new;
1891
int error;
1892
1893
error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
1894
if (error != 0)
1895
return (error);
1896
1897
PF_RULES_WLOCK();
1898
error = pfr_del_tables(&attrs.pfrio_table, 1, &attrs.pfrio_ndel,
1899
attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
1900
PF_RULES_WUNLOCK();
1901
if (error != 0)
1902
return (error);
1903
1904
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1905
return (ENOMEM);
1906
1907
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1908
ghdr_new->cmd = PFNL_CMD_ADD_TABLE;
1909
ghdr_new->version = 0;
1910
ghdr_new->reserved = 0;
1911
1912
nlattr_add_u32(nw, PF_T_NBR_DELETED, attrs.pfrio_ndel);
1913
1914
if (!nlmsg_end(nw)) {
1915
nlmsg_abort(nw);
1916
return (ENOMEM);
1917
}
1918
1919
return (0);
1920
}
1921
1922
static bool
1923
nlattr_add_pfr_table(struct nl_writer *nw, int attrtype,
1924
struct pfr_table *t)
1925
{
1926
int off = nlattr_add_nested(nw, attrtype);
1927
1928
nlattr_add_string(nw, PF_T_ANCHOR, t->pfrt_anchor);
1929
nlattr_add_string(nw, PF_T_NAME, t->pfrt_name);
1930
nlattr_add_u32(nw, PF_T_TABLE_FLAGS, t->pfrt_flags);
1931
1932
nlattr_set_len(nw, off);
1933
1934
return (true);
1935
}
1936
1937
static int
1938
pf_handle_get_tstats(struct nlmsghdr *hdr, struct nl_pstate *npt)
1939
{
1940
struct pfioc_table attrs = { 0 };
1941
struct nl_writer *nw = npt->nw;
1942
struct genlmsghdr *ghdr_new;
1943
struct pfr_tstats *pfrtstats;
1944
int error;
1945
int n;
1946
1947
PF_RULES_RLOCK_TRACKER;
1948
1949
error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
1950
if (error != 0)
1951
return (error);
1952
1953
PF_TABLE_STATS_LOCK();
1954
PF_RULES_RLOCK();
1955
1956
n = pfr_table_count(&attrs.pfrio_table, attrs.pfrio_flags);
1957
pfrtstats = mallocarray(n,
1958
sizeof(struct pfr_tstats), M_PF, M_NOWAIT | M_ZERO);
1959
1960
error = pfr_get_tstats(&attrs.pfrio_table, pfrtstats,
1961
&n, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
1962
1963
PF_RULES_RUNLOCK();
1964
PF_TABLE_STATS_UNLOCK();
1965
1966
if (error == 0) {
1967
hdr->nlmsg_flags |= NLM_F_MULTI;
1968
1969
for (int i = 0; i < n; i++) {
1970
uint64_t refcnt[PFR_REFCNT_MAX];
1971
1972
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
1973
error = ENOMEM;
1974
break;
1975
}
1976
1977
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1978
ghdr_new->cmd = PFNL_CMD_GET_TSTATS;
1979
ghdr_new->version = 0;
1980
ghdr_new->reserved = 0;
1981
1982
nlattr_add_pfr_table(nw, PF_TS_TABLE,
1983
&pfrtstats[i].pfrts_t);
1984
nlattr_add_u64_array(nw, PF_TS_PACKETS,
1985
PFR_DIR_MAX * PFR_OP_TABLE_MAX,
1986
(uint64_t *)pfrtstats[i].pfrts_packets);
1987
nlattr_add_u64_array(nw, PF_TS_BYTES,
1988
PFR_DIR_MAX * PFR_OP_TABLE_MAX,
1989
(uint64_t *)pfrtstats[i].pfrts_bytes);
1990
nlattr_add_u64(nw, PF_TS_MATCH,
1991
pfrtstats[i].pfrts_match);
1992
nlattr_add_u64(nw, PF_TS_NOMATCH,
1993
pfrtstats[i].pfrts_nomatch);
1994
nlattr_add_u64(nw, PF_TS_TZERO,
1995
pfrtstats[i].pfrts_tzero);
1996
nlattr_add_u64(nw, PF_TS_CNT, pfrtstats[i].pfrts_cnt);
1997
1998
for (int j = 0; j < PFR_REFCNT_MAX; j++)
1999
refcnt[j] = pfrtstats[i].pfrts_refcnt[j];
2000
2001
nlattr_add_u64_array(nw, PF_TS_REFCNT, PFR_REFCNT_MAX,
2002
refcnt);
2003
2004
if (! nlmsg_end(nw)) {
2005
error = ENOMEM;
2006
break;
2007
}
2008
}
2009
}
2010
free(pfrtstats, M_PF);
2011
2012
if (!nlmsg_end_dump(npt->nw, error, hdr)) {
2013
NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
2014
return (ENOMEM);
2015
}
2016
2017
return (error);
2018
}
2019
2020
static int
2021
pf_handle_clear_tstats(struct nlmsghdr *hdr, struct nl_pstate *npt)
2022
{
2023
struct pfioc_table attrs = { 0 };
2024
struct nl_writer *nw = npt->nw;
2025
struct genlmsghdr *ghdr_new;
2026
int error;
2027
int nzero;
2028
2029
PF_RULES_RLOCK_TRACKER;
2030
2031
error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
2032
if (error != 0)
2033
return (error);
2034
2035
PF_TABLE_STATS_LOCK();
2036
PF_RULES_RLOCK();
2037
error = pfr_clr_tstats(&attrs.pfrio_table, 1,
2038
&nzero, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
2039
PF_RULES_RUNLOCK();
2040
PF_TABLE_STATS_UNLOCK();
2041
2042
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2043
return (ENOMEM);
2044
2045
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2046
ghdr_new->cmd = PFNL_CMD_CLR_TSTATS;
2047
ghdr_new->version = 0;
2048
ghdr_new->reserved = 0;
2049
2050
nlattr_add_u64(nw, PF_TS_NZERO, nzero);
2051
2052
if (! nlmsg_end(nw))
2053
error = ENOMEM;
2054
2055
return (error);
2056
}
2057
2058
static int
2059
pf_handle_clear_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
2060
{
2061
struct pfioc_table attrs = { 0 };
2062
struct nl_writer *nw = npt->nw;
2063
struct genlmsghdr *ghdr_new;
2064
int error;
2065
int ndel;
2066
2067
error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
2068
if (error != 0)
2069
return (error);
2070
2071
PF_RULES_WLOCK();
2072
error = pfr_clr_addrs(&attrs.pfrio_table, &ndel,
2073
attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
2074
PF_RULES_WUNLOCK();
2075
2076
if (error)
2077
return (error);
2078
2079
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2080
return (ENOMEM);
2081
2082
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2083
ghdr_new->cmd = PFNL_CMD_CLR_ADDRS;
2084
ghdr_new->version = 0;
2085
ghdr_new->reserved = 0;
2086
2087
nlattr_add_u64(nw, PF_T_NBR_DELETED, ndel);
2088
2089
if (!nlmsg_end(nw))
2090
return (ENOMEM);
2091
2092
return (error);
2093
}
2094
2095
TAILQ_HEAD(pfr_addrq, pfr_addr_item);
2096
struct nl_parsed_table_addrs {
2097
struct pfr_table table;
2098
uint32_t flags;
2099
struct pfr_addr addrs[256];
2100
size_t addr_count;
2101
int nadd;
2102
int ndel;
2103
};
2104
#define _OUT(_field) offsetof(struct pfr_addr, _field)
2105
static const struct nlattr_parser nla_p_pfr_addr[] = {
2106
{ .type = PFR_A_AF, .off = _OUT(pfra_af), .cb = nlattr_get_uint8 },
2107
{ .type = PFR_A_NET, .off = _OUT(pfra_net), .cb = nlattr_get_uint8 },
2108
{ .type = PFR_A_NOT, .off = _OUT(pfra_not), .cb = nlattr_get_bool },
2109
{ .type = PFR_A_ADDR, .off = _OUT(pfra_u), .cb = nlattr_get_in6_addr },
2110
};
2111
#undef _OUT
2112
NL_DECLARE_ATTR_PARSER(pfra_addr_parser, nla_p_pfr_addr);
2113
2114
static int
2115
nlattr_get_pfr_addr(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
2116
void *target)
2117
{
2118
struct nl_parsed_table_addrs *attrs = target;
2119
struct pfr_addr addr = { 0 };
2120
int error;
2121
2122
if (attrs->addr_count >= nitems(attrs->addrs))
2123
return (E2BIG);
2124
2125
error = nlattr_get_nested(nla, npt, &pfra_addr_parser, &addr);
2126
if (error != 0)
2127
return (error);
2128
2129
memcpy(&attrs->addrs[attrs->addr_count], &addr, sizeof(addr));
2130
attrs->addr_count++;
2131
2132
return (0);
2133
}
2134
2135
NL_DECLARE_ATTR_PARSER(nested_table_parser, nla_p_table);
2136
2137
#define _OUT(_field) offsetof(struct nl_parsed_table_addrs, _field)
2138
static const struct nlattr_parser nla_p_table_addr[] = {
2139
{ .type = PF_TA_TABLE, .off = _OUT(table), .arg = &nested_table_parser, .cb = nlattr_get_nested },
2140
{ .type = PF_TA_ADDR, .cb = nlattr_get_pfr_addr },
2141
{ .type = PF_TA_FLAGS, .off = _OUT(flags), .cb = nlattr_get_uint32 },
2142
};
2143
NL_DECLARE_PARSER(table_addr_parser, struct genlmsghdr, nlf_p_empty, nla_p_table_addr);
2144
#undef _OUT
2145
2146
static int
2147
pf_handle_table_add_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
2148
{
2149
struct nl_parsed_table_addrs attrs = { 0 };
2150
struct nl_writer *nw = npt->nw;
2151
struct genlmsghdr *ghdr_new;
2152
int error;
2153
2154
error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs);
2155
if (error != 0)
2156
return (error);
2157
2158
PF_RULES_WLOCK();
2159
error = pfr_add_addrs(&attrs.table, &attrs.addrs[0],
2160
attrs.addr_count, &attrs.nadd, attrs.flags | PFR_FLAG_USERIOCTL);
2161
PF_RULES_WUNLOCK();
2162
2163
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2164
return (ENOMEM);
2165
2166
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2167
ghdr_new->cmd = PFNL_CMD_TABLE_ADD_ADDR;
2168
ghdr_new->version = 0;
2169
ghdr_new->reserved = 0;
2170
2171
nlattr_add_u32(nw, PF_TA_NBR_ADDED, attrs.nadd);
2172
2173
if (!nlmsg_end(nw))
2174
return (ENOMEM);
2175
2176
return (error);
2177
}
2178
2179
static int
2180
pf_handle_table_del_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
2181
{
2182
struct nl_parsed_table_addrs attrs = { 0 };
2183
struct nl_writer *nw = npt->nw;
2184
struct genlmsghdr *ghdr_new;
2185
int error;
2186
2187
error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs);
2188
if (error != 0)
2189
return (error);
2190
2191
PF_RULES_WLOCK();
2192
error = pfr_del_addrs(&attrs.table, &attrs.addrs[0],
2193
attrs.addr_count, &attrs.ndel, attrs.flags | PFR_FLAG_USERIOCTL);
2194
PF_RULES_WUNLOCK();
2195
2196
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2197
return (ENOMEM);
2198
2199
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2200
ghdr_new->cmd = PFNL_CMD_TABLE_DEL_ADDR;
2201
ghdr_new->version = 0;
2202
ghdr_new->reserved = 0;
2203
2204
nlattr_add_u32(nw, PF_TA_NBR_DELETED, attrs.ndel);
2205
2206
if (!nlmsg_end(nw))
2207
return (ENOMEM);
2208
2209
return (error);
2210
}
2211
2212
static const struct nlhdr_parser *all_parsers[] = {
2213
&state_parser,
2214
&addrule_parser,
2215
&getrules_parser,
2216
&clear_states_parser,
2217
&set_statusif_parser,
2218
&natlook_parser,
2219
&set_debug_parser,
2220
&set_timeout_parser,
2221
&set_limit_parser,
2222
&pool_addr_parser,
2223
&add_addr_parser,
2224
&ruleset_parser,
2225
&table_parser,
2226
&table_addr_parser,
2227
};
2228
2229
static uint16_t family_id;
2230
2231
static const struct genl_cmd pf_cmds[] = {
2232
{
2233
.cmd_num = PFNL_CMD_GETSTATES,
2234
.cmd_name = "GETSTATES",
2235
.cmd_cb = pf_handle_getstates,
2236
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2237
.cmd_priv = PRIV_NETINET_PF,
2238
},
2239
{
2240
.cmd_num = PFNL_CMD_GETCREATORS,
2241
.cmd_name = "GETCREATORS",
2242
.cmd_cb = pf_handle_getcreators,
2243
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2244
.cmd_priv = PRIV_NETINET_PF,
2245
},
2246
{
2247
.cmd_num = PFNL_CMD_START,
2248
.cmd_name = "START",
2249
.cmd_cb = pf_handle_start,
2250
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2251
.cmd_priv = PRIV_NETINET_PF,
2252
},
2253
{
2254
.cmd_num = PFNL_CMD_STOP,
2255
.cmd_name = "STOP",
2256
.cmd_cb = pf_handle_stop,
2257
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2258
.cmd_priv = PRIV_NETINET_PF,
2259
},
2260
{
2261
.cmd_num = PFNL_CMD_ADDRULE,
2262
.cmd_name = "ADDRULE",
2263
.cmd_cb = pf_handle_addrule,
2264
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2265
.cmd_priv = PRIV_NETINET_PF,
2266
},
2267
{
2268
.cmd_num = PFNL_CMD_GETRULES,
2269
.cmd_name = "GETRULES",
2270
.cmd_cb = pf_handle_getrules,
2271
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2272
.cmd_priv = PRIV_NETINET_PF,
2273
},
2274
{
2275
.cmd_num = PFNL_CMD_GETRULE,
2276
.cmd_name = "GETRULE",
2277
.cmd_cb = pf_handle_getrule,
2278
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2279
.cmd_priv = PRIV_NETINET_PF,
2280
},
2281
{
2282
.cmd_num = PFNL_CMD_CLRSTATES,
2283
.cmd_name = "CLRSTATES",
2284
.cmd_cb = pf_handle_clear_states,
2285
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2286
.cmd_priv = PRIV_NETINET_PF,
2287
},
2288
{
2289
.cmd_num = PFNL_CMD_KILLSTATES,
2290
.cmd_name = "KILLSTATES",
2291
.cmd_cb = pf_handle_kill_states,
2292
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2293
.cmd_priv = PRIV_NETINET_PF,
2294
},
2295
{
2296
.cmd_num = PFNL_CMD_SET_STATUSIF,
2297
.cmd_name = "SETSTATUSIF",
2298
.cmd_cb = pf_handle_set_statusif,
2299
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2300
.cmd_priv = PRIV_NETINET_PF,
2301
},
2302
{
2303
.cmd_num = PFNL_CMD_GET_STATUS,
2304
.cmd_name = "GETSTATUS",
2305
.cmd_cb = pf_handle_get_status,
2306
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2307
.cmd_priv = PRIV_NETINET_PF,
2308
},
2309
{
2310
.cmd_num = PFNL_CMD_CLEAR_STATUS,
2311
.cmd_name = "CLEARSTATUS",
2312
.cmd_cb = pf_handle_clear_status,
2313
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2314
.cmd_priv = PRIV_NETINET_PF,
2315
},
2316
{
2317
.cmd_num = PFNL_CMD_NATLOOK,
2318
.cmd_name = "NATLOOK",
2319
.cmd_cb = pf_handle_natlook,
2320
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2321
.cmd_priv = PRIV_NETINET_PF,
2322
},
2323
{
2324
.cmd_num = PFNL_CMD_SET_DEBUG,
2325
.cmd_name = "SET_DEBUG",
2326
.cmd_cb = pf_handle_set_debug,
2327
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2328
.cmd_priv = PRIV_NETINET_PF,
2329
},
2330
{
2331
.cmd_num = PFNL_CMD_SET_TIMEOUT,
2332
.cmd_name = "SET_TIMEOUT",
2333
.cmd_cb = pf_handle_set_timeout,
2334
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2335
.cmd_priv = PRIV_NETINET_PF,
2336
},
2337
{
2338
.cmd_num = PFNL_CMD_GET_TIMEOUT,
2339
.cmd_name = "GET_TIMEOUT",
2340
.cmd_cb = pf_handle_get_timeout,
2341
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2342
.cmd_priv = PRIV_NETINET_PF,
2343
},
2344
{
2345
.cmd_num = PFNL_CMD_SET_LIMIT,
2346
.cmd_name = "SET_LIMIT",
2347
.cmd_cb = pf_handle_set_limit,
2348
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2349
.cmd_priv = PRIV_NETINET_PF,
2350
},
2351
{
2352
.cmd_num = PFNL_CMD_GET_LIMIT,
2353
.cmd_name = "GET_LIMIT",
2354
.cmd_cb = pf_handle_get_limit,
2355
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2356
.cmd_priv = PRIV_NETINET_PF,
2357
},
2358
{
2359
.cmd_num = PFNL_CMD_BEGIN_ADDRS,
2360
.cmd_name = "BEGIN_ADDRS",
2361
.cmd_cb = pf_handle_begin_addrs,
2362
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2363
.cmd_priv = PRIV_NETINET_PF,
2364
},
2365
{
2366
.cmd_num = PFNL_CMD_ADD_ADDR,
2367
.cmd_name = "ADD_ADDR",
2368
.cmd_cb = pf_handle_add_addr,
2369
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2370
.cmd_priv = PRIV_NETINET_PF,
2371
},
2372
{
2373
.cmd_num = PFNL_CMD_GET_ADDRS,
2374
.cmd_name = "GET_ADDRS",
2375
.cmd_cb = pf_handle_get_addrs,
2376
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2377
.cmd_priv = PRIV_NETINET_PF,
2378
},
2379
{
2380
.cmd_num = PFNL_CMD_GET_ADDR,
2381
.cmd_name = "GET_ADDRS",
2382
.cmd_cb = pf_handle_get_addr,
2383
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2384
.cmd_priv = PRIV_NETINET_PF,
2385
},
2386
{
2387
.cmd_num = PFNL_CMD_GET_RULESETS,
2388
.cmd_name = "GET_RULESETS",
2389
.cmd_cb = pf_handle_get_rulesets,
2390
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2391
.cmd_priv = PRIV_NETINET_PF,
2392
},
2393
{
2394
.cmd_num = PFNL_CMD_GET_RULESET,
2395
.cmd_name = "GET_RULESET",
2396
.cmd_cb = pf_handle_get_ruleset,
2397
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2398
.cmd_priv = PRIV_NETINET_PF,
2399
},
2400
{
2401
.cmd_num = PFNL_CMD_GET_SRCNODES,
2402
.cmd_name = "GET_SRCNODES",
2403
.cmd_cb = pf_handle_get_srcnodes,
2404
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2405
.cmd_priv = PRIV_NETINET_PF,
2406
},
2407
{
2408
.cmd_num = PFNL_CMD_CLEAR_TABLES,
2409
.cmd_name = "CLEAR_TABLES",
2410
.cmd_cb = pf_handle_clear_tables,
2411
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2412
.cmd_priv = PRIV_NETINET_PF,
2413
},
2414
{
2415
.cmd_num = PFNL_CMD_ADD_TABLE,
2416
.cmd_name = "ADD_TABLE",
2417
.cmd_cb = pf_handle_add_table,
2418
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2419
.cmd_priv = PRIV_NETINET_PF,
2420
},
2421
{
2422
.cmd_num = PFNL_CMD_DEL_TABLE,
2423
.cmd_name = "DEL_TABLE",
2424
.cmd_cb = pf_handle_del_table,
2425
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2426
.cmd_priv = PRIV_NETINET_PF,
2427
},
2428
{
2429
.cmd_num = PFNL_CMD_GET_TSTATS,
2430
.cmd_name = "GET_TSTATS",
2431
.cmd_cb = pf_handle_get_tstats,
2432
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2433
.cmd_priv = PRIV_NETINET_PF,
2434
},
2435
{
2436
.cmd_num = PFNL_CMD_CLR_TSTATS,
2437
.cmd_name = "CLR_TSTATS",
2438
.cmd_cb = pf_handle_clear_tstats,
2439
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2440
.cmd_priv = PRIV_NETINET_PF,
2441
},
2442
{
2443
.cmd_num = PFNL_CMD_CLR_ADDRS,
2444
.cmd_name = "CRL_ADDRS",
2445
.cmd_cb = pf_handle_clear_addrs,
2446
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2447
.cmd_priv = PRIV_NETINET_PF,
2448
},
2449
{
2450
.cmd_num = PFNL_CMD_TABLE_ADD_ADDR,
2451
.cmd_name = "TABLE_ADD_ADDRS",
2452
.cmd_cb = pf_handle_table_add_addrs,
2453
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2454
.cmd_priv = PRIV_NETINET_PF,
2455
},
2456
{
2457
.cmd_num = PFNL_CMD_TABLE_DEL_ADDR,
2458
.cmd_name = "TABLE_DEL_ADDRS",
2459
.cmd_cb = pf_handle_table_del_addrs,
2460
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2461
.cmd_priv = PRIV_NETINET_PF,
2462
},
2463
};
2464
2465
void
2466
pf_nl_register(void)
2467
{
2468
NL_VERIFY_PARSERS(all_parsers);
2469
2470
family_id = genl_register_family(PFNL_FAMILY_NAME, 0, 2, PFNL_CMD_MAX);
2471
genl_register_cmds(family_id, pf_cmds, nitems(pf_cmds));
2472
}
2473
2474
void
2475
pf_nl_unregister(void)
2476
{
2477
genl_unregister_family(family_id);
2478
}
2479
2480