VirtualBox provides a traffic limiting tool through its CLI interface. However, one might want to use the full power of traffic control to further limit or shape the traffic going in/out or ever between VMs. Problems arise when your VM needs access to internet, and we are going to see how to circumvent them.
VirtualBox does a fairly good job with its built-in NAT adapter feature. But it does so by using a socket and not a distinct network device visible in /sys/class/net/. This comes with some drawbacks:
- You can’t easily monitor the network on the built-in NAT. So if your VM is misbehaving, you couldn’t use tcpdump to troubleshoot.
- The built in NAT reaches directly to the Internet in a transparent manner. If you wanted to control access to the Internet you would have to switch to a bridge device or go with host-only.
I figured out the only solution to these would be to make the VM use an interface I could fully control. And while Virtualbox supports an option through the CLI utility VBoxManage to make the built-in NAT go through an interface by designating its IP, I went for another option: make a Host-Only adapter in Virtualbox.
This is done in
File -> Preferences -> Network. Click the green icon with a PLUS sign in it. A new network is created, probably called vboxnet0. Then click the little screwdriver icon to edit the vboxnet0 settings. Select the DHCP Server tab and make sure “Enable Server” is unticked. It will be ticked by default. We don’t want the default DHCP server, because it will bind its lease on the Virtualbox socket.
Then install dnsmasq. We are gonna use it to deal with the DHCP leases and DNS entries. While dnsmasq configuration can vary depending on your host system, it is generally found under a /etc/dnsmasq.conf.
interface=vboxnet0 bind-interface dhcp-range=192.168.56.2,192.168.56.150
The range is up to you. If you set the vboxnet0 adapter to 192.168.56.0/24, then any range within this lane will fit. After you have done it, restart the dnsmasq service with your host service manager.
The big advantage of having that network device for ourselves and not just hidden inside a socket managed by Virtualbox is that we can now use kernel features to deal with packets. But that also means we have to setup the NAT feature ourselves. Hopefully this is (almost) a one-liner.
We are gonna use iptables for this. If you are using another firewall like ufw, disable it beforehand.
We also have to activate the ip forwarding at the kernel level. It can be done in /etc/syctl.conf or by running
sysctl -w net.ipv4.ip_forward=1.
Then we can setup the nat filter rule for iptables with
iptables -t nat -A POSTROUTING -s 192.168.56.0/24 -j MASQUERADE.
Make sure to have the iptables running and to save the configuration with
iptables-save > /etc/iptables/iptables.rules.
We then have an operable interface. You can launch the VM, but be sure to make it use the previously defined adapter with said settings.
Using traffic control (tc), we can constrain the vboxnet0 interface without harming our main internet-providing interface (typically eth0 or wlan0, YMMV). However I recommend the tc wrapper tcconfig.
Another requirement for me was to setup a second interface for the host to get access to the host services without the constraint of tc. This time add a new Host-Only adapter with the embedded DHCP activated. You can access the host through this interface just by going to the adapter’s address.
To do it the other way around, just type :
VBoxManage list vms VBoxManage guestproperty get <vm name> "/VirtualBox/GuestInfo/Net/0/V4/IP"