Tuesday, August 11, 2020

Using a Raspberry Pi for basic network services, Part 2: DHCP Server


Photo credit: Michael Henzler
Wikimedia Commons, CC BY-SA 4.0


The Raspberry Pi for basic Networking services series:

Every computer on a LAN needs an IP address in order to communicate with anything else. While you can manually configure each device with a hard-coded ("static") address, this can be inconvenient and sometimes difficult. Especially for small IoT devices like smart appliances.

A long time ago, in the 1980's, several different technologies were invented so devices could be configured from a centralized location, without needing explicit on-device configuration of IP addresses and related information. The DHCP protocol was invented in 1993 and remains the most common mechanism in use today.

Using DHCP, a device doesn't need to be pre-configured with an IP address. When it starts up, it broadcasts a request to the network asking for an address. If there is a DHCP server (or a "relay agent" that can proxy the request to another network) present, the server will generate an IP address known to be valid on the LAN and assign it to the device.

A DHCP server can be configured for three different kinds of address allocations:

Dynamic allocation
The DHCP server picks an address from a pre-configured range. A lease system is used to expire addresses that are not used for some configured amount of time (typically between a few hours and a few day).
Automatic allocation
Like dynamic allocation, the DHCP server picks an address from a pre-configured range. The assignment of address to device is recorded so a device that goes off-line long enough for its lease to expire may be assinged the same address when it reconnects, if possible.
Manual (static) allocation
The DHCP server is configured to assign specific addresses to specific devices. The device is typically identified by its MAC address, but other unique identifiers may also be used.

In addition to IP addresses, DHCP servers can usually provide other related network configuration parameters, including:

  • Gateway router IP address
  • Subnet mask and broadcast address
  • DNS server IP address(es)
  • DNS domain name and domain search path

The DHCP servers built-in to consumer routers typically only support dynamic allocation. The range of IP addresses that it may use is usually configurable, but other parameters (including lease times) may not be. Support for manual allocation may be absent, or if present may not be fully functional.

For this reason, it is often desirable to disable the DHCP server built in to your router and run your own. This article explains how to set up a DHCP server on a Raspberry Pi computer running Raspbian Linux version 10.

Installing DHCP server on a Raspberry Pi

Step 1: Use Ethernet

Although you can run a DHCP server using a Wi-Fi network interface, Ethernet is a better choice. It is more reliable and doesn't require a (potentially slow) connection process at system startup time.

Nevertheless, if Ethernet is not an option for you, you can proceed with Wi-Fi.

Step 2: Configure a static IP address

Because the Raspberry Pi will be generating IP addresses, it can't rely on another device on the network for assigning its IP address. Its network interfaces need to be up and running before the DHCP server starts. Additionally, if the Pi will be acting as a DNS server in the future (will be described in a future article), then it must have a well-known IP address that it can serve to DHCP clients.

There are several different ways one may configure a network interface for a static IP address. By default, Raspbian Linux uses NetworkManager for network device configuration. The easiest way to configure a static IP address is to use the graphical interface to manually configure the network interface's IP address, router address, domain name, DNS server(s) and domain search path.

To do this without the graphical interface, edit the file /etc/dhcpcd.conf and append the following text:

interface eth0
static ip_address=192.168.1.15/24
static routers=192.168.1.1
static domain_name=example.com
static domain_name_servers=192.168.1.15 8.8.8.8 8.8.4.4
static domain_search=example.com

