![Wie kann ich Ports im Benutzermodus von QEMU ohne Konflikte weiterleiten?](https://rvso.com/image/756237/Wie%20kann%20ich%20Ports%20im%20Benutzermodus%20von%20QEMU%20ohne%20Konflikte%20weiterleiten%3F.png)
Ich verwende Linux unter QEMU als Teil einer Testsuite für ein Python-Skript, das einige privilegierte Vorgänge ausführt. Der Betrieb einer vollständigen virtuellen Maschine ist mir wichtig, weil:
- Ich möchte keinen Sudo-Zugriff benötigen, um Tests auszuführen
- später wird es einfacher sein, die Tests über verschiedene Distributionen und Kernel-Versionen hinweg durchzuführen
- Es ist weniger wahrscheinlich, dass mein Computer kaputt geht
Mein Ansatz besteht darin, die QEMU-VM mit einem Host-Port zu starten, der an SSH auf der VM weitergeleitet wird, das Skript über SSH zu senden und auszuführen, das Skript auszuführen und Dinge über das Remote-System zu bestätigen. Das Ärgerliche an diesem Setup sind der SSH-Port und die Ports für andere Netzwerkanwendungen.
Meine Frage:Wie kann ich Ports im Benutzermodus von QEMU ohne Konflikte weiterleiten?
Mein Ziel hier ist, mehrere Tests gleichzeitig ohne vorherige Einrichtung und ohne sudo ausführen zu können, wie oben erwähnt. Die Benutzermodus-Netzwerkfunktion in QEMU unterstützt Portweiterleitung, und wenn ich 0
in der Hostfwd-Deklaration ( hostfwd=tcp:127.0.0.1:0-:22
) den Host-Port übergebe, weist das Betriebssystem dynamisch einen zu. Genial! Das Problem dabei war, diesen Port im übergeordneten Prozess zuverlässig zu erhalten.
Ich mache das Äquivalent von:
#!/bin/sh
set -e
cd "$(mktemp -d)"
# Download cloud image.
image_base_url="https://cloud-images.ubuntu.com/releases/18.04/release/"
image_name="ubuntu-18.04-server-cloudimg-amd64.img"
image_url="$image_base_url$image_name"
curl --location -o linux.img $image_url
# Create SSH key.
ssh_key_path="$PWD/id_rsa"
ssh-keygen -t rsa -b 4096 -N "" -f "$ssh_key_path"
# Create cloud-init payload.
cat <<EOF > user_data
#cloud-config
password: ubuntu
chpasswd: { expire: False }
ssh_pwauth: True
ssh_authorized_keys:
- $(cat "${ssh_key_path}.pub")
EOF
cloud-localds user_data.img user_data
# Socket path for QMP.
qmp_socket="$PWD/qmp.sock"
# Start VM.
qemu-system-x86_64 \
-drive file=linux.img,format=qcow2 \
-drive file=user_data.img,format=raw \
-netdev user,id=net0,hostfwd=tcp:127.0.0.1:0-:22 \
-device rtl8139,netdev=net0 \
-enable-kvm \
-m 2G \
-serial mon:stdio \
-nographic \
-smp 2 \
-snapshot \
-qmp unix:$qmp_socket,server,nowait \
& \
;
# wait a bit, then test stuff here
# ...
Das Gastbetriebssystem wird problemlos gestartet.
Dinge, die ich versucht habe:
spielte ein wenig mitQMP, konnte aber keinen Befehl finden, der die Informationen lieferte
habe überlegt, einen zufälligen Port im übergeordneten Prozess zu binden
SO_REUSEPORT
und ihn dann für den untergeordneten Befehl anzugeben, aber QEMU verwendet dieses Flag nicht, also funktioniert es nichtnetstat -nalp | grep $child_pid
, dies ist jedoch nicht verwendbar, wenn mehrere Ports weitergeleitet werdeneinen zufälligen ungebundenen Port auswählen, versuchen, qemu damit zu starten, und es erneut versuchen, wenn es mit einer passenden Nachricht fehlschlägt
Could not set up host forwarding rule 'tcp:...'
. Das funktioniert, aber- tritt mit größerer Wahrscheinlichkeit ein Fehler auf, wenn mehr Ports vorhanden sind
- kann andere Probleme verschleiern, für die es sich nicht lohnt, einen erneuten Versuch zu unternehmen
Das ist ein akzeptabler Ersatz, aber ich hoffe auf eine einfachere Lösung.
Antwort1
Nach etwas mehr Recherche: QEMU stellt die Informationen über den info usernet
Befehl zur Verfügung. So sieht die Ausgabe aus:
(qemu) info usernet
VLAN -1 (net0):
Protocol[State] FD Source Address Port Dest. Address Port RecvQ SendQ
TCP[HOST_FORWARD] 13 127.0.0.1 38117 10.0.2.15 22 0 0
UDP[236 sec] 24 10.0.2.15 35061 91.189.89.198 123 0 0
UDP[204 sec] 26 10.0.2.15 60630 91.189.89.198 123 0 0
Es ist nicht über QMP verfügbar, aber es wurde ein Patch eingereicht, um ein Äquivalent hinzuzufügenquery-usernet
Hiervor einiger Zeit.
In meinem Fall ist es unkompliziert, den Monitor verfügbar zu machen -monitor unix:$PWD/mon.sock,server,nowait
, eine Verbindung herzustellen, den Befehl zu senden, die Ausgabe zu lesen und sie nach den gewünschten Werten zu analysieren.
Zusammenfassend lässt sich also sagen, wie Sie QEMU zum Testen von Netzwerkanwendungen verwenden können, ohne dass sudo oder andere Voraussetzungen (außer QEMU selbst) erforderlich sind und Portkonflikte auf dem Host vermieden werden:
- Erstellen Sie für jede Anwendung über die Kommandozeile (
-netdev
) oder den Monitor (netdev_add
) eine Portzuordnung und geben Sie dabei0
den Host-Port an - Stellen Sie es
monitor
als Unix-Socket für die nutzende Anwendung bereit. - Führen Sie die Ausführung
info usernet
über den Socket durch und extrahieren Sie den Quellport für jede Zuordnung. Dabei handelt es sich um den tatsächlichen Port, der vom Betriebssystem zugewiesen wurde.