Cover

DHCP

1. DHCP

1.1. Intro

DHCP (Dynamic Host Configuration Program) is the standard way to give computers an IP address without the need of configuration on the computer. DHCP is capable of much more: assigning gateways, netmask, proxies etcetera, basically all network configuration can be done via DHCP. If you are a lazy network administrator at home, you probably use the DHCP server in your Internet router.

In a data centre, DHCP can be used to give control of the network configuration to the network administrators. Sysadmins only need to use dhclient to get an up-to-date network configuration.

There are some problems with DHCP. For example: you need a network layer 2 connection with the DHCP server.

1.2. Our virtual machines

We'll use Vagrant to start our virtual machines.
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
	config.vm.define :xenial1 do |t|
		t.vm.box = "ubuntu/xenial64"
		# t.vm.box_url = "file:////links/virt_comp/vagrant/boxes/xenial64.box"
		t.vm.provider "virtualbox" do |prov|
			prov.customize ["modifyvm", :id, "--nic2", "hostonly", "--hostonlyadapter2", "vboxnet1" ]
			prov.customize ["modifyvm", :id, "--macaddress2","020000000001" ]
		end
		t.vm.provision "shell", path: "./setup.xenial1.sh"
	end
	config.vm.define :xenial2 do |t|
		t.vm.box = "ubuntu/xenial64"
		# t.vm.box_url = "file:////links/virt_comp/vagrant/boxes/xenial64.box"
		t.vm.provider "virtualbox" do |prov|
			prov.customize ["modifyvm", :id, "--nic2", "hostonly", "--hostonlyadapter2", "vboxnet2" ]
			prov.customize ["modifyvm", :id, "--macaddress2","020000000002" ]
		end
		t.vm.provision "shell", path: "./setup.xenial2.sh"
	end
	config.vm.define :xenial3 do |t|
		t.vm.box = "ubuntu/xenial64"
		# t.vm.box_url = "file:////links/virt_comp/vagrant/boxes/xenial64.box"
		t.vm.provider "virtualbox" do |prov|
			prov.customize ["modifyvm", :id, "--nic2", "hostonly", "--hostonlyadapter2", "vboxnet3" ]
			prov.customize ["modifyvm", :id, "--macaddress2","020000000003" ]
		end
		t.vm.provision "shell", path: "./setup.xenial3.sh"
	end
end

A bit special here is the prov.customize ["modifyvm", :id, "--macaddress2","020000000003" ] which forces a specific MAC-ID on eth1. The reason for this is that it allows me to create a static lease easily.

All setup-scripts contain the following code:
ETH1=$(dmesg | grep -i 'renamed from eth1' | sed -n 's/: renamed from eth1//;s/.* //p')
ifconfig $ETH1 down
ip link set $ETH1 name eth1
ifconfig eth1 up

2. Installing a DHCP server

2.1. Installing the software

We'll use xenial1 as our DHCP server. Installing is default:
apt-get install dhcpd

This makes the setup for xenial1 as follows:
#!/bin/bash
ETH1=$(dmesg | grep -i 'renamed from eth1' | sed -n 's/: renamed from eth1//;s/.* //p')
ifconfig $ETH1 down
ip link set $ETH1 name eth1
ifconfig eth1 10.168.65.101 netmask 255.255.255.0 up
route add -net 10.168.0.0 netmask 255.255.0.0 gw 10.168.65.1
apt-get install dhcpd
cp /vagrant/udhcpd.conf /etc
cp /vagrant/udhcpd.default /etc/default/udhcpd
/etc/init.d/udhcpd restart

2.2. Configuration

The setup-script copies a configuration from our /vagrant directory. The content of udhcpd.conf is:
# Sample udhcpd configuration file (/etc/udhcpd.conf)
# The start and end of the IP lease block
start          10.168.65.200
end            10.168.65.250
interface      eth1
static_lease	02:00:00:00:00:02	10.168.65.55
static_lease	02:00:00:00:00:03	10.168.63.222
option  subnet 255.255.255.0
opt     router 10.168.63.1
option  lease  30

We see the static_lease for the MAC-IDs that we defined in our vagrant file. We also see that the router is defined as 10.168.63.1. We're not really interested in routing here, and because xenial1 is here the center of our universe, we're only interested in getting traffic to xenial1. We do not care that this router information is invalid for xenial2.

The lease time is short, because I do not want to wait long wth wireshark.

2.3. A simple network for DHCP testing

In GNS3, I created the following network. Precise1 is on vboxnet1; xenial2 is on vboxnet2.

