深入理解Linux iptables:从四表五链到实战防火墙配置
1. 项目概述从“防火墙”到“流量交警”的认知升级很多刚接触Linux网络管理的朋友一听到“iptables”这个词第一反应就是“防火墙”。这个理解没错但太笼统了。在我十多年的运维和开发经历里我更愿意把它比作一个功能极其强大的“网络流量交警系统”。它不仅仅是在你家门口服务器入口站岗检查谁可以进、谁不能进传统防火墙功能它更深入到城市操作系统内核的每一个十字路口网络协议栈的关键节点对经过的每一辆“数据包车辆”进行精细化的指挥、分流、限速甚至改造。为什么我们需要这样一个“交警系统”想象一下你的服务器是一栋对外开放的大楼。你希望访客用户请求能正常访问一楼展厅Web服务和二楼会议室SSH管理但绝不允许任何人进入地下机房敏感端口或在楼道里乱涂乱画恶意扫描。同时你还希望来自合作公司IP的车辆可以走VIP通道高优先级而对某些已知的广告推销员恶意IP直接拒之门外。这些复杂、动态的规则就是iptables的用武之地。它直接工作在内核空间效率极高是构建Linux系统网络安全、实现网络地址转换NAT、流量控制乃至简单负载均衡的基石。理解iptables核心在于掌握其“四表五链”的架构思想。这就像交警局的“科室”表和城市里的“执勤点”链。不同的科室负责不同性质的业务如过滤、地址转换而执勤点则分布在流量必经的各个路口。只有搞清楚了数据包会经过哪些执勤点以及每个执勤点有哪些科室的警察可以执法你才能写出精准、高效的规则。接下来我们就从最核心的“四表五链”模型开始拆解然后过渡到最贴近实战的配置案例最后分享那些只有踩过坑才知道的排查技巧。2. 核心架构拆解深入理解“四表五链”的交警体系要指挥交通必须先有一张清晰的交通网络图和执法体系。iptables的“四表五链”模型就是这张图和这个体系。2.1 五链Chains流量必经的五个核心执勤点链Chain是规则的集合你可以把它理解为数据包传输路径上的关键“检查点”或“执勤点”。数据包到达某个检查点时就会依次匹配这个检查点上的所有规则。Linux内核预定义了五个内置的链对应着数据包生命周期中最关键的五个节点PREROUTING链数据包刚进入网络接口网卡在进行路由判断之前的检查点。这是数据包接触到的第一个链。通常在这里进行目标地址转换DNAT比如把访问公网IP:80的包转发到内网服务器的192.168.1.100:8080。INPUT链数据包经过路由判断目标是本机例如用户SSH连接到这台服务器时会经过此链。这是我们做主机防火墙最常打交道的链用来控制哪些外部连接可以访问本机的服务。FORWARD链数据包经过路由判断目标是其他机器这台服务器充当路由器或网关时会经过此链。这是实现网络防火墙功能的核心控制流经本机的数据包能否被转发。OUTPUT链由本机进程产生并准备发送出去的数据包在离开本机之前会经过此链。可以用来控制本机哪些程序可以访问外部网络。POSTROUTING链数据包在离开网络接口之前进行路由判断之后的检查点。这是数据包离开前的最后一站。通常在这里进行源地址转换SNAT比如让内网机器通过网关服务器上网时将内网IP替换为网关的公网IP。一个简单的比喻PREROUTING和POSTROUTING是城市边界的高速路口进出口INPUT和OUTPUT是市政府大楼本机的门口而FORWARD则是城市里连接不同区域的立交桥转发流量。2.2 四表Tables交警局的四个专业科室表Table是链的容器定义了规则的功能类别。不同的“科室”负责不同性质的执法工作它们会在特定的“执勤点”上岗。四张表及其职责如下filter表过滤科室最常用的表。负责数据包的过滤决定是放行ACCEPT、拒绝REJECT还是丢弃DROP。它默认作用于INPUT、FORWARD和OUTPUT链。我们常说的“防火墙规则”大多定义在这个表里。nat表地址转换科室。负责网络地址转换修改数据包的源或目标IP地址/端口。这是实现共享上网、端口映射的核心。它作用于PREROUTING、OUTPUT和POSTROUTING链注意INPUT链一般不用于nat这是一个常见误区。mangle表改造科室。功能强大且灵活用于修改数据包的内容比如修改TTL生存时间、TOS服务类型字段或者给数据包打上特殊的“标记”MARK供后续规则或其他工具如tc流量控制识别。它可以作用于所有五个链。raw表特殊处理科室。优先级最高用于连接跟踪conntrack机制相关的处理。主要作用是在PREROUTING和OUTPUT链上对数据包进行“NOTRACK”标记使其绕过连接跟踪系统。这对于处理流量极大或需要极低延迟的场景如游戏服务器、高并发代理很有用可以减轻内核负担。2.3 表与链的钩子关系谁在哪儿执法理解了科室和执勤点关键是要知道哪个科室在哪个执勤点有执法权。数据包到达一个链时并不是所有表都会参与检查而是按照固定的优先级顺序依次通过有权限的表。这个优先级从高到低是raw - mangle - nat - filter。我们可以用一张表来清晰地展示这个关系链Chainraw表mangle表nat表filter表PREROUTING✓✓✓INPUT✓✓FORWARD✓✓OUTPUT✓✓✓✓POSTROUTING✓✓解读与记忆技巧filter表只管“过滤”所以只关心目的地是本机INPUT、从本机发出OUTPUT或路过本机FORWARD的包。nat表只管“地址转换”转换发生在路由决策前后PREROUTING做DNATPOSTROUTING做SNAT以及本机进程发出的包可能也需要做源地址转换OUTPUT。mangle表是“万金油”哪里需要改包就去哪里。raw表为了性能优化只在最开始接触包PREROUTING和本机刚产生包OUTPUT时介入。注意上表中nat表在INPUT链的缺失是重点。很多新手试图在INPUT链做DNAT这是无效的。因为INPUT链的检查发生在路由决策之后此时数据包的目标地址已经是本机了nat表的PREROUTING链才是修改目标地址的正确位置。3. 规则管理与语法精讲给交警编写执法手册规则Rule就是交警的具体执法指令。一条完整的iptables规则通常由匹配条件Matches和目标动作Target构成其逻辑是“如果数据包符合这些条件那么就执行那个动作”。3.1 基础命令结构与常用参数查看规则的命令是iptables -t 表名 -L 链名其中-t指定表默认为filter。-v显示详细信息如包计数、字节计数-n以数字形式显示IP和端口避免耗时的DNS反向解析。实操心得iptables -nvL是我最常用的组合。-n能极大提升列表显示速度尤其是在DNS解析慢或规则很多时。-v看到的包/字节计数器对于排查“规则是否被匹配”至关重要。添加规则的命令是iptables -t 表名 -A 链名 匹配条件 -j 目标动作。-A在链的末尾追加规则。-I在链的指定位置默认为开头插入规则。规则是有顺序的数据包会从上到下依次匹配一旦匹配成功就执行动作并停止后续匹配。-D删除指定规则。可以通过规则编号或完整规则描述来删除。-P设置链的默认策略Policy。当数据包不匹配任何规则时将执行默认策略。常见策略有ACCEPT接受和DROP丢弃。强烈建议将默认策略设为DROP或REJECT并显式开放所需端口即“默认拒绝按需允许”的白名单模式。3.2 核心匹配条件详解匹配条件是规则的精髓决定了规则的精度。通用匹配-s, --source源IP地址。支持CIDR格式如192.168.1.0/24。-d, --destination目标IP地址。-i, --in-interface数据包流入的网卡接口如eth0。仅能用于PREROUTING, INPUT, FORWARD链。-o, --out-interface数据包流出的网卡接口。仅能用于FORWARD, OUTPUT, POSTROUTING链。-p, --protocol协议类型如tcp,udp,icmp,all。隐含匹配当使用-p tcp或-p udp时自动启用。--sport, --source-port源端口。可以指定单个端口80或范围1000:2000。--dport, --destination-port目标端口。这是控制服务访问最常用的条件。显式匹配-m match需要显式加载的扩展模块功能强大。-m state --state状态匹配至关重要这是实现“有状态防火墙”的关键。常见状态有NEW新建连接的第一个包。ESTABLISHED已建立连接的后续包。RELATED与已有连接相关的连接如FTP的数据连接。INVALID无效的包。-m multiport匹配多个不连续的端口如--dports 22,80,443。-m iprange匹配一个IP地址范围如--src-range 192.168.1.100-192.168.1.200。-m limit限制匹配速率用于防止洪水攻击如--limit 10/second。-m connlimit限制单个IP的并发连接数如--connlimit-above 10 -j REJECT。3.3 目标动作-j Target目标动作决定了匹配后的命运。ACCEPT接受数据包。DROP丢弃数据包不发送任何响应。对客户端来说就像连接超时。更安全但体验不友好。REJECT拒绝数据包会发送一个拒绝响应的报文如TCP RST或ICMP port-unreachable。客户端能立刻知道被拒绝。SNAT源地址转换用于nat表的POSTROUTING链。格式-j SNAT --to-source 公网IP[:端口范围]。DNAT目标地址转换用于nat表的PREROUTING链。格式-j DNAT --to-destination 内网IP[:端口]。MASQUERADE动态SNAT常用于拨号上网等IP不固定的情况。会自动使用出口网卡的IP。-j MASQUERADE。LOG将匹配的数据包信息记录到系统日志如/var/log/messages或/var/log/syslog然后继续匹配后续规则。用于调试非常有用。可以附加前缀--log-prefix IPTABLES-DROP: 。重要注意事项关于DROP和REJECT的选择。对于对外服务在INPUT链上对非法访问使用DROP可以增加攻击者的探测成本他们需要等待超时。但在 OUTPUT 或 FORWARD 链上如果误丢弃了正常流量使用REJECT能让你更快地发现并定位问题因为应用会立刻收到错误。我的经验是对外防御用DROP对内排错用REJECT。4. 实用配置案例实录从零构建服务器防火墙理论说得再多不如动手配置一遍。我们假设一个典型的Web服务器场景来构建一套实用的iptables规则集。服务器公网IP是203.0.113.10内网IP是192.168.1.10需要开放SSH22、HTTP80、HTTPS443端口并作为内网192.168.1.0/24的网关提供上网服务。4.1 案例一基础主机防火墙配置我们的策略是默认拒绝所有入站连接只开放必要的服务允许所有出站连接允许已建立的连接和相关的连接回包。# 1. 设置默认策略危险务必在确保当前SSH连接不会被中断的情况下操作或先设置允许SSH的规则 # 更安全的做法是先在所有链末尾添加允许当前SSH连接的规则或者通过管理口操作。 iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT # 通常允许本机主动发起的连接 # 2. 允许本地回环接口(lo)的通信许多本地服务依赖它 iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # 3. 允许状态为ESTABLISHED和RELATED的入站数据包 # 这是实现“有状态检测”的核心允许我们对外请求的回应包进来。 iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 4. 开放特定服务端口入站 # SSH强烈建议限制源IP例如只允许管理IP 198.51.100.5 iptables -A INPUT -p tcp --dport 22 -s 198.51.100.5 -j ACCEPT # 如果无法固定管理IP至少使用limit模块限制爆破 # iptables -A INPUT -p tcp --dport 22 -m limit --limit 3/min --limit-burst 3 -j LOG --log-prefix SSH-ATTEMPT: # iptables -A INPUT -p tcp --dport 22 -j ACCEPT # 谨慎使用 # HTTP HTTPS iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT # 5. 允许ICMPping便于网络诊断可根据安全要求选择开放 iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/second -j ACCEPT # 6. 记录并拒绝其他所有非法入站尝试可选用于监控 iptables -A INPUT -j LOG --log-prefix IPTABLES-INPUT-DROP: iptables -A INPUT -j DROP # 注意LOG规则一定要放在对应链的末尾并且LOG后数据包还会继续匹配所以最后需要跟一个DROP。配置解析与技巧规则顺序ESTABLISHED,RELATED的规则应该放在开放具体端口之前。因为对于一台活跃的服务器回包流量远大于新建连接请求这条规则匹配频率最高放在前面能提升效率。SSH安全将SSH端口暴露在公网且不限源IP是极其危险的。务必使用密钥认证、修改默认端口、或结合fail2ban等工具。这里展示的limit日志规则可以帮助你观察爆破尝试。ICMP管理完全禁止ICMP会影响traceroute等工具。适度限速开放是平衡安全与可维护性的好方法。4.2 案例二实现网关与端口转发NAT现在让这台服务器充当内网192.168.1.0/24的网关并实现将公网IP的8080端口转发到内网一台Web服务器192.168.1.100:80。# 1. 启用Linux内核的IP转发功能临时生效 echo 1 /proc/sys/net/ipv4/ip_forward # 永久生效编辑 /etc/sysctl.conf设置 net.ipv4.ip_forward 1然后执行 sysctl -p # 2. 设置nat表的POSTROUTING链实现内网机器共享上网SNAT/MASQUERADE # 假设公网网卡是 eth0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE # 如果你的公网IP固定使用SNAT更高效 # iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 203.0.113.10 # 3. 设置filter表的FORWARD链控制经过本机的流量网关防火墙 # 允许已建立的连接和相关的连接通过 iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT # 允许从内网eth1到外网eth0的新建连接 iptables -A FORWARD -i eth1 -o eth0 -s 192.168.1.0/24 -j ACCEPT # 可以根据需要限制从外网主动发起到内网的连接默认策略是DROP所以这里不开放即禁止 # iptables -A FORWARD -i eth0 -o eth1 -d 192.168.1.100 -p tcp --dport 80 -j ACCEPT # 如果需要则添加 # 4. 实现端口转发DNAT将公网8080端口转到内网Web服务器 iptables -t nat -A PREROUTING -d 203.0.113.10 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80 # 同时为了让返回的数据包能正确NAT回去需要确保FORWARD链允许此流量上面第3步的规则已涵盖原理解析MASQUERADE/SNAT内网机器192.168.1.5访问外网时数据包到达网关。网关在POSTROUTING链将数据包源IP改为自己的公网IP203.0.113.10再发出。外网服务器回包给203.0.113.10网关再根据连接跟踪记录将目标IP改回192.168.1.5并转发到内网。DNAT外部用户访问203.0.113.10:8080。数据包到达网关在PREROUTING链目标IP和端口被改为192.168.1.100:80。然后内核进行路由发现目标不是本机于是将包送到FORWARD链如果允许则转发给内网服务器。4.3 案例三防御常见网络攻击利用iptables的扩展模块可以实施一些简单的防御。# 1. 防御SYN洪水攻击半连接攻击 iptables -A INPUT -p tcp --syn -m limit --limit 10/s --limit-burst 20 -j ACCEPT iptables -A INPUT -p tcp --syn -j DROP # 解释限制每秒最多接受10个新的SYN包突发允许20个。超过的直接丢弃。 # 2. 限制单个IP对SSH端口的连接频率 iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 3 --name SSH -j LOG --log-prefix SSH-BRUTE-FORCE: iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 3 --name SSH -j DROP # 解释--set 记录访问IP。--update 检查60秒内是否超过3次新连接如果是则记录日志并丢弃。 # 3. 防止Ping洪水ICMP Flood iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT iptables -A INPUT -p icmp --icmp-type echo-request -j DROP5. 规则持久化与高级管理技巧通过命令行配置的iptables规则在重启后会丢失。必须将其保存到文件并在开机时自动加载。5.1 规则保存与恢复# 保存当前规则到默认文件通常为 /etc/sysconfig/iptables 或 /etc/iptables/rules.v4 iptables-save /etc/iptables/rules.v4 # 在系统启动时自动加载规则 # 对于使用systemd的系统如CentOS 7, Ubuntu 16.04可以安装并启用 iptables-persistent # Ubuntu/Debian: apt-get install iptables-persistent # 安装时会询问是否保存当前规则。之后可以使用 netfilter-persistent save 手动保存。 # 手动加载保存的规则 iptables-restore /etc/iptables/rules.v45.2 使用自定义链管理复杂规则当规则非常多时可以创建自定义链来模块化管理。# 创建一个名为 WEBSERVER 的自定义链 iptables -N WEBSERVER # 将针对Web服务器的规则添加到自定义链 iptables -A WEBSERVER -p tcp --dport 80 -j ACCEPT iptables -A WEBSERVER -p tcp --dport 443 -j ACCEPT iptables -A WEBSERVER -p tcp --dport 8080 -j ACCEPT # 在INPUT链中跳转到自定义链进行处理 iptables -A INPUT -d 203.0.113.10 -p tcp -m multiport --dports 80,443,8080 -j WEBSERVER # 这样所有访问80/443/8080端口的流量都会先跳到WEBSERVER链去匹配规则使INPUT链更简洁。 # 查看自定义链规则iptables -L WEBSERVER -nv5.3 连接跟踪conntrack的威力与陷阱前面提到的-m state --state ESTABLISHED,RELATED依赖于内核的conntrack连接跟踪模块。它记录了所有经过系统的连接状态是实现有状态防火墙的基础。但高并发场景下它可能成为瓶颈。# 查看当前连接跟踪表 cat /proc/net/nf_conntrack # 或使用 conntrack 工具需安装 conntrack -L # 调整连接跟踪表大小如果遇到“nf_conntrack: table full”错误 # 临时调整 echo 655360 /sys/module/nf_conntrack/parameters/hashsize # 永久调整在 /etc/modprobe.d/ 下创建配置文件添加 options nf_conntrack hashsize655360踩坑记录我曾管理过一个高并发的代理服务器经常出现新连接建立缓慢的问题。排查后发现是conntrack表满了。默认表大小可能只有几万条对于每秒数万连接的场景远远不够。通过监控/proc/net/nf_conntrack_count和/proc/sys/net/netfilter/nf_conntrack_max并适当调大hashsize和nf_conntrack_max参数解决了问题。对于纯粹转发的中间设备如果不需要状态跟踪可以在raw表的PREROUTING链对某些流量打上NOTRACK标记来绕过连接跟踪能显著提升性能。6. 故障排查与调试实战手册再完善的规则也可能出错。掌握排查方法比记忆规则更重要。6.1 排查流程与常用命令确认规则是否生效使用iptables -L -nv查看规则计数器。如果某条规则的包计数pkts始终为0说明它可能被前面的规则拦截了或者匹配条件写错了。检查规则顺序规则是从上到下执行的。用iptables -L --line-numbers显示规则编号。一条允许规则如果放在默认的DROP或REJECT规则后面将永远不会被匹配到。使用 LOG 目标进行调试这是最强大的调试工具。在怀疑有问题的规则前插入LOG规则观察日志。iptables -I INPUT 5 -p tcp --dport 8080 -j LOG --log-prefix [DEBUG-8080-IN] 然后去/var/log/syslog或journalctl -f查看日志。调试完毕后记得删除临时规则。检查网络拓扑和路由iptables工作依赖于路由决策。用ip route或route -n确认数据包的流向是否正确是INPUT还是FORWARD。检查内核模块是否加载确保nf_conntrack、iptable_filter、iptable_nat等所需模块已加载 (lsmod | grep nf)。6.2 常见问题速查表问题现象可能原因排查步骤规则配置了但服务仍无法访问1. 规则顺序错误被前面的DROP规则拦截。2. 规则匹配条件写错如IP、端口、协议。3. 服务本身未监听或防火墙问题。1.iptables -L -nv --line-numbers看计数器检查顺序。2. 在规则前插入LOG规则看数据包是否匹配。3.netstat -tlnp确认服务监听状态。内网机器无法通过网关上网1. 未开启内核IP转发。2. nat表的POSTROUTING规则错误或缺失。3. filter表的FORWARD链未允许转发。1.cat /proc/sys/net/ipv4/ip_forward确认是否为1。2.iptables -t nat -L -nv检查SNAT/MASQUERADE规则。3.iptables -L FORWARD -nv检查转发规则。端口转发DNAT配置后外网仍无法访问内网服务1. DNAT规则写错IP/端口。2. FORWARD链未允许该转发流量。3. 内网服务器网关未指向本机或自身有防火墙。1.iptables -t nat -L PREROUTING -nv检查DNAT规则和计数器。2. 在FORWARD链前后插入LOG规则看包是否被转发。3. 检查内网服务器的路由和防火墙。服务器自身无法访问外网如ping不通1. OUTPUT链或POSTROUTING链有 restrictive 规则。2. 本机DNS解析问题。1.iptables -L OUTPUT -nv和iptables -t nat -L POSTROUTING -nv检查。2. 尝试ping IP地址如8.8.8.8排除DNS问题。出现“nf_conntrack: table full”错误连接跟踪表已满无法建立新连接。1. conntrack -L6.3 一个真实的排错案例为什么DNAT后内网服务能通外网不通曾经配置一个端口转发将公网IP的2222端口转发到内网服务器的22端口。在网关服务器上telnet 内网IP 22是通的但从外网telnet 公网IP 2222却超时。排查过程检查DNAT规则和FORWARD规则计数器都在增加说明包匹配并转发了。在内网服务器上抓包 (tcpdump -i eth0 port 22)发现能收到来自网关的SYN包但内网服务器回复的SYN-ACK包的目的IP是外网客户端的IP而不是网关。问题根源内网服务器的默认网关指向了另一个设备而不是这台做端口转发的网关服务器。因此内网服务器回复外网的包没有经过网关直接发往了错误的下一条导致丢包。解决方案将内网服务器的默认网关设置为这台网关服务器的内网IP。或者在网关服务器上对转发的流量启用“反向路径过滤”的宽松模式echo 2 /proc/sys/net/ipv4/conf/all/rp_filter但这只是权宜之计修正路由才是根本。这个案例告诉我们iptables的NAT功能依赖于完整的双向路由路径。不仅要考虑“怎么去”还要考虑“怎么回”。

相关新闻