Conflict free DNS and routes with multiple DHCP interfaces
— Paul Annesley, October 2009
The Problem
Running DHCP on two or more network interfaces inevitably leads to conflicting or unpredictable DNS and default route settings.
For development at home and work, I use an Ubuntu virtual machine running on Mac OS. To ensure I have a predictable IP address regardless of what network I'm on, the VM primary network interface is NATed, so it gets an IP address from VMware's DHCP server. To let my co-workers access HTTP on my virtual machine, I have a second network interface which is bridged
The biggest symptom of the problem is complete loss of connectivity when I switch between home and office, and the default route from the previous location is retained.
The Solution That Should Work
DHCP client configuration lets you specify which details you want to request from the DHCP server.
The request statement
request [ option ] [, ... option ];
The request statement causes the client to request that any server responding to the client send the client its values for the specified options. Only the option names should be specified in the request statement - not option parameters. By default, the DHCP server requests the subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, host-name, nis-domain, nis-servers, and ntp-servers options.
So it should be possible to omit 'routers' and 'domain-name-servers' from the 'request' statement of the bridged interface, and all should be good. However, it seems that some DHCP servers (like in my Linksys router at home) send a 'router' anyway, and the DHCP client respects it despite not having requested it.
The Solution That Does Work
The solution that seems to work reliably is to write a simple dhclient-enter-hook to unset any unwanted details before they are processed.
# /etc/dhcp3/dhclient-enter-hooks.d/bridged-eth1
if [ "$interface" = eth1 -a -n "$new_routers" ]; then
echo Discarding eth1 routers: $new_routers
unset new_routers
fi
if [ "$interface" = eth1 -a -n "$new_domain_name_servers" ]; then
echo Discarding eth1 dns servers: $new_domain_name_servers
unset new_domain_name_servers
fi