From mboxrd@z Thu Jan 1 00:00:00 1970 Received: by passt.top (Postfix, from userid 1000) id 718795A026E; Sun, 22 Mar 2026 15:18:43 +0100 (CET) From: Stefano Brivio To: passt-dev@passt.top Subject: [PATCH 18/18] [DO NOT USE] pesto, conf: Parse, send and receive rules, try to sync forwards Date: Sun, 22 Mar 2026 15:18:43 +0100 Message-ID: <20260322141843.4095972-3-sbrivio@redhat.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260319061157.1983818-1-david@gibson.dropbear.id.au> References: <20260319061157.1983818-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: IONIQBTUIM33RH7U7PTT57X3JJZ36JVO X-Message-ID-Hash: IONIQBTUIM33RH7U7PTT57X3JJZ36JVO X-MailFrom: sbrivio@passt.top 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: David Gibson 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: *** DO NOT USE ***: this introduces a security weakness as it allows passt to dynamically allocate memory based on external input (needed by fwd_rule_seread(), which will need either a replacement or a rewrite). This adds parsing of options using conf_ports() in pesto, builds rules, takes them out of the table (!) and sends them one by one to passt, which now receives them and uses them to replace the current forwarding table. This part works. This also adds a convenience implementation that closes all current sockets and tries to synchronise listening sockets from the new set of rules. This partially works, but for some reason sockets don't bind correctly, and I couldn't quite wrap my head around the complexity of the new "fwd_rule_state" and the fact that with this we can't simply dump rules in the tables and re-sync them (this part was very simple and it worked in my earlier draft). I'm sharing this part as well anyway as it might be convenient if it's useful to build a quick hack that makes the whole flow work with Podman, but that's about it. Signed-off-by: Stefano Brivio --- Makefile | 2 +- conf.c | 65 +++++++++++++++++++++++++++++++++++++++-- fwd.c | 8 ++++-- fwd.h | 2 +- pesto.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- pif.h | 2 ++ util.c | 2 ++ 7 files changed, 160 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index b6b6a82..2423570 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ SRCS = $(PASST_SRCS) $(QRAP_SRCS) $(PASST_REPAIR_SRCS) $(PESTO_SRCS) MANPAGES = passt.1 pasta.1 pesto.1 qrap.1 passt-repair.1 PESTO_HEADERS = common.h fwd_rule.h inany.h ip.h pesto.h serialise.h ports.h \ - lineread.h + lineread.h pif.h PASST_HEADERS = arch.h arp.h checksum.h conf.h dhcp.h dhcpv6.h epoll_ctl.h \ flow.h fwd.h flow_table.h icmp.h icmp_flow.h iov.h isolation.h \ lineread.h log.h migrate.h ndp.h netlink.h packet.h passt.h pasta.h \ diff --git a/conf.c b/conf.c index 8e54b85..10fef65 100644 --- a/conf.c +++ b/conf.c @@ -2041,6 +2041,49 @@ static int conf_send_rules(const struct ctx *c, int fd) return 0; } +/** + * conf_send_rules() - Send current forwarding rules to dynamic update client (pesto) + * @c: Execution context + * @fd: Socket to the client + * + * Return: 0 on success, -1 on failure + */ +static int conf_recv_rules(const struct ctx *c, int fd) +{ + unsigned pif, i, j; + + for (i = 0; i < PIF_NUM_TYPES; i++) { + struct fwd_table *fwd; + struct fwd_rule r; + uint32_t count; + uint8_t num; + + if (seread_u8(fd, &num)) + return -1; + + pif = num; + if (pif == PIF_NONE) + return 0; + + fwd = c->fwd[pif]; + if (!fwd) + continue; + + fwd_listen_close(fwd); + + if (seread_u32(fd, &count)) + return -1; + + for (j = 0; j < count; j++) { + fwd_rule_seread(fd, &r); + fwd_rule_add(fwd, r.proto, 0, &r.addr, NULL, + r.first, r.last, r.to); + } + } + + return 0; +} + /** * conf_listen_handler() - Handle events on configuration listening socket * @c: Execution context @@ -2055,14 +2098,14 @@ void conf_listen_handler(struct ctx *c, uint32_t events) union epoll_ref ref = { .type = EPOLL_TYPE_CONF }; struct ucred uc = { 0 }; socklen_t len = sizeof(uc); - int fd, rc; + int fd, rc, i; if (events != EPOLLIN) { err("Unexpected event 0x%04x on configuration socket", events); return; } - fd = accept4(c->fd_control_listen, NULL, NULL, SOCK_NONBLOCK); + fd = accept4(c->fd_control_listen, NULL, NULL, 0); if (fd < 0) { warn_perror("accept4() on configuration listening socket"); return; @@ -2103,6 +2146,24 @@ void conf_listen_handler(struct ctx *c, uint32_t events) if (conf_send_rules(c, fd) < 0) goto fail; + if (conf_recv_rules(c, fd) < 0) + goto fail; + + info("Received new forwarding table:"); + for (i = 0; i < PIF_NUM_TYPES; i++) { + if (!c->fwd[i]) + continue; + + info("Forwarding from %s:", pif_name(i)); + fwd_rules_print(c->fwd[i]); + } + + memset(&c->tcp.scan_in, 0, PORT_BITMAP_SIZE); + memset(&c->tcp.scan_out, 0, PORT_BITMAP_SIZE); + memset(&c->udp.scan_in, 0, PORT_BITMAP_SIZE); + memset(&c->udp.scan_out, 0, PORT_BITMAP_SIZE); + fwd_listen_init(c); + return; fail: diff --git a/fwd.c b/fwd.c index 4592af2..eda382e 100644 --- a/fwd.c +++ b/fwd.c @@ -487,12 +487,12 @@ int fwd_listen_sync(const struct ctx *c, uint8_t pif, /** fwd_listen_close() - Close all listening sockets * @fwd: Forwarding information */ -void fwd_listen_close(const struct fwd_table *fwd) +void fwd_listen_close(struct fwd_table *fwd) { unsigned i; for (i = 0; i < fwd->count; i++) { - const struct fwd_rule_state *rs = &fwd->rules[i]; + struct fwd_rule_state *rs = &fwd->rules[i]; unsigned port; for (port = rs->rule.first; port <= rs->rule.last; port++) { @@ -503,9 +503,11 @@ void fwd_listen_close(const struct fwd_table *fwd) } } } + + fwd->sock_count = 0; } -/** fwd_listen_init() - Set up listening sockets at start up +/** fwd_listen_init() - Set up listening sockets * @c: Execution context * * Return: 0 on success, -1 on failure diff --git a/fwd.h b/fwd.h index 00450a4..d2a0c39 100644 --- a/fwd.h +++ b/fwd.h @@ -51,7 +51,7 @@ void fwd_scan_ports_timer(struct ctx * c, const struct timespec *now); int fwd_listen_sync(const struct ctx *c, uint8_t pif, const struct fwd_scan *tcp, const struct fwd_scan *udp); -void fwd_listen_close(const struct fwd_table *fwd); +void fwd_listen_close(struct fwd_table *fwd); int fwd_listen_init(const struct ctx *c); bool nat_inbound(const struct ctx *c, const union inany_addr *addr, diff --git a/pesto.c b/pesto.c index 42fa7f2..85683fa 100644 --- a/pesto.c +++ b/pesto.c @@ -38,6 +38,7 @@ #include "fwd_rule.h" #include "pesto.h" #include "log.h" +#include "pif.h" int verbosity = 1; @@ -65,6 +66,36 @@ static void usage(const char *name, FILE *f, int status) FPRINTF(f, "Usage: %s [OPTION]... PATH\n", name); FPRINTF(f, "\n" + " -t, --tcp-ports SPEC TCP inbound port forwarding\n" + " can be specified multiple times\n" + " SPEC can be:\n" + " 'none': don't forward any ports\n" + " 'auto': forward all ports currently bound in namespace\n" + " 'all': forward all unbound, non-ephemeral ports\n" + " a comma-separated list, optionally ranged with '-'\n" + " and optional target ports after ':', with optional\n" + " address specification suffixed by '/' and optional\n" + " interface prefixed by '%%'. Examples:\n" + " -t 22 Forward local port 22 to port 22 in netns\n" + " -t 22:23 Forward local port 22 to port 23\n" + " -t 22,25 Forward ports 22, 25 to ports 22, 25\n" + " -t 22-80 Forward ports 22 to 80\n" + " -t 22-80:32-90 Forward ports 22 to 80 to\n" + " corresponding port numbers plus 10\n" + " -t 192.0.2.1/5 Bind port 5 of 192.0.2.1\n" + " -t 5-25,~10-20 Forward ports 5 to 9, and 21 to 25\n" + " -t ~25 Forward all bound ports except for 25\n" + " IPv6 bound ports are also forwarded for IPv4\n" + " -u, --udp-ports SPEC UDP inbound port forwarding\n" + " SPEC is as described for TCP above\n" + " IPv6 bound ports are also forwarded for IPv4\n" + " unless specified, with '-t auto', UDP ports with numbers\n" + " corresponding to forwarded TCP port numbers are\n" + " forwarded too\n" + " -T, --tcp-ns SPEC TCP port forwarding to init namespace\n" + " SPEC is as described above\n" + " -U, --udp-ns SPEC UDP port forwarding to init namespace\n" + " SPEC is as described above\n" " -v, --verbose Be more verbose\n" " -q, --quiet Be less verbose\n" " -h, --help Display this help message and exit\n" @@ -221,7 +252,7 @@ static void show_state(const struct conf_state *state) * * Return: 0 on success, won't return on failure * - * #syscalls:pesto connect write close exit_group fstat brk getrandom + * #syscalls:pesto connect write close exit_group fstat brk getrandom openat * #syscalls:pesto socket s390x:socketcall i686:socketcall * #syscalls:pesto recvfrom recvmsg arm:recv ppc64le:recv * #syscalls:pesto sendto sendmsg arm:send ppc64le:send @@ -233,15 +264,22 @@ int main(int argc, char **argv) {"verbose", no_argument, NULL, 'v' }, {"help", no_argument, NULL, 'h' }, {"version", no_argument, NULL, 1 }, + {"tcp-ports", required_argument, NULL, 't' }, + {"udp-ports", required_argument, NULL, 'u' }, + {"tcp-ns", required_argument, NULL, 'T' }, + {"udp-ns", required_argument, NULL, 'U' }, { 0 }, }; + struct fwd_table fwd_in = { .count = 0 }, fwd_out = { .count = 0 }; struct sockaddr_un a = { AF_UNIX, "" }; - const char *optstring = "vh"; + const char *optstring = "vht:u:T:U:"; + enum fwd_mode fwd_default; struct pesto_hello hello; struct conf_state *state; struct sock_fprog prog; int optname, ret, s; uint32_t s_version; + unsigned i; prog.len = (unsigned short)sizeof(filter_pesto) / sizeof(filter_pesto[0]); @@ -250,6 +288,8 @@ int main(int argc, char **argv) prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) die("Failed to apply seccomp filter"); + fwd_probe_ephemeral(); + do { optname = getopt_long(argc, argv, optstring, options, NULL); @@ -266,6 +306,18 @@ int main(int argc, char **argv) case 'v': verbosity++; break; + case 't': + case 'u': + fwd_default = FWD_MODE_UNSET; + conf_ports(optname, optarg, &fwd_in, &fwd_default, + true, true, true); + break; + case 'T': + case 'U': + fwd_default = FWD_MODE_UNSET; + conf_ports(optname, optarg, &fwd_out, &fwd_default, + true, true, true); + break; case 1: FPRINTF(stdout, "pesto "); FPRINTF(stdout, VERSION_BLOB); @@ -291,6 +343,22 @@ int main(int argc, char **argv) a.sun_path, strerror(errno)); } + debug("Inbound rules from command line:"); + for (i = 0; i < fwd_in.count; i++) { + const struct fwd_rule *rule = &fwd_in.rules[i].rule; + char rulestr[FWD_RULE_STRLEN]; + + debug(" %s", fwd_rule_ntop(rule, rulestr, sizeof(rulestr))); + } + + debug("Outbound rules from command line:"); + for (i = 0; i < fwd_out.count; i++) { + const struct fwd_rule *rule = &fwd_out.rules[i].rule; + char rulestr[FWD_RULE_STRLEN]; + + debug(" %s", fwd_rule_ntop(rule, rulestr, sizeof(rulestr))); + } + debug("Connected to passt/pasta control socket"); ret = seread_var(s, &hello); @@ -324,5 +392,21 @@ int main(int argc, char **argv) show_state(state); + if (fwd_in.count) { + sewrite_u8(s, PIF_HOST); + sewrite_u32(s, fwd_in.count); + for (i = 0; i < fwd_in.count; i++) + fwd_rule_sewrite(s, &fwd_in.rules[i].rule); + } + + if (fwd_out.count) { + sewrite_u8(s, PIF_SPLICE); + sewrite_u32(s, fwd_out.count); + for (i = 0; i < fwd_out.count; i++) + fwd_rule_sewrite(s, &fwd_out.rules[i].rule); + } + + sewrite_u8(s, PIF_NONE); + exit(0); } diff --git a/pif.h b/pif.h index 7bb58e5..c96a090 100644 --- a/pif.h +++ b/pif.h @@ -35,6 +35,7 @@ enum pif_type { PIF_NUM_TYPES, }; +#ifndef PESTO extern const char *pif_type_str[]; static inline const char *pif_type(enum pif_type pt) @@ -66,5 +67,6 @@ void pif_sockaddr(const struct ctx *c, union sockaddr_inany *sa, int pif_listen(const struct ctx *c, enum epoll_type type, uint8_t pif, const union inany_addr *addr, const char *ifname, in_port_t port, unsigned rule); +#endif /* !PESTO */ #endif /* PIF_H */ diff --git a/util.c b/util.c index ff5094e..069c126 100644 --- a/util.c +++ b/util.c @@ -990,6 +990,8 @@ bool snprintf_check(char *str, size_t size, const char *format, ...) * * Assumes that the random data is essential, and will die() if unable to obtain * it. + * + * #syscalls getrandom brk */ void raw_random(void *buf, size_t buflen) { -- 2.43.0