public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
* [PATCH 0/5] RFC: Forwarding table data structure
@ 2025-12-12  7:10 David Gibson
  2025-12-12  7:10 ` [PATCH 1/5] tcp: Remove extra space from TCP_INFO debug messages (trivial) David Gibson
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: David Gibson @ 2025-12-12  7:10 UTC (permalink / raw)
  To: passt-dev, Stefano Brivio; +Cc: David Gibson

Here's some patches starting to create a data structure to store more
flexible (and eventually dynamically updateable) forwarding
configuration.

So far this is just creating the data structures, not actually using
them to drive the rest of the code, so it's not ready for merge (but
the preliminaries in 1..2/5 could be merged if you like).  Putting it
out there for early review.

David Gibson (5):
  tcp: Remove extra space from TCP_INFO debug messages (trivial)
  conf, fwd: Move initialisation of auto port scanning out of conf()
  conf, fwd: Keep a table of our port forwarding configuration
  conf: Accurately record ifname and address for outbound forwards
  conf, fwd: Record "auto" port forwards in forwarding table

 conf.c  | 140 +++++++++++++++++++++++++++++++++++++++++---------------
 fwd.c   |  78 +++++++++++++++++++++++++++++++
 fwd.h   |  33 +++++++++++++
 passt.c |   1 +
 tcp.c   |   2 +-
 5 files changed, 216 insertions(+), 38 deletions(-)

-- 
2.52.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/5] tcp: Remove extra space from TCP_INFO debug messages (trivial)
  2025-12-12  7:10 [PATCH 0/5] RFC: Forwarding table data structure David Gibson
@ 2025-12-12  7:10 ` David Gibson
  2025-12-12  7:10 ` [PATCH 2/5] conf, fwd: Move initialisation of auto port scanning out of conf() David Gibson
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: David Gibson @ 2025-12-12  7:10 UTC (permalink / raw)
  To: passt-dev, Stefano Brivio; +Cc: David Gibson

Debug messages about which tcp_info fields are supported contained an
extra space, always ending with "  supported".

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 tcp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tcp.c b/tcp.c
index 1711bcc7..81bc1145 100644
--- a/tcp.c
+++ b/tcp.c
@@ -2950,7 +2950,7 @@ int tcp_init(struct ctx *c)
 	tcp_info_size = tcp_probe_tcp_info();
 
 #define dbg_tcpi(f_)	debug("TCP_INFO tcpi_%s field%s supported",	\
-			      STRINGIFY(f_), tcp_info_cap(f_) ? " " : " not ")
+			      STRINGIFY(f_), tcp_info_cap(f_) ? "" : " not")
 	dbg_tcpi(snd_wnd);
 	dbg_tcpi(bytes_acked);
 	dbg_tcpi(min_rtt);
-- 
2.52.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/5] conf, fwd: Move initialisation of auto port scanning out of conf()
  2025-12-12  7:10 [PATCH 0/5] RFC: Forwarding table data structure David Gibson
  2025-12-12  7:10 ` [PATCH 1/5] tcp: Remove extra space from TCP_INFO debug messages (trivial) David Gibson
@ 2025-12-12  7:10 ` David Gibson
  2025-12-12  7:10 ` [PATCH 3/5] conf, fwd: Keep a table of our port forwarding configuration David Gibson
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: David Gibson @ 2025-12-12  7:10 UTC (permalink / raw)
  To: passt-dev, Stefano Brivio; +Cc: David Gibson

We call fwd_scan_ports_init() at (almost) the end of conf().  It's a bit
odd to do actual work from a function that's ostensibly about getting our
configuration.  It's not the only instance of this, but to make things a
bit clearer move the call to main(), right after flow_init().

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 conf.c  | 2 --
 passt.c | 1 +
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/conf.c b/conf.c
index 24b44419..2942c8c2 100644
--- a/conf.c
+++ b/conf.c
@@ -2144,8 +2144,6 @@ void conf(struct ctx *c, int argc, char **argv)
 	if (!c->udp.fwd_out.mode)
 		c->udp.fwd_out.mode = fwd_default;
 
