On my other thread I was talking about some interesting things about the iptables policy and states, now I would like to understand more about how the DHCP works and how iptables understands it.
ETH0 is connected to my main switch that receives the dynamic ip from my router to gain not only internet access but aswell as access to my outer network.
ETH1 is the internal card that is connected to a internal switch where X clients receive their IPS from this server
ETH1 network is 192.168.1.0/255.255.255.0 where the server ip is 192.168.1.254.
From what I understood, dhcp is a bootp protocol so even if you have your firewall policies to DROP everything, your network would still receive the DHCP, which in the tests I made it seemed to be true.
From tcpdump:
root@test:~# tcpdump -i eth1 port 67 or 68
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 96 bytes
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 (oui Unknown), length 303
11:34:03.957647 IP 192.168.1.254.bootps > 192.168.1.2.bootpc: BOOTP/DHCP, Reply, length 300
11:34:06.492153 IP 192.168.1.2.bootpc > 192.168.1.254.bootps: BOOTP/DHCP, Request from 00:0c:29:29:52:8b (oui Unknown), length 303
11:34:06.506593 IP 192.168.1.254.bootps > 192.168.1.2.bootpc: BOOTP/DHCP, Reply, length 300
I made a simple log rule to see what iptables does:
root@test:~# tail -f /var/log/syslog
Oct 15 11:30:58 test kernel: IN=eth1 OUT= MAC=ff:ff:ff:ff:ff:ff:00:0c:29:29:52:8b:08:00 SRC=192.168.1.2 DST=255.255.255.255 LEN=331 TOS=0x00 PREC=0x00 TTL=128 ID=9527 PROTO=UDP SPT=68 DPT=67 LEN=311
Oct 15 11:31:43 test kernel: IN=eth1 OUT= MAC=ff:ff:ff:ff:ff:ff:00:0c:29:29:52:8b:08:00 SRC=192.168.1.2 DST=255.255.255.255 LEN=331 TOS=0x00 PREC=0x00 TTL=128 ID=9529 PROTO=UDP SPT=68 DPT=67 LEN=311
Oct 15 11:33:32 test kernel: IN=eth1 OUT= MAC=ff:ff:ff:ff:ff:ff:00:0c:29:29:52:8b:08:00 SRC=192.168.1.2 DST=255.255.255.255 LEN=331 TOS=0x00 PREC=0x00 TTL=128 ID=9531 PROTO=UDP SPT=68 DPT=67 LEN=311
Oct 15 11:34:03 test kernel: IN=eth1 OUT= MAC=ff:ff:ff:ff:ff:ff:00:0c:29:29:52:8b:08:00 SRC=192.168.1.2 DST=255.255.255.255 LEN=331 TOS=0x00 PREC=0x00 TTL=128 ID=9533 PROTO=UDP SPT=68 DPT=67 LEN=311
Here is my iptables rules at the momment:
# deny all traffic
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT DROP
# Use stateful inspection feature to only allow incoming connections
# related to connections I have already established myself
$IPT -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# allow all traffic on lo interface
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
So even with the default POLICY to drop everything i still get the DHCP on my network while it does take a lot longer to renew an IP and such.
If I add the follow rule to my firewall:
$IPT -I OUTPUT -o $INTIF -p udp --dport 67:68 --sport 67:68 -j ACCEPT
It will take a LOT LESS TIME to update any client dhcp.
Considering the above:
- why does it indeed take longer time to update it even tought it is not being blocked ?
- is it possible to DROP the dhcp server at all without turning it off ?
- is it possible to ACCEPT the dhcp server within iptables with the BOOTP ? how is that done ?
If you know good links I wouldn't mind taking a lot :)
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.
Adding
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
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:
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:
the renewals seem to work forever.
You may find the following tcpdump cmdline args useful:
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.