netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Corubba Smith <corubba@gmx.de>
To: netfilter-devel@vger.kernel.org
Subject: [PATCH ulogd2,v2 2/4] nfct: add network namespace support
Date: Tue, 25 Mar 2025 02:07:25 +0100	[thread overview]
Message-ID: <4c328ab1-b799-4e8b-a786-4329b40043a9@gmx.de> (raw)
In-Reply-To: <c5cd1c3a-3875-4352-8181-5081103f96f6@gmx.de>

Allow the plugin to fetch data from a different network namespace. This
is possible by changing the network namespace before opening the netlink
socket, and immediately changing back to the original network namespace
once the socket is open. The number of nfct_open usages here warranted a
dedicated wrapper function.

If changing back to the original network namespace fails, ulogd will
log an error, but continue to run in a different network namespace than
it was started in, which may cause unexpected behaviour. But I don't see
a way to properly "escalate" it such that ulogd aborts entirely.

Also slightly adjust the error log messages to specify which socket
failed to open.

Signed-off-by: Corubba Smith <corubba@gmx.de>
---
 input/flow/ulogd_inpflow_NFCT.c | 81 +++++++++++++++++++++++++++------
 ulogd.conf.in                   |  1 +
 2 files changed, 69 insertions(+), 13 deletions(-)

diff --git a/input/flow/ulogd_inpflow_NFCT.c b/input/flow/ulogd_inpflow_NFCT.c
index 93edb76..7168b24 100644
--- a/input/flow/ulogd_inpflow_NFCT.c
+++ b/input/flow/ulogd_inpflow_NFCT.c
@@ -45,6 +45,7 @@
 #include <ulogd/timer.h>
 #include <ulogd/ipfix_protocol.h>
 #include <ulogd/addr.h>
+#include <ulogd/namespace.h>

 #include <libnetfilter_conntrack/libnetfilter_conntrack.h>

