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