1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2023 Alexander V. Chernikov <melifaro@FreeBSD.org>
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
dump_addr(struct nl_writer * nw,int attr,const struct pf_addr * addr,int af)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
dump_state_peer(struct nl_writer * nw,int attr,const struct pf_state_peer * peer)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
dump_state_key(struct nl_writer * nw,int attr,const struct pf_state_key * key)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
dump_state(struct nlpcb * nlp,const struct nlmsghdr * hdr,struct pf_kstate * s,struct nl_pstate * npt)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
handle_dumpstates(struct nlpcb * nlp,struct nl_parsed_state * attrs,struct nlmsghdr * hdr,struct nl_pstate * npt)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
handle_getstate(struct nlpcb * nlp,struct nl_parsed_state * attrs,struct nlmsghdr * hdr,struct nl_pstate * npt)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
dump_creatorid(struct nlpcb * nlp,const struct nlmsghdr * hdr,uint32_t creator,struct nl_pstate * npt)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
pf_handle_getstates(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_getcreators(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_start(struct nlmsghdr * hdr __unused,struct nl_pstate * npt __unused)409 pf_handle_start(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
410 {
411 return (pf_start());
412 }
413
414 static int
pf_handle_stop(struct nlmsghdr * hdr __unused,struct nl_pstate * npt __unused)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
nlattr_add_addr_wrap(struct nl_writer * nw,int attrtype,struct pf_addr_wrap * a)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
nlattr_add_rule_addr(struct nl_writer * nw,int attrtype,struct pf_rule_addr * r)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
nlattr_add_mape_portset(struct nl_writer * nw,int attrtype,const struct pf_mape_portset * m)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
nlattr_get_pf_rule_labels(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)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
nlattr_get_nested_pf_rule_labels(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)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
nlattr_add_labels(struct nl_writer * nw,int attrtype,const struct pf_krule * r)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
nlattr_add_pool(struct nl_writer * nw,int attrtype,const struct pf_kpool * pool)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
nlattr_add_rule_uid(struct nl_writer * nw,int attrtype,const struct pf_rule_uid * u)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
nlattr_get_pf_timeout(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)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
nlattr_get_nested_timeouts(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)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
nlattr_add_timeout(struct nl_writer * nw,int attrtype,uint32_t * timeout)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
pf_handle_addrule(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_getrules(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_getrule(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_killclear_states(struct nlmsghdr * hdr,struct nl_pstate * npt,int cmd)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
pf_handle_clear_states(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_kill_states(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_set_statusif(struct nlmsghdr * hdr,struct nl_pstate * npt)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
nlattr_add_counters(struct nl_writer * nw,int attr,size_t number,char ** names,counter_u64_t * counters)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
nlattr_add_fcounters(struct nl_writer * nw,int attr,size_t number,char ** names,struct pf_counter_u64 * counters)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
nlattr_add_u64_array(struct nl_writer * nw,int attr,size_t number,uint64_t * array)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
pf_handle_get_status(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_clear_status(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_natlook(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_set_debug(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_set_timeout(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_get_timeout(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_set_limit(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_get_limit(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_begin_addrs(struct nlmsghdr * hdr,struct nl_pstate * npt)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
nlattr_add_pool_addr(struct nl_writer * nw,int attrtype,struct pf_pooladdr * a)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
pf_handle_add_addr(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_get_addrs(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_get_addr(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_get_rulesets(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_get_ruleset(struct nlmsghdr * hdr,struct nl_pstate * npt)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
nlattr_add_pf_threshold(struct nl_writer * nw,int attrtype,struct pf_kthreshold * t)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
pf_handle_get_srcnodes(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_clear_tables(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_add_table(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_del_table(struct nlmsghdr * hdr,struct nl_pstate * npt)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
nlattr_add_pfr_table(struct nl_writer * nw,int attrtype,struct pfr_table * t)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
pf_handle_get_tstats(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_clear_tstats(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_clear_addrs(struct nlmsghdr * hdr,struct nl_pstate * npt)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
nlattr_get_pfr_addr(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)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
pf_handle_table_add_addrs(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_handle_table_del_addrs(struct nlmsghdr * hdr,struct nl_pstate * npt)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
pf_nl_register(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
pf_nl_unregister(void)2475 pf_nl_unregister(void)
2476 {
2477 genl_unregister_family(family_id);
2478 }
2479