From 0294fae2050a224d7c6ad99d9cb8f2490c58594c Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 11 Mar 2026 23:03:06 +1100 Subject: conf, fwd: Make overall forwarding mode local to conf path The 'mode' field of struct fwd_ports records the overall forwarding mode. Now that runtime forwarding decisions are made based on the forwarding table, this is almost unused outside conf(). The only exception is the auto-port scanning code, which uses it to determine if a port scan is necessary. We can instead derive that from the forwarding table itself by checking if there are any entries with the FWD_SCAN flag. Once that's done, make the mode purely local to conf(). While we're there rename the constants to FWD_MODE_* to avoid confusion with the forwarding rule flag bits, which are also prefixed with FWD_. Signed-off-by: David Gibson Signed-off-by: Stefano Brivio --- conf.c | 87 ++++++++++++++++++++++++++++++++++++++++++------------------------ fwd.c | 27 ++++++++++++++++----- fwd.h | 10 -------- 3 files changed, 77 insertions(+), 47 deletions(-) diff --git a/conf.c b/conf.c index 11d8453..a1a67f9 100644 --- a/conf.c +++ b/conf.c @@ -199,15 +199,32 @@ static void conf_ports_range_except(const struct ctx *c, char optname, } } +/** + * 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() - Parse port configuration options, initialise UDP/TCP sockets * @c: Execution context * @optname: Short option name, t, T, u, or U * @optarg: Option argument (port specification) * @fwd: Pointer to @fwd_ports to be updated + * @mode: Overall port forwarding mode (updated) */ static void conf_ports(const struct ctx *c, char optname, const char *optarg, - struct fwd_ports *fwd) + struct fwd_ports *fwd, enum fwd_mode *mode) { union inany_addr addr_buf = inany_any6, *addr = &addr_buf; char buf[BUFSIZ], *spec, *ifname = NULL, *p; @@ -216,10 +233,10 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg, unsigned i; if (!strcmp(optarg, "none")) { - if (fwd->mode) + if (*mode) goto mode_conflict; - fwd->mode = FWD_NONE; + *mode = FWD_MODE_NONE; return; } @@ -229,7 +246,7 @@ 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 (fwd->mode) + if (*mode) goto mode_conflict; if (c->mode != MODE_PASTA) @@ -241,18 +258,18 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg, warn( "Forwarding from addresses other than 127.0.0.1 will not work"); } - fwd->mode = FWD_AUTO; + *mode = FWD_MODE_AUTO; return; } if (!strcmp(optarg, "all")) { - if (fwd->mode) + if (*mode) goto mode_conflict; if (c->mode == MODE_PASTA) die("'all' port forwarding is only allowed for passt"); - fwd->mode = FWD_ALL; + *mode = FWD_MODE_ALL; /* Exclude ephemeral ports */ for (i = 0; i < NUM_PORTS; i++) @@ -266,10 +283,10 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg, return; } - if (fwd->mode > FWD_SPEC) + if (*mode > FWD_MODE_SPEC) die("Specific ports cannot be specified together with all/none/auto"); - fwd->mode = FWD_SPEC; + *mode = FWD_MODE_SPEC; strncpy(buf, optarg, sizeof(buf) - 1); @@ -1525,7 +1542,11 @@ void conf(struct ctx *c, int argc, char **argv) const char *logname = (c->mode == MODE_PASTA) ? "pasta" : "passt"; char userns[PATH_MAX] = { 0 }, netns[PATH_MAX] = { 0 }; bool copy_addrs_opt = false, copy_routes_opt = false; - enum fwd_ports_mode fwd_default = FWD_NONE; + 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; + enum fwd_mode fwd_default = FWD_MODE_NONE; bool v4_only = false, v6_only = false; unsigned dns4_idx = 0, dns6_idx = 0; unsigned long max_mtu = IP_MAX_MTU; @@ -1540,17 +1561,16 @@ void conf(struct ctx *c, int argc, char **argv) int name, ret; uid_t uid; gid_t gid; + if (c->mode == MODE_PASTA) { c->no_dhcp_dns = c->no_dhcp_dns_search = 1; - fwd_default = FWD_AUTO; + fwd_default = FWD_MODE_AUTO; } if (tap_l2_max_len(c) - ETH_HLEN < max_mtu) max_mtu = tap_l2_max_len(c) - ETH_HLEN; c->mtu = ROUND_DOWN(max_mtu, sizeof(uint32_t)); - c->tcp.fwd_in.mode = c->tcp.fwd_out.mode = FWD_UNSET; - c->udp.fwd_in.mode = c->udp.fwd_out.mode = FWD_UNSET; memcpy(c->our_tap_mac, MAC_OUR_LAA, ETH_ALEN); optind = 0; @@ -2100,9 +2120,11 @@ 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->tcp.fwd_in); + conf_ports(c, name, optarg, + &c->tcp.fwd_in, &tcp_in_mode); } else if (name == 'u') { - conf_ports(c, name, optarg, &c->udp.fwd_in); + conf_ports(c, name, optarg, + &c->udp.fwd_in, &udp_in_mode); } else if (name == 'D') { struct in6_addr dns6_tmp; struct in_addr dns4_tmp; @@ -2172,10 +2194,13 @@ void conf(struct ctx *c, int argc, char **argv) do { name = getopt_long(argc, argv, optstring, options, NULL); - if (name == 'T') - conf_ports(c, name, optarg, &c->tcp.fwd_out); - else if (name == 'U') - conf_ports(c, name, optarg, &c->udp.fwd_out); + if (name == 'T') { + conf_ports(c, name, optarg, + &c->tcp.fwd_out, &tcp_out_mode); + } else if (name == 'U') { + conf_ports(c, name, optarg, + &c->udp.fwd_out, &udp_out_mode); + } } while (name != -1); if (!c->ifi4) @@ -2197,31 +2222,31 @@ void conf(struct ctx *c, int argc, char **argv) if_indextoname(c->ifi6, c->pasta_ifn); } - if (!c->tcp.fwd_in.mode) - c->tcp.fwd_in.mode = fwd_default; - if (!c->tcp.fwd_out.mode) - c->tcp.fwd_out.mode = fwd_default; - if (!c->udp.fwd_in.mode) - c->udp.fwd_in.mode = fwd_default; - if (!c->udp.fwd_out.mode) - c->udp.fwd_out.mode = fwd_default; + if (!tcp_in_mode) + tcp_in_mode = fwd_default; + if (!tcp_out_mode) + tcp_out_mode = fwd_default; + if (!udp_in_mode) + udp_in_mode = fwd_default; + if (!udp_out_mode) + udp_out_mode = fwd_default; - if (c->tcp.fwd_in.mode == FWD_AUTO) { + if (tcp_in_mode == FWD_MODE_AUTO) { conf_ports_range_except(c, 't', "auto", &c->tcp.fwd_in, NULL, NULL, 1, NUM_PORTS - 1, NULL, 1, FWD_SCAN); } - if (c->tcp.fwd_out.mode == FWD_AUTO) { + if (tcp_out_mode == FWD_MODE_AUTO) { conf_ports_range_except(c, 'T', "auto", &c->tcp.fwd_out, NULL, "lo", 1, NUM_PORTS - 1, NULL, 1, FWD_SCAN); } - if (c->udp.fwd_in.mode == FWD_AUTO) { + if (udp_in_mode == FWD_MODE_AUTO) { conf_ports_range_except(c, 'u', "auto", &c->udp.fwd_in, NULL, NULL, 1, NUM_PORTS - 1, NULL, 1, FWD_SCAN); } - if (c->udp.fwd_out.mode == FWD_AUTO) { + if (udp_out_mode == FWD_MODE_AUTO) { conf_ports_range_except(c, 'U', "auto", &c->udp.fwd_out, NULL, "lo", 1, NUM_PORTS - 1, NULL, 1, FWD_SCAN); diff --git a/fwd.c b/fwd.c index 4052b79..c5090fb 100644 --- a/fwd.c +++ b/fwd.c @@ -717,6 +717,21 @@ static void procfs_scan_listen(int fd, unsigned int lstate, uint8_t *map) } } +/** + * has_scan_rules() - Does the given table have any FWD_SCAN rules? + * @fwd: Forwarding table + */ +static bool has_scan_rules(const struct fwd_ports *fwd) +{ + unsigned i; + + for (i = 0; i < fwd->count; i++) { + if (fwd->rules[i].flags & FWD_SCAN) + return true; + } + return false; +} + /** * fwd_scan_ports_tcp() - Scan /proc to update TCP forwarding map * @fwd: Forwarding information to update @@ -724,7 +739,7 @@ static void procfs_scan_listen(int fd, unsigned int lstate, uint8_t *map) */ static void fwd_scan_ports_tcp(struct fwd_ports *fwd, const uint8_t *exclude) { - if (fwd->mode != FWD_AUTO) + if (!has_scan_rules(fwd)) return; memset(fwd->map, 0, PORT_BITMAP_SIZE); @@ -743,7 +758,7 @@ static void fwd_scan_ports_udp(struct fwd_ports *fwd, const struct fwd_ports *tcp_fwd, const uint8_t *exclude) { - if (fwd->mode != FWD_AUTO) + if (!has_scan_rules(fwd)) return; memset(fwd->map, 0, PORT_BITMAP_SIZE); @@ -816,19 +831,19 @@ void fwd_scan_ports_init(struct ctx *c) c->udp.fwd_in.scan4 = c->udp.fwd_in.scan6 = -1; c->udp.fwd_out.scan4 = c->udp.fwd_out.scan6 = -1; - if (c->tcp.fwd_in.mode == FWD_AUTO) { + if (has_scan_rules(&c->tcp.fwd_in)) { c->tcp.fwd_in.scan4 = open_in_ns(c, "/proc/net/tcp", flags); c->tcp.fwd_in.scan6 = open_in_ns(c, "/proc/net/tcp6", flags); } - if (c->udp.fwd_in.mode == FWD_AUTO) { + if (has_scan_rules(&c->udp.fwd_in)) { c->udp.fwd_in.scan4 = open_in_ns(c, "/proc/net/udp", flags); c->udp.fwd_in.scan6 = open_in_ns(c, "/proc/net/udp6", flags); } - if (c->tcp.fwd_out.mode == FWD_AUTO) { + if (has_scan_rules(&c->tcp.fwd_out)) { c->tcp.fwd_out.scan4 = open("/proc/net/tcp", flags); c->tcp.fwd_out.scan6 = open("/proc/net/tcp6", flags); } - if (c->udp.fwd_out.mode == FWD_AUTO) { + if (has_scan_rules(&c->udp.fwd_out)) { c->udp.fwd_out.scan4 = open("/proc/net/udp", flags); c->udp.fwd_out.scan6 = open("/proc/net/udp6", flags); } diff --git a/fwd.h b/fwd.h index 7f52f76..6d657dd 100644 --- a/fwd.h +++ b/fwd.h @@ -68,14 +68,6 @@ struct fwd_listen_ref { unsigned rule :FWD_RULE_BITS; }; -enum fwd_ports_mode { - FWD_UNSET = 0, - FWD_SPEC = 1, - FWD_NONE, - FWD_AUTO, - FWD_ALL, -}; - #define PORT_BITMAP_SIZE DIV_ROUND_UP(NUM_PORTS, 8) /* Maximum number of listening sockets (per pif & protocol) @@ -87,7 +79,6 @@ enum fwd_ports_mode { /** * fwd_ports() - Describes port forwarding for one protocol and direction - * @mode: Overall mode (all, none, auto, specific ports) * @scan4: /proc/net fd to scan for IPv4 ports when in AUTO mode * @scan6: /proc/net fd to scan for IPv6 ports when in AUTO mode * @count: Number of forwarding rules @@ -97,7 +88,6 @@ enum fwd_ports_mode { * @socks: Listening sockets for forwarding */ struct fwd_ports { - enum fwd_ports_mode mode; int scan4; int scan6; unsigned count; -- cgit v1.2.3