十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

ip6tables-save 详解:IPv6防火墙规则备份与迁移的必备工具

ip6tables-save 详解:IPv6防火墙规则备份与迁移的必备工具 做 IPv6 防火墙规则管理时很多朋友知道用 ip6tables 一条条添加规则但要把当前内核里跑着的规则导出来备份第一反应往往是截图或者手打记录其实 ip6tables-save 就是专门干这个的。这个命令会把内核中 Netfilter 框架下 IPv6 相关的防火墙规则完整输出成可读的文本格式方便备份、迁移和二次编辑。这篇文章就围绕 ip6tables-save 展开从命令本身的原理讲到实操场景再到我踩过的一些坑希望对正在做双栈运维或者纯 IPv6 环境的朋友有帮助。1. 理解 ip6tables-save 的定位与使用场景1.1 ip6tables-save 到底是什么ip6tables-save 是 Linux 系统里 ip6tables 命令家族的一员作用是把当前内核中已经加载的 IPv6 防火墙规则导出为标准输出。这里说的“内核中的规则”指的是通过 ip6tables 命令添加后、真正生效在 Netfilter 框架里的那套规则表。它不读取任何配置文件而是直接和内核态的规则集打交道。有些朋友会混淆配置规则时我们用的是 ip6tables为什么导出不用它加一个参数而是单独搞一个命令原因在于职责分离。ip6tables 侧重规则的增删改查ip6tables-save 专攻“整体导出”ip6tables-restore 负责“整体恢复”。三者配合起来才是一套完整的管理链路。我第一次用这个命令时直接在终端敲了 ip6tables-save结果屏幕上哗啦啦输出一大堆带 -A 前缀的规则行。当时第一反应是“这玩意儿不就是把规则列表打了个快照吗”确实如此但它输出的格式经过专门设计不仅能给人看还能直接交给 ip6tables-restore 原样加载回去。1.2 为什么需要把内核规则导出成文本实际运维中规则导出这件事几乎是刚需尤其是在 IPv6 逐步铺开的阶段。第一个场景是备份。防火墙规则往往是业务稳定运行的命脉尤其是过滤规则配置得又长又复杂的时候一旦机器重启或者有人误操作规则集说没就没。把规则导出成文本定期存到安全位置这是最基本的操作习惯。第二个场景是迁移。比如要从一台旧服务器迁移到新服务器或者要把一套测试环境的标准策略同步到生产环境。如果一条条手工重新敲费时费力还容易漏掉细节。直接导出文本、在目标机器上用 ip6tables-restore 加载几分钟就能完成整批规则迁移。第三个场景是审计与排查。规则多的时候光靠人眼在终端里翻输出效率很低。导出成文本后可以 grep、可以 diff、可以写入脚本做自动化分析。比如我想确认有没有放行某个端口直接 grep 一下导出文件比在终端里逐屏翻找省力得多。还有一类场景容易被忽略规则变更前的快照。我在生产环境改防火墙策略前习惯先执行 ip6tables-save backup.rules 留个底。万一改完之后业务异常一条 ip6tables-restore backup.rules 就能回滚到改动前的状态。这个习惯救过我很多次。1.3 与 iptables-save 的异同对比iptables-save 处理的是 IPv4 规则ip6tables-save 处理的是 IPv6 规则两者逻辑类似但细节上需要注意区分。最直观的差别是地址格式。IPv6 规则里的地址是冒号分组的十六进制表示同一地址通常有压缩写法。比如 2001:db8::1 这种形式。在匹配条件里IPv6 规则的源/目标地址字段会显示为带前缀长度的标准形式例如 2001:db8::/32。另一个差别是扩展模块。IPv6 场景下常用的匹配扩展比如 icmpv6、hlhop limit、rt路由头、ipv6header 等在 IPv4 规则里根本不会出现。这些扩展导出到文本时会有对应参数恢复时也需要相关模块支持。还有一个容易忽略的点两条命令保存的表结构各有侧重。ip6tables-save 默认同样会导出 filter、mangle、raw、security 等表但如果你只用 IPv4 规则输出文件里看不到这些差异真正双栈环境下IPv4 和 IPv6 的规则必须分别导出不能混着来。我见过有人把 iptables-save 的结果直接拿给 ip6tables-restore 用那结果只能是报错。2. 规则存储格式深度解析2.1 一条规则的完整结构ip6tables-save 输出的文本规则看起来像一串加了参数的 iptables 命令但它不是完整命令而是带 -A追加前缀的规则描述。举例来说一条允许 ICMPv6 回显请求的规则导出后大概长这样-A INPUT -i eth0 -p ipv6-icmp --icmpv6-type echo-request -j ACCEPT拆开来看这条规则包含几部分-A 表示要追加到某条链INPUT 是链名-i eth0 是流入接口匹配-p ipv6-icmp 是协议匹配--icmpv6-type echo-request 是 ICMPv6 类型匹配-j ACCEPT 是最终动作。文本格式的关键在于“可读”。每个字段的含义和手工添加规则时几乎一致所以即使不查文档也能大致看明白一条规则在做什么。这也是为什么 ip6tables-save 输出的内容能直接用于审计——它把内核里的二进制的规则结构翻译成了人话。恢复时的行为也有讲究ip6tables-restore 并不是把规则文本逐条翻译成命令重新执行一遍而是直接解析规则描述在内核中构造对应的规则结构。这样效率更高也避免了一些命令执行时的隐式排序问题。2.2 两层表结构与链的类型导出文件的整体结构通常以一个表格头部开始然后是具体的链定义和规则条目。常见的头部是这样的*filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -i eth0 -p ipv6-icmp -j ACCEPT ... COMMIT*filter 表示当前段属于 filter 表。:INPUT DROP [0:0] 是链的默认策略定义方括号里是数据包计数器和字节计数器导出时归零恢复后开始重新累计。规则行以 -A 开头描述具体规则。COMMIT 表示提交本表的全部变更。链类型在导出文本里不会显式标注但熟悉 ip6tables 的朋友知道每个表都有内置链和自定义链之分。自定义链在导出文件里也有对应的定义行比如 :MY_CHAIN - [0:0]- 表示没有默认策略因为自定义链没有默认策略只能被其他规则跳转引用。恢复的时候自定义链会一并恢复不用担心跳转目标丢失。多层表结构意味着同一份规则文件里可能包含多个表的段落。例如*filter ...filter表规则... COMMIT *mangle ...mangle表规则... COMMITip6tables-restore 加载时会按文件顺序依次处理各表所以同一个文件里包含多个表完全没问题。2.3 IPv6 特有的匹配扩展与格式差异IPv6 防火墙规则里有些匹配条件是 IPv4 场景见不到的这些在导出文本里也会有对应的表达方式。ICMPv6 匹配最常见。IPv6 协议栈依赖 ICMPv6 做邻居发现NDP、路由通告RA、重复地址检测DAD等如果规则把 ICMPv6 一刀切全部丢弃那 IPv6 基本就没法正常工作。所以在写 IPv6 防火墙规则时通常需要显式放行某些 ICMPv6 类型。导出文本里就会看到 --icmpv6-type 相关的规则行。HLHop Limit匹配也是 IPv6 特有的类似于 IPv4 的 TTL。它常用于防转发环路或者限制某些流量只能在一个子网内传播。导出文本中对应的是 -m hl --hl-lt 这种参数格式。IPv6 分片处理也和 IPv4 不同。IPv6 只有源节点才能分片中间路由器不分片所以分片相关匹配在 IPv6 规则里的写法是 -m ipv6header 或者专门的分片匹配模块。我在实际环境中就遇到过因为漏掉了分片放行规则导致大包 ping 不通而小包正常的情况排了半天才发现是规则里没处理分片。3. 实操从导出到恢复完整工作流3.1 导出规则的正确姿势直接在终端里敲 ip6tables-save屏幕上会输出全部规则但这只是起步。实际使用时我一般会加一些参数或者结合重定向来做。最基础的做法是重定向到文件ip6tables-save /backup/ip6tables.rules如果只想看某个表的规则可以用 -t 参数ip6tables-save -t filter这里有个细节ip6tables-save 不加 -t 时会输出所有表这样恢复比较方便加了 -t 只输出指定表适合只想查看某个表的时候使用。我在写脚本时经常抓某个表做审计这种半结构化输出配合 grep 非常顺手。导出文件建议用 .rules 后缀方便和 iptables-save 导出的 .rules 文件区分。文件名里最好带上主机名和日期比如 ip6tables-firewall-20250115-web01.rules。这样后期查找历史版本时一眼就能看出是哪台机器、哪个时间点的快照。导出的权限也要注意。规则内容可能暴露业务端口和网络架构这类文件默认权限不要放开。我习惯在导出后执行 chmod 600确保只有 root 能读。3.2 恢复规则与启动时自动加载导出只是第一步真正的价值在于能顺利恢复。恢复用 ip6tables-restore基本用法ip6tables-restore /backup/ip6tables.rules这个命令会把文件里的规则整体加载到内核。它和逐条执行 ip6tables -A 不一样ip6tables-restore 会先清空对应表中原有规则再按文件内容重建。如果文件里包含多个表的定义它会依次处理。注意它不会清空没有在文件里出现的表。比如文件里只有 filter 表的定义那么 mangle 表的规则会原样保留。开机自动加载规则最常见的做法是把恢复命令写到启动脚本里。在 systemd 环境下可以创建一个服务单元比如 /etc/systemd/system/ip6tables-restore.service内容大致是[Unit] DescriptionRestore IPv6 firewall rules Beforenetwork-pre.target [Service] Typeoneshot ExecStart/usr/sbin/ip6tables-restore /etc/ip6tables.rules [Install] WantedBymulti-user.target之后 enable 这个服务再配合存放规则文件的路径开机时就会自动加载。不同发行版可能自带 ip6tables 服务比如 CentOS 7/8 上可以先把规则存到 /etc/sysconfig/ip6tables然后 systemctl enable ip6tables它会负责启动时加载。具体路径和名称以发行版为准但思路一致。3.3 一台服务器从 IPv4 迁移到双栈的规则迁移示例举一个实际的迁移场景一台原来只跑 IPv4 的 Web 服务器现在要接入 IPv6 双栈。防火墙规则需要同步支持 IPv6 流量。我当时的做法是分三步走。第一步先梳理业务需要的放行清单。这台服务器是 Nginx 反向代理对外放行 80/443 端口的入站流量出站流量默认放行SSH 管理端口只允许内网访问。这个清单无论 IPv4 还是 IPv6 都适用。第二步在测试环境里把 IPv6 规则写好先手动执行 ip6tables 命令逐条添加验证业务正常。比如ip6tables -P INPUT DROP ip6tables -P FORWARD DROP ip6tables -P OUTPUT ACCEPT ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT ip6tables -A INPUT -p ipv6-icmp -j ACCEPT ip6tables -A INPUT -i lo -j ACCEPT ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT第三步验证通过后用 ip6tables-save 导出成文件再优化规则结构对 ICMPv6 细化类型、增加防扫描策略等最终形成正式规则文件。迁移完成后对比导出的规则文本确认关键放行项没有遗漏。这个过程中有个容易犯的错直接照搬 IPv4 的规则思路把 ICMPv6 全部放行又觉得不够安全于是改成丢弃所有 ICMP。结果 IPv6 邻居发现失败网络直接不通。后来把需要的 ICMPv6 类型逐一放行问题才解决。4. 常见问题与排查技巧实录4.1 规则导出了但恢复失败恢复失败是最常见的问题报错大多是“line N failed”这种提示。原因往往出在模块缺失或者参数不兼容。比如在导出文件里有一条规则用到了 -m rt --rt-type 0但目标机器内核模块没加载或编译时没启用相应支持恢复时就会失败。排查思路是先确认目标机器内核是否支持对应匹配模块ls /lib/modules/$(uname -r)/kernel/net/ipv6/netfilter/看看有没有对应的 .ko 文件。如果没有要么换内核要么修改规则把涉及该模块的规则改成其他匹配方式。还有一种情况是版本差异。不同 Linux 发行版、不同版本的内核对某些参数的解析可能略有不同。我遇到过在 CentOS 7 上导出的规则拿到 Ubuntu 20.04 上恢复直接在 IPv6 段报错的情况。原因是两边 ip6tables 版本对 ipv6-icmp 匹配的写法有细微差异。解决办法最好是让源和目标机保持相同的发行版和内核版本或者恢复前先检查规则文件里的语法必要时手动调整。4.2 匹配不到的流量“静默放行”问题有时规则文件看起来没毛病恢复也成功了但某些流量就不对劲。IPv6 和 IPv4 在防火墙行为上的差异最容易让人栽跟头。最典型的例子就是 ICMPv6。有些人把 ICMP 全部 drop模仿 IPv4 的“安全策略”。但 IPv6 协议栈比 IPv4 更依赖 ICMPv6没有邻居通告地址解析就完蛋没有路由通告终端拿不到默认网关没有分包过大错误PMTU 发现就失效大包传输直接卡死。这些流量出问题时防火墙不会报任何错流量就像凭空消失了一样。排查这种问题思路是先抓包看状态。比如用 tcpdump 抓 icmp6 流量看看数据包是否到达了服务器到了服务器是否被防火墙丢弃。命令类似tcpdump -i eth0 ip6 icmp6如果抓包里能看到邻居请求Neighbor Solicitation但服务器不回邻居通告Neighbor Advertisement基本可以断定防火墙把 ICMPv6 的某个类型丢了。这在新装系统配置完规则后很常见也最容易让人误判成“IPv6 没配置好”。处理办法是放行必要的 ICMPv6 类型。我一般会放行 echo-request、echo-reply、destination-unreachable、packet-too-big、time-exceeded、parameter-problem、neighbor-solicitation、neighbor-advertisement、router-solicitation、router-advertisement 这些。具体的类型编号可以查 RFC 4443 对应关系但更快的办法是用 --icmpv6-type 参数配合 Tab 键自动补全系统会列出可选类型名。4.3 调试防火墙规则的三板斧规则配完不对怎么快速定位我基本靠三板斧查看、计数、抓包。第一板斧是实时查看规则计数。ip6tables 的 -L -v 会显示每条规则的匹配包数和字节数。如果规则没计数说明流量压根没经过这条规则要么是前面的规则已经匹配并放行/丢弃了要么是流量根本没到这张表。这个信息对定位规则顺序问题非常有帮助。ip6tables -L -v -n第二板斧是临时放通观察。怀疑防火墙丢包时可以临时加一条日志规则记录被丢弃的包。比如ip6tables -I INPUT -j LOG --log-prefix DROP6: --log-level warning然后去 /var/log/messages 或者 journalctl 里看日志。如果日志里刷出来很多被 DROP 的记录就能确定丢包发生在防火墙层还能看到具体是哪个协议的包。Debug 完记得把这条日志规则删掉不然日志会一直涨。第三板斧是 tcpdump 与规则对比。抓包能确认数据包是否到达服务器防火墙规则能确认到达后放行或丢弃。二者结合基本能把“物理网络问题”“协议栈问题”“防火墙问题”区分开。IPv6 环境下抓包要记得指定 ip6 过滤条件不然包太多刷不过来看。我排过最多的一类问题就是服务器本身 IPv6 地址、路由配置完全正常但外部访问不通。最后发现是防火墙默认策略 DROP 了 INPUT只放行了部分端口而业务监听的端口忘了加放行规则。这种情况通过第一板斧就能快速定位加规则后立即恢复。最后再分享一个规则文件管理的经验用 ip6tables-save 导出规则养成写注释的好习惯可能比规则本身更重要。规则文件是纯文本可以在里面加 # 开头的注释行说明每条规则是干什么的、当时的业务需求是什么、维护人是谁。我习惯在文件头部先写一段本文件的适用范围和最近变更记录。# File: ip6tables.rules # Host: web01 # Date: 2025-04-10 # Desc: IPv6 firewall rules for public web services # Change: 2025-04-10 allow https from all; restrict ssh to mgmt network *filter ... COMMIT这样做的好处是几个月后你回来看这个文件还能想起来当时的改动人是谁、为什么要这么改。双栈运维的复杂度比纯 IPv4 高不少规则文件本身又不像代码有 commit 历史只能靠注释和版本管理来弥补。我自己会把导出文件纳入 Git 仓库管理每次变更前 commit 一次出问题可以 diff 任意两个版本回溯非常方便。最后提醒一句规则文件保存的位置和文件名要统一最好在一台机器上有固定保存点。我在实际运维中发现有些同事喜欢把规则直接存到 /root 下文件名还随手写过几天自己都找不到。建议大家固定用 /etc/ip6tables.rules或者至少有一个专门的备份目录配合定时任务定期导出这样不管什么时候需要回滚都能找到最近一份可用配置。
返回列表