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 {