I installed a server with libvirt, and I've created a test VM. When I use the default network for it's interface, it gets a private IP and the NATing seems to work fine. I installed OpenVPN, so I have a tun0 interface I want to NAT that VM on now (tun0 has a private IP on, I have no control over the vpn server and I have no way of getting more private IPs there). I created the network using the same parameters as the default network, but using for the DHCP (because why not), but when I try to ping something on the Internet from the VM I get an icmp-port-unreachable.

Here is the forward chain in iptables :

0     0 ACCEPT     all  --  tun0   vpn0           ctstate RELATED,ESTABLISHED
0     0 ACCEPT     all  --  vpn0   tun0           
0     0 ACCEPT     all  --  vpn0   vpn0             
0     0 REJECT     all  --  *      vpn0              reject-with icmp-port-unreachable
15 1244 REJECT     all  --  vpn0   *              reject-with icmp-port-unreachable
0     0 ACCEPT     all  --  eno1   virbr0       ctstate RELATED,ESTABLISHED
0     0 ACCEPT     all  --  virbr0 eno1           
0     0 ACCEPT     all  --  virbr0 virbr0             
0     0 REJECT     all  --  *      virbr0              reject-with icmp-port-unreachable
0     0 REJECT     all  --  virbr0 *              reject-with icmp-port-unreachable

As you can see, eno1 is the interface leading to internet the default network is using through virbr0, and tun0 is the vpn interface used through the vpn0 interface (that's how I named it in libvirt's config). Looking at the number, the 5th rule is the one matching, for some reason.

Is it possible libvirt isn't properly using the tun0 interface but instead, for some reason, trying to NAT through eno1 ?

Here is it's config :

<network connections='1'>
  <forward dev='tun0' mode='nat'>
      <port start='1024' end='65535'/>
    <interface dev='tun0'/>
  <bridge name='vpn0' stp='on' delay='0'/>
  <mac address='52:54:00:c2:05:79'/>
  <ip address='' netmask=''>
      <range start='' end=''/>

I can't see any difference with the default network, except that the default network works.

Thanks for the help


When libvirt sets up NAT, it doesn't force traffic to flow to any specific physical NIC. The host's routing rules control where NAT'd traffic will flow. IOW, if using the default libvirt virtual network, traffic ought to be able to flow either to your default NIC eno1 or to the VPN via tun0, according to what target IP addr the guest is trying to connect to. When you add a rule <interface dev='tun0'/> in your config, this simply tells libvirt to block traffic to any NIC except tun0. IOW, assuming the original default config for virbr0, did not have <interface ..>' set, then it should have "just worked" with your VPN. Your iptables rules listed, show 'eno1' which suggests you had an <interface dev='eno1'> rule present - you could simply delete that rule

  • I don't understand how. My goal is to use the vpn interface to reach the whole internet for that VM, if I understand what you are saying correctly it means I still need to setup separate routing tables on my hypervisor to handle that, which makes it basically useless : it's simpler to just bring the VPN up in the VM itself. – Ulrar Mar 9 '17 at 13:02
  • Yeah, I'm afraid the NAT setup isn't intended to actually changing the routing of the traffic via the host - it restricts itself to merely masquerading it, and blocking traffic to undesired locations. So yes, if you want to force all traffic to go via the VPN, regardless of host routing, that's not possible with libvirt's network setup I'm afraid. – DanielB Mar 10 '17 at 13:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.