The Problem
While implementing a naming scheme (I’m going with the not very creative name-after-types-of-alcohol naming scheme) for machines at work, I wanted bash prompt to reflect my machine’s current hostname as distributed by DHCP. I’m running Ubuntu 11.10 on my laptop, a Dell Inspiron N5110.
By default, Linux systems determine their hostname by using the hostname
command. hostname
, in turn, uses uname(2) to determine the hostname.
Ubuntu 11.10 uses NetworkManager as tool of choice for users to configure network interfaces and NetworkManager seems to be using dhclient
as its DHCP client. I’m personally more familiar with dhcpcd
, but that’s neither here nor there (or so I thought).
What I wanted to accomplish was simple. I wanted Ubuntu to set my hostname dynamically upon receiving an address from DHCP, so that hostname
returned a name that came from DHCP. I know that DHCP has a mechanism by which clients can request a particular hostname, but this is the opposite of what I want. I want DHCP to tell me my hostname, and I want Ubuntu to set it. Here’s how I made that happen.
Background
In the good old days, when I was one of the cool kids drinking the Gentoo kool-aid, I remember dealing with this exact same issue using a switch to dhcpcd
. It turns out that it was the -H
switch. From man dhcpcd
:
-H Forces dhcpcd to set hostname of the host to the hostname option supplied by DHCP server. By default dhcpcd will NOT set hostname of the host to the hostname option received from DHCP server.
Great! This is exactly what I want.
Unfortunately, as I mentioned before, NetworkManager doesn’t use dhcpcd
. It uses dhclient
, provided by the isc-dhcp-client
package. The simple functionality that I want can’t be unique to dhcpcd
, can it?
Well, it is, sort of. dhclient
doesn’t natively support this functionality, but instead offers a hook-based interface in which scripts can be run at certain times in the address-acquisition process. The dhclient-script
program provides the framework for this hook-based interface. It looks for hooks in two places: /etc/dhcp/dhclient-enter-hooks.d/
and /etc/dhcp/dhclient-exit-hooks.d/
. For our purposes, we want to set our hostname based upon the address acquired from DHCP, so we’ll have to place our script in the latter location, as it should be executed as an “exit” hook.
The Solution
The script itself has fortunately already been written by the Debian folks. Look here for the original article if you are interested, but here is the script, modified slightly to work on Ubuntu 11.10:
#!/bin/sh # Filename: /etc/dhcp/dhclient-exit-hooks.d/hostname # Purpose: Used by dhclient-script to set the hostname of the system # to match the DNS information for the host as provided by # DHCP. # if [ "$reason" != BOUND ] && [ "$reason" != RENEW ] \ && [ "$reason" != REBIND ] && [ "$reason" != REBOOT ] then return fi echo dhclient-exit-hooks.d/hostname: Dynamic IP address = $new_ip_address hostname=$(host $new_ip_address | cut -d ' ' -f 5) echo $hostname > /etc/hostname hostname $hostname echo dhclient-exit-hooks.d/hostname: Dynamic Hostname = $hostname
Save this script in /etc/dhcp/dhclient-exit-hooks.d/
and your system’s hostname will henceforth be set automatically by dhclient
.
Update
Since saving this script, I’ve been noticing that I’d receive strange hostnames from DHCP. It turns out that the reason for this was virtual machines requesting an IP address. To fix this, we need to add some sort of specification to the hostname
script that only updates our hostname if the response from DHCP is intended for a real (not virtual) interface.
To support this kind of logic, dhclient-script
provides the $interface
variable. From man dhclient-script
:
The interface name is passed in $interface, and the media type is passed in $medium.
So, we add this to the top of our script:
# Do not update hostname for virtual machine IP assignments if [ "$interface" != "eth0" ] && [ "$interface" != "wlan0" ] then return fi
Add a test block for each “real” interface that could receive a response from DHCP for your machine.