From: David Gibson <david@gibson.dropbear.id.au>
To: passt-dev@passt.top, Stefano Brivio <sbrivio@redhat.com>
Cc: David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH 12/18] conf: Don't be strict about exclusivity of forwarding mode
Date: Tue, 7 Apr 2026 13:16:24 +1000 [thread overview]
Message-ID: <20260407031630.2457081-13-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20260407031630.2457081-1-david@gibson.dropbear.id.au>
Currently as well as building the forwarding tables, conf() maintains a
"forwarding mode" value for each protocol and direction. This prevents,
for example "-t all" and "-t 40000" being given on the same command line.
This restriction predates the forwarding table and is no longer really
necessary. Remove the restriction, instead doing our best to apply all the
given options simultaneously.
* Many combinations previously disallowed will still be disallowed because
of conflicts between the specific generated rules, e.g.
-t all -t 8888
(because -t all already listens on port 8888)
* Some new combinations are now allowed and will work, e.g.
-t all -t 40000
because 'all' excludes ephemeral ports (which includes 40000 on default
Linux configurations).
* We remove our mode variables, but keep boolean variables to track if
any forwarding config option has been given. This is needed in order to
correctly default to -t auto -T auto -u auto -U auto for pasta.
* -[tTuU] none after any other rules is still considered an error.
However -t none *before* other rules is allowed. This is potentially
confusing, but is awkward to avoid for the time being.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
conf.c | 97 ++++++++++++++++------------------------------------------
1 file changed, 27 insertions(+), 70 deletions(-)
diff --git a/conf.c b/conf.c
index cd30f2f8..1e456361 100644
--- a/conf.c
+++ b/conf.c
@@ -232,22 +232,6 @@ fail:
fwd_rule_fmt(&rule, rulestr, sizeof(rulestr)));
}
-/**
- * enum fwd_mode - Overall forwarding mode for a direction and protocol
- * @FWD_MODE_UNSET Initial value, not parsed/configured yet
- * @FWD_MODE_SPEC Forward specified ports
- * @FWD_MODE_NONE No forwarded ports
- * @FWD_MODE_AUTO Automatic detection and forwarding based on bound ports
- * @FWD_MODE_ALL Bind all free ports
- */
-enum fwd_mode {
- FWD_MODE_UNSET = 0,
- FWD_MODE_SPEC,
- FWD_MODE_NONE,
- FWD_MODE_AUTO,
- FWD_MODE_ALL,
-};
-
/**
* conf_ports_spec() - Parse port range(s) specifier
* @c: Execution context
@@ -350,13 +334,12 @@ bad:
* @optname: Short option name, t, T, u, or U
* @optarg: Option argument (port specification)
* @fwd: Forwarding table to be updated
- * @mode: Overall port forwarding mode (updated)
*/
static void conf_ports(const struct ctx *c, char optname, const char *optarg,
- struct fwd_table *fwd, enum fwd_mode *mode)
+ struct fwd_table *fwd)
{
union inany_addr addr_buf = inany_any6, *addr = &addr_buf;
- char buf[BUFSIZ], *spec, *ifname = NULL, *p;
+ char buf[BUFSIZ], *spec, *ifname = NULL;
uint8_t proto;
if (optname == 't' || optname == 'T')
@@ -367,10 +350,14 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
assert(0);
if (!strcmp(optarg, "none")) {
- if (*mode)
- goto mode_conflict;
+ unsigned i;
- *mode = FWD_MODE_NONE;
+ for (i = 0; i < fwd->count; i++) {
+ if (fwd->rules[i].proto == proto) {
+ die("-%c none conflicts with previous options",
+ optname);
+ }
+ }
return;
}
@@ -380,14 +367,9 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
die("UDP port forwarding requested but UDP is disabled");
if (!strcmp(optarg, "auto")) {
- if (*mode)
- goto mode_conflict;
-
if (c->mode != MODE_PASTA)
die("'auto' port forwarding is only allowed for pasta");
- *mode = FWD_MODE_AUTO;
-
conf_ports_range_except(c, optname, optarg, fwd,
proto, NULL, NULL,
1, NUM_PORTS - 1, NULL, 1, FWD_SCAN);
@@ -398,11 +380,6 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
if (!strcmp(optarg, "all")) {
uint8_t exclude[PORT_BITMAP_SIZE] = { 0 };
- if (*mode)
- goto mode_conflict;
-
- *mode = FWD_MODE_ALL;
-
/* Exclude ephemeral ports */
fwd_port_map_ephemeral(exclude);
@@ -413,11 +390,6 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
return;
}
- if (*mode > FWD_MODE_SPEC)
- die("Specific ports cannot be specified together with all/none/auto");
-
- *mode = FWD_MODE_SPEC;
-
strncpy(buf, optarg, sizeof(buf) - 1);
if ((spec = strchr(buf, '/'))) {
@@ -445,7 +417,7 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
if (ifname == buf + 1) { /* Interface without address */
addr = NULL;
} else {
- p = buf;
+ char *p = buf;
/* Allow square brackets for IPv4 too for convenience */
if (*p == '[' && p[strlen(p) - 1] == ']') {
@@ -482,10 +454,6 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
ifname = "lo";
conf_ports_spec(c, optname, optarg, fwd, proto, addr, ifname, spec);
- return;
-
-mode_conflict:
- die("Port forwarding mode '%s' conflicts with previous mode", optarg);
}
/**
@@ -1594,12 +1562,9 @@ void conf(struct ctx *c, int argc, char **argv)
};
const char *optstring = "+dqfel:hs:F:I:p:P:m:a:n:M:g:i:o:D:S:H:461t:u:T:U:";
const char *logname = (c->mode == MODE_PASTA) ? "pasta" : "passt";
+ bool opt_t = false, opt_T = false, opt_u = false, opt_U = false;
char userns[PATH_MAX] = { 0 }, netns[PATH_MAX] = { 0 };
bool copy_addrs_opt = false, copy_routes_opt = false;
- enum fwd_mode tcp_out_mode = FWD_MODE_UNSET;
- enum fwd_mode udp_out_mode = FWD_MODE_UNSET;
- enum fwd_mode tcp_in_mode = FWD_MODE_UNSET;
- enum fwd_mode udp_in_mode = FWD_MODE_UNSET;
bool v4_only = false, v6_only = false;
unsigned dns4_idx = 0, dns6_idx = 0;
unsigned long max_mtu = IP_MAX_MTU;
@@ -2204,17 +2169,17 @@ void conf(struct ctx *c, int argc, char **argv)
name = getopt_long(argc, argv, optstring, options, NULL);
if (name == 't') {
- conf_ports(c, name, optarg, c->fwd[PIF_HOST],
- &tcp_in_mode);
+ opt_t = true;
+ conf_ports(c, name, optarg, c->fwd[PIF_HOST]);
} else if (name == 'u') {
- conf_ports(c, name, optarg, c->fwd[PIF_HOST],
- &udp_in_mode);
+ opt_u = true;
+ conf_ports(c, name, optarg, c->fwd[PIF_HOST]);
} else if (name == 'T') {
- conf_ports(c, name, optarg, c->fwd[PIF_SPLICE],
- &tcp_out_mode);
+ opt_T = true;
+ conf_ports(c, name, optarg, c->fwd[PIF_SPLICE]);
} else if (name == 'U') {
- conf_ports(c, name, optarg, c->fwd[PIF_SPLICE],
- &udp_out_mode);
+ opt_U = true;
+ conf_ports(c, name, optarg, c->fwd[PIF_SPLICE]);
}
} while (name != -1);
@@ -2265,22 +2230,14 @@ void conf(struct ctx *c, int argc, char **argv)
}
if (c->mode == MODE_PASTA) {
- if (!tcp_in_mode) {
- conf_ports(c, 't', "auto",
- c->fwd[PIF_HOST], &tcp_in_mode);
- }
- if (!tcp_out_mode) {
- conf_ports(c, 'T', "auto",
- c->fwd[PIF_SPLICE], &tcp_out_mode);
- }
- if (!udp_in_mode) {
- conf_ports(c, 'u', "auto",
- c->fwd[PIF_HOST], &udp_in_mode);
- }
- if (!udp_out_mode) {
- conf_ports(c, 'U', "auto",
- c->fwd[PIF_SPLICE], &udp_out_mode);
- }
+ if (!opt_t)
+ conf_ports(c, 't', "auto", c->fwd[PIF_HOST]);
+ if (!opt_T)
+ conf_ports(c, 'T', "auto", c->fwd[PIF_SPLICE]);
+ if (!opt_u)
+ conf_ports(c, 'u', "auto", c->fwd[PIF_HOST]);
+ if (!opt_U)
+ conf_ports(c, 'U', "auto", c->fwd[PIF_SPLICE]);
}
if (!c->quiet)
--
2.53.0
next prev parent reply other threads:[~2026-04-07 3:16 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-07 3:16 [PATCH 00/18] Rework forwarding option parsing David Gibson
2026-04-07 3:16 ` [PATCH 01/18] conf: Split parsing of port specifiers from the rest of -[tuTU] parsing David Gibson
2026-04-07 3:16 ` [PATCH 02/18] conf: Simplify handling of default forwarding mode David Gibson
2026-04-07 23:14 ` Stefano Brivio
2026-04-08 1:10 ` David Gibson
2026-04-07 3:16 ` [PATCH 03/18] conf: Move first pass handling of -[TU] next to handling of -[tu] David Gibson
2026-04-07 3:16 ` [PATCH 04/18] doc: Consolidate -[tu] option descriptions for passt and pasta David Gibson
2026-04-07 23:14 ` Stefano Brivio
2026-04-08 1:23 ` David Gibson
2026-04-07 3:16 ` [PATCH 05/18] conf: Permit -[tTuU] all in pasta mode David Gibson
2026-04-07 3:16 ` [PATCH 06/18] fwd: Better split forwarding rule specification from associated sockets David Gibson
2026-04-07 23:14 ` Stefano Brivio
2026-04-08 1:30 ` David Gibson
2026-04-08 21:39 ` Stefano Brivio
2026-04-09 0:47 ` David Gibson
2026-04-07 3:16 ` [PATCH 07/18] fwd_rule: Move forwarding rule formatting David Gibson
2026-04-07 3:16 ` [PATCH 08/18] conf: Pass protocol explicitly to conf_ports_range_except() David Gibson
2026-04-07 3:16 ` [PATCH 09/18] fwd: Split rule building from rule adding David Gibson
2026-04-07 3:16 ` [PATCH 10/18] fwd_rule: Move rule conflict checking from fwd_rule_add() to caller David Gibson
2026-04-07 23:14 ` Stefano Brivio
2026-04-08 1:37 ` David Gibson
2026-04-08 4:42 ` David Gibson
2026-04-07 3:16 ` [PATCH 11/18] fwd: Improve error handling in fwd_rule_add() David Gibson
2026-04-08 21:40 ` Stefano Brivio
2026-04-09 0:10 ` David Gibson
2026-04-07 3:16 ` David Gibson [this message]
2026-04-08 21:40 ` [PATCH 12/18] conf: Don't be strict about exclusivity of forwarding mode Stefano Brivio
2026-04-09 0:12 ` David Gibson
2026-04-07 3:16 ` [PATCH 13/18] conf: Rework stepping through chunks of port specifiers David Gibson
2026-04-08 21:40 ` Stefano Brivio
2026-04-09 0:13 ` David Gibson
2026-04-07 3:16 ` [PATCH 14/18] conf: Rework checking for garbage after a range David Gibson
2026-04-08 21:40 ` Stefano Brivio
2026-04-09 0:15 ` David Gibson
2026-04-07 3:16 ` [PATCH 15/18] conf: Move "all" handling to port specifier David Gibson
2026-04-08 21:40 ` Stefano Brivio
2026-04-07 3:16 ` [PATCH 16/18] conf: Allow user-specified auto-scanned port forwarding ranges David Gibson
2026-04-08 21:40 ` Stefano Brivio
2026-04-07 3:16 ` [PATCH 17/18] conf: Move SO_BINDTODEVICE workaround to conf_ports() David Gibson
2026-04-07 3:16 ` [PATCH 18/18] conf: Don't pass raw commandline argument to conf_ports_spec() David Gibson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260407031630.2457081-13-david@gibson.dropbear.id.au \
--to=david@gibson.dropbear.id.au \
--cc=passt-dev@passt.top \
--cc=sbrivio@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).