Bridged Networking with VirtualBox on Linux Hosts

IMPORTANT NOTE:
As of VirtualBox 2.1.0 this page has become unnecessary. I'm leaving it up as it's still a reasonable guide to bridging in general, and can be used with KVM. Also, especially in some older Fedora systems where the tunctl program can be difficult to find, one can still use VirtualBox's VBoxTunctl to set up tap interfaces.

On wireless machines, there will be an error message. See this ticket about conflicting addresses. Despite the message, wireless host networking works without further configuration, and the message can be safely ignored.

The rest of this page has the original article, from when VirtualBox's host networking was non-trivial.

VirtualBox is a nice alternative to VMware. It's quite fast, and lately, my experience (subjectively, I haven't done any benchmarks) is that it's become faster than VMware's free VMware-server. However, like qemu, its default networking is NAT, where the guest O/S isn't visible on a LAN. At times, one wants the machine to have its own LAN address, as if it were another host on the network.

The VirtualBox Users' Guide (it's a pdf file) is quite good, but some folks do find it a bit confusing. This is an effort to give a quick explanation of using bridged networking on a Linux host system.

One note here. On various forums and mailing lists, people seem to attempt to use this howto in conjunction with the manual, then get stuck. I didn't find the manual adequate, which is why I wrote this.

Use this page if you like. It works for me. If it doesn't work for you, I'm sorry, but if you edit some configuration file as suggested by the manual, and then it doesn't work for you, I can't really help you. Go back, pretend there is no manual, and just use this page. See if that works.

However, I should mention that this page goes under the assumption that you want temporary interfaces. That is how I use VirtualBox. If you want to have it running all the time, the manual does have a method to make these changes permanent. I never investigated it thoroughly as I didn't need it. If that is what you want or need, you are better off trying to figure out the manual than you are using this page.

Now, back to this tutorial.

Let's take care of a few permissions first. When VirtualBox is installed, it echoes a message that any user must be added to vboxusers. If the user name is john, it can be done with usermod.
/usr/sbin/usermod -G vboxusers -a john

You will have to log out and log back in before that takes effect. This doesn't mean using sudo or doing su to root. It means logging out completely and then logging back in.

When using bridging, whether for wired or wireless, we will be creating an interface called tap0 which will create a /dev/net/tun. The /dev/net/tun device will, by default, be owned by root with 600 permissions, (read write). We want the vboxusers group to have access to it, so we'll edit the file (or create it if it doesn't already exist) /etc/udev/rules.d/10-local.rules. We want the line
KERNEL=="tun", NAME="net/%k", GROUP="vboxusers", MODE="0660"

Wired Networks

This first method is for a wired network. For wireless bridged networking see below. My own network is behind a Linksys router which also gives out DHCP addresses. I use the default subnet of 192.168.1.0 with a netmask of 255.255.255.0. While I've been doing this on Fedora hosts, it should work with any Linux distribution. You will have to adjust addresses to your own network's layout.

In short, we'll create a bridge, bring down the ethernet interface, add it as a member of the bridge, bring the bridge up, create a tap interface, add that to the bridge as well, and we'll be more or less good to go. Before beginning make sure that you have bridge-utils (your distribution might call it something else) installed. Also, you'll have to either be root or have root privileges with sudo to perform many of these commands.

Lastly, most of these commands, on Fedora, are found in /usr/sbin or /sbin. In Fedora, those two directories are not in the $PATH of the normal user. There are various ways around this. In Fedora, you can first do su - (note the - after the su and space) which will give you root's environment, including the $PATH. Another way is to, before starting the series of commands, temporarily add those two directories to your $PATH. That can be done by typing
PATH=$PATH:/sbin:/usr/sbin