@@ -78,7 +79,7 @@ struct nfct_pluginstance {
 #define EVENT_MASK	NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY

 static struct config_keyset nfct_kset = {
-	.num_ces = 12,
+	.num_ces = 13,
 	.ces = {
 		{
 			.key	 = "pollinterval",
@@ -149,6 +150,11 @@ static struct config_keyset nfct_kset = {
 			.type	 = CONFIG_TYPE_STRING,
 			.options = CONFIG_OPT_NONE,
 		},
+		{
+			.key     = "network_namespace_path",
+			.type    = CONFIG_TYPE_STRING,
+			.options = CONFIG_OPT_NONE,
+		},
 	},
 };
 #define pollint_ce(x)	(x->ces[0])
@@ -163,6 +169,7 @@ static struct config_keyset nfct_kset = {
 #define src_filter_ce(x)	((x)->ces[9])
 #define dst_filter_ce(x)	((x)->ces[10])
 #define proto_filter_ce(x)	((x)->ces[11])
+#define network_namespace_path_ce(x)	((x)->ces[12])

 enum nfct_keys {
 	NFCT_ORIG_IP_SADDR = 0,
@@ -979,6 +986,54 @@ static int read_cb_ovh(int fd, unsigned int what, void *param)
 	return 0;
 }

+/**
+ * nfct_open_in_netns() - Open conntrack netlink socket in a namespace
+ * @subscriptions: ctnetlink groups to subscribe to events
+ * @target_netns_path: path to the network namespace, can be NULL
+ *
+ * On error, NULL is returned and errno is explicitly set.
+ */
+struct nfct_handle *nfct_open_in_netns(unsigned int subscriptions,
+                                       const char *const target_netns_path)
+{
+	struct nfct_handle *result = NULL;
+	int source_netns_fd = -1;
+
+	if ((target_netns_path != NULL) &&
+	    (strlen(target_netns_path) > 0) &&
+	    (join_netns_path(target_netns_path, &source_netns_fd) != ULOGD_IRET_OK)) {
+		ulogd_log(ULOGD_FATAL, "error joining target network "
+		                       "namespace\n");
+		goto err_tns;
+	}
+
+	result = nfct_open(NFNL_SUBSYS_CTNETLINK, subscriptions);
+	if (result == NULL) {
+		ulogd_log(ULOGD_FATAL, "error opening ctnetlink: %s\n",
+		                       strerror(errno));
+		goto err_nfct;
+	}
+
+	if ((target_netns_path != NULL) &&
+	    (strlen(target_netns_path) > 0) &&
+	    (join_netns_fd(source_netns_fd, NULL) != ULOGD_IRET_OK)) {
+		ulogd_log(ULOGD_FATAL, "error joining source network "
+		                       "namespace\n");
+		goto err_sns;
+	}
+	source_netns_fd = -1;
+
+	return result;
+
+err_sns:
+	nfct_close(result);
+err_nfct:
+	if (source_netns_fd >= 0)
+		close(source_netns_fd);
+err_tns:
+	return NULL;
+}
+
 static int
 dump_reset_handler(enum nf_conntrack_msg_type type,
 		   struct nf_conntrack *ct, void *data)
@@ -1025,7 +1080,7 @@ static void get_ctr_zero(struct ulogd_pluginstance *upi)
 	struct nfct_handle *h;
 	int family = AF_UNSPEC;

-	h = nfct_open(CONNTRACK, 0);
+	h = nfct_open_in_netns(0, network_namespace_path_ce(upi->config_kset).u.string);
 	if (h == NULL) {
 		ulogd_log(ULOGD_FATAL, "Cannot dump and reset counters\n");
 		return;
@@ -1301,10 +1356,10 @@ static int constructor_nfct_events(struct ulogd_pluginstance *upi)
 			(struct nfct_pluginstance *)upi->private;


-	cpi->cth = nfct_open(NFNL_SUBSYS_CTNETLINK,
-			     eventmask_ce(upi->config_kset).u.value);
+	cpi->cth = nfct_open_in_netns(eventmask_ce(upi->config_kset).u.value,
+	                              network_namespace_path_ce(upi->config_kset).u.string);
 	if (!cpi->cth) {
-		ulogd_log(ULOGD_FATAL, "error opening ctnetlink\n");
+		ulogd_log(ULOGD_FATAL, "error opening event netlink socket\n");
 		goto err_cth;
 	}

@@ -1372,9 +1427,9 @@ static int constructor_nfct_events(struct ulogd_pluginstance *upi)
 		/* populate the hashtable: we use a disposable handler, we
 		 * may hit overrun if we use cpi->cth. This ensures that the
 		 * initial dump is successful. */
-		h = nfct_open(CONNTRACK, 0);
+		h = nfct_open_in_netns(0, network_namespace_path_ce(upi->config_kset).u.string);
 		if (!h) {
-			ulogd_log(ULOGD_FATAL, "error opening ctnetlink\n");
+			ulogd_log(ULOGD_FATAL, "error opening initial-fill netlink socket\n");
 			goto err_ovh;
 		}
 		nfct_callback_register(h, NFCT_T_ALL,
@@ -1384,9 +1439,9 @@ static int constructor_nfct_events(struct ulogd_pluginstance *upi)

 		/* the overrun handler only make sense with the hashtable,
 		 * if we hit overrun, we resync with ther kernel table. */
-		cpi->ovh = nfct_open(NFNL_SUBSYS_CTNETLINK, 0);
+		cpi->ovh = nfct_open_in_netns(0, network_namespace_path_ce(upi->config_kset).u.string);
 		if (!cpi->ovh) {
-			ulogd_log(ULOGD_FATAL, "error opening ctnetlink\n");
+			ulogd_log(ULOGD_FATAL, "error opening overrun-read netlink socket\n");
 			goto err_ovh;
 		}

@@ -1403,9 +1458,9 @@ static int constructor_nfct_events(struct ulogd_pluginstance *upi)
 		ulogd_register_fd(&cpi->nfct_ov);

 		/* we use this to purge old entries during overruns.*/
-		cpi->pgh = nfct_open(NFNL_SUBSYS_CTNETLINK, 0);
+		cpi->pgh = nfct_open_in_netns(0, network_namespace_path_ce(upi->config_kset).u.string);
 		if (!cpi->pgh) {
-			ulogd_log(ULOGD_FATAL, "error opening ctnetlink\n");
+			ulogd_log(ULOGD_FATAL, "error opening overrun-purge netlink socket\n");
 			goto err_pgh;
 		}
 	}
@@ -1438,9 +1493,9 @@ static int constructor_nfct_polling(struct ulogd_pluginstance *upi)
 		goto err;
 	}

-	cpi->pgh = nfct_open(NFNL_SUBSYS_CTNETLINK, 0);
+	cpi->pgh = nfct_open_in_netns(0, network_namespace_path_ce(upi->config_kset).u.string);
 	if (!cpi->pgh) {
-		ulogd_log(ULOGD_FATAL, "error opening ctnetlink\n");
+		ulogd_log(ULOGD_FATAL, "error opening polling netlink socket\n");
 		goto err;
 	}
 	nfct_callback_register(cpi->pgh, NFCT_T_ALL, &polling_handler, upi);
diff --git a/ulogd.conf.in b/ulogd.conf.in
index 9a04bf7..f7e3fa3 100644
--- a/ulogd.conf.in
+++ b/ulogd.conf.in
@@ -139,6 +139,7 @@ logfile="/var/log/ulogd.log"
 #netlink_socket_buffer_size=217088
 #netlink_socket_buffer_maxsize=1085440
 #reliable=1 # enable reliable flow-based logging (may drop packets)
+#network_namespace_path=/run/netns/other # import flows from a different network namespace
 hash_enable=0

 # Logging of system packet through NFLOG
--
2.49.0

  reply	other threads:[~2025-03-25  1:07 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-25  1:05 [PATCH ulogd2,v2 1/4] ulogd: add linux namespace helper Corubba Smith
2025-03-25  1:07 ` Corubba Smith [this message]
2025-03-25  1:08 ` [PATCH ulogd2,v2 3/4] nflog: add network namespace support Corubba Smith
2025-03-26 19:27   ` Florian Westphal
2025-03-25  1:09 ` [PATCH ulogd2,v2 4/4] nfacct: " Corubba Smith
2025-03-26 19:23 ` [PATCH ulogd2,v2 1/4] ulogd: add linux namespace helper Florian Westphal
2025-04-10 20:02   ` Corubba Smith
2025-04-11 20:06     ` Florian Westphal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4c328ab1-b799-4e8b-a786-4329b40043a9@gmx.de \
    --to=corubba@gmx.de \
    --cc=netfilter-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).