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
30 #include <sys/param.h>
31 #include <sys/malloc.h>
32 #include <sys/mbuf.h>
33 #include <sys/priv.h>
34 #include <sys/socket.h>
35 #include <sys/ucred.h>
36
37 #include <net/pfvar.h>
38
39 #include <netlink/netlink.h>
40 #include <netlink/netlink_ctl.h>
41 #include <netlink/netlink_generic.h>
42 #include <netlink/netlink_message_writer.h>
43
44 #include <netpfil/pf/pf_nl.h>
45
46 #define DEBUG_MOD_NAME nl_pf
47 #define DEBUG_MAX_LEVEL LOG_DEBUG3
48 #include <netlink/netlink_debug.h>
49 _DECLARE_DEBUG(LOG_DEBUG);
50
51 struct nl_parsed_state {
52 uint8_t version;
53 uint32_t id;
54 uint32_t creatorid;
55 char ifname[IFNAMSIZ];
56 uint16_t proto;
57 sa_family_t af;
58 struct pf_addr addr;
59 struct pf_addr mask;
60 };
61
62 #define _IN(_field) offsetof(struct genlmsghdr, _field)
63 #define _OUT(_field) offsetof(struct nl_parsed_state, _field)
64 static const struct nlattr_parser nla_p_state[] = {
65 { .type = PF_ST_ID, .off = _OUT(id), .cb = nlattr_get_uint32 },
66 { .type = PF_ST_CREATORID, .off = _OUT(creatorid), .cb = nlattr_get_uint32 },
67 { .type = PF_ST_IFNAME, .arg = (const void *)IFNAMSIZ, .off = _OUT(ifname), .cb = nlattr_get_chara },
68 { .type = PF_ST_AF, .off = _OUT(proto), .cb = nlattr_get_uint8 },
69 { .type = PF_ST_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint16 },
70 { .type = PF_ST_FILTER_ADDR, .off = _OUT(addr), .cb = nlattr_get_in6_addr },
71 { .type = PF_ST_FILTER_MASK, .off = _OUT(mask), .cb = nlattr_get_in6_addr },
72 };
73 static const struct nlfield_parser nlf_p_generic[] = {
74 { .off_in = _IN(version), .off_out = _OUT(version), .cb = nlf_get_u8 },
75 };
76 #undef _IN
77 #undef _OUT
78 NL_DECLARE_PARSER(state_parser, struct genlmsghdr, nlf_p_generic, nla_p_state);
79
80 static void
dump_addr(struct nl_writer * nw,int attr,const struct pf_addr * addr,int af)81 dump_addr(struct nl_writer *nw, int attr, const struct pf_addr *addr, int af)
82 {
83 switch (af) {
84 case AF_INET:
85 nlattr_add(nw, attr, 4, &addr->v4);
86 break;
87 case AF_INET6:
88 nlattr_add(nw, attr, 16, &addr->v6);
89 break;
90 };
91 }
92
93 static bool
dump_state_peer(struct nl_writer * nw,int attr,const struct pf_state_peer * peer)94 dump_state_peer(struct nl_writer *nw, int attr, const struct pf_state_peer *peer)
95 {
96 int off = nlattr_add_nested(nw, attr);
97 if (off == 0)
98 return (false);
99
100 nlattr_add_u32(nw, PF_STP_SEQLO, peer->seqlo);
101 nlattr_add_u32(nw, PF_STP_SEQHI, peer->seqhi);
102 nlattr_add_u32(nw, PF_STP_SEQDIFF, peer->seqdiff);
103 nlattr_add_u16(nw, PF_STP_MAX_WIN, peer->max_win);
104 nlattr_add_u16(nw, PF_STP_MSS, peer->mss);
105 nlattr_add_u8(nw, PF_STP_STATE, peer->state);
106 nlattr_add_u8(nw, PF_STP_WSCALE, peer->wscale);
107
108 if (peer->scrub != NULL) {
109 struct pf_state_scrub *sc = peer->scrub;
110 uint16_t pfss_flags = sc->pfss_flags & PFSS_TIMESTAMP;
111
112 nlattr_add_u16(nw, PF_STP_PFSS_FLAGS, pfss_flags);
113 nlattr_add_u32(nw, PF_STP_PFSS_TS_MOD, sc->pfss_ts_mod);
114 nlattr_add_u8(nw, PF_STP_PFSS_TTL, sc->pfss_ttl);
115 nlattr_add_u8(nw, PF_STP_SCRUB_FLAG, PFSYNC_SCRUB_FLAG_VALID);
116 }
117 nlattr_set_len(nw, off);
118
119 return (true);
120 }
121
122 static bool
dump_state_key(struct nl_writer * nw,int attr,const struct pf_state_key * key)123 dump_state_key(struct nl_writer *nw, int attr, const struct pf_state_key *key)
124 {
125 int off = nlattr_add_nested(nw, attr);
126 if (off == 0)
127 return (false);
128
129 dump_addr(nw, PF_STK_ADDR0, &key->addr[0], key->af);
130 dump_addr(nw, PF_STK_ADDR1, &key->addr[1], key->af);
131 nlattr_add_u16(nw, PF_STK_PORT0, key->port[0]);
132 nlattr_add_u16(nw, PF_STK_PORT1, key->port[1]);
133
134 nlattr_set_len(nw, off);
135
136 return (true);
137 }
138
139 static int
dump_state(struct nlpcb * nlp,const struct nlmsghdr * hdr,struct pf_kstate * s,struct nl_pstate * npt)140 dump_state(struct nlpcb *nlp, const struct nlmsghdr *hdr, struct pf_kstate *s,
141 struct nl_pstate *npt)
142 {
143 struct nl_writer *nw = npt->nw;
144 int error = 0;
145 int af;
146 struct pf_state_key *key;
147
148 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
149 goto enomem;
150
151 struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
152 ghdr_new->cmd = PFNL_CMD_GETSTATES;
153 ghdr_new->version = 0;
154 ghdr_new->reserved = 0;
155
156 nlattr_add_u64(nw, PF_ST_VERSION, PF_STATE_VERSION);
157
158 key = s->key[PF_SK_WIRE];
159 if (!dump_state_key(nw, PF_ST_KEY_WIRE, key))
160 goto enomem;
161 key = s->key[PF_SK_STACK];
162 if (!dump_state_key(nw, PF_ST_KEY_STACK, key))
163 goto enomem;
164
165 af = s->key[PF_SK_WIRE]->af;
166 nlattr_add_u8(nw, PF_ST_PROTO, s->key[PF_SK_WIRE]->proto);
167 nlattr_add_u8(nw, PF_ST_AF, af);
168
169 nlattr_add_string(nw, PF_ST_IFNAME, s->kif->pfik_name);
170 nlattr_add_string(nw, PF_ST_ORIG_IFNAME, s->orig_kif->pfik_name);
171 dump_addr(nw, PF_ST_RT_ADDR, &s->rt_addr, af);
172 nlattr_add_u32(nw, PF_ST_CREATION, time_uptime - (s->creation / 1000));
173 uint32_t expire = pf_state_expires(s);
174 if (expire > time_uptime)
175 expire = expire - time_uptime;
176 nlattr_add_u32(nw, PF_ST_EXPIRE, expire);
177 nlattr_add_u8(nw, PF_ST_DIRECTION, s->direction);
178 nlattr_add_u8(nw, PF_ST_LOG, s->act.log);
179 nlattr_add_u8(nw, PF_ST_TIMEOUT, s->timeout);
180 nlattr_add_u16(nw, PF_ST_STATE_FLAGS, s->state_flags);
181 uint8_t sync_flags = 0;
182 if (s->src_node)
183 sync_flags |= PFSYNC_FLAG_SRCNODE;
184 if (s->nat_src_node)
185 sync_flags |= PFSYNC_FLAG_NATSRCNODE;
186 nlattr_add_u8(nw, PF_ST_SYNC_FLAGS, sync_flags);
187 nlattr_add_u64(nw, PF_ST_ID, s->id);
188 nlattr_add_u32(nw, PF_ST_CREATORID, htonl(s->creatorid));
189
190 nlattr_add_u32(nw, PF_ST_RULE, s->rule.ptr ? s->rule.ptr->nr : -1);
191 nlattr_add_u32(nw, PF_ST_ANCHOR, s->anchor.ptr ? s->anchor.ptr->nr : -1);
192 nlattr_add_u32(nw, PF_ST_NAT_RULE, s->nat_rule.ptr ? s->nat_rule.ptr->nr : -1);
193
194 nlattr_add_u64(nw, PF_ST_PACKETS0, s->packets[0]);
195 nlattr_add_u64(nw, PF_ST_PACKETS1, s->packets[1]);
196 nlattr_add_u64(nw, PF_ST_BYTES0, s->bytes[0]);
197 nlattr_add_u64(nw, PF_ST_BYTES1, s->bytes[1]);
198 nlattr_add_u32(nw, PF_ST_RTABLEID, s->act.rtableid);
199 nlattr_add_u8(nw, PF_ST_MIN_TTL, s->act.min_ttl);
200 nlattr_add_u16(nw, PF_ST_MAX_MSS, s->act.max_mss);
201 nlattr_add_u16(nw, PF_ST_DNPIPE, s->act.dnpipe);
202 nlattr_add_u16(nw, PF_ST_DNRPIPE, s->act.dnrpipe);
203 nlattr_add_u8(nw, PF_ST_RT, s->rt);
204 if (s->rt_kif != NULL)
205 nlattr_add_string(nw, PF_ST_RT_IFNAME, s->rt_kif->pfik_name);
206
207 if (!dump_state_peer(nw, PF_ST_PEER_SRC, &s->src))
208 goto enomem;
209 if (!dump_state_peer(nw, PF_ST_PEER_DST, &s->dst))
210 goto enomem;
211
212 if (nlmsg_end(nw))
213 return (0);
214
215 enomem:
216 error = ENOMEM;
217 nlmsg_abort(nw);
218 return (error);
219 }
220
221 static int
handle_dumpstates(struct nlpcb * nlp,struct nl_parsed_state * attrs,struct nlmsghdr * hdr,struct nl_pstate * npt)222 handle_dumpstates(struct nlpcb *nlp, struct nl_parsed_state *attrs,
223 struct nlmsghdr *hdr, struct nl_pstate *npt)
224 {
225 int error = 0;
226
227 hdr->nlmsg_flags |= NLM_F_MULTI;
228
229 for (int i = 0; i <= pf_hashmask; i++) {
230 struct pf_idhash *ih = &V_pf_idhash[i];
231 struct pf_kstate *s;
232
233 if (LIST_EMPTY(&ih->states))
234 continue;
235
236 PF_HASHROW_LOCK(ih);
237 LIST_FOREACH(s, &ih->states, entry) {
238 sa_family_t af = s->key[PF_SK_WIRE]->af;
239
240 if (s->timeout == PFTM_UNLINKED)
241 continue;
242
243 /* Filter */
244 if (attrs->creatorid != 0 && s->creatorid != attrs->creatorid)
245 continue;
246 if (attrs->ifname[0] != 0 &&
247 strncmp(attrs->ifname, s->kif->pfik_name, IFNAMSIZ) != 0)
248 continue;
249 if (attrs->proto != 0 && s->key[PF_SK_WIRE]->proto != attrs->proto)
250 continue;
251 if (attrs->af != 0 && af != attrs->af)
252 continue;
253 if (pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[0],
254 &attrs->mask, &attrs->addr, af) &&
255 pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[1],
256 &attrs->mask, &attrs->addr, af) &&
257 pf_match_addr(1, &s->key[PF_SK_STACK]->addr[0],
258 &attrs->mask, &attrs->addr, af) &&
259 pf_match_addr(1, &s->key[PF_SK_STACK]->addr[1],
260 &attrs->mask, &attrs->addr, af))
261 continue;
262
263 error = dump_state(nlp, hdr, s, npt);
264 if (error != 0)
265 break;
266 }
267 PF_HASHROW_UNLOCK(ih);
268 }
269
270 if (!nlmsg_end_dump(npt->nw, error, hdr)) {
271 NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
272 return (ENOMEM);
273 }
274
275 return (error);
276 }
277
278 static int
handle_getstate(struct nlpcb * nlp,struct nl_parsed_state * attrs,struct nlmsghdr * hdr,struct nl_pstate * npt)279 handle_getstate(struct nlpcb *nlp, struct nl_parsed_state *attrs,
280 struct nlmsghdr *hdr, struct nl_pstate *npt)
281 {
282 struct pf_kstate *s = pf_find_state_byid(attrs->id, attrs->creatorid);
283 if (s == NULL)
284 return (ENOENT);
285 return (dump_state(nlp, hdr, s, npt));
286 }
287
288 static int
dump_creatorid(struct nlpcb * nlp,const struct nlmsghdr * hdr,uint32_t creator,struct nl_pstate * npt)289 dump_creatorid(struct nlpcb *nlp, const struct nlmsghdr *hdr, uint32_t creator,
290 struct nl_pstate *npt)
291 {
292 struct nl_writer *nw = npt->nw;
293
294 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
295 goto enomem;
296
297 struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
298 ghdr_new->cmd = PFNL_CMD_GETCREATORS;
299 ghdr_new->version = 0;
300 ghdr_new->reserved = 0;
301
302 nlattr_add_u32(nw, PF_ST_CREATORID, htonl(creator));
303
304 if (nlmsg_end(nw))
305 return (0);
306
307 enomem:
308 nlmsg_abort(nw);
309 return (ENOMEM);
310 }
311
312 static int
pf_handle_getstates(struct nlmsghdr * hdr,struct nl_pstate * npt)313 pf_handle_getstates(struct nlmsghdr *hdr, struct nl_pstate *npt)
314 {
315 int error;
316
317 struct nl_parsed_state attrs = {};
318 error = nl_parse_nlmsg(hdr, &state_parser, npt, &attrs);
319 if (error != 0)
320 return (error);
321
322 if (attrs.id != 0)
323 error = handle_getstate(npt->nlp, &attrs, hdr, npt);
324 else
325 error = handle_dumpstates(npt->nlp, &attrs, hdr, npt);
326
327 return (error);
328 }
329
330 static int
pf_handle_getcreators(struct nlmsghdr * hdr,struct nl_pstate * npt)331 pf_handle_getcreators(struct nlmsghdr *hdr, struct nl_pstate *npt)
332 {
333 uint32_t creators[16];
334 int error = 0;
335
336 bzero(creators, sizeof(creators));
337
338 for (int i = 0; i < pf_hashmask; i++) {
339 struct pf_idhash *ih = &V_pf_idhash[i];
340 struct pf_kstate *s;
341
342 if (LIST_EMPTY(&ih->states))
343 continue;
344
345 PF_HASHROW_LOCK(ih);
346 LIST_FOREACH(s, &ih->states, entry) {
347 int j;
348 if (s->timeout == PFTM_UNLINKED)
349 continue;
350
351 for (j = 0; j < nitems(creators); j++) {
352 if (creators[j] == s->creatorid)
353 break;
354 if (creators[j] == 0) {
355 creators[j] = s->creatorid;
356 break;
357 }
358 }
359 if (j == nitems(creators))
360 printf("Warning: too many creators!\n");
361 }
362 PF_HASHROW_UNLOCK(ih);
363 }
364
365 hdr->nlmsg_flags |= NLM_F_MULTI;
366 for (int i = 0; i < nitems(creators); i++) {
367 if (creators[i] == 0)
368 break;
369 error = dump_creatorid(npt->nlp, hdr, creators[i], npt);
370 }
371
372 if (!nlmsg_end_dump(npt->nw, error, hdr)) {
373 NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
374 return (ENOMEM);
375 }
376
377 return (error);
378 }
379
380 static int
pf_handle_start(struct nlmsghdr * hdr __unused,struct nl_pstate * npt __unused)381 pf_handle_start(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
382 {
383 return (pf_start());
384 }
385
386 static int
pf_handle_stop(struct nlmsghdr * hdr __unused,struct nl_pstate * npt __unused)387 pf_handle_stop(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
388 {
389 return (pf_stop());
390 }
391
392 #define _OUT(_field) offsetof(struct pf_addr_wrap, _field)
393 static const struct nlattr_parser nla_p_addr_wrap[] = {
394 { .type = PF_AT_ADDR, .off = _OUT(v.a.addr), .cb = nlattr_get_in6_addr },
395 { .type = PF_AT_MASK, .off = _OUT(v.a.mask), .cb = nlattr_get_in6_addr },
396 { .type = PF_AT_IFNAME, .off = _OUT(v.ifname), .arg = (void *)IFNAMSIZ,.cb = nlattr_get_chara },
397 { .type = PF_AT_TABLENAME, .off = _OUT(v.tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
398 { .type = PF_AT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
399 { .type = PF_AT_IFLAGS, .off = _OUT(iflags), .cb = nlattr_get_uint8 },
400 };
401 NL_DECLARE_ATTR_PARSER(addr_wrap_parser, nla_p_addr_wrap);
402 #undef _OUT
403
404 static bool
nlattr_add_addr_wrap(struct nl_writer * nw,int attrtype,struct pf_addr_wrap * a)405 nlattr_add_addr_wrap(struct nl_writer *nw, int attrtype, struct pf_addr_wrap *a)
406 {
407 int off = nlattr_add_nested(nw, attrtype);
408 int num;
409
410 nlattr_add_in6_addr(nw, PF_AT_ADDR, &a->v.a.addr.v6);
411 nlattr_add_in6_addr(nw, PF_AT_MASK, &a->v.a.mask.v6);
412 nlattr_add_u8(nw, PF_AT_TYPE, a->type);
413 nlattr_add_u8(nw, PF_AT_IFLAGS, a->iflags);
414
415 if (a->type == PF_ADDR_DYNIFTL) {
416 nlattr_add_string(nw, PF_AT_IFNAME, a->v.ifname);
417 num = 0;
418 if (a->p.dyn != NULL)
419 num = a->p.dyn->pfid_acnt4 + a->p.dyn->pfid_acnt6;
420 nlattr_add_u32(nw, PF_AT_DYNCNT, num);
421 } else if (a->type == PF_ADDR_TABLE) {
422 struct pfr_ktable *kt;
423
424 nlattr_add_string(nw, PF_AT_TABLENAME, a->v.tblname);
425 num = -1;
426 kt = a->p.tbl;
427 if ((kt->pfrkt_flags & PFR_TFLAG_ACTIVE) &&
428 kt->pfrkt_root != NULL)
429 kt = kt->pfrkt_root;
430 if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE)
431 num = kt->pfrkt_cnt;
432 nlattr_add_u32(nw, PF_AT_TBLCNT, num);
433 }
434
435 nlattr_set_len(nw, off);
436
437 return (true);
438 }
439
440 #define _OUT(_field) offsetof(struct pf_rule_addr, _field)
441 static const struct nlattr_parser nla_p_ruleaddr[] = {
442 { .type = PF_RAT_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
443 { .type = PF_RAT_SRC_PORT, .off = _OUT(port[0]), .cb = nlattr_get_uint16 },
444 { .type = PF_RAT_DST_PORT, .off = _OUT(port[1]), .cb = nlattr_get_uint16 },
445 { .type = PF_RAT_NEG, .off = _OUT(neg), .cb = nlattr_get_uint8 },
446 { .type = PF_RAT_OP, .off = _OUT(port_op), .cb = nlattr_get_uint8 },
447 };
448 NL_DECLARE_ATTR_PARSER(rule_addr_parser, nla_p_ruleaddr);
449 #undef _OUT
450
451 static bool
nlattr_add_rule_addr(struct nl_writer * nw,int attrtype,struct pf_rule_addr * r)452 nlattr_add_rule_addr(struct nl_writer *nw, int attrtype, struct pf_rule_addr *r)
453 {
454 int off = nlattr_add_nested(nw, attrtype);
455
456 nlattr_add_addr_wrap(nw, PF_RAT_ADDR, &r->addr);
457 nlattr_add_u16(nw, PF_RAT_SRC_PORT, r->port[0]);
458 nlattr_add_u16(nw, PF_RAT_DST_PORT, r->port[1]);
459 nlattr_add_u8(nw, PF_RAT_NEG, r->neg);
460 nlattr_add_u8(nw, PF_RAT_OP, r->port_op);
461
462 nlattr_set_len(nw, off);
463
464 return (true);
465 }
466
467 #define _OUT(_field) offsetof(struct pf_mape_portset, _field)
468 static const struct nlattr_parser nla_p_mape_portset[] = {
469 { .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = nlattr_get_uint8 },
470 { .type = PF_MET_PSID_LEN, .off = _OUT(psidlen), .cb = nlattr_get_uint8 },
471 {. type = PF_MET_PSID, .off = _OUT(psid), .cb = nlattr_get_uint16 },
472 };
473 NL_DECLARE_ATTR_PARSER(mape_portset_parser, nla_p_mape_portset);
474 #undef _OUT
475
476 static bool
nlattr_add_mape_portset(struct nl_writer * nw,int attrtype,const struct pf_mape_portset * m)477 nlattr_add_mape_portset(struct nl_writer *nw, int attrtype, const struct pf_mape_portset *m)
478 {
479 int off = nlattr_add_nested(nw, attrtype);
480
481 nlattr_add_u8(nw, PF_MET_OFFSET, m->offset);
482 nlattr_add_u8(nw, PF_MET_PSID_LEN, m->psidlen);
483 nlattr_add_u16(nw, PF_MET_PSID, m->psid);
484
485 nlattr_set_len(nw, off);
486
487 return (true);
488 }
489
490 struct nl_parsed_labels
491 {
492 char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
493 uint32_t i;
494 };
495
496 static int
nlattr_get_pf_rule_labels(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)497 nlattr_get_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt,
498 const void *arg, void *target)
499 {
500 struct nl_parsed_labels *l = (struct nl_parsed_labels *)target;
501 int ret;
502
503 if (l->i >= PF_RULE_MAX_LABEL_COUNT)
504 return (E2BIG);
505
506 ret = nlattr_get_chara(nla, npt, (void *)PF_RULE_LABEL_SIZE,
507 l->labels[l->i]);
508 if (ret == 0)
509 l->i++;
510
511 return (ret);
512 }
513
514 #define _OUT(_field) offsetof(struct nl_parsed_labels, _field)
515 static const struct nlattr_parser nla_p_labels[] = {
516 { .type = PF_LT_LABEL, .off = 0, .cb = nlattr_get_pf_rule_labels },
517 };
518 NL_DECLARE_ATTR_PARSER(rule_labels_parser, nla_p_labels);
519 #undef _OUT
520
521 static int
nlattr_get_nested_pf_rule_labels(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)522 nlattr_get_nested_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
523 {
524 struct nl_parsed_labels parsed_labels = { };
525 int error;
526
527 /* Assumes target points to the beginning of the structure */
528 error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &rule_labels_parser, npt, &parsed_labels);
529 if (error != 0)
530 return (error);
531
532 memcpy(target, parsed_labels.labels, sizeof(parsed_labels));
533
534 return (0);
535 }
536
537 static bool
nlattr_add_labels(struct nl_writer * nw,int attrtype,const struct pf_krule * r)538 nlattr_add_labels(struct nl_writer *nw, int attrtype, const struct pf_krule *r)
539 {
540 int off = nlattr_add_nested(nw, attrtype);
541 int i = 0;
542
543 while (r->label[i][0] != 0
544 && i < PF_RULE_MAX_LABEL_COUNT) {
545 nlattr_add_string(nw, PF_LT_LABEL, r->label[i]);
546 i++;
547 }
548
549 nlattr_set_len(nw, off);
550
551 return (true);
552 }
553
554 #define _OUT(_field) offsetof(struct pf_kpool, _field)
555 static const struct nlattr_parser nla_p_pool[] = {
556 { .type = PF_PT_KEY, .off = _OUT(key), .arg = (void *)sizeof(struct pf_poolhashkey), .cb = nlattr_get_bytes },
557 { .type = PF_PT_COUNTER, .off = _OUT(counter), .cb = nlattr_get_in6_addr },
558 { .type = PF_PT_TBLIDX, .off = _OUT(tblidx), .cb = nlattr_get_uint32 },
559 { .type = PF_PT_PROXY_SRC_PORT, .off = _OUT(proxy_port[0]), .cb = nlattr_get_uint16 },
560 { .type = PF_PT_PROXY_DST_PORT, .off = _OUT(proxy_port[1]), .cb = nlattr_get_uint16 },
561 { .type = PF_PT_OPTS, .off = _OUT(opts), .cb = nlattr_get_uint8 },
562 { .type = PF_PT_MAPE, .off = _OUT(mape), .arg = &mape_portset_parser, .cb = nlattr_get_nested },
563 };
564 NL_DECLARE_ATTR_PARSER(pool_parser, nla_p_pool);
565 #undef _OUT
566
567 static bool
nlattr_add_pool(struct nl_writer * nw,int attrtype,const struct pf_kpool * pool)568 nlattr_add_pool(struct nl_writer *nw, int attrtype, const struct pf_kpool *pool)
569 {
570 int off = nlattr_add_nested(nw, attrtype);
571
572 nlattr_add(nw, PF_PT_KEY, sizeof(struct pf_poolhashkey), &pool->key);
573 nlattr_add_in6_addr(nw, PF_PT_COUNTER, (const struct in6_addr *)&pool->counter);
574 nlattr_add_u32(nw, PF_PT_TBLIDX, pool->tblidx);
575 nlattr_add_u16(nw, PF_PT_PROXY_SRC_PORT, pool->proxy_port[0]);
576 nlattr_add_u16(nw, PF_PT_PROXY_DST_PORT, pool->proxy_port[1]);
577 nlattr_add_u8(nw, PF_PT_OPTS, pool->opts);
578 nlattr_add_mape_portset(nw, PF_PT_MAPE, &pool->mape);
579
580 nlattr_set_len(nw, off);
581
582 return (true);
583 }
584
585 #define _OUT(_field) offsetof(struct pf_rule_uid, _field)
586 static const struct nlattr_parser nla_p_rule_uid[] = {
587 { .type = PF_RUT_UID_LOW, .off = _OUT(uid[0]), .cb = nlattr_get_uint32 },
588 { .type = PF_RUT_UID_HIGH, .off = _OUT(uid[1]), .cb = nlattr_get_uint32 },
589 { .type = PF_RUT_OP, .off = _OUT(op), .cb = nlattr_get_uint8 },
590 };
591 NL_DECLARE_ATTR_PARSER(rule_uid_parser, nla_p_rule_uid);
592 #undef _OUT
593
594 static bool
nlattr_add_rule_uid(struct nl_writer * nw,int attrtype,const struct pf_rule_uid * u)595 nlattr_add_rule_uid(struct nl_writer *nw, int attrtype, const struct pf_rule_uid *u)
596 {
597 int off = nlattr_add_nested(nw, attrtype);
598
599 nlattr_add_u32(nw, PF_RUT_UID_LOW, u->uid[0]);
600 nlattr_add_u32(nw, PF_RUT_UID_HIGH, u->uid[1]);
601 nlattr_add_u8(nw, PF_RUT_OP, u->op);
602
603 nlattr_set_len(nw, off);
604
605 return (true);
606 }
607
608 struct nl_parsed_timeouts
609 {
610 uint32_t timeouts[PFTM_MAX];
611 uint32_t i;
612 };
613
614 static int
nlattr_get_pf_timeout(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)615 nlattr_get_pf_timeout(struct nlattr *nla, struct nl_pstate *npt,
616 const void *arg, void *target)
617 {
618 struct nl_parsed_timeouts *t = (struct nl_parsed_timeouts *)target;
619 int ret;
620
621 if (t->i >= PFTM_MAX)
622 return (E2BIG);
623
624 ret = nlattr_get_uint32(nla, npt, NULL, &t->timeouts[t->i]);
625 if (ret == 0)
626 t->i++;
627
628 return (ret);
629 }
630
631 #define _OUT(_field) offsetof(struct nl_parsed_timeout, _field)
632 static const struct nlattr_parser nla_p_timeouts[] = {
633 { .type = PF_TT_TIMEOUT, .off = 0, .cb = nlattr_get_pf_timeout },
634 };
635 NL_DECLARE_ATTR_PARSER(timeout_parser, nla_p_timeouts);
636 #undef _OUT
637
638 static int
nlattr_get_nested_timeouts(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)639 nlattr_get_nested_timeouts(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
640 {
641 struct nl_parsed_timeouts parsed_timeouts = { };
642 int error;
643
644 /* Assumes target points to the beginning of the structure */
645 error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &timeout_parser, npt, &parsed_timeouts);
646 if (error != 0)
647 return (error);
648
649 memcpy(target, parsed_timeouts.timeouts, sizeof(parsed_timeouts.timeouts));
650
651 return (0);
652 }
653
654 static bool
nlattr_add_timeout(struct nl_writer * nw,int attrtype,uint32_t * timeout)655 nlattr_add_timeout(struct nl_writer *nw, int attrtype, uint32_t *timeout)
656 {
657 int off = nlattr_add_nested(nw, attrtype);
658
659 for (int i = 0; i < PFTM_MAX; i++)
660 nlattr_add_u32(nw, PF_RT_TIMEOUT, timeout[i]);
661
662 nlattr_set_len(nw, off);
663
664 return (true);
665 }
666
667 #define _OUT(_field) offsetof(struct pf_krule, _field)
668 static const struct nlattr_parser nla_p_rule[] = {
669 { .type = PF_RT_SRC, .off = _OUT(src), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
670 { .type = PF_RT_DST, .off = _OUT(dst), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
671 { .type = PF_RT_RIDENTIFIER, .off = _OUT(ridentifier), .cb = nlattr_get_uint32 },
672 { .type = PF_RT_LABELS, .off = _OUT(label), .arg = &rule_labels_parser,.cb = nlattr_get_nested_pf_rule_labels },
673 { .type = PF_RT_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
674 { .type = PF_RT_QNAME, .off = _OUT(qname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
675 { .type = PF_RT_PQNAME, .off = _OUT(pqname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
676 { .type = PF_RT_TAGNAME, .off = _OUT(tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
677 { .type = PF_RT_MATCH_TAGNAME, .off = _OUT(match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
678 { .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
679 { .type = PF_RT_RPOOL, .off = _OUT(rpool), .arg = &pool_parser, .cb = nlattr_get_nested },
680 { .type = PF_RT_OS_FINGERPRINT, .off = _OUT(os_fingerprint), .cb = nlattr_get_uint32 },
681 { .type = PF_RT_RTABLEID, .off = _OUT(rtableid), .cb = nlattr_get_uint32 },
682 { .type = PF_RT_TIMEOUT, .off = _OUT(timeout), .arg = &timeout_parser, .cb = nlattr_get_nested_timeouts },
683 { .type = PF_RT_MAX_STATES, .off = _OUT(max_states), .cb = nlattr_get_uint32 },
684 { .type = PF_RT_MAX_SRC_NODES, .off = _OUT(max_src_nodes), .cb = nlattr_get_uint32 },
685 { .type = PF_RT_MAX_SRC_STATES, .off = _OUT(max_src_states), .cb = nlattr_get_uint32 },
686 { .type = PF_RT_MAX_SRC_CONN_RATE_LIMIT, .off = _OUT(max_src_conn_rate.limit), .cb = nlattr_get_uint32 },
687 { .type = PF_RT_MAX_SRC_CONN_RATE_SECS, .off = _OUT(max_src_conn_rate.seconds), .cb = nlattr_get_uint32 },
688 { .type = PF_RT_DNPIPE, .off = _OUT(dnpipe), .cb = nlattr_get_uint16 },
689 { .type = PF_RT_DNRPIPE, .off = _OUT(dnrpipe), .cb = nlattr_get_uint16 },
690 { .type = PF_RT_DNFLAGS, .off = _OUT(free_flags), .cb = nlattr_get_uint32 },
691 { .type = PF_RT_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
692 { .type = PF_RT_PROB, .off = _OUT(prob), .cb = nlattr_get_uint32 },
693 { .type = PF_RT_CUID, .off = _OUT(cuid), .cb = nlattr_get_uint32 },
694 {. type = PF_RT_CPID, .off = _OUT(cpid), .cb = nlattr_get_uint32 },
695 { .type = PF_RT_RETURN_ICMP, .off = _OUT(return_icmp), .cb = nlattr_get_uint16 },
696 { .type = PF_RT_RETURN_ICMP6, .off = _OUT(return_icmp6), .cb = nlattr_get_uint16 },
697 { .type = PF_RT_MAX_MSS, .off = _OUT(max_mss), .cb = nlattr_get_uint16 },
698 { .type = PF_RT_SCRUB_FLAGS, .off = _OUT(scrub_flags), .cb = nlattr_get_uint16 },
699 { .type = PF_RT_UID, .off = _OUT(uid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
700 { .type = PF_RT_GID, .off = _OUT(gid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
701 { .type = PF_RT_RULE_FLAG, .off = _OUT(rule_flag), .cb = nlattr_get_uint32 },
702 { .type = PF_RT_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
703 { .type = PF_RT_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
704 { .type = PF_RT_LOG, .off = _OUT(log), .cb = nlattr_get_uint8 },
705 { .type = PF_RT_LOGIF, .off = _OUT(logif), .cb = nlattr_get_uint8 },
706 { .type = PF_RT_QUICK, .off = _OUT(quick), .cb = nlattr_get_uint8 },
707 { .type = PF_RT_IF_NOT, .off = _OUT(ifnot), .cb = nlattr_get_uint8 },
708 { .type = PF_RT_MATCH_TAG_NOT, .off = _OUT(match_tag_not), .cb = nlattr_get_uint8 },
709 { .type = PF_RT_NATPASS, .off = _OUT(natpass), .cb = nlattr_get_uint8 },
710 { .type = PF_RT_KEEP_STATE, .off = _OUT(keep_state), .cb = nlattr_get_uint8 },
711 { .type = PF_RT_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
712 { .type = PF_RT_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
713 { .type = PF_RT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
714 { .type = PF_RT_CODE, .off = _OUT(code), .cb = nlattr_get_uint8 },
715 { .type = PF_RT_FLAGS, .off = _OUT(flags), .cb = nlattr_get_uint8 },
716 { .type = PF_RT_FLAGSET, .off = _OUT(flagset), .cb = nlattr_get_uint8 },
717 { .type = PF_RT_MIN_TTL, .off = _OUT(min_ttl), .cb = nlattr_get_uint8 },
718 { .type = PF_RT_ALLOW_OPTS, .off = _OUT(allow_opts), .cb = nlattr_get_uint8 },
719 { .type = PF_RT_RT, .off = _OUT(rt), .cb = nlattr_get_uint8 },
720 { .type = PF_RT_RETURN_TTL, .off = _OUT(return_ttl), .cb = nlattr_get_uint8 },
721 { .type = PF_RT_TOS, .off = _OUT(tos), .cb = nlattr_get_uint8 },
722 { .type = PF_RT_SET_TOS, .off = _OUT(set_tos), .cb = nlattr_get_uint8 },
723 { .type = PF_RT_ANCHOR_RELATIVE, .off = _OUT(anchor_relative), .cb = nlattr_get_uint8 },
724 { .type = PF_RT_ANCHOR_WILDCARD, .off = _OUT(anchor_wildcard), .cb = nlattr_get_uint8 },
725 { .type = PF_RT_FLUSH, .off = _OUT(flush), .cb = nlattr_get_uint8 },
726 { .type = PF_RT_PRIO, .off = _OUT(prio), .cb = nlattr_get_uint8 },
727 { .type = PF_RT_SET_PRIO, .off = _OUT(set_prio[0]), .cb = nlattr_get_uint8 },
728 { .type = PF_RT_SET_PRIO_REPLY, .off = _OUT(set_prio[1]), .cb = nlattr_get_uint8 },
729 { .type = PF_RT_DIVERT_ADDRESS, .off = _OUT(divert.addr), .cb = nlattr_get_in6_addr },
730 { .type = PF_RT_DIVERT_PORT, .off = _OUT(divert.port), .cb = nlattr_get_uint16 },
731 };
732 NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule);
733 #undef _OUT
734 struct nl_parsed_addrule {
735 struct pf_krule *rule;
736 uint32_t ticket;
737 uint32_t pool_ticket;
738 char *anchor;
739 char *anchor_call;
740 };
741 #define _IN(_field) offsetof(struct genlmsghdr, _field)
742 #define _OUT(_field) offsetof(struct nl_parsed_addrule, _field)
743 static const struct nlattr_parser nla_p_addrule[] = {
744 { .type = PF_ART_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
745 { .type = PF_ART_POOL_TICKET, .off = _OUT(pool_ticket), .cb = nlattr_get_uint32 },
746 { .type = PF_ART_ANCHOR, .off = _OUT(anchor), .cb = nlattr_get_string },
747 { .type = PF_ART_ANCHOR_CALL, .off = _OUT(anchor_call), .cb = nlattr_get_string },
748 { .type = PF_ART_RULE, .off = _OUT(rule), .arg = &rule_parser, .cb = nlattr_get_nested_ptr }
749 };
750 static const struct nlfield_parser nlf_p_addrule[] = {
751 };
752 #undef _IN
753 #undef _OUT
754 NL_DECLARE_PARSER(addrule_parser, struct genlmsghdr, nlf_p_addrule, nla_p_addrule);
755
756 static int
pf_handle_addrule(struct nlmsghdr * hdr,struct nl_pstate * npt)757 pf_handle_addrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
758 {
759 int error;
760 struct nl_parsed_addrule attrs = {};
761
762 attrs.rule = pf_krule_alloc();
763
764 error = nl_parse_nlmsg(hdr, &addrule_parser, npt, &attrs);
765 if (error != 0) {
766 pf_free_rule(attrs.rule);
767 return (error);
768 }
769
770 error = pf_ioctl_addrule(attrs.rule, attrs.ticket, attrs.pool_ticket,
771 attrs.anchor, attrs.anchor_call, nlp_get_cred(npt->nlp)->cr_uid,
772 hdr->nlmsg_pid);
773
774 return (error);
775 }
776
777 #define _IN(_field) offsetof(struct genlmsghdr, _field)
778 #define _OUT(_field) offsetof(struct pfioc_rule, _field)
779 static const struct nlattr_parser nla_p_getrules[] = {
780 { .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
781 { .type = PF_GR_ACTION, .off = _OUT(rule.action), .cb = nlattr_get_uint8 },
782 };
783 static const struct nlfield_parser nlf_p_getrules[] = {
784 };
785 #undef _IN
786 #undef _OUT
787 NL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, nlf_p_getrules, nla_p_getrules);
788
789 static int
pf_handle_getrules(struct nlmsghdr * hdr,struct nl_pstate * npt)790 pf_handle_getrules(struct nlmsghdr *hdr, struct nl_pstate *npt)
791 {
792 struct pfioc_rule attrs = {};
793 int error;
794 struct nl_writer *nw = npt->nw;
795 struct genlmsghdr *ghdr_new;
796
797 error = nl_parse_nlmsg(hdr, &getrules_parser, npt, &attrs);
798 if (error != 0)
799 return (error);
800
801 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
802 return (ENOMEM);
803
804 ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
805 ghdr_new->cmd = PFNL_CMD_GETRULES;
806 ghdr_new->version = 0;
807 ghdr_new->reserved = 0;
808
809 error = pf_ioctl_getrules(&attrs);
810 if (error != 0)
811 goto out;
812
813 nlattr_add_u32(nw, PF_GR_NR, attrs.nr);
814 nlattr_add_u32(nw, PF_GR_TICKET, attrs.ticket);
815
816 if (!nlmsg_end(nw)) {
817 error = ENOMEM;
818 goto out;
819 }
820
821 return (0);
822
823 out:
824 nlmsg_abort(nw);
825 return (error);
826 }
827
828 struct nl_parsed_get_rule {
829 char anchor[MAXPATHLEN];
830 uint8_t action;
831 uint32_t nr;
832 uint32_t ticket;
833 uint8_t clear;
834 };
835 #define _IN(_field) offsetof(struct genlmsghdr, _field)
836 #define _OUT(_field) offsetof(struct nl_parsed_get_rule, _field)
837 static const struct nlattr_parser nla_p_getrule[] = {
838 { .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
839 { .type = PF_GR_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
840 { .type = PF_GR_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
841 { .type = PF_GR_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
842 { .type = PF_GR_CLEAR, .off = _OUT(clear), .cb = nlattr_get_uint8 },
843 };
844 static const struct nlfield_parser nlf_p_getrule[] = {
845 };
846 #undef _IN
847 #undef _OUT
848 NL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, nlf_p_getrule, nla_p_getrule);
849
850 static int
pf_handle_getrule(struct nlmsghdr * hdr,struct nl_pstate * npt)851 pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
852 {
853 char anchor_call[MAXPATHLEN];
854 struct nl_parsed_get_rule attrs = {};
855 struct nl_writer *nw = npt->nw;
856 struct genlmsghdr *ghdr_new;
857 struct pf_kruleset *ruleset;
858 struct pf_krule *rule;
859 int rs_num;
860 int error;
861
862 error = nl_parse_nlmsg(hdr, &getrule_parser, npt, &attrs);
863 if (error != 0)
864 return (error);
865
866 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
867 return (ENOMEM);
868
869 ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
870 ghdr_new->cmd = PFNL_CMD_GETRULE;
871 ghdr_new->version = 0;
872 ghdr_new->reserved = 0;
873
874 PF_RULES_WLOCK();
875 ruleset = pf_find_kruleset(attrs.anchor);
876 if (ruleset == NULL) {
877 PF_RULES_WUNLOCK();
878 error = ENOENT;
879 goto out;
880 }
881
882 rs_num = pf_get_ruleset_number(attrs.action);
883 if (rs_num >= PF_RULESET_MAX) {
884 PF_RULES_WUNLOCK();
885 error = EINVAL;
886 goto out;
887 }
888
889 if (attrs.ticket != ruleset->rules[rs_num].active.ticket) {
890 PF_RULES_WUNLOCK();
891 error = EBUSY;
892 goto out;
893 }
894
895 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
896 while ((rule != NULL) && (rule->nr != attrs.nr))
897 rule = TAILQ_NEXT(rule, entries);
898 if (rule == NULL) {
899 PF_RULES_WUNLOCK();
900 error = EBUSY;
901 goto out;
902 }
903
904 nlattr_add_rule_addr(nw, PF_RT_SRC, &rule->src);
905 nlattr_add_rule_addr(nw, PF_RT_DST, &rule->dst);
906 nlattr_add_u32(nw, PF_RT_RIDENTIFIER, rule->ridentifier);
907 nlattr_add_labels(nw, PF_RT_LABELS, rule);
908 nlattr_add_string(nw, PF_RT_IFNAME, rule->ifname);
909 nlattr_add_string(nw, PF_RT_QNAME, rule->qname);
910 nlattr_add_string(nw, PF_RT_PQNAME, rule->pqname);
911 nlattr_add_string(nw, PF_RT_TAGNAME, rule->tagname);
912 nlattr_add_string(nw, PF_RT_MATCH_TAGNAME, rule->match_tagname);
913 nlattr_add_string(nw, PF_RT_OVERLOAD_TBLNAME, rule->overload_tblname);
914 nlattr_add_pool(nw, PF_RT_RPOOL, &rule->rpool);
915 nlattr_add_u32(nw, PF_RT_OS_FINGERPRINT, rule->os_fingerprint);
916 nlattr_add_u32(nw, PF_RT_RTABLEID, rule->rtableid);
917 nlattr_add_timeout(nw, PF_RT_TIMEOUT, rule->timeout);
918 nlattr_add_u32(nw, PF_RT_MAX_STATES, rule->max_states);
919 nlattr_add_u32(nw, PF_RT_MAX_SRC_NODES, rule->max_src_nodes);
920 nlattr_add_u32(nw, PF_RT_MAX_SRC_STATES, rule->max_src_states);
921 nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_LIMIT, rule->max_src_conn_rate.limit);
922 nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_SECS, rule->max_src_conn_rate.seconds);
923
924 nlattr_add_u16(nw, PF_RT_DNPIPE, rule->dnpipe);
925 nlattr_add_u16(nw, PF_RT_DNRPIPE, rule->dnrpipe);
926 nlattr_add_u32(nw, PF_RT_DNFLAGS, rule->free_flags);
927
928 nlattr_add_u32(nw, PF_RT_NR, rule->nr);
929 nlattr_add_u32(nw, PF_RT_PROB, rule->prob);
930 nlattr_add_u32(nw, PF_RT_CUID, rule->cuid);
931 nlattr_add_u32(nw, PF_RT_CPID, rule->cpid);
932
933 nlattr_add_u16(nw, PF_RT_RETURN_ICMP, rule->return_icmp);
934 nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
935 nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
936 nlattr_add_u16(nw, PF_RT_MAX_MSS, rule->max_mss);
937 nlattr_add_u16(nw, PF_RT_SCRUB_FLAGS, rule->scrub_flags);
938
939 nlattr_add_rule_uid(nw, PF_RT_UID, &rule->uid);
940 nlattr_add_rule_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&rule->gid);
941
942 nlattr_add_u32(nw, PF_RT_RULE_FLAG, rule->rule_flag);
943 nlattr_add_u8(nw, PF_RT_ACTION, rule->action);
944 nlattr_add_u8(nw, PF_RT_DIRECTION, rule->direction);
945 nlattr_add_u8(nw, PF_RT_LOG, rule->log);
946 nlattr_add_u8(nw, PF_RT_LOGIF, rule->logif);
947 nlattr_add_u8(nw, PF_RT_QUICK, rule->quick);
948 nlattr_add_u8(nw, PF_RT_IF_NOT, rule->ifnot);
949 nlattr_add_u8(nw, PF_RT_MATCH_TAG_NOT, rule->match_tag_not);
950 nlattr_add_u8(nw, PF_RT_NATPASS, rule->natpass);
951 nlattr_add_u8(nw, PF_RT_KEEP_STATE, rule->keep_state);
952
953 nlattr_add_u8(nw, PF_RT_AF, rule->af);
954 nlattr_add_u8(nw, PF_RT_PROTO, rule->proto);
955 nlattr_add_u8(nw, PF_RT_TYPE, rule->type);
956 nlattr_add_u8(nw, PF_RT_CODE, rule->code);
957 nlattr_add_u8(nw, PF_RT_FLAGS, rule->flags);
958 nlattr_add_u8(nw, PF_RT_FLAGSET, rule->flagset);
959 nlattr_add_u8(nw, PF_RT_MIN_TTL, rule->min_ttl);
960 nlattr_add_u8(nw, PF_RT_ALLOW_OPTS, rule->allow_opts);
961 nlattr_add_u8(nw, PF_RT_RT, rule->rt);
962 nlattr_add_u8(nw, PF_RT_RETURN_TTL, rule->return_ttl);
963 nlattr_add_u8(nw, PF_RT_TOS, rule->tos);
964 nlattr_add_u8(nw, PF_RT_SET_TOS, rule->set_tos);
965 nlattr_add_u8(nw, PF_RT_ANCHOR_RELATIVE, rule->anchor_relative);
966 nlattr_add_u8(nw, PF_RT_ANCHOR_WILDCARD, rule->anchor_wildcard);
967 nlattr_add_u8(nw, PF_RT_FLUSH, rule->flush);
968 nlattr_add_u8(nw, PF_RT_PRIO, rule->prio);
969 nlattr_add_u8(nw, PF_RT_SET_PRIO, rule->set_prio[0]);
970 nlattr_add_u8(nw, PF_RT_SET_PRIO_REPLY, rule->set_prio[1]);
971
972 nlattr_add_in6_addr(nw, PF_RT_DIVERT_ADDRESS, &rule->divert.addr.v6);
973 nlattr_add_u16(nw, PF_RT_DIVERT_PORT, rule->divert.port);
974
975 nlattr_add_u64(nw, PF_RT_PACKETS_IN, pf_counter_u64_fetch(&rule->packets[0]));
976 nlattr_add_u64(nw, PF_RT_PACKETS_OUT, pf_counter_u64_fetch(&rule->packets[1]));
977 nlattr_add_u64(nw, PF_RT_BYTES_IN, pf_counter_u64_fetch(&rule->bytes[0]));
978 nlattr_add_u64(nw, PF_RT_BYTES_OUT, pf_counter_u64_fetch(&rule->bytes[1]));
979 nlattr_add_u64(nw, PF_RT_EVALUATIONS, pf_counter_u64_fetch(&rule->evaluations));
980 nlattr_add_u64(nw, PF_RT_TIMESTAMP, pf_get_timestamp(rule));
981 nlattr_add_u64(nw, PF_RT_STATES_CUR, counter_u64_fetch(rule->states_cur));
982 nlattr_add_u64(nw, PF_RT_STATES_TOTAL, counter_u64_fetch(rule->states_tot));
983 nlattr_add_u64(nw, PF_RT_SRC_NODES, counter_u64_fetch(rule->src_nodes));
984
985 error = pf_kanchor_copyout(ruleset, rule, anchor_call);
986 MPASS(error == 0);
987
988 nlattr_add_string(nw, PF_RT_ANCHOR_CALL, anchor_call);
989
990 if (attrs.clear)
991 pf_krule_clear_counters(rule);
992
993 PF_RULES_WUNLOCK();
994
995 if (!nlmsg_end(nw)) {
996 error = ENOMEM;
997 goto out;
998 }
999
1000 return (0);
1001 out:
1002 nlmsg_abort(nw);
1003 return (error);
1004 }
1005
1006 #define _IN(_field) offsetof(struct genlmsghdr, _field)
1007 #define _OUT(_field) offsetof(struct pf_kstate_kill, _field)
1008 static const struct nlattr_parser nla_p_clear_states[] = {
1009 { .type = PF_CS_CMP_ID, .off = _OUT(psk_pfcmp.id), .cb = nlattr_get_uint64 },
1010 { .type = PF_CS_CMP_CREATORID, .off = _OUT(psk_pfcmp.creatorid), .cb = nlattr_get_uint32 },
1011 { .type = PF_CS_CMP_DIR, .off = _OUT(psk_pfcmp.direction), .cb = nlattr_get_uint8 },
1012 { .type = PF_CS_AF, .off = _OUT(psk_af), .cb = nlattr_get_uint8 },
1013 { .type = PF_CS_PROTO, .off = _OUT(psk_proto), .cb = nlattr_get_uint8 },
1014 { .type = PF_CS_SRC, .off = _OUT(psk_src), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1015 { .type = PF_CS_DST, .off = _OUT(psk_dst), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1016 { .type = PF_CS_RT_ADDR, .off = _OUT(psk_rt_addr), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1017 { .type = PF_CS_IFNAME, .off = _OUT(psk_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
1018 { .type = PF_CS_LABEL, .off = _OUT(psk_label), .arg = (void *)PF_RULE_LABEL_SIZE, .cb = nlattr_get_chara },
1019 { .type = PF_CS_KILL_MATCH, .off = _OUT(psk_kill_match), .cb = nlattr_get_bool },
1020 { .type = PF_CS_NAT, .off = _OUT(psk_nat), .cb = nlattr_get_bool },
1021 };
1022 static const struct nlfield_parser nlf_p_clear_states[] = {};
1023 #undef _IN
1024 #undef _OUT
1025 NL_DECLARE_PARSER(clear_states_parser, struct genlmsghdr, nlf_p_clear_states, nla_p_clear_states);
1026
1027 static int
pf_handle_killclear_states(struct nlmsghdr * hdr,struct nl_pstate * npt,int cmd)1028 pf_handle_killclear_states(struct nlmsghdr *hdr, struct nl_pstate *npt, int cmd)
1029 {
1030 struct pf_kstate_kill kill = {};
1031 struct epoch_tracker et;
1032 struct nl_writer *nw = npt->nw;
1033 struct genlmsghdr *ghdr_new;
1034 int error;
1035 unsigned int killed = 0;
1036
1037 error = nl_parse_nlmsg(hdr, &clear_states_parser, npt, &kill);
1038 if (error != 0)
1039 return (error);
1040
1041 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1042 return (ENOMEM);
1043
1044 ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1045 ghdr_new->cmd = cmd;
1046 ghdr_new->version = 0;
1047 ghdr_new->reserved = 0;
1048
1049 NET_EPOCH_ENTER(et);
1050 if (cmd == PFNL_CMD_KILLSTATES)
1051 pf_killstates(&kill, &killed);
1052 else
1053 killed = pf_clear_states(&kill);
1054 NET_EPOCH_EXIT(et);
1055
1056 nlattr_add_u32(nw, PF_CS_KILLED, killed);
1057
1058 if (! nlmsg_end(nw)) {
1059 error = ENOMEM;
1060 goto out;
1061 }
1062
1063 return (0);
1064
1065 out:
1066 nlmsg_abort(nw);
1067 return (error);
1068 }
1069
1070 static int
pf_handle_clear_states(struct nlmsghdr * hdr,struct nl_pstate * npt)1071 pf_handle_clear_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
1072 {
1073 return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_CLRSTATES));
1074 }
1075
1076 static int
pf_handle_kill_states(struct nlmsghdr * hdr,struct nl_pstate * npt)1077 pf_handle_kill_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
1078 {
1079 return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_KILLSTATES));
1080 }
1081
1082 struct nl_parsed_set_statusif {
1083 char ifname[IFNAMSIZ];
1084 };
1085 #define _IN(_field) offsetof(struct genlmsghdr, _field)
1086 #define _OUT(_field) offsetof(struct nl_parsed_set_statusif, _field)
1087 static const struct nlattr_parser nla_p_set_statusif[] = {
1088 { .type = PF_SS_IFNAME, .off = _OUT(ifname), .arg = (const void *)IFNAMSIZ, .cb = nlattr_get_chara },
1089 };
1090 static const struct nlfield_parser nlf_p_set_statusif[] = {};
1091 #undef _IN
1092 #undef _OUT
1093 NL_DECLARE_PARSER(set_statusif_parser, struct genlmsghdr, nlf_p_set_statusif, nla_p_set_statusif);
1094
1095 static int
pf_handle_set_statusif(struct nlmsghdr * hdr,struct nl_pstate * npt)1096 pf_handle_set_statusif(struct nlmsghdr *hdr, struct nl_pstate *npt)
1097 {
1098 int error;
1099 struct nl_parsed_set_statusif attrs = {};
1100
1101 error = nl_parse_nlmsg(hdr, &set_statusif_parser, npt, &attrs);
1102 if (error != 0)
1103 return (error);
1104
1105 PF_RULES_WLOCK();
1106 strlcpy(V_pf_status.ifname, attrs.ifname, IFNAMSIZ);
1107 PF_RULES_WUNLOCK();
1108
1109 return (0);
1110 }
1111
1112 static bool
nlattr_add_counters(struct nl_writer * nw,int attr,size_t number,char ** names,counter_u64_t * counters)1113 nlattr_add_counters(struct nl_writer *nw, int attr, size_t number, char **names,
1114 counter_u64_t *counters)
1115 {
1116 for (int i = 0; i < number; i++) {
1117 int off = nlattr_add_nested(nw, attr);
1118 nlattr_add_u32(nw, PF_C_ID, i);
1119 nlattr_add_string(nw, PF_C_NAME, names[i]);
1120 nlattr_add_u64(nw, PF_C_COUNTER, counter_u64_fetch(counters[i]));
1121 nlattr_set_len(nw, off);
1122 }
1123
1124 return (true);
1125 }
1126
1127 static bool
nlattr_add_fcounters(struct nl_writer * nw,int attr,size_t number,char ** names,struct pf_counter_u64 * counters)1128 nlattr_add_fcounters(struct nl_writer *nw, int attr, size_t number, char **names,
1129 struct pf_counter_u64 *counters)
1130 {
1131 for (int i = 0; i < number; i++) {
1132 int off = nlattr_add_nested(nw, attr);
1133 nlattr_add_u32(nw, PF_C_ID, i);
1134 nlattr_add_string(nw, PF_C_NAME, names[i]);
1135 nlattr_add_u64(nw, PF_C_COUNTER, pf_counter_u64_fetch(&counters[i]));
1136 nlattr_set_len(nw, off);
1137 }
1138
1139 return (true);
1140 }
1141
1142 static bool
nlattr_add_u64_array(struct nl_writer * nw,int attr,size_t number,uint64_t * array)1143 nlattr_add_u64_array(struct nl_writer *nw, int attr, size_t number, uint64_t *array)
1144 {
1145 int off = nlattr_add_nested(nw, attr);
1146
1147 for (size_t i = 0; i < number; i++)
1148 nlattr_add_u64(nw, 0, array[i]);
1149
1150 nlattr_set_len(nw, off);
1151
1152 return (true);
1153 }
1154
1155 static int
pf_handle_get_status(struct nlmsghdr * hdr,struct nl_pstate * npt)1156 pf_handle_get_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
1157 {
1158 struct pf_status s;
1159 struct nl_writer *nw = npt->nw;
1160 struct genlmsghdr *ghdr_new;
1161 char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
1162 char *pf_lcounter[KLCNT_MAX+1] = KLCNT_NAMES;
1163 char *pf_fcounter[FCNT_MAX+1] = FCNT_NAMES;
1164 int error;
1165
1166 PF_RULES_RLOCK_TRACKER;
1167
1168 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1169 return (ENOMEM);
1170
1171 ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1172 ghdr_new->cmd = PFNL_CMD_GET_STATUS;
1173 ghdr_new->version = 0;
1174 ghdr_new->reserved = 0;
1175
1176 PF_RULES_RLOCK();
1177
1178 nlattr_add_string(nw, PF_GS_IFNAME, V_pf_status.ifname);
1179 nlattr_add_bool(nw, PF_GS_RUNNING, V_pf_status.running);
1180 nlattr_add_u32(nw, PF_GS_SINCE, V_pf_status.since);
1181 nlattr_add_u32(nw, PF_GS_DEBUG, V_pf_status.debug);
1182 nlattr_add_u32(nw, PF_GS_HOSTID, ntohl(V_pf_status.hostid));
1183 nlattr_add_u32(nw, PF_GS_STATES, V_pf_status.states);
1184 nlattr_add_u32(nw, PF_GS_SRC_NODES, V_pf_status.src_nodes);
1185 nlattr_add_u32(nw, PF_GS_REASSEMBLE, V_pf_status.reass);
1186 nlattr_add_u32(nw, PF_GS_SYNCOOKIES_ACTIVE, V_pf_status.syncookies_active);
1187
1188 nlattr_add_counters(nw, PF_GS_COUNTERS, PFRES_MAX, pf_reasons,
1189 V_pf_status.counters);
1190 nlattr_add_counters(nw, PF_GS_LCOUNTERS, KLCNT_MAX, pf_lcounter,
1191 V_pf_status.lcounters);
1192 nlattr_add_fcounters(nw, PF_GS_FCOUNTERS, FCNT_MAX, pf_fcounter,
1193 V_pf_status.fcounters);
1194 nlattr_add_counters(nw, PF_GS_SCOUNTERS, SCNT_MAX, pf_fcounter,
1195 V_pf_status.scounters);
1196
1197 pfi_update_status(V_pf_status.ifname, &s);
1198 nlattr_add_u64_array(nw, PF_GS_BCOUNTERS, 2 * 2, (uint64_t *)s.bcounters);
1199 nlattr_add_u64_array(nw, PF_GS_PCOUNTERS, 2 * 2 * 2, (uint64_t *)s.pcounters);
1200
1201 nlattr_add(nw, PF_GS_CHKSUM, PF_MD5_DIGEST_LENGTH, V_pf_status.pf_chksum);
1202
1203 PF_RULES_RUNLOCK();
1204
1205 if (!nlmsg_end(nw)) {
1206 error = ENOMEM;
1207 goto out;
1208 }
1209
1210 return (0);
1211
1212 out:
1213 nlmsg_abort(nw);
1214 return (error);
1215 }
1216
1217 static const struct nlhdr_parser *all_parsers[] = {
1218 &state_parser,
1219 &addrule_parser,
1220 &getrules_parser,
1221 &clear_states_parser,
1222 &set_statusif_parser,
1223 };
1224
1225 static int family_id;
1226
1227 static const struct genl_cmd pf_cmds[] = {
1228 {
1229 .cmd_num = PFNL_CMD_GETSTATES,
1230 .cmd_name = "GETSTATES",
1231 .cmd_cb = pf_handle_getstates,
1232 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1233 .cmd_priv = PRIV_NETINET_PF,
1234 },
1235 {
1236 .cmd_num = PFNL_CMD_GETCREATORS,
1237 .cmd_name = "GETCREATORS",
1238 .cmd_cb = pf_handle_getcreators,
1239 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1240 .cmd_priv = PRIV_NETINET_PF,
1241 },
1242 {
1243 .cmd_num = PFNL_CMD_START,
1244 .cmd_name = "START",
1245 .cmd_cb = pf_handle_start,
1246 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1247 .cmd_priv = PRIV_NETINET_PF,
1248 },
1249 {
1250 .cmd_num = PFNL_CMD_STOP,
1251 .cmd_name = "STOP",
1252 .cmd_cb = pf_handle_stop,
1253 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1254 .cmd_priv = PRIV_NETINET_PF,
1255 },
1256 {
1257 .cmd_num = PFNL_CMD_ADDRULE,
1258 .cmd_name = "ADDRULE",
1259 .cmd_cb = pf_handle_addrule,
1260 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1261 .cmd_priv = PRIV_NETINET_PF,
1262 },
1263 {
1264 .cmd_num = PFNL_CMD_GETRULES,
1265 .cmd_name = "GETRULES",
1266 .cmd_cb = pf_handle_getrules,
1267 .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1268 .cmd_priv = PRIV_NETINET_PF,
1269 },
1270 {
1271 .cmd_num = PFNL_CMD_GETRULE,
1272 .cmd_name = "GETRULE",
1273 .cmd_cb = pf_handle_getrule,
1274 .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1275 .cmd_priv = PRIV_NETINET_PF,
1276 },
1277 {
1278 .cmd_num = PFNL_CMD_CLRSTATES,
1279 .cmd_name = "CLRSTATES",
1280 .cmd_cb = pf_handle_clear_states,
1281 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1282 .cmd_priv = PRIV_NETINET_PF,
1283 },
1284 {
1285 .cmd_num = PFNL_CMD_KILLSTATES,
1286 .cmd_name = "KILLSTATES",
1287 .cmd_cb = pf_handle_kill_states,
1288 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1289 .cmd_priv = PRIV_NETINET_PF,
1290 },
1291 {
1292 .cmd_num = PFNL_CMD_SET_STATUSIF,
1293 .cmd_name = "SETSTATUSIF",
1294 .cmd_cb = pf_handle_set_statusif,
1295 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1296 .cmd_priv = PRIV_NETINET_PF,
1297 },
1298 {
1299 .cmd_num = PFNL_CMD_GET_STATUS,
1300 .cmd_name = "GETSTATUS",
1301 .cmd_cb = pf_handle_get_status,
1302 .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1303 .cmd_priv = PRIV_NETINET_PF,
1304 },
1305 };
1306
1307 void
pf_nl_register(void)1308 pf_nl_register(void)
1309 {
1310 NL_VERIFY_PARSERS(all_parsers);
1311
1312 family_id = genl_register_family(PFNL_FAMILY_NAME, 0, 2, PFNL_CMD_MAX);
1313 genl_register_cmds(PFNL_FAMILY_NAME, pf_cmds, NL_ARRAY_LEN(pf_cmds));
1314 }
1315
1316 void
pf_nl_unregister(void)1317 pf_nl_unregister(void)
1318 {
1319 genl_unregister_family(PFNL_FAMILY_NAME);
1320 }
1321