* [PATCH nft 1/2] src: mnl: prepare for listing all device netdev device hooks
2024-08-20 22:12 [PATCH 0/2 nft] mnl: query netdevices for in/egress hooks Florian Westphal
@ 2024-08-20 22:12 ` Florian Westphal
2024-08-20 22:12 ` [PATCH nft 2/2] src: mnl: always dump all netdev hooks if no interface name was given Florian Westphal
2024-08-21 8:48 ` [PATCH 0/2 nft] mnl: query netdevices for in/egress hooks Pablo Neira Ayuso
2 siblings, 0 replies; 4+ messages in thread
From: Florian Westphal @ 2024-08-20 22:12 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
Change output foramt slightly so device name is included for netdev
family.
% nft list hooks netdev device eth0
family netdev {
hook ingress device eth0 {
0000000000 chain inet ingress in_public [nf_tables]
0000000000 chain netdev ingress in_public [nf_tables]
}
hook egress device eth0 {
0000000000 chain netdev ingress out_public [nf_tables]
}
}
Signed-off-by: Florian Westphal <fw@strlen.de>
---
src/mnl.c | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/src/mnl.c b/src/mnl.c
index 3cacb47e7242..e585241d9395 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -45,6 +45,7 @@ struct basehook {
const char *hookfn;
const char *table;
const char *chain;
+ const char *devname;
int family;
int chain_family;
uint32_t num;
@@ -2179,9 +2180,24 @@ static void basehook_free(struct basehook *b)
free_const(b->hookfn);
free_const(b->chain);
free_const(b->table);
+ free_const(b->devname);
free(b);
}
+static bool basehook_eq(const struct basehook *prev, const struct basehook *hook)
+{
+ if (prev->num != hook->num)
+ return false;
+
+ if (prev->devname != NULL && hook->devname != NULL)
+ return strcmp(prev->devname, hook->devname) == 0;
+
+ if (prev->devname == NULL && prev->devname == NULL)
+ return true;
+
+ return false;
+}
+
static void basehook_list_add_tail(struct basehook *b, struct list_head *head)
{
struct basehook *hook;
@@ -2310,6 +2326,7 @@ static int dump_nf_attr_bpf_cb(const struct nlattr *attr, void *data)
struct dump_nf_hook_data {
struct list_head *hook_list;
+ const char *devname;
int family;
};
@@ -2331,6 +2348,7 @@ static int dump_nf_hooks(const struct nlmsghdr *nlh, void *_data)
hook = basehook_alloc();
hook->prio = ntohl(mnl_attr_get_u32(tb[NFNLA_HOOK_PRIORITY]));
+ hook->devname = data->devname ? xstrdup(data->devname) : NULL;
if (tb[NFNLA_HOOK_FUNCTION_NAME])
hook->hookfn = xstrdup(mnl_attr_get_str(tb[NFNLA_HOOK_FUNCTION_NAME]));
@@ -2420,6 +2438,7 @@ static int __mnl_nft_dump_nf_hooks(struct netlink_ctx *ctx, uint8_t query_family
char buf[MNL_SOCKET_BUFFER_SIZE];
struct dump_nf_hook_data data = {
.hook_list = hook_list,
+ .devname = devname,
.family = query_family,
};
struct nlmsghdr *nlh;
@@ -2459,7 +2478,7 @@ static void print_hooks(struct netlink_ctx *ctx, int family, struct list_head *h
continue;
if (prev) {
- if (prev->num == hook->num) {
+ if (basehook_eq(prev, hook)) {
fprintf(fp, "\n");
same = true;
} else {
@@ -2472,8 +2491,12 @@ static void print_hooks(struct netlink_ctx *ctx, int family, struct list_head *h
prev = hook;
if (!same) {
- fprintf(fp, "\thook %s {\n",
- hooknum2str(family, hook->num));
+ if (hook->devname)
+ fprintf(fp, "\thook %s device %s {\n",
+ hooknum2str(family, hook->num), hook->devname);
+ else
+ fprintf(fp, "\thook %s {\n",
+ hooknum2str(family, hook->num));
}
prio = hook->prio;
--
2.44.2
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH nft 2/2] src: mnl: always dump all netdev hooks if no interface name was given
2024-08-20 22:12 [PATCH 0/2 nft] mnl: query netdevices for in/egress hooks Florian Westphal
2024-08-20 22:12 ` [PATCH nft 1/2] src: mnl: prepare for listing all device netdev device hooks Florian Westphal
@ 2024-08-20 22:12 ` Florian Westphal
2024-08-21 8:48 ` [PATCH 0/2 nft] mnl: query netdevices for in/egress hooks Pablo Neira Ayuso
2 siblings, 0 replies; 4+ messages in thread
From: Florian Westphal @ 2024-08-20 22:12 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
Instead of not returning any results for
nft list hooks netdev
Iterate all interfaces and then query all of them.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
doc/additional-commands.txt | 8 ++++----
include/iface.h | 2 ++
src/iface.c | 17 +++++++++++++++++
src/mnl.c | 29 ++++++++++++++++++++++-------
4 files changed, 45 insertions(+), 11 deletions(-)
diff --git a/doc/additional-commands.txt b/doc/additional-commands.txt
index 9ad338f8c7d1..0f96fc354007 100644
--- a/doc/additional-commands.txt
+++ b/doc/additional-commands.txt
@@ -8,13 +8,13 @@ registered implicitly by kernel modules such as nf_conntrack. +
[verse]
____
*list hooks* ['family']
-*list hooks netdev device* 'DEVICE_NAME'
+*list hooks netdev [ device* 'DEVICE_NAME' ]
____
*list hooks* is enough to display everything that is active
-on the system, however, it does currently omit hooks that are
-tied to a specific network device (netdev family). To obtain
-those, the network device needs to be queried by name.
+on the system. Hooks in the netdev family are tied to a network
+device. If no device name is given, nft will query all network
+devices in the current network namespace.
Example Usage:
.List all active netfilter hooks in either the ip or ip6 stack
diff --git a/include/iface.h b/include/iface.h
index f41ee8be6c89..786b1dfc8f8f 100644
--- a/include/iface.h
+++ b/include/iface.h
@@ -2,6 +2,7 @@
#define _NFTABLES_IFACE_H_
#include <net/if.h>
+#include <list.h>
struct iface {
struct list_head list;
@@ -15,4 +16,5 @@ char *nft_if_indextoname(unsigned int ifindex, char *name);
void iface_cache_update(void);
void iface_cache_release(void);
+const struct iface *iface_cache_get_next_entry(const struct iface *prev);
#endif
diff --git a/src/iface.c b/src/iface.c
index 428acaae2eac..a85341a1703a 100644
--- a/src/iface.c
+++ b/src/iface.c
@@ -171,3 +171,20 @@ char *nft_if_indextoname(unsigned int ifindex, char *name)
}
return NULL;
}
+
+const struct iface *iface_cache_get_next_entry(const struct iface *prev)
+{
+ if (!iface_cache_init)
+ iface_cache_update();
+
+ if (list_empty(&iface_list))
+ return NULL;
+
+ if (!prev)
+ return list_first_entry(&iface_list, struct iface, list);
+
+ if (list_is_last(&prev->list, &iface_list))
+ return NULL;
+
+ return list_next_entry(prev, list);
+}
diff --git a/src/mnl.c b/src/mnl.c
index e585241d9395..12e145204ef5 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -9,6 +9,7 @@
*/
#include <nft.h>
+#include <iface.h>
#include <libmnl/libmnl.h>
#include <libnftnl/common.h>
@@ -2205,7 +2206,7 @@ static void basehook_list_add_tail(struct basehook *b, struct list_head *head)
list_for_each_entry(hook, head, list) {
if (hook->family != b->family)
continue;
- if (hook->num != b->num)
+ if (!basehook_eq(hook, b))
continue;
if (hook->prio < b->prio)
continue;
@@ -2591,11 +2592,9 @@ int mnl_nft_dump_nf_hooks(struct netlink_ctx *ctx, int family, const char *devna
if (tmp == 0)
ret = 0;
- if (devname) {
- tmp = mnl_nft_dump_nf_hooks(ctx, NFPROTO_NETDEV, devname);
- if (tmp == 0)
- ret = 0;
- }
+ tmp = mnl_nft_dump_nf_hooks(ctx, NFPROTO_NETDEV, devname);
+ if (tmp == 0)
+ ret = 0;
return ret;
case NFPROTO_INET:
@@ -2622,7 +2621,23 @@ int mnl_nft_dump_nf_hooks(struct netlink_ctx *ctx, int family, const char *devna
ret = mnl_nft_dump_nf_arp(ctx, family, devname, &hook_list);
break;
case NFPROTO_NETDEV:
- ret = mnl_nft_dump_nf_netdev(ctx, family, devname, &hook_list);
+ if (devname) {
+ ret = mnl_nft_dump_nf_netdev(ctx, family, devname, &hook_list);
+ } else {
+ const struct iface *iface;
+
+ iface = iface_cache_get_next_entry(NULL);
+ ret = 0;
+
+ while (iface) {
+ tmp = mnl_nft_dump_nf_netdev(ctx, family, iface->name, &hook_list);
+ if (tmp == 0)
+ ret = 0;
+
+ iface = iface_cache_get_next_entry(iface);
+ }
+ }
+
break;
}
--
2.44.2
^ permalink raw reply related [flat|nested] 4+ messages in thread