That segues nicely into my next comment. The User Guide's directions for Fedora won't work unless you have /sbin and /usr/sbin in your $PATH when you first log on or do an su -. The VBoxAddIF command that they discuss calls, among other things, ifconfig, which is in /sbin. Therefore, if you run it as a user with sudo, or do an su without the - afterwards, you'll get errors that ifconfig wasn't found. However, we're not going to do it their way. :).

We are going to create some temporary interfaces. Let's begin.

First create a bridge
brctl addbr br0

Now bring down the interface that you're using, in most cases, eth0. If you get your address through DHCP, you don't have to make note of your current settings. If you manually configure your ethernet card, then make sure you know its settings before doing this. You can find that out with
ifconfig eth0

For this example, we'll say that my settings are 192.168.1.55 for the address, with a netmask of 255.255.255.0. Such an address indicates that my network is a 192.168.1.0 network with a mask of 255.255.255.0. You can usually check this with route -n or netstat -r. It should show, among other things, something like
Destination   Gateway     Genmask          Iface
192.168.1.0   *           255.255.255.0    eth0
default      192.168.1.1  0.0.0.0          eth0

(I've left some things out of the actual output, what I have above is what you want to notice. The Destination is the network, the Genmask the network's netmask and the line that begins default, with an address under the Gateway column is, oddly enough, your default gateway. If your card is manually configured, you'll need that information in a few minutes. Once you have the information (again, unnecessary if you get your address through DHCP) we can bring down the network card.

Note that this will temporarily disconnect you from the network, so you can't do this remotely.
ifconfig eth0 0.0.0.0

Next we add interface eth0 to the bridge
brctl addif br0 eth0

Now we can bring up the bridge. If you use DHCP, then simply run
dhclient br0

It should get an address. (If you get an error that dhclient is already running, then first kill it with pkill dhclient and try again. Some systems use dhcpcd rather than dhclient, adjust accordingly.)

If you had to manually set your address on eth0, then we'll do that on br0. In my example, say that I saw my IP address was 192.168.1.55. I'll give the bridge that address.
ifconfig br0 192.168.1.55 netmask 255.255.255.0 up
route add -net 192.168.1.0 netmask 255.255.255.0 br0
route add default gw 192.168.1.1 br0

Remember, we got those settings from route -n or netstat -r. If you manually give br0 an address, you will give it the same address that eth0 had before. Now that your bridge is up and running (you can test it by pinging google, yahoo or someone else) it's time to add the tap interface. Most of this is taken from the User's Guide, but we're not making a script right now. The commands are fairly similar though. Say your user name is john.
VBoxTunctl -b -u john

You should see tap0 echoed on the screen.
ifconfig tap0 up
brctl addif br0 tap0

Insert an iptables rule allowing traffic to the bridge. Before starting VirtualBox, I run (in Fedora and CentOS)
iptables -I RH-Firewall-1-INPUT -i br0 -j ACCEPT

If you're not using a RedHat based system, change RH-FIREWALL-1-INPUT to INPUT.

Now, when you run VirtualBox and edit the settings of the guest O/S, in the networking section choose Attached to Host Interface and for Interface Name choose tap0.

Now, when you start your guest system, if you're on DHCP, it can get its address dynamically. Otherwise, give it an IP address in that network, for example, 192.168.1.56 with the same subnet mask of 255.255.255.0 and gateway of 192.168.1.1.

In some cases, I've been able to leave my default iptables settings alone and everything works. If not, I add the bridge to allowed interfaces. When finished, after closing VirtualBox, you can bring things back to the way they were before. Bring down the tap interface and remove it.
ifconfig tap0 down
VBoxTunctl -d tap0

You can also remove the bridge and give everything back to eth0. Keep in mind that this will, once again, temporarily disconnect you from the network.
ifconfig br0 down

You are now off the network. You can now remove the bridge.
brctl delbr br0

Bring eth0 back up, either by running dhclient eth0 or giving it an address with the same commands we used earlier to give br0 an address.
ifconfig eth0 192.168.1.55 netmask 255.255.255.0
route add -net 192.168.1.0 netmask 255.255.255.0 eth0
route add default gw 192.168.1.1 eth0

Wireless

If you don't need bridged networking, the default NAT networking works quite well with wireless in my experience. However, many of us need or at least want, the guest O/S to have its own visible address on the LAN. Thanks to the Hazard's Stuff page I was able to do it quite easily. The technique is different. Rather than use a bridge, we use parprouted to connect the wireless card and tap0 and give tap0 an address.

I've done this on Fedora, Ubuntu and Arch. There are slight differences.
We will need the parprouted program. One can install from source or use the rpm from the Dag repos. I used the one for RHEL 5 on Fedora 8 without problems.

Ubuntu has a package for it--it might have a slightly different name, do apt-cache search parprouted and intall it. Archers, use the source. (See the ArchLinux section below for links and suggestions about building the package.)

With wireless and parprouted, we can eliminate the bridge. I left my ethernet card's address alone. The wireless gets its address from DHCP, which is fine. Say that eth1 is my wireless, with its address that works on my network, whether from DHCP or being set manually.

If you skipped the earlier part of this article about wired networks, we're using a typical 192.168.1.0/24 network. In this example, my wireless card has an address of 192.168.1.105

We have to make sure that IP forwarding is enabled. You can edit /etc/sysctl.conf in Fedora, changing the variable from 0 to 1. If you want to do it permanently, do it in sysctl.conf, if you just want the change to be temporary, you can do it with the command
sysctl net.ipv4.ip_forward=1

If making the change in /etc/sysctl.conf, to get the system to read the change without a reboot, run sysctl -p.

Now we have to create tap0. Fortunately, the VirtualBox program includes its own version of tunctl, and we can use that. The -u in the next command refers to the user who will be using VirtualBox. In this case, it's a user with the login name of john.
VBoxTunctl -b -u john

You'll see tap0 echoed to the screen. Now we bring up tap0 and give it an address. One can use ifconfig or ip--in this case, we'll use ip. Archers, please take a moment and refer to the ArchLinux section. You'll have to install the ip command (part of the iproute package) and also symlink it to /sbin. Once you've done that, return to the steps below.
ip link set tap0 up
ip addr add 192.168.1.108/24 dev tap0

We are giving tap0 an address on our LAN, which, as we discussed above is a 192.168.1.0/24 LAN. (The /24 is the same as 255.255.255.0)

Lastly, we use parprouted to bind the wireless card to tap0
parprouted eth1 tap0

Now we have the wireless card, eth1 with an address of 192.168.1.105 and the tap0 interface with an address of 192.168.1.107. After starting VirtualBox, edit the guest O/S's networking settings, just as we did in the wired setup. Once again we choose Attached to Host Interface and for the Interface Name section, we put in tap0.

On Hardy Heron (8.04 beta) I had a bit of difficulty. It no longer worked. After some trial and error, the answer turned out to be that after starting parprouted but before starting VirtualBox, use the route command to add the route to tap0. If we're on the 192.168.1.x network, the command would be
sudo route add -net 192.168.1.0 netmask 255.255.255.0 tap0

Do this after starting parprouted, or it will cut off your connection to the outside. Then, start VirtualBox.

Also, on Hardy Heron, I noticed that I had to change the default virtual network card. The default was PCnet-PCI II (Am79C970A). It didn't work till I changed it to PCnet-FAST III (Am79C973). I also clicked the Generate button for the MAC address a few times. Whether this was just for this one installation or not, I don't know, but at any rate, it was the only distro where I had to change the default. I've also noted that with further upgrades, it will choose the proper card, the Fast-III by default, so this may no longer be an issue.

Supposedly, there are iptables rules that work with this. However, so far, I have had to completely flush my iptables rules for it to be able to connect. Oddly, enough, this is only the case at times--otherwise, I can leave my default rules (Fedora defaults, pretty much, allowing ssh and nothing else) and it works. I haven't figured this out yet, nor have the many posts I've found while googling given me the solution. I'm not sure why, apparently their solutions work for the people who have posted them. The most typical one seems to be, if your card was eth1, which is what my wireless is,

iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE

It's quite possible I'm missing something though, my experience is more with the BSD pf filtering program. On Fedora Forums, someone pointed out that the command didn't work for him either. However, choosing system-config-firewall, clicking masquerade and then choosing his wireless card worked for him. I tried it and it worked for me as well. In my case, my card wasn't listed, but there is a place to add an interface.

Running iptables-save with both methods shows that the difference is that when running the command the lines allowing masquerading appear at the top of the listing. When using system-config-firewall, the lines appear at the end of iptables-save. I haven't investigated this yet, when I do, I'll add the information to the page, but at any rate, it seems that you can get it working by using system-config-firewall to have the wireless card masqueraded. When you do that, it automatically does the sysctl setting for you, changing net.ipv4.ip_forward to 1.

(To digress briefly, I recently received an email from someone who found that though this howto didn't work for them, the IP-Masquerade howto brought them success. Also, note that that howto recommends NOT using the iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE rule as default. The reader might want to try that howto's scripts for firewalling. As I'm running everything behind other firewalls, I haven't gone through that howto and tested it myself).

When the guest O/S boots up, you will have to manually assign it an address. Give it an address on the same network, that is, in this case, something like 192.168.1.109 with a netmask of 255.255.255.0 and a default gateway of 192.168.1.1. Use whatever DNS servers you usually use on the host machine.

When done, you can remove the various changes you've made. After shutting down the host machine, bring down the tap0 interface, remove it and change your sysctl variable back if you choose.
ifconfig tap0 down
VBoxTunctl -d tap0
sysctl net.ipv4.ip_forward=0
pkill parprouted

Notes for ArchLinux users

ArchLinux is a little different. I'm assuming that you've followed the ArchLinux wiki and have VirtualBox working with bridged networking using the tun module. All that is covered quite well in the wiki.

The parprouted program will have to be built from source. The tarball can be found here.

Decompress and untar it with the usual tar zxvf parprouted-<version-number>. Then cd into the directory that has been created.

The README says just do make all && make install. There's no configure script and it will install the program into /usr/local/sbin which isn't a default ArchLinux path. You have a few choices. You can edit the Makefile, just changing the /usr/local/sbin to /usr/sbin and the man pages to /usr/man instead of /usr/local/man. (That's what I do.) Other choices are to add /usr/local/sbin to the path of any users that will be running the program. (Most Archers know how to do this, but if not, you can edit the user's $HOME/.bashrc file, adding a line
PATH=$PATH:/usr/local/sbin ; export $PATH

The easiest way might be to symlink the program to /usr/sbin.
ln -s /usr/local/sbin/parprouted /usr/sbin/parprouted

Arch doesn't include the ip program by default. It's part of the iproute package. It's required if you're going to use parprouted.
pacman -S iproute

The last time I installed Arch and did a quick VirtualBox install, using the virtualbox-ose from the Arch repos, there was no VBoxTunctl. I'm not sure if this was just a minor glitch, or something else. I was in a hurry, so didn't bother researching it. I just installed the uml_utilities, also in the repos, which gave me the tunctl command and used that instead of VBoxTunctl.

There's one more minor issue. Arch installs the ip command into /usr/sbin. The parprouted program looks for ip in /sbin. Therefore, once you've installed the iproute package, to use ip with parprouted you have to symlink the ip command to /sbin.
ln -s /usr/sbin/ip /sbin/ip

(I found this out by using parprouted's useful -d as in debug flag. That runs the program in the foreground so you can see what's happening. I saw that it was calling /sbin/ip and not finding the command.)

That's all there is to it. Whether wired or wireless, bridged networking isn't that difficult.