ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

iptables从零到实战:表、链、规则与NAT配置详解

iptables从零到实战:表、链、规则与NAT配置详解 只要你还跑着Linux服务器iptables就不是可以绕开的东西。不管是云主机、物理机、还是公司内部的路由设备几乎所有流量进出都在某个环节被netfilter框架审查过一遍而iptables恰恰就是我们管理这套审查规则最常用的入口。很多朋友一上来就复制几条命令规则能加能删就觉得会了可一旦遇到“为什么端口不通”“为什么重启规则没了”“为什么nat表报错”就彻底卡住。这篇文章就是想把这个缺口补上。我会先讲清楚表、链、规则这几个核心概念再把数据包在Linux内核里的完整走向捋一遍然后直接带你把一台机器的防火墙从零配起来默认策略、SSH和Web放行、NAT端口转发、防暴力破解、规则持久化每一个命令都会解释为什么这么写。最后把我踩过的坑和常见的排查思路整理成速查表。适合谁看刚接手Linux服务器的运维新人、写后端但要自己部署服务的开发者以及那些一直用firewalld/ufw掩盖底层细节、真出问题就抓瞎的朋友。1. iptables到底是什么先搞清它和“防火墙”的关系1.1 netfilter与iptables的分工每次看到有人把iptables说成“防火墙软件”我都想纠正一下iptables只是一个用户态命令真正干活的是Linux内核里的netfilter框架。你把一条规则敲进去iptables通过setsockopt、getsockopt这一类系统调用把规则塞给内核里挂在各个协议栈关键点上的钩子函数。数据包每到达一个钩子点内核就按顺序执行挂在这个点上的规则决定它是放行、丢弃、拒绝还是转向其他处理流程。这一点看似琐碎但理解后你就知道为什么“规则加了没用”这个问题经常出现要么规则没真正写进内核比如内核模块没加载要么规则挂在错误的链上要么规则顺序不对。排查的第一步永远不是怀疑配置而是确认内核里到底有什么。1.2 都202x年了为什么还要学iptables新版Linux内核和主流发行版已经全面转向nftables很多系统里你敲iptables命令底层其实已经被映射到nftables了。但现实是存量服务器里还有大量老系统网上绝大多数教程、运维文档、云厂商帮助中心写的还是iptables命令Docker的端口映射原理也完全依赖netfilter的NAT逻辑。不把iptables这套概念吃透你连Docker的-p参数为什么有时会失败都说不清楚。所以iptables不是一门“过时技术”而是理解Linux网络处理的底层语言。学懂了它再看nftables、firewalld、ufw都是在同一个知识框架上加一层壳而已。1.3 本文的适用范围这篇文章围绕Linux主机上的iptables展开讨论的是标准内核协议栈、物理机或虚拟机场景。至于Windows防火墙比如Win11防火墙错误代码0x800706d9、企业级设备华为USG、H3C、山石、锐捷等厂商的Web界面和命令行是另一套体系不在本文范围内。但理解本文讲的链、NAT、策略顺序这些思想对你操作任何防火墙设备都有帮助因为底层逻辑是相通的。2. 核心概念拆解表、链、规则怎么配合2.1 五条内置链数据包的必经之路链的本质是数据包在内核协议栈中的“检查点”。iptables内置了五条链PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING。PREROUTING数据包刚进入协议栈、还没做路由决策时经过常用于DNAT也就是目的地址转换。INPUT目的地址是本机的数据包进入本地进程前经过本地主机防火墙的主要战场就在这里。FORWARD不是发给本机、只是路过本机转发的数据包经过在做路由器或网关时使用。OUTPUT本机进程发出的数据包在发出前经过。POSTROUTING数据包准备离开协议栈前经过常用于SNAT和MASQUERADE也就是源地址转换。用生活化的方式理解你是一个小区门口的保安。PREROUTING是“来人先看一眼身份”INPUT是“进楼的人登记”FORWARD是“通过小区去隔壁小区的人只判断放不放行”OUTPUT是“本楼住户出门时检查有没有带违禁品”POSTROUTING是“离开时在出门条上盖个章改一下显示身份”。每个环节干的事不一样挂错环节的规则自然就不生效。2.2 四张表职责要分开有了检查点还需要分工。iptables的表就是不同的“业务模块”同一张表可以挂到多条链上不同表可以挂到同一条链上规则按表、按链组织。表名主要职责通常会用到哪几条链filter过滤决定放行还是拒绝INPUT、OUTPUT、FORWARDnat网络地址转换改写源地址或目的地址PREROUTING、OUTPUT、POSTROUTINGmangle修改数据包头、设置标记QoS常用所有五条链都可用raw跳过连接跟踪性能调优用PREROUTING、OUTPUT四张表在同一条链上是有执行优先级的顺序一般是 raw → mangle → nat → filter。同一个数据包在同一链上会先过raw再过mangle再进nat最后才轮到filter。很多人习惯把所有规则一股脑往INPUT上堆结果用到NAT的时候发现规则写到了POSTROUTING上或者把filter规则写进了nat表命令虽然没报错效果却完全不对就是这个分工没搞清楚。2.3 规则的三个要素匹配条件、目标、计数器一条iptables规则的完整写法可以拆成三个部分匹配条件什么样数据包会被这条规则匹配比如协议类型、源IP、目的端口、网卡接口、状态。目标target匹配之后怎么办常见的有ACCEPT放行、DROP丢弃且不响应、REJECT拒绝并回错误信息、LOG记录日志。计数器内核会自动记录这条规则匹配了多少个包、多少字节方便调试。看一条例子iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT拆开就是追加-A一条规则到INPUT链匹配条件是“TCP协议、目的端口22、来源是192.168.1.0/24网段”命中后目标-j是ACCEPT。其余不满足这几个条件的包这条规则根本不看它继续往链的下一条规则走。2.4 规则顺序与“匹配即落定”iptables的链是顺序执行的规则从上到下逐条匹配一旦某条规则被匹配后面的规则就不再看了。这就是“匹配即落定”原则。它带来一个非常重要的结论规则顺序就是规则逻辑。举个例子你想“除了192.168.1.100这台机器其他都不许访问22端口”。如果先写“全部DROP 22端口”再写“允许192.168.1.100访问22端口”后者永远不会生效因为包在第一条就被DROP了。正确的顺序一定是先放行特定IP再拒绝其余所有。这个坑几乎每个新手都踩过。所以我建议你在动手配置之前先拿张纸把规则的先后关系画出来尤其是有“全局拒绝”和“放行例外”同时出现时。3. 从零配置策略先行规则跟上3.1 配之前先看清现状很多人拿到一台机器就刷规则这是最危险的操作。第一步永远是看现状我一般用这三条命令iptables -L -n -v --line-numbers iptables -t nat -L -n -v --line-numbers iptables-save-L是列出所有规则-n不做反向解析IP跑得快也不会被DNS带偏-v显示计数器--line-numbers显示行号方便后面按行号删规则。iptables-save输出的是标准的持久化格式能看出当前所有表的完整配置。如果你连现在机器上有什么规则都不知道就不要动任何一条规则。3.2 默认策略DROP还是ACCEPT要想清楚默认策略policy是链上所有规则都没匹配时最终执行的兜底动作。一条链只能有一个默认策略可以用-P修改。比如iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT这里有个灵魂问题INPUT默认策略是选DROP还是ACCEPTDROP策略默认拒绝一切只放行你明确写出来的流量。安全系数高但配置时必须先把SSH等管理通道放行否则一条规则写错你就被锁在外面了。ACCEPT策略默认放行一切只拒绝你明确禁止的流量。安全性差一些但不容易断连适合内部测试环境。我个人的习惯凡是暴露在公网的机器INPUT和FORWARD一律DROPOUTPUT按需选择内网机器可以先ACCEPT再逐步收紧。生产环境走上线前一定要经过DROP策略的完整验证。3.3 黑白名单两种落地方式热点里经常看到“防火墙黑白名单”在iptables里其实就是两种完全不同的配置思想。白名单模式先放行已知合法流量然后默认拒绝一切。典型配置是先把回环、已连接状态、明确的业务端口都放行最后把INPUT的默认策略设置成DROP。它的优点是被攻击面最小缺点是每加一个新服务都要改防火墙运维负担重。黑名单模式默认一切放行只封禁已确认的恶意IP、恶意端口。实现起来很简单几条DROP或REJECT规则就能搞定日常维护省事。缺点是机器暴露面大只适合信任度高的内网环境。需要特别提醒的是黑白名单不是二选一写死的事。生产上常见的是“白名单为骨架、黑名单做补充”整体走DROP默认策略再把已知攻击IP用黑名单提前DROP掉减少它们探测你的机会。3.4 常用命令速查表操作命令查看filter表规则iptables -L -n -v --line-numbers查看nat表规则iptables -t nat -L -n -v --line-numbers清空filter表规则iptables -F清空nat表规则iptables -t nat -F设置INPUT默认策略为DROPiptables -P INPUT DROP在INPUT链顶部插入规则iptables -I INPUT 1 规则删除第3行规则iptables -D INPUT 3保存规则到文件iptables-save /etc/iptables/rules.v4其中-I INPUT 1这种“在顶部插入”的写法特别实用。因为新规则在最前面优先级最高适合临时加一条紧急放行、紧急封禁不需要关心原来规则的长短。4. 实操案例一台Linux主机的完整防护配置4.1 场景设定假设我手里有一台新装的Ubuntu服务器对外IP是203.0.113.10上面的业务是SSH远程管理端口22只允许管理网段192.168.10.0/24连入对外提供Web服务80和443端口对所有来源开放内网还有一台Web服务器192.168.1.100需要把公网80端口转发给它这台机器还要作为内网网关让内网机器共享公网出口上网。下面所有命令都按这个场景来写你可以直接照着改IP和端口用。4.2 基础放行回环、已连接状态、SSH、Web配置顺序非常重要先放行“必须通的”最后才收紧。我通常按这个顺序来。# 1. 清空旧规则防止之前的配置干扰 iptables -F iptables -t nat -F iptables -X # 2. 默认策略先设为ACCEPT等规则都加完再收紧 iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT # 3. 回环接口直接放行 iptables -A INPUT -i lo -j ACCEPT # 4. 已建立连接及衍生连接放行 iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # 5. 放行SSH只允许管理网段 iptables -A INPUT -p tcp -s 192.168.10.0/24 --dport 22 -j ACCEPT # 6. 放行Web服务 iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT # 7. 放行ping方便连通性排查 iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT # 8. 最后收紧其他入站流量全部丢弃 iptables -P INPUT DROP第4条很多人会漏。没有这条即使你前面的规则放行了22端口每次SSH连接建立后的交互包也可能被视为新连接被后续DROP规则拦掉表现就是能连但一敲命令就断。ESTABLISHED是已建立的连接RELATED是与此相关的衍生连接比如FTP数据连接、ICMP错误报文。这两个状态放行之后业务的表现会稳定很多。第8步把INPUT默认策略设为DROP之前一定要确认前面几条放行规则都已经加上并且你的SSH连接还活着。我见过太多人第8步一执行当前SSH会话直接断掉后面重新登录也进不去了。4.3 NAT端口转发与内网上网端口转发的核心是DNAT在PREROUTING链上完成。公网用户访问203.0.113.10的80端口时目的地址被改写为192.168.1.100:80iptables -t nat -A PREROUTING -d 203.0.113.10 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.100:80这里要解释一个关键点DNAT只改了目的地址应答包回来的时候源地址是192.168.1.100而不是用户访问的203.0.113.10。如果不做源地址转换用户侧就会觉得“连接来了但没人说话”。解决办法是加一条SNAT让内网服务器应答时把源地址伪装成网关的对外地址iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADEMASQUERADE是SNAT的一种特殊形式适合出口IP动态变化的场景比如拨号、DHCP地址经常变的链路。它不需要手动指定转换后的源地址会自动取网卡当前的IP。如果出口IP是固定的也可以用显式SNATiptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 203.0.113.10上面这条命令同时解决了内网机器上网的问题内网192.168.1.0/24的机器出去时源地址都被改成公网IP应答包也能正确回到内网。但要注意跨网段转发还需要开启内核转发开关sysctl -w net.ipv4.ip_forward1这个参数不改FORWARD链路即使有允许规则内核也不会转发任何包。想让配置永久生效把它写进/etc/sysctl.conf并执行sysctl -p。FORWARD链别忘了放行很多人NAT配完了发现内网还是上不了网结果一看FORWARD默认策略是DROP转发包直接被拦掉。可以在上面基础配置里补一条iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -s 192.168.1.0/24 -j ACCEPT4.4 限制SSH暴力破解SSH暴露在公网扫描和暴力破解几乎是24小时不打烊的。iptables可以基于连接速率做限流虽然不如Fail2ban那么智能但胜在零额外依赖内核原生支持。思路是同一个来源IP每分钟新建的连接数超过一定阈值就拒绝它后续的新连接。# 放行速率内的新SSH连接 iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m limit --limit 5/minute --limit-burst 10 -j ACCEPT # 超过速率的SSH新连接一律丢弃 iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j DROP # 已建立的SSH连接不受影响 iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT--limit 5/minute表示平均每分钟放行5个新连接--limit-burst 10表示允许峰值时连续放行10个新连接然后才开始按平均速率节制。这种配置对正常使用几乎没有影响但能把扫端口的攻击脚本挡掉一大半。要注意这两条规则必须在基础配置中SSH放行规则之后插入并且排在DROP默认策略之前否则新连接的包会被默认策略直接丢掉限流就失去意义了。实际用下来我还会配合SSH本身的配置修改默认端口、禁用密码登录改用密钥、限制允许登录的用户。iptables限流只是第一道闸真正扛住暴力破解的是密钥和账户策略。4.5 让规则永久生效手敲的iptables规则存在内核里重启就没了。想让它在重启后自动恢复标准做法是先把规则导出再在开机时导入。Debian/Ubuntu下可以安装iptables-persistent这个工具也可以手动操作iptables-save /etc/iptables/rules.v4 ip6tables-save /etc/iptables/rules.v6然后在系统启动脚本或网络接口配置里调用iptables-restore /etc/iptables/rules.v4。用systemd的话可以写一个简单的service[Unit] DescriptionRestore iptables rules Afternetwork.target [Service] Typeoneshot ExecStart/usr/sbin/iptables-restore /etc/iptables/rules.v4 ExecStart/usr/sbin/ip6tables-restore /etc/iptables/rules.v6 RemainAfterExityes [Install] WantedBymulti-user.target保存规则这件事一定要在规则全部验证通过之后再执行。我习惯在每次规则调整后先保存一份带时间戳的备份比如rules.v4.20250115这样万一新规则出问题还能快速回滚到上一份可用配置。注意如果这台机器同时在跑Docker规则保存和恢复要特别小心因为Docker启动时会往nat表写入自己的链和规则两个体系叠加顺序错了很容易让容器网络出问题。5. 常见问题与排查技巧实录5.1 报错nat表不存在先查内核模块和容器权限有阵子我常遇到这类报错iptables v1.8.9 (legacy): cant initialize iptables table nat: table does not exist第一次遇到时我也懵了明明同一套配置在别的机器上好好的。后来排查发现问题出在三个方向内核没有加载NAT相关模块。很多最小化安装的Linux发行版nat表默认不启用。可以先用lsmod | grep nat看看有没有nf_nat、iptable_nat这类模块没有就手动加载modprobe iptable_nat modprobe nf_nat加载完再看看cat /proc/net/ip_tables_names正常情况下应该能看到nat字样。容器环境权限不足。如果你在Docker容器里敲iptables容器默认没有NET_ADMIN权限netfilter相关操作会被内核拒绝表现就是各个表都初始化不了。解决办法是启动容器时加--privileged或至少--cap-addNET_ADMIN。不过这会把容器的网络权限放大自己权衡。iptables的legacy后端与nft后端选错。iptables 1.8.x开始分iptables-legacy和iptables-nft两套后端。默认用的是nft后端某些老内核或老模块下它去初始化nat表时会失败。可以强制切回legacy后端试试update-alternatives --set iptables /usr/sbin/iptables-legacy或者直接运行iptables-legacy -t nat -L -n -v确认是不是后端问题。这个坑在云主机、容器平台、嵌入式设备上都很常见排查路径就是从内核模块、容器权限、后端选择这三条线依次扫。5.2 规则莫名其妙消失“我明明加好了规则重启就没了”这几乎是新手的第一大问。原因很简单iptables规则默认只存在内核里不落盘。它和你在编辑器里打字不一样没有一个“保存”按钮。所以凡是要求规则重启后还在的场景必须做规则持久化。方法就是4.5里讲的iptables-save/iptables-restore加systemd service。另外还有一种情况要留意有些云平台的控制台有自己的“安全组”和云防火墙它们和操作系统里的iptables是两层体系有时候你的iptables规则还在但入口流量在云平台安全组就被拦掉了表现为“规则明明放行了还不通”。这不算iptables的问题但排查时一定把这一层也查一遍。5.3 手滑把自己关在门外怎么救配置防火墙最怕的就是还没放行SSH就先把INPUT默认策略设成了DROP然后当前会话一断再也登不进去。真遇到这种情况我的救援顺位是如果有物理控制台或带外管理IPMI/iDRC/iLO直接通过控制台登录把规则清掉或修正。这是最稳的办法。如果云主机有VNC之类的网页控制台效果同上可以进入系统操作。如果都没有只能依赖定时任务自救。在操作前先在另一个会话里加一个“保险”# 30分钟后自动清空INPUT规则给自己留一条退路 echo iptables -F INPUT | at now 30 minutes这条保险命令一定要在动手改规则之前设置好。实际操作中必须先把SSH放行规则加进去并确认连接正常才去设置DROP默认策略这个顺序不能乱。我自己每次改生产环境防火墙都坚持“改一条、验证一条、备份一条”宁可慢不能断。5.4 加了规则还是不通顺序、日志、计数器三件套规则加了、持久化也做了但端口还是不通这是最耗时的排查场景。我的固定排查三板斧第一板斧查顺序和计数器。用iptables -L -n -v --line-numbers看规则列表重点看每条规则命中计数器是不是有增长。如果流量根本没到你的放行规则就被前面的DROP拦了计数器会非常直观地告诉你。比如你放行了443端口但计数器一直是0那就说明包压根没走到这条规则。第二板斧查日志。在可疑位置临时加一条LOG规则把它放在所有规则的较前位置iptables -A INPUT -p tcp --dport 443 -j LOG --log-prefix IPT-443: --log-level 4然后在/var/log/kern.log或/var/log/messages里看有没有对应记录。LOG规则不会改变包的走向只是记录下来非常适合定位“包到底来没来”“被哪条规则处理了”。排查完记得把LOG规则删掉否则生产环境日志会被刷爆。第三板斧抓包确认。用tcpdump在服务器内外网卡分别抓包tcpdump -i eth0 -nn port 443看看SYN包有没有到达网卡。如果网卡根本没收到包问题就不在iptables而在上层路由、安全组或者对端网络如果收到了但应用层没反应才是防火墙或服务本身的问题。这三板斧按顺序走下来绝大多数“规则不生效”的谜团都能解开。6. iptables、firewalld和ufw怎么选6.1 三者的真实关系很多新人被这仨名字搞晕其实它们的关系很清晰iptables直接操作netfilter规则的命令行工具最底层、最直接。ufwUbuntu/Debian系推出的前端工具把iptables规则封装成“允许某个端口”“拒绝某个IP”这类简单命令默认规则自动生成适合个人和小型服务器快速配置。firewalldRHEL/CentOS/Rocky系默认的防火墙服务提供命令行和图形界面核心是区域zone概念底层在较新版本上基于nftables但也兼容iptables语法。可以这么理解ufw和firewalld都是“翻译官”把人类友好的需求翻译成内核能执行的规则。iptables是它们背后真正干活的引擎之一。所以firewalld和ufw管理下的机器底层同样能看见iptables规则只是不希望你手工去动。6.2 什么时候你仍然得直接碰iptables既然有更友好的工具为什么还要碰iptables我的实际经验是这几个场景绕不开排障上层工具生成的规则出了问题最终还是要回到iptables-save、iptables -L来看底层到底发生了什么。NAT和端口转发ufw对NAT的支持很蹩脚firewalld虽然支持但配置复杂。而只要涉及一台机器做网关、做端口映射直接写iptables的nat表往往是最快最清晰的方案。Docker和容器网络Docker会在iptables的nat表和filter表里插入自己的链比如DOCKER链。容器端口映射异常时看不懂这些链就无从下手。老系统维护CentOS 6、Ubuntu 14.04这类老系统没有firewalldufw也未必装iptables就是唯一选择。6.3 给新人的选型建议如果你是刚上手Linux单机配置用ufw或者firewalld快速满足需求完全没问题没必要非跟自己较劲。但只要你满足下面任何一条就建议系统学一遍iptables管理多台服务器的NAT路由、排查过网络问题、用Docker做过端口映射、或者手里有老系统要维护。学的时候不用背命令把“表、链、规则顺序、匹配即落定、默认策略”这五个概念吃透剩下的都是查手册的事。iptables命令本身语法固定真正的门槛是理解数据包在内核里怎么走、规则在哪个环节起作用。再补充一句关于企业级设备的题外话华为USG、H3C、山石、锐捷这些硬件防火墙界面和命令虽然五花八门但你配置NAT、安全策略、黑白名单时本质还是在决定“哪个检查点、对哪种流量、做什么动作”。把iptables这一套概念学扎实了切到任何品牌设备都能快速上手。最后说说我个人的体会。iptables这东西配置策略写得再漂亮都不如“可回滚、可验证”重要。我的习惯是把每台服务器的规则文件纳入版本管理改动前先diff改动后立刻保存再跑一遍端口连通性测试。常见的安全加固都是靠这种笨功夫堆出来的没有哪条命令能一键解决所有问题。还有一个小技巧每次配置完把iptables-save的输出和操作日期一起记下来积累一段时间后回头看你会发现自己对“哪些流量该放、哪些该收”的判断比刚开始那会儿清晰得多。防火墙的本质不是禁止而是搞清楚你到底该信任谁。
返回列表