public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: Stefano Brivio <sbrivio@redhat.com>, passt-dev@passt.top
Cc: David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH v3 09/14] conf, fwd: Check forwarding table for conflicting rules
Date: Thu,  8 Jan 2026 13:29:43 +1100	[thread overview]
Message-ID: <20260108022948.2657573-10-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20260108022948.2657573-1-david@gibson.dropbear.id.au>

It's possible for a user to supply conflicting forwarding parameters, e.g.
    $ pasta -t 80:8080 -t 127.0.0.1/80:8888

We give a warning in this case, but it's based on the legacy
forwarding bitmaps.  This is too strict, because it will also warn on
cases that shouldn't conflict because they use different addresses,
e.g.
    $ pasta -t 192.0.2.1/80:8080 127.0.0.1/80:8888

Theoretically, it's also too loose because it won't take into account
auto-scan forwarding rules.  We can't hit that in practice now,
because we only ever have one auto-scan rule and nothing else, but we
want to remove that restriction in future.

Replace the bitmap based check with a check based on actually scanning
the forwarding rules for conflicts.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 conf.c  |  5 -----
 fwd.c   | 21 ++++++++++++++++++++-
 inany.c | 19 +++++++++++++++++++
 inany.h |  1 +
 4 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/conf.c b/conf.c
index 725cf88b..e8d6d5d9 100644
--- a/conf.c
+++ b/conf.c
@@ -172,11 +172,6 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
 		for (i = base; i <= last; i++) {
 			if (exclude && bitmap_isset(exclude, i))
 				break;
-
-			if (bitmap_isset(fwd->map, i)) {
-				warn(
-"Altering mapping of already mapped port number: %s", optarg);
-			}
 		}
 
 		if ((optname == 'T' || optname == 'U') && c->no_bindtodevice) {
diff --git a/fwd.c b/fwd.c
index 70ef73a3..5208155b 100644
--- a/fwd.c
+++ b/fwd.c
@@ -348,7 +348,7 @@ void fwd_rule_add(struct fwd_ports *fwd, uint8_t flags,
 	const uint8_t allowed_flags = FWD_WEAK | FWD_SCAN;
 	unsigned num = (unsigned)last - first + 1;
 	struct fwd_rule *new;
-	unsigned port;
+	unsigned i, port;
 
 	ASSERT(!(flags & ~allowed_flags));
 
@@ -357,6 +357,25 @@ void fwd_rule_add(struct fwd_ports *fwd, uint8_t flags,
 	if ((fwd->listen_sock_count + num) > ARRAY_SIZE(fwd->listen_socks))
 		die("Too many listening sockets");
 
+	/* Check for any conflicting entries */
+	for (i = 0; i < fwd->count; i++) {
+		char newstr[INANY_ADDRSTRLEN], rulestr[INANY_ADDRSTRLEN];
+		struct fwd_rule *rule = &fwd->rules[i];
+
+		if (!inany_matches(addr, fwd_rule_addr(rule)))
+			/* Non-conflicting addresses */
+			continue;
+
+		if (last < rule->first || rule->last < first)
+			/* Port ranges don't overlap */
+			continue;
+
+		die("Forwarding configuration conflict: %s/%u-%u versus %s/%u-%u",
+		    inany_ntop(addr, newstr, sizeof(newstr)), first, last,
+		    inany_ntop(fwd_rule_addr(rule), rulestr, sizeof(rulestr)),
+		    rule->first, rule->last);
+	}
+
 	new = &fwd->rules[fwd->count++];
 	new->flags = flags;
 
diff --git a/inany.c b/inany.c
index 87a4d8b6..a8c44237 100644
--- a/inany.c
+++ b/inany.c
@@ -21,6 +21,25 @@
 const union inany_addr inany_loopback4 = INANY_INIT4(IN4ADDR_LOOPBACK_INIT);
 const union inany_addr inany_any4 = INANY_INIT4(IN4ADDR_ANY_INIT);
 
+/** inany_matches - Do two addresses match
+ * @a, @b:	IPv[46] addresses (NULL for 0.0.0.0 & ::)
+ *
+ * Return: true if they match, false otherwise
+ *
+ * Addresses match themselves, but also with unspecified addresses of the same
+ * family.
+ */
+bool inany_matches(const union inany_addr *a, const union inany_addr *b)
+{
+	if (!a || !b)
+		return true;
+
+	if (inany_is_unspecified(a) || inany_is_unspecified(b))
+		return !!inany_v4(a) == !!inany_v4(b);
+
+	return inany_equals(a, b);
+}
+
 /** inany_ntop - Convert an IPv[46] address to text format
  * @src:	IPv[46] address (NULL for unspecified)
  * @dst:	output buffer, minimum INANY_ADDRSTRLEN bytes
diff --git a/inany.h b/inany.h
index 61b36fb4..b02c2891 100644
--- a/inany.h
+++ b/inany.h
@@ -293,6 +293,7 @@ static inline void inany_siphash_feed(struct siphash_state *state,
 
 #define INANY_ADDRSTRLEN	MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)
 
+bool inany_matches(const union inany_addr *a, const union inany_addr *b);
 const char *inany_ntop(const union inany_addr *src, char *dst, socklen_t size);
 int inany_pton(const char *src, union inany_addr *dst);
 
-- 
2.52.0


  parent reply	other threads:[~2026-01-08  2:29 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-08  2:29 [PATCH v3 00/14] Introduce forwarding table David Gibson
2026-01-08  2:29 ` [PATCH v3 01/14] inany: Extend inany_ntop() to treat NULL as a fully unspecified address David Gibson
2026-01-08 13:16   ` Laurent Vivier
2026-01-08  2:29 ` [PATCH v3 02/14] conf, fwd: Keep a table of our port forwarding configuration David Gibson
2026-01-08  2:29 ` [PATCH v3 03/14] conf: Accurately record ifname and address for outbound forwards David Gibson
2026-01-08  2:29 ` [PATCH v3 04/14] conf, fwd: Record "auto" port forwards in forwarding table David Gibson
2026-01-08  2:29 ` [PATCH v3 05/14] fwd: Make space to store listening sockets in forward table David Gibson
2026-01-08  2:29 ` [PATCH v3 06/14] ip: Add ipproto_name() function David Gibson
2026-01-08 13:22   ` Laurent Vivier
2026-01-08 23:12     ` David Gibson
2026-01-08  2:29 ` [PATCH v3 07/14] fwd, tcp, udp: Set up listening sockets based on forward table David Gibson
2026-01-08  2:29 ` [PATCH v3 08/14] tcp, udp: Remove old auto-forwarding socket arrays David Gibson
2026-01-08  2:29 ` David Gibson [this message]
2026-01-08  2:29 ` [PATCH v3 10/14] fwd: Generate auto-forward exclusions from socket fd tables David Gibson
2026-01-08  2:29 ` [PATCH v3 11/14] flow, fwd: Consult rules table when forwarding a new flow from socket David Gibson
2026-01-08  2:29 ` [PATCH v3 12/14] fwd: Remap ports based directly on forwarding rule David Gibson
2026-01-08  2:29 ` [PATCH v3 13/14] fwd, tcp, udp: Add forwarding rule to listening socket epoll references David Gibson
2026-01-08  2:29 ` [PATCH v3 14/14] flow, fwd: Optimise forwarding rule lookup using epoll ref when possible David Gibson

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=20260108022948.2657573-10-david@gibson.dropbear.id.au \
    --to=david@gibson.dropbear.id.au \
    --cc=passt-dev@passt.top \
    --cc=sbrivio@redhat.com \
    /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.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

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 IMAP folder(s).