-	fwd_scan_ports_init(c);
-
 	if (!c->quiet)
 		conf_print(c);
 }
diff --git a/passt.c b/passt.c
index cf38822f..7488a84c 100644
--- a/passt.c
+++ b/passt.c
@@ -396,6 +396,7 @@ int main(int argc, char **argv)
 		die_perror("Failed to get CLOCK_MONOTONIC time");
 
 	flow_init();
+	fwd_scan_ports_init(&c);
 
 	if ((!c.no_udp && udp_init(&c)) || (!c.no_tcp && tcp_init(&c)))
 		passt_exit(EXIT_FAILURE);
-- 
2.52.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 3/5] conf, fwd: Keep a table of our port forwarding configuration
  2025-12-12  7:10 [PATCH 0/5] RFC: Forwarding table data structure David Gibson
  2025-12-12  7:10 ` [PATCH 1/5] tcp: Remove extra space from TCP_INFO debug messages (trivial) David Gibson
  2025-12-12  7:10 ` [PATCH 2/5] conf, fwd: Move initialisation of auto port scanning out of conf() David Gibson
@ 2025-12-12  7:10 ` David Gibson
  2025-12-12  7:10 ` [PATCH 4/5] conf: Accurately record ifname and address for outbound forwards David Gibson
  2025-12-12  7:10 ` [PATCH 5/5] conf, fwd: Record "auto" port forwards in forwarding table David Gibson
  4 siblings, 0 replies; 6+ messages in thread
From: David Gibson @ 2025-12-12  7:10 UTC (permalink / raw)
  To: passt-dev, Stefano Brivio; +Cc: David Gibson

At present, we set up forwarding as we parse the -t, and -u options, not
keeping a persistent data structure with all the details.  We do have
some information in struct fwd_ports, but it doesn't capture all the nuance
that the options do.

As a first step to generalising our forwarding model, add a table of all
the forwarding configured to struct fwd_ports.  For now it covers only
explicit forwards, not automatic, and we don't do anything with it other
than print some additional debug information.  We'll do more with it in
future patches.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 conf.c | 85 +++++++++++++++++++++++++++++++++++++---------------------
 fwd.c  | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fwd.h  | 31 +++++++++++++++++++++
 3 files changed, 162 insertions(+), 30 deletions(-)

diff --git a/conf.c b/conf.c
index 2942c8c2..88971d04 100644
--- a/conf.c
+++ b/conf.c
@@ -137,7 +137,7 @@ static int parse_port_range(const char *s, char **endptr,
  * @last:	Last port to forward
  * @exclude:	Bitmap of ports to exclude
  * @to:		Port to translate @first to when forwarding
- * @weak:	Ignore errors, as long as at least one port is mapped
+ * @flags:	Flags for forwarding entries
  */
 static void conf_ports_range_except(const struct ctx *c, char optname,
 				    const char *optarg, struct fwd_ports *fwd,
@@ -145,10 +145,11 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
 				    const char *ifname,
 				    uint16_t first, uint16_t last,
 				    const uint8_t *exclude, uint16_t to,
-				    bool weak)
+				    uint8_t flags)
 {
+	unsigned delta = to - first;
 	bool bound_one = false;
-	unsigned i;
+	unsigned base, i;
 	int ret;
 
 	if (first == 0) {
@@ -162,37 +163,50 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
 		    optname, optarg);
 	}
 
-	for (i = first; i <= last; i++) {
-		if (bitmap_isset(exclude, i))
+	for (base = first; base <= last; base++) {
+		if (bitmap_isset(exclude, base))
 			continue;
 
-		if (bitmap_isset(fwd->map, i)) {
-			warn(
-"Altering mapping of already mapped port number: %s", optarg);
-		}
+		for (i = base; i <= last; i++) {
+			if (bitmap_isset(exclude, i))
+				break;
 
-		bitmap_set(fwd->map, i);
-		fwd->delta[i] = to - first;
+			if (bitmap_isset(fwd->map, i)) {
+				warn(
+"Altering mapping of already mapped port number: %s", optarg);
+			}
 
-		if (optname == 't')
-			ret = tcp_sock_init(c, PIF_HOST, addr, ifname, i);
-		else if (optname == 'u')
-			ret = udp_sock_init(c, PIF_HOST, addr, ifname, i);
-		else
-			/* No way to check in advance for -T and -U */
-			ret = 0;
+			bitmap_set(fwd->map, i);
+			fwd->delta[i] = delta;
+
+			if (optname == 't')
+				ret = tcp_sock_init(c, PIF_HOST, addr, ifname,
+						    i);
+			else if (optname == 'u')
+				ret = udp_sock_init(c, PIF_HOST, addr, ifname,
+						    i);
+			else
+				/* No way to check in advance for -T and -U */
+				ret = 0;
+
+			if (ret == -ENFILE || ret == -EMFILE) {
+				die(
+"Can't open enough sockets for port specifier: %s",
+				    optarg);
+			}
 
-		if (ret == -ENFILE || ret == -EMFILE) {
-			die("Can't open enough sockets for port specifier: %s",
-			    optarg);
+			if (!ret) {
+				bound_one = true;
+			} else if (!(flags & FWD_WEAK)) {
+				die(
+"Failed to bind port %u (%s) for option '-%c %s'",
+				    i, strerror_(-ret), optname, optarg);
+			}
 		}
 
-		if (!ret) {
-			bound_one = true;
-		} else if (!weak) {
-			die("Failed to bind port %u (%s) for option '-%c %s'",
-			    i, strerror_(-ret), optname, optarg);
-		}
+		fwd_table_add(fwd, flags, addr, ifname,
+			      base, i - 1, base + delta);
+		base = i - 1;
 	}
 
 	if (!bound_one)
@@ -262,7 +276,7 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
 		conf_ports_range_except(c, optname, optarg, fwd,
 					NULL, NULL,
 					1, NUM_PORTS - 1, exclude,
-					1, true);
+					1, FWD_WEAK);
 		return;
 	}
 
@@ -347,7 +361,7 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
 		conf_ports_range_except(c, optname, optarg, fwd,
 					addr, ifname,
 					1, NUM_PORTS - 1, exclude,
-					1, true);
+					1, FWD_WEAK);
 		return;
 	}
 
@@ -380,7 +394,7 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
 					addr, ifname,
 					orig_range.first, orig_range.last,
 					exclude,
-					mapped_range.first, false);
+					mapped_range.first, 0);
 	} while ((p = next_chunk(p, ',')));
 
 	return;
@@ -1210,6 +1224,17 @@ dns6:
 			info("    %s", c->dns_search[i].n);
 		}
 	}
+
+	info("Inbound TCP forwarding:");
+	fwd_table_print(&c->tcp.fwd_in);
+	info("Inbound UDP forwarding:");
+	fwd_table_print(&c->udp.fwd_in);
+	if (c->mode == MODE_PASTA) {
+		info("Outbound TCP forwarding:");
+		fwd_table_print(&c->tcp.fwd_out);
+		info("Outbound UDP forwarding:");
+		fwd_table_print(&c->udp.fwd_out);
+	}
 }
 
 /**
diff --git a/fwd.c b/fwd.c
index 44a0e109..f4b6c492 100644
--- a/fwd.c
+++ b/fwd.c
@@ -13,6 +13,7 @@
  * Author: David Gibson <david@gibson.dropbear.id.au>
  */
 
+#include <assert.h>
 #include <stdint.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -22,6 +23,8 @@
 
 #include "util.h"
 #include "ip.h"
+#include "siphash.h"
+#include "inany.h"
 #include "fwd.h"
 #include "passt.h"
 #include "lineread.h"
@@ -313,6 +316,79 @@ bool fwd_port_is_ephemeral(in_port_t port)
 	return (port >= fwd_ephemeral_min) && (port <= fwd_ephemeral_max);
 }
 
+/**
+ * fwd_table_add() - Add an entry to a forwarding table
+ * @tab:	Table to add to
+ * @flags:	Flags for this entry
+ * @addr:	Our address to forward (NULL for both 0.0.0.0 and ::)
+ * @ifname:	Only forward from this interface name, if non-empty
+ * @first:	First port number to forward
+ * @last:	Last port number to forward
+ * @to:		First port of target port range to map to
+ */
+void fwd_table_add(struct fwd_ports *tab, uint8_t flags,
+		   const union inany_addr *addr, const char *ifname,
+		   in_port_t first, in_port_t last, in_port_t to)
+{
+	/* Flags which can be set from the caller */
+	const uint8_t allowed_flags = FWD_WEAK;
+	struct fwd_entry *new;
+
+	ASSERT(!(flags & ~allowed_flags));
+
+	if (tab->count >= ARRAY_SIZE(tab->tab))
+		die("Too many port forwarding ranges");
+
+	new = &tab->tab[tab->count++];
+	new->flags = flags;
+
+	if (addr) {
+		new->addr = *addr;
+	} else {
+		new->addr = inany_any6;
+		new->flags |= FWD_DUAL_STACK;
+	}
+
+	memset(new->ifname, 0, sizeof(new->ifname));
+	if (ifname)
+		strncpy(new->ifname, ifname, sizeof(new->ifname));
+
+	ASSERT(first <= last);
+	new->first = first;
+	new->last = last;
+
+	new->to = to;
+}
+
+/**
+ * fwd_table_print() - Print forwarding table for debugging
+ * @tab:	Table to print
+ */
+void fwd_table_print(const struct fwd_ports *tab)
+{
+	unsigned i;
+
+	for (i = 0; i < tab->count; i++) {
+		const struct fwd_entry *fwd = &tab->tab[i];
+		const char *weak = fwd->flags & FWD_WEAK ? " WEAK" : "";
+		const char *percent = *fwd->ifname ? "%" : "";
+		char addr[INANY_ADDRSTRLEN] = "*";
+
+		if (!(fwd->flags & FWD_DUAL_STACK))
+			inany_ntop(&fwd->addr, addr, sizeof(addr));
+
+		if (fwd->first == fwd->last) {
+			info("    [%s]%s%s:%hu  =>  %hu %s",
+			     addr, percent, fwd->ifname,
+			     fwd->first, fwd->to, weak);
+		} else {
+			info("    [%s]%s%s:%hu-%hu  =>  %hu-%hu %s",
+			     addr, percent, fwd->ifname, fwd->first, fwd->last,
+			     fwd->to, fwd->last - fwd->first + fwd->to, weak);
+		}
+	}
+}
+
 /* See enum in kernel's include/net/tcp_states.h */
 #define UDP_LISTEN	0x07
 #define TCP_LISTEN	0x0a
diff --git a/fwd.h b/fwd.h
index 77925822..07222f41 100644
--- a/fwd.h
+++ b/fwd.h
@@ -16,6 +16,30 @@ struct flowside;
 void fwd_probe_ephemeral(void);
 bool fwd_port_is_ephemeral(in_port_t port);
 
+/**
+ * struct fwd_entry - One range of ports to forward
+ * @addr:	Address to forward from
+ * @ifname:	Interface to forward from
+ * @first:	First port number to forward
+ * @last:	Last port number to forward
+ * @to:		Port number to forward port @first to.
+ * @flags:	Flag mask
+ * 	FWD_DUAL_STACK - forward both IPv4 and IPv6 (requires @addr be ::)
+ *	FWD_WEAK - Don't give an error if binds fail for some forwards
+ *
+ * FIXME: @addr and @ifname currently ignored for outbound tables
+ */
+struct fwd_entry {
+	union inany_addr addr;
+	char ifname[IFNAMSIZ];
+	in_port_t first, last, to;
+#define FWD_DUAL_STACK		BIT(0)
+#define FWD_WEAK		BIT(1)
+	uint8_t flags;
+};
+
+#define MAX_FWDS	1024
+
 enum fwd_ports_mode {
 	FWD_UNSET = 0,
 	FWD_SPEC = 1,
@@ -38,12 +62,19 @@ struct fwd_ports {
 	enum fwd_ports_mode mode;
 	int scan4;
 	int scan6;
+	unsigned count;
+	struct fwd_entry tab[MAX_FWDS];
 	uint8_t map[PORT_BITMAP_SIZE];
 	in_port_t delta[NUM_PORTS];
 };
 
 #define FWD_PORT_SCAN_INTERVAL		1000	/* ms */
 
+void fwd_table_add(struct fwd_ports *tab, uint8_t flags,
+		   const union inany_addr *addr, const char *ifname,
+		   in_port_t first, in_port_t last, in_port_t to);
+void fwd_table_print(const struct fwd_ports *tab);
+
 void fwd_scan_ports_init(struct ctx *c);
 void fwd_scan_ports_timer(struct ctx *c, const struct timespec *now);
 
-- 
2.52.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 4/5] conf: Accurately record ifname and address for outbound forwards
  2025-12-12  7:10 [PATCH 0/5] RFC: Forwarding table data structure David Gibson
                   ` (2 preceding siblings ...)
  2025-12-12  7:10 ` [PATCH 3/5] conf, fwd: Keep a table of our port forwarding configuration David Gibson
@ 2025-12-12  7:10 ` David Gibson
  2025-12-12  7:10 ` [PATCH 5/5] conf, fwd: Record "auto" port forwards in forwarding table David Gibson
  4 siblings, 0 replies; 6+ messages in thread
From: David Gibson @ 2025-12-12  7:10 UTC (permalink / raw)
  To: passt-dev, Stefano Brivio; +Cc: David Gibson

-T and -U options don't allow specifying a listening address.  Usually this
will listen on *%lo in the guest.  However on kernels without unprivileged
SO_BINDTODEVICE that's not possible so we instead listen separately on
127.0.0.1 and ::1.

Currently that's handled at the point we actually set up the listens, we
record both address and ifname as NULL in the forwarding table entry.  That
will cause trouble for future extensions we want, so update this to
accurately create the forwarding table: either a single entry with ifname
== "lo" or two entries with address of 127.0.0.1 and ::1.

As a bonus, this gives the user a warning if they specify an explicit
outbound forwarding on a kernel without SO_BINDTODEVICE.  The existing
warning for missing SO_BINDTODEVICE (incorrectly) only covers the case of
-T auto or -U auto.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 conf.c | 38 ++++++++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/conf.c b/conf.c
index 88971d04..b24ab407 100644
--- a/conf.c
+++ b/conf.c
@@ -157,12 +157,6 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
 		    optname, optarg);
 	}
 
-	if (ifname && c->no_bindtodevice) {
-		die(
-"Device binding for '-%c %s' unsupported (requires kernel 5.7+)",
-		    optname, optarg);
-	}
-
 	for (base = first; base <= last; base++) {
 		if (bitmap_isset(exclude, base))
 			continue;
@@ -204,8 +198,27 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
 			}
 		}
 
-		fwd_table_add(fwd, flags, addr, ifname,
-			      base, i - 1, base + delta);
+		if ((optname == 'T' || optname == 'U') && c->no_bindtodevice) {
+			/* FIXME: Once the fwd bitmaps are removed, move this
+			 * workaround to the caller
+			 */
+			ASSERT(!addr && ifname && !strcmp(ifname, "lo"));
+			warn(
+"SO_BINDTODEVICE unavailable, forwarding only 127.0.0.1 and ::1 for '-%c %s'",
+			     optname, optarg);
+
+			if (c->ifi4) {
+				fwd_table_add(fwd, flags, &inany_loopback4, NULL,
+					      base, i - 1, base + delta);
+			}
+			if (c->ifi6) {
+				fwd_table_add(fwd, flags, &inany_loopback6, NULL,
+					      base, i - 1, base + delta);
+			}
+		} else {
+			fwd_table_add(fwd, flags, addr, ifname,
+				      base, i - 1, base + delta);
+		}
 		base = i - 1;
 	}
 
@@ -352,6 +365,15 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
 		}
 	} while ((p = next_chunk(p, ',')));
 
+	if (ifname && c->no_bindtodevice) {
+		die(
+"Device binding for '-%c %s' unsupported (requires kernel 5.7+)",
+		    optname, optarg);
+	}
+	/* Outbound forwards come from guest loopback */
+	if ((optname == 'T' || optname == 'U') && !ifname)
+		ifname = "lo";
+
 	if (exclude_only) {
 		/* Exclude ephemeral ports */
 		for (i = 0; i < NUM_PORTS; i++)
-- 
2.52.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 5/5] conf, fwd: Record "auto" port forwards in forwarding table
  2025-12-12  7:10 [PATCH 0/5] RFC: Forwarding table data structure David Gibson
                   ` (3 preceding siblings ...)
  2025-12-12  7:10 ` [PATCH 4/5] conf: Accurately record ifname and address for outbound forwards David Gibson
@ 2025-12-12  7:10 ` David Gibson
  4 siblings, 0 replies; 6+ messages in thread
