GRE隧道避坑指南:当Iptables遇到华为防火墙时的5个典型配置错误

📅 发布时间:2026/7/5 17:31:35 👁️ 浏览次数:
GRE隧道避坑指南:当Iptables遇到华为防火墙时的5个典型配置错误
GRE隧道避坑指南当Iptables遇到华为防火墙时的5个典型配置错误最近在帮一个客户做跨数据中心网络打通的项目场景很典型总部用的是华为防火墙一个分公司的业务服务器跑在公有云上系统是CentOS。两边需要拉一条GRE隧道把云上的服务接入总部的内网。本以为是个教科书式的标准操作结果从隧道建立、策略路由到流量转发踩的坑一个接一个尤其是Linux那头的Iptables和华为防火墙的策略配置稍有不慎就导致隧道不通或者流量乱跑。折腾了两天总算把问题都捋清楚了。这篇文章我就把这些实战中遇到的典型配置错误和排查思路整理出来特别是针对那些初次接触跨厂商设备对接的技术朋友希望能帮你省下几个通宵的时间。1. 隧道接口“假在线”基础配置与状态检查的盲区很多人配置完隧道在华为防火墙上看到Tunnel0接口状态显示up或者在Linux上用ip link show tun0看到接口是UP状态就以为万事大吉了。这其实是第一个大坑——接口状态“up”不等于隧道已建立。GRE隧道是点对点的它需要两端都能通过底层IP网络即公网收到对方的GRE封装报文并在逻辑上完成三次握手虽然GRE本身没有严格的三次握手但需要双向可达才能算真正建立。错误1仅检查接口物理/逻辑状态忽略了对端可达性验证。典型表现在华为防火墙执行display interface Tunnel 0显示Line protocol current state : UP。在Linux执行ip addr show tun0也显示state UP。但互相ping隧道对端IP如172.16.1.1和172.16.1.2却完全不通。根因分析接口UP只意味着本地配置已加载隧道逻辑接口已创建。但承载隧道流量的物理接口如GE0/0/0可能没有正确的路由指向对端公网IP或者安全策略/本地防火墙如Linux的Iptables、华为防火墙的域间策略丢弃了GRE协议报文IP协议号47或ICMP报文。注意GRE隧道本身没有keepalive机制。一旦建立只要底层IP路径通畅它就认为隧道是好的。但如果中间路径发生变化如某条路由失效隧道不会主动告警只会表现为流量突然中断。正确的诊断流程应该是这样从底层往上层排查先确保两端能通过公网IP互相ping通。这是隧道建立的基础。# 在Linux服务器上ping华为防火墙的公网IP ping 100.1.1.1 # 在华为防火墙上ping Linux服务器的公网IP ping 200.1.1.1如果不通检查物理接口地址、默认路由、以及可能存在的任何访问控制列表ACL。检查并放行GRE协议这是最容易被忽略的一步。GRE封装后的报文其IP头部协议字段是47。在Linux (Iptables) 端# 允许协议号为47GRE的入站报文 iptables -I INPUT -p gre -j ACCEPT # 为了调试方便也可以暂时允许所有来自对端公网IP的流量 iptables -I INPUT -s 100.1.1.1 -j ACCEPT在华为防火墙端需要在untrust到untrust如果公网接口在untrust区或者对应区域的安全策略中允许协议为GRE的流量。security-policy rule name permit_gre source-zone untrust destination-zone untrust source-address 200.1.1.1 32 # Linux端公网IP destination-address 100.1.1.1 32 # 本端公网IP service protocol gre action permit使用tcpdump进行抓包验证这是定位隧道问题的“终极武器”。# 在Linux服务器的公网接口如eth0上抓包查看是否有GRE报文交互 tcpdump -i eth0 -nn host 100.1.1.1 and (ip proto 47 or icmp) -v如果能看到来自100.1.1.1的GRE协议报文说明对方发过来了如果只有icmp回显请求而没有GRE说明对方没发或者被中间设备丢弃了如果什么都看不到说明本端的请求报文可能都没发出去。一个快速验证隧道是否真正工作的技巧在两端分别抓取隧道接口tun0的流量。如果隧道已建立当你ping对端隧道IP时在tun0接口上应该能看到ICMP报文。如果在公网接口能看到GRE包但在tun0上看不到解封装后的ICMP包那问题可能出在隧道解封装环节。2. MTU与碎片化隐形丢包杀手隧道建立成功小包如ping通信正常但一旦传输大文件或进行大数据量查询连接就变得时断时续速度极慢。这十有八九是MTU最大传输单元问题在作祟。错误2忽略隧道封装开销未调整TCP MSS导致数据包被静默丢弃。GRE封装会在原始IP报文外添加一个新的IP头通常20字节和GRE头通常4字节至少增加24字节的开销。如果原始报文长度是1500字节标准以太网MTU封装后就会变成1524字节超过了物理接口的1500字节MTU限制。对于IPv4超出MTU的包可能会被分片传输但分片效率低且容易出问题更常见的情况是如果报文被设置了DFDon‘t Fragment标志TCP报文默认如此中间的路由器或防火墙就会直接丢弃这个包并回复一个“Fragmentation needed”的ICMP消息。在Linux端的解决方案降低隧道接口的MTU将tun0的MTU设置为1500 - 24 1476。ip link set dev tun0 mtu 1476可以将此命令写入/etc/rc.local或网络配置脚本使其永久生效。配置Iptables规则修正TCP MSS这是更优雅和通用的方法。它会在TCP连接建立时SYN包阶段将协商的MSS值调小确保封装后的报文不会超过路径MTU。iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o tun0 -j TCPMSS --set-mss 1436这里1436的计算是1500(物理MTU) - 20(新IP头) - 4(GRE头) - 20(原始IP头) - 20(原始TCP头) 1436。这个规则只修改从tun0接口出去的TCP SYN包的MSS值。在华为防火墙端的配置 华为防火墙的Tunnel接口通常会自动计算MTU。但为了保险起见可以手动配置并启用TCP MSS调整功能。interface Tunnel0 ip address 172.16.1.2 255.255.255.0 tunnel-protocol gre source 100.1.1.1 destination 200.1.1.1 # 手动设置MTU mtu 1476 # 启用TCP路径MTU发现 tcp adjust-mss 1436排查MTU问题的一个有效命令是ping使用-s和-M选项# 测试不分片情况下能通过的最大包大小 ping -M do -s 1472 172.16.1.2-s 1472指定数据部分大小加上28字节的IP头和ICMP头总包大小为1500。-M do表示设置DF标志位。如果这个包能通但-s 1473就不通了那就证实了MTU问题。3. 策略路由与NAT的优先级陷阱这是让流量“迷路”的最常见原因。我们的场景是内网主机192.168.1.10访问互联网的流量需要被引入GRE隧道从云端服务器出去。在华为防火墙上我们配置了策略路由PBR来匹配源地址192.168.1.0/24并指定出接口为Tunnel0。同时防火墙通常会有默认的源NAT策略将内网地址转换为公网地址。错误3策略路由生效前流量已被NAT策略匹配并转换导致策略路由失效。华为防火墙的数据包处理流程中策略路由的匹配点通常在NAT转换之前对于入方向流量。但这里有一个关键细节如果有一条NAT策略的匹配条件如源区域、目的区域、地址过于宽泛先于策略路由匹配了流量那么策略路由就可能不生效。因为经过NAT转换后数据包的源地址已经改变可能不再匹配策略路由中设定的源地址条件。错误配置示例nat-policy rule name default_nat source-zone trust destination-zone untrust source-address 192.168.1.0 mask 255.255.255.0 action source-nat address-group interface # 将源IP转换为接口地址这条规则意图是将所有从trust到untrust的流量做源NAT。但它匹配了192.168.1.0/24去往任何目的地的流量包括那些你希望走隧道目的地可能是另一个私网或特定公网的流量。一旦被转换策略路由可能就失效了。正确做法使用“no-nat”策略。 你需要创建一条更精确的NAT策略明确指定“去往隧道对端网络的流量不做NAT”并确保这条策略的优先级高于默认的NAT策略规则ID更小。nat-policy # 规则1去往隧道对端网络的流量不做NAT rule name no_nat_for_tunnel id 1 source-zone trust destination-zone tunnel # 目的区域是隧道区域 source-address 192.168.1.0 mask 255.255.255.0 action no-nat # 规则2默认的其他上网流量做NAT rule name default_nat id 10 source-zone trust destination-zone untrust action source-nat address-group interface这样当192.168.1.10访问隧道对端网络时匹配规则1执行no-nat源地址保持192.168.1.10不变。然后策略路由基于源地址192.168.1.10生效将流量引向Tunnel0。而访问普通互联网的流量匹配规则2进行源NAT。诊断命令 在华为防火墙上可以使用display firewall session table verbose查看具体的会话信息重点关注NAT字段看流量是否被正确转换或保持了原地址。4. Iptables FORWARD链与conntrack的干扰在Linux服务器作为隧道端点并充当路由器时iptables的FORWARD链和连接跟踪conntrack模块会介入经过它的所有转发流量。配置不当会导致转发失败。错误4只配置了PREROUTING/POSTROUTING的NAT规则却忘记了FORWARD链的放行规则。很多人记得做DNAT/SNAT却忘了Linux内核默认的FORWARD链策略是DROP在某些发行版上可能是ACCEPT但安全起见应显式配置。即使策略是ACCEPT如果FORWARD链上有其他限制规则也可能阻断隧道流量。一个完整的Iptables转发配置示例# 1. 设置默认策略如果已经是ACCEPT可跳过 iptables -P FORWARD ACCEPT # 2. 放行与隧道相关的双向转发流量更精确的做法 # 放行从物理网卡(eth0)到隧道(tun0)的GRE封装流量 iptables -A FORWARD -i eth0 -o tun0 -s 200.1.1.1 -d 100.1.1.1 -p gre -j ACCEPT # 放行从隧道(tun0)到物理网卡(eth0)的GRE解封装后流量 iptables -A FORWARD -i tun0 -o eth0 -s 100.1.1.1 -d 200.1.1.1 -p gre -j ACCEPT # 放行通过隧道接口转发的内部数据流量 iptables -A FORWARD -i tun0 -o eth1 -s 192.168.1.0/24 -j ACCEPT # 假设eth1是内部网络接口 iptables -A FORWARD -i eth1 -o tun0 -d 192.168.1.0/24 -j ACCEPT # 3. 配置NAT规则端口映射和源地址转换 # DNAT: 将到达本机公网IP 200.1.1.1:8080的流量映射到内网服务器 192.168.1.10:8080 iptables -t nat -A PREROUTING -d 200.1.1.1 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.10:8080 # SNAT: 将来自内网192.168.1.0/24从eth0出去的流量源地址转换为200.1.1.1 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 200.1.1.1 # 4. 保存配置根据系统不同 service iptables save # 或 iptables-save /etc/sysconfig/iptables错误5conntrack表满或状态不匹配导致转发异常。当流量经过Linux时conntrack会跟踪连接状态。在复杂的NAT和隧道组合场景下可能会遇到conntrack表溢出或者GRE隧道报文因为不属于任何已知的conntrack连接而被丢弃的情况尤其是在有状态防火墙规则时。排查与解决查看连接跟踪表cat /proc/net/nf_conntrack | grep gre可以查看GRE相关的连接跟踪条目。调整conntrack参数如果表项过多可以调整哈希表大小和超时时间。sysctl -w net.netfilter.nf_conntrack_max655360 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established7200为GRE连接设置更长的超时时间GRE本身是无状态的但conntrack会跟踪它。默认超时可能较短。sysctl -w net.netfilter.nf_conntrack_generic_timeout600在FORWARD链上为隧道流量添加无状态放行规则如果问题依旧可以考虑在FORWARD链最前面添加一条规则直接放行隧道接口的所有流量绕过状态检测。iptables -I FORWARD -i tun0 -j ACCEPT iptables -I FORWARD -o tun0 -j ACCEPT但这会降低安全性需权衡使用。5. 华为防火墙安全策略的域间隔离华为防火墙基于安全区域Zone实施访问控制。隧道接口Tunnel0需要被加入一个安全区域比如新建的tunnel区并配置正确的域间策略流量才能通过。错误6只配置了trust - tunnel和tunnel - untrust的策略遗漏了local区域与隧道区域的互访策略。这个错误非常隐蔽。当你从华为防火墙本身local区域去ping隧道对端的Linux服务器隧道IP172.16.1.1时会发现不通。这是因为流量路径是local-tunnel。你需要一条允许local区域访问tunnel区域的安全策略。反之如果你希望从Linux端能ping通或管理华为防火墙的隧道接口地址也需要tunnel-local的策略。完整的安全策略配置参考security-policy # 允许内网访问隧道对端网络 rule name trust_to_tunnel source-zone trust destination-zone tunnel action permit # 允许隧道对端网络访问内网 rule name tunnel_to_trust source-zone tunnel destination-zone trust action permit # 允许隧道流量访问互联网如果需要 rule name tunnel_to_untrust source-zone tunnel destination-zone untrust action permit # 允许防火墙本机与隧道端点管理通信关键 rule name local_to_tunnel source-zone local destination-zone tunnel action permit rule name tunnel_to_local source-zone tunnel destination-zone local action permit日志定位如果流量被安全策略拒绝华为防火墙会生成日志。在Web界面的“监控 日志 安全日志”中查看被拒绝的日志重点关注“源/目的安全区域”和“动作”字段这能快速告诉你流量在哪一层被拦截了。最后分享一个我自己的排查习惯画一张简单的数据流图。标出源IP、目的IP、经过的每个设备接口、每个设备上做的NAT转换、策略路由和安全策略。然后按照“物理连通性 - 协议放行(GRE/ICMP) - 路由指向(策略路由) - NAT转换 - 安全策略 - 隧道封装/解封装”的顺序一层一层去验证。很多时候问题就出在自以为配置正确但实际上各环节的匹配条件存在细微偏差上。跨厂商对接对协议和配置逻辑的理解深度往往比记住具体命令更重要。