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