VirtualBox Host Interface Networking with NAT

Posted on September 21st, 2008 in Tech Tips by gmendoza

Here’s a detailed tutorial on VirtualBox host interface networking with NAT for multiple guests.  I typically run a number of guests simultaneously for labs and product testing, so they all need internet access through my host, as well as full communication directly with each other.

The built in NAT interface of VirtualBox isn’t very flexible for what we want to do, so here’s a summary what what we will do. We’ll create three TAP interfaces, one for each guest, since TAP interfaces cannot be shared by multiple guests. These interfaces will serve as each guest’s default gateway, but all of the guests will use the same address space and subnet mask. For full communication between the guests, we’ll add appropriate host routes and enable proxy ARP on the host. Nothing will need to be configured on the guests accept for their IP address, subnet mask, default gateway, and DNS if needed.

Here’s a diagram of the virtual topology, which hopefully will make things a little more clear.

VirtualBox Host Interface NAT Topology

VirtualBox Host Interface NAT Topology

Getting Started

You’ll need to install the User Mode Linux utilities first, if you have done so already.

sudo apt-get install uml-utilities

TAP interfaces

Let’s create three TAP interfaces.

sudo tunctl -u $USER
sudo tunctl -u $USER
sudo tunctl -u $USER

Assign IP addresses to the TAP interfaces.

sudo ip addr add 192.168.20.1/32 dev tap0
sudo ip addr add 192.168.20.2/32 dev tap1
sudo ip addr add 192.168.20.3/32 dev tap2
sudo ip link set tap0 up
sudo ip link set tap1 up
sudo ip link set tap2 up

Routing Requirements

Enable routing and add host routes for each of the guest IP addresses.

sudo sysctl net.ipv4.ip_forward=1
sudo route add -host 192.168.20.201 dev tap0
sudo route add -host 192.168.20.202 dev tap1
sudo route add -host 192.168.20.203 dev tap2

Proxy ARP

Enable proxy ARP on all TAP interfaces so that all the guests can communicate with each other.

sudo sysctl net.ipv4.conf.tap0.proxy_arp=1
sudo sysctl net.ipv4.conf.tap1.proxy_arp=1
sudo sysctl net.ipv4.conf.tap2.proxy_arp=1

Notice, it is NOT necessary to enable proxy ARP on the public interface, since we will be using NAT for guests to access the public network and internet.

NAT Configuration

First flush all iptables rules and enable NAT on the public interface. For brevity, I’ll just show eth0, but if you have multiple interfaces, feel free to use the same command for each of them.

sudo iptables --flush
sudo iptables -t nat --flush
sudo iptables -t nat -A POSTROUTING --out-interface eth0 -j MASQUERADE
sudo iptables -A FORWARD --in-interface eth0 -j ACCEPT

Now it’s just a matter of configuring each of your guests to use the appropriate host interface as shown in the screenshot below.

After assigning the guest to an interface, configure the guest operating system with the appropriate IP address and routing information. The following list will show the IP address configuration each guest should use for this example.

Guest 1
Host interface: tap0
IP Address: 192.168.20.201
Subnet Mask: 255.255.255.0
Gateway: 192.168.20.1
DNS: Any reachable DNS server.

Guest 2
Host interface: tap1
IP Address: 192.168.20.202
Subnet Mask: 255.255.255.0
Gateway: 192.168.20.2
DNS: Any reachable DNS server.

Guest 3
Host interface: tap2
IP Address: 192.168.20.203

Subnet Mask: 255.255.255.0
Gateway: 192.168.20.3
DNS: Any reachable DNS server.

And that’s it. Your guests should all be able to ping each other, and access the internet!

To make things easy, I have also created the following Bash shell script that creates and tears down the environment with ease. Modify settings to your liking.

#!/bin/bash
# tap-setup.sh
# By Gilbert Mendoza
 
# Change username accordingly
USER="gmendoza"
PROXY="tap0 tap1 tap2"
TAPS="tap0 tap1 tap2"
NAT_OUT="eth0 wlan0"
 
ip_setup(){
ip addr add 192.168.20.1/32 dev tap0
ip addr add 192.168.20.2/32 dev tap1
ip addr add 192.168.20.3/32 dev tap2
route add -host 192.168.20.201 dev tap0
route add -host 192.168.20.202 dev tap1
route add -host 192.168.20.203 dev tap2
}
 
nat_setup(){
iptables --flush
iptables -t nat --flush
for i in $NAT_OUT
 do
   iptables -t nat -A POSTROUTING --out-interface $i -j MASQUERADE
done
for i in $TAPS
 do
   iptables -A FORWARD --in-interface $i -j ACCEPT
done
}
 
tap_up(){
tunctl -u $USER
tunctl -u $USER
tunctl -u $USER
sysctl net.ipv4.ip_forward=1
for i in $PROXY
 do 
   sysctl net.ipv4.conf.$i.proxy_arp=1
done
for i in $TAPS
 do
   ip link set $i up
done
}
 