Where:

  • eth0 is the name of your network interface. For a Raspberry Pi, the default name of the Ethernet interface is eth0 and the Wi-Fi interface it wlan0. To see the complete set of interfaces on your computer, type ip link show:
    $ ip link show
    1: lo: <LOOPBACK,UP,LOWER_UP> ...
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
    3: wlan0: <NO-CARRIER,BROADCAST,MULTICAST,UP> ...
  • The ip_address parameter is the IP address and prefix length you are assigning to the interface. In this case, I am using 192.168.1.15 with a prefix length of 24 bits (equivalent to a subnet mask of 255.255.255.0.
  • The routers parameter is the IP address of the gateway router for the LAN segment. In this case, it is 192.168.1.1.
  • The domain_name parameter is the DNS domain for your LAN. If you have a domain name, you should provide it here. If not, you may leave it blank or pick a domain that you know nobody else is using. You may want to consult the list of top-level domains and pick something that is not on it (perhaps your name). If you pick a domain that is in use by someone else, you may encounter network problems, especially if you try to access their network (e.g. their web page). If you plan on setting up a DNS server on your LAN, use the same domain you expect to use for it.

    You should avoid using the .local top-level domain name. .local is used by Apple's Bonjour protocol for multicast-DNS resolution. If you have Apple equipment on your LAN, use of .local for other purposes (including a traditional DNS server) will create problems.

  • The domain_name_servers parameter is a list of IP addresses used to resolve DNS lookups. In this case, three IP addresses are presented. 192.168.1.15 is the Pi's static address (which is also running a DNS server). 8.8.8.8 and 8.8.4.4 are Google's public DNS servers, used as a backup for when the local DNS server is not working.
  • The domain_search parameter is a list of DNS names that will be searched when resolving host names that do not include domain names.

There are other ways to configure static IP addresses on a Raspberry Pi. If you have a method you think is easier to configure on Raspbian 10, please share it in the comments, below.

Once you have a static address configured, reboot the Raspberry Pi and check the address used (type ip address show) to see that it is using the configured address. If not, go back and double-check your work.

Install the DHCP server software

The DHCP server is provided by the Raspbian Linux distribution as an optional package. To install it, type:

sudo apt install isc-dhcp-server

You will see an error when the server tries to start, and fails (due to not being configure). You should ignore it at this time.

Configure the DHCP server

The first step is to tell the DHCP server which network interface(s) it will be operating on. Edit the file /etc/default/isc-dhcp/server and add the interface to the INTERFACES parameter:

# On what interfaces should the DHCP server (dhcpd) serve DHCP requests?
#       Separate multiple interfaces with spaces, e.g. "eth0 eth1".
INTERFACESv4="eth0"

Next, edit the DHCP server's configuration file, /etc/dhcp/dhcpd.conf and make the following changes:

Default DNS options served to DHCP clients

Add/edit the following lines at the top of the file:

# option definitions common to all supported networks...
option domain-name "example.com;
option domain-search "example.com";
option domain-name-servers 192.168.1.15;
Replace example.com with the DNS domain name for your LAN (see above). Replace 192.168.1.15 with the DNS server's IP address for your LAN.

Set lease times

Add/edit the following lines:

default-lease-time 86400;
max-lease-time 2592000;
The lease time is how long a client may hold on to an address before it must be renewed. The units are seconds. The values used here (86400 and 2592000) correspond to 1 day and 30 days.

The defaults (if you don't configure lease times) are 43200 (12 hours) and 86400 (24 hours), respectively. The sample configuration that comes bundled with the DHCP server software uses 600 (10 minutes) and 7200 (2 hours), respectively.

The correct values for your network will depend on expected usage. If most of your devices remain constant over time (e.g. a home or office LAN), then you probably want to use long leases, so devices will tend to retain their IP address over time. If devices frequently come and go (e.g. a public hot-spot), then you will want to use shorter leases in order to avoid running out of addresses.

Make the DHCP server authoritative

Add/edit the following lines:

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;
An authoritative DHCP server has the final say about which addresses are and are not valid. If this is the primary (or only) server on your LAN, then it should be authoritative. If there is another DHCP server that is primary, then this server should not be authoritative.

Configure a subnet for dynamic address assignment

Add/edit the following lines:

# My home LAN.  Dynamic addresses from .100-254
#
subnet 192.168.1.0 netmask 255.255.255.0
{
  range 192.168.1.100 192.168.1.254;
  option domain-name-servers 192.168.1.15;
  option domain-name "example.com";
  option domain-search "example.com";
  option routers 192.168.1.1;
  option broadcast-address 192.168.1.255;
}
Where:
  • The subnet line specifies the block addresses that will be served, using an IP address and subnet mask. In this case (address 192.168.1.0 and subnet mask 255.255.255.0), we are specifying the block 192.168.1.*.

    All parameters within the subnet block configure the subnet. Options specify parameters that are served to clients while other parameters configure the DHCP server itself. Any options that also appear in the DNS server's global configuration will override the global configuration for hosts in this subnet.

  • The range parameter specifies the range of addresses within the subnet from which the DHCP server will choose addresses. Multiple range statements are allowed. You should always omit the NULL address (the start of the subnet, in this case 192.168.1.0) and the broadcast address (the end of the subnet, in this case 192.168.1.255) from all ranges because they are invalid host addresses.

    In this example case, the DHCP server will choose addresses between 192.168.1.100 and 192.168.1.254. Addresses between 192.168.1.1 and 192.168.1.99 will not be served. On my LAN, I use these for static address assignments.

  • The domain-name-servers option is a comma-separated list of DNS servers (in order of preference) that will be configured on clients. Technically, this option is not necessary because it is already configured globally with the same value (see above).
  • The domain-name option is the domain name that will be configured on clients. Tehcnically, this option is not necessary because it is already configured globally with the same value (see above).
  • The domain-search option is a comma-separated list (in order of preference) of domain search-prefixes that will be configured on clients. Techncally, this option is not necessary because it is already configured globally with the same value (see above).
  • The routers option is a comma-separated list of gateway router addresses (in order or preference) of IP addresses that are used to route traffic out of the LAN (typically to the Internet).
  • The broadcast-address is the IP address used for broadcast traffic on the subnet.

Start the DHCP server

Now that you have the server configured, disable any other DHCP servers running on your LAN (e.g. in your router) and issue the following command:

sudo systemctl start isc-dhcp-server

If you see any error messages, go back and double-check your configuration. Detailed reasons for a failure will be written to /var/log/syslog.

Enable the DHCP server to auto-start

Once you are confident that your DHCP server is running, the following command will enable it so it will auto-start whenever your Raspberry Pi restarts:

sudo systemctl enable isc-dhcp-server

After doing this, reboot the Raspberry Pi. When it restarts, issue the following command to confirm that it is running properly:

sudo systemctl status isc-dhcp-server

If it is not running, try manually starting it, as you did before:

sudo systemctl start isc-dhcp-server

If you see that you can start it manually, but it fails after a reboot, this is a known problem. The DHCP server can not start until after your network interfaces become active, but the system tries to start it before then. I don't know of a good solution, but I applied a hack that gets the job done. Edit the file /etc/init.d/isc-dhcp/server and add the following lines to the start_daemon() function between the INTERFACES="$*" line and the test_config "$VERSION" "$CONF" line:

# HACK: DHCPD fails because it is started before the network comes up
#       This makes it wait a bit
#
sleep 10

If you know of a better solution, please share it in the comments below.

And that's it

At this point, your Raspberry Pi should be a running DHCP server and devices on your LAN should be receiving addresses from it.

To test this, go to your favorite device that gets its configuration from DHCP and toggle its network interface on and off. It should receive an IP address from the range you configured and receive the options you configured.

You can then check the server-side of the connection by looking at its list of active leases:

cat /var/lib/dhcp/dhcpd.leases
and look for your device on the list.

Up next

My next article in this series (hopefully later this week) will show how to configure your DHCP server to assign static addresses to devices. After that, there will be an article on how to set up a DNS server on a Raspberry Pi.

References

The following web pages have been extremely helpful in helping me learn how to set up a DHCP server on my Raspberry Pi:

2 comments:

Joaquin Abian said...

Great. I am enjoying it.
Please, insert a link to the next part of this series.

Shamino said...

Thanks for reminding me. I had neglected to include forward links.

I've now added a box at the top of the four articles in the series so you can have quick access to them all.