From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202602 header.b=S8Pselgw; dkim-atps=neutral Received: from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id B09675A0626 for ; Thu, 19 Mar 2026 07:12:12 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202602; t=1773900722; bh=9b9EzWUTr+ScuRJi4NVgLQY1hMDzLiQxsGaxaW8v5tY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=S8PselgwWOL3CORLZCC8hyezSYUxUelyxQuvX/h3Tecl7ECfBisFPdUPfwfsi/+CG kkrcf7abuhEEyycnKreeGw5krEOMJtZyxnIrp/wIoOaxOkCYEmoKsmYI0yrVkVwo2P MxOqlpookEu6oI7kQ2FCY4PusfT8bTIHeBO5mS/Ijg5Ts/e+RtwfwG2RYTWM8Y5BCC rjQC3CKtZL+FWDYSBIGk8z86AJ7OMt5lbM9j+iqUS2gw4qIpLvQo0LFuNbPFi/f+x5 4eYomihj5ZdWYTuGOBMrE4AaHIAyVXQBuI6C9LYBI28b0kPqMcEHG/ajFgGUdFvJ8s i81k4ZzxcrhMA== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4fbwMQ0PTQz4wSs; Thu, 19 Mar 2026 17:12:02 +1100 (AEDT) From: David Gibson To: Stefano Brivio , passt-dev@passt.top Subject: [PATCH v2 07/15] pesto: Introduce stub configuration interface and tool Date: Thu, 19 Mar 2026 17:11:49 +1100 Message-ID: <20260319061157.1983818-8-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.53.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: TU2MNRJMOSQN75TOM763H3P6PJMQ6LH3 X-Message-ID-Hash: TU2MNRJMOSQN75TOM763H3P6PJMQ6LH3 X-MailFrom: dgibson@gandalf.ozlabs.org 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: Add a control socket to passt/pasta for updating configuration at runtime. Add a tool (pesto) for communicating with the control socket. For now this is a stub implementation that forms the connection and sends some version information, but nothing more. Example: ./pasta --debug --config-net -c /tmp/pasta.conf -t none ./pesto /tmp/pasta.conf Signed-off-by: Stefano Brivio [dwg: Based on an early draft from Stefano] Signed-off-by: David Gibson --- .gitignore | 2 + Makefile | 30 +++++++---- common.h | 14 +++++ conf.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++- conf.h | 2 + epoll_type.h | 4 ++ log.c | 1 + passt.1 | 5 ++ passt.c | 9 ++++ passt.h | 6 +++ pesto.1 | 46 ++++++++++++++++ pesto.c | 113 ++++++++++++++++++++++++++++++++++++++ pesto.h | 34 ++++++++++++ serialise.c | 3 ++ util.h | 3 -- 15 files changed, 407 insertions(+), 15 deletions(-) create mode 100644 common.h create mode 100644 pesto.1 create mode 100644 pesto.c create mode 100644 pesto.h diff --git a/.gitignore b/.gitignore index 3c16adc7..3e40d9f7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,11 @@ /pasta /pasta.avx2 /passt-repair +/pesto /qrap /pasta.1 /seccomp.h +/seccomp_pesto.h /seccomp_repair.h /c*.json README.plain.md diff --git a/Makefile b/Makefile index 5b6891d7..d085c9c1 100644 --- a/Makefile +++ b/Makefile @@ -44,17 +44,19 @@ PASST_SRCS = arch.c arp.c checksum.c conf.c dhcp.c dhcpv6.c epoll_ctl.c \ udp.c udp_flow.c udp_vu.c util.c vhost_user.c virtio.c vu_common.c QRAP_SRCS = qrap.c PASST_REPAIR_SRCS = passt-repair.c -SRCS = $(PASST_SRCS) $(QRAP_SRCS) $(PASST_REPAIR_SRCS) +PESTO_SRCS = pesto.c serialise.c +SRCS = $(PASST_SRCS) $(QRAP_SRCS) $(PASST_REPAIR_SRCS) $(PESTO_SRCS) -MANPAGES = passt.1 pasta.1 qrap.1 passt-repair.1 +MANPAGES = passt.1 pasta.1 pesto.1 qrap.1 passt-repair.1 +PESTO_HEADERS = common.h pesto.h serialise.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 inany.h iov.h ip.h \ isolation.h lineread.h log.h migrate.h ndp.h netlink.h packet.h \ - passt.h pasta.h pcap.h pif.h repair.h serialise.h siphash.h tap.h tcp.h \ - tcp_buf.h tcp_conn.h tcp_internal.h tcp_splice.h tcp_vu.h udp.h \ - udp_flow.h udp_internal.h udp_vu.h util.h vhost_user.h virtio.h \ - vu_common.h + passt.h pasta.h pcap.h pif.h repair.h siphash.h tap.h tcp.h tcp_buf.h \ + tcp_conn.h tcp_internal.h tcp_splice.h tcp_vu.h udp.h udp_flow.h \ + udp_internal.h udp_vu.h util.h vhost_user.h virtio.h vu_common.h \ + $(PESTO_HEADERS) HEADERS = $(PASST_HEADERS) seccomp.h C := \#include \nint main(){int a=getrandom(0, 0, 0);} @@ -75,9 +77,9 @@ mandir ?= $(datarootdir)/man man1dir ?= $(mandir)/man1 ifeq ($(TARGET_ARCH),x86_64) -BIN := passt passt.avx2 pasta pasta.avx2 qrap passt-repair +BIN := passt passt.avx2 pasta pasta.avx2 qrap passt-repair pesto else -BIN := passt pasta qrap passt-repair +BIN := passt pasta qrap passt-repair pesto endif all: $(BIN) $(MANPAGES) docs @@ -91,6 +93,9 @@ seccomp.h: seccomp.sh $(PASST_SRCS) $(PASST_HEADERS) seccomp_repair.h: seccomp.sh $(PASST_REPAIR_SRCS) @ ARCH="$(TARGET_ARCH)" CC="$(CC)" ./seccomp.sh seccomp_repair.h $(PASST_REPAIR_SRCS) +seccomp_pesto.h: seccomp.sh $(PESTO_SRCS) + @ ARCH="$(TARGET_ARCH)" CC="$(CC)" ./seccomp.sh seccomp_pesto.h $(PESTO_SRCS) + passt: $(PASST_SRCS) $(HEADERS) $(CC) $(FLAGS) $(CFLAGS) $(CPPFLAGS) $(PASST_SRCS) -o passt $(LDFLAGS) @@ -110,6 +115,9 @@ qrap: $(QRAP_SRCS) passt.h passt-repair: $(PASST_REPAIR_SRCS) seccomp_repair.h $(CC) $(FLAGS) $(CFLAGS) $(CPPFLAGS) $(PASST_REPAIR_SRCS) -o passt-repair $(LDFLAGS) +pesto: $(PESTO_SRCS) $(PESTO_HEADERS) seccomp_pesto.h + $(CC) $(FLAGS) $(CFLAGS) $(CPPFLAGS) $(PESTO_SRCS) -o pesto $(LDFLAGS) + valgrind: EXTRA_SYSCALLS += rt_sigprocmask rt_sigtimedwait rt_sigaction \ rt_sigreturn getpid gettid kill clock_gettime \ mmap|mmap2 munmap open unlink gettimeofday futex \ @@ -119,7 +127,7 @@ valgrind: all .PHONY: clean clean: - $(RM) $(BIN) *~ *.o seccomp.h seccomp_repair.h pasta.1 \ + $(RM) $(BIN) *~ *.o seccomp.h seccomp_repair.h seccomp_pesto.h pasta.1 \ passt.tar passt.tar.gz *.deb *.rpm \ passt.pid README.plain.md @@ -173,11 +181,11 @@ docs: README.md done < README.md; \ ) > README.plain.md -clang-tidy: $(PASST_SRCS) +clang-tidy: $(PASST_SRCS) $(PESTO_SRCS) clang-tidy $^ -- $(filter-out -pie,$(FLAGS) $(CFLAGS) $(CPPFLAGS)) \ -DCLANG_TIDY_58992 -cppcheck: $(PASST_SRCS) $(HEADERS) +cppcheck: $(PASST_SRCS) $(PESTO_SRCS) $(HEADERS) if cppcheck --check-level=exhaustive /dev/null > /dev/null 2>&1; then \ CPPCHECK_EXHAUSTIVE="--check-level=exhaustive"; \ else \ diff --git a/common.h b/common.h new file mode 100644 index 00000000..76a95609 --- /dev/null +++ b/common.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright Red Hat + * Author: David Gibson + * + * Definitions used by both passt/pasta and other tools + */ + +#ifndef COMMON_H +#define COMMON_H + +/* FPRINTF() intentionally silences cert-err33-c clang-tidy warnings */ +#define FPRINTF(f, ...) (void)fprintf(f, __VA_ARGS__) + +#endif /* _COMMON_H */ diff --git a/conf.c b/conf.c index 6af3c8a5..031de352 100644 --- a/conf.c +++ b/conf.c @@ -35,6 +35,7 @@ #include #include +#include "common.h" #include "util.h" #include "ip.h" #include "passt.h" @@ -47,6 +48,10 @@ #include "isolation.h" #include "log.h" #include "vhost_user.h" +#include "epoll_ctl.h" +#include "conf.h" +#include "pesto.h" +#include "serialise.h" #define NETNS_RUN_DIR "/run/netns" @@ -894,6 +899,7 @@ static void usage(const char *name, FILE *f, int status) " --runas UID|UID:GID Run as given UID, GID, which can be\n" " numeric, or login and group names\n" " default: drop to user \"nobody\"\n" + " -c, --conf-path PATH Configuration socket path\n" " -h, --help Display this help message and exit\n" " --version Show version and exit\n"); @@ -1426,6 +1432,17 @@ static void conf_open_files(struct ctx *c) if (c->pidfile_fd < 0) die_perror("Couldn't open PID file %s", c->pidfile); } + + c->fd_conf = -1; + if (*c->conf_path) { + c->fd_conf_listen = sock_unix(c->conf_path); + if (c->fd_conf_listen < 0) { + die_perror("Couldn't open control socket %s", + c->conf_path); + } + } else { + c->fd_conf_listen = -1; + } } /** @@ -1461,6 +1478,25 @@ fail: die("Invalid MAC address: %s", str); } +/** + * conf_sock_listen() - Start listening for connections on configuration socket + * @c: Execution context + */ +static void conf_sock_listen(const struct ctx *c) +{ + union epoll_ref ref = { .type = EPOLL_TYPE_CONF_LISTEN }; + + if (c->fd_conf_listen < 0) + return; + + if (listen(c->fd_conf_listen, 0)) + die_perror("Couldn't listen on configuration socket"); + + ref.fd = c->fd_conf_listen; + if (epoll_add(c->epollfd, EPOLLIN | EPOLLET, ref)) + die_perror("Couldn't add configuration socket to epoll"); +} + /** * conf() - Process command-line arguments and set configuration * @c: Execution context @@ -1543,9 +1579,10 @@ void conf(struct ctx *c, int argc, char **argv) {"migrate-exit", no_argument, NULL, 29 }, {"migrate-no-linger", no_argument, NULL, 30 }, {"stats", required_argument, NULL, 31 }, + {"conf-path", required_argument, NULL, 'c' }, { 0 }, }; - 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 *optstring = "+dqfel:hs:c: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"; char userns[PATH_MAX] = { 0 }, netns[PATH_MAX] = { 0 }; bool copy_addrs_opt = false, copy_routes_opt = false; @@ -1809,6 +1846,13 @@ void conf(struct ctx *c, int argc, char **argv) c->fd_tap = -1; break; + case 'c': + ret = snprintf(c->conf_path, sizeof(c->conf_path), "%s", + optarg); + if (ret <= 0 || ret >= (int)sizeof(c->sock_path)) + die("Invalid configuration path: %s", optarg); + c->fd_conf_listen = c->fd_conf = -1; + break; case 'F': errno = 0; fd_tap_opt = strtol(optarg, NULL, 0); @@ -2253,4 +2297,108 @@ void conf(struct ctx *c, int argc, char **argv) if (!c->quiet) conf_print(c); + + conf_sock_listen(c); +} + +/** + * conf_listen_handler() - Handle events on configuration listening socket + * @c: Execution context + * @events: epoll events + */ +void conf_listen_handler(struct ctx *c, uint32_t events) +{ + struct pesto_hello hello = { + .magic = PESTO_SERVER_MAGIC, + .version = htonl(PESTO_PROTOCOL_VERSION), + }; + union epoll_ref ref = { .type = EPOLL_TYPE_CONF }; + struct ucred uc = { 0 }; + socklen_t len = sizeof(uc); + int fd, rc; + + if (events != EPOLLIN) { + err("Unexpected event 0x%04x on configuration socket", events); + return; + } + + fd = accept4(c->fd_conf_listen, NULL, NULL, SOCK_NONBLOCK); + if (fd < 0) { + warn_perror("accept4() on configuration listening socket"); + return; + } + + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &uc, &len) < 0) + warn_perror("Can't get configuration client credentials"); + + /* Another client is already connected: accept and close right away. */ + if (c->fd_conf != -1) { + info("Discarding configuration client, PID %i", uc.pid); + goto fail; + } + + ref.fd = fd; + rc = epoll_add(c->epollfd, EPOLLIN | EPOLLET, ref); + if (rc < 0) { + warn_perror("epoll_ctl() on configuration socket"); + goto fail; + } + + rc = sewrite_var(fd, &hello); + if (rc < 0) { + warn_perror("Error writing configuration protocol hello"); + goto fail; + } + + c->fd_conf = fd; + info("Accepted configuration client, PID %i", uc.pid); + if (!PESTO_PROTOCOL_VERSION) { + warn( +"Warning: Using experimental unsupported configuration protocol"); + } + + return; + +fail: + close(fd); +} + +/** + * conf_handler() - Handle events on configuration socket + * @c: Execution context + * @events: epoll events + */ +void conf_handler(struct ctx *c, uint32_t events) +{ + if (events & EPOLLIN) { + char discard[BUFSIZ]; + ssize_t n; + + do { + n = read(c->fd_conf, discard, sizeof(discard)); + if (n > 0) + debug("Discarded %zd bytes of config data", n); + } while (n > 0); + if (n == 0) { + debug("Configuration client EOF"); + goto close; + } + if (errno != EAGAIN && errno != EWOULDBLOCK) { + err_perror("Error reading config data"); + goto close; + } + } + + if (events & EPOLLHUP) { + debug("Configuration client hangup"); + goto close; + } + + return; + +close: + debug("Closing configuration socket"); + epoll_ctl(c->epollfd, EPOLL_CTL_DEL, c->fd_conf, NULL); + close(c->fd_conf); + c->fd_conf = -1; } diff --git a/conf.h b/conf.h index b45ad746..16f97189 100644 --- a/conf.h +++ b/conf.h @@ -8,5 +8,7 @@ enum passt_modes conf_mode(int argc, char *argv[]); void conf(struct ctx *c, int argc, char **argv); +void conf_listen_handler(struct ctx *c, uint32_t events); +void conf_handler(struct ctx *c, uint32_t events); #endif /* CONF_H */ diff --git a/epoll_type.h b/epoll_type.h index a90ffb67..061325aa 100644 --- a/epoll_type.h +++ b/epoll_type.h @@ -46,6 +46,10 @@ enum epoll_type { EPOLL_TYPE_REPAIR, /* Netlink neighbour subscription socket */ EPOLL_TYPE_NL_NEIGH, + /* Configuration listening socket */ + EPOLL_TYPE_CONF_LISTEN, + /* Configuration socket */ + EPOLL_TYPE_CONF, EPOLL_NUM_TYPES, }; diff --git a/log.c b/log.c index 21e3673e..99404e25 100644 --- a/log.c +++ b/log.c @@ -26,6 +26,7 @@ #include #include +#include "common.h" #include "linux_dep.h" #include "log.h" #include "util.h" diff --git a/passt.1 b/passt.1 index 13e8df9d..32d70c8d 100644 --- a/passt.1 +++ b/passt.1 @@ -127,6 +127,11 @@ login name and group name can be passed. This requires privileges (either initial effective UID 0 or CAP_SETUID capability) to work. Default is to change to user \fInobody\fR if started as root. +.TP +.BR \-c ", " \-\-conf-path " " \fIpath " " (EXPERIMENTAL) +Path for configuration and control socket used by \fBpesto\fR(1) to +dynamically update passt or pasta's configuration. + .TP .BR \-h ", " \-\-help Display a help message and exit. diff --git a/passt.c b/passt.c index f84419c7..d37beef3 100644 --- a/passt.c +++ b/passt.c @@ -36,6 +36,7 @@ #include #include +#include "common.h" #include "util.h" #include "passt.h" #include "dhcp.h" @@ -80,6 +81,8 @@ char *epoll_type_str[] = { [EPOLL_TYPE_REPAIR_LISTEN] = "TCP_REPAIR helper listening socket", [EPOLL_TYPE_REPAIR] = "TCP_REPAIR helper socket", [EPOLL_TYPE_NL_NEIGH] = "netlink neighbour notifier socket", + [EPOLL_TYPE_CONF_LISTEN] = "configuration listening socket", + [EPOLL_TYPE_CONF] = "configuration socket", }; static_assert(ARRAY_SIZE(epoll_type_str) == EPOLL_NUM_TYPES, "epoll_type_str[] doesn't match enum epoll_type"); @@ -303,6 +306,12 @@ static void passt_worker(void *opaque, int nfds, struct epoll_event *events) case EPOLL_TYPE_NL_NEIGH: nl_neigh_notify_handler(c); break; + case EPOLL_TYPE_CONF_LISTEN: + conf_listen_handler(c, eventmask); + break; + case EPOLL_TYPE_CONF: + conf_handler(c, eventmask); + break; default: /* Can't happen */ assert(0); diff --git a/passt.h b/passt.h index 5fc4e07f..6bb748fb 100644 --- a/passt.h +++ b/passt.h @@ -158,6 +158,7 @@ struct ip6_ctx { * @foreground: Run in foreground, don't log to stderr by default * @nofile: Maximum number of open files (ulimit -n) * @sock_path: Path for UNIX domain socket + * @conf_path: Path for configuration UNIX domain socket * @repair_path: TCP_REPAIR helper path, can be "none", empty for default * @pcap: Path for packet capture file * @pidfile: Path to PID file, empty string if not configured @@ -169,6 +170,8 @@ struct ip6_ctx { * @epollfd: File descriptor for epoll instance * @fd_tap_listen: File descriptor for listening AF_UNIX socket, if any * @fd_tap: AF_UNIX socket, tuntap device, or pre-opened socket + * @fd_conf_listen: Listening configuration socket, if any + * @fd_conf: Configuration socket, if any * @fd_repair_listen: File descriptor for listening TCP_REPAIR socket, if any * @fd_repair: Connected AF_UNIX socket for TCP_REPAIR helper * @our_tap_mac: Pasta/passt's MAC on the tap link @@ -224,6 +227,7 @@ struct ctx { int foreground; int nofile; char sock_path[UNIX_PATH_MAX]; + char conf_path[UNIX_PATH_MAX]; char repair_path[UNIX_PATH_MAX]; char pcap[PATH_MAX]; @@ -241,6 +245,8 @@ struct ctx { int epollfd; int fd_tap_listen; int fd_tap; + int fd_conf_listen; + int fd_conf; int fd_repair_listen; int fd_repair; unsigned char our_tap_mac[ETH_ALEN]; diff --git a/pesto.1 b/pesto.1 new file mode 100644 index 00000000..338fb8a6 --- /dev/null +++ b/pesto.1 @@ -0,0 +1,46 @@ +.\" SPDX-License-Identifier: GPL-2.0-or-later +.\" Copyright Red Hat +.\" Author: David Gibson +.TH pesto 1 + +.SH NAME +.B pesto +\- Configure a running \fBpasst\fR(1) or \fBpasta\fR(1) instance. + +.SH SYNOPSIS +.B pesto +\fIPATH\fR + +.SH DESCRIPTION + +.B pesto +is an experimental client to view and update the port forwarding +configuration of a running \fBpasst\fR(1) or \fBpasta\fR(1) instance. + +\fIPATH\fR gives the path to the UNIX domain socket created by +\fBpasst\fR or \fBpasta\fR. It should match the \fB-c\fR command line +option given to that instance. + +.SH AUTHORS + +Stefano Brivio , +David Gibson . + +.SH REPORTING BUGS + +Please report issues on the bug tracker at https://bugs.passt.top/, or +send a message to the passt-user@passt.top mailing list, see +https://lists.passt.top/. + +.SH COPYRIGHT + +Copyright Red Hat + +\fBpesto\fR is free software: you can redistribute them and/or modify +them under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or (at +your option) any later version. + +.SH SEE ALSO + +\fBpasst\fR(1), \fBpasta\fR(1), \fBunix\fR(7). diff --git a/pesto.c b/pesto.c new file mode 100644 index 00000000..edc07e77 --- /dev/null +++ b/pesto.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* PESTO - Programmable Extensible Socket Translation Orchestrator + * front-end for passt(1) and pasta(1) forwarding configuration + * + * pesto.c - Main program (it's not actually extensible) + * + * Copyright (c) 2026 Red Hat GmbH + * Author: Stefano Brivio + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "common.h" +#include "seccomp_pesto.h" +#include "serialise.h" +#include "pesto.h" + +#define die(...) \ + do { \ + FPRINTF(stderr, __VA_ARGS__); \ + FPRINTF(stderr, "\n"); \ + exit(EXIT_FAILURE); \ + } while (0) + +/** + * main() - Entry point and whole program with loop + * @argc: Argument count + * @argv: Arguments: socket path, operation, port specifiers + * + * Return: 0 on success, won't return on failure + * + * #syscalls:pesto connect write close exit_group fstat brk + * #syscalls:pesto socket s390x:socketcall i686:socketcall + * #syscalls:pesto recvfrom recvmsg arm:recv ppc64le:recv + * #syscalls:pesto sendto sendmsg arm:send ppc64le:send + */ +int main(int argc, char **argv) +{ + struct sockaddr_un a = { AF_UNIX, "" }; + struct pesto_hello hello; + struct sock_fprog prog; + uint32_t s_version; + int ret, s; + + prctl(PR_SET_DUMPABLE, 0); + + prog.len = (unsigned short)sizeof(filter_pesto) / + sizeof(filter_pesto[0]); + prog.filter = filter_pesto; + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || + prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) + die("Failed to apply seccomp filter"); + + if (argc < 2) + die("Usage: %s CONTROLPATH", argv[0]); + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + die("Failed to create AF_UNIX socket: %s", strerror(errno)); + + ret = snprintf(a.sun_path, sizeof(a.sun_path), "%s", argv[1]); + if (ret <= 0 || ret >= (int)sizeof(a.sun_path)) + die("Invalid socket path \"%s\"", argv[1]); + + ret = connect(s, (struct sockaddr *)&a, sizeof(a)); + if (ret < 0) { + die("Failed to connect to %s: %s", + a.sun_path, strerror(errno)); + } + + ret = seread_var(s, &hello); + if (ret < 0) + die("Couldn't read server greeting: %s", strerror(errno)); + + if (memcmp(hello.magic, PESTO_SERVER_MAGIC, sizeof(hello.magic))) + die("Bad magic number from server"); + + s_version = ntohl(hello.version); + + if (s_version > PESTO_PROTOCOL_VERSION) { + die("Unknown server protocol version %"PRIu32" > %"PRIu32"\n", + s_version, PESTO_PROTOCOL_VERSION); + } + + /* cppcheck-suppress knownConditionTrueFalse */ + if (!s_version) { + if (PESTO_PROTOCOL_VERSION) + die("Unsupported experimental server protocol"); + FPRINTF(stderr, +"Warning: Using experimental protocol version, client and server must match\n"); + } + + exit(0); +} diff --git a/pesto.h b/pesto.h new file mode 100644 index 00000000..92d4df3a --- /dev/null +++ b/pesto.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright Red Hat + * Author: David Gibson + * + * Definitions and functions used by both client and server of the configuration + * update protocol (pesto). + */ + +#ifndef PESTO_H +#define PESTO_H + +#include +#include + +#define PESTO_SERVER_MAGIC "pesto:s" + +/* Version 0 is reserved for unreleased / unsupported experimental versions */ +#define PESTO_PROTOCOL_VERSION 0 + +/** + * struct pesto_hello - Server introduction message + * @magic: PESTO_SERVER_MAGIC + * @version: Version number + */ +struct pesto_hello { + char magic[8]; + uint32_t version; +} __attribute__ ((__packed__)); + +static_assert(sizeof(PESTO_SERVER_MAGIC) + == sizeof(((struct pesto_hello *)0)->magic), + "PESTO_SERVER_MAGIC has wrong size"); + +#endif /* PESTO_H */ diff --git a/serialise.c b/serialise.c index 098ae35c..4fc0d116 100644 --- a/serialise.c +++ b/serialise.c @@ -6,6 +6,9 @@ * PASTA - Pack A Subtle Tap Abstraction * for network namespace/tap device mode * + * PESTO - Programmable Extensible Socket Translation Orchestrator + * front-end for passt(1) and pasta(1) forwarding configuration + * * serialise.c - Serialisation of data structures over bytestreams * * Copyright Red Hat diff --git a/util.h b/util.h index cb669105..e7993f4d 100644 --- a/util.h +++ b/util.h @@ -317,9 +317,6 @@ static inline bool mod_between(unsigned x, unsigned i, unsigned j, unsigned m) return mod_sub(x, i, m) < mod_sub(j, i, m); } -/* FPRINTF() intentionally silences cert-err33-c clang-tidy warnings */ -#define FPRINTF(f, ...) (void)fprintf(f, __VA_ARGS__) - void raw_random(void *buf, size_t buflen); /* -- 2.53.0