IPTables and DHCP questions?

Solution 1:

I'll answer #2: No.

When getting an IP address the dhcp daemon creates a raw socket to the network interface and handles the UDP protocol itself. Thus the UDP packets never go through iptables.

The reason the dhcp daemon has to implement UDP is that the kernel can only handle UDP (in fact all of the TCP/IP suite) when the interface has an IP address. Previously dhcp daemons would first give an interface the IP address of 0.0.0.0 but that no longer works.

Solution 2:

Adding

$IPT -I INPUT -i $INTIF -p udp --dport 67:68 --sport 67:68 -j ACCEPT

shall make DHCPD update faster :) It shall works both side INPUT and OUTPUT. You can DROP dhcpd with ebtables, not with iptables. DHCPD listening at 0.0.0.0, not within IP

Solution 3:

My recent observation, on OpenWRT Kamikaze 7.09 = 2.4.34 and udhcpc from busybox 1.4.2 :

I have an "ACCEPT" policy in the OUTPUT chain, and in the INPUT direction, originally I relied on this classic catch-all rule:

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

to allow the DHCP responses in (to my udhcpc) on the WAN interface. I.e., this is where my ISP's upstream DHCP server assigns an IP Address to me.

Mind the difference between an initial DHCP exchange (discover, offer, request, ack) and a DHCP lease renewal (request, ack).

After boot, udhcpc starts by the full initial exchange. That exchange would succeed. And another renewal or two would succeed too - just a request and acknowledgement. My ISP's DHCP server typically asks for a renewal time of about an hour to 1.5 hours, thus my DHCP client asks for a renewal every 30 to 45 minutes (this behavior is based on the RFC).

But, on about the third or fourth renewal, it would start to get interesting. TCPdump would show about three or so renewal attempts, followed by a full initial exchange - that within a timespan of just a few minutes or even seconds. As if udhcpc didn't like what it got back :-( and would ultimately get satisfied with the full exchange. After that, another renewal in half an hour would succeed... and the story would repeat again.

I figured out, that it's perhaps the connection tracking in the kernel that's got something wrong. As if the conntrack entry expires after two hours or so, and the later DHCP renewals fail because the ACK from the server doesn't actually make it to udhcpc listening on the socket. Note that tcpdump (libpcap) listens on the raw interface and can see all packets coming in, before they're subject to iptables. Once udhcpc gives up renewals and, in despair, tries to start over from scratch using a full exchange (starting with DISCOVER), the kernel establishes a new conntrack entry and can understand related packets for some more time...

Sure enough, once I added something like:

iptables -A INPUT -i $OUT_IF -p udp --sport 67 --dport 68 -j ACCEPT

the renewals seem to work forever.

You may find the following tcpdump cmdline args useful:

tcpdump -vv -s 1500 -i eth0.1 port 67 or port 68

Note: the -vv asks for the verbose dissector output. eth0.1 is my WAN port (also a "NAT outside" interface).

An interesting attribute in the ACK packets is the LT: field = suggested / maximum granted lease time in seconds. DHCP requests are sent from port 68 to port 67. Responses come from port 67 to port 68.