testdhcp.png>

The switch is a standard GNS3-switch.

When xenial2 is started, it generates dhcp requests. This is directly visible on the console as a series of Sending OFFER and Sending ACK with the IP address.
# pkill udhcp
# 
# udhcpd -f              
udhcpd (v1.18.5) started
udhcpd: max_leases=235 is too big, setting to 51
Sending OFFER of 10.168.65.55
Sending OFFER of 10.168.65.55
Sending ACK to 10.168.65.55
Sending ACK to 10.168.65.55
Sending ACK to 10.168.65.55
Sending ACK to 10.168.65.55

An ifconfig eth1 on xenial2 will show that the predicted IP address is present on that interface.
$ ifconfig eth1     
eth1      Link encap:Ethernet  HWaddr 08:00:27:9d:73:b6  
          inet addr:10.168.65.55  Bcast:10.168.65.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe9d:73b6/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:74 errors:0 dropped:0 overruns:0 frame:0
          TX packets:28 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:17440 (17.4 KB)  TX bytes:6492 (6.4 KB)

3. DHCP forwarding

It is all very well to have a DHCP server in the same VLAN, but if you have different VLANs or network segments separated by a router, you'll need a forwarder on the router to get your DHCP request at the DHCP server. We'll implement the forwarder on a network further away.

3.1. The basic network set-up


dhcpfwd.jpg>

Between the DHCP server xenial1 and the possible client xenial3 there are now two routers. We'll set them up in static routing; this will avoid routing messages to apear in out wireshark traces.

For R1:
interface Ethernet0/1
 ip address 10.168.65.1 255.255.255.0
 no shut
!
interface Ethernet0/3
 ip address 10.168.64.1 255.255.255.0
 no shut
!
ip route 0.0.0.0 0.0.0.0 10.168.64.2

and for R2:
interface Ethernet0/0
 ip address 10.168.63.1 255.255.255.0
 no shut
!
interface Ethernet0/3
 ip address 10.168.64.2 255.255.255.0
 no shut
!
ip route 0.0.0.0 0.0.0.0 10.168.64.1

Now you should be able to ping xenial1 (10.168.65.101) from R2.

3.2. Normal DHCP

If you are in the same L2-network, you can do a DHCP request. Precise2 is in the same L2 network.
vagrant@xenial64:~$ ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 02:00:00:00:00:02  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
vagrant@xenial64:~$ sudo dhclient eth1
vagrant@xenial64:~$ ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 02:00:00:00:00:02  
          inet addr:10.168.65.5  Bcast:10.168.65.255  Mask:255.255.255.0
          inet6 addr: fe80::ff:fe00:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:9 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:1040 (1.0 KB)  TX bytes:1012 (1.0 KB)
vagrant@xenial64:~$ ping -c1 10.168.65.1
PING 10.168.65.1 (10.168.65.55) 56(84) bytes of data.
64 bytes from 10.168.65.55: icmp_req=1 ttl=64 time=0.029 ms
--- 10.168.65.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.029/0.029/0.029/0.000 ms
vagrant@xenial64:~$ 

3.3. DHCP forwarding

If you now try a dhclient eth1 on xenial3, you'll get no reply. This is because the broadcast that xenial3 does gets stopped at the router. DHCP Discovers are not routed; they can't be. The destination is 255.255.255.255 and the source is 0.0.0.0. We'll need some translation to convert this broadcast to a unicast.

On Cisco, there is an IP helper. This relays broadcasts to a helper address. This is protocol independent, so it works for all sorts of broadcasts, and therefore with DHCP.

Configure the router to relay the DHCP requests. This is done on the interface so for R2 in this configuration:
interface e0/0
 ip helper-address 10.168.65.101

Finally, we start a dhclient eth1 on prcecise3. Verifying with ifconfig we see that eth1 now has the IP address 10.168.65.222, just as we expected.

To see what the helper does, we start a wireshark trace on the link between R1 and R2. First the discover:

relaydiscover.png>

We see an UDP packet with the source 10.168.65.1 (the router interface that has the relay on it) and the destination 10.168.65.101 (the DHCP server). This is effectively a unicast version of the original broadcast. In the information of the Bootstrap Protocol, we see that the client IP is still 0.0.0.0 and we see the mac-id.

As a reply, we see the DHCP offer:

relayoffer.png>

Now the source is the DHCP server and the destination is the interface that does the relay. The relay agent will send the answer to the DHCP client.
1
sept 2016
creation
2
verified
2018-04-29
3
upgraded to xenial
2020-02-04