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