tap_down(){
sysctl net.ipv4.ip_forward=0
iptables --flush
iptables -t nat --flush
for i in $PROXY
 do
   sysctl net.ipv4.conf.$i.proxy_arp=0
done
for i in $TAPS
 do
   tunctl -d $i
done
}
 
if [[ $EUID -ne 0 ]]; then
  echo "This script must be run as root" 1>&2
  exit 1
else
 
case "$1" in
 
start)
	tap_up
	ip_setup
	nat_setup
	;;
stop)
	tap_down
	;;
*)
	echo "Usage: $0 {start|stop}"
	;;
esac
 
fi
 
exit 0

Using it is as simple as the following.

sudo tap-setup.sh start
sudo tap-setup.sh stop

31 Responses to 'VirtualBox Host Interface Networking with NAT'

Subscribe to comments with RSS or TrackBack to 'VirtualBox Host Interface Networking with NAT'.

  1. lorim said,

    on September 23rd, 2008 at 8:19 am

    great howto… i was doing this with parprouted on a wlan but sometimes pinging between guests doesn’t work, while with your howto it works 100% :) (maybe something isn’t working right in parprouted) thanks a lot! PS: you can also put the functions in some scripts that virtualbox can call when powering on the guests, so you can keep every settings “per-guests” and avoid having a lot of tap interfaces when you just need one ;)

  2. palik said,

    on October 7th, 2008 at 8:21 am

    it’s work perfect for me.
    thanks a lot

  3. eDRoaCH said,

    on October 30th, 2008 at 2:04 pm

    Great tutorial, I appreciate it. However I remember you having 2, a ’sandbox’ version and this one. It is nice you consolodated them but in the process you dropped the windows info. I cant remember how to enable the proxy arp on the network bridge.

    some of us dual boot you know.

  4. eDRoaCH said,

    on October 30th, 2008 at 3:05 pm

    found it, Windows XP users:
    To create bridge:
    rclick My Network Places-> properties.
    select all adapters you want in the bridge
    rclick->bridge connections

    Enable promiscuous mode:
    start->run->cmd
    ( ‘>’ means type whats after it)
    >netsh bridge show a
    >netsh bridge set adapter # forcecompatmode=enable
    where # = whichever ones do NOT have ‘enabled on them’ in the list, one at a time.
    >netsh bridge show a
    to verify.
    Note you will loose network access for a minute or so after you create the bridge and each “set adapter” command

    enjoy!

  5. Juan C. A. said,

    on November 7th, 2008 at 10:10 am

    Great! Thanks!

  6. tkgafs said,

    on November 10th, 2008 at 3:36 am

    Thanks for this it works well, but for one small issue I have created a guest with two nics assigned to tap4 & tap5

    in the guest they are both seen as up and running and both can be pinged succesfully from the guest itself, but from any other guest or the host only 1 nic can be contacted, normally this is the guest eth0 but if run ifconfig eth0 down then the 2nd nic on eth1 starts replying to pings and stays online even if ifconfig eth0 up is run but eth0 remains unavailable.

    anybody got any suggestions as to what the problem might be

    Tkgafs

  7. gmendoza said,

    on November 10th, 2008 at 9:10 am

    Drop me an email using the information found on my contact page. It sounds like either a basic routing decision issue.

  8. Ralf S. said,

    on November 14th, 2008 at 4:54 am

    Thanks, exactly what I’m trying to implement. One question left: How do I bind tap0 (tap1, …) to a guest system? I just set IP data as mentioned and ran the tap-setup script, but the VMs do not see each other and Internet is not available to the guests neither.
    TIA, Ralf

  9. gmendoza said,

    on November 14th, 2008 at 8:22 am

    @Ralf

    Edit the network settings of your guest in VirtualBox and change the “Attached To” value to “Host Interface”. I added an additonal screenshot to the post to make it a bit more complete.

  10. Ralf S. said,

    on November 14th, 2008 at 10:22 am

    Fantastic – thanks a bunch!!! I missed the “interface name” field. Once again, thank you!

  11. dicipulus said,

    on November 20th, 2008 at 7:39 pm

    hmmm, I can ping the real world. I can ping tap0’s gateway from tap1 and vice versa, but I can’t seem to get past the gateway of either to the hosts. Need to study routes and such better I think. I just am not seeing the issue

  12. gmendoza said,

    on November 21st, 2008 at 4:22 pm

    Make sure that you don’t have any iptables rules blocking your forwarding.

  13. okubax said,

    on November 23rd, 2008 at 6:17 pm

    You are my hero. after months spent trying out different solutions and breaking my Linux (ubuntu) computer more than once, I have found a solution that works and so easy. Thanks for the script too, that makes it even easier.
    NOTE to some users with ufw enabled in ubuntu, ufw didn’t allow the connection to work until I disabled it then the interface started working.
    Thanks again !

  14. Snaggletooth said,

    on December 2nd, 2008 at 11:48 pm

    You sir, rock my fucking world! After roughly 30 some odd links on this subject, finally one that makes clean sense.

  15. Vazemeazer said,

    on December 6th, 2008 at 12:41 pm

    Awesome!! Works like a charm!!

  16. Ronald Baljeu said,

    on January 28th, 2009 at 6:06 pm

    Thanks! Great article. Very well documented.

    I would just like to add that Virtualbox 2.1.2 has a problem which prevents guests to see each other, when using your setup. Version 2.1.0 however works perfectly. I sent a bug report for this (#3215).

    Thanks again!

  17. Ronald Baljeu said,

    on January 29th, 2009 at 11:17 am

    Follow up: with version 2.1.0 or later, you can share a single host interface among multiple guests. This makes the setup much easier. Just create tap0 with IP 192.168.20.1/24, skip the host routes and proxy-arp, and setup all guests to use 192.168.20.1 as gateway. This works for 2.1.2, too. Hope this helps.

  18. Alsan Wong said,

    on February 7th, 2009 at 6:03 pm

    Thanks very much for the sharing.
    One things, I can ping the guest through tapN from host, but I can’t access the service inside (ie: HTTP). This can be simply by testing “telnet 192.168.20.1 80″.
    So, how can I achieve this? Thanks in advance.

  19. gmendoza said,

    on February 8th, 2009 at 10:30 am

    Well, if all the instructions have been followed, typically connectivity issues arise with iptables firewall rules. I would flush any you have on the host and the client. Re-check connectivity, and use tcpdump on client and host to see where the problem is.

  20. Alexwebmaster said,

    on March 3rd, 2009 at 4:26 am

    Hello webmaster
    I would like to share with you a link to your site
    write me here preonrelt@mail.ru

  21. CyberThug said,

    on April 3rd, 2009 at 10:17 pm

    Great Tutorial, may repost in my Blog ? I want to share to my friend in Indonesia.

  22. gmendoza said,

    on April 4th, 2009 at 6:35 am

    Sure thing! Glad to have helped.

  23. z0n said,

    on April 9th, 2009 at 7:46 am

    After many late nights trying to get my wifi interface bridged for vbox, I run your script and everything just works – without a single dodgy if-up script or weird, mystical manual interface setting.

    Excellent script, Dude – you must wear a beard, I’m sure ;>

    Many thanks – you rule!

  24. gab said,

    on April 21st, 2009 at 2:42 am

    How will i use the this script? can you guys provide some steps? many thanks!

  25. gmendoza said,

    on April 21st, 2009 at 9:10 am

    gab… my apologies for not explaining how to set up the script. my reasoning is that if I explain how to set it up, it becomes redundant across all of my posts.

    1. Save the script as a text file in a place you have “write” access to. Your home directory should be fine. Save it as “tap-setup.sh” or any other name you find appropriate.

    2. Copy the script to a directory referenced in your $PATH variable. I like to put my own custom scripts in “/usr/local/bin/”. This allows you to just type in the name of the script at the command line without having to type it’s absolute path.

    3. Make the script executable.

    sudo chmod +x /usr/local/bin/tap-setup.sh

    4. Run the scripte from the command line.

    sudo tap-setup.sh start
    sudo tap-setup.sh stop

  26. gab said,

    on April 23rd, 2009 at 3:15 am

    Does it affect my current internet connection if I enable this script? I’m directly connected to a cable modem..

    Thanks for writing the steps. I appreciate your help!

  27. gmendoza said,

    on April 23rd, 2009 at 9:58 am

    You run this script only when you need to start and use Virtualbox. After finished with Virtualbox and it’s all shut down, you can use it again with the stop option. It should not affect your internet connection at all, but if you have firewall rules turned on your host computer, you may need more fine tuning of your rules.

    You should know that if you just want to have your guests behind a NAT, this process has been made easier in the most recent versions of Virtualbox.


  28. on May 18th, 2009 at 11:49 am

    [...] IPtables Tutorial IPTables Port Redirect VirtualBox, com nat VBoxManage Port Forward Linux porta, redirecionamento, [...]

  29. Mark Nicholas said,

    on June 10th, 2009 at 1:28 pm

    works great with Air Cards as well (ppp0) modify script from
    NAT_OUT=”eth0 wlan0″
    to
    NAT_OUT=”eth0 wlan0 ppp0″
    and voila! life is good

    thank you for the help!

  30. scott said,

    on June 30th, 2009 at 12:14 pm

    I have been using something similar I believe @ work, but the problem is it is updating the DNS with my NAT IP address. Do one of the iptables rules above stop that from happening ?

  31. edward said,

    on July 2nd, 2009 at 1:31 pm

    With version 2.1.4 OSE of virtualbox you can just go to Settings -> Network: and change the “Attached to:” from “Nat” to “Host Interface”. Then select your host machine’s active network device from the list. Start up your guest and it should pick up an IP from your networks’ Dhcp server. If you have no DHCP server configure the guest with a static IP. Note, you may have to open a terminal and run dhclient3 as root or with sudo to get your guest to pick up an IP via dhcp. Otherwise it should just work. It did for me.

    thanks
    emk

Post a comment