Port Forwarding from QEMU/KVM Guest to Host: Reverse Hostfwd Implementation Guide


4 views

When working with QEMU/KVM virtualization, we commonly use hostfwd to forward host ports to guest VMs. However, the reverse operation - forwarding guest ports to the host - requires a different approach since QEMU doesn't provide a direct equivalent to hostfwd for outbound forwarding.

Here are three effective methods to achieve guest-to-host port forwarding:

Method 1: Using libvirt NAT Rules

For libvirt-managed VMs, add the following to your network definition:


<network>
  <name>default</name>
  <forward mode='nat'/>
  <nat>
    <port start='1024' end='65535'/>
    <forward port='6633' to='6633' toaddr='192.168.122.1'/>
  </nat>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

Method 2: SSH Reverse Tunneling

From the guest VM, establish a reverse SSH tunnel:


ssh -NfR 6633:localhost:6633 user@host-machine

This forwards guest port 6633 to the host's 6633 port through an encrypted connection.

Method 3: Custom QEMU Network Configuration

When launching QEMU directly, use tap networking with iptables rules:


sudo qemu-system-x86_64 \
  -net nic -net tap,script=/etc/qemu-ifup \
  -m 2048 -hda vm.qcow2

Then create /etc/qemu-ifup with:


#!/bin/sh
sudo /sbin/iptables -t nat -A PREROUTING -p tcp --dport 6633 -j DNAT --to-destination 192.168.122.1:6633
sudo /sbin/iptables -I FORWARD -d 192.168.122.1/32 -p tcp -m state --state NEW -m tcp --dport 6633 -j ACCEPT
  • Ensure host firewall rules allow the forwarded traffic
  • Verify the host IP in the guest's default route
  • Check that the service is listening on the correct interface
  • Confirm SELinux/apparmor isn't blocking the connection

For more complex scenarios, consider creating a bridged network where the guest appears as a separate host:


sudo brctl addbr br0
sudo brctl addif br0 eth0
sudo ifconfig br0 up

Then launch QEMU with:


sudo qemu-system-x86_64 -net nic -net bridge,br=br0 -m 2048 -hda vm.qcow2

When working with QEMU/KVM virtual machines, we often need bidirectional network communication between host and guest systems. While forwarding host ports to guests (using hostfwd) is well-documented, the reverse scenario - exposing guest ports to the host - requires different approaches.

The default user-mode networking (-net user) doesn't support guest-to-host port forwarding out of the box. This is because:

  • User-mode networking implements NAT, making the guest appear behind the host
  • By design, it only allows initiated connections from guest to external networks

Method 1: Using TAP Networking

The most robust solution is to configure a TAP interface:


# Create tap interface
sudo ip tuntap add dev tap0 mode tap
sudo ip addr add 192.168.123.1/24 dev tap0
sudo ip link set tap0 up

# Start QEMU with tap networking
qemu-system-x86_64 \
  -netdev tap,id=mynet0,ifname=tap0,script=no,downscript=no \
  -device virtio-net-pci,netdev=mynet0

On the guest system, configure a static IP (e.g., 192.168.123.2) and you can now access host services directly.

Method 2: SSH Reverse Tunneling

For quick temporary solutions, SSH can create reverse tunnels:


# From guest machine:
ssh -R 6633:localhost:6633 user@host

This forwards guest port 6633 to host port 6633.

Method 3: Using socat

For TCP forwarding without SSH:


# On host (assuming default SLIRP IP):
socat TCP-LISTEN:6633,fork TCP:10.0.2.2:6633

When implementing these solutions:

  • Firewall rules may need adjustment on both host and guest
  • For production environments, consider bridged networking instead of TAP
  • Performance-critical applications may benefit from virtio-net drivers

Verify connectivity with these tools:


# Check listening ports on guest:
ss -tulnp

# Test connection from host:
telnet 192.168.123.2 6633
nc -zv 192.168.123.2 6633