简介
iptables 是用于管理 Linux 数据包过滤规则的命令行工具。尽管许多现代发行版通过 nftables 后端实现这些规则,但管理员在实际工作中仍会遇到使用 iptables 命令语法的任务和现有系统。
对于初学者来说,可以把防火墙想象成一份按顺序执行的检查清单。数据包进入一条链后,每条规则都会检查数据包是否符合某些条件,例如网络接口、协议或端口;随后,ACCEPT 或 REJECT 这样的目标会决定数据包的处理方式。INPUT 链负责处理发往本地主机的数据包。由于规则会从上到下依次评估,因此规则内容和所在位置都非常重要。
在本实验中,你将操作一个本地 Web 服务,只针对其 TCP 端口进行范围严格限定的修改。你会先检查当前防火墙,添加一条拒绝请求的规则,通过真实流量验证其效果,再将该规则替换为明确的允许规则,最后移除本实验创建的规则,而不会清空或改写其他无关的防火墙状态。
检查防火墙和测试服务
在本步骤中,你将确认已安装的 iptables 实现,并在修改任何防火墙规则前验证本地测试服务正常运行。
先进入项目目录,确保后续命令都从课程工作区开始执行。
cd /home/labex/project
使用 command -v 查找 Shell 实际会执行的程序文件。
command -v iptables
相比直接假设命令已经安装,这种检查方式更可靠:它会显示解析后的可执行文件路径,通常是 /usr/sbin/iptables;如果 Shell 找不到该命令,则会返回非零状态。
显示版本和后端信息。在此 Ubuntu 主机上,输出通常会包含 nf_tables;这表示熟悉的 iptables 语法会被转换为现代内核规则集后端所使用的形式。
sudo iptables --version
你应该会看到类似以下内容的输出:
iptables v1.8... (nf_tables)
后端名称不会改变本实验中的命令。你仍然可以使用 iptables 创建和检查规则,具体的实现会负责处理这些规则在内核中的表示方式。
在过滤该端口之前,先请求服务的健康检查端点。请求成功说明应用已经准备就绪,后续请求失败时即可判断问题来自防火墙规则。
curl --noproxy '*' --fail --silent http://127.0.0.1:18086/health
这里,127.0.0.1 是 IPv4 回环地址,因此流量会通过本地 lo 接口发出并返回,不会访问外部网络。--noproxy '*' 可防止代理设置重定向请求,--fail 会让 HTTP 错误产生失败状态,而 --silent 会隐藏进度条,便于直接查看服务响应。
服务会返回:
iptables filter service ready
检查 INPUT 链并添加拒绝规则
在本步骤中,你将查看当前的 INPUT 链,并插入一条精确规则,拒绝发往测试端口的回环 TCP 流量。
-S 选项会以类似命令的形式输出规则。指定 INPUT 后,输出范围会限制为发往本主机的数据包。
sudo iptables -S INPUT
第一行通常会显示链策略,例如 -P INPUT ACCEPT。只有在之前的规则都没有作出最终决定时,链策略才会作为备用处理方式。后续以 -A INPUT 开头的行,就是当前追加到该链中的规则。
如果需要更适合运维查看的结果,可以使用 -L 列出链,使用 -n 避免缓慢的名称解析,并使用 --line-numbers 显示每条规则的位置。规则顺序很重要,因为第一个匹配到的终止目标会决定数据包的处理结果。
sudo iptables -L INPUT -n --line-numbers
这两种查看方式用途不同:需要复用规则语法时,-S 更方便;需要查看规则位置、数据包计数器和快速了解当前状态时,-L 更实用。
使用 -I INPUT 1 将本实验规则插入到第 1 位。该规则匹配回环接口 lo、TCP 协议以及目标端口 18086。带有 tcp-reset 参数的 REJECT 目标会立即拒绝连接,而不是让客户端等待被丢弃的数据包超时。
sudo iptables -I INPUT 1 -i lo -p tcp --dport 18086 -j REJECT --reject-with tcp-reset
从左到右理解这条命令:-i lo 限定传入接口,-p tcp 选择协议,--dport 18086 指定服务端口,-j REJECT 跳转到拒绝目标。-I 会将规则插入指定位置;相比之下,-A 会把规则追加到末尾,此时前面可能已有匹配规则,导致新规则永远无法执行。这种严格限定的匹配条件不会影响其他端口或外部接口。
REJECT 和 DROP 并不相同。REJECT 会发送错误响应,而 DROP 会静默丢弃数据包。TCP 重置可以让本地测试快速、明确地失败,比等待超时更容易诊断。
使用 -C 检查该精确规则是否存在。检查成功时会返回状态码 0。在此主机上,由 nftables 支持的实现还会输出规范化后的匹配规则;其他实现可能不会输出任何内容,而是直接完成检查。
sudo iptables -C INPUT -i lo -p tcp --dport 18086 -j REJECT --reject-with tcp-reset
-C 的可移植判断依据是命令退出状态,而不是屏幕上是否显示文本。因此,同一条命令也适合用于 Shell 脚本和自动化验证。
再次列出该链。新规则应该显示为第 1 条,并包含 tcp dpt:18086。
sudo iptables -L INPUT -n --line-numbers
验证流量已被阻断
在本步骤中,你将重新执行原来的请求,并检查规则计数器,从而证明是防火墙拒绝了流量,而不是应用本身出现了问题。
将请求放入 if 语句中执行。由于请求预期会失败,else 分支会把这一预期失败转换为清晰的提示,同时让引导流程继续进行。
if curl --noproxy '*' --fail --silent http://127.0.0.1:18086/health; then
echo "Unexpected: request succeeded"
else
echo "Expected: iptables rejected the request"
fi
Shell 条件语句会根据命令的退出状态作出判断:状态为 0 时执行 then 分支,非零状态时执行 else 分支。防火墙发送的重置会导致 curl 返回非零状态,因此这里进入 else 分支才是预期结果。
预期消息为:
Expected: iptables rejected the request
现在使用 -v 查看详细计数器。请求完成后,端口 18086 规则的计数数据包数和字节数应该都大于 0。
sudo iptables -L INPUT -n -v --line-numbers
输出中的 pkts 列表示匹配到的数据包数量,bytes 列表示这些数据包的总大小。计数器可以提供有力证据:使用 -C 检查只能证明规则存在,而计数器增加则证明真实流量到达了该规则并与之匹配。如果计数器仍为 0,应先检查接口、协议、端口和规则位置,再判断应用是否存在问题。
将拒绝规则替换为允许规则
在本步骤中,你将删除完整的拒绝规则,为相同流量添加明确的允许规则,并验证访问已恢复。
下面的 -D 命令通过完整的匹配条件和目标来定位规则。相比清空链,这种方式更安全,因为它只会移除本实验创建的修改。
sudo iptables -D INPUT -i lo -p tcp --dport 18086 -j REJECT --reject-with tcp-reset
也可以根据行号删除规则,但每当插入或移除规则时,行号都会发生变化。在可重复执行的操作中,使用完整规则定义进行删除更清晰,也能降低误删相邻规则的风险。这里不要使用 iptables -F:清空操作会移除所选链中的全部规则,包括与本实验无关的规则。
为相同的接口、协议和端口插入一条 ACCEPT 规则。
sudo iptables -I INPUT 1 -i lo -p tcp --dport 18086 -j ACCEPT
ACCEPT 会允许匹配的数据包继续通过网络协议栈。将其插入第 1 位,可以避免结果被更早的终止规则覆盖。请注意,匹配条件仍然和之前一样严格,变化的只有目标。
检查这条精确的允许规则。
sudo iptables -C INPUT -i lo -p tcp --dport 18086 -j ACCEPT
再次执行原来的健康检查请求。
curl --noproxy '*' --fail --silent http://127.0.0.1:18086/health
此时可以再次获得响应:
iptables filter service ready
移除本实验创建的规则
在本步骤中,你将移除临时的允许规则,并确认本次练习创建的规则已经不再存在。
删除完整的 ACCEPT 规则。和之前一样,这不会清空链,也不会影响平台或其他管理员创建的规则。
sudo iptables -D INPUT -i lo -p tcp --dport 18086 -j ACCEPT
移除明确的允许规则,并不意味着服务一定会被阻断。规则删除后,剩余规则以及最后的链策略会共同决定数据包的处理结果。在当前准备好的环境中,原有防火墙仍允许本地请求。
再次检查该规则。这次检查失败是预期结果,因此只有当 iptables -C 返回非零状态时,|| 才会执行右侧的消息。
sudo iptables -C INPUT -i lo -p tcp --dport 18086 -j ACCEPT 2>/dev/null || echo "Lab allow rule removed"
你应该会看到:
Lab allow rule removed
最后确认移除明确规则并没有停止应用。此时,链的原始策略和规则会再次决定是否允许访问。
curl --noproxy '*' --fail --silent http://127.0.0.1:18086/health
总结
你检查了 iptables 的实现方式和 INPUT 链,插入并验证了一条范围严格限定的拒绝规则,通过真实流量和计数器证明了规则效果,将其替换为允许规则,最后只移除了本实验创建的修改。这些操作提供了数据包过滤所需的命令级实践,帮助你在不清空无关防火墙状态的前提下安全地进行管理。



