]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: mnl: always dump all netdev hooks if no interface name was given
authorFlorian Westphal <fw@strlen.de>
Tue, 20 Aug 2024 22:12:27 +0000 (00:12 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 1 Sep 2025 20:47:56 +0000 (22:47 +0200)
commit db70959a5ccf2952b218f51c3d529e186a5a43bb upstream.

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 [new file with mode: 0644]
include/iface.h
src/iface.c
src/mnl.c

diff --git a/doc/additional-commands.txt b/doc/additional-commands.txt
new file mode 100644 (file)
index 0000000..2ebc299
--- /dev/null
@@ -0,0 +1,116 @@
+LIST HOOKS
+~~~~~~~~~~
+
+This shows the list of functions that have been registered for the
+given protocol family, including functions that have been
+registered implicitly by kernel modules such as nf_conntrack. +
+
+[verse]
+____
+*list hooks* ['family']
+*list hooks netdev* [ *device* 'DEVICE_NAME' ]
+____
+
+*list hooks* is enough to display everything that is active
+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
+--------------------------------------------------------------
+% nft list hooks inet
+family ip {
+        hook prerouting {
+                -0000000400 ipv4_conntrack_defrag [nf_defrag_ipv4]
+                -0000000200 ipv4_conntrack_in [nf_conntrack]
+                -0000000100 nf_nat_ipv4_pre_routing [nf_nat]
+        }
+        hook input {
+                 0000000000 chain inet filter input [nf_tables]
+                +0000000100 nf_nat_ipv4_local_in [nf_nat]
+[..]
+--------------------------------------------------------------
+
+The above shows a host that has nat, conntrack and ipv4 packet
+defragmentation enabled.
+For each hook location for the queried family a list of active hooks
+using the format +
+
+*priority* *identifier* [*module_name*]
+
+will be shown.
+
+The *priority* value dictates the order in which the hooks are called.
+The list is sorted, the lowest number is run first.
+
+The priority value of hooks registered by the kernel cannot be changed.
+For basechains registered by nftables, this value corresponds to the
+*priority* value specified in the base chain definition.
+
+After the numerical value, information about the hook is shown.
+For basechains defined in nftables this includes the table family,
+the table name and the basechains name.
+For hooks coming from kernel modules, the function name is used
+instead.
+
+If a *module name* is given, the hook was registered by the kernel
+module with this name.  You can use 'modinfo *module name*' to
+obtain more information about the module.
+
+This functionality requires a kernel built with the option +
+CONFIG_NETFILTER_NETLINK_HOOK
+enabled, either as a module or builtin. The module is named
+*nfnetlink_hook*.
+
+MONITOR
+~~~~~~~
+The monitor command allows you to listen to Netlink events produced by the
+nf_tables subsystem. These are either related to creation and deletion of
+objects or to packets for which *meta nftrace* was enabled. When they
+occur, nft will print to stdout the monitored events in either JSON or
+native nft format. +
+
+[verse]
+____
+*monitor* [*new* | *destroy*] 'MONITOR_OBJECT'
+*monitor* *trace*
+
+'MONITOR_OBJECT' := *tables* | *chains* | *sets* | *rules* | *elements* | *ruleset*
+____
+
+To filter events related to a concrete object, use one of the keywords in
+'MONITOR_OBJECT'.
+
+To filter events related to a concrete action, use keyword *new* or *destroy*.
+
+The second form of invocation takes no further options and exclusively prints
+events generated for packets with *nftrace* enabled.
+
+Hit ^C to finish the monitor operation.
+
+.Listen to all events, report in native nft format
+--------------------------------------------------
+% nft monitor
+--------------------------------------------------
+
+.Listen to deleted rules, report in JSON format
+-----------------------------------------------
+% nft -j monitor destroy rules
+-----------------------------------------------
+
+.Listen to both new and destroyed chains, in native nft format
+-----------------------------------------------------------------
+% nft monitor chains
+-------------------------------
+
+.Listen to ruleset events such as table, chain, rule, set, counters and quotas, in native nft format
+----------------------------------------------------------------------------------------------------
+% nft monitor ruleset
+---------------------
+
+.Trace incoming packets from host 10.0.0.1
+------------------------------------------
+% nft add rule filter input ip saddr 10.0.0.1 meta nftrace set 1
+% nft monitor trace
+------------------------------------------
index f41ee8be6c8956e3c4c6955762f404db1ad67db0..b61e974f22f42e78b1eb193cb9c1c5e48894721a 100644 (file)
@@ -2,6 +2,8 @@
 #define _NFTABLES_IFACE_H_
 
 #include <net/if.h>
+#include <list.h>
+#include <stdint.h>
 
 struct iface {
        struct list_head        list;
@@ -15,4 +17,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
index 3647778c1f0d7d1db025c47d3fb48e24923cf4a8..a67cb2985c01355165f15758f2159df9a6e33dfa 100644 (file)
@@ -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);
+}
index 311c920defc5e14fbb4dbaec04bb611c9d820f1e..9cc609b3e49bf34787d65ac0fbb9f4940bb41a56 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -8,6 +8,8 @@
  * Development of this code funded by Astaro AG (http://www.astaro.com/)
  */
 
+#include <iface.h>
+
 #include <libmnl/libmnl.h>
 #include <libnftnl/common.h>
 #include <libnftnl/ruleset.h>
@@ -2159,7 +2161,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;
@@ -2504,11 +2506,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:
@@ -2535,7 +2535,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;
        }