From mboxrd@z Thu Jan 1 00:00:00 1970 Received: by passt.top (Postfix, from userid 1000) id DBB855A0269; Thu, 07 May 2026 07:50:36 +0200 (CEST) From: Stefano Brivio To: Paul Holzinger Subject: [PATCH HACK] fwd, fwd_rule: Implement configurable destination address mapping Date: Thu, 7 May 2026 07:50:36 +0200 Message-ID: <20260507055036.2110260-1-sbrivio@redhat.com> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: 7WMDFEVSAZB6AA3R733VDYCDZF6FHQIM X-Message-ID-Hash: 7WMDFEVSAZB6AA3R733VDYCDZF6FHQIM X-MailFrom: sbrivio@passt.top 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: passt-dev@passt.top 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: This isn't complete, it's rather a quick hack to enable early integration testing. Add a 'daddr' field to forwarding rules, and some rudimentary parsing. Format (for either command line or pesto): -t 2222:192.0.2.1/2222 This should work along with all the other bits, that is, say: -t 192.0.2.1%eth0/2222-2225:192.0.2.2/22-25 Signed-off-by: Stefano Brivio --- fwd.c | 4 +++- fwd_rule.c | 46 +++++++++++++++++++++++++++++++++++----------- fwd_rule.h | 2 ++ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/fwd.c b/fwd.c index d224c0a..75db350 100644 --- a/fwd.c +++ b/fwd.c @@ -1095,7 +1095,9 @@ uint8_t fwd_nat_from_host(const struct ctx *c, } tgt->oport = ini->eport; - if (inany_v4(&tgt->oaddr)) { + if (!inany_is_unspecified(&rule->daddr)) { + tgt->eaddr = rule->daddr; + } else if (inany_v4(&tgt->oaddr)) { tgt->eaddr = inany_from_v4(c->ip4.addr_seen); } else { if (inany_is_linklocal6(&tgt->oaddr)) diff --git a/fwd_rule.c b/fwd_rule.c index 5fc04d7..5bce2fb 100644 --- a/fwd_rule.c +++ b/fwd_rule.c @@ -465,6 +465,7 @@ static int parse_keyword(const char *s, const char **endptr, const char *kw) */ static void fwd_rule_range_except(struct fwd_table *fwd, bool del, uint8_t proto, const union inany_addr *addr, + const union inany_addr *daddr, const char *ifname, uint16_t first, uint16_t last, const uint8_t *exclude, uint16_t to, @@ -472,6 +473,7 @@ static void fwd_rule_range_except(struct fwd_table *fwd, bool del, { struct fwd_rule rule = { .addr = addr ? *addr : inany_any6, + .daddr = daddr ? *daddr : inany_any6, .ifname = { 0 }, .proto = proto, .flags = flags, @@ -544,13 +546,13 @@ fail: */ static void fwd_rule_parse_ports(struct fwd_table *fwd, bool del, uint8_t proto, const union inany_addr *addr, - const char *ifname, - const char *spec) + const char *ifname, char *spec) { + union inany_addr daddr_buf = inany_any6, *daddr = &daddr_buf; uint8_t exclude[PORT_BITMAP_SIZE] = { 0 }; bool exclude_only = true; - const char *p, *ep; uint8_t flags = 0; + char *p, *ep; unsigned i; if (!strcmp(spec, "all")) { @@ -568,7 +570,7 @@ static void fwd_rule_parse_ports(struct fwd_table *fwd, bool del, uint8_t proto, continue; } - if (parse_keyword(p, &p, "auto") == 0) { + if (parse_keyword(p, (const char **)&p, "auto") == 0) { if (p != ep) /* Garbage after the keyword */ goto bad; @@ -586,7 +588,7 @@ static void fwd_rule_parse_ports(struct fwd_table *fwd, bool del, uint8_t proto, goto bad; p++; - if (parse_port_range(p, &p, &xrange)) + if (parse_port_range(p, (const char **)&p, &xrange)) goto bad; if (p != ep) /* Garbage after the range */ goto bad; @@ -599,7 +601,7 @@ static void fwd_rule_parse_ports(struct fwd_table *fwd, bool del, uint8_t proto, /* Exclude ephemeral ports */ fwd_port_map_ephemeral(exclude); - fwd_rule_range_except(fwd, del, proto, addr, ifname, + fwd_rule_range_except(fwd, del, proto, addr, NULL, ifname, 1, NUM_PORTS - 1, exclude, 1, flags | FWD_WEAK); return; @@ -613,11 +615,32 @@ static void fwd_rule_parse_ports(struct fwd_table *fwd, bool del, uint8_t proto, /* Already parsed */ continue; - if (parse_port_range(p, &p, &orig_range)) + if (parse_port_range(p, (const char **)&p, &orig_range)) goto bad; - if (*p == ':') { /* There's a range to map to as well */ - if (parse_port_range(p + 1, &p, &mapped_range)) + if (*p == ':') { + /* There's a range or address to map to as well */ + char *addr_end = strchr(p, '/'); + + if (addr_end) { + *addr_end = '\0'; + + if (*p == '[' && p[strlen(p) - 1] == ']') { + p[strlen(p) - 1] = '\0'; + p++; + } + + if (!inany_pton(p + 1, daddr)) + die("Bad forwarding address '%s'", p); + + p = addr_end; + } else { + daddr = NULL; + } + + + if (parse_port_range(p + 1, (const char **)&p, + &mapped_range)) goto bad; if ((mapped_range.last - mapped_range.first) != (orig_range.last - orig_range.first)) @@ -629,7 +652,7 @@ static void fwd_rule_parse_ports(struct fwd_table *fwd, bool del, uint8_t proto, if (p != ep) /* Garbage after the ranges */ goto bad; - fwd_rule_range_except(fwd, del, proto, addr, ifname, + fwd_rule_range_except(fwd, del, proto, addr, daddr, ifname, orig_range.first, orig_range.last, exclude, mapped_range.first, flags); @@ -675,7 +698,8 @@ void fwd_rule_parse(char optname, bool del, const char *optarg, strncpy(buf, optarg, sizeof(buf) - 1); - if ((spec = strchr(buf, '/'))) { + if ((spec = strchr(buf, '/')) && + strchr(spec, ':') == strchr(buf, ':')) { *spec = 0; spec++; diff --git a/fwd_rule.h b/fwd_rule.h index ae9a3cb..3a2a809 100644 --- a/fwd_rule.h +++ b/fwd_rule.h @@ -35,6 +35,7 @@ /** * struct fwd_rule - Forwarding rule governing a range of ports * @addr: Address to forward from + * @daddr: Optional address to set as destination when forwarding * @ifname: Interface to forward from * @first: First port number to forward * @last: Last port number to forward @@ -47,6 +48,7 @@ */ struct fwd_rule { union inany_addr addr; + union inany_addr daddr; char ifname[IFNAMSIZ]; in_port_t first; in_port_t last; -- 2.43.0