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=202602 header.b=PuNP+VbB; dkim-atps=neutral Received: from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id E19385A0269 for ; Thu, 14 May 2026 06:54:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202602; t=1778734476; bh=uD5IgyROK9lQ6omO4p/tNmOjrJw+wT99dI4v9FV0JSs=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=PuNP+VbBV21YuoR4PUPajwezJYaMf5LV8tgd7rg0Uj/tm0MYhdtUQbiciAaCuAfHb jk05wqERZqRyzda9NiywJzewQCN8r9jUq571tMS+anx//JLKsFUeN0CjWfxv0BPKXh HAyLAPxUkEXMNbtO2LsZ95SeK4gyfxFVFNKGQiYrRPLbPgI5LxZ+hxhQyUEJGG0PLl gdtjUiGZoSOGulKGJ2AcHiGvnooXgLPMxkZo6ax+3e9Q4Y3k7XCHKAHHGMgRlMsrZX QYPvbK15wsvtNCeM9hHrt7meWfoWjjivhVAkvzO1AErFVxQylWNQ1rJIn8N/6URqIP xDNf6pTCp2JmA== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4gGJ0D2g4Gz4w9r; Thu, 14 May 2026 14:54:36 +1000 (AEST) Date: Thu, 14 May 2026 14:54:33 +1000 From: David Gibson To: Stefano Brivio Subject: Re: [PATCH HACK] fwd, fwd_rule: Implement configurable destination address mapping Message-ID: References: <20260507055036.2110260-1-sbrivio@redhat.com> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="CeHOs032v4npoHo3" Content-Disposition: inline In-Reply-To: <20260507055036.2110260-1-sbrivio@redhat.com> Message-ID-Hash: MRUYPJSLQSJ2FCUTQ5PX4UX2AY2GGVAU X-Message-ID-Hash: MRUYPJSLQSJ2FCUTQ5PX4UX2AY2GGVAU 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: Paul Holzinger , 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: --CeHOs032v4npoHo3 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Thu, May 07, 2026 at 07:50:36AM +0200, Stefano Brivio wrote: > This isn't complete, it's rather a quick hack to enable early > integration testing. >=20 > Add a 'daddr' field to forwarding rules, and some rudimentary parsing. >=20 > Format (for either command line or pesto): >=20 > -t 2222:192.0.2.1/2222 >=20 > This should work along with all the other bits, that is, say: >=20 > -t 192.0.2.1%eth0/2222-2225:192.0.2.2/22-25 >=20 > Signed-off-by: Stefano Brivio Very nice for a quick hack, and it gets surprisingly far with not much code at all. > --- > fwd.c | 4 +++- > fwd_rule.c | 46 +++++++++++++++++++++++++++++++++++----------- > fwd_rule.h | 2 ++ > 3 files changed, 40 insertions(+), 12 deletions(-) >=20 > 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 =3D ini->eport; > =20 > - if (inany_v4(&tgt->oaddr)) { > + if (!inany_is_unspecified(&rule->daddr)) { > + tgt->eaddr =3D rule->daddr; Longer term, there are at least two options for what we want to do if the rule doesn't specify a specific destination address: * Use the observed guest address (what we do now) * Use the host side destination address (potentially useful if we have multiple containers each assigned different host addresses) So we'll probably want to allow for some new rule flags to cover options like this. > + } else if (inany_v4(&tgt->oaddr)) { > tgt->eaddr =3D 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 *f= wd, bool del, > { > struct fwd_rule rule =3D { > .addr =3D addr ? *addr : inany_any6, > + .daddr =3D daddr ? *daddr : inany_any6, > .ifname =3D { 0 }, > .proto =3D proto, > .flags =3D 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 =3D inany_any6, *daddr =3D &daddr_buf; > uint8_t exclude[PORT_BITMAP_SIZE] =3D { 0 }; > bool exclude_only =3D true; > - const char *p, *ep; > uint8_t flags =3D 0; > + char *p, *ep; > unsigned i; > =20 > if (!strcmp(spec, "all")) { > @@ -568,7 +570,7 @@ static void fwd_rule_parse_ports(struct fwd_table *fw= d, bool del, uint8_t proto, > continue; > } > =20 > - if (parse_keyword(p, &p, "auto") =3D=3D 0) { > + if (parse_keyword(p, (const char **)&p, "auto") =3D=3D 0) { > if (p !=3D ep) /* Garbage after the keyword */ > goto bad; > =20 > @@ -586,7 +588,7 @@ static void fwd_rule_parse_ports(struct fwd_table *fw= d, bool del, uint8_t proto, > goto bad; > p++; > =20 > - if (parse_port_range(p, &p, &xrange)) > + if (parse_port_range(p, (const char **)&p, &xrange)) > goto bad; > if (p !=3D ep) /* Garbage after the range */ > goto bad; > @@ -599,7 +601,7 @@ static void fwd_rule_parse_ports(struct fwd_table *fw= d, bool del, uint8_t proto, > /* Exclude ephemeral ports */ > fwd_port_map_ephemeral(exclude); > =20 > - 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; > =20 > - if (parse_port_range(p, &p, &orig_range)) > + if (parse_port_range(p, (const char **)&p, &orig_range)) > goto bad; > =20 > - if (*p =3D=3D ':') { /* There's a range to map to as well */ > - if (parse_port_range(p + 1, &p, &mapped_range)) > + if (*p =3D=3D ':') { > + /* There's a range or address to map to as well */ > + char *addr_end =3D strchr(p, '/'); > + > + if (addr_end) { > + *addr_end =3D '\0'; > + > + if (*p =3D=3D '[' && p[strlen(p) - 1] =3D=3D ']') { > + p[strlen(p) - 1] =3D '\0'; > + p++; > + } > + > + if (!inany_pton(p + 1, daddr)) > + die("Bad forwarding address '%s'", p); > + > + p =3D addr_end; > + } else { > + daddr =3D NULL; > + } We probably want to factor some of this address parsing out into a helper, since we're now doing it twice. > + > + > + if (parse_port_range(p + 1, (const char **)&p, > + &mapped_range)) > goto bad; > if ((mapped_range.last - mapped_range.first) !=3D > (orig_range.last - orig_range.first)) > @@ -629,7 +652,7 @@ static void fwd_rule_parse_ports(struct fwd_table *fw= d, bool del, uint8_t proto, > if (p !=3D ep) /* Garbage after the ranges */ > goto bad; > =20 > - 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 cha= r *optarg, > =20 > strncpy(buf, optarg, sizeof(buf) - 1); > =20 > - if ((spec =3D strchr(buf, '/'))) { > + if ((spec =3D strchr(buf, '/')) && > + strchr(spec, ':') =3D=3D strchr(buf, ':')) { strchr() for ':' needs a lot of caution, since it can appear within IPv6 addresses. > *spec =3D 0; > spec++; > =20 > 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; We probably want to rethink the names here. Both of these are destination addresses, just one is host side the other is guest side (or, in general, they're destination addresses for two different pifs). "initiating" vs. "target" are probably the terms to use, since we already use that in the flow table. At some point I'm pretty sure we'll also want to put a target pif in the table. Not sure if we want to introduce that initially, or whether just an address makes sense for the first cut. > char ifname[IFNAMSIZ]; > in_port_t first; > in_port_t last; > --=20 > 2.43.0 >=20 --=20 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 --CeHOs032v4npoHo3 Content-Type: application/pgp-signature; name=signature.asc -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmoFVXsACgkQzQJF27ox 2GdKhw/+L+JzD4nygQq56JLfG35EqPPuiqn+RQFxrzC9DkJdv3XeSpdEPD/8KW9V nXOEUgzPPnDV98troQGjqsZ5FipbkZs5RYIXUzzlNEtMPAKJfkw8lC1T+AsnlWxy rb3x/FjsxeVCw4UoU+wr+OMbrga2Uu8Iycp7xV8OCuq9DHPtwRFZ5wzjdDI/YRZo xloI36SZO091XfBph5DokIERGI12km5asVfBu6YS/vfUviI5jco4pk7H27j0ix5E 9rDMZK8Bhg7rYq2ZxbZrUZF+vWOrVXZNpyVXyXlIVVFjEIdcK6pMqI0WZ1G909dc qExOMejNE86071JT8aGeKSZmVX6qX5FivuwTHMwK9aVO3zR3AiL8w1uYv55jEh49 hirgEqdrB6scYgao85SRW3smhfW9Bh1iptLBwBRTETgniQcdjz8j8HBzC74oKhED 2RUahokTRsDWh83784cQnqfn/FDx/DTb4KwenEURp9AIzy49Mc/8JGnccnFqChdj sqVuCdLMkF3Y0eGAngB4ft15lo9KA/J2NA7Cfp99Xxx/gSXnHOWfd6KGhBvwvPnu tnPP+QLkPAD/FawAfdx8t6EAGpuMbJUNbZm04O+rHFoqY0ehhu3XDG4VoF05KHbM Xo7/0msXOnq7ChZ/NPCFx5CbaMwl4qYXzLZmErBVhPELzTnZJcM= =9ae2 -----END PGP SIGNATURE----- --CeHOs032v4npoHo3--