When working with DHCP servers behind IPTables firewalls, we observe an interesting phenomenon: DHCP traffic appears to bypass default DROP policies. Let's examine why this occurs and how to properly manage it.
From your tcpdump output, we see the standard DHCP conversation:
11:34:03.943928 IP 192.168.1.2.bootpc > 255.255.255.255.bootps: BOOTP/DHCP request
11:34:03.957647 IP 192.168.1.254.bootps > 192.168.1.2.bootpc: BOOTP/DHCP reply
Key observations from your syslog:
IN=eth1 OUT= MAC=ff:ff:ff:ff:ff:ff SRC=192.168.1.2 DST=255.255.255.255
PROTO=UDP SPT=68 DPT=67 LEN=311
DHCP operates at layer 2 (Ethernet) before IPTables processes layer 3 rules. However, the delay occurs because:
- The initial broadcast packet gets through (layer 2)
- Subsequent unicast responses are subject to IPTables processing
- Without explicit rules, these must timeout before falling back to broadcast
For proper DHCP functionality, these rules are recommended:
# Allow DHCP client requests (outgoing)
$IPT -A OUTPUT -o $INTIF -p udp --dport 67 --sport 68 -j ACCEPT
# Allow DHCP server responses (incoming)
$IPT -A INPUT -i $INTIF -p udp --dport 68 --sport 67 -j ACCEPT
# Allow broadcast traffic for initial discovery
$IPT -A INPUT -i $INTIF -d 255.255.255.255 -p udp --dport 67 -j ACCEPT
To prevent DHCP serving while keeping the daemon running:
# Drop all DHCP offers from server
$IPT -A OUTPUT -o $INTIF -p udp --sport 67 -j DROP
# Alternative: Rate limiting DHCP responses
$IPT -A OUTPUT -o $INTIF -p udp --sport 67 -m limit --limit 1/min -j ACCEPT
$IPT -A OUTPUT -o $INTIF -p udp --sport 67 -j DROP
The delay you observe comes from:
- Retransmission timeouts when unicast packets are blocked
- Fallback to broadcast mechanism
- Default kernel timers for DHCP (typically 1-4 seconds per attempt)
For stateful DHCP handling (requires kernel support):
$IPT -A INPUT -i $INTIF -p udp -m conntrack --ctstate DNAT --dport 68 -j ACCEPT
$IPT -A OUTPUT -o $INTIF -p udp -m conntrack --ctstate SNAT --sport 67 -j ACCEPT
For further reading:
- RFC 2131 (DHCP protocol specification)
- Linux netfilter documentation (conntrack modules)
- dhcpd.conf man pages for server configuration
When examining the packet flow through tcpdump (tcpdump -i eth1 port 67 or 68
), we observe DHCP traffic successfully traversing the network even with strict DROP policies. This occurs because DHCP operates at layer 2 (broadcast) and some network stacks handle these packets before IPTables rules are evaluated.
# Sample unexpected DHCP traffic capture
11:34:03.943928 IP 192.168.1.2.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 00:0c:29:29:52:8b
11:34:03.957647 IP 192.168.1.254.bootps > 192.168.1.2.bootpc: BOOTP/DHCP, Reply, length 300
The delay in DHCP renewal occurs because:
- Broadcast packets trigger conntrack evaluation
- UDP has no connection state, making stateful inspection inefficient
- Default Linux kernel behavior retries DHCP before timing out
Adding explicit rules dramatically improves performance:
# Optimal DHCP firewall rules
$IPT -A INPUT -i $INTIF -p udp --dport 67:68 -j ACCEPT
$IPT -A OUTPUT -o $INTIF -p udp --sport 67:68 -j ACCEPT
For a proper DHCP-enabled firewall, consider this enhanced ruleset:
#!/bin/sh
INTIF="eth1"
EXTIF="eth0"
# Base policies
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT DROP
# Local interface and established connections
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
$IPT -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# DHCP specific rules
$IPT -A INPUT -i $INTIF -p udp --dport 67 -j ACCEPT # DHCP requests
$IPT -A OUTPUT -o $INTIF -p udp --sport 67 -j ACCEPT # DHCP server responses
$IPT -A INPUT -i $INTIF -p udp --dport 68 -j ACCEPT # DHCP client requests
$IPT -A OUTPUT -o $INTIF -p udp --sport 68 -j ACCEPT # DHCP client responses
# Broadcast handling (critical for DHCP)
$IPT -A INPUT -i $INTIF -d 255.255.255.255 -p udp --dport 68 -j ACCEPT
$IPT -A OUTPUT -o $INTIF -d 255.255.255.255 -p udp --dport 67 -j ACCEPT
To completely block DHCP while keeping the service running, you can use these methods:
# Method 1: Block by MAC address of DHCP server
$IPT -A INPUT -i $INTIF -p udp --dport 67 -m mac --mac-source 00:0c:29:29:52:8b -j DROP
# Method 2: Rate limiting DHCP responses
$IPT -A OUTPUT -o $INTIF -p udp --sport 67 -m limit --limit 1/sec -j ACCEPT
$IPT -A OUTPUT -o $INTIF -p udp --sport 67 -j DROP
# Method 3: Interface-specific blocking
$IPT -A INPUT -i $INTIF -p udp --dport 67 -j DROP
For environments requiring maximum DHCP performance, consider these sysctl tweaks:
# Increase DHCP packet buffer
echo "net.core.rmem_max=1048576" >> /etc/sysctl.conf
echo "net.core.wmem_max=1048576" >> /etc/sysctl.conf
# Optimize conntrack for UDP
echo "net.netfilter.nf_conntrack_udp_timeout=30" >> /etc/sysctl.conf
echo "net.netfilter.nf_conntrack_udp_timeout_stream=60" >> /etc/sysctl.conf
# Apply changes
sysctl -p
Use these commands to monitor DHCP traffic flow:
# Log all DHCP traffic
$IPT -A INPUT -p udp --dport 67 -j LOG --log-prefix "[DHCP-IN] "
$IPT -A OUTPUT -p udp --sport 67 -j LOG --log-prefix "[DHCP-OUT] "
# View logged packets
tail -f /var/log/syslog | grep DHCP