What a host needs before it can talk
A laptop that has just joined a network needs several things:
| It needs | It gets it from |
|---|---|
| An IP address, a subnet mask, a default gateway and a DNS server | DHCP (automatically from a server) |
| The MAC address of the next device on the link | ARP (by asking the LAN) |
IP addresses are logical and can change. MAC addresses are physical and identify a network card on one link. A frame is delivered by MAC address, a packet is routed by IP address, so every host needs a way to map one to the other. See subnetting for how the mask divides addresses.
DHCP: getting an address (DORA)
Run DHCP get an address in the 3D model. Host A is plugged in with no address:
| # | Message | Direction | What it says |
|---|---|---|---|
| 1 | Discover | broadcast, A → everybody | “Is there a DHCP server?” Source IP 0.0.0.0, destination 255.255.255.255, UDP port 68 → 67. |
| 2 | Offer | server → A | “You can have 192.168.1.100, mask /24, gateway .1, DNS 8.8.8.8, lease 8 hours.” Addressed to A’s MAC. |
| 3 | Request | broadcast, A → everybody | “I accept 192.168.1.100 from server 192.168.1.1.” |
| 4 | Acknowledge | server → A | “Confirmed. It is yours for 8 hours.” |
Why is the Request a broadcast when A already knows the server? Several servers may have sent offers. By broadcasting, A tells all of them whose offer it took, and the others return their addresses to the pool. DHCP runs over UDP: the server listens on port 67, the client on port 68.
Leases
An address is only leased. At 50% of the lease time (T1) the client asks the same server to renew. If that fails, at 87.5% (T2) it asks any server. When the lease expires, the client must stop using the address and begin again with a Discover.
Good to know
- A DHCP relay agent on the router lets one DHCP server serve many subnets, by forwarding the broadcasts of each subnet as unicasts to the server.
- A client that finds no server gives itself a link-local address in 169.254.0.0/16 (APIPA), which only works on the local link.
- The server can assign the same address every time to a given MAC (a reservation), which is how you get a stable IP without configuring the host.
ARP: finding the MAC address
Suppose A (192.168.1.100) wants to send a packet to B (192.168.1.20). First A checks its subnet mask to decide where B is:
192.168.1.100 AND 255.255.255.0 = 192.168.1.0
192.168.1.20 AND 255.255.255.0 = 192.168.1.0 same network → send it directly to B
8.8.8.8 AND 255.255.255.0 = 8.8.8.0 different network → send it to the gateway
Then A needs the MAC address of the next hop (B, or the gateway). It looks in its ARP cache. If the entry is missing:
- A broadcasts an ARP request: “Who has 192.168.1.20? Tell 192.168.1.100”. The destination MAC is FF:FF:FF:FF:FF:FF, so the switch floods it to every port.
- Every host examines the target IP. Everybody except B ignores it.
- B sends an ARP reply straight back to A (unicast): “192.168.1.20 is at BB:22.”
- A stores the pair in its ARP cache (entries expire after a few minutes) and sends the frame to BB:22. Later packets skip steps 1 to 3.
ARP is not carried inside IP: it sits directly on Ethernet. It works only inside one LAN; a router never forwards an ARP broadcast.
The IP address stays, the MAC address changes
Press ARP via gateway. A wants to reach 8.8.8.8. It cannot reach it directly, so it does ARP for the router, 192.168.1.1, and gets EE:01. The frame is:
| Field | Value |
|---|---|
| Destination MAC | EE:01 (the router) |
| Destination IP | 8.8.8.8 (the final destination) |
At each router the frame is taken apart, the destination IP is looked up in the routing table, and a new frame with new MAC addresses is built for the next link. IP addresses stay the same end to end; MAC addresses change at every hop.
Other things ARP does
- Gratuitous ARP: a host announces its own IP → MAC mapping (after a change, or to check whether another host already uses its address).
- Proxy ARP: a router answers for hosts behind it.
- ARP spoofing: ARP has no authentication, so an attacker can send false replies and redirect traffic to itself. Defences include static entries and dynamic ARP inspection on switches.
- IPv6 has no ARP; it uses Neighbor Discovery (NDP).
Code
import ipaddress
# ---------------- DHCP ----------------
class DhcpServer:
def __init__(self, network, first, last, gateway, dns, lease=8 * 3600):
self.net = ipaddress.ip_network(network)
self.pool = [ipaddress.ip_address(first) + i
for i in range(int(ipaddress.ip_address(last)) - int(ipaddress.ip_address(first)) + 1)]
self.gateway, self.dns, self.lease = gateway, dns, lease
self.leases = {} # MAC -> IP
def discover(self, mac):
"""DHCPDISCOVER arrives: offer the client's old address, else the first free one."""
taken = set(self.leases.values())
ip = self.leases.get(mac) or next(p for p in self.pool if p not in taken)
return {'type': 'OFFER', 'ip': str(ip), 'mask': str(self.net.netmask), 'gateway': self.gateway,
'dns': self.dns, 'lease': self.lease}
def request(self, mac, ip):
"""DHCPREQUEST arrives: if the address is still free (or ours), bind it and acknowledge."""
owner = [m for m, a in self.leases.items() if str(a) == ip]
if owner and owner[0] != mac:
return {'type': 'NAK'}
self.leases[mac] = ipaddress.ip_address(ip)
return {'type': 'ACK', 'ip': ip, 'lease': self.lease}
server = DhcpServer('192.168.1.0/24', '192.168.1.100', '192.168.1.200', '192.168.1.1', '8.8.8.8')
offer = server.discover('AA:11')
print(offer)
# {'type': 'OFFER', 'ip': '192.168.1.100', 'mask': '255.255.255.0', 'gateway': '192.168.1.1', 'dns': '8.8.8.8', 'lease': 28800}
print(server.request('AA:11', offer['ip']))
# {'type': 'ACK', 'ip': '192.168.1.100', 'lease': 28800}
print(server.discover('BB:22')['ip']) # the next client gets the next address
# 192.168.1.101
# ---------------- ARP ----------------
class Host:
def __init__(self, ip, mac, mask='255.255.255.0', gateway='192.168.1.1'):
self.ip, self.mac, self.mask, self.gateway = ip, mac, mask, gateway
self.arp_cache = {} # IP -> MAC
def next_hop(host, dst_ip):
"""Same subnet: deliver directly. Otherwise: hand the packet to the default gateway."""
net = ipaddress.ip_network(f'{host.ip}/{host.mask}', strict=False)
return dst_ip if ipaddress.ip_address(dst_ip) in net else host.gateway
def resolve(host, lan, dst_ip, log):
"""Return the destination MAC for the next hop, sending an ARP request if it is not cached."""
hop = next_hop(host, dst_ip)
if hop not in host.arp_cache:
log.append(f'ARP request (broadcast): who has {hop}? tell {host.ip}')
for other in lan: # the broadcast reaches everybody
if other.ip == hop: # only the owner answers
log.append(f'ARP reply (unicast to {host.mac}): {hop} is at {other.mac}')
host.arp_cache[hop] = other.mac
return host.arp_cache[hop]
a = Host('192.168.1.100', 'AA:11')
b = Host('192.168.1.20', 'BB:22')
r = Host('192.168.1.1', 'EE:01')
lan = [a, b, r]
log = []
print(resolve(a, lan, '192.168.1.20', log)) # same subnet: ask for B itself
# BB:22
print(resolve(a, lan, '8.8.8.8', log)) # other network: ask for the gateway
# EE:01
print(resolve(a, lan, '192.168.1.20', log)) # cached: no new ARP request
# BB:22
print(*log, sep='\n')
# ARP request (broadcast): who has 192.168.1.20? tell 192.168.1.100
# ARP reply (unicast to AA:11): 192.168.1.20 is at BB:22
# ARP request (broadcast): who has 192.168.1.1? tell 192.168.1.100
# ARP reply (unicast to AA:11): 192.168.1.1 is at EE:01
print(a.arp_cache)
# {'192.168.1.20': 'BB:22', '192.168.1.1': 'EE:01'}
Common mistakes
- Saying ARP finds the MAC address of the final destination. It finds the MAC of the next hop, which is the gateway for remote destinations.
- Thinking the ARP reply is a broadcast. The request is broadcast; the reply is unicast to the asker.
- Believing ARP crosses routers. It stays inside one broadcast domain (one subnet / VLAN).
- Forgetting that DHCP Discover and Request are broadcasts, while Offer and Ack go to the client. (In some implementations the Offer and Ack are also broadcast; the model shows the usual unicast version.)
- Mixing up DHCP ports. The server uses UDP 67 and the client uses UDP 68.
- Confusing ARP with DNS. DNS maps a name to an IP address; ARP maps an IP address to a MAC address.
Complexity at a glance
| Case / operation | Time | Why |
|---|---|---|
| DHCP exchange | 4 messages (DORA) | Discover and Request are broadcasts; Offer and Ack go back to the client. |
| ARP resolution | 1 broadcast + 1 unicast | Only for the first packet to a neighbour; later packets use the cache. |
| Lease renewal | at 50% of the lease (T1) | Then at 87.5% (T2) to any server, and at 100% the address must be given up. |
| Extra space | One lease per client (server); one IP → MAC entry per neighbour (client) |
Quick check
Test yourself — pick an answer to see if you got it.
1. What do the letters in DORA stand for?
The client discovers a server, the server offers an address, the client requests it and the server acknowledges it.
2. Why does a client broadcast its DHCPDISCOVER?
The client has no address of its own and does not know the server's address, so it uses 0.0.0.0 as the source and 255.255.255.255 (broadcast) as the destination.
3. What does ARP find out?
ARP maps an IP address to a MAC address, so that a frame can be delivered on the local link. Domain names are resolved by DNS.
4. Host A (192.168.1.100/24) sends a packet to 8.8.8.8. Which MAC address is in the destination field of the Ethernet frame?
8.8.8.8 is outside the subnet, so A sends the frame to the router. The IP destination stays 8.8.8.8, the MAC destination is the router's.
5. Who answers an ARP request, and how?
The request is a broadcast so that it reaches everybody, but only the owner of the target IP replies, and it replies directly to the asking host.