On Tue, Jan 13, 2026 at 12:26:15AM +0100, Stefano Brivio wrote:
On Thu, 8 Jan 2026 13:29:38 +1100 David Gibson
wrote: 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 rules for auto-scanned forwards, using a new FWD_SCAN flag. For now the mechanism of auto port forwarding isn't updated, and we will only create a single FWD_SCAN rule per protocol and direction. We'll better integrate auto scanning with other forward table mechanics in future.
Signed-off-by: David Gibson
--- conf.c | 31 ++++++++++++++++++++++++++----- fwd.c | 18 +++++++++++------- fwd.h | 2 ++ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/conf.c b/conf.c index b486fefe..0bcf80d7 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 */ @@ -168,11 +168,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)) { @@ -180,9 +180,9 @@ static void conf_ports_range_except(const struct ctx *c, char optname, "Altering mapping of already mapped port number: %s", optarg); }
- if (optname == 't') + if (!(flags & FWD_SCAN) && optname == 't') fd = tcp_listen(c, PIF_HOST, addr, ifname, i); - else if (optname == 'u') + else if (!(flags & FWD_SCAN) && optname == 'u') fd = udp_listen(c, PIF_HOST, addr, ifname, i); else /* No way to check in advance for -T and -U */ @@ -2202,6 +2202,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 ad398e54..69aca441 100644 --- a/fwd.c +++ b/fwd.c @@ -344,7 +344,7 @@ void fwd_rule_add(struct fwd_ports *fwd, 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_rule *new; unsigned port;
@@ -375,7 +375,8 @@ void fwd_rule_add(struct fwd_ports *fwd, uint8_t flags,
for (port = new->first; port <= new->last; port++) { /* Fill in the legacy data structures to match the table */ - bitmap_set(fwd->map, port); + if (!(new->flags & FWD_SCAN)) + bitmap_set(fwd->map, port); fwd->delta[port] = new->to - new->first; } } @@ -391,19 +392,22 @@ void fwd_rules_print(const struct fwd_ports *fwd) for (i = 0; i < fwd->count; i++) { const struct fwd_rule *rule = &fwd->rules[i]; const char *weak = rule->flags & FWD_WEAK ? " WEAK" : ""; + const char *scan = rule->flags & FWD_SCAN ? " AUTO" : ""; const char *percent = *rule->ifname ? "%" : ""; char addr[INANY_ADDRSTRLEN];
inany_ntop(fwd_rule_addr(rule), addr, sizeof(addr));
if (rule->first == rule->last) { - info(" [%s]%s%s:%hu => %hu %s", + info(" [%s]%s%s:%hu => %hu %s%s", addr, percent, rule->ifname, - rule->first, rule->to, weak); + rule->first, rule->to, weak, scan); } else { - info(" [%s]%s%s:%hu-%hu => %hu-%hu %s", - addr, percent, rule->ifname, rule->first, rule->last, - rule->to, rule->last - rule->first + rule->to, weak); + info(" [%s]%s%s:%hu-%hu => %hu-%hu %s%s", + addr, percent, rule->ifname, + rule->first, rule->last, + rule->to, rule->last - rule->first + rule->to, + weak, scan); } } } diff --git a/fwd.h b/fwd.h index 3dfc7959..94869c2a 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_ANY - match any IPv4 or IPv6 address (@addr should 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
Nit: I guess this could be slightly more descriptive than "scan a listener", mentioning for example "if the corresponding port is bound on the target".
Done.
* * FIXME: @addr and @ifname currently ignored for outbound tables */ @@ -35,6 +36,7 @@ struct fwd_rule { in_port_t first, last, to; #define FWD_DUAL_STACK_ANY BIT(0) #define FWD_WEAK BIT(1) +#define FWD_SCAN BIT(2) uint8_t flags; };
-- Stefano
-- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson