From: Stefano Brivio <sbrivio@redhat.com>
To: passt-dev@passt.top
Cc: David Gibson <david@gibson.dropbear.id.au>
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 [thread overview]
Message-ID: <20260322141843.4095972-3-sbrivio@redhat.com> (raw)
In-Reply-To: <20260319061157.1983818-1-david@gibson.dropbear.id.au>
*** 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 <sbrivio@redhat.com>
---
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
prev parent reply other threads:[~2026-03-22 14:18 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-19 6:11 [PATCH v2 00/15] RFC: Read-only dynamic update implementation David Gibson
2026-03-19 6:11 ` [PATCH v2 01/15] treewide: Spell ASSERT() as assert() David Gibson
2026-03-20 20:58 ` Stefano Brivio
2026-03-19 6:11 ` [PATCH v2 02/15] serialise: Split functions user for serialisation from util.c David Gibson
2026-03-20 20:58 ` Stefano Brivio
2026-03-19 6:11 ` [PATCH v2 03/15] serialise: Add helpers for serialising unsigned integers David Gibson
2026-03-19 6:11 ` [PATCH v2 04/15] fwd: Move selecting correct scan bitmap into fwd_sync_one() David Gibson
2026-03-19 6:11 ` [PATCH v2 05/15] fwd: Look up rule index in fwd_sync_one() David Gibson
2026-03-19 6:11 ` [PATCH v2 06/15] fwd: Store forwarding tables indexed by (origin) pif David Gibson
2026-03-20 20:58 ` Stefano Brivio
2026-03-19 6:11 ` [PATCH v2 07/15] pesto: Introduce stub configuration interface and tool David Gibson
2026-03-19 6:11 ` [PATCH v2 08/15] pesto: Add command line option parsing and debug messages David Gibson
2026-03-19 6:11 ` [PATCH v2 09/15] pesto: Expose list of pifs to pesto David Gibson
2026-03-19 6:11 ` [PATCH v2 10/15] ip: Prepare ip.[ch] for sharing with pesto tool David Gibson
2026-03-19 6:11 ` [PATCH v2 11/15] inany: Prepare inany.[ch] " David Gibson
2026-03-19 6:11 ` [PATCH v2 12/15] fwd: Split forwading rule specification from its implementation state David Gibson
2026-03-19 6:11 ` [PATCH v2 13/15] ip: Define a bound for the string returned by ipproto_name() David Gibson
2026-03-19 6:11 ` [PATCH v2 14/15] fwd_rule: Move forwarding rule text formatting to common code David Gibson
2026-03-19 6:11 ` [PATCH v2 15/15] pesto: Read current ruleset from passt/pasta and display it David Gibson
2026-03-22 14:18 ` [PATCH 16/18] conf: Move port parsing functions to own file, ports.c Stefano Brivio
2026-03-22 14:18 ` [PATCH 17/18] conf, fwd, ports, util: Move things around for pesto Stefano Brivio
2026-03-22 14:18 ` Stefano Brivio [this message]
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=20260322141843.4095972-3-sbrivio@redhat.com \
--to=sbrivio@redhat.com \
--cc=david@gibson.dropbear.id.au \
--cc=passt-dev@passt.top \
/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).