From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202512 header.b=i/xVeQT7; dkim-atps=neutral Received: from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id 96B615A0653 for ; Fri, 12 Dec 2025 08:10:43 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202512; t=1765523440; bh=SDvJDMWBZc6FYlz3hAGW5OB/MRxg5Xl3E45zFrDuurk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=i/xVeQT7CKLZGPoA8LmBGi2brQL0WqriDGHvgsSBviJqry80QYkFcth1FBIl0I0LA udqabpjOzIU0YRZtrCFpbpJEjA87rvBO2VL9jMrK50c+oqI0uQ3HDRvo7Ia/cxDUaC L6tKXZWYcwXmhiE9p0hzVMy5x+S6eyuyleZN9kHE0mZV3hhQ7pKrMHm5x0wxRQ+JWu ZbeRHTKTLoyz7UfdC/IT2Gt03kD2I8EyY3REq8YlgKxFwKAMgTzdewye3J0Te1GaNu 6WU5Z7EVWpQg+0d/feIBkwdkEoJ0iaA8gAnPRYuzL0DmR9IrlIMBkSd/39574Pzkgo 0pchon/iEHN/Q== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4dSLFr1r2Rz4wHY; Fri, 12 Dec 2025 18:10:40 +1100 (AEDT) From: David Gibson To: passt-dev@passt.top, Stefano Brivio Subject: [PATCH 3/5] conf, fwd: Keep a table of our port forwarding configuration Date: Fri, 12 Dec 2025 18:10:36 +1100 Message-ID: <20251212071038.3943933-4-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20251212071038.3943933-1-david@gibson.dropbear.id.au> References: <20251212071038.3943933-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: ZWDQ4OCDV4VASXRU6Y7X3WFQUFD5OX6P X-Message-ID-Hash: ZWDQ4OCDV4VASXRU6Y7X3WFQUFD5OX6P X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: David Gibson X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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 --- 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 */ +#include #include #include #include @@ -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