Deep Dive: DHCP and IPTables Interaction – Analyzing Packet Flow and Firewall Rules for BOOTP Protocol


2 views

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:

  1. The initial broadcast packet gets through (layer 2)
  2. Subsequent unicast responses are subject to IPTables processing
  3. 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