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