public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
* [PATCH HACK] fwd, fwd_rule: Implement configurable destination address mapping
@ 2026-05-07  5:50 Stefano Brivio
  0 siblings, 0 replies; only message in thread
From: Stefano Brivio @ 2026-05-07  5:50 UTC (permalink / raw)
  To: Paul Holzinger; +Cc: passt-dev

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 <sbrivio@redhat.com>
---
 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


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-05-07  5:50 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-07  5:50 [PATCH HACK] fwd, fwd_rule: Implement configurable destination address mapping Stefano Brivio

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