From: David Gibson @ 2025-12-12  7:10 UTC (permalink / raw)
  To: passt-dev, Stefano Brivio; +Cc: David Gibson

Currently the forwarding table records details of explicit port forwards,
but nothing for -[tTuU] auto.  That looks a little odd on the debug output,
and will be a problem for future changes.

Extend the forward table to have entries for auto-scanned forwards, using
a new FWD_SCAN flag.  For now the mechanism of auto port forwarding isn't
updated, and we can only create a single FWD_SCAN entry per protocol and
direction.  We'll better integrate auto scanning with other forward table
mechanics in future.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 conf.c | 31 ++++++++++++++++++++++++++-----
 fwd.c  | 12 +++++++-----
 fwd.h  |  2 ++
 3 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/conf.c b/conf.c
index b24ab407..36f5d448 100644
--- a/conf.c
+++ b/conf.c
@@ -135,7 +135,7 @@ static int parse_port_range(const char *s, char **endptr,
  * @ifname:	Listening interface
  * @first:	First port to forward
  * @last:	Last port to forward
- * @exclude:	Bitmap of ports to exclude
+ * @exclude:	Bitmap of ports to exclude (may be NULL)
  * @to:		Port to translate @first to when forwarding
  * @flags:	Flags for forwarding entries
  */
@@ -158,11 +158,11 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
 	}
 
 	for (base = first; base <= last; base++) {
-		if (bitmap_isset(exclude, base))
+		if (exclude && bitmap_isset(exclude, base))
 			continue;
 
 		for (i = base; i <= last; i++) {
-			if (bitmap_isset(exclude, i))
+			if (exclude && bitmap_isset(exclude, i))
 				break;
 
 			if (bitmap_isset(fwd->map, i)) {
@@ -173,10 +173,10 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
 			bitmap_set(fwd->map, i);
 			fwd->delta[i] = delta;
 
-			if (optname == 't')
+			if (!(flags & FWD_SCAN) && optname == 't')
 				ret = tcp_sock_init(c, PIF_HOST, addr, ifname,
 						    i);
-			else if (optname == 'u')
+			else if (!(flags & FWD_SCAN) && optname == 'u')
 				ret = udp_sock_init(c, PIF_HOST, addr, ifname,
 						    i);
 			else
@@ -2191,6 +2191,27 @@ void conf(struct ctx *c, int argc, char **argv)
 	if (!c->udp.fwd_out.mode)
 		c->udp.fwd_out.mode = fwd_default;
 
+	if (c->tcp.fwd_in.mode == FWD_AUTO) {
+		conf_ports_range_except(c, 't', "auto", &c->tcp.fwd_in,
+					NULL, NULL, 1, NUM_PORTS - 1,
+					NULL, 1, FWD_SCAN);
+	}
+	if (c->tcp.fwd_out.mode == FWD_AUTO) {
+		conf_ports_range_except(c, 'T', "auto", &c->tcp.fwd_out,
+					NULL, "lo", 1, NUM_PORTS - 1,
+					NULL, 1, FWD_SCAN);
+	}
+	if (c->udp.fwd_in.mode == FWD_AUTO) {
+		conf_ports_range_except(c, 'u', "auto", &c->udp.fwd_in,
+					NULL, NULL, 1, NUM_PORTS - 1,
+					NULL, 1, FWD_SCAN);
+	}
+	if (c->udp.fwd_out.mode == FWD_AUTO) {
+		conf_ports_range_except(c, 'U', "auto", &c->udp.fwd_out,
+					NULL, "lo", 1, NUM_PORTS - 1,
+					NULL, 1, FWD_SCAN);
+	}
+
 	if (!c->quiet)
 		conf_print(c);
 }
diff --git a/fwd.c b/fwd.c
index f4b6c492..4e54f5ce 100644
--- a/fwd.c
+++ b/fwd.c
@@ -331,7 +331,7 @@ void fwd_table_add(struct fwd_ports *tab, uint8_t flags,
 		   in_port_t first, in_port_t last, in_port_t to)
 {
 	/* Flags which can be set from the caller */
-	const uint8_t allowed_flags = FWD_WEAK;
+	const uint8_t allowed_flags = FWD_WEAK | FWD_SCAN;
 	struct fwd_entry *new;
 
 	ASSERT(!(flags & ~allowed_flags));
@@ -371,6 +371,7 @@ void fwd_table_print(const struct fwd_ports *tab)
 	for (i = 0; i < tab->count; i++) {
 		const struct fwd_entry *fwd = &tab->tab[i];
 		const char *weak = fwd->flags & FWD_WEAK ? " WEAK" : "";
+		const char *scan = fwd->flags & FWD_SCAN ? " AUTO" : "";
 		const char *percent = *fwd->ifname ? "%" : "";
 		char addr[INANY_ADDRSTRLEN] = "*";
 
@@ -378,13 +379,14 @@ void fwd_table_print(const struct fwd_ports *tab)
 			inany_ntop(&fwd->addr, addr, sizeof(addr));
 
 		if (fwd->first == fwd->last) {
-			info("    [%s]%s%s:%hu  =>  %hu %s",
+			info("    [%s]%s%s:%hu  =>  %hu %s%s",
 			     addr, percent, fwd->ifname,
-			     fwd->first, fwd->to, weak);
+			     fwd->first, fwd->to, weak, scan);
 		} else {
-			info("    [%s]%s%s:%hu-%hu  =>  %hu-%hu %s",
+			info("    [%s]%s%s:%hu-%hu  =>  %hu-%hu %s%s",
 			     addr, percent, fwd->ifname, fwd->first, fwd->last,
-			     fwd->to, fwd->last - fwd->first + fwd->to, weak);
+			     fwd->to, fwd->last - fwd->first + fwd->to,
+			     weak, scan);
 		}
 	}
 }
diff --git a/fwd.h b/fwd.h
index 07222f41..7a9bc3ed 100644
--- a/fwd.h
+++ b/fwd.h
@@ -26,6 +26,7 @@ bool fwd_port_is_ephemeral(in_port_t port);
  * @flags:	Flag mask
  * 	FWD_DUAL_STACK - forward both IPv4 and IPv6 (requires @addr be ::)
  *	FWD_WEAK - Don't give an error if binds fail for some forwards
+ *	FWD_SCAN - Only forward if we scan a listener on the target
  *
  * FIXME: @addr and @ifname currently ignored for outbound tables
  */
@@ -35,6 +36,7 @@ struct fwd_entry {
 	in_port_t first, last, to;
 #define FWD_DUAL_STACK		BIT(0)
 #define FWD_WEAK		BIT(1)
+#define FWD_SCAN		BIT(2)
 	uint8_t flags;
 };
 
-- 
2.52.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2025-12-12  7:10 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-12  7:10 [PATCH 0/5] RFC: Forwarding table data structure David Gibson
2025-12-12  7:10 ` [PATCH 1/5] tcp: Remove extra space from TCP_INFO debug messages (trivial) David Gibson
2025-12-12  7:10 ` [PATCH 2/5] conf, fwd: Move initialisation of auto port scanning out of conf() David Gibson
2025-12-12  7:10 ` [PATCH 3/5] conf, fwd: Keep a table of our port forwarding configuration David Gibson
2025-12-12  7:10 ` [PATCH 4/5] conf: Accurately record ifname and address for outbound forwards David Gibson
2025-12-12  7:10 ` [PATCH 5/5] conf, fwd: Record "auto" port forwards in forwarding table David Gibson

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).