While tightening up and securing the firewall rules in my network with UFW, I ran into a problem that completely broke DHCP. My goal was simple: to allow DHCP requests from devices in my LAN. So I added the following rule:

On paper, it looked right. DHCP traffic should only be coming from devices in that subnet, but as soon as I applied it, clients stopped getting IP addresses and I only realised this a day later after some devices rebooted or tried to renew their IP addresses. Static IPs worked fine, but DHCP wasn’t working.
DHCP Protocol — Where I got it wrong
DCHP is unique in that it uses broadcast IP addresses to communicate. When clients join a new network, they send a message requesting an IP address to 255.255.255.255
. This is the equivalent of entering a room and shouting to get everyone’s attention. Since I had created a rule to only allow DHCP traffic on a specific subnet that isn’t 255.255.255.255, the rule didn’t match, and UFW silently dropped it and didn’t allow the messages to reach the DHCP server. In other words, my rule was too restrictive, and DHCP couldn’t allocate IP addresses to network devices.
The fix
When I saw the problem on one of the devices in my network, I first thought the network cable was damaged, so I swapped the cable with one from another device that worked, but the problem didn’t go away, so I knew it had to be something else. I checked the network settings and noticed that the device didn’t have an IP address, which meant there was something wrong with DHCP. I logged into the DHCP server, ran a few troubleshooting commands and realised that the problem wasn’t on the server itself, so it had to be clients failing to reach the server.
Whenever I encounter a problem in code or in my network, the first question I ask myself is, “What changed recently?”. I remembered modifying the firewall rules the day before, and when I looked at them it hit me, I had configured the firewall to only allow DHCP traffic on the subnet and not on the broadcast address.
To fix it, I simply deleted the rule and added another without the subnet:

This accepts DHCP traffic from any address. The rule feels like a security hole, which is why I changed it in the first place, but it isn’t because of the way DHCP works. To get IP addresses via DHCP, devices have to already be in the same network; devices outside the network can’t send DHCP requests to the server, so I’m only opening up traffic that’s already on the network. If a malicious person is already there, then I have bigger problems.
Conclusion
The lesson for me here is to spend more time thinking about the underlying protocols I want to implement firewall rules for before applying the firewall rules.