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 v2 12/23] conf: Don't be strict about exclusivity of forwarding mode
Date: Fri, 10 Apr 2026 11:02:58 +1000 [thread overview]
Message-ID: <20260410010309.736855-13-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20260410010309.736855-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 5c913820..67d88ee2 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);
}
/**
@@ -1602,12 +1570,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;
@@ -2212,17 +2177,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);
@@ -2273,22 +2238,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-10 1:03 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-10 1:02 [PATCH v2 00/23] Rework forwarding option parsing David Gibson
2026-04-10 1:02 ` [PATCH v2 01/23] conf: Split parsing of port specifiers from the rest of -[tuTU] parsing David Gibson
2026-04-10 1:02 ` [PATCH v2 02/23] conf: Simplify handling of default forwarding mode David Gibson
2026-04-10 1:02 ` [PATCH v2 03/23] conf: Move first pass handling of -[TU] next to handling of -[tu] David Gibson
2026-04-10 1:02 ` [PATCH v2 04/23] doc: Consolidate -[tu] option descriptions for passt and pasta David Gibson
2026-04-10 1:02 ` [PATCH v2 05/23] conf: Permit -[tTuU] all in pasta mode David Gibson
2026-04-10 1:02 ` [PATCH v2 06/23] fwd: Better split forwarding rule specification from associated sockets David Gibson
2026-04-10 1:02 ` [PATCH v2 07/23] fwd_rule: Move forwarding rule formatting David Gibson
2026-04-10 1:02 ` [PATCH v2 08/23] conf: Pass protocol explicitly to conf_ports_range_except() David Gibson
2026-04-10 1:02 ` [PATCH v2 09/23] fwd: Split rule building from rule adding David Gibson
2026-04-10 1:02 ` [PATCH v2 10/23] fwd_rule: Move rule conflict checking from fwd_rule_add() to caller David Gibson
2026-04-10 1:02 ` [PATCH v2 11/23] fwd: Improve error handling in fwd_rule_add() David Gibson
2026-04-10 1:02 ` David Gibson [this message]
2026-04-10 1:02 ` [PATCH v2 13/23] conf: Rework stepping through chunks of port specifiers David Gibson
2026-04-10 1:03 ` [PATCH v2 14/23] conf: Rework checking for garbage after a range David Gibson
2026-04-10 1:03 ` [PATCH v2 15/23] doc: Rework man page description of port specifiers David Gibson
2026-04-10 1:03 ` [PATCH v2 16/23] conf: Move "all" handling to port specifier David Gibson
2026-04-10 1:03 ` [PATCH v2 17/23] conf: Allow user-specified auto-scanned port forwarding ranges David Gibson
2026-04-10 1:03 ` [PATCH v2 18/23] conf: Move SO_BINDTODEVICE workaround to conf_ports() David Gibson
2026-04-10 1:03 ` [PATCH v2 19/23] conf: Don't pass raw commandline argument to conf_ports_spec() David Gibson
2026-04-10 1:03 ` [PATCH v2 20/23] fwd, conf: Add capabilities bits to each forwarding table David Gibson
2026-04-10 1:03 ` [PATCH v2 21/23] conf, fwd: Stricter rule checking in fwd_rule_add() David Gibson
2026-04-10 1:03 ` [PATCH v2 22/23] fwd_rule: Move ephemeral port probing to fwd_rule.c David Gibson
2026-04-10 1:03 ` [PATCH v2 23/23] fwd, conf: Move rule parsing code to fwd_rule.[ch] 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=20260410010309.736855-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).