在我的另一个帖子中我讨论了一些有趣的事情关于 iptables 策略和状态,现在我想进一步了解DHCP的工作原理以及iptables如何理解它。
ETH0 连接到我的主交换机,它从我的路由器接收动态 IP,不仅可以访问互联网,还可以访问我的外部网络。
ETH1 是连接到内部交换机的内部卡,X 客户端从该服务器接收其 IPS
ETH1 网络是 192.168.1.0/255.255.255.0,其中服务器 ip 是 192.168.1.254。
据我所知,dhcp 是一种 bootp 协议,因此即使你的防火墙策略是 DROP 所有内容,你的网络仍然会接收 DHCP,这在我所做的测试中似乎是正确的。
来自 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
我制定了一个简单的日志规则来查看 iptables 做了什么:
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
这是我目前的 iptables 规则:
# 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
因此,即使采用默认策略来放弃所有内容,我的网络仍然可以获得 DHCP,而更新 IP 等则需要更长的时间。
如果我将以下规则添加到我的防火墙:
$IPT -I OUTPUT -o $INTIF -p udp --dport 67:68 --sport 67:68 -j ACCEPT
更新任何客户端 dhcp 都将花费少得多的时间。
考虑到以上情况:
- 为什么即使它没有被阻止,更新也需要更长的时间?
- 是否有可能在不关闭 dhcp 服务器的情况下完全删除它?
- 是否可以使用 BOOTP 在 iptables 中接受 dhcp 服务器?如何做到?
如果你知道好的链接我不会介意多拿一些:)
答案1
我的回答是第二个问题:不。
获取 IP 地址时,dhcp 守护进程会创建网络接口的原始套接字并自行处理 UDP 协议。因此 UDP 数据包永远不会经过 iptables。
dhcp 守护进程必须实现 UDP 的原因是,当接口具有 IP 地址时,内核只能处理 UDP(实际上是所有 TCP/IP 套件)。以前,dhcp 守护进程会首先为接口提供 IP 地址 0.0.0.0,但现在不再适用。
答案2
添加
$IPT -I INPUT -i $INTIF -p udp --dport 67:68 --sport 67:68 -j ACCEPT
应使 DHCPD 更新更快 :) 它应同时在输入和输出端工作。您可以使用 ebtables 而不是 iptables 删除 dhcpd。DHCPD 在 0.0.0.0 处监听,而不是在 IP 范围内
答案3
我最近对 OpenWRT Kamikaze 7.09 = 2.4.34 和 busybox 1.4.2 的 udhcpc 进行了观察:
我在 OUTPUT 链中有一个“接受”策略,而在 INPUT 方向,最初我依赖于这个经典的包罗万象的规则:
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
允许 WAN 接口上的 DHCP 响应(到我的 udhcpc)。即,这是我的 ISP 的上游 DHCP 服务器为我分配 IP 地址的地方。
注意初始 DHCP 交换(发现、提供、请求、确认)和 DHCP 租约续订(请求、确认)之间的区别。
启动后,udhcpc 会通过完整的初始交换启动。该交换会成功。另外一两次更新也会成功 - 只需请求和确认。我的 ISP 的 DHCP 服务器通常要求更新时间约为 1 小时到 1.5 小时,因此我的 DHCP 客户端每 30 到 45 分钟请求一次更新(此行为基于 RFC)。
但是,在第三次或第四次续订时,事情开始变得有趣起来。TCPdump 将显示大约三次续订尝试,然后是完整的初始交换 - 时间跨度只有几分钟甚至几秒钟。好像 udhcpc 不喜欢它得到的回复 :-( 并最终对完整交换感到满意。之后,半小时后的另一次续订将成功... 故事将再次重演。
我发现,可能是内核中的连接跟踪出了问题。好像 conntrack 条目在大约两小时后过期,并且后续的 DHCP 更新会失败,因为来自服务器的 ACK 实际上并没有到达监听套接字的 udhcpc。请注意,tcpdump (libpcap) 监听原始接口,并且可以看到所有进入的数据包,然后才会受到 iptables 的影响。一旦 udhcpc 放弃更新,并绝望地尝试使用完整交换(从 DISCOVER 开始)从头开始,内核就会建立一个新的 conntrack 条目,并且可以在一段时间内理解相关数据包……
果然,我添加了类似这样的内容:
iptables -A INPUT -i $OUT_IF -p udp --sport 67 --dport 68 -j ACCEPT
这种更新似乎永远有效。
您可能会发现以下 tcpdump cmdline 参数很有用:
tcpdump -vv -s 1500 -i eth0.1 port 67 or port 68
注意:-vv
要求详细的解剖器输出。eth0.1
是我的 WAN 端口(也是“NAT 外部”接口)。
ACK 数据包中一个有趣的属性是 LT:字段 = 建议/最大授予租约时间(以秒为单位)。DHCP 请求从端口 68 发送到端口 67。响应从端口 67 发送到端口 68。