How can I automatically switch my VMs’ bridged adapters between eth0 and wlan0 depending on what’s active?

Posted on

Problem :

In Virtualbox, I have a bunch of virtual machines. The host is a Debian laptop that frequently switches between a wired and a wireless connection. Every time I go wireless (or go wired), I have to change the Virtualbox settings of each virtual machine from eth0 to wlan0 (or the other way around) to have the guests connect to the network. How can I make this switch automatic?

Solution :

It is possible to change the type of the virtual network interface with a command like:

VBoxManage controlvm <VM_name> nic1 bridged eth0

This will make the first virtual interface in this VM be bridged to eth0. However, it only works when the guest is running. (I’m not sure exactly when it will update the persistent configuration, but some testing has shown that the command does nothing if the guest is not running, but if it is, it both changes the immediate state of the interface and updates the configuration.)

But it can be made to work if you have something running it frequently, specifying the interface you want to bridge to. You can use my NCD programming language to do this automatically. The NCD program below will observe the state of eth0 and wlan0, and will repeatedly invoke a command like above to make sure your VM is bridged the right interface. (in particular, the one which has the RUNNING flag; e.g. for wired interfaces this means that the cable is plugged in)

process vbox_iface {
    # Wait for link on either eth0 or wlan0. Prefer eth0.
    multidepend({"link-eth0", "link-wlan0"}) linkif;

    println("Using ", linkif.dev);

    # Enter loop (this is a hackish loop).
    multiprovide("loop-run");
    multidepend({"loop-again", "loop-run"});

    println("Setting bridged to ", linkif.dev);

    # Set VM NIC config.
    runonce({"/usr/bin/VBoxManage", "controlvm", "Windows XP", "nic1", "bridged", linkif.dev});

    # Wait some time (in milliseconds).
    sleep("2000", "0");

    # Continue loop.
    multiprovide("loop-again");
}

process lan_iface {
    var("eth0") dev;

    # Wait for device to appear and for link (e.g. cable).
    net.backend.waitdevice(dev);
    net.backend.waitlink(dev);

    multiprovide("link-eth0");
}

process wlan_iface {
    var("wlan0") dev;

    # Wait for device to appear and for link (e.g. cable).
    net.backend.waitdevice(dev);
    net.backend.waitlink(dev);

    multiprovide("link-wlan0");
}

You can use the above program by running (as your user account, not root):

badvpn-ncd --loglevel warning --config-file <file_with_above_script.ncd>

Be sure to adjust the interface names in the script, and the VM name. Once you have verified that it works, you can configure your desktop environment to autostart the badvpn-ncd process.

Leave a Reply

Your email address will not be published. Required fields are marked *