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=U5TPkkhR; dkim-atps=neutral Received: from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id 886A85A026D for ; Thu, 16 Apr 2026 03:47:27 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202602; t=1776304043; bh=g7dc77m7KuDxXuquKmJUeSZC18gAvCwXKHwhYKwrwfY=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=U5TPkkhRcQfFcILjCBW/eu89sAvQgKRY5ckcDsqYPc1zyEACn2uuEhc8W6vVHqvgK qyPRj3cZczdHxBU1g/sk1vI6e5h6+kl5SyIuzuA1gst5bObVnu7HcO17n8kzR/TUJx MLCyimSvn8JUPW3hev1JjdGXSNOEndRAelLmVaOUzzLz3Gwa1Yw5dkD1CYf7WxqM7+ 9YK4yynbR6m42yBrvqpZGC7CvK3HN75fpgEVH45ZFmTTzHsIBildJGINw99z/4/F7f T7kiEwZdrFrcDAJqmRuML9VdCVfG4q1/Tf8hegqvHDNYBGd8kdJBCYbHG1UyYbSxkh HcKZoDFy4swuw== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4fx1975L05z4wLZ; Thu, 16 Apr 2026 11:47:23 +1000 (AEST) Date: Thu, 16 Apr 2026 11:44:57 +1000 From: David Gibson To: Stefano Brivio Subject: Re: [PATCH v2 17/23] conf: Allow user-specified auto-scanned port forwarding ranges Message-ID: References: <20260410010309.736855-1-david@gibson.dropbear.id.au> <20260410010309.736855-18-david@gibson.dropbear.id.au> <20260416000450.56189eb6@elisabeth> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="h2GZyTM8ZipZQrvF" Content-Disposition: inline In-Reply-To: <20260416000450.56189eb6@elisabeth> Message-ID-Hash: LXXI5I6LCQQOU63EIP2SNF4NODPRXHME X-Message-ID-Hash: LXXI5I6LCQQOU63EIP2SNF4NODPRXHME 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: 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: --h2GZyTM8ZipZQrvF Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Thu, Apr 16, 2026 at 12:04:51AM +0200, Stefano Brivio wrote: > On Fri, 10 Apr 2026 11:03:03 +1000 > David Gibson wrote: >=20 > > The forwarding table now allows for arbitrary port ranges to be marked = as > > FWD_SCAN, meaning we don't open sockets for every port, but only those = we > > scan as listening on the target side. However, there's currently no way > > to create such rules, except -[tTuU] auto which always scans every port > > with an unspecified listening address and interface. > >=20 > > Allow user-specified "auto" ranges by moving the parsing of the "auto" > > keyword from conf_ports(), to conf_ports_spec() as part of the port > > specified. "auto" can be combined freely with other port ranges, e.g. > > -t 127.0.0.1/auto > > -u %lo/5000-7000,auto > > -T auto,12345 > > -U auto,~1-9000 > >=20 > > Note that any address and interface given only affects where the automa= tic > > forwards listen, not what addresses we consider when scanning. That is, > > if the target side is listening on *any* address, we will create a forw= ard > > on the specified address. > >=20 > > Link: https://bugs.passt.top/show_bug.cgi?id=3D180 > >=20 > > Signed-off-by: David Gibson > > --- > > conf.c | 85 ++++++++++++++++++++++++++++++++++++++++++--------------- > > passt.1 | 30 ++++++++++++++------ > > 2 files changed, 85 insertions(+), 30 deletions(-) > >=20 > > diff --git a/conf.c b/conf.c > > index f62109b5..8e3b4b20 100644 > > --- a/conf.c > > +++ b/conf.c > > @@ -13,6 +13,7 @@ > > */ > > =20 > > #include > > +#include > > #include > > #include > > #include > > @@ -112,6 +113,28 @@ static int parse_port_range(const char *s, const c= har **endptr, > > return 0; > > } > > =20 > > +/** > > + * parse_keyword() - Parse a literal keyword > > + * @s: String to parse > > + * @endptr: Update to the character after the keyword > > + * @kw: Keyword to accept > > + * > > + * Return: 0, if @s starts with @kw, -EINVAL if it does not > > + */ > > +static int parse_keyword(const char *s, const char **endptr, const cha= r *kw) > > +{ > > + size_t len =3D strlen(kw); > > + > > + if (strlen(s) < len) > > + return -EINVAL; > > + > > + if (memcmp(s, kw, len)) > > + return -EINVAL; > > + > > + *endptr =3D s + len; > > + return 0; > > +} > > + > > /** > > * conf_ports_range_except() - Set up forwarding for a range of ports = minus a > > * bitmap of exclusions > > @@ -249,6 +272,7 @@ static void conf_ports_spec(const struct ctx *c, > > uint8_t exclude[PORT_BITMAP_SIZE] =3D { 0 }; > > bool exclude_only =3D true; > > const char *p, *ep; > > + uint8_t flags =3D 0; > > unsigned i; > > =20 > > if (!strcmp(spec, "all")) { > > @@ -256,15 +280,32 @@ static void conf_ports_spec(const struct ctx *c, > > spec =3D ""; > > } > > =20 > > - /* Mark all exclusions first, they might be given after base ranges */ > > + /* Parse excluded ranges and "auto" in the first pass */ > > for_each_chunk(p, ep, spec, ",") { > > struct port_range xrange; > > =20 > > - if (*p !=3D '~') { > > - /* Not an exclude range, parse later */ > > + if (isdigit(*p)) { > > + /* Include range, parse later */ > > exclude_only =3D false; > > continue; > > } > > + > > + if (parse_keyword(p, &p, "auto") =3D=3D 0) { > > + if (p !=3D ep) /* Garbage after the keyword */ > > + goto bad; > > + > > + if (c->mode !=3D MODE_PASTA) { > > + die( > > +"'auto' port forwarding is only allowed for pasta"); > > + } > > + > > + flags |=3D FWD_SCAN; > > + continue; > > + } > > + > > + /* Should be an exclude range */ > > + if (*p !=3D '~') > > + goto bad; > > p++; > > =20 > > if (parse_port_range(p, &p, &xrange)) > > @@ -283,7 +324,7 @@ static void conf_ports_spec(const struct ctx *c, > > conf_ports_range_except(c, optname, optarg, fwd, > > proto, addr, ifname, > > 1, NUM_PORTS - 1, exclude, > > - 1, FWD_WEAK); > > + 1, flags | FWD_WEAK); > > return; > > } > > =20 > > @@ -291,8 +332,8 @@ static void conf_ports_spec(const struct ctx *c, > > for_each_chunk(p, ep, spec, ",") { > > struct port_range orig_range, mapped_range; > > =20 > > - if (*p =3D=3D '~') > > - /* Exclude range, already parsed */ > > + if (!isdigit(*p)) > > + /* Already parsed */ > > continue; > > =20 > > if (parse_port_range(p, &p, &orig_range)) > > @@ -320,7 +361,7 @@ static void conf_ports_spec(const struct ctx *c, > > proto, addr, ifname, > > orig_range.first, orig_range.last, > > exclude, > > - mapped_range.first, 0); > > + mapped_range.first, flags); > > } > > =20 > > return; > > @@ -366,17 +407,6 @@ static void conf_ports(const struct ctx *c, char o= ptname, const char *optarg, > > if (proto =3D=3D IPPROTO_UDP && c->no_udp) > > die("UDP port forwarding requested but UDP is disabled"); > > =20 > > - if (!strcmp(optarg, "auto")) { > > - if (c->mode !=3D MODE_PASTA) > > - die("'auto' port forwarding is only allowed for pasta"); > > - > > - conf_ports_range_except(c, optname, optarg, fwd, > > - proto, NULL, NULL, > > - 1, NUM_PORTS - 1, NULL, 1, FWD_SCAN); > > - > > - return; > > - } > > - > > strncpy(buf, optarg, sizeof(buf) - 1); > > =20 > > if ((spec =3D strchr(buf, '/'))) { > > @@ -1031,13 +1061,13 @@ static void usage(const char *name, FILE *f, in= t status) > > " can be specified multiple times\n" > > " SPEC can be:\n" > > " 'none': don't forward any ports\n" > > - "%s" > > " [ADDR[%%IFACE]/]PORTS: forward specific ports\n" > > " PORTS is either 'all' (forward all unbound, non-ephemeral\n" > > " ports), or a comma-separated list of ports, optionally\n" > > " ranged with '-' and optional target ports after ':'.\n" > > " Ranges can be reduced by excluding ports or ranges\n" > > - " prefixed by '~'\n" > > + " prefixed by '~'.\n" > > + "%s" > > " Examples:\n" > > " -t all Forward all ports\n" > > " -t 127.0.0.1/all Forward all ports from local address\n" > > @@ -1051,15 +1081,26 @@ static void usage(const char *name, FILE *f, in= t status) > > " -t 192.0.2.1/5 Bind port 5 of 192.0.2.1 to %s\n" > > " -t 5-25,~10-20 Forward ports 5 to 9, and 21 to 25\n" > > " -t ~25 Forward all ports except for 25\n" > > + "%s" > > " default: %s\n" > > " -u, --udp-ports SPEC UDP port forwarding to %s\n" > > " SPEC is as described for TCP above\n" > > " default: %s\n", > > guest, > > strstr(name, "pasta") ? > > - " 'auto': forward all ports currently bound in namespace\n" > > + " The 'auto' keyword may be given to only forward\n" > > + " ports which are bound in the target namespace\n" > > + : "", > > + guest, guest, guest, > > + strstr(name, "pasta") ? > > + " -t auto Forward all ports bound in namespace\n" > > + " -t 192.0.2.2/auto Forward ports from 192.0.2.2 if\n" > > + " they are bound in the namespace\n" > > + " -t 8000-8010,auto Forward ports 8000-8010 if they\n" > > + " are bound in the namespace\n" >=20 > The whole thing is now rendered as: >=20 > Examples: > -t all Forward all ports > -t 127.0.0.1/all Forward all ports from local address > 127.0.0.1 > -t 22 Forward local port 22 to 22 on namespace > -t 22:23 Forward local port 22 to 23 on namespace > -t 22,25 Forward ports 22, 25 to ports 22, 25 > -t 22-80 Forward ports 22 to 80 > -t 22-80:32-90 Forward ports 22 to 80 to > corresponding port numbers plus 10 > -t 192.0.2.1/5 Bind port 5 of 192.0.2.1 to namespace > -t 5-25,~10-20 Forward ports 5 to 9, and 21 to 25 > -t ~25 Forward all ports except for 25 > -t auto Forward all ports bound in namespace > -t 192.0.2.2/auto Forward ports from 192.0.2.2 if > they are bound in the namespace > -t 8000-8010,auto Forward ports 8000-8010 if they > are bound in the namespace >=20 > I think this could be: >=20 > " -t auto\t Forward all ports bound in namespace\n" > " -t ::1/auto Forward ports from ::1 if bound in\n" > " namespace\n" > " -t 80-82,auto Forward ports 80-82 if bound in\n" > " namespace\n" >=20 > instead. Good ideas, done. --=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 --h2GZyTM8ZipZQrvF Content-Type: application/pgp-signature; name=signature.asc -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmngPxgACgkQzQJF27ox 2Gd+yg//TOq2NU5EWxdsxLS3TI6m4QWfncgeprKWq6dMXF6TmkLaIY1OR0tetHVH Syaf+nF5LdUIRG4GWUpQoK8QgCO1HEmmC0JxfBAB7Otl/JvRHLABQjJcfB3eoCwZ oBecisXlc334H5MShscOZOfnr1UNC8JBQ7uyMO0GQCmHXYAASKhSIg4TFM87ba9e MMOYXp9vCvwKnrfqFG/u0lJDIk/HTNa+MGAs6J82ww0c8KbICxB2z+WF+7/FBqj9 UIZzUdC0ZjhQ2n8JVkjMQ1M1PsyTVt1RwUGmsQvUdgzqL10eR9g1Vd5P5sgdBw+K mVJXKxCJYjNq54NJ16tkE4HivjkEsunAMCmUmT7gi6a2Qge0TxYS0N5n24F0xtE5 iBQ/DSOQt9NAq3ea1y2ZJOulYHn4TSdbNisjcTZ20CXJrUppwbXy1g0Gg6n3MWOk dOSF3IjDlZKA351I5fFxI6wZI1B5UMI95HJKaV3CN4LYN61M+3bq0m86qPYu/zrE rIyY3Al4TiMxQgV27+hxCfwh/0biN3v9+R/wJ1iP45nQi9u9z9gj8Jq7lC/hjt4+ oibWklNgOQgpsvLLiklf/ynW7iKuj8+trxNn7koGZN2rYlx/1qQXvpoXncouJl1I EXWPWuXGleOFeIt0HRs2zKOA2rNXdMcGlrP4pxvFfEP5bmO2keo= =hh9E -----END PGP SIGNATURE----- --h2GZyTM8ZipZQrvF--