ARTICLE DETAIL

资讯详情

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

多网卡Linux防火墙FORWARD链配置与排障实战

多网卡Linux防火墙FORWARD链配置与排障实战 搞过多网卡防火墙或Linux网关的朋友一定遇到过这种经典场景主机上插着三块网卡分别接两个业务网段和一条上联线路结果内网A段能出去内网B段死活不通或者从某个网段ping网关能通ping对面网段的机器就像扔进黑洞连个ICMP应答都没有。最后用tcpdump一抓发现数据包明明到了防火墙就是没被转发出去。问题大多出在同一个地方FORWARD链的规则没有按多网卡的实际转发路径来设计。这篇文章不聊命令手册也不堆概念就围绕“多网卡环境下如何确保FORWARD链正确处理跨网段流量”这个具体问题把流量路径、内核转发开关、规则设计顺序、NAT联动、以及我实际排障中踩过的那些坑一次讲透。适合正在维护Linux网关、软路由、多线接入服务器或者刚开始接触iptables/nftables的运维和网络工程师参考。1. 先搞清楚FORWARD链的职责边界别在错误的地方写规则很多人第一次配置防火墙时习惯把注意力放在INPUT链和OUTPUT链上觉得只要“放行入站”“放行出站”就够了。但对于一台承担网段间转发任务的多网卡主机来说这种思路基本等于没配防火墙。要理解FORWARD链为什么是核心得先把Linux内核处理数据包的路径理清楚。1.1 数据包在Linux防火墙中的完整旅程当一块网卡收到一个数据包时内核并不是直接把它送给应用程序而是先经过一组Netfilter钩子点。对于目标是本机的数据包路径是网卡接收 - PREROUTING链 - 路由决策发现目的IP是本机- INPUT链 - 本地协议栈 - 应用程序处理。对于本机向外发送的数据包路径是应用程序生成 - 路由决策 - OUTPUT链 - POSTROUTING链 - 网卡发出。而第三种情况也就是跨网段流量数据包的目标IP不属于本机任何一个接口地址它只是借道这台机器去往别的网段。此时路径变成网卡接收 - PREROUTING链 - 路由决策发现目的IP不在本机- FORWARD链 - POSTROUTING链 - 另一块网卡发出。从这个路径就能看出来转发流量根本不会经过INPUT链和OUTPUT链。INPUT链只管“发给本机进程”的包OUTPUT链只管“本机进程发出”的包。如果你在INPUT链里写了一条“放行所有来自192.168.10.0/24的流量”然后发现这个网段还是访问不了另一个网段原因很简单那些转发包根本没走INPUT链它们只会走FORWARD链FORWARD链依旧按默认策略处理它们。我见过很多新手在INPUT链里反复加放行规则抓包显示数据包已经到达防火墙但转发就是不成功最后才知道问题在FORWARD链默认DROP上。这个误区非常典型所以第一件事就是建立条件反射多网卡转发场景下跨网段流量只认FORWARD链默认策略、放行规则、日志记录都必须围绕它来做。1.2 为什么说FORWARD链是网段间的“唯一关卡”把防火墙比作办公大楼门禁的话INPUT链是“进入大楼内部房间”的检查OUTPUT链是“从大楼内部房间出去”的检查而FORWARD链是“从A楼穿过大厅去B楼”的过境检查。如果一个访客只是路过大厅去另一栋楼你在大楼前台INPUT链给他放行完全不解决他在过境通道FORWARD链被拦下的问题。这也是多网卡环境最容易犯的错误以为只要放行了源IP或目的IP就能通没有意识到每个网段之间的流量都必须经过FORWARD链的一次完整匹配。如果FORWARD链的默认策略是DROP那么即使PREROUTING做了DNAT、POSTROUTING做了SNAT规则缺漏时数据包依然会在转发环节被静默丢弃网络表现就是“ping不通但抓包能看到包到了机器上又消失”。所以正确设计思路的第一步是明确边界哪些网段之间的流量需要转发、以什么方向转发、业务端口是什么然后把所有放行规则统一写在FORWARD链上。2. 多网卡转发的硬前提内核转发开关与接口配置在写任何一条FORWARD规则之前有两个前提如果没满足规则写得再漂亮都是白搭内核的IP转发功能必须开启而且每个网卡的接口状态、IP地址、路由信息必须正确。这两个点看起来基础但实际排障中大量“FORWARD不生效”的案例最后都栽在这里。2.1 开启内核IP转发临时生效与永久生效Linux内核默认不转发数据包因为普通主机不应该充当路由器。即使你配置了多块网卡在没有开启转发功能前任何进入一块网卡且目标IP不属于本机的数据包都会被内核直接丢弃。这个丢弃发生在Netfilter之前所以连FORWARD链都看不到这个包抓包时你会发现数据包“进了网卡就没了”。开启方法很简单临时生效用sysctl -w net.ipv4.ip_forward1或者直接改proc接口echo 1 /proc/sys/net/ipv4/ip_forward这里有个容易被忽略的细节如果网络环境还涉及IPv6跨网段转发需要同时配置sysctl -w net.ipv6.conf.all.forwarding1如果系统重启后配置丢失需要在/etc/sysctl.conf或/etc/sysctl.d/目录下新建配置文件写入net.ipv4.ip_forward 1 net.ipv6.conf.all.forwarding 1然后执行sysctl -p或sysctl --system使其生效。我建议在生产环境使用独立的配置文件比如/etc/sysctl.d/99-forward.conf避免和系统默认配置混在一起出问题时也方便排查。另外提醒一句光看一个全局开关还不够。某些发行版可能还有接口级别的转发控制但绝大多数场景下net.ipv4.ip_forward1就足够了。开启后可以用sysctl net.ipv4.ip_forward验证一下确保显示为1而不是0。2.2 网卡接口状态与路由核查转发路径上任何一块网卡处于down状态或者接口没有配置预期地址都可能让跨网段转发失败。很多人忽略这一步直接开始写iptables规则结果排查一圈回原点发现是网卡没启用。先看接口信息ip addr show确认每个网卡的IP地址、子网掩码、状态是否为UP。如果是DOWN状态手动启用ip link set dev eth1 up再看路由表ip route show多网卡主机最容易出现的问题是缺路由。假设eth0连接外网eth1连接192.168.10.0/24网段eth2连接192.168.20.0/24网段路由表里必须有到达这两个内网网段的路由。通常给接口配置IP后系统会自动生成直连路由但如果你手动修改过配置、或者使用了奇怪的网段划分就可能缺少对应路由。缺少路由的结果是数据包进入FORWARD链后路由决策阶段就找不到出口接口直接丢包。这时tcpdump抓包会看到包到了机器上但没有任何网卡发出它。还需要检查的是反向路由过滤rp_filter。这是Linux内核默认开启的一个安全机制用来防止IP欺骗当数据包从某个接口进来时内核会检查如果以这个源IP回包是否应该从这个接口出去。如果不是说明存在不对称路径数据包会被直接丢弃。问题在于多网卡环境下如果两个网段之间有策略路由、或者回程路径和去程路径不一样rp_filter会静默丢掉合法转发流量且表现为转发诡异地失败。可以用下面的命令查看当前配置sysctl net.ipv4.conf.all.rp_filter sysctl net.ipv4.conf.eth1.rp_filter如果值为1且确认存在对称路由问题需要临时关闭sysctl -w net.ipv4.conf.all.rp_filter0 sysctl -w net.ipv4.conf.eth1.rp_filter0但这里我不建议无脑关闭因为rp_filter确实能防御源地址欺骗。更好的做法是确保路由对称让回包路径与去包路径一致。如果实在无法保证对称再针对受影响接口关闭该机制并做好网络边界的安全限制。2.3 一些容易被忽略的接口级问题多网卡环境下接口配置相关的坑很多我挑几个实际遇到频率最高的说一下第一接口上配了重复网段的IP。比如eth1配了192.168.10.1/24eth2也配了192.168.10.5/24内核路由表里会出现两条指向同一网段但出口不同的直连路由系统只能选其中一条结果就是某个方向的流量完全走错接口转发自然失败。这种低级错误一旦出现规则怎么调都白搭。第二接口没有关闭或者没有开启IPv4确认。有些网卡需要启用硬件特性但大多数情况下只要IP配好、链路up就没问题。如果真的发现接口虽然配置了IP但一直没流量检查一下ethtool eth1的Link detected是否为yes。第三网卡命名混淆。多网卡服务器上eth0、eth1的顺序在重启后可能变化如果配置文件里绑定的MAC和实际接口不一致也会出现转发异常。建议用ip link show核对MAC地址必要时通过udev规则固定网卡名。3. FORWARD链规则设计按“网段接口”组合而不是按单一IP满足了转发开关和接口配置后才轮到真正的规则设计。很多人在这一步栽跟头主要是因为规则写得过于随意要么只写源IP不写出接口要么把放行规则堆在一起没有逻辑。多网卡环境下FORWARD链规则的正确姿态应该是按“入接口、出接口、源网段、目的网段”这样的组合来精确匹配而不是笼统地放行某个IP。3.1 先定默认策略白名单思路更适合多网卡隔离FORWARD链的默认策略只有两种选择ACCEPT或者DROP。如果你的机器是纯粹的转发设备且网段之间没有强隔离需求可以直接用ACCEPT作为默认策略然后只写DROP规则。但对于大多数有多网卡隔离需求的场景我强烈建议默认策略设为DROP然后逐一放行需要转发的流量。这样做的好处是即使你漏掉了某条规则最坏的结果是流量不通而不是你不希望互通的网段之间意外变成全通。安全边界宁可收紧再逐步放开也不要一开始就开着大门裸奔。设置默认策略iptables -P FORWARD DROP设置完之后所有跨网段转发流量都会被丢弃直到你显式添加放行规则。这里有一个非常关键的提醒默认策略DROP后不只是业务流量会被丢弃像ICMP、DHCP、DNS这些看起来“辅助性”的流量同样会被丢弃。如果你发现内网能上网但ping不通网关或者DHCP分配不到IP先检查是不是FORWARD链默认策略导致的。3.2 状态规则永远放在最前面避免回程流量被误杀在多网卡场景下流量往往是双向的。比如内网192.168.10.0/24访问外网数据包从eth1进、eth0出回包时方向完全反过来从eth0进、eth1出。如果你只写了从内网到外网的单向放行规则没有考虑回程方向回包就会被FORWARD链拦截连接依然建立不起来。解决这个问题的标准做法是使用连接跟踪让防火墙自动识别“这是已建立连接的回包”。在FORWARD链的最前面先放行所有状态为ESTABLISHED或RELATED的包iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT这条规则的意思是只要是某个已被允许建立起来的连接发出的回包或者与该连接相关的新连接比如FTP数据连接都直接放行。这样你只需要关心正向的“新连接发起方向”怎么放行回程流量交给状态规则接管。注意在新版本的iptables中-m conntrack --ctstate是推荐写法旧版的--state也能用但conntrack模块更通用。规则放行顺序上这条状态规则必须放在其他所有FORWARD规则之前否则先被DROP规则匹配到的回包依然会被丢掉。3.3 核心放行规则的写法接口方向决定一切多网卡流量方向是多网卡环境下最核心的抽象数据包一定有一个入口接口-i和一个出口接口-o。匹配规则时这两个参数要明确写出来而不是依赖源IP或目的IP去猜。举个例子假设eth1是内网A段192.168.10.0/24eth0是上联外网接口允许A段访问外网的规则可以这样写iptables -A FORWARD -i eth1 -o eth0 -s 192.168.10.0/24 -j ACCEPT这条规则拆解一下-i eth1表示数据包从eth1进来-o eth0表示数据包要从eth0出去-s 192.168.10.0/24表示源地址属于内网A段-d 0.0.0.0/0或省略表示目的地址不限。合起来就是从内网A段进入、从外网接口出去、源IP是A段的流量允许转发。很多人会问为什么还要写-i和-o只写-s 192.168.10.0/24 -j ACCEPT不就行了吗如果这样写意味着从任何接口进来的、源IP为192.168.10.0/24的转发流量都会被放行。换句话说如果某个不懂事的接口假冒了这个源IP它也能骗过防火墙。更重要的是不写接口组合时规则无法表达“从A到B”和“从A到外网”的区别会大大增加规则冲突的概率。尤其是当同一个源网段可以通过不同出口访问不同目的时靠-i/-o才能精确表达方向。反过来如果你想控制的是从外网到内网某个网段的访问规则就要把-i和-o调换比如iptables -A FORWARD -i eth0 -o eth1 -d 192.168.10.0/24 -j ACCEPT如果方向写反比如应该从eth1到eth0却写成了从eth0到eth1那么真正需要转发的流量会被后续规则拦住表现就是网络时通时不通。所以每次写规则时我习惯先问自己一句“这个包是从哪个接口进来的要从哪个接口出去”想清楚了再动手指。3.4 多网段之间互访控制需要清晰的规则顺序多网卡设备最常见的需求不只是“内网到外网”还包括内网网段之间的互访。比如有一台三网卡机器eth1接办公网192.168.10.0/24eth2接服务器网192.168.20.0/24eth3接外网上联。需求是办公网可以访问服务器网的Web服务但服务器网不能主动访问办公网。这种场景下规则需要分两条写。先允许办公网访问服务器网指定端口iptables -A FORWARD -i eth1 -o eth2 -s 192.168.10.0/24 -d 192.168.20.0/24 -p tcp --dport 80 -j ACCEPT iptables -A FORWARD -i eth1 -o eth2 -s 192.168.10.0/24 -d 192.168.20.0/24 -p tcp --dport 443 -j ACCEPT然后因为默认策略是DROP服务器网到办公网的方向不需要额外写DROP规则默认就丢弃。但如果你的默认策略是ACCEPT就需要显式拒绝iptables -A FORWARD -i eth2 -o eth1 -s 192.168.20.0/24 -d 192.168.10.0/24 -j DROP这里要特别注意规则匹配顺序。FORWARD链中的规则是从上到下逐条匹配一旦命中带-j的动作ACCEPT、DROP、REJECT等这条规则就是最终处理结果后面的规则不再执行。假设你先把“所有从eth1到eth2的流量都放行”再写一条“拒绝某网段到某网段”前面那条放行规则会把大部分流量先接走后面那条DROP规则根本派不上用场。所以精细控制规则的顺序一定是从小范围到大范围先放行特定端口、特定IP段再放行更宽泛的流量最后再兜底DROP。我习惯把允许规则尽量写得精确把宽泛的放行规则放后面。如果拿不准顺序可以用iptables -S FORWARD查看当前规则列表核对顺序是否符合预期。3.5 NAT与FORWARD链的联动看清楚数据包的地址变化多网卡转发场景中几乎绕不开NAT。NAT的存在会让FORWARD链的匹配逻辑变得有点绕因为源地址和目的地址在转发前/后可能已经改变而你写的规则是在FORWARD链上、在NAT转换过程的“中间点”生效的。理解这个时序是避免规则写反的关键。以最常见的“内网上网”场景为例内网192.168.10.0/24要访问外网通常会在POSTROUTING链做SNAT把源地址伪装成外网接口IP。此时FORWARD链看到的源IP是192.168.10.x而不是外网接口IP因为SNAT发生在POSTROUTING阶段位于FORWARD链之后。所以FORWARD放行规则应当匹配原始内网源IP。这一点和很多人直觉相反你以为要放行SNAT后的公网IP实际上完全不用。另一个常见场景是外网访问内网服务器需要做DNAT。DNAT发生在PREROUTING阶段位于FORWARD链之前所以当数据包到达FORWARD链时目的地址已经被改成了内网服务器IP比如192.168.20.10。此时FORWARD规则必须匹配这个内网目标IP而不是原始的公网目标IP。如果规则写成放行外部地址永远匹配不到任何数据包。给一个具体例子假设公网IP是202.100.80.1内网Web服务器是192.168.20.10做了DNAT把访问202.100.80.1:80的流量转发到192.168.20.10:80。FORWARD链需要放行的是“从外网接口进来、目标为192.168.20.10且端口80”的包iptables -t nat -A PREROUTING -i eth0 -d 202.100.80.1 -p tcp --dport 80 -j DNAT --to-destination 192.168.20.10:80 iptables -A FORWARD -i eth0 -o eth2 -d 192.168.20.10 -p tcp --dport 80 -j ACCEPT注意DNAT后的回程流量会被conntrack自动还原所以状态规则依然能正确匹配。如果你发现外网访问内网服务不通但内网HTTP服务本身正常优先检查FORWARD链是否放行了DNAT后的目标IP而不是一直在PREROUTING上死磕。4. 实操示例三网卡主机完整FORWARD规则集光说理论不够我直接给一个可以照抄的三网卡转发配置示例覆盖从开启转发、到写规则、到保存生效的完整流程。这个配置我在实验环境实测过也可以直接放到测试机或内部网关设备上做验证。4.1 网络拓扑与需求规划设备有三个网卡eth0上联外网IP为202.100.80.1/24作为默认出网接口eth1接内网A段IP为192.168.10.1/24eth2接内网B段IP为192.168.20.1/24需求如下内网A段和内网B段都可以访问外网源地址需要SNAT内网A段可以访问内网B段的Web服务80和443端口内网B段不能主动访问内网A段所有被丢弃的转发流量记录日志便于审计在写规则前先把路由和接口准备好。假设接口IP已经通过系统配置文件或ip addr命令配置好启动转发sysctl -w net.ipv4.ip_forward1 echo net.ipv4.ip_forward 1 /etc/sysctl.d/99-forward.conf此时确认一下路由表ip route show预期应该有四条直连路由和一条默认路由。如果没有默认路由需要手动添加ip route add default via 202.100.80.254 dev eth04.2 FORWARD链规则配置全流程先把FORWARD链清空避免历史规则干扰然后设置默认策略为DROP。在生产环境执行清空操作前务必确认自己可以通过其他方式管理设备否则一旦规则清空且默认策略改为DROP可能把远程管理链路一并切断。实际排障时我见过太多因远程调整规则把自己锁在门外的案例建议至少保留一个带外管理通道。iptables -F FORWARD iptables -P FORWARD DROP接着在链首插入状态放行规则确保所有已建立连接的回包都能通过iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT放行内网A段和B段访问外网。因为默认策略是DROP这一步相当于把上网流量路径打开iptables -A FORWARD -i eth1 -o eth0 -s 192.168.10.0/24 -j ACCEPT iptables -A FORWARD -i eth2 -o eth0 -s 192.168.20.0/24 -j ACCEPT注意这里我写了入接口、出接口和源网段没有限制目的IP。目的IP不限内网才能访问任意外网地址。如果不希望某个网段访问某些外网IP再在前方插入更精确的DROP规则。然后放行A段到B段的Web服务iptables -A FORWARD -i eth1 -o eth2 -s 192.168.10.0/24 -d 192.168.20.0/24 -p tcp --dport 80 -j ACCEPT iptables -A FORWARD -i eth1 -o eth2 -s 192.168.10.0/24 -d 192.168.20.0/24 -p tcp --dport 443 -j ACCEPT由于默认策略是DROPB段主动连接A段的流量会在FORWARD链被兜底丢弃不需要再写一条显式DROP。但如果你想明确记录这类被拒流量可以加一条日志规则并放在规则表末尾iptables -A FORWARD -i eth2 -o eth1 -s 192.168.20.0/24 -d 192.168.10.0/24 -j LOG --log-prefix FORWARD_DROP_B-to-A: --log-level 4 iptables -A FORWARD -i eth2 -o eth1 -s 192.168.20.0/24 -d 192.168.10.0/24 -j DROP这里用了两条规则先LOG记录再DROP。如果只写LOG而不跟DROP数据包会被放行日志记录就没有意义了。4.3 配置NAT并保存规则上网流量还需要SNAT否则外网回包不知道应该送回哪个内网IP。在POSTROUTING链上做源地址伪装iptables -t nat -A POSTROUTING -o eth0 -s 192.168.10.0/24 -j MASQUERADE iptables -t nat -A POSTROUTING -o eth0 -s 192.168.20.0/24 -j MASQUERADEMASQUERADE适合动态获取外网IP的场景如果eth0是固定公网IP也可以写成更明确的SNATiptables -t nat -A POSTROUTING -o eth0 -s 192.168.10.0/24 -j SNAT --to-source 202.100.80.1固定IP场景下SNAT效率更高而且重启后不会因为IP变更导致规则失效。但如果你不确定用MASQUERADE更稳妥。保存规则让重启后自动加载。不同发行版方式不同Debian/Ubuntu可以使用iptables-persistentapt install iptables-persistent iptables-save /etc/iptables/rules.v4CentOS/RHEL可以使用iptables-services然后执行iptables-save /etc/sysconfig/iptables systemctl enable iptables systemctl restart iptables注意NAT表的规则也要一起保存所以iptables-save不带-t nat参数时保存的是所有表正好满足需求。我习惯把保存后的规则文件做版本管理改规则后先diff确认无误再覆盖这个习惯帮我避免过不止一次“改错规则导致全网断开”的事故。5. 实战排查跨网段流量不通的常见原因与定位方法即使规则写得再完整实际运行中跨网段流量不通的概率依然很高。还好这类问题有章可循按照固定顺序排查多半能在十分钟内定位。我总结了最常见的五个方向每个都配有具体的排查命令和判断标准你可以直接照着做。5.1 先看转发开关和接口状态排除“先天性”问题排查第一步永远是确认内核转发开关不看这个就开始抓包很容易浪费时间。执行sysctl net.ipv4.ip_forward如果输出net.ipv4.ip_forward 0转发功能没开后面所有规则都不会起作用。开启方法前面已经说过这里不再重复。确认转发开关后再看接口状态ip addr show ip link show eth0重点看三块网卡的state是否为UP地址配置是否正确。如果接口是DOWN状态一切转发都无从谈起。然后再用ping测试一下防火墙到两个内网网段的网关是否连通排除链路层问题。防火墙自己能ping通对端网段的网关转发才有基础如果连防火墙自己都到不了对面问题出在物理链路或底层配置上和iptables无关。5.2 抓包确认数据包到底卡在哪块网卡这是定位转发问题最直接的方法。在防火墙的两个接口上分别抓包对比数据包到达了哪里、又消失在何处。场景假设内网A段192.168.10.2要ping外网202.100.80.88在eth1上执行tcpdump -i eth1 -n icmp在eth0上执行tcpdump -i eth0 -n icmp如果eth1能抓到来自192.168.10.2的ICMP请求包说明数据包到达了防火墙的接收接口问题出在后续转发环节。如果eth0也能抓到同样的ICMP请求包说明数据包已经成功穿过FORWARD链并由eth0发出问题在于回程方向。如果eth1有包、eth0没有问题大概率在FORWARD链上要么被规则DROP要么被rp_filter丢弃要么路由缺失导致找不到出口接口。还可以结合iptables计数器判断规则是否命中iptables -L FORWARD -n -v执行上述命令后看一下每行规则前面的pkts和bytes计数。如果某个规则的计数一直没有增长可能说明流量没有走到这条规则或者规则条件没匹配上。比如你想放行eth1到eth0的流量但实际数据包是从eth1进入、从eth3出去那么你的规则永远匹配不到。5.3 用conntrack表确认连接状态FORWARD链中的状态规则依赖于conntrack表所以检查conntrack表也是排查重点。执行conntrack -L | grep 202.100.80.88或者使用cat /proc/net/nf_conntrack | grep 202.100.80.88重点看连接条目是否存在、状态是否为ESTABLISHED。如果能看到内网IP到外网IP的连接条目且状态正常说明conntrack记录了这条连接问题可能出在策略或路由上。如果连conntrack条目都没有说明数据包在进入前端就被丢弃了比如rp_filter拦截。顺便提醒一句conntrack表是有容量上限的。如果并发连接数接近上限新连接会被丢弃表现为“流量时通时不通”。可以用以下命令查看当前使用量和上限sysctl net.netfilter.nf_conntrack_count sysctl net.netfilter.nf_conntrack_max如果使用量接近上限需要适当调大nf_conntrack_max同时注意服务器内存占用。5.4 不对称路由与rp_filter的坑多网卡环境中不对称路由是一个极其隐蔽的问题。假设防火墙从eth1接口收到内网A发来的数据包经过转发从eth0发出。外网服务器回包时可能由于路由策略原因回包不是从eth0进入防火墙而是从eth2进入。这样防火墙看到的回包源IP和入接口不匹配rp_filter就会把它当成伪造包丢弃。排查时可以查看系统日志被rp_filter丢弃的包通常会留下提示。在大多数系统上启用rp_filter时日志不一定明显但可以通过手动抓包辅助判断。如果你发现数据包明明到达了某个接口但没有任何一条iptables规则命中同时该接口的计数器也没有增加可以尝试临时将相关接口的rp_filter设为0看转发是否恢复。sysctl -w net.ipv4.conf.eth0.rp_filter0 sysctl -w net.ipv4.conf.eth1.rp_filter0 sysctl -w net.ipv4.conf.eth2.rp_filter0如果设置后转发恢复正常说明确实是不对称路由导致的。此时不要只依赖关闭rp_filter应该从路由设计入手尽量让流量路径对称。比如在两侧设备上都配置正确且对称的静态路由避免回包走上游另一条链路。如果无法从根本上解决再考虑针对特定接口关闭rp_filter并严格限制哪些源IP允许从该接口进入。5.5 规则顺序和规则冲突排查iptables规则是顺序匹配、命中即执行所以规则顺序错误是转发不通的常见原因之一。举一个我实际处理过的案例某台网关设备FORWARD链第一条规则写的是“禁止所有源地址为192.168.20.0/24的包通过”第二条才是“允许内网A段访问192.168.20.0/24的Web服务”。由于第一条规则在顺序上先匹配后者永远没有机会执行。表面上看网段间访问不通实际上是被前面那条大范围拒绝规则拦住了。排查方法很简单用iptables -S FORWARD或iptables -L FORWARD -n --line-numbers查看规则及序号逐条检查是否存在大范围DROP规则排在小范围ACCEPT规则前面的情况。如果有需要调整规则顺序。调整方式是删除旧规则再插入新规则或者使用iptables -I FORWARD 3 ...指定插入位置。比如把一条放行规则插到第5条位置让它在大范围拒绝规则前生效iptables -I FORWARD 5 -i eth1 -o eth2 -s 192.168.10.0/24 -d 192.168.20.0/24 -p tcp --dport 80 -j ACCEPT使用-I指定序号插入时要反复确认插入位置是否在合适的地方。我习惯先iptables -L FORWARD --line-numbers看一眼完整列表再决定插到哪一行避免插错导致行为变化。还有一个常见误区是同时存在多条重复或冲突规则尤其是通过脚本批量添加规则时。建议每隔一段时间用iptables-save导出规则文件做代码审查把冗余规则清理掉减少排查时的认知负担。6. 我踩过的几个坑以及现在推荐的规范做法写了这么多最后说点个人体会。多网卡防火墙配置本身不难难的是各种细节叠加在一起后问题会变得极其隐蔽。我总结几个自己在实际运维中踩过、也帮别人处理过的坑给读者做一个参考。6.1 最容易被忽略的几个“隐形杀手”第一个是忘了开ip_forward。这个问题出现频率高得离谱尤其是刚接手一台新装好的Linux服务器时什么都配好了路由也通了转发就是不工作总觉得是防火墙规则的问题结果一个sysctl搞定。我现在检查转发问题第一步永远是看这个开关不看它不看别的。第二个是默认策略DROP后忘了放行ICMP。在很多业务场景下内网需要ping网关或ping外网IP排障。就算业务流量都放行了ICMP被DROP会让运维误以为链路断了。最好在规则集里显式放行受信网段的ICMP并在文档中说明这是用于排障的避免安全审计时被问。第三个是rp_filter导致的多接口丢包。这个坑我之所以单独拿出来说是因为它在生产环境中出现过多次而且现象非常迷惑数据包能到防火墙但就是出不去iptables计数器没增长tcpdump能看到包。如果没有经验很容易在FORWARD链上反复找原因最后才发现是内核安全机制在作祟。第四个是保存规则时忘了保存NAT表。很多人只执行了iptables-save但用的命令带了--table filter或者只保存了filter表重启后NAT规则丢失上网立即瘫痪。建议统一执行iptables-save 保存文件不带表参数保存所有表内容。6.2 我现在的规范化操作流程经过多次折腾后我现在管理多网卡防火墙规则时基本遵循一套固定流程分享出来供参考。首先规则文件全部用iptables-save托管而不是零散地在命令行里现场敲。规则变更时先修改规则文件再用iptables-restore加载这样既方便回滚也方便通过diff看到改动内容。对于大规模环境我会把规则文件放到svn或git仓库每次变更留痕。其次每条规则都加上注释。iptables本身支持comment模块iptables -A FORWARD -i eth1 -o eth0 -s 192.168.10.0/24 -j ACCEPT -m comment --comment allow A segment to internet这样执行iptables-save后规则文件里能看到每一条规则的用途后期排查时不需要靠回忆。再次规则顺序严格按照“状态放行、定向放行、宽泛放行、日志、丢弃”的层次来组织。先把ESTABLISHED,RELATED放行再放行特定的网段间业务再放行上网流量最后统一记录并丢弃剩余流量。这个顺序通用性很强也符合大部分网络安全策略的直觉。最后每次变更规则前都要在测试环境或业务低峰期进行验证。变更后第一时间用iptables -L FORWARD -n -v观察计数器确认规则是否被命中。不要凭感觉认为“规则写对了就一定会生效”多网卡环境中的接口错位、地址转换、路由不对称都会让看似正确的规则变成废纸。6.3 一个日常维护小技巧把FORWARD链计数器当监控指标FORWARD链规则自带计数器这其实是一个原始但有效的监控工具。你可以定期执行iptables -L FORWARD -n -v观察各规则的packets和bytes增长情况。如果某条业务放行规则长时间没有流量很可能是上游路由变了、接口切换了或者业务本身停了。如果某条日志规则突然暴涨说明有人在持续触发拒绝策略值得进一步排查。我习惯写一个简单的shell脚本定时抓取FORWARD链计数器写入日志配合现有监控系统做阈值告警。这不需要装额外组件却能及时发现转发层面的异常。比如某天内网B段到外网的规则重新计数突然暴增可能是B段有机器中招往外发包这时结合conntrack -L按源IP统计能快速找到异常主机。多网卡FORWARD链的配置与管理说到底就是三个词路径清晰、规则有序、验证到位。把每条规则都想清楚“它从哪个接口来、要到哪个接口去”把每个连接都验证到“正向能否建立、回程能否通过”绝大多数转发问题都能在半小时内解决。这也是我这几年代维网关设备过程中最深刻的体会。
返回列表