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