Using native OS X NAT with VirtualBox

VirtualBox provides built-in NAT, but on OS X it doesn’t allow to access VM from host, so every time I need to set up host only network. I wanted to have one, fully functional virtual network with NAT routing. OS X has built-in NAT capability that is used by Internet Sharing – why not use it with VirtualBox?


Note: This post is work-in-progress.

VirtualBox configuration

First of all we need to configure host-only network in VirtualBox. I arbitrary choose 10.0.69.0/24 network for purpose of this tutorial. I configured host-only network vboxnet0 to use this network. Remember to disable VirtualBox DHCP server, as it doesn’t allow to provide gateway address.

VirtualBox Network Settings

OS X NAT configuration

First, we need to enable routing capability in OS X network stack. Run sudo sysctl net.inet.ip.forwarding=1 or add

net.inet.ip.forwarding=1

to /etc/sysctl.conf (create this file if necessary) to make this persist over reboots.

Then add the following NAT rules to /etc/pf.conf after rdr-anchor line:

nat on {en0, en1} proto {tcp, udp, icmp} from 10.0.69.0/24 to any -> {en0, en1}
pass from {lo0, 10.0.69.0/24} to any keep state

On my Mac en0 is Gigabit Ethernet and en1 is AirPort. That way NAT will work regardless of what is my current internet connection. You may need to adjust it depending on your configuration.

To load new rules run sudo pfctl -e -f /etc/pf.conf and to ensure that rules are loaded on each boot run:

sudo /usr/libexec/PlistBuddy -c 'add :ProgramArguments:3 string -e' /System/Library/LaunchDaemons/com.apple.pfctl.plist

Add host-only network to VMs

This should be quite straightforward, simply add host-only network to your VMs and run DHCP client or set static ip from chosen network.

DHCP configuration (optional)

This is optional, but you probably want to have DHCP server. We may use OS X built-in DHCP server. First of all, you’ll need to create /etc/bootpd.plist file that setups DHCP server for 10.0.69.0/24 network with dynamic range of 10.0.69.50-254 and providing public DNS server (8.8.8.8) to clients:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>bootp_enabled</key>
    <false/>
    <key>detect_other_dhcp_server</key>
    <integer>1</integer>
    <key>dhcp_enabled</key>
    <array>
        <string>vboxnet0</string>
    </array>
    <key>reply_threshold_seconds</key>
    <integer>0</integer>
    <key>Subnets</key>
    <array>
        <dict>
            <key>allocate</key>
            <true/>
            <key>lease_max</key>
            <integer>86400</integer>
            <key>lease_min</key>
            <integer>86400</integer>
            <key>name</key>
            <string>10.0.69</string>
            <key>net_address</key>
            <string>10.0.69.0</string>
            <key>net_mask</key>
            <string>255.255.255.0</string>
            <key>net_range</key>
            <array>
                <string>10.0.69.50</string>
                <string>10.0.69.254</string>
            </array>
            <key>dhcp_domain_name_server</key>
            <array>
                <string>8.8.8.8</string>
            </array>            
        </dict>
    </array>
</dict>
</plist>

Then you may enable bootpd with sudo /bin/launchctl load -w /System/Library/LaunchDaemons/bootps.plist. To disable just replace load with unload in the command.

Set static MAC-based DHCP IP addresses (optional)

Create /etc/bootpstab file, here is an example of the content:

#
# bootptab example
#
%%
# machine entries have the following format:
#
# hostname      hwtype  hwaddr              ipaddr          bootfile
client1         1       00:01:02:03:04:05   10.0.0.20       
client2         1       00:a0:b2:ef:ff:0a   10.0.0.20       

Further reading

comments powered by Disqus