I am trying to create a firewall rule on an Ubuntu 10.04 server running isc-dhcpd. I only want dhcp to be accessible by a single relay host (172.1.1.1). I have iptables set up like so:
# iptables -vnL
Chain INPUT (policy ACCEPT 5325 packets, 523K bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT udp -- * * 172.1.1.1 0.0.0.0/0 udp dpt:67
1497 533K DROP udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:67
This is my attempt to drop all UDP traffic destined to port 67 unless it's coming from 172.1.1.1.
However, with this rule in place, when I start the dhcpd I immediately see DHCP requests start to come in via broadcast (the log says via eth0).
Do I need another firewall rule to catch the broadcast traffic? I've tried adding a rule like
iptables -A INPUT -p udp -d 255.255.255.255 -j DROP
which should drop all UDP broadcast traffic. But again when I start dhcpd I see tons of requests via broadcast.
EDIT: According to this page:
For most operations, DHCP software interfaces to the Linux IP stack at a level below Netfilter. Hence, Netfilter (and therefore Shorewall) cannot be used effectively to police DHCP.
So is there any way to accomplish what I want here?
Since it appears that netfilter (
iptables
) is not effective for filtering DHCP broadcasts, try usingebtables
, the Linux tool for filtering at a lower level, of ethernet frames. I don't have direct, real world experience withebtables
, but a brief perusal of the man page suggests that something like the following may be effective in your case:This should cause the Linux kernel to drop all ethernet frames that contain IPv4 UDP packets that are not from 172.1.1.1 and are destined for port 67.
It doesn't work on pure IP-level, one needs to know how DHCP does work:
At first, the DHCP client does send a packet (DHCPDISCOVER) from 0.0.0.0 to 255.255.255.255 (the local broadcast address).
The DHCP server will offer an IP address (DHCPOFFER); in terms of iptables, this will be a packet from the DHCP server's address and also targeted at the local broadcast address 255.255.255.255. The ethernet frame is addressed at the MAC address of the DHCP client.
The DHCP client chooses from any offers sent at their ethernet MAC address and sends a DHCPREQUEST to the DHCP server; for iptables, this is yet another packet from 0.0.0.0 and still targeted at local broadcast address 255.255.255.255.
The DHCP server acknowledges the IP address assignment (DHCPACK). The resulting IP packet is from the DHCP server's IP address, the destination IP address is one more time 255.255.255.255, the ethernet frame address will be addressed at the DHCP client's MAC address.
When a DHCP client wants to renew its DHCP lease, it does send another DHCPREQUEST from 0.0.0.0 to 255.255.255.255 and request the current IP address. It'll do this until the DHCP lease has expired, from where it'll start with DHCPDISCOVER again.
So more likely, you're looking for something like this:
iptables -A INPUT -m mac --mac-source xx:xx:xx:xx:xx:xx -p udp --dport 67 -j ACCEPT iptables -A INPUT -p udp --dport 67 -j DROP
This will drop any dhcp requests aimed at your server who don't originate at the listed MAC.
The issue may also be solved at a different level: remove the IP address pool from the DHCP server and do only assign static mappings for your respective MAC addresses. This way, the DHCP server won't answer to anyone listed and will only assign IPs to known hosts.