DHCP Client Script Examples

A DHCP client may override /etc/resolv.conf, the hostname and set routes upon receiving. If this is undesired, it can be turned off by overriding a function in the dhclient-script.

Two dhclients
There are two dhclients: the ISC DHCP client, and the OpenBSD DHCP client.

The ISC client is installed by default on Linux, while the OpenBSD client is more common for BSD, including FreeBSD.

Please be aware of the difference. The configuration file for both clients is very similar, but there are differences, so I strongly recommend to make sure you read the correct man pages.

Known differences I've encountered:
 * In ISC, the interface in the config file takes presedence over the interface specified on the command line. In BSD DHClient, the command line takes presedence.
 * The BSD dhclient.conf does not know about adding new names: option vendor-specific-info code 43 = string
 * The BSD dhclient-script and ISC dhclient-script have different functions, so they behave different if you to override them in dhclient-enter-hooks or dhclient-exit-hooks.

More information can be found in the manual pages or source code:


 * OpenBSD and FreeBSD man page
 * OpenBSD and FreeBSD dhclient-script source code
 * ISC dhclient-script man page
 * ISC dhclient-script source code

Don't override resolv.conf
resolv.conf is overwritten if the DHCP server send a DHCP message with options domain-name-servers (code 6), domain-name (code 15), or domain-search (code 119).

OpenBSD DHCP client
Create a file called /etc/dhclient-enter-hooks and add this:

add_new_resolv_conf { # We don't want /etc/resolv.conf changed # So this is an empty function return 0 }

ISC DHCP client
Create a file called /etc/dhcp/dhclient-enter-hooks and add this:

make_resolv_conf { # We don't want /etc/resolv.conf changed # So this is an empty function return 0 }

Don't ask for name servers
Alternatively, in /etc/dhclient.conf</tt>, add a line that only requests certain options, but not domain-name-servers</tt>, domain-name</tt>, nor domain-search</tt>. E.g.:

request routers, subnet-mask, broadcast-address, ntp-servers, host-name

Don't override hostname
The hostname is overwritten if the DHCP server send a DHCP message with option host-name</tt> (code 12).

OpenBSD DHCP client
Create a file called /etc/dhclient-enter-hooks</tt> and add this:

check_hostname { # We don't want the hostname changed # So this is an empty function return 0 }

ISC DHCP client
Create a file called /etc/dhcp/dhclient-enter-hooks</tt> and add this:

unset new_host_name

Don't ask for a hostname
Alternatively, in /etc/dhclient.conf</tt>, add a line that only requests certain options, but not host-name</tt>. E.g.:

request routers, subnet-mask, broadcast-address, domain-name-servers, ntp-servers

Do not set a default route
Suppose you have a multihomed FreeBSD, with two interfaces receiving an IP address and default route by DHCP. E.g. interface em0 is for Internet, interface em1 is for IPTV. The default behaviour for the OpenBSD/FreeBSD dhclient-script is to only set the default route for the first interface that receives a DHCP reply. The default behaviour for ISC dhclient-script is to set the default route for all interfaces.

If you want to have more control, e.g. only set the default route for em0, but not for other interface, add the following lines to /etc/dhclient-enter-hooks</tt>:

if [ "$interface" != "em0" ] then unset new_routers fi
 * 1) Do not set default route on any interface except em0

Add Routes
Suppose your FreeBSD router receives a default route, but you only want to specify certain routes, you can add the following to /etc/dhclient-enter-hooks</tt>:

case "$reason" in    BOUND|RENEW|REBIND|REBOOT|TIMEOUT)         # Add static routes on em1         if [ "$interface" = "em1" -a -n "$new_routers" ]         then             # Determine gateway from routers             # extract first IP address and replace all . with " "             gateway=`echo "${new_routers%% *}" | sed 's/\./ /g'`             # route 192.2.0.128/25 and 10.0.0.0/8 to the gateway IP.             new_classless_routes="25 192 0 2 128 $gateway 8 10 $gateway"         fi         # Do not set default route on any interface except em0         if [ "$interface" != "em0" ]         then             unset new_routers         fi     ;; esac

This script performs two actions:
 * 1) If em1</tt> is configured, add two routes.
 * 2) if any other interface than em0</tt> is configured, do not set a default route.

Rather than calling route</tt> directly, the script uses the classless-routes DHCP option to tell the dhclient-script</tt> to add a certain route in the routing table. Note that the encoding is a bit odd: the size of the subnet determines how many octets of the IP address are encoded in the DHCP option, and thus in the new_classless_routes</tt> variable.

If you use the ISC dhclient instead of the OpenBSD dhclient, note that the FreeBSD dhclient-script supports the classless-routes, but the ISC dhclient-script only supports the older static-routes DHCP option, and will not set any routes. As a work-around, you can set <tt>new_static_routes</tt> instead of <tt>new_classless_routes</tt>. Officially, this bad syntax (<tt>static-routes</tt> is supposed the work on individual IP addresses, not IP ranges), but in practise it should work fine for the ISC dhclient-script.

gateway=${new_routers%% *} # select first IP address new_static_routes=192.2.0.128/25 $gateway 10.0.0.0/8 $gateway

In case you are wondering why I used sed instead of the following parameter expansion: the second line is a bash-construct, and does not work in sh, which is used by dhclient-script.

gateway=${new_routers%% *} # extract first IP address gateway=${gateway//./ } # replace all. with " "