From 84e32ef1f263c419ee853cd2826053fa3fd523dd Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Wed, 29 Jul 2026 04:39:03 +0200 Subject: [PATCH] feat(qemu): optional restricted guest egress via a single guestfwd tunnel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Guests stay on '-nic none' unless a profile opts in, and opting in does NOT mean internet: the NIC is user,restrict=on (no route out, no route to the host LAN) with one guestfwd to whatever command the overlay configures — a filtering proxy in practice. Keeps 'user code never gets a raw socket outside' true by construction. --- backend/app/services/qemu_manager.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/backend/app/services/qemu_manager.py b/backend/app/services/qemu_manager.py index 6cdc7dfb..a523c84c 100644 --- a/backend/app/services/qemu_manager.py +++ b/backend/app/services/qemu_manager.py @@ -491,7 +491,22 @@ class QemuManager: # exactly the two chardev-backed virtio-serial ports we # need. -nographic auto-binds -serial mon:stdio which # collides with our explicit -chardev IDs. - '-nic', 'none', + # Networking: OFF by default. A profile that wants the guest to + # reach anything sets `egress_guestfwd`, and even then the NIC is + # `restrict=on` — no route to the internet, no route to the host + # LAN — with a single guestfwd tunnel to whatever the overlay + # points at (a filtering proxy). User code never gets a raw + # socket to the outside. + *( + ['-nic', 'none'] + if not cfg.get('egress_guestfwd') + else [ + '-netdev', + 'user,id=egress,restrict=on,guestfwd=tcp:10.0.2.100:8080-cmd:' + + str(cfg['egress_guestfwd']), + '-device', 'virtio-net-pci,netdev=egress', + ] + ), '-display', 'none', '-monitor', 'none', '-serial', 'none',