xref: /freebsd/sys/netpfil/pf/pf_nl.c (revision 44f323ecdec02dc947c34d08c34b881fe2da1ba6)
12cef6288SAlexander V. Chernikov /*-
22cef6288SAlexander V. Chernikov  * SPDX-License-Identifier: BSD-2-Clause
32cef6288SAlexander V. Chernikov  *
42cef6288SAlexander V. Chernikov  * Copyright (c) 2023 Alexander V. Chernikov <melifaro@FreeBSD.org>
52cef6288SAlexander V. Chernikov  * Copyright (c) 2023 Rubicon Communications, LLC (Netgate)
62cef6288SAlexander V. Chernikov  *
72cef6288SAlexander V. Chernikov  * Redistribution and use in source and binary forms, with or without
82cef6288SAlexander V. Chernikov  * modification, are permitted provided that the following conditions
92cef6288SAlexander V. Chernikov  * are met:
102cef6288SAlexander V. Chernikov  * 1. Redistributions of source code must retain the above copyright
112cef6288SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer.
122cef6288SAlexander V. Chernikov  * 2. Redistributions in binary form must reproduce the above copyright
132cef6288SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer in the
142cef6288SAlexander V. Chernikov  *    documentation and/or other materials provided with the distribution.
152cef6288SAlexander V. Chernikov  *
162cef6288SAlexander V. Chernikov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172cef6288SAlexander V. Chernikov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182cef6288SAlexander V. Chernikov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192cef6288SAlexander V. Chernikov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202cef6288SAlexander V. Chernikov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212cef6288SAlexander V. Chernikov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222cef6288SAlexander V. Chernikov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232cef6288SAlexander V. Chernikov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242cef6288SAlexander V. Chernikov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252cef6288SAlexander V. Chernikov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262cef6288SAlexander V. Chernikov  * SUCH DAMAGE.
272cef6288SAlexander V. Chernikov  *
282cef6288SAlexander V. Chernikov  */
292cef6288SAlexander V. Chernikov 
302cef6288SAlexander V. Chernikov #include <sys/param.h>
312cef6288SAlexander V. Chernikov #include <sys/malloc.h>
322cef6288SAlexander V. Chernikov #include <sys/mbuf.h>
332cef6288SAlexander V. Chernikov #include <sys/socket.h>
347b2ab18fSKonstantin Belousov #include <sys/ucred.h>
352cef6288SAlexander V. Chernikov 
362cef6288SAlexander V. Chernikov #include <net/pfvar.h>
372cef6288SAlexander V. Chernikov 
382cef6288SAlexander V. Chernikov #include <netlink/netlink.h>
392cef6288SAlexander V. Chernikov #include <netlink/netlink_ctl.h>
402cef6288SAlexander V. Chernikov #include <netlink/netlink_generic.h>
412cef6288SAlexander V. Chernikov #include <netlink/netlink_message_writer.h>
422cef6288SAlexander V. Chernikov 
432cef6288SAlexander V. Chernikov #include <netpfil/pf/pf_nl.h>
442cef6288SAlexander V. Chernikov 
452cef6288SAlexander V. Chernikov #define	DEBUG_MOD_NAME	nl_pf
462cef6288SAlexander V. Chernikov #define	DEBUG_MAX_LEVEL	LOG_DEBUG3
472cef6288SAlexander V. Chernikov #include <netlink/netlink_debug.h>
482cef6288SAlexander V. Chernikov _DECLARE_DEBUG(LOG_DEBUG);
492cef6288SAlexander V. Chernikov 
502cef6288SAlexander V. Chernikov struct nl_parsed_state {
512cef6288SAlexander V. Chernikov 	uint8_t		version;
522cef6288SAlexander V. Chernikov 	uint32_t	id;
532cef6288SAlexander V. Chernikov 	uint32_t	creatorid;
54044eef6aSKristof Provost 	char		ifname[IFNAMSIZ];
55044eef6aSKristof Provost 	uint16_t	proto;
56044eef6aSKristof Provost 	sa_family_t	af;
57044eef6aSKristof Provost 	struct pf_addr	addr;
58044eef6aSKristof Provost 	struct pf_addr	mask;
592cef6288SAlexander V. Chernikov };
602cef6288SAlexander V. Chernikov 
612cef6288SAlexander V. Chernikov #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
622cef6288SAlexander V. Chernikov #define	_OUT(_field)	offsetof(struct nl_parsed_state, _field)
632cef6288SAlexander V. Chernikov static const struct nlattr_parser nla_p_state[] = {
642cef6288SAlexander V. Chernikov 	{ .type = PF_ST_ID, .off = _OUT(id), .cb = nlattr_get_uint32 },
652cef6288SAlexander V. Chernikov 	{ .type = PF_ST_CREATORID, .off = _OUT(creatorid), .cb = nlattr_get_uint32 },
66044eef6aSKristof Provost 	{ .type = PF_ST_IFNAME, .arg = (const void *)IFNAMSIZ, .off = _OUT(ifname), .cb = nlattr_get_chara },
67044eef6aSKristof Provost 	{ .type = PF_ST_AF, .off = _OUT(proto), .cb = nlattr_get_uint8 },
68044eef6aSKristof Provost 	{ .type = PF_ST_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint16 },
69044eef6aSKristof Provost 	{ .type = PF_ST_FILTER_ADDR, .off = _OUT(addr), .cb = nlattr_get_in6_addr },
70044eef6aSKristof Provost 	{ .type = PF_ST_FILTER_MASK, .off = _OUT(mask), .cb = nlattr_get_in6_addr },
712cef6288SAlexander V. Chernikov };
722cef6288SAlexander V. Chernikov static const struct nlfield_parser nlf_p_generic[] = {
732cef6288SAlexander V. Chernikov 	{ .off_in = _IN(version), .off_out = _OUT(version), .cb = nlf_get_u8 },
742cef6288SAlexander V. Chernikov };
752cef6288SAlexander V. Chernikov #undef _IN
762cef6288SAlexander V. Chernikov #undef _OUT
772cef6288SAlexander V. Chernikov NL_DECLARE_PARSER(state_parser, struct genlmsghdr, nlf_p_generic, nla_p_state);
782cef6288SAlexander V. Chernikov 
792cef6288SAlexander V. Chernikov static void
802cef6288SAlexander V. Chernikov dump_addr(struct nl_writer *nw, int attr, const struct pf_addr *addr, int af)
812cef6288SAlexander V. Chernikov {
822cef6288SAlexander V. Chernikov 	switch (af) {
832cef6288SAlexander V. Chernikov 	case AF_INET:
842cef6288SAlexander V. Chernikov 		nlattr_add(nw, attr, 4, &addr->v4);
852cef6288SAlexander V. Chernikov 		break;
862cef6288SAlexander V. Chernikov 	case AF_INET6:
872cef6288SAlexander V. Chernikov 		nlattr_add(nw, attr, 16, &addr->v6);
882cef6288SAlexander V. Chernikov 		break;
892cef6288SAlexander V. Chernikov 	};
902cef6288SAlexander V. Chernikov }
912cef6288SAlexander V. Chernikov 
922cef6288SAlexander V. Chernikov static bool
932cef6288SAlexander V. Chernikov dump_state_peer(struct nl_writer *nw, int attr, const struct pf_state_peer *peer)
942cef6288SAlexander V. Chernikov {
952cef6288SAlexander V. Chernikov 	int off = nlattr_add_nested(nw, attr);
962cef6288SAlexander V. Chernikov 	if (off == 0)
972cef6288SAlexander V. Chernikov 		return (false);
982cef6288SAlexander V. Chernikov 
992cef6288SAlexander V. Chernikov 	nlattr_add_u32(nw, PF_STP_SEQLO, peer->seqlo);
1002cef6288SAlexander V. Chernikov 	nlattr_add_u32(nw, PF_STP_SEQHI, peer->seqhi);
1012cef6288SAlexander V. Chernikov 	nlattr_add_u32(nw, PF_STP_SEQDIFF, peer->seqdiff);
1022cef6288SAlexander V. Chernikov 	nlattr_add_u16(nw, PF_STP_MAX_WIN, peer->max_win);
1032cef6288SAlexander V. Chernikov 	nlattr_add_u16(nw, PF_STP_MSS, peer->mss);
1042cef6288SAlexander V. Chernikov 	nlattr_add_u8(nw, PF_STP_STATE, peer->state);
1052cef6288SAlexander V. Chernikov 	nlattr_add_u8(nw, PF_STP_WSCALE, peer->wscale);
1062cef6288SAlexander V. Chernikov 
1072cef6288SAlexander V. Chernikov 	if (peer->scrub != NULL) {
1082cef6288SAlexander V. Chernikov 		struct pf_state_scrub *sc = peer->scrub;
1092cef6288SAlexander V. Chernikov 		uint16_t pfss_flags = sc->pfss_flags & PFSS_TIMESTAMP;
1102cef6288SAlexander V. Chernikov 
1112cef6288SAlexander V. Chernikov 		nlattr_add_u16(nw, PF_STP_PFSS_FLAGS, pfss_flags);
1122cef6288SAlexander V. Chernikov 		nlattr_add_u32(nw, PF_STP_PFSS_TS_MOD, sc->pfss_ts_mod);
1132cef6288SAlexander V. Chernikov 		nlattr_add_u8(nw, PF_STP_PFSS_TTL, sc->pfss_ttl);
1142cef6288SAlexander V. Chernikov 		nlattr_add_u8(nw, PF_STP_SCRUB_FLAG, PFSYNC_SCRUB_FLAG_VALID);
1152cef6288SAlexander V. Chernikov 	}
1162cef6288SAlexander V. Chernikov 	nlattr_set_len(nw, off);
1172cef6288SAlexander V. Chernikov 
1182cef6288SAlexander V. Chernikov 	return (true);
1192cef6288SAlexander V. Chernikov }
1202cef6288SAlexander V. Chernikov 
1212cef6288SAlexander V. Chernikov static bool
1222cef6288SAlexander V. Chernikov dump_state_key(struct nl_writer *nw, int attr, const struct pf_state_key *key)
1232cef6288SAlexander V. Chernikov {
1242cef6288SAlexander V. Chernikov 	int off = nlattr_add_nested(nw, attr);
1252cef6288SAlexander V. Chernikov 	if (off == 0)
1262cef6288SAlexander V. Chernikov 		return (false);
1272cef6288SAlexander V. Chernikov 
1282cef6288SAlexander V. Chernikov 	dump_addr(nw, PF_STK_ADDR0, &key->addr[0], key->af);
1292cef6288SAlexander V. Chernikov 	dump_addr(nw, PF_STK_ADDR1, &key->addr[1], key->af);
1302cef6288SAlexander V. Chernikov 	nlattr_add_u16(nw, PF_STK_PORT0, key->port[0]);
1312cef6288SAlexander V. Chernikov 	nlattr_add_u16(nw, PF_STK_PORT1, key->port[1]);
1322cef6288SAlexander V. Chernikov 
1332cef6288SAlexander V. Chernikov 	nlattr_set_len(nw, off);
1342cef6288SAlexander V. Chernikov 
1352cef6288SAlexander V. Chernikov 	return (true);
1362cef6288SAlexander V. Chernikov }
1372cef6288SAlexander V. Chernikov 
1382cef6288SAlexander V. Chernikov static int
1392cef6288SAlexander V. Chernikov dump_state(struct nlpcb *nlp, const struct nlmsghdr *hdr, struct pf_kstate *s,
1402cef6288SAlexander V. Chernikov     struct nl_pstate *npt)
1412cef6288SAlexander V. Chernikov {
1422cef6288SAlexander V. Chernikov 	struct nl_writer *nw = npt->nw;
1432cef6288SAlexander V. Chernikov 	int error = 0;
1442cef6288SAlexander V. Chernikov 	int af;
1452cef6288SAlexander V. Chernikov 	struct pf_state_key *key;
1462cef6288SAlexander V. Chernikov 
1472cef6288SAlexander V. Chernikov 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1482cef6288SAlexander V. Chernikov 		goto enomem;
1492cef6288SAlexander V. Chernikov 
1502cef6288SAlexander V. Chernikov 	struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1512cef6288SAlexander V. Chernikov 	ghdr_new->cmd = PFNL_CMD_GETSTATES;
1522cef6288SAlexander V. Chernikov 	ghdr_new->version = 0;
1532cef6288SAlexander V. Chernikov 	ghdr_new->reserved = 0;
1542cef6288SAlexander V. Chernikov 
1552cef6288SAlexander V. Chernikov 	nlattr_add_u64(nw, PF_ST_VERSION, PF_STATE_VERSION);
1562cef6288SAlexander V. Chernikov 
1572cef6288SAlexander V. Chernikov 	key = s->key[PF_SK_WIRE];
1582cef6288SAlexander V. Chernikov 	if (!dump_state_key(nw, PF_ST_KEY_WIRE, key))
1592cef6288SAlexander V. Chernikov 		goto enomem;
1602cef6288SAlexander V. Chernikov 	key = s->key[PF_SK_STACK];
1612cef6288SAlexander V. Chernikov 	if (!dump_state_key(nw, PF_ST_KEY_STACK, key))
1622cef6288SAlexander V. Chernikov 		goto enomem;
1632cef6288SAlexander V. Chernikov 
1642cef6288SAlexander V. Chernikov 	af = s->key[PF_SK_WIRE]->af;
1652cef6288SAlexander V. Chernikov 	nlattr_add_u8(nw, PF_ST_PROTO, s->key[PF_SK_WIRE]->proto);
1662cef6288SAlexander V. Chernikov 	nlattr_add_u8(nw, PF_ST_AF, af);
1672cef6288SAlexander V. Chernikov 
1682cef6288SAlexander V. Chernikov 	nlattr_add_string(nw, PF_ST_IFNAME, s->kif->pfik_name);
1692cef6288SAlexander V. Chernikov 	nlattr_add_string(nw, PF_ST_ORIG_IFNAME, s->orig_kif->pfik_name);
1702cef6288SAlexander V. Chernikov 	dump_addr(nw, PF_ST_RT_ADDR, &s->rt_addr, af);
1712cef6288SAlexander V. Chernikov 	nlattr_add_u32(nw, PF_ST_CREATION, time_uptime - s->creation);
1722cef6288SAlexander V. Chernikov 	uint32_t expire = pf_state_expires(s);
1732cef6288SAlexander V. Chernikov 	if (expire > time_uptime)
1742cef6288SAlexander V. Chernikov 		expire = expire - time_uptime;
1752cef6288SAlexander V. Chernikov 	nlattr_add_u32(nw, PF_ST_EXPIRE, expire);
1762cef6288SAlexander V. Chernikov 	nlattr_add_u8(nw, PF_ST_DIRECTION, s->direction);
1772cef6288SAlexander V. Chernikov 	nlattr_add_u8(nw, PF_ST_LOG, s->act.log);
1782cef6288SAlexander V. Chernikov 	nlattr_add_u8(nw, PF_ST_TIMEOUT, s->timeout);
1792cef6288SAlexander V. Chernikov 	nlattr_add_u16(nw, PF_ST_STATE_FLAGS, s->state_flags);
1802cef6288SAlexander V. Chernikov 	uint8_t sync_flags = 0;
1812cef6288SAlexander V. Chernikov 	if (s->src_node)
1822cef6288SAlexander V. Chernikov 		sync_flags |= PFSYNC_FLAG_SRCNODE;
1832cef6288SAlexander V. Chernikov 	if (s->nat_src_node)
1842cef6288SAlexander V. Chernikov 		sync_flags |= PFSYNC_FLAG_NATSRCNODE;
1852cef6288SAlexander V. Chernikov 	nlattr_add_u8(nw, PF_ST_SYNC_FLAGS, sync_flags);
1862cef6288SAlexander V. Chernikov 	nlattr_add_u64(nw, PF_ST_ID, s->id);
1872cef6288SAlexander V. Chernikov 	nlattr_add_u32(nw, PF_ST_CREATORID, htonl(s->creatorid));
1882cef6288SAlexander V. Chernikov 
1892cef6288SAlexander V. Chernikov 	nlattr_add_u32(nw, PF_ST_RULE, s->rule.ptr ? s->rule.ptr->nr : -1);
1902cef6288SAlexander V. Chernikov 	nlattr_add_u32(nw, PF_ST_ANCHOR, s->anchor.ptr ? s->anchor.ptr->nr : -1);
1912cef6288SAlexander V. Chernikov 	nlattr_add_u32(nw, PF_ST_NAT_RULE, s->nat_rule.ptr ? s->nat_rule.ptr->nr : -1);
1922cef6288SAlexander V. Chernikov 
1932cef6288SAlexander V. Chernikov 	nlattr_add_u64(nw, PF_ST_PACKETS0, s->packets[0]);
1942cef6288SAlexander V. Chernikov 	nlattr_add_u64(nw, PF_ST_PACKETS1, s->packets[1]);
1952cef6288SAlexander V. Chernikov 	nlattr_add_u64(nw, PF_ST_BYTES0, s->bytes[0]);
1962cef6288SAlexander V. Chernikov 	nlattr_add_u64(nw, PF_ST_BYTES1, s->bytes[1]);
1972cef6288SAlexander V. Chernikov 
1982cef6288SAlexander V. Chernikov 	if (!dump_state_peer(nw, PF_ST_PEER_SRC, &s->src))
1992cef6288SAlexander V. Chernikov 		goto enomem;
2002cef6288SAlexander V. Chernikov 	if (!dump_state_peer(nw, PF_ST_PEER_DST, &s->dst))
2012cef6288SAlexander V. Chernikov 		goto enomem;
2022cef6288SAlexander V. Chernikov 
2032cef6288SAlexander V. Chernikov 	if (nlmsg_end(nw))
2042cef6288SAlexander V. Chernikov 		return (0);
2052cef6288SAlexander V. Chernikov 
2062cef6288SAlexander V. Chernikov enomem:
2072cef6288SAlexander V. Chernikov 	error = ENOMEM;
2082cef6288SAlexander V. Chernikov 	nlmsg_abort(nw);
2092cef6288SAlexander V. Chernikov 	return (error);
2102cef6288SAlexander V. Chernikov }
2112cef6288SAlexander V. Chernikov 
2122cef6288SAlexander V. Chernikov static int
2132cef6288SAlexander V. Chernikov handle_dumpstates(struct nlpcb *nlp, struct nl_parsed_state *attrs,
2142cef6288SAlexander V. Chernikov     struct nlmsghdr *hdr, struct nl_pstate *npt)
2152cef6288SAlexander V. Chernikov {
2162cef6288SAlexander V. Chernikov 	int error = 0;
2172cef6288SAlexander V. Chernikov 
2182cef6288SAlexander V. Chernikov 	hdr->nlmsg_flags |= NLM_F_MULTI;
2192cef6288SAlexander V. Chernikov 
2202cef6288SAlexander V. Chernikov 	for (int i = 0; i <= pf_hashmask; i++) {
2212cef6288SAlexander V. Chernikov 		struct pf_idhash *ih = &V_pf_idhash[i];
2222cef6288SAlexander V. Chernikov 		struct pf_kstate *s;
2232cef6288SAlexander V. Chernikov 
2242cef6288SAlexander V. Chernikov 		if (LIST_EMPTY(&ih->states))
2252cef6288SAlexander V. Chernikov 			continue;
2262cef6288SAlexander V. Chernikov 
2272cef6288SAlexander V. Chernikov 		PF_HASHROW_LOCK(ih);
2282cef6288SAlexander V. Chernikov 		LIST_FOREACH(s, &ih->states, entry) {
229044eef6aSKristof Provost 			sa_family_t af = s->key[PF_SK_WIRE]->af;
230044eef6aSKristof Provost 
231044eef6aSKristof Provost 			if (s->timeout == PFTM_UNLINKED)
232044eef6aSKristof Provost 				continue;
233044eef6aSKristof Provost 
234044eef6aSKristof Provost 			/* Filter */
235044eef6aSKristof Provost 			if (attrs->creatorid != 0 && s->creatorid != attrs->creatorid)
236044eef6aSKristof Provost 				continue;
237044eef6aSKristof Provost 			if (attrs->ifname[0] != 0 &&
238044eef6aSKristof Provost 			    strncmp(attrs->ifname, s->kif->pfik_name, IFNAMSIZ) != 0)
239044eef6aSKristof Provost 				continue;
240044eef6aSKristof Provost 			if (attrs->proto != 0 && s->key[PF_SK_WIRE]->proto != attrs->proto)
241044eef6aSKristof Provost 				continue;
242044eef6aSKristof Provost 			if (attrs->af != 0 && af != attrs->af)
243044eef6aSKristof Provost 				continue;
244044eef6aSKristof Provost 			if (pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[0],
245044eef6aSKristof Provost 			    &attrs->mask, &attrs->addr, af) &&
246044eef6aSKristof Provost 			    pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[1],
247044eef6aSKristof Provost 			    &attrs->mask, &attrs->addr, af) &&
248044eef6aSKristof Provost 			    pf_match_addr(1, &s->key[PF_SK_STACK]->addr[0],
249044eef6aSKristof Provost 			    &attrs->mask, &attrs->addr, af) &&
250044eef6aSKristof Provost 			    pf_match_addr(1, &s->key[PF_SK_STACK]->addr[1],
251044eef6aSKristof Provost 			    &attrs->mask, &attrs->addr, af))
252044eef6aSKristof Provost 				continue;
253044eef6aSKristof Provost 
2542cef6288SAlexander V. Chernikov 			error = dump_state(nlp, hdr, s, npt);
2552cef6288SAlexander V. Chernikov 			if (error != 0)
2562cef6288SAlexander V. Chernikov 				break;
2572cef6288SAlexander V. Chernikov 		}
2582cef6288SAlexander V. Chernikov 		PF_HASHROW_UNLOCK(ih);
2592cef6288SAlexander V. Chernikov 	}
2602cef6288SAlexander V. Chernikov 
2612cef6288SAlexander V. Chernikov 	if (!nlmsg_end_dump(npt->nw, error, hdr)) {
2622cef6288SAlexander V. Chernikov 		NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
2632cef6288SAlexander V. Chernikov 		return (ENOMEM);
2642cef6288SAlexander V. Chernikov 	}
2652cef6288SAlexander V. Chernikov 
2662cef6288SAlexander V. Chernikov 	return (error);
2672cef6288SAlexander V. Chernikov }
2682cef6288SAlexander V. Chernikov 
2692cef6288SAlexander V. Chernikov static int
2702cef6288SAlexander V. Chernikov handle_getstate(struct nlpcb *nlp, struct nl_parsed_state *attrs,
2712cef6288SAlexander V. Chernikov     struct nlmsghdr *hdr, struct nl_pstate *npt)
2722cef6288SAlexander V. Chernikov {
2732cef6288SAlexander V. Chernikov 	struct pf_kstate *s = pf_find_state_byid(attrs->id, attrs->creatorid);
2742cef6288SAlexander V. Chernikov 	if (s == NULL)
2752cef6288SAlexander V. Chernikov 		return (ENOENT);
2762cef6288SAlexander V. Chernikov 	return (dump_state(nlp, hdr, s, npt));
2772cef6288SAlexander V. Chernikov }
2782cef6288SAlexander V. Chernikov 
2792cef6288SAlexander V. Chernikov static int
280a7191e5dSKristof Provost dump_creatorid(struct nlpcb *nlp, const struct nlmsghdr *hdr, uint32_t creator,
281a7191e5dSKristof Provost     struct nl_pstate *npt)
282a7191e5dSKristof Provost {
283a7191e5dSKristof Provost 	struct nl_writer *nw = npt->nw;
284a7191e5dSKristof Provost 
285a7191e5dSKristof Provost 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
286a7191e5dSKristof Provost 		goto enomem;
287a7191e5dSKristof Provost 
288a7191e5dSKristof Provost 	struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
289a7191e5dSKristof Provost 	ghdr_new->cmd = PFNL_CMD_GETCREATORS;
290a7191e5dSKristof Provost 	ghdr_new->version = 0;
291a7191e5dSKristof Provost 	ghdr_new->reserved = 0;
292a7191e5dSKristof Provost 
293a7191e5dSKristof Provost 	nlattr_add_u32(nw, PF_ST_CREATORID, htonl(creator));
294a7191e5dSKristof Provost 
295a7191e5dSKristof Provost 	if (nlmsg_end(nw))
296a7191e5dSKristof Provost 		return (0);
297a7191e5dSKristof Provost 
298a7191e5dSKristof Provost enomem:
299a7191e5dSKristof Provost 	nlmsg_abort(nw);
300a7191e5dSKristof Provost 	return (ENOMEM);
301a7191e5dSKristof Provost }
302a7191e5dSKristof Provost 
303a7191e5dSKristof Provost static int
3042cef6288SAlexander V. Chernikov pf_handle_getstates(struct nlmsghdr *hdr, struct nl_pstate *npt)
3052cef6288SAlexander V. Chernikov {
3062cef6288SAlexander V. Chernikov 	int error;
3072cef6288SAlexander V. Chernikov 
3082cef6288SAlexander V. Chernikov 	struct nl_parsed_state attrs = {};
3092cef6288SAlexander V. Chernikov 	error = nl_parse_nlmsg(hdr, &state_parser, npt, &attrs);
3102cef6288SAlexander V. Chernikov 	if (error != 0)
3112cef6288SAlexander V. Chernikov 		return (error);
3122cef6288SAlexander V. Chernikov 
3132cef6288SAlexander V. Chernikov 	if (attrs.id != 0)
3142cef6288SAlexander V. Chernikov 		error = handle_getstate(npt->nlp, &attrs, hdr, npt);
3152cef6288SAlexander V. Chernikov 	else
3162cef6288SAlexander V. Chernikov 		error = handle_dumpstates(npt->nlp, &attrs, hdr, npt);
3172cef6288SAlexander V. Chernikov 
3182cef6288SAlexander V. Chernikov 	return (error);
3192cef6288SAlexander V. Chernikov }
3202cef6288SAlexander V. Chernikov 
321a7191e5dSKristof Provost static int
322a7191e5dSKristof Provost pf_handle_getcreators(struct nlmsghdr *hdr, struct nl_pstate *npt)
323a7191e5dSKristof Provost {
324a7191e5dSKristof Provost 	uint32_t creators[16];
325a7191e5dSKristof Provost 	int error = 0;
326a7191e5dSKristof Provost 
327a7191e5dSKristof Provost 	bzero(creators, sizeof(creators));
328a7191e5dSKristof Provost 
329a7191e5dSKristof Provost 	for (int i = 0; i < pf_hashmask; i++) {
330a7191e5dSKristof Provost 		struct pf_idhash *ih = &V_pf_idhash[i];
331a7191e5dSKristof Provost 		struct pf_kstate *s;
332a7191e5dSKristof Provost 
333a7191e5dSKristof Provost 		if (LIST_EMPTY(&ih->states))
334a7191e5dSKristof Provost 			continue;
335a7191e5dSKristof Provost 
336a7191e5dSKristof Provost 		PF_HASHROW_LOCK(ih);
337a7191e5dSKristof Provost 		LIST_FOREACH(s, &ih->states, entry) {
338a7191e5dSKristof Provost 			int j;
339a7191e5dSKristof Provost 			if (s->timeout == PFTM_UNLINKED)
340a7191e5dSKristof Provost 				continue;
341a7191e5dSKristof Provost 
342a7191e5dSKristof Provost 			for (j = 0; j < nitems(creators); j++) {
343a7191e5dSKristof Provost 				if (creators[j] == s->creatorid)
344a7191e5dSKristof Provost 					break;
345a7191e5dSKristof Provost 				if (creators[j] == 0) {
346a7191e5dSKristof Provost 					creators[j] = s->creatorid;
347a7191e5dSKristof Provost 					break;
348a7191e5dSKristof Provost 				}
349a7191e5dSKristof Provost 			}
350a7191e5dSKristof Provost 			if (j == nitems(creators))
351a7191e5dSKristof Provost 				printf("Warning: too many creators!\n");
352a7191e5dSKristof Provost 		}
353a7191e5dSKristof Provost 		PF_HASHROW_UNLOCK(ih);
354a7191e5dSKristof Provost 	}
355a7191e5dSKristof Provost 
356a7191e5dSKristof Provost 	hdr->nlmsg_flags |= NLM_F_MULTI;
357a7191e5dSKristof Provost 	for (int i = 0; i < nitems(creators); i++) {
358a7191e5dSKristof Provost 		if (creators[i] == 0)
359a7191e5dSKristof Provost 			break;
360a7191e5dSKristof Provost 		error = dump_creatorid(npt->nlp, hdr, creators[i], npt);
361a7191e5dSKristof Provost 	}
362a7191e5dSKristof Provost 
363a7191e5dSKristof Provost 	if (!nlmsg_end_dump(npt->nw, error, hdr)) {
364a7191e5dSKristof Provost 		NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
365a7191e5dSKristof Provost 		return (ENOMEM);
366a7191e5dSKristof Provost 	}
367a7191e5dSKristof Provost 
368a7191e5dSKristof Provost 	return (error);
369a7191e5dSKristof Provost }
370a7191e5dSKristof Provost 
37181647eb6SKristof Provost static int
37281647eb6SKristof Provost pf_handle_start(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
37381647eb6SKristof Provost {
37481647eb6SKristof Provost 	return (pf_start());
37581647eb6SKristof Provost }
37681647eb6SKristof Provost 
37781647eb6SKristof Provost static int
37881647eb6SKristof Provost pf_handle_stop(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
37981647eb6SKristof Provost {
38081647eb6SKristof Provost 	return (pf_stop());
38181647eb6SKristof Provost }
38281647eb6SKristof Provost 
383ffbf2595SKristof Provost #define _OUT(_field)	offsetof(struct pf_addr_wrap, _field)
384ffbf2595SKristof Provost static const struct nlattr_parser nla_p_addr_wrap[] = {
385ffbf2595SKristof Provost 	{ .type = PF_AT_ADDR, .off = _OUT(v.a.addr), .cb = nlattr_get_in6_addr },
386ffbf2595SKristof Provost 	{ .type = PF_AT_MASK, .off = _OUT(v.a.mask), .cb = nlattr_get_in6_addr },
387ffbf2595SKristof Provost 	{ .type = PF_AT_IFNAME, .off = _OUT(v.ifname), .arg = (void *)IFNAMSIZ,.cb = nlattr_get_chara },
388ffbf2595SKristof Provost 	{ .type = PF_AT_TABLENAME, .off = _OUT(v.tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
389ffbf2595SKristof Provost 	{ .type = PF_AT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
390ffbf2595SKristof Provost 	{ .type = PF_AT_IFLAGS, .off = _OUT(iflags), .cb = nlattr_get_uint8 },
391ffbf2595SKristof Provost };
392ffbf2595SKristof Provost NL_DECLARE_ATTR_PARSER(addr_wrap_parser, nla_p_addr_wrap);
393ffbf2595SKristof Provost #undef _OUT
394ffbf2595SKristof Provost 
395ffbf2595SKristof Provost #define _OUT(_field)	offsetof(struct pf_rule_addr, _field)
396ffbf2595SKristof Provost static const struct nlattr_parser nla_p_ruleaddr[] = {
397ffbf2595SKristof Provost 	{ .type = PF_RAT_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
398ffbf2595SKristof Provost 	{ .type = PF_RAT_SRC_PORT, .off = _OUT(port[0]), .cb = nlattr_get_uint16 },
399ffbf2595SKristof Provost 	{ .type = PF_RAT_DST_PORT, .off = _OUT(port[1]), .cb = nlattr_get_uint16 },
400ffbf2595SKristof Provost 	{ .type = PF_RAT_NEG, .off = _OUT(neg), .cb = nlattr_get_uint8 },
401ffbf2595SKristof Provost 	{ .type = PF_RAT_OP, .off = _OUT(port_op), .cb = nlattr_get_uint8 },
402ffbf2595SKristof Provost };
403ffbf2595SKristof Provost NL_DECLARE_ATTR_PARSER(rule_addr_parser, nla_p_ruleaddr);
404ffbf2595SKristof Provost #undef _OUT
405ffbf2595SKristof Provost 
406ffbf2595SKristof Provost #define _OUT(_field)	offsetof(struct pf_mape_portset, _field)
407ffbf2595SKristof Provost static const struct nlattr_parser nla_p_mape_portset[] = {
408ffbf2595SKristof Provost 	{ .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = nlattr_get_uint8 },
409ffbf2595SKristof Provost 	{ .type = PF_MET_PSID_LEN, .off = _OUT(psidlen), .cb = nlattr_get_uint8 },
410ffbf2595SKristof Provost 	{. type = PF_MET_PSID, .off = _OUT(psid), .cb = nlattr_get_uint16 },
411ffbf2595SKristof Provost };
412ffbf2595SKristof Provost NL_DECLARE_ATTR_PARSER(mape_portset_parser, nla_p_mape_portset);
413ffbf2595SKristof Provost #undef _OUT
414ffbf2595SKristof Provost 
415ffbf2595SKristof Provost struct nl_parsed_labels
416ffbf2595SKristof Provost {
417ffbf2595SKristof Provost 	char		labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
418ffbf2595SKristof Provost 	uint32_t	i;
419ffbf2595SKristof Provost };
420ffbf2595SKristof Provost 
421ffbf2595SKristof Provost static int
422ffbf2595SKristof Provost nlattr_get_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt,
423ffbf2595SKristof Provost     const void *arg, void *target)
424ffbf2595SKristof Provost {
425ffbf2595SKristof Provost 	struct nl_parsed_labels *l = (struct nl_parsed_labels *)target;
426ffbf2595SKristof Provost 	int ret;
427ffbf2595SKristof Provost 
428ffbf2595SKristof Provost 	if (l->i >= PF_RULE_MAX_LABEL_COUNT)
429ffbf2595SKristof Provost 		return (E2BIG);
430ffbf2595SKristof Provost 
431ffbf2595SKristof Provost 	ret = nlattr_get_chara(nla, npt, (void *)PF_RULE_LABEL_SIZE,
432ffbf2595SKristof Provost 	    l->labels[l->i]);
433ffbf2595SKristof Provost 	if (ret == 0)
434ffbf2595SKristof Provost 		l->i++;
435ffbf2595SKristof Provost 
436ffbf2595SKristof Provost 	return (ret);
437ffbf2595SKristof Provost }
438ffbf2595SKristof Provost 
439ffbf2595SKristof Provost #define _OUT(_field)	offsetof(struct nl_parsed_labels, _field)
440ffbf2595SKristof Provost static const struct nlattr_parser nla_p_labels[] = {
441ffbf2595SKristof Provost 	{ .type = PF_LT_LABEL, .off = 0, .cb = nlattr_get_pf_rule_labels },
442ffbf2595SKristof Provost };
443ffbf2595SKristof Provost NL_DECLARE_ATTR_PARSER(rule_labels_parser, nla_p_labels);
444ffbf2595SKristof Provost #undef _OUT
445ffbf2595SKristof Provost 
446ffbf2595SKristof Provost static int
447ffbf2595SKristof Provost nlattr_get_nested_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
448ffbf2595SKristof Provost {
449ffbf2595SKristof Provost 	struct nl_parsed_labels parsed_labels = { };
450ffbf2595SKristof Provost 	int error;
451ffbf2595SKristof Provost 
452ffbf2595SKristof Provost 	/* Assumes target points to the beginning of the structure */
453ffbf2595SKristof Provost 	error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &rule_labels_parser, npt, &parsed_labels);
454ffbf2595SKristof Provost 	if (error != 0)
455ffbf2595SKristof Provost 		return (error);
456ffbf2595SKristof Provost 
457ffbf2595SKristof Provost 	memcpy(target, parsed_labels.labels, sizeof(parsed_labels));
458ffbf2595SKristof Provost 
459ffbf2595SKristof Provost 	return (0);
460ffbf2595SKristof Provost }
461ffbf2595SKristof Provost 
462ffbf2595SKristof Provost #define _OUT(_field)	offsetof(struct pf_kpool, _field)
463ffbf2595SKristof Provost static const struct nlattr_parser nla_p_pool[] = {
464ffbf2595SKristof Provost 	{ .type = PF_PT_KEY, .off = _OUT(key), .arg = (void *)sizeof(struct pf_poolhashkey), .cb = nlattr_get_bytes },
465ffbf2595SKristof Provost 	{ .type = PF_PT_COUNTER, .off = _OUT(counter), .cb = nlattr_get_in6_addr },
466ffbf2595SKristof Provost 	{ .type = PF_PT_TBLIDX, .off = _OUT(tblidx), .cb = nlattr_get_uint32 },
467ffbf2595SKristof Provost 	{ .type = PF_PT_PROXY_SRC_PORT, .off = _OUT(proxy_port[0]), .cb = nlattr_get_uint16 },
468ffbf2595SKristof Provost 	{ .type = PF_PT_PROXY_DST_PORT, .off = _OUT(proxy_port[1]), .cb = nlattr_get_uint16 },
469ffbf2595SKristof Provost 	{ .type = PF_PT_OPTS, .off = _OUT(opts), .cb = nlattr_get_uint8 },
470ffbf2595SKristof Provost 	{ .type = PF_PT_MAPE, .off = _OUT(mape), .arg = &mape_portset_parser, .cb = nlattr_get_nested },
471ffbf2595SKristof Provost };
472ffbf2595SKristof Provost NL_DECLARE_ATTR_PARSER(pool_parser, nla_p_pool);
473ffbf2595SKristof Provost #undef _OUT
474ffbf2595SKristof Provost 
475ffbf2595SKristof Provost #define _OUT(_field)	offsetof(struct pf_rule_uid, _field)
476ffbf2595SKristof Provost static const struct nlattr_parser nla_p_rule_uid[] = {
477ffbf2595SKristof Provost 	{ .type = PF_RUT_UID_LOW, .off = _OUT(uid[0]), .cb = nlattr_get_uint32 },
478ffbf2595SKristof Provost 	{ .type = PF_RUT_UID_HIGH, .off = _OUT(uid[1]), .cb = nlattr_get_uint32 },
479ffbf2595SKristof Provost 	{ .type = PF_RUT_OP, .off = _OUT(op), .cb = nlattr_get_uint8 },
480ffbf2595SKristof Provost };
481ffbf2595SKristof Provost NL_DECLARE_ATTR_PARSER(rule_uid_parser, nla_p_rule_uid);
482ffbf2595SKristof Provost #undef _OUT
483ffbf2595SKristof Provost 
484ffbf2595SKristof Provost struct nl_parsed_timeouts
485ffbf2595SKristof Provost {
486ffbf2595SKristof Provost 	uint32_t	timeouts[PFTM_MAX];
487ffbf2595SKristof Provost 	uint32_t	i;
488ffbf2595SKristof Provost };
489ffbf2595SKristof Provost 
490ffbf2595SKristof Provost static int
491ffbf2595SKristof Provost nlattr_get_pf_timeout(struct nlattr *nla, struct nl_pstate *npt,
492ffbf2595SKristof Provost     const void *arg, void *target)
493ffbf2595SKristof Provost {
494ffbf2595SKristof Provost 	struct nl_parsed_timeouts *t = (struct nl_parsed_timeouts *)target;
495ffbf2595SKristof Provost 	int ret;
496ffbf2595SKristof Provost 
497ffbf2595SKristof Provost 	if (t->i >= PFTM_MAX)
498ffbf2595SKristof Provost 		return (E2BIG);
499ffbf2595SKristof Provost 
500ffbf2595SKristof Provost 	ret = nlattr_get_uint32(nla, npt, NULL, &t->timeouts[t->i]);
501ffbf2595SKristof Provost 	if (ret == 0)
502ffbf2595SKristof Provost 		t->i++;
503ffbf2595SKristof Provost 
504ffbf2595SKristof Provost 	return (ret);
505ffbf2595SKristof Provost }
506ffbf2595SKristof Provost 
507ffbf2595SKristof Provost #define _OUT(_field)	offsetof(struct nl_parsed_timeout, _field)
508ffbf2595SKristof Provost static const struct nlattr_parser nla_p_timeouts[] = {
509ffbf2595SKristof Provost 	{ .type = PF_TT_TIMEOUT, .off = 0, .cb = nlattr_get_pf_timeout },
510ffbf2595SKristof Provost };
511ffbf2595SKristof Provost NL_DECLARE_ATTR_PARSER(timeout_parser, nla_p_timeouts);
512ffbf2595SKristof Provost #undef _OUT
513ffbf2595SKristof Provost 
514ffbf2595SKristof Provost static int
515ffbf2595SKristof Provost nlattr_get_nested_timeouts(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
516ffbf2595SKristof Provost {
517ffbf2595SKristof Provost 	struct nl_parsed_timeouts parsed_timeouts = { };
518ffbf2595SKristof Provost 	int error;
519ffbf2595SKristof Provost 
520ffbf2595SKristof Provost 	/* Assumes target points to the beginning of the structure */
521ffbf2595SKristof Provost 	error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &timeout_parser, npt, &parsed_timeouts);
522ffbf2595SKristof Provost 	if (error != 0)
523ffbf2595SKristof Provost 		return (error);
524ffbf2595SKristof Provost 
525ffbf2595SKristof Provost 	memcpy(target, parsed_timeouts.timeouts, sizeof(parsed_timeouts.timeouts));
526ffbf2595SKristof Provost 
527ffbf2595SKristof Provost 	return (0);
528ffbf2595SKristof Provost }
529ffbf2595SKristof Provost 
530ffbf2595SKristof Provost #define _OUT(_field)	offsetof(struct pf_krule, _field)
531ffbf2595SKristof Provost static const struct nlattr_parser nla_p_rule[] = {
532ffbf2595SKristof Provost 	{ .type = PF_RT_SRC, .off = _OUT(src), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
533ffbf2595SKristof Provost 	{ .type = PF_RT_DST, .off = _OUT(dst), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
534ffbf2595SKristof Provost 	{ .type = PF_RT_RIDENTIFIER, .off = _OUT(ridentifier), .cb = nlattr_get_uint32 },
535ffbf2595SKristof Provost 	{ .type = PF_RT_LABELS, .off = _OUT(label), .arg = &rule_labels_parser,.cb = nlattr_get_nested_pf_rule_labels },
536ffbf2595SKristof Provost 	{ .type = PF_RT_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
537ffbf2595SKristof Provost 	{ .type = PF_RT_QNAME, .off = _OUT(qname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
538ffbf2595SKristof Provost 	{ .type = PF_RT_PQNAME, .off = _OUT(pqname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
539ffbf2595SKristof Provost 	{ .type = PF_RT_TAGNAME, .off = _OUT(tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
540ffbf2595SKristof Provost 	{ .type = PF_RT_MATCH_TAGNAME, .off = _OUT(match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
541ffbf2595SKristof Provost 	{ .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
542ffbf2595SKristof Provost 	{ .type = PF_RT_RPOOL, .off = _OUT(rpool), .arg = &pool_parser, .cb = nlattr_get_nested },
543ffbf2595SKristof Provost 	{ .type = PF_RT_OS_FINGERPRINT, .off = _OUT(os_fingerprint), .cb = nlattr_get_uint32 },
544ffbf2595SKristof Provost 	{ .type = PF_RT_RTABLEID, .off = _OUT(rtableid), .cb = nlattr_get_uint32 },
545ffbf2595SKristof Provost 	{ .type = PF_RT_TIMEOUT, .off = _OUT(timeout), .arg = &timeout_parser, .cb = nlattr_get_nested_timeouts },
546ffbf2595SKristof Provost 	{ .type = PF_RT_MAX_STATES, .off = _OUT(max_states), .cb = nlattr_get_uint32 },
547ffbf2595SKristof Provost 	{ .type = PF_RT_MAX_SRC_NODES, .off = _OUT(max_src_nodes), .cb = nlattr_get_uint32 },
548ffbf2595SKristof Provost 	{ .type = PF_RT_MAX_SRC_STATES, .off = _OUT(max_src_states), .cb = nlattr_get_uint32 },
549ffbf2595SKristof Provost 	{ .type = PF_RT_MAX_SRC_CONN_RATE_LIMIT, .off = _OUT(max_src_conn_rate.limit), .cb = nlattr_get_uint32 },
550ffbf2595SKristof Provost 	{ .type = PF_RT_MAX_SRC_CONN_RATE_SECS, .off = _OUT(max_src_conn_rate.seconds), .cb = nlattr_get_uint32 },
551ffbf2595SKristof Provost 	{ .type = PF_RT_DNPIPE, .off = _OUT(dnpipe), .cb = nlattr_get_uint16 },
552ffbf2595SKristof Provost 	{ .type = PF_RT_DNRPIPE, .off = _OUT(dnrpipe), .cb = nlattr_get_uint16 },
553ffbf2595SKristof Provost 	{ .type = PF_RT_DNFLAGS, .off = _OUT(free_flags), .cb = nlattr_get_uint32 },
554ffbf2595SKristof Provost 	{ .type = PF_RT_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
555ffbf2595SKristof Provost 	{ .type = PF_RT_PROB, .off = _OUT(prob), .cb = nlattr_get_uint32 },
556ffbf2595SKristof Provost 	{ .type = PF_RT_CUID, .off = _OUT(cuid), .cb = nlattr_get_uint32 },
557ffbf2595SKristof Provost 	{. type = PF_RT_CPID, .off = _OUT(cpid), .cb = nlattr_get_uint32 },
558ffbf2595SKristof Provost 	{ .type = PF_RT_RETURN_ICMP, .off = _OUT(return_icmp), .cb = nlattr_get_uint16 },
559ffbf2595SKristof Provost 	{ .type = PF_RT_RETURN_ICMP6, .off = _OUT(return_icmp6), .cb = nlattr_get_uint16 },
560ffbf2595SKristof Provost 	{ .type = PF_RT_MAX_MSS, .off = _OUT(max_mss), .cb = nlattr_get_uint16 },
561ffbf2595SKristof Provost 	{ .type = PF_RT_SCRUB_FLAGS, .off = _OUT(scrub_flags), .cb = nlattr_get_uint16 },
562ffbf2595SKristof Provost 	{ .type = PF_RT_UID, .off = _OUT(uid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
563ffbf2595SKristof Provost 	{ .type = PF_RT_GID, .off = _OUT(gid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
564ffbf2595SKristof Provost 	{ .type = PF_RT_RULE_FLAG, .off = _OUT(rule_flag), .cb = nlattr_get_uint32 },
565ffbf2595SKristof Provost 	{ .type = PF_RT_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
566ffbf2595SKristof Provost 	{ .type = PF_RT_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
567ffbf2595SKristof Provost 	{ .type = PF_RT_LOG, .off = _OUT(log), .cb = nlattr_get_uint8 },
568ffbf2595SKristof Provost 	{ .type = PF_RT_LOGIF, .off = _OUT(logif), .cb = nlattr_get_uint8 },
569ffbf2595SKristof Provost 	{ .type = PF_RT_QUICK, .off = _OUT(quick), .cb = nlattr_get_uint8 },
570ffbf2595SKristof Provost 	{ .type = PF_RT_IF_NOT, .off = _OUT(ifnot), .cb = nlattr_get_uint8 },
571ffbf2595SKristof Provost 	{ .type = PF_RT_MATCH_TAG_NOT, .off = _OUT(match_tag_not), .cb = nlattr_get_uint8 },
572ffbf2595SKristof Provost 	{ .type = PF_RT_NATPASS, .off = _OUT(natpass), .cb = nlattr_get_uint8 },
573ffbf2595SKristof Provost 	{ .type = PF_RT_KEEP_STATE, .off = _OUT(keep_state), .cb = nlattr_get_uint8 },
574ffbf2595SKristof Provost 	{ .type = PF_RT_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
575ffbf2595SKristof Provost 	{ .type = PF_RT_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
576ffbf2595SKristof Provost 	{ .type = PF_RT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
577ffbf2595SKristof Provost 	{ .type = PF_RT_CODE, .off = _OUT(code), .cb = nlattr_get_uint8 },
578ffbf2595SKristof Provost 	{ .type = PF_RT_FLAGS, .off = _OUT(flags), .cb = nlattr_get_uint8 },
579ffbf2595SKristof Provost 	{ .type = PF_RT_FLAGSET, .off = _OUT(flagset), .cb = nlattr_get_uint8 },
580ffbf2595SKristof Provost 	{ .type = PF_RT_MIN_TTL, .off = _OUT(min_ttl), .cb = nlattr_get_uint8 },
581ffbf2595SKristof Provost 	{ .type = PF_RT_ALLOW_OPTS, .off = _OUT(allow_opts), .cb = nlattr_get_uint8 },
582ffbf2595SKristof Provost 	{ .type = PF_RT_RT, .off = _OUT(rt), .cb = nlattr_get_uint8 },
583ffbf2595SKristof Provost 	{ .type = PF_RT_RETURN_TTL, .off = _OUT(return_ttl), .cb = nlattr_get_uint8 },
584ffbf2595SKristof Provost 	{ .type = PF_RT_TOS, .off = _OUT(tos), .cb = nlattr_get_uint8 },
585ffbf2595SKristof Provost 	{ .type = PF_RT_SET_TOS, .off = _OUT(set_tos), .cb = nlattr_get_uint8 },
586ffbf2595SKristof Provost 	{ .type = PF_RT_ANCHOR_RELATIVE, .off = _OUT(anchor_relative), .cb = nlattr_get_uint8 },
587ffbf2595SKristof Provost 	{ .type = PF_RT_ANCHOR_WILDCARD, .off = _OUT(anchor_wildcard), .cb = nlattr_get_uint8 },
588ffbf2595SKristof Provost 	{ .type = PF_RT_FLUSH, .off = _OUT(flush), .cb = nlattr_get_uint8 },
589ffbf2595SKristof Provost 	{ .type = PF_RT_PRIO, .off = _OUT(prio), .cb = nlattr_get_uint8 },
590ffbf2595SKristof Provost 	{ .type = PF_RT_SET_PRIO, .off = _OUT(set_prio[0]), .cb = nlattr_get_uint8 },
591ffbf2595SKristof Provost 	{ .type = PF_RT_SET_PRIO_REPLY, .off = _OUT(set_prio[1]), .cb = nlattr_get_uint8 },
592ffbf2595SKristof Provost 	{ .type = PF_RT_DIVERT_ADDRESS, .off = _OUT(divert.addr), .cb = nlattr_get_in6_addr },
593ffbf2595SKristof Provost 	{ .type = PF_RT_DIVERT_PORT, .off = _OUT(divert.port), .cb = nlattr_get_uint16 },
594ffbf2595SKristof Provost };
595ffbf2595SKristof Provost NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule);
596ffbf2595SKristof Provost #undef _OUT
597ffbf2595SKristof Provost struct nl_parsed_addrule {
598ffbf2595SKristof Provost 	struct pf_krule	*rule;
599ffbf2595SKristof Provost 	uint32_t	 ticket;
600ffbf2595SKristof Provost 	uint32_t	 pool_ticket;
601ffbf2595SKristof Provost 	char		*anchor;
602ffbf2595SKristof Provost 	char		*anchor_call;
603ffbf2595SKristof Provost };
604ffbf2595SKristof Provost #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
605ffbf2595SKristof Provost #define	_OUT(_field)	offsetof(struct nl_parsed_addrule, _field)
606ffbf2595SKristof Provost static const struct nlattr_parser nla_p_addrule[] = {
607ffbf2595SKristof Provost 	{ .type = PF_ART_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
608ffbf2595SKristof Provost 	{ .type = PF_ART_POOL_TICKET, .off = _OUT(pool_ticket), .cb = nlattr_get_uint32 },
609ffbf2595SKristof Provost 	{ .type = PF_ART_ANCHOR, .off = _OUT(anchor), .cb = nlattr_get_string },
610ffbf2595SKristof Provost 	{ .type = PF_ART_ANCHOR_CALL, .off = _OUT(anchor_call), .cb = nlattr_get_string },
611ffbf2595SKristof Provost 	{ .type = PF_ART_RULE, .off = _OUT(rule), .arg = &rule_parser, .cb = nlattr_get_nested_ptr }
612ffbf2595SKristof Provost };
613ffbf2595SKristof Provost static const struct nlfield_parser nlf_p_addrule[] = {
614ffbf2595SKristof Provost };
615ffbf2595SKristof Provost #undef _IN
616ffbf2595SKristof Provost #undef _OUT
617ffbf2595SKristof Provost NL_DECLARE_PARSER(addrule_parser, struct genlmsghdr, nlf_p_addrule, nla_p_addrule);
618ffbf2595SKristof Provost 
619ffbf2595SKristof Provost static int
620ffbf2595SKristof Provost pf_handle_addrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
621ffbf2595SKristof Provost {
622ffbf2595SKristof Provost 	int error;
623ffbf2595SKristof Provost 	struct nl_parsed_addrule attrs = {};
624ffbf2595SKristof Provost 
625ffbf2595SKristof Provost 	attrs.rule = pf_krule_alloc();
626ffbf2595SKristof Provost 
627ffbf2595SKristof Provost 	error = nl_parse_nlmsg(hdr, &addrule_parser, npt, &attrs);
628ffbf2595SKristof Provost 	if (error != 0)
629ffbf2595SKristof Provost 		return (error);
630ffbf2595SKristof Provost 
631ffbf2595SKristof Provost 	error = pf_ioctl_addrule(attrs.rule, attrs.ticket, attrs.pool_ticket,
632ffbf2595SKristof Provost 	    attrs.anchor, attrs.anchor_call, nlp_get_cred(npt->nlp)->cr_uid,
633ffbf2595SKristof Provost 	    hdr->nlmsg_pid);
634ffbf2595SKristof Provost 
635ffbf2595SKristof Provost 	return (error);
636ffbf2595SKristof Provost }
637ffbf2595SKristof Provost 
638*44f323ecSKristof Provost struct nl_parsed_getrules {
639*44f323ecSKristof Provost 	char		*anchor;
640*44f323ecSKristof Provost 	uint8_t		 action;
641*44f323ecSKristof Provost };
642*44f323ecSKristof Provost #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
643*44f323ecSKristof Provost #define	_OUT(_field)	offsetof(struct pfioc_rule, _field)
644*44f323ecSKristof Provost static const struct nlattr_parser nla_p_getrules[] = {
645*44f323ecSKristof Provost 	{ .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
646*44f323ecSKristof Provost 	{ .type = PF_GR_ACTION, .off = _OUT(rule.action), .cb = nlattr_get_uint8 },
647*44f323ecSKristof Provost };
648*44f323ecSKristof Provost static const struct nlfield_parser nlf_p_getrules[] = {
649*44f323ecSKristof Provost };
650*44f323ecSKristof Provost NL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, nlf_p_getrules, nla_p_getrules);
651*44f323ecSKristof Provost 
652*44f323ecSKristof Provost static int
653*44f323ecSKristof Provost pf_handle_getrules(struct nlmsghdr *hdr, struct nl_pstate *npt)
654*44f323ecSKristof Provost {
655*44f323ecSKristof Provost 	struct pfioc_rule attrs = {};
656*44f323ecSKristof Provost 	int error;
657*44f323ecSKristof Provost 	struct nl_writer *nw = npt->nw;
658*44f323ecSKristof Provost 	struct genlmsghdr *ghdr_new;
659*44f323ecSKristof Provost 
660*44f323ecSKristof Provost 	error = nl_parse_nlmsg(hdr, &getrules_parser, npt, &attrs);
661*44f323ecSKristof Provost 	if (error != 0)
662*44f323ecSKristof Provost 		return (error);
663*44f323ecSKristof Provost 
664*44f323ecSKristof Provost 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
665*44f323ecSKristof Provost 		return (ENOMEM);
666*44f323ecSKristof Provost 
667*44f323ecSKristof Provost 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
668*44f323ecSKristof Provost 	ghdr_new->cmd = PFNL_CMD_GETRULES;
669*44f323ecSKristof Provost 	ghdr_new->version = 0;
670*44f323ecSKristof Provost 	ghdr_new->reserved = 0;
671*44f323ecSKristof Provost 
672*44f323ecSKristof Provost 	error = pf_ioctl_getrules(&attrs);
673*44f323ecSKristof Provost 	if (error != 0)
674*44f323ecSKristof Provost 		goto out;
675*44f323ecSKristof Provost 
676*44f323ecSKristof Provost 	nlattr_add_u32(nw, PF_GR_NR, attrs.nr);
677*44f323ecSKristof Provost 	nlattr_add_u32(nw, PF_GR_TICKET, attrs.ticket);
678*44f323ecSKristof Provost 
679*44f323ecSKristof Provost 	if (!nlmsg_end(nw)) {
680*44f323ecSKristof Provost 		error = ENOMEM;
681*44f323ecSKristof Provost 		goto out;
682*44f323ecSKristof Provost 	}
683*44f323ecSKristof Provost 
684*44f323ecSKristof Provost 	return (0);
685*44f323ecSKristof Provost 
686*44f323ecSKristof Provost out:
687*44f323ecSKristof Provost 	nlmsg_abort(nw);
688*44f323ecSKristof Provost 	return (error);
689*44f323ecSKristof Provost }
690*44f323ecSKristof Provost 
691*44f323ecSKristof Provost static const struct nlhdr_parser *all_parsers[] = {
692*44f323ecSKristof Provost 	&state_parser,
693*44f323ecSKristof Provost 	&addrule_parser,
694*44f323ecSKristof Provost 	&getrules_parser
695*44f323ecSKristof Provost };
6962cef6288SAlexander V. Chernikov 
6972cef6288SAlexander V. Chernikov static int family_id;
6982cef6288SAlexander V. Chernikov 
6992cef6288SAlexander V. Chernikov static const struct genl_cmd pf_cmds[] = {
7002cef6288SAlexander V. Chernikov 	{
7012cef6288SAlexander V. Chernikov 		.cmd_num = PFNL_CMD_GETSTATES,
7022cef6288SAlexander V. Chernikov 		.cmd_name = "GETSTATES",
7032cef6288SAlexander V. Chernikov 		.cmd_cb = pf_handle_getstates,
7042cef6288SAlexander V. Chernikov 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
7052cef6288SAlexander V. Chernikov 	},
706a7191e5dSKristof Provost 	{
707a7191e5dSKristof Provost 		.cmd_num = PFNL_CMD_GETCREATORS,
708a7191e5dSKristof Provost 		.cmd_name = "GETCREATORS",
709a7191e5dSKristof Provost 		.cmd_cb = pf_handle_getcreators,
710a7191e5dSKristof Provost 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
711a7191e5dSKristof Provost 	},
71281647eb6SKristof Provost 	{
71381647eb6SKristof Provost 		.cmd_num = PFNL_CMD_START,
71481647eb6SKristof Provost 		.cmd_name = "START",
71581647eb6SKristof Provost 		.cmd_cb = pf_handle_start,
71681647eb6SKristof Provost 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
71781647eb6SKristof Provost 	},
71881647eb6SKristof Provost 	{
71981647eb6SKristof Provost 		.cmd_num = PFNL_CMD_STOP,
72081647eb6SKristof Provost 		.cmd_name = "STOP",
72181647eb6SKristof Provost 		.cmd_cb = pf_handle_stop,
72281647eb6SKristof Provost 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
72381647eb6SKristof Provost 	},
724ffbf2595SKristof Provost 	{
725ffbf2595SKristof Provost 		.cmd_num = PFNL_CMD_ADDRULE,
726ffbf2595SKristof Provost 		.cmd_name = "ADDRULE",
727ffbf2595SKristof Provost 		.cmd_cb = pf_handle_addrule,
728ffbf2595SKristof Provost 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
729ffbf2595SKristof Provost 	},
730*44f323ecSKristof Provost 	{
731*44f323ecSKristof Provost 		.cmd_num = PFNL_CMD_GETRULES,
732*44f323ecSKristof Provost 		.cmd_name = "GETRULES",
733*44f323ecSKristof Provost 		.cmd_cb = pf_handle_getrules,
734*44f323ecSKristof Provost 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
735*44f323ecSKristof Provost 	},
7362cef6288SAlexander V. Chernikov };
7372cef6288SAlexander V. Chernikov 
7382cef6288SAlexander V. Chernikov void
7392cef6288SAlexander V. Chernikov pf_nl_register(void)
7402cef6288SAlexander V. Chernikov {
7412cef6288SAlexander V. Chernikov 	NL_VERIFY_PARSERS(all_parsers);
742ffbf2595SKristof Provost 
7432cef6288SAlexander V. Chernikov 	family_id = genl_register_family(PFNL_FAMILY_NAME, 0, 2, PFNL_CMD_MAX);
7442cef6288SAlexander V. Chernikov 	genl_register_cmds(PFNL_FAMILY_NAME, pf_cmds, NL_ARRAY_LEN(pf_cmds));
7452cef6288SAlexander V. Chernikov }
7462cef6288SAlexander V. Chernikov 
7472cef6288SAlexander V. Chernikov void
7482cef6288SAlexander V. Chernikov pf_nl_unregister(void)
7492cef6288SAlexander V. Chernikov {
7502cef6288SAlexander V. Chernikov 	genl_unregister_family(PFNL_FAMILY_NAME);
7512cef6288SAlexander V. Chernikov }
752