git: 044eef6ab9cf - main - pf: support basic filters for state listing
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 23 Oct 2023 15:10:34 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=044eef6ab9cf1730d21c5f5dffebb0cd35fb5bbf commit 044eef6ab9cf1730d21c5f5dffebb0cd35fb5bbf Author: Kristof Provost <kp@FreeBSD.org> AuthorDate: 2023-10-16 14:47:22 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2023-10-23 14:24:52 +0000 pf: support basic filters for state listing Allow users(pace) to specify a protocol, interface, address family and/ or address and mask, allowing the state listing to be pre-filtered in the kernel. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D42280 --- lib/libpfctl/libpfctl.c | 18 ++++++++++++++++-- lib/libpfctl/libpfctl.h | 9 +++++++++ sbin/pfctl/pfctl.c | 9 +++++---- sys/netpfil/pf/pf_nl.c | 43 ++++++++++++++++++++++++++++++++++++++----- sys/netpfil/pf/pf_nl.h | 2 ++ 5 files changed, 70 insertions(+), 11 deletions(-) diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c index 3865dc85aea1..25bb77d9c021 100644 --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -1342,7 +1342,7 @@ static const struct snl_hdr_parser *all_parsers[] = { }; static int -pfctl_get_states_nl(struct snl_state *ss, pfctl_get_state_fn f, void *arg) +pfctl_get_states_nl(struct pfctl_state_filter *filter, struct snl_state *ss, pfctl_get_state_fn f, void *arg) { SNL_VERIFY_PARSERS(all_parsers); int family_id = snl_get_genl_family(ss, PFNL_FAMILY_NAME); @@ -1354,7 +1354,14 @@ pfctl_get_states_nl(struct snl_state *ss, pfctl_get_state_fn f, void *arg) snl_init_writer(ss, &nw); hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETSTATES); hdr->nlmsg_flags |= NLM_F_DUMP; + snl_add_msg_attr_string(&nw, PF_ST_IFNAME, filter->ifname); + snl_add_msg_attr_u16(&nw, PF_ST_PROTO, filter->proto); + snl_add_msg_attr_u8(&nw, PF_ST_AF, filter->af); + snl_add_msg_attr_ip6(&nw, PF_ST_FILTER_ADDR, &filter->addr.v6); + snl_add_msg_attr_ip6(&nw, PF_ST_FILTER_MASK, &filter->mask.v6); + hdr = snl_finalize_msg(&nw); + uint32_t seq_id = hdr->nlmsg_seq; snl_send_message(ss, hdr); @@ -1379,12 +1386,19 @@ pfctl_get_states_nl(struct snl_state *ss, pfctl_get_state_fn f, void *arg) int pfctl_get_states_iter(pfctl_get_state_fn f, void *arg) +{ + struct pfctl_state_filter filter = {}; + return (pfctl_get_filtered_states_iter(&filter, f, arg)); +} + +int +pfctl_get_filtered_states_iter(struct pfctl_state_filter *filter, pfctl_get_state_fn f, void *arg) { struct snl_state ss = {}; int error; snl_init(&ss, NETLINK_GENERIC); - error = pfctl_get_states_nl(&ss, f, arg); + error = pfctl_get_states_nl(filter, &ss, f, arg); snl_free(&ss); return (error); diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h index 06cd25e82c08..ad6fde89771c 100644 --- a/lib/libpfctl/libpfctl.h +++ b/lib/libpfctl/libpfctl.h @@ -415,8 +415,17 @@ int pfctl_add_rule(int dev, const struct pfctl_rule *r, uint32_t pool_ticket); int pfctl_set_keepcounters(int dev, bool keep); int pfctl_get_creatorids(uint32_t *creators, size_t *len); + +struct pfctl_state_filter { + char ifname[IFNAMSIZ]; + uint16_t proto; + sa_family_t af; + struct pf_addr addr; + struct pf_addr mask; +}; typedef int (*pfctl_get_state_fn)(struct pfctl_state *, void *); int pfctl_get_states_iter(pfctl_get_state_fn f, void *arg); +int pfctl_get_filtered_states_iter(struct pfctl_state_filter *filter, pfctl_get_state_fn f, void *arg); int pfctl_get_states(int dev, struct pfctl_states *states); void pfctl_free_states(struct pfctl_states *states); int pfctl_clear_states(int dev, const struct pfctl_kill *kill, diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 56b1d28c6fd6..c3f3d82ff767 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -1529,9 +1529,6 @@ pfctl_show_state(struct pfctl_state *s, void *arg) { struct pfctl_show_state_arg *a = (struct pfctl_show_state_arg *)arg; - if (a->iface != NULL && strcmp(s->ifname, a->iface)) - return (0); - if (a->dotitle) { pfctl_print_title("STATES:"); a->dotitle = 0; @@ -1545,12 +1542,16 @@ int pfctl_show_states(int dev, const char *iface, int opts) { struct pfctl_show_state_arg arg; + struct pfctl_state_filter filter = {}; + + if (iface != NULL) + strncpy(filter.ifname, iface, IFNAMSIZ); arg.opts = opts; arg.dotitle = opts & PF_OPT_SHOWALL; arg.iface = iface; - if (pfctl_get_states_iter(pfctl_show_state, &arg)) + if (pfctl_get_filtered_states_iter(&filter, pfctl_show_state, &arg)) return (-1); return (0); diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c index d5d294134b1f..53ff5d031ed6 100644 --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -52,6 +52,11 @@ struct nl_parsed_state { uint8_t version; uint32_t id; uint32_t creatorid; + char ifname[IFNAMSIZ]; + uint16_t proto; + sa_family_t af; + struct pf_addr addr; + struct pf_addr mask; }; #define _IN(_field) offsetof(struct genlmsghdr, _field) @@ -59,6 +64,11 @@ struct nl_parsed_state { static const struct nlattr_parser nla_p_state[] = { { .type = PF_ST_ID, .off = _OUT(id), .cb = nlattr_get_uint32 }, { .type = PF_ST_CREATORID, .off = _OUT(creatorid), .cb = nlattr_get_uint32 }, + { .type = PF_ST_IFNAME, .arg = (const void *)IFNAMSIZ, .off = _OUT(ifname), .cb = nlattr_get_chara }, + { .type = PF_ST_AF, .off = _OUT(proto), .cb = nlattr_get_uint8 }, + { .type = PF_ST_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint16 }, + { .type = PF_ST_FILTER_ADDR, .off = _OUT(addr), .cb = nlattr_get_in6_addr }, + { .type = PF_ST_FILTER_MASK, .off = _OUT(mask), .cb = nlattr_get_in6_addr }, }; static const struct nlfield_parser nlf_p_generic[] = { { .off_in = _IN(version), .off_out = _OUT(version), .cb = nlf_get_u8 }, @@ -217,11 +227,34 @@ handle_dumpstates(struct nlpcb *nlp, struct nl_parsed_state *attrs, PF_HASHROW_LOCK(ih); LIST_FOREACH(s, &ih->states, entry) { - if (s->timeout != PFTM_UNLINKED) { - error = dump_state(nlp, hdr, s, npt); - if (error != 0) - break; - } + sa_family_t af = s->key[PF_SK_WIRE]->af; + + if (s->timeout == PFTM_UNLINKED) + continue; + + /* Filter */ + if (attrs->creatorid != 0 && s->creatorid != attrs->creatorid) + continue; + if (attrs->ifname[0] != 0 && + strncmp(attrs->ifname, s->kif->pfik_name, IFNAMSIZ) != 0) + continue; + if (attrs->proto != 0 && s->key[PF_SK_WIRE]->proto != attrs->proto) + continue; + if (attrs->af != 0 && af != attrs->af) + continue; + if (pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[0], + &attrs->mask, &attrs->addr, af) && + pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[1], + &attrs->mask, &attrs->addr, af) && + pf_match_addr(1, &s->key[PF_SK_STACK]->addr[0], + &attrs->mask, &attrs->addr, af) && + pf_match_addr(1, &s->key[PF_SK_STACK]->addr[1], + &attrs->mask, &attrs->addr, af)) + continue; + + error = dump_state(nlp, hdr, s, npt); + if (error != 0) + break; } PF_HASHROW_UNLOCK(ih); } diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h index d936044c0d7d..8265ae1d1bfa 100644 --- a/sys/netpfil/pf/pf_nl.h +++ b/sys/netpfil/pf/pf_nl.h @@ -97,6 +97,8 @@ enum pfstate_type_t { PF_ST_SYNC_FLAGS = 26, /* u8 */ PF_ST_UPDATES = 27, /* u8 */ PF_ST_VERSION = 28, /* u64 */ + PF_ST_FILTER_ADDR = 29, /* in6_addr */ + PF_ST_FILTER_MASK = 30, /* in6_addr */ }; enum pf_addr_type_t {