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(proto), .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
137 nlattr_set_len(nw, off);
138
139 return (true);
140 }
141
142 static int
dump_state(struct nlpcb * nlp,const struct nlmsghdr * hdr,struct pf_kstate * s,struct nl_pstate * npt)143 dump_state(struct nlpcb *nlp, const struct nlmsghdr *hdr, struct pf_kstate *s,
144 struct nl_pstate *npt)
145 {
146 struct nl_writer *nw = npt->nw;
147 int error = 0;
148 int af;
149 struct pf_state_key *key;
150
151 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
152 goto enomem;
153
154 struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
155 ghdr_new->cmd = PFNL_CMD_GETSTATES;
156 ghdr_new->version = 0;
157 ghdr_new->reserved = 0;
158
159 nlattr_add_u64(nw, PF_ST_VERSION, PF_STATE_VERSION);
160
161 key = s->key[PF_SK_WIRE];
162 if (!dump_state_key(nw, PF_ST_KEY_WIRE, key))
163 goto enomem;
164 key = s->key[PF_SK_STACK];
165 if (!dump_state_key(nw, PF_ST_KEY_STACK, key))
166 goto enomem;
167
168 af = s->key[PF_SK_WIRE]->af;
169 nlattr_add_u8(nw, PF_ST_PROTO, s->key[PF_SK_WIRE]->proto);
170 nlattr_add_u8(nw, PF_ST_AF, af);
171
172 nlattr_add_string(nw, PF_ST_IFNAME, s->kif->pfik_name);
173 nlattr_add_string(nw, PF_ST_ORIG_IFNAME, s->orig_kif->pfik_name);
174 dump_addr(nw, PF_ST_RT_ADDR, &s->rt_addr, af);
175 nlattr_add_u32(nw, PF_ST_CREATION, time_uptime - (s->creation / 1000));
176 uint32_t expire = pf_state_expires(s);
177 if (expire > time_uptime)
178 expire = expire - time_uptime;
179 nlattr_add_u32(nw, PF_ST_EXPIRE, expire);
180 nlattr_add_u8(nw, PF_ST_DIRECTION, s->direction);
181 nlattr_add_u8(nw, PF_ST_LOG, s->act.log);
182 nlattr_add_u8(nw, PF_ST_TIMEOUT, s->timeout);
183 nlattr_add_u16(nw, PF_ST_STATE_FLAGS, s->state_flags);
184 uint8_t sync_flags = 0;
185 if (s->src_node)
186 sync_flags |= PFSYNC_FLAG_SRCNODE;
187 if (s->nat_src_node)
188 sync_flags |= PFSYNC_FLAG_NATSRCNODE;
189 nlattr_add_u8(nw, PF_ST_SYNC_FLAGS, sync_flags);
190 nlattr_add_u64(nw, PF_ST_ID, s->id);
191 nlattr_add_u32(nw, PF_ST_CREATORID, htonl(s->creatorid));
192
193 nlattr_add_u32(nw, PF_ST_RULE, s->rule.ptr ? s->rule.ptr->nr : -1);
194 nlattr_add_u32(nw, PF_ST_ANCHOR, s->anchor.ptr ? s->anchor.ptr->nr : -1);
195 nlattr_add_u32(nw, PF_ST_NAT_RULE, s->nat_rule.ptr ? s->nat_rule.ptr->nr : -1);
196
197 nlattr_add_u64(nw, PF_ST_PACKETS0, s->packets[0]);
198 nlattr_add_u64(nw, PF_ST_PACKETS1, s->packets[1]);
199 nlattr_add_u64(nw, PF_ST_BYTES0, s->bytes[0]);
200 nlattr_add_u64(nw, PF_ST_BYTES1, s->bytes[1]);
201 nlattr_add_u32(nw, PF_ST_RTABLEID, s->act.rtableid);
202 nlattr_add_u8(nw, PF_ST_MIN_TTL, s->act.min_ttl);
203 nlattr_add_u16(nw, PF_ST_MAX_MSS, s->act.max_mss);
204 nlattr_add_u16(nw, PF_ST_DNPIPE, s->act.dnpipe);
205 nlattr_add_u16(nw, PF_ST_DNRPIPE, s->act.dnrpipe);
206 nlattr_add_u8(nw, PF_ST_RT, s->rt);
207 if (s->rt_kif != NULL)
208 nlattr_add_string(nw, PF_ST_RT_IFNAME, s->rt_kif->pfik_name);
209
210 if (!dump_state_peer(nw, PF_ST_PEER_SRC, &s->src))
211 goto enomem;
212 if (!dump_state_peer(nw, PF_ST_PEER_DST, &s->dst))
213 goto enomem;
214
215 if (nlmsg_end(nw))
216 return (0);
217
218 enomem:
219 error = ENOMEM;
220 nlmsg_abort(nw);
221 return (error);
222 }
223
224 static int
handle_dumpstates(struct nlpcb * nlp,struct nl_parsed_state * attrs,struct nlmsghdr * hdr,struct nl_pstate * npt)225 handle_dumpstates(struct nlpcb *nlp, struct nl_parsed_state *attrs,
226 struct nlmsghdr *hdr, struct nl_pstate *npt)
227 {
228 int error = 0;
229
230 hdr->nlmsg_flags |= NLM_F_MULTI;
231
232 for (int i = 0; i <= pf_hashmask; i++) {
233 struct pf_idhash *ih = &V_pf_idhash[i];
234 struct pf_kstate *s;
235
236 if (LIST_EMPTY(&ih->states))
237 continue;
238
239 PF_HASHROW_LOCK(ih);
240 LIST_FOREACH(s, &ih->states, entry) {
241 sa_family_t af = s->key[PF_SK_WIRE]->af;
242
243 if (s->timeout == PFTM_UNLINKED)
244 continue;
245
246 /* Filter */
247 if (attrs->creatorid != 0 && s->creatorid != attrs->creatorid)
248 continue;
249 if (attrs->ifname[0] != 0 &&
250 strncmp(attrs->ifname, s->kif->pfik_name, IFNAMSIZ) != 0)
251 continue;
252 if (attrs->proto != 0 && s->key[PF_SK_WIRE]->proto != attrs->proto)
253 continue;
254 if (attrs->af != 0 && af != attrs->af)
255 continue;
256 if (pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[0],
257 &attrs->mask, &attrs->addr, af) &&
258 pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[1],
259 &attrs->mask, &attrs->addr, af) &&
260 pf_match_addr(1, &s->key[PF_SK_STACK]->addr[0],
261 &attrs->mask, &attrs->addr, af) &&
262 pf_match_addr(1, &s->key[PF_SK_STACK]->addr[1],
263 &attrs->mask, &attrs->addr, af))
264 continue;
265
266 error = dump_state(nlp, hdr, s, npt);
267 if (error != 0)
268 break;
269 }
270 PF_HASHROW_UNLOCK(ih);
271 }
272
273 if (!nlmsg_end_dump(npt->nw, error, hdr)) {
274 NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
275 return (ENOMEM);
276 }
277
278 return (error);
279 }
280
281 static int
handle_getstate(struct nlpcb * nlp,struct nl_parsed_state * attrs,struct nlmsghdr * hdr,struct nl_pstate * npt)282 handle_getstate(struct nlpcb *nlp, struct nl_parsed_state *attrs,
283 struct nlmsghdr *hdr, struct nl_pstate *npt)
284 {
285 struct pf_kstate *s = pf_find_state_byid(attrs->id, attrs->creatorid);
286 if (s == NULL)
287 return (ENOENT);
288 return (dump_state(nlp, hdr, s, npt));
289 }
290
291 static int
dump_creatorid(struct nlpcb * nlp,const struct nlmsghdr * hdr,uint32_t creator,struct nl_pstate * npt)292 dump_creatorid(struct nlpcb *nlp, const struct nlmsghdr *hdr, uint32_t creator,
293 struct nl_pstate *npt)
294 {
295 struct nl_writer *nw = npt->nw;
296
297 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
298 goto enomem;
299
300 struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
301 ghdr_new->cmd = PFNL_CMD_GETCREATORS;
302 ghdr_new->version = 0;
303 ghdr_new->reserved = 0;
304
305 nlattr_add_u32(nw, PF_ST_CREATORID, htonl(creator));
306
307 if (nlmsg_end(nw))
308 return (0);
309
310 enomem:
311 nlmsg_abort(nw);
312 return (ENOMEM);
313 }
314
315 static int
pf_handle_getstates(struct nlmsghdr * hdr,struct nl_pstate * npt)316 pf_handle_getstates(struct nlmsghdr *hdr, struct nl_pstate *npt)
317 {
318 int error;
319
320 struct nl_parsed_state attrs = {};
321 error = nl_parse_nlmsg(hdr, &state_parser, npt, &attrs);
322 if (error != 0)
323 return (error);
324
325 if (attrs.id != 0)
326 error = handle_getstate(npt->nlp, &attrs, hdr, npt);
327 else
328 error = handle_dumpstates(npt->nlp, &attrs, hdr, npt);
329
330 return (error);
331 }
332
333 static int
pf_handle_getcreators(struct nlmsghdr * hdr,struct nl_pstate * npt)334 pf_handle_getcreators(struct nlmsghdr *hdr, struct nl_pstate *npt)
335 {
336 uint32_t creators[16];
337 int error = 0;
338
339 bzero(creators, sizeof(creators));
340
341 for (int i = 0; i < pf_hashmask; i++) {
342 struct pf_idhash *ih = &V_pf_idhash[i];
343 struct pf_kstate *s;
344
345 if (LIST_EMPTY(&ih->states))
346 continue;
347
348 PF_HASHROW_LOCK(ih);
349 LIST_FOREACH(s, &ih->states, entry) {
350 int j;
351 if (s->timeout == PFTM_UNLINKED)
352 continue;
353
354 for (j = 0; j < nitems(creators); j++) {
355 if (creators[j] == s->creatorid)
356 break;
357 if (creators[j] == 0) {
358 creators[j] = s->creatorid;
359 break;
360 }
361 }
362 if (j == nitems(creators))
363 printf("Warning: too many creators!\n");
364 }
365 PF_HASHROW_UNLOCK(ih);
366 }
367
368 hdr->nlmsg_flags |= NLM_F_MULTI;
369 for (int i = 0; i < nitems(creators); i++) {
370 if (creators[i] == 0)
371 break;
372 error = dump_creatorid(npt->nlp, hdr, creators[i], npt);
373 }
374
375 if (!nlmsg_end_dump(npt->nw, error, hdr)) {
376 NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
377 return (ENOMEM);
378 }
379
380 return (error);
381 }
382
383 static int
pf_handle_start(struct nlmsghdr * hdr __unused,struct nl_pstate * npt __unused)384 pf_handle_start(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
385 {
386 return (pf_start());
387 }
388
389 static int
pf_handle_stop(struct nlmsghdr * hdr __unused,struct nl_pstate * npt __unused)390 pf_handle_stop(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
391 {
392 return (pf_stop());
393 }
394
395 #define _OUT(_field) offsetof(struct pf_addr_wrap, _field)
396 static const struct nlattr_parser nla_p_addr_wrap[] = {
397 { .type = PF_AT_ADDR, .off = _OUT(v.a.addr), .cb = nlattr_get_in6_addr },
398 { .type = PF_AT_MASK, .off = _OUT(v.a.mask), .cb = nlattr_get_in6_addr },
399 { .type = PF_AT_IFNAME, .off = _OUT(v.ifname), .arg = (void *)IFNAMSIZ,.cb = nlattr_get_chara },
400 { .type = PF_AT_TABLENAME, .off = _OUT(v.tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
401 { .type = PF_AT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
402 { .type = PF_AT_IFLAGS, .off = _OUT(iflags), .cb = nlattr_get_uint8 },
403 };
404 NL_DECLARE_ATTR_PARSER(addr_wrap_parser, nla_p_addr_wrap);
405 #undef _OUT
406
407 static bool
nlattr_add_addr_wrap(struct nl_writer * nw,int attrtype,struct pf_addr_wrap * a)408 nlattr_add_addr_wrap(struct nl_writer *nw, int attrtype, struct pf_addr_wrap *a)
409 {
410 int off = nlattr_add_nested(nw, attrtype);
411 int num;
412
413 nlattr_add_in6_addr(nw, PF_AT_ADDR, &a->v.a.addr.v6);
414 nlattr_add_in6_addr(nw, PF_AT_MASK, &a->v.a.mask.v6);
415 nlattr_add_u8(nw, PF_AT_TYPE, a->type);
416 nlattr_add_u8(nw, PF_AT_IFLAGS, a->iflags);
417
418 if (a->type == PF_ADDR_DYNIFTL) {
419 nlattr_add_string(nw, PF_AT_IFNAME, a->v.ifname);
420 num = 0;
421 if (a->p.dyn != NULL)
422 num = a->p.dyn->pfid_acnt4 + a->p.dyn->pfid_acnt6;
423 nlattr_add_u32(nw, PF_AT_DYNCNT, num);
424 } else if (a->type == PF_ADDR_TABLE) {
425 struct pfr_ktable *kt;
426
427 nlattr_add_string(nw, PF_AT_TABLENAME, a->v.tblname);
428 num = -1;
429 kt = a->p.tbl;
430 if ((kt->pfrkt_flags & PFR_TFLAG_ACTIVE) &&
431 kt->pfrkt_root != NULL)
432 kt = kt->pfrkt_root;
433 if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE)
434 num = kt->pfrkt_cnt;
435 nlattr_add_u32(nw, PF_AT_TBLCNT, num);
436 }
437
438 nlattr_set_len(nw, off);
439
440 return (true);
441 }
442
443 #define _OUT(_field) offsetof(struct pf_rule_addr, _field)
444 static const struct nlattr_parser nla_p_ruleaddr[] = {
445 { .type = PF_RAT_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
446 { .type = PF_RAT_SRC_PORT, .off = _OUT(port[0]), .cb = nlattr_get_uint16 },
447 { .type = PF_RAT_DST_PORT, .off = _OUT(port[1]), .cb = nlattr_get_uint16 },
448 { .type = PF_RAT_NEG, .off = _OUT(neg), .cb = nlattr_get_uint8 },
449 { .type = PF_RAT_OP, .off = _OUT(port_op), .cb = nlattr_get_uint8 },
450 };
451 NL_DECLARE_ATTR_PARSER(rule_addr_parser, nla_p_ruleaddr);
452 #undef _OUT
453
454 static bool
nlattr_add_rule_addr(struct nl_writer * nw,int attrtype,struct pf_rule_addr * r)455 nlattr_add_rule_addr(struct nl_writer *nw, int attrtype, struct pf_rule_addr *r)
456 {
457 int off = nlattr_add_nested(nw, attrtype);
458
459 nlattr_add_addr_wrap(nw, PF_RAT_ADDR, &r->addr);
460 nlattr_add_u16(nw, PF_RAT_SRC_PORT, r->port[0]);
461 nlattr_add_u16(nw, PF_RAT_DST_PORT, r->port[1]);
462 nlattr_add_u8(nw, PF_RAT_NEG, r->neg);
463 nlattr_add_u8(nw, PF_RAT_OP, r->port_op);
464
465 nlattr_set_len(nw, off);
466
467 return (true);
468 }
469
470 #define _OUT(_field) offsetof(struct pf_mape_portset, _field)
471 static const struct nlattr_parser nla_p_mape_portset[] = {
472 { .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = nlattr_get_uint8 },
473 { .type = PF_MET_PSID_LEN, .off = _OUT(psidlen), .cb = nlattr_get_uint8 },
474 {. type = PF_MET_PSID, .off = _OUT(psid), .cb = nlattr_get_uint16 },
475 };
476 NL_DECLARE_ATTR_PARSER(mape_portset_parser, nla_p_mape_portset);
477 #undef _OUT
478
479 static bool
nlattr_add_mape_portset(struct nl_writer * nw,int attrtype,const struct pf_mape_portset * m)480 nlattr_add_mape_portset(struct nl_writer *nw, int attrtype, const struct pf_mape_portset *m)
481 {
482 int off = nlattr_add_nested(nw, attrtype);
483
484 nlattr_add_u8(nw, PF_MET_OFFSET, m->offset);
485 nlattr_add_u8(nw, PF_MET_PSID_LEN, m->psidlen);
486 nlattr_add_u16(nw, PF_MET_PSID, m->psid);
487
488 nlattr_set_len(nw, off);
489
490 return (true);
491 }
492
493 struct nl_parsed_labels
494 {
495 char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
496 uint32_t i;
497 };
498
499 static int
nlattr_get_pf_rule_labels(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)500 nlattr_get_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt,
501 const void *arg, void *target)
502 {
503 struct nl_parsed_labels *l = (struct nl_parsed_labels *)target;
504 int ret;
505
506 if (l->i >= PF_RULE_MAX_LABEL_COUNT)
507 return (E2BIG);
508
509 ret = nlattr_get_chara(nla, npt, (void *)PF_RULE_LABEL_SIZE,
510 l->labels[l->i]);
511 if (ret == 0)
512 l->i++;
513
514 return (ret);
515 }
516
517 #define _OUT(_field) offsetof(struct nl_parsed_labels, _field)
518 static const struct nlattr_parser nla_p_labels[] = {
519 { .type = PF_LT_LABEL, .off = 0, .cb = nlattr_get_pf_rule_labels },
520 };
521 NL_DECLARE_ATTR_PARSER(rule_labels_parser, nla_p_labels);
522 #undef _OUT
523
524 static int
nlattr_get_nested_pf_rule_labels(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)525 nlattr_get_nested_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
526 {
527 struct nl_parsed_labels parsed_labels = { };
528 int error;
529
530 /* Assumes target points to the beginning of the structure */
531 error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &rule_labels_parser, npt, &parsed_labels);
532 if (error != 0)
533 return (error);
534
535 memcpy(target, parsed_labels.labels, sizeof(parsed_labels.labels));
536
537 return (0);
538 }
539
540 static bool
nlattr_add_labels(struct nl_writer * nw,int attrtype,const struct pf_krule * r)541 nlattr_add_labels(struct nl_writer *nw, int attrtype, const struct pf_krule *r)
542 {
543 int off = nlattr_add_nested(nw, attrtype);
544 int i = 0;
545
546 while (r->label[i][0] != 0
547 && i < PF_RULE_MAX_LABEL_COUNT) {
548 nlattr_add_string(nw, PF_LT_LABEL, r->label[i]);
549 i++;
550 }
551
552 nlattr_set_len(nw, off);
553
554 return (true);
555 }
556
557 #define _OUT(_field) offsetof(struct pf_kpool, _field)
558 static const struct nlattr_parser nla_p_pool[] = {
559 { .type = PF_PT_KEY, .off = _OUT(key), .arg = (void *)sizeof(struct pf_poolhashkey), .cb = nlattr_get_bytes },
560 { .type = PF_PT_COUNTER, .off = _OUT(counter), .cb = nlattr_get_in6_addr },
561 { .type = PF_PT_TBLIDX, .off = _OUT(tblidx), .cb = nlattr_get_uint32 },
562 { .type = PF_PT_PROXY_SRC_PORT, .off = _OUT(proxy_port[0]), .cb = nlattr_get_uint16 },
563 { .type = PF_PT_PROXY_DST_PORT, .off = _OUT(proxy_port[1]), .cb = nlattr_get_uint16 },
564 { .type = PF_PT_OPTS, .off = _OUT(opts), .cb = nlattr_get_uint8 },
565 { .type = PF_PT_MAPE, .off = _OUT(mape), .arg = &mape_portset_parser, .cb = nlattr_get_nested },
566 };
567 NL_DECLARE_ATTR_PARSER(pool_parser, nla_p_pool);
568 #undef _OUT
569
570 static bool
nlattr_add_pool(struct nl_writer * nw,int attrtype,const struct pf_kpool * pool)571 nlattr_add_pool(struct nl_writer *nw, int attrtype, const struct pf_kpool *pool)
572 {
573 int off = nlattr_add_nested(nw, attrtype);
574
575 nlattr_add(nw, PF_PT_KEY, sizeof(struct pf_poolhashkey), &pool->key);
576 nlattr_add_in6_addr(nw, PF_PT_COUNTER, (const struct in6_addr *)&pool->counter);
577 nlattr_add_u32(nw, PF_PT_TBLIDX, pool->tblidx);
578 nlattr_add_u16(nw, PF_PT_PROXY_SRC_PORT, pool->proxy_port[0]);
579 nlattr_add_u16(nw, PF_PT_PROXY_DST_PORT, pool->proxy_port[1]);
580 nlattr_add_u8(nw, PF_PT_OPTS, pool->opts);
581 nlattr_add_mape_portset(nw, PF_PT_MAPE, &pool->mape);
582
583 nlattr_set_len(nw, off);
584
585 return (true);
586 }
587
588 #define _OUT(_field) offsetof(struct pf_rule_uid, _field)
589 static const struct nlattr_parser nla_p_rule_uid[] = {
590 { .type = PF_RUT_UID_LOW, .off = _OUT(uid[0]), .cb = nlattr_get_uint32 },
591 { .type = PF_RUT_UID_HIGH, .off = _OUT(uid[1]), .cb = nlattr_get_uint32 },
592 { .type = PF_RUT_OP, .off = _OUT(op), .cb = nlattr_get_uint8 },
593 };
594 NL_DECLARE_ATTR_PARSER(rule_uid_parser, nla_p_rule_uid);
595 #undef _OUT
596
597 static bool
nlattr_add_rule_uid(struct nl_writer * nw,int attrtype,const struct pf_rule_uid * u)598 nlattr_add_rule_uid(struct nl_writer *nw, int attrtype, const struct pf_rule_uid *u)
599 {
600 int off = nlattr_add_nested(nw, attrtype);
601
602 nlattr_add_u32(nw, PF_RUT_UID_LOW, u->uid[0]);
603 nlattr_add_u32(nw, PF_RUT_UID_HIGH, u->uid[1]);
604 nlattr_add_u8(nw, PF_RUT_OP, u->op);
605
606 nlattr_set_len(nw, off);
607
608 return (true);
609 }
610
611 struct nl_parsed_timeouts
612 {
613 uint32_t timeouts[PFTM_MAX];
614 uint32_t i;
615 };
616
617 static int
nlattr_get_pf_timeout(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)618 nlattr_get_pf_timeout(struct nlattr *nla, struct nl_pstate *npt,
619 const void *arg, void *target)
620 {
621 struct nl_parsed_timeouts *t = (struct nl_parsed_timeouts *)target;
622 int ret;
623
624 if (t->i >= PFTM_MAX)
625 return (E2BIG);
626
627 ret = nlattr_get_uint32(nla, npt, NULL, &t->timeouts[t->i]);
628 if (ret == 0)
629 t->i++;
630
631 return (ret);
632 }
633
634 #define _OUT(_field) offsetof(struct nl_parsed_timeout, _field)
635 static const struct nlattr_parser nla_p_timeouts[] = {
636 { .type = PF_TT_TIMEOUT, .off = 0, .cb = nlattr_get_pf_timeout },
637 };
638 NL_DECLARE_ATTR_PARSER(timeout_parser, nla_p_timeouts);
639 #undef _OUT
640
641 static int
nlattr_get_nested_timeouts(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)642 nlattr_get_nested_timeouts(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
643 {
644 struct nl_parsed_timeouts parsed_timeouts = { };
645 int error;
646
647 /* Assumes target points to the beginning of the structure */
648 error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &timeout_parser, npt, &parsed_timeouts);
649 if (error != 0)
650 return (error);
651
652 memcpy(target, parsed_timeouts.timeouts, sizeof(parsed_timeouts.timeouts));
653
654 return (0);
655 }
656
657 static bool
nlattr_add_timeout(struct nl_writer * nw,int attrtype,uint32_t * timeout)658 nlattr_add_timeout(struct nl_writer *nw, int attrtype, uint32_t *timeout)
659 {
660 int off = nlattr_add_nested(nw, attrtype);
661
662 for (int i = 0; i < PFTM_MAX; i++)
663 nlattr_add_u32(nw, PF_RT_TIMEOUT, timeout[i]);
664
665 nlattr_set_len(nw, off);
666
667 return (true);
668 }
669
670 #define _OUT(_field) offsetof(struct pf_krule, _field)
671 static const struct nlattr_parser nla_p_rule[] = {
672 { .type = PF_RT_SRC, .off = _OUT(src), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
673 { .type = PF_RT_DST, .off = _OUT(dst), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
674 { .type = PF_RT_RIDENTIFIER, .off = _OUT(ridentifier), .cb = nlattr_get_uint32 },
675 { .type = PF_RT_LABELS, .off = _OUT(label), .arg = &rule_labels_parser,.cb = nlattr_get_nested_pf_rule_labels },
676 { .type = PF_RT_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
677 { .type = PF_RT_QNAME, .off = _OUT(qname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
678 { .type = PF_RT_PQNAME, .off = _OUT(pqname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
679 { .type = PF_RT_TAGNAME, .off = _OUT(tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
680 { .type = PF_RT_MATCH_TAGNAME, .off = _OUT(match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
681 { .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
682 { .type = PF_RT_RPOOL, .off = _OUT(rpool), .arg = &pool_parser, .cb = nlattr_get_nested },
683 { .type = PF_RT_OS_FINGERPRINT, .off = _OUT(os_fingerprint), .cb = nlattr_get_uint32 },
684 { .type = PF_RT_RTABLEID, .off = _OUT(rtableid), .cb = nlattr_get_uint32 },
685 { .type = PF_RT_TIMEOUT, .off = _OUT(timeout), .arg = &timeout_parser, .cb = nlattr_get_nested_timeouts },
686 { .type = PF_RT_MAX_STATES, .off = _OUT(max_states), .cb = nlattr_get_uint32 },
687 { .type = PF_RT_MAX_SRC_NODES, .off = _OUT(max_src_nodes), .cb = nlattr_get_uint32 },
688 { .type = PF_RT_MAX_SRC_STATES, .off = _OUT(max_src_states), .cb = nlattr_get_uint32 },
689 { .type = PF_RT_MAX_SRC_CONN_RATE_LIMIT, .off = _OUT(max_src_conn_rate.limit), .cb = nlattr_get_uint32 },
690 { .type = PF_RT_MAX_SRC_CONN_RATE_SECS, .off = _OUT(max_src_conn_rate.seconds), .cb = nlattr_get_uint32 },
691 { .type = PF_RT_DNPIPE, .off = _OUT(dnpipe), .cb = nlattr_get_uint16 },
692 { .type = PF_RT_DNRPIPE, .off = _OUT(dnrpipe), .cb = nlattr_get_uint16 },
693 { .type = PF_RT_DNFLAGS, .off = _OUT(free_flags), .cb = nlattr_get_uint32 },
694 { .type = PF_RT_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
695 { .type = PF_RT_PROB, .off = _OUT(prob), .cb = nlattr_get_uint32 },
696 { .type = PF_RT_CUID, .off = _OUT(cuid), .cb = nlattr_get_uint32 },
697 {. type = PF_RT_CPID, .off = _OUT(cpid), .cb = nlattr_get_uint32 },
698 { .type = PF_RT_RETURN_ICMP, .off = _OUT(return_icmp), .cb = nlattr_get_uint16 },
699 { .type = PF_RT_RETURN_ICMP6, .off = _OUT(return_icmp6), .cb = nlattr_get_uint16 },
700 { .type = PF_RT_MAX_MSS, .off = _OUT(max_mss), .cb = nlattr_get_uint16 },
701 { .type = PF_RT_SCRUB_FLAGS, .off = _OUT(scrub_flags), .cb = nlattr_get_uint16 },
702 { .type = PF_RT_UID, .off = _OUT(uid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
703 { .type = PF_RT_GID, .off = _OUT(gid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
704 { .type = PF_RT_RULE_FLAG, .off = _OUT(rule_flag), .cb = nlattr_get_uint32 },
705 { .type = PF_RT_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
706 { .type = PF_RT_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
707 { .type = PF_RT_LOG, .off = _OUT(log), .cb = nlattr_get_uint8 },
708 { .type = PF_RT_LOGIF, .off = _OUT(logif), .cb = nlattr_get_uint8 },
709 { .type = PF_RT_QUICK, .off = _OUT(quick), .cb = nlattr_get_uint8 },
710 { .type = PF_RT_IF_NOT, .off = _OUT(ifnot), .cb = nlattr_get_uint8 },
711 { .type = PF_RT_MATCH_TAG_NOT, .off = _OUT(match_tag_not), .cb = nlattr_get_uint8 },
712 { .type = PF_RT_NATPASS, .off = _OUT(natpass), .cb = nlattr_get_uint8 },
713 { .type = PF_RT_KEEP_STATE, .off = _OUT(keep_state), .cb = nlattr_get_uint8 },
714 { .type = PF_RT_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
715 { .type = PF_RT_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
716 { .type = PF_RT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
717 { .type = PF_RT_CODE, .off = _OUT(code), .cb = nlattr_get_uint8 },
718 { .type = PF_RT_FLAGS, .off = _OUT(flags), .cb = nlattr_get_uint8 },
719 { .type = PF_RT_FLAGSET, .off = _OUT(flagset), .cb = nlattr_get_uint8 },
720 { .type = PF_RT_MIN_TTL, .off = _OUT(min_ttl), .cb = nlattr_get_uint8 },
721 { .type = PF_RT_ALLOW_OPTS, .off = _OUT(allow_opts), .cb = nlattr_get_uint8 },
722 { .type = PF_RT_RT, .off = _OUT(rt), .cb = nlattr_get_uint8 },
723 { .type = PF_RT_RETURN_TTL, .off = _OUT(return_ttl), .cb = nlattr_get_uint8 },
724 { .type = PF_RT_TOS, .off = _OUT(tos), .cb = nlattr_get_uint8 },
725 { .type = PF_RT_SET_TOS, .off = _OUT(set_tos), .cb = nlattr_get_uint8 },
726 { .type = PF_RT_ANCHOR_RELATIVE, .off = _OUT(anchor_relative), .cb = nlattr_get_uint8 },
727 { .type = PF_RT_ANCHOR_WILDCARD, .off = _OUT(anchor_wildcard), .cb = nlattr_get_uint8 },
728 { .type = PF_RT_FLUSH, .off = _OUT(flush), .cb = nlattr_get_uint8 },
729 { .type = PF_RT_PRIO, .off = _OUT(prio), .cb = nlattr_get_uint8 },
730 { .type = PF_RT_SET_PRIO, .off = _OUT(set_prio[0]), .cb = nlattr_get_uint8 },
731 { .type = PF_RT_SET_PRIO_REPLY, .off = _OUT(set_prio[1]), .cb = nlattr_get_uint8 },
732 { .type = PF_RT_DIVERT_ADDRESS, .off = _OUT(divert.addr), .cb = nlattr_get_in6_addr },
733 { .type = PF_RT_DIVERT_PORT, .off = _OUT(divert.port), .cb = nlattr_get_uint16 },
734 };
735 NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule);
736 #undef _OUT
737 struct nl_parsed_addrule {
738 struct pf_krule *rule;
739 uint32_t ticket;
740 uint32_t pool_ticket;
741 char *anchor;
742 char *anchor_call;
743 };
744 #define _IN(_field) offsetof(struct genlmsghdr, _field)
745 #define _OUT(_field) offsetof(struct nl_parsed_addrule, _field)
746 static const struct nlattr_parser nla_p_addrule[] = {
747 { .type = PF_ART_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
748 { .type = PF_ART_POOL_TICKET, .off = _OUT(pool_ticket), .cb = nlattr_get_uint32 },
749 { .type = PF_ART_ANCHOR, .off = _OUT(anchor), .cb = nlattr_get_string },
750 { .type = PF_ART_ANCHOR_CALL, .off = _OUT(anchor_call), .cb = nlattr_get_string },
751 { .type = PF_ART_RULE, .off = _OUT(rule), .arg = &rule_parser, .cb = nlattr_get_nested_ptr }
752 };
753 static const struct nlfield_parser nlf_p_addrule[] = {
754 };
755 #undef _IN
756 #undef _OUT
757 NL_DECLARE_PARSER(addrule_parser, struct genlmsghdr, nlf_p_addrule, nla_p_addrule);
758
759 static int
pf_handle_addrule(struct nlmsghdr * hdr,struct nl_pstate * npt)760 pf_handle_addrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
761 {
762 int error;
763 struct nl_parsed_addrule attrs = {};
764
765 attrs.rule = pf_krule_alloc();
766
767 error = nl_parse_nlmsg(hdr, &addrule_parser, npt, &attrs);
768 if (error != 0) {
769 pf_free_rule(attrs.rule);
770 return (error);
771 }
772
773 error = pf_ioctl_addrule(attrs.rule, attrs.ticket, attrs.pool_ticket,
774 attrs.anchor, attrs.anchor_call, nlp_get_cred(npt->nlp)->cr_uid,
775 hdr->nlmsg_pid);
776
777 return (error);
778 }
779
780 #define _IN(_field) offsetof(struct genlmsghdr, _field)
781 #define _OUT(_field) offsetof(struct pfioc_rule, _field)
782 static const struct nlattr_parser nla_p_getrules[] = {
783 { .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
784 { .type = PF_GR_ACTION, .off = _OUT(rule.action), .cb = nlattr_get_uint8 },
785 };
786 static const struct nlfield_parser nlf_p_getrules[] = {
787 };
788 #undef _IN
789 #undef _OUT
790 NL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, nlf_p_getrules, nla_p_getrules);
791
792 static int
pf_handle_getrules(struct nlmsghdr * hdr,struct nl_pstate * npt)793 pf_handle_getrules(struct nlmsghdr *hdr, struct nl_pstate *npt)
794 {
795 struct pfioc_rule attrs = {};
796 int error;
797 struct nl_writer *nw = npt->nw;
798 struct genlmsghdr *ghdr_new;
799
800 error = nl_parse_nlmsg(hdr, &getrules_parser, npt, &attrs);
801 if (error != 0)
802 return (error);
803
804 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
805 return (ENOMEM);
806
807 ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
808 ghdr_new->cmd = PFNL_CMD_GETRULES;
809 ghdr_new->version = 0;
810 ghdr_new->reserved = 0;
811
812 error = pf_ioctl_getrules(&attrs);
813 if (error != 0)
814 goto out;
815
816 nlattr_add_u32(nw, PF_GR_NR, attrs.nr);
817 nlattr_add_u32(nw, PF_GR_TICKET, attrs.ticket);
818
819 if (!nlmsg_end(nw)) {
820 error = ENOMEM;
821 goto out;
822 }
823
824 return (0);
825
826 out:
827 nlmsg_abort(nw);
828 return (error);
829 }
830
831 struct nl_parsed_get_rule {
832 char anchor[MAXPATHLEN];
833 uint8_t action;
834 uint32_t nr;
835 uint32_t ticket;
836 uint8_t clear;
837 };
838 #define _IN(_field) offsetof(struct genlmsghdr, _field)
839 #define _OUT(_field) offsetof(struct nl_parsed_get_rule, _field)
840 static const struct nlattr_parser nla_p_getrule[] = {
841 { .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
842 { .type = PF_GR_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
843 { .type = PF_GR_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
844 { .type = PF_GR_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
845 { .type = PF_GR_CLEAR, .off = _OUT(clear), .cb = nlattr_get_uint8 },
846 };
847 static const struct nlfield_parser nlf_p_getrule[] = {
848 };
849 #undef _IN
850 #undef _OUT
851 NL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, nlf_p_getrule, nla_p_getrule);
852
853 static int
pf_handle_getrule(struct nlmsghdr * hdr,struct nl_pstate * npt)854 pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
855 {
856 char anchor_call[MAXPATHLEN];
857 struct nl_parsed_get_rule attrs = {};
858 struct nl_writer *nw = npt->nw;
859 struct genlmsghdr *ghdr_new;
860 struct pf_kruleset *ruleset;
861 struct pf_krule *rule;
862 int rs_num;
863 int error;
864
865 error = nl_parse_nlmsg(hdr, &getrule_parser, npt, &attrs);
866 if (error != 0)
867 return (error);
868
869 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
870 return (ENOMEM);
871
872 ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
873 ghdr_new->cmd = PFNL_CMD_GETRULE;
874 ghdr_new->version = 0;
875 ghdr_new->reserved = 0;
876
877 PF_RULES_WLOCK();
878 ruleset = pf_find_kruleset(attrs.anchor);
879 if (ruleset == NULL) {
880 PF_RULES_WUNLOCK();
881 error = ENOENT;
882 goto out;
883 }
884
885 rs_num = pf_get_ruleset_number(attrs.action);
886 if (rs_num >= PF_RULESET_MAX) {
887 PF_RULES_WUNLOCK();
888 error = EINVAL;
889 goto out;
890 }
891
892 if (attrs.ticket != ruleset->rules[rs_num].active.ticket) {
893 PF_RULES_WUNLOCK();
894 error = EBUSY;
895 goto out;
896 }
897
898 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
899 while ((rule != NULL) && (rule->nr != attrs.nr))
900 rule = TAILQ_NEXT(rule, entries);
901 if (rule == NULL) {
902 PF_RULES_WUNLOCK();
903 error = EBUSY;
904 goto out;
905 }
906
907 nlattr_add_rule_addr(nw, PF_RT_SRC, &rule->src);
908 nlattr_add_rule_addr(nw, PF_RT_DST, &rule->dst);
909 nlattr_add_u32(nw, PF_RT_RIDENTIFIER, rule->ridentifier);
910 nlattr_add_labels(nw, PF_RT_LABELS, rule);
911 nlattr_add_string(nw, PF_RT_IFNAME, rule->ifname);
912 nlattr_add_string(nw, PF_RT_QNAME, rule->qname);
913 nlattr_add_string(nw, PF_RT_PQNAME, rule->pqname);
914 nlattr_add_string(nw, PF_RT_TAGNAME, rule->tagname);
915 nlattr_add_string(nw, PF_RT_MATCH_TAGNAME, rule->match_tagname);
916 nlattr_add_string(nw, PF_RT_OVERLOAD_TBLNAME, rule->overload_tblname);
917 nlattr_add_pool(nw, PF_RT_RPOOL, &rule->rpool);
918 nlattr_add_u32(nw, PF_RT_OS_FINGERPRINT, rule->os_fingerprint);
919 nlattr_add_u32(nw, PF_RT_RTABLEID, rule->rtableid);
920 nlattr_add_timeout(nw, PF_RT_TIMEOUT, rule->timeout);
921 nlattr_add_u32(nw, PF_RT_MAX_STATES, rule->max_states);
922 nlattr_add_u32(nw, PF_RT_MAX_SRC_NODES, rule->max_src_nodes);
923 nlattr_add_u32(nw, PF_RT_MAX_SRC_STATES, rule->max_src_states);
924 nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_LIMIT, rule->max_src_conn_rate.limit);
925 nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_SECS, rule->max_src_conn_rate.seconds);
926
927 nlattr_add_u16(nw, PF_RT_DNPIPE, rule->dnpipe);
928 nlattr_add_u16(nw, PF_RT_DNRPIPE, rule->dnrpipe);
929 nlattr_add_u32(nw, PF_RT_DNFLAGS, rule->free_flags);
930
931 nlattr_add_u32(nw, PF_RT_NR, rule->nr);
932 nlattr_add_u32(nw, PF_RT_PROB, rule->prob);
933 nlattr_add_u32(nw, PF_RT_CUID, rule->cuid);
934 nlattr_add_u32(nw, PF_RT_CPID, rule->cpid);
935
936 nlattr_add_u16(nw, PF_RT_RETURN_ICMP, rule->return_icmp);
937 nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
938 nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
939 nlattr_add_u16(nw, PF_RT_MAX_MSS, rule->max_mss);
940 nlattr_add_u16(nw, PF_RT_SCRUB_FLAGS, rule->scrub_flags);
941
942 nlattr_add_rule_uid(nw, PF_RT_UID, &rule->uid);
943 nlattr_add_rule_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&rule->gid);
944
945 nlattr_add_u32(nw, PF_RT_RULE_FLAG, rule->rule_flag);
946 nlattr_add_u8(nw, PF_RT_ACTION, rule->action);
947 nlattr_add_u8(nw, PF_RT_DIRECTION, rule->direction);
948 nlattr_add_u8(nw, PF_RT_LOG, rule->log);
949 nlattr_add_u8(nw, PF_RT_LOGIF, rule->logif);
950 nlattr_add_u8(nw, PF_RT_QUICK, rule->quick);
951 nlattr_add_u8(nw, PF_RT_IF_NOT, rule->ifnot);
952 nlattr_add_u8(nw, PF_RT_MATCH_TAG_NOT, rule->match_tag_not);
953 nlattr_add_u8(nw, PF_RT_NATPASS, rule->natpass);
954 nlattr_add_u8(nw, PF_RT_KEEP_STATE, rule->keep_state);
955
956 nlattr_add_u8(nw, PF_RT_AF, rule->af);
957 nlattr_add_u8(nw, PF_RT_PROTO, rule->proto);
958 nlattr_add_u8(nw, PF_RT_TYPE, rule->type);
959 nlattr_add_u8(nw, PF_RT_CODE, rule->code);
960 nlattr_add_u8(nw, PF_RT_FLAGS, rule->flags);
961 nlattr_add_u8(nw, PF_RT_FLAGSET, rule->flagset);
962 nlattr_add_u8(nw, PF_RT_MIN_TTL, rule->min_ttl);
963 nlattr_add_u8(nw, PF_RT_ALLOW_OPTS, rule->allow_opts);
964 nlattr_add_u8(nw, PF_RT_RT, rule->rt);
965 nlattr_add_u8(nw, PF_RT_RETURN_TTL, rule->return_ttl);
966 nlattr_add_u8(nw, PF_RT_TOS, rule->tos);
967 nlattr_add_u8(nw, PF_RT_SET_TOS, rule->set_tos);
968 nlattr_add_u8(nw, PF_RT_ANCHOR_RELATIVE, rule->anchor_relative);
969 nlattr_add_u8(nw, PF_RT_ANCHOR_WILDCARD, rule->anchor_wildcard);
970 nlattr_add_u8(nw, PF_RT_FLUSH, rule->flush);
971 nlattr_add_u8(nw, PF_RT_PRIO, rule->prio);
972 nlattr_add_u8(nw, PF_RT_SET_PRIO, rule->set_prio[0]);
973 nlattr_add_u8(nw, PF_RT_SET_PRIO_REPLY, rule->set_prio[1]);
974
975 nlattr_add_in6_addr(nw, PF_RT_DIVERT_ADDRESS, &rule->divert.addr.v6);
976 nlattr_add_u16(nw, PF_RT_DIVERT_PORT, rule->divert.port);
977
978 nlattr_add_u64(nw, PF_RT_PACKETS_IN, pf_counter_u64_fetch(&rule->packets[0]));
979 nlattr_add_u64(nw, PF_RT_PACKETS_OUT, pf_counter_u64_fetch(&rule->packets[1]));
980 nlattr_add_u64(nw, PF_RT_BYTES_IN, pf_counter_u64_fetch(&rule->bytes[0]));
981 nlattr_add_u64(nw, PF_RT_BYTES_OUT, pf_counter_u64_fetch(&rule->bytes[1]));
982 nlattr_add_u64(nw, PF_RT_EVALUATIONS, pf_counter_u64_fetch(&rule->evaluations));
983 nlattr_add_u64(nw, PF_RT_TIMESTAMP, pf_get_timestamp(rule));
984 nlattr_add_u64(nw, PF_RT_STATES_CUR, counter_u64_fetch(rule->states_cur));
985 nlattr_add_u64(nw, PF_RT_STATES_TOTAL, counter_u64_fetch(rule->states_tot));
986 nlattr_add_u64(nw, PF_RT_SRC_NODES, counter_u64_fetch(rule->src_nodes));
987
988 error = pf_kanchor_copyout(ruleset, rule, anchor_call, sizeof(anchor_call));
989 MPASS(error == 0);
990
991 nlattr_add_string(nw, PF_RT_ANCHOR_CALL, anchor_call);
992
993 if (attrs.clear)
994 pf_krule_clear_counters(rule);
995
996 PF_RULES_WUNLOCK();
997
998 if (!nlmsg_end(nw)) {
999 error = ENOMEM;
1000 goto out;
1001 }
1002
1003 return (0);
1004 out:
1005 nlmsg_abort(nw);
1006 return (error);
1007 }
1008
1009 #define _IN(_field) offsetof(struct genlmsghdr, _field)
1010 #define _OUT(_field) offsetof(struct pf_kstate_kill, _field)
1011 static const struct nlattr_parser nla_p_clear_states[] = {
1012 { .type = PF_CS_CMP_ID, .off = _OUT(psk_pfcmp.id), .cb = nlattr_get_uint64 },
1013 { .type = PF_CS_CMP_CREATORID, .off = _OUT(psk_pfcmp.creatorid), .cb = nlattr_get_uint32 },
1014 { .type = PF_CS_CMP_DIR, .off = _OUT(psk_pfcmp.direction), .cb = nlattr_get_uint8 },
1015 { .type = PF_CS_AF, .off = _OUT(psk_af), .cb = nlattr_get_uint8 },
1016 { .type = PF_CS_PROTO, .off = _OUT(psk_proto), .cb = nlattr_get_uint8 },
1017 { .type = PF_CS_SRC, .off = _OUT(psk_src), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1018 { .type = PF_CS_DST, .off = _OUT(psk_dst), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1019 { .type = PF_CS_RT_ADDR, .off = _OUT(psk_rt_addr), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1020 { .type = PF_CS_IFNAME, .off = _OUT(psk_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
1021 { .type = PF_CS_LABEL, .off = _OUT(psk_label), .arg = (void *)PF_RULE_LABEL_SIZE, .cb = nlattr_get_chara },
1022 { .type = PF_CS_KILL_MATCH, .off = _OUT(psk_kill_match), .cb = nlattr_get_bool },
1023 { .type = PF_CS_NAT, .off = _OUT(psk_nat), .cb = nlattr_get_bool },
1024 };
1025 static const struct nlfield_parser nlf_p_clear_states[] = {};
1026 #undef _IN
1027 #undef _OUT
1028 NL_DECLARE_PARSER(clear_states_parser, struct genlmsghdr, nlf_p_clear_states, nla_p_clear_states);
1029
1030 static int
pf_handle_killclear_states(struct nlmsghdr * hdr,struct nl_pstate * npt,int cmd)1031 pf_handle_killclear_states(struct nlmsghdr *hdr, struct nl_pstate *npt, int cmd)
1032 {
1033 struct pf_kstate_kill kill = {};
1034 struct epoch_tracker et;
1035 struct nl_writer *nw = npt->nw;
1036 struct genlmsghdr *ghdr_new;
1037 int error;
1038 unsigned int killed = 0;
1039
1040 error = nl_parse_nlmsg(hdr, &clear_states_parser, npt, &kill);
1041 if (error != 0)
1042 return (error);
1043
1044 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1045 return (ENOMEM);
1046
1047 ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1048 ghdr_new->cmd = cmd;
1049 ghdr_new->version = 0;
1050 ghdr_new->reserved = 0;
1051
1052 NET_EPOCH_ENTER(et);
1053 if (cmd == PFNL_CMD_KILLSTATES)
1054 pf_killstates(&kill, &killed);
1055 else
1056 killed = pf_clear_states(&kill);
1057 NET_EPOCH_EXIT(et);
1058
1059 nlattr_add_u32(nw, PF_CS_KILLED, killed);
1060
1061 if (! nlmsg_end(nw)) {
1062 error = ENOMEM;
1063 goto out;
1064 }
1065
1066 return (0);
1067
1068 out:
1069 nlmsg_abort(nw);
1070 return (error);
1071 }
1072
1073 static int
pf_handle_clear_states(struct nlmsghdr * hdr,struct nl_pstate * npt)1074 pf_handle_clear_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
1075 {
1076 return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_CLRSTATES));
1077 }
1078
1079 static int
pf_handle_kill_states(struct nlmsghdr * hdr,struct nl_pstate * npt)1080 pf_handle_kill_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
1081 {
1082 return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_KILLSTATES));
1083 }
1084
1085 struct nl_parsed_set_statusif {
1086 char ifname[IFNAMSIZ];
1087 };
1088 #define _IN(_field) offsetof(struct genlmsghdr, _field)
1089 #define _OUT(_field) offsetof(struct nl_parsed_set_statusif, _field)
1090 static const struct nlattr_parser nla_p_set_statusif[] = {
1091 { .type = PF_SS_IFNAME, .off = _OUT(ifname), .arg = (const void *)IFNAMSIZ, .cb = nlattr_get_chara },
1092 };
1093 static const struct nlfield_parser nlf_p_set_statusif[] = {};
1094 #undef _IN
1095 #undef _OUT
1096 NL_DECLARE_PARSER(set_statusif_parser, struct genlmsghdr, nlf_p_set_statusif, nla_p_set_statusif);
1097
1098 static int
pf_handle_set_statusif(struct nlmsghdr * hdr,struct nl_pstate * npt)1099 pf_handle_set_statusif(struct nlmsghdr *hdr, struct nl_pstate *npt)
1100 {
1101 int error;
1102 struct nl_parsed_set_statusif attrs = {};
1103
1104 error = nl_parse_nlmsg(hdr, &set_statusif_parser, npt, &attrs);
1105 if (error != 0)
1106 return (error);
1107
1108 PF_RULES_WLOCK();
1109 strlcpy(V_pf_status.ifname, attrs.ifname, IFNAMSIZ);
1110 PF_RULES_WUNLOCK();
1111
1112 return (0);
1113 }
1114
1115 static bool
nlattr_add_counters(struct nl_writer * nw,int attr,size_t number,char ** names,counter_u64_t * counters)1116 nlattr_add_counters(struct nl_writer *nw, int attr, size_t number, char **names,
1117 counter_u64_t *counters)
1118 {
1119 for (int i = 0; i < number; i++) {
1120 int off = nlattr_add_nested(nw, attr);
1121 nlattr_add_u32(nw, PF_C_ID, i);
1122 nlattr_add_string(nw, PF_C_NAME, names[i]);
1123 nlattr_add_u64(nw, PF_C_COUNTER, counter_u64_fetch(counters[i]));
1124 nlattr_set_len(nw, off);
1125 }
1126
1127 return (true);
1128 }
1129
1130 static bool
nlattr_add_fcounters(struct nl_writer * nw,int attr,size_t number,char ** names,struct pf_counter_u64 * counters)1131 nlattr_add_fcounters(struct nl_writer *nw, int attr, size_t number, char **names,
1132 struct pf_counter_u64 *counters)
1133 {
1134 for (int i = 0; i < number; i++) {
1135 int off = nlattr_add_nested(nw, attr);
1136 nlattr_add_u32(nw, PF_C_ID, i);
1137 nlattr_add_string(nw, PF_C_NAME, names[i]);
1138 nlattr_add_u64(nw, PF_C_COUNTER, pf_counter_u64_fetch(&counters[i]));
1139 nlattr_set_len(nw, off);
1140 }
1141
1142 return (true);
1143 }
1144
1145 static bool
nlattr_add_u64_array(struct nl_writer * nw,int attr,size_t number,uint64_t * array)1146 nlattr_add_u64_array(struct nl_writer *nw, int attr, size_t number, uint64_t *array)
1147 {
1148 int off = nlattr_add_nested(nw, attr);
1149
1150 for (size_t i = 0; i < number; i++)
1151 nlattr_add_u64(nw, 0, array[i]);
1152
1153 nlattr_set_len(nw, off);
1154
1155 return (true);
1156 }
1157
1158 static int
pf_handle_get_status(struct nlmsghdr * hdr,struct nl_pstate * npt)1159 pf_handle_get_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
1160 {
1161 struct pf_status s;
1162 struct nl_writer *nw = npt->nw;
1163 struct genlmsghdr *ghdr_new;
1164 char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
1165 char *pf_lcounter[KLCNT_MAX+1] = KLCNT_NAMES;
1166 char *pf_fcounter[FCNT_MAX+1] = FCNT_NAMES;
1167 int error;
1168
1169 PF_RULES_RLOCK_TRACKER;
1170
1171 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1172 return (ENOMEM);
1173
1174 ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1175 ghdr_new->cmd = PFNL_CMD_GET_STATUS;
1176 ghdr_new->version = 0;
1177 ghdr_new->reserved = 0;
1178
1179 PF_RULES_RLOCK();
1180
1181 nlattr_add_string(nw, PF_GS_IFNAME, V_pf_status.ifname);
1182 nlattr_add_bool(nw, PF_GS_RUNNING, V_pf_status.running);
1183 nlattr_add_u32(nw, PF_GS_SINCE, V_pf_status.since);
1184 nlattr_add_u32(nw, PF_GS_DEBUG, V_pf_status.debug);
1185 nlattr_add_u32(nw, PF_GS_HOSTID, ntohl(V_pf_status.hostid));
1186 nlattr_add_u32(nw, PF_GS_STATES, V_pf_status.states);
1187 nlattr_add_u32(nw, PF_GS_SRC_NODES, V_pf_status.src_nodes);
1188 nlattr_add_u32(nw, PF_GS_REASSEMBLE, V_pf_status.reass);
1189 nlattr_add_u32(nw, PF_GS_SYNCOOKIES_ACTIVE, V_pf_status.syncookies_active);
1190
1191 nlattr_add_counters(nw, PF_GS_COUNTERS, PFRES_MAX, pf_reasons,
1192 V_pf_status.counters);
1193 nlattr_add_counters(nw, PF_GS_LCOUNTERS, KLCNT_MAX, pf_lcounter,
1194 V_pf_status.lcounters);
1195 nlattr_add_fcounters(nw, PF_GS_FCOUNTERS, FCNT_MAX, pf_fcounter,
1196 V_pf_status.fcounters);
1197 nlattr_add_counters(nw, PF_GS_SCOUNTERS, SCNT_MAX, pf_fcounter,
1198 V_pf_status.scounters);
1199
1200 pfi_update_status(V_pf_status.ifname, &s);
1201 nlattr_add_u64_array(nw, PF_GS_BCOUNTERS, 2 * 2, (uint64_t *)s.bcounters);
1202 nlattr_add_u64_array(nw, PF_GS_PCOUNTERS, 2 * 2 * 2, (uint64_t *)s.pcounters);
1203
1204 nlattr_add(nw, PF_GS_CHKSUM, PF_MD5_DIGEST_LENGTH, V_pf_status.pf_chksum);
1205
1206 PF_RULES_RUNLOCK();
1207
1208 if (!nlmsg_end(nw)) {
1209 error = ENOMEM;
1210 goto out;
1211 }
1212
1213 return (0);
1214
1215 out:
1216 nlmsg_abort(nw);
1217 return (error);
1218 }
1219
1220 static int
pf_handle_clear_status(struct nlmsghdr * hdr,struct nl_pstate * npt)1221 pf_handle_clear_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
1222 {
1223 pf_ioctl_clear_status();
1224
1225 return (0);
1226 }
1227
1228 struct pf_nl_natlook {
1229 sa_family_t af;
1230 uint8_t direction;
1231 uint8_t proto;
1232 struct pf_addr src;
1233 struct pf_addr dst;
1234 uint16_t sport;
1235 uint16_t dport;
1236 };
1237
1238 #define _IN(_field) offsetof(struct genlmsghdr, _field)
1239 #define _OUT(_field) offsetof(struct pf_nl_natlook, _field)
1240 static const struct nlattr_parser nla_p_natlook[] = {
1241 { .type = PF_NL_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
1242 { .type = PF_NL_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
1243 { .type = PF_NL_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
1244 { .type = PF_NL_SRC_ADDR, .off = _OUT(src), .cb = nlattr_get_in6_addr },
1245 { .type = PF_NL_DST_ADDR, .off = _OUT(dst), .cb = nlattr_get_in6_addr },
1246 { .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = nlattr_get_uint16 },
1247 { .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = nlattr_get_uint16 },
1248 };
1249 static const struct nlfield_parser nlf_p_natlook[] = {};
1250 #undef _IN
1251 #undef _OUT
1252 NL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, nlf_p_natlook, nla_p_natlook);
1253
1254 static int
pf_handle_natlook(struct nlmsghdr * hdr,struct nl_pstate * npt)1255 pf_handle_natlook(struct nlmsghdr *hdr, struct nl_pstate *npt)
1256 {
1257 struct pf_nl_natlook attrs = {};
1258 struct pf_state_key_cmp key = {};
1259 struct nl_writer *nw = npt->nw;
1260 struct pf_state_key *sk;
1261 struct pf_kstate *state;
1262 struct genlmsghdr *ghdr_new;
1263 int error, m;
1264 int sidx, didx;
1265
1266 error = nl_parse_nlmsg(hdr, &natlook_parser, npt, &attrs);
1267 if (error != 0)
1268 return (error);
1269
1270 if (attrs.proto == 0 ||
1271 PF_AZERO(&attrs.src, attrs.af) ||
1272 PF_AZERO(&attrs.dst, attrs.af) ||
1273 ((attrs.proto == IPPROTO_TCP || attrs.proto == IPPROTO_UDP) &&
1274 (attrs.sport == 0 || attrs.dport == 0)))
1275 return (EINVAL);
1276
1277 /* NATLOOK src and dst are reversed, so reverse sidx/didx */
1278 sidx = (attrs.direction == PF_IN) ? 1 : 0;
1279 didx = (attrs.direction == PF_IN) ? 0 : 1;
1280
1281 key.af = attrs.af;
1282 key.proto = attrs.proto;
1283 PF_ACPY(&key.addr[sidx], &attrs.src, attrs.af);
1284 key.port[sidx] = attrs.sport;
1285 PF_ACPY(&key.addr[didx], &attrs.dst, attrs.af);
1286 key.port[didx] = attrs.dport;
1287
1288 state = pf_find_state_all(&key, attrs.direction, &m);
1289 if (state == NULL)
1290 return (ENOENT);
1291 if (m > 1) {
1292 PF_STATE_UNLOCK(state);
1293 return (E2BIG);
1294 }
1295
1296 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
1297 PF_STATE_UNLOCK(state);
1298 return (ENOMEM);
1299 }
1300
1301 ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1302 ghdr_new->cmd = PFNL_CMD_NATLOOK;
1303 ghdr_new->version = 0;
1304 ghdr_new->reserved = 0;
1305
1306 sk = state->key[sidx];
1307
1308 nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &sk->addr[sidx].v6);
1309 nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &sk->addr[didx].v6);
1310 nlattr_add_u16(nw, PF_NL_SRC_PORT, sk->port[sidx]);
1311 nlattr_add_u16(nw, PF_NL_DST_PORT, sk->port[didx]);
1312
1313 PF_STATE_UNLOCK(state);
1314
1315 if (!nlmsg_end(nw)) {
1316 nlmsg_abort(nw);
1317 return (ENOMEM);
1318 }
1319
1320 return (0);
1321 }
1322
1323 struct pf_nl_set_debug
1324 {
1325 uint32_t level;
1326 };
1327 #define _OUT(_field) offsetof(struct pf_nl_set_debug, _field)
1328 static const struct nlattr_parser nla_p_set_debug[] = {
1329 { .type = PF_SD_LEVEL, .off = _OUT(level), .cb = nlattr_get_uint32 },
1330 };
1331 static const struct nlfield_parser nlf_p_set_debug[] = {};
1332 #undef _OUT
1333 NL_DECLARE_PARSER(set_debug_parser, struct genlmsghdr, nlf_p_set_debug, nla_p_set_debug);
1334
1335 static int
pf_handle_set_debug(struct nlmsghdr * hdr,struct nl_pstate * npt)1336 pf_handle_set_debug(struct nlmsghdr *hdr, struct nl_pstate *npt)
1337 {
1338 struct pf_nl_set_debug attrs = {};
1339 int error;
1340
1341 error = nl_parse_nlmsg(hdr, &set_debug_parser, npt, &attrs);
1342 if (error != 0)
1343 return (error);
1344
1345 PF_RULES_WLOCK();
1346 V_pf_status.debug = attrs.level;
1347 PF_RULES_WUNLOCK();
1348
1349 return (0);
1350 }
1351
1352 struct pf_nl_set_timeout
1353 {
1354 uint32_t timeout;
1355 uint32_t seconds;
1356 };
1357 #define _OUT(_field) offsetof(struct pf_nl_set_timeout, _field)
1358 static const struct nlattr_parser nla_p_set_timeout[] = {
1359 { .type = PF_TO_TIMEOUT, .off = _OUT(timeout), .cb = nlattr_get_uint32 },
1360 { .type = PF_TO_SECONDS, .off = _OUT(seconds), .cb = nlattr_get_uint32 },
1361 };
1362 static const struct nlfield_parser nlf_p_set_timeout[] = {};
1363 #undef _OUT
1364 NL_DECLARE_PARSER(set_timeout_parser, struct genlmsghdr, nlf_p_set_timeout, nla_p_set_timeout);
1365
1366 static int
pf_handle_set_timeout(struct nlmsghdr * hdr,struct nl_pstate * npt)1367 pf_handle_set_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
1368 {
1369 struct pf_nl_set_timeout attrs = {};
1370 int error;
1371
1372 error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
1373 if (error != 0)
1374 return (error);
1375
1376 return (pf_ioctl_set_timeout(attrs.timeout, attrs.seconds, NULL));
1377 }
1378
1379 static int
pf_handle_get_timeout(struct nlmsghdr * hdr,struct nl_pstate * npt)1380 pf_handle_get_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
1381 {
1382 struct pf_nl_set_timeout attrs = {};
1383 struct nl_writer *nw = npt->nw;
1384 struct genlmsghdr *ghdr_new;
1385 int error;
1386
1387 error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
1388 if (error != 0)
1389 return (error);
1390
1391 error = pf_ioctl_get_timeout(attrs.timeout, &attrs.seconds);
1392 if (error != 0)
1393 return (error);
1394
1395 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1396 return (ENOMEM);
1397
1398 ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1399 ghdr_new->cmd = PFNL_CMD_GET_TIMEOUT;
1400 ghdr_new->version = 0;
1401 ghdr_new->reserved = 0;
1402
1403 nlattr_add_u32(nw, PF_TO_SECONDS, attrs.seconds);
1404
1405 if (!nlmsg_end(nw)) {
1406 nlmsg_abort(nw);
1407 return (ENOMEM);
1408 }
1409
1410 return (0);
1411 }
1412
1413 struct pf_nl_set_limit
1414 {
1415 uint32_t index;
1416 uint32_t limit;
1417 };
1418 #define _OUT(_field) offsetof(struct pf_nl_set_limit, _field)
1419 static const struct nlattr_parser nla_p_set_limit[] = {
1420 { .type = PF_LI_INDEX, .off = _OUT(index), .cb = nlattr_get_uint32 },
1421 { .type = PF_LI_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
1422 };
1423 static const struct nlfield_parser nlf_p_set_limit[] = {};
1424 #undef _OUT
1425 NL_DECLARE_PARSER(set_limit_parser, struct genlmsghdr, nlf_p_set_limit, nla_p_set_limit);
1426
1427 static int
pf_handle_set_limit(struct nlmsghdr * hdr,struct nl_pstate * npt)1428 pf_handle_set_limit(struct nlmsghdr *hdr, struct nl_pstate *npt)
1429 {
1430 struct pf_nl_set_limit attrs = {};
1431 int error;
1432
1433 error = nl_parse_nlmsg(hdr, &set_limit_parser, npt, &attrs);
1434 if (error != 0)
1435 return (error);
1436
1437 return (pf_ioctl_set_limit(attrs.index, attrs.limit, NULL));
1438 }
1439
1440 static int
pf_handle_get_limit(struct nlmsghdr * hdr,struct nl_pstate * npt)1441 pf_handle_get_limit(struct nlmsghdr *hdr, struct nl_pstate *npt)
1442 {
1443 struct pf_nl_set_limit attrs = {};
1444 struct nl_writer *nw = npt->nw;
1445 struct genlmsghdr *ghdr_new;
1446 int error;
1447
1448 error = nl_parse_nlmsg(hdr, &set_limit_parser, npt, &attrs);
1449 if (error != 0)
1450 return (error);
1451
1452 error = pf_ioctl_get_limit(attrs.index, &attrs.limit);
1453 if (error != 0)
1454 return (error);
1455
1456 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1457 return (ENOMEM);
1458
1459 ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1460 ghdr_new->cmd = PFNL_CMD_GET_LIMIT;
1461 ghdr_new->version = 0;
1462 ghdr_new->reserved = 0;
1463
1464 nlattr_add_u32(nw, PF_LI_LIMIT, attrs.limit);
1465
1466 if (!nlmsg_end(nw)) {
1467 nlmsg_abort(nw);
1468 return (ENOMEM);
1469 }
1470
1471 return (0);
1472 }
1473
1474 static int
pf_handle_begin_addrs(struct nlmsghdr * hdr,struct nl_pstate * npt)1475 pf_handle_begin_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
1476 {
1477 struct nl_writer *nw = npt->nw;
1478 struct genlmsghdr *ghdr_new;
1479 uint32_t ticket;
1480 int error;
1481
1482 error = pf_ioctl_begin_addrs(&ticket);
1483 if (error != 0)
1484 return (error);
1485
1486 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1487 return (ENOMEM);
1488
1489 ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1490 ghdr_new->cmd = PFNL_CMD_BEGIN_ADDRS;
1491 ghdr_new->version = 0;
1492 ghdr_new->reserved = 0;
1493
1494 nlattr_add_u32(nw, PF_BA_TICKET, ticket);
1495
1496 if (!nlmsg_end(nw)) {
1497 nlmsg_abort(nw);
1498 return (ENOMEM);
1499 }
1500
1501 return (0);
1502 }
1503
1504 static const struct nlhdr_parser *all_parsers[] = {
1505 &state_parser,
1506 &addrule_parser,
1507 &getrules_parser,
1508 &clear_states_parser,
1509 &set_statusif_parser,
1510 &natlook_parser,
1511 &set_debug_parser,
1512 &set_timeout_parser,
1513 &set_limit_parser,
1514 };
1515
1516 static int family_id;
1517
1518 static const struct genl_cmd pf_cmds[] = {
1519 {
1520 .cmd_num = PFNL_CMD_GETSTATES,
1521 .cmd_name = "GETSTATES",
1522 .cmd_cb = pf_handle_getstates,
1523 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1524 .cmd_priv = PRIV_NETINET_PF,
1525 },
1526 {
1527 .cmd_num = PFNL_CMD_GETCREATORS,
1528 .cmd_name = "GETCREATORS",
1529 .cmd_cb = pf_handle_getcreators,
1530 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1531 .cmd_priv = PRIV_NETINET_PF,
1532 },
1533 {
1534 .cmd_num = PFNL_CMD_START,
1535 .cmd_name = "START",
1536 .cmd_cb = pf_handle_start,
1537 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1538 .cmd_priv = PRIV_NETINET_PF,
1539 },
1540 {
1541 .cmd_num = PFNL_CMD_STOP,
1542 .cmd_name = "STOP",
1543 .cmd_cb = pf_handle_stop,
1544 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1545 .cmd_priv = PRIV_NETINET_PF,
1546 },
1547 {
1548 .cmd_num = PFNL_CMD_ADDRULE,
1549 .cmd_name = "ADDRULE",
1550 .cmd_cb = pf_handle_addrule,
1551 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1552 .cmd_priv = PRIV_NETINET_PF,
1553 },
1554 {
1555 .cmd_num = PFNL_CMD_GETRULES,
1556 .cmd_name = "GETRULES",
1557 .cmd_cb = pf_handle_getrules,
1558 .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1559 .cmd_priv = PRIV_NETINET_PF,
1560 },
1561 {
1562 .cmd_num = PFNL_CMD_GETRULE,
1563 .cmd_name = "GETRULE",
1564 .cmd_cb = pf_handle_getrule,
1565 .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1566 .cmd_priv = PRIV_NETINET_PF,
1567 },
1568 {
1569 .cmd_num = PFNL_CMD_CLRSTATES,
1570 .cmd_name = "CLRSTATES",
1571 .cmd_cb = pf_handle_clear_states,
1572 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1573 .cmd_priv = PRIV_NETINET_PF,
1574 },
1575 {
1576 .cmd_num = PFNL_CMD_KILLSTATES,
1577 .cmd_name = "KILLSTATES",
1578 .cmd_cb = pf_handle_kill_states,
1579 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1580 .cmd_priv = PRIV_NETINET_PF,
1581 },
1582 {
1583 .cmd_num = PFNL_CMD_SET_STATUSIF,
1584 .cmd_name = "SETSTATUSIF",
1585 .cmd_cb = pf_handle_set_statusif,
1586 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1587 .cmd_priv = PRIV_NETINET_PF,
1588 },
1589 {
1590 .cmd_num = PFNL_CMD_GET_STATUS,
1591 .cmd_name = "GETSTATUS",
1592 .cmd_cb = pf_handle_get_status,
1593 .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1594 .cmd_priv = PRIV_NETINET_PF,
1595 },
1596 {
1597 .cmd_num = PFNL_CMD_CLEAR_STATUS,
1598 .cmd_name = "CLEARSTATUS",
1599 .cmd_cb = pf_handle_clear_status,
1600 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1601 .cmd_priv = PRIV_NETINET_PF,
1602 },
1603 {
1604 .cmd_num = PFNL_CMD_NATLOOK,
1605 .cmd_name = "NATLOOK",
1606 .cmd_cb = pf_handle_natlook,
1607 .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1608 .cmd_priv = PRIV_NETINET_PF,
1609 },
1610 {
1611 .cmd_num = PFNL_CMD_SET_DEBUG,
1612 .cmd_name = "SET_DEBUG",
1613 .cmd_cb = pf_handle_set_debug,
1614 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1615 .cmd_priv = PRIV_NETINET_PF,
1616 },
1617 {
1618 .cmd_num = PFNL_CMD_SET_TIMEOUT,
1619 .cmd_name = "SET_TIMEOUT",
1620 .cmd_cb = pf_handle_set_timeout,
1621 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1622 .cmd_priv = PRIV_NETINET_PF,
1623 },
1624 {
1625 .cmd_num = PFNL_CMD_GET_TIMEOUT,
1626 .cmd_name = "GET_TIMEOUT",
1627 .cmd_cb = pf_handle_get_timeout,
1628 .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1629 .cmd_priv = PRIV_NETINET_PF,
1630 },
1631 {
1632 .cmd_num = PFNL_CMD_SET_LIMIT,
1633 .cmd_name = "SET_LIMIT",
1634 .cmd_cb = pf_handle_set_limit,
1635 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1636 .cmd_priv = PRIV_NETINET_PF,
1637 },
1638 {
1639 .cmd_num = PFNL_CMD_GET_LIMIT,
1640 .cmd_name = "GET_LIMIT",
1641 .cmd_cb = pf_handle_get_limit,
1642 .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1643 .cmd_priv = PRIV_NETINET_PF,
1644 },
1645 {
1646 .cmd_num = PFNL_CMD_BEGIN_ADDRS,
1647 .cmd_name = "BEGIN_ADDRS",
1648 .cmd_cb = pf_handle_begin_addrs,
1649 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1650 .cmd_priv = PRIV_NETINET_PF,
1651 },
1652 };
1653
1654 void
pf_nl_register(void)1655 pf_nl_register(void)
1656 {
1657 NL_VERIFY_PARSERS(all_parsers);
1658
1659 family_id = genl_register_family(PFNL_FAMILY_NAME, 0, 2, PFNL_CMD_MAX);
1660 genl_register_cmds(PFNL_FAMILY_NAME, pf_cmds, NL_ARRAY_LEN(pf_cmds));
1661 }
1662
1663 void
pf_nl_unregister(void)1664 pf_nl_unregister(void)
1665 {
1666 genl_unregister_family(PFNL_FAMILY_NAME);
1667 }
1668