ping6.net
安全

IPv6 防火墙配置:基本规则

为 IPv6 配置防火墙而不破坏连接。基本 ICMPv6 规则、Linux 示例和要避免的常见错误。

ping6.net2024年12月14日6 min read
IPv6防火墙安全iptablesnftablesICMPv6

IPv4 防火墙让你可以阻止 ICMP 而没有重大后果。IPv6 不是这样工作的。阻止错误的 ICMPv6 消息,你将破坏路径 MTU 发现、邻居发现和基本连接。你的防火墙将静默导致连接失败,需要数小时才能调试。

TL;DR - 快速摘要

要点:

  • ICMPv6 是必不可少的:与 IPv4 ICMP 不同,阻止 ICMPv6 会破坏基本网络操作
  • 允许特定类型:类型 1-3(错误)、128-129(ping)、133-136(NDP)是必需的
  • 永远不要阻止类型 2:Packet Too Big 消息对路径 MTU 发现至关重要
  • 对 NDP 使用跃点限制 255:防止来自链路外的邻居发现欺骗
  • 应用于所有协议族:不要忘记同时配置 iptables 和 ip6tables

跳转至: 基本 ICMPv6 类型 | Linux 示例 | 常见错误


为什么 IPv6 防火墙不同#

在 IPv4 中,ICMP 处理像 ping 和 traceroute 这样的诊断。你可以完全阻止它,大多数东西仍然可以工作。ARP 在第 2 层运行,DHCP 使用 UDP,路由器使用专用协议。

IPv6 将这些功能合并到 ICMPv6 中。地址解析、路由器发现和重复地址检测都依赖于特定的 ICMPv6 类型。阻止它们,主机无法找到它们的默认网关,邻居无法在同一链路上通信,当 MTU 不匹配时连接会挂起。

协议设计者故意做出这个选择。ICMPv6 是 IPv6 规范的一部分,而不是诊断附加组件。

基本 ICMPv6 类型#

你的防火墙必须允许这些 ICMPv6 类型以实现基本功能:

类型名称用途阻止这个?
1目标不可达端口/协议已关闭否 - 破坏 TCP
2数据包太大路径 MTU 发现永远不要 - 破坏连接
3超时跳数限制已达到否 - 破坏 traceroute
128回显请求Ping 请求可选(但为什么?)
129回显回复Ping 响应可选(但为什么?)
133路由器请求查找默认网关永远不要 - 破坏连接
134路由器通告网关通告永远不要 - 破坏连接
135邻居请求地址解析(ARP 等效)永远不要 - 破坏一切
136邻居通告地址解析响应永远不要 - 破坏一切

阻止 ICMPv6 类型 2、133、134、135 或 136 将以微妙、难以调试的方式破坏 IPv6 连接。不要这样做。

类型 2(数据包太大)值得特别注意。IPv6 在中间路由器上没有分片。当数据包超过路径 MTU 时,路由器删除它并发回数据包太大消息。阻止这个,初始 SYN/ACK 后连接会挂起。你将花费数小时调试为什么 HTTPS 工作但大传输失败。

Linux ip6tables 示例#

最小主机防火墙#

对于不路由流量的客户端机器或服务器:

# 刷新现有规则
ip6tables -F
ip6tables -X
 
# 默认策略
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT ACCEPT
 
# 允许环回
ip6tables -A INPUT -i lo -j ACCEPT
 
# 允许已建立的连接
ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
 
# 允许基本 ICMPv6
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 1 -j ACCEPT   # 目标不可达
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 2 -j ACCEPT   # 数据包太大
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 3 -j ACCEPT   # 超时
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 128 -j ACCEPT # 回显请求
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 129 -j ACCEPT # 回显回复
 
# 允许邻居发现(必须是跳数限制为 255 的链路本地)
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 133 -m hl --hl-eq 255 -j ACCEPT # 路由器请求
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 134 -m hl --hl-eq 255 -j ACCEPT # 路由器通告
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 135 -m hl --hl-eq 255 -j ACCEPT # 邻居请求
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 136 -m hl --hl-eq 255 -j ACCEPT # 邻居通告
 
# 允许 DHCPv6(如果需要)
ip6tables -A INPUT -p udp --dport 546 -j ACCEPT
 
# 记录丢弃的数据包(可选)
ip6tables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "ip6tables-dropped: "

跳数限制检查(--hl-eq 255)防止来自链路外源的欺骗邻居发现数据包。合法的邻居发现始终使用跳数限制 255。

服务器防火墙#

在 ICMPv6 规则后添加你的服务:

# SSH
ip6tables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
ip6tables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT
 
# HTTP/HTTPS
ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT
 
# DNS(如果运行 DNS 服务器)
ip6tables -A INPUT -p udp --dport 53 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 53 -j ACCEPT

SSH 规则使用 recent 实现基本速率限制。从同一地址在 60 秒内尝试 4 次连接后,其他尝试被删除。

路由器转发规则#

对于路由器或转发流量的系统:

ip6tables -P FORWARD DROP
 
# 允许已建立的连接
ip6tables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
 
# 允许 ICMPv6 转发(对于 PMTUD 至关重要)
ip6tables -A FORWARD -p ipv6-icmp --icmpv6-type 1 -j ACCEPT
ip6tables -A FORWARD -p ipv6-icmp --icmpv6-type 2 -j ACCEPT
ip6tables -A FORWARD -p ipv6-icmp --icmpv6-type 3 -j ACCEPT
ip6tables -A FORWARD -p ipv6-icmp --icmpv6-type 128 -j ACCEPT
ip6tables -A FORWARD -p ipv6-icmp --icmpv6-type 129 -j ACCEPT
 
# 允许内部网络访问互联网
ip6tables -A FORWARD -i eth1 -o eth0 -j ACCEPT

不要转发邻居发现消息(133-136)。那些仅是链路本地的。

Linux nftables 示例#

现代发行版使用 nftables 而不是 iptables。语法更清晰:

# 创建表
nft add table ip6 filter
 
# 创建链
nft add chain ip6 filter input { type filter hook input priority 0\; policy drop\; }
nft add chain ip6 filter forward { type filter hook forward priority 0\; policy drop\; }
nft add chain ip6 filter output { type filter hook output priority 0\; policy accept\; }
 
# 环回
nft add rule ip6 filter input iif lo accept
 
# 已建立的连接
nft add rule ip6 filter input ct state established,related accept
 
# ICMPv6
nft add rule ip6 filter input icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, echo-request, echo-reply } accept
 
# 带跳数限制检查的邻居发现
nft add rule ip6 filter input icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
 
# 带速率限制的 SSH
nft add rule ip6 filter input tcp dport 22 ct state new limit rate 4/minute accept
 
# HTTP/HTTPS
nft add rule ip6 filter input tcp dport { 80, 443 } accept

集合表示法({ 80, 443 })创建一个规则而不是两个,使规则集更有效。

Windows 防火墙#

Windows 防火墙默认为大多数基本类型启用 IPv6 ICMPv6,但你应该验证:

# 显示当前 ICMPv6 规则
Get-NetFirewallRule -DisplayName "*ICMPv6*" | Format-Table DisplayName, Enabled, Direction
 
# 启用所有 ICMPv6 入站(如果禁用)
Enable-NetFirewallRule -DisplayName "Core Networking - Destination Unreachable (ICMPv6-In)"
Enable-NetFirewallRule -DisplayName "Core Networking - Packet Too Big (ICMPv6-In)"
Enable-NetFirewallRule -DisplayName "Core Networking - Neighbor Discovery Solicitation (ICMPv6-In)"
Enable-NetFirewallRule -DisplayName "Core Networking - Neighbor Discovery Advertisement (ICMPv6-In)"
Enable-NetFirewallRule -DisplayName "Core Networking - Router Advertisement (ICMPv6-In)"
 
# 在 IPv6 上允许 SSH 服务器
New-NetFirewallRule -DisplayName "SSH (IPv6)" -Direction Inbound -Protocol TCP -LocalPort 22 -Action Allow -Profile Any -RemoteAddress Any

对于 Web 服务器:

New-NetFirewallRule -DisplayName "HTTP (IPv6)" -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow
New-NetFirewallRule -DisplayName "HTTPS (IPv6)" -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow

云安全组#

AWS#

安全组是有状态的,并自动允许已建立的返回流量。添加明确的规则:

  • ICMPv6:使用「所有 ICMPv6」或选择特定类型
  • 服务:添加你的 TCP/UDP 端口

Azure#

网络安全组(NSG)处理 IPv6。默认规则允许出站和已建立的流量。为服务添加入站规则。

GCP#

防火墙规则支持 IPv6。使用 --source-ranges=::/0 为 IPv6 创建单独的规则。默认规则不包括 ICMPv6,因此明确添加它。

所有三个提供商都要求你首先在 VPC/网络上启用 IPv6。IPv6 不是默认启用的。

常见错误#

阻止所有 ICMPv6#

最常见的 IPv6 防火墙错误。管理员移植阻止所有 ICMP 的 IPv4 规则,并想知道为什么 IPv6 不工作。如果你只记住这篇文章中的一件事:永远不要阻止所有 ICMPv6

没有 IPv6 防火墙规则#

一些管理员仔细配置 iptables,但完全忽略 ip6tables。然后 IPv6 完全开放。两个协议族都需要防火墙规则。

忘记出口过滤#

大多数示例只显示入口规则。如果你实施严格的出口过滤(你应该),允许出站 ICMPv6 类型 133、135 和 128。阻止出站邻居请求会阻止主机解析邻居。

邻居发现上的错误跳数限制#

接受邻居发现数据包而不检查跳数限制(255)允许攻击者从互联网上的任何地方发送欺骗的路由器或邻居通告。始终验证跳数限制。

允许太多#

启用「所有 ICMPv6」比阻止它全部更安全,但它仍然是过度的。你不需要允许来自互联网的多播侦听器发现消息,例如。使用特定类型。

测试你的防火墙#

配置规则后,验证基本连接:

# 测试 ping(需要 ICMPv6 类型 128/129)
ping6 -c 3 2001:4860:4860::8888
 
# 测试路径 MTU 发现(需要 ICMPv6 类型 2)
# 发送大数据包,验证它不会挂起
curl -6 -v https://ipv6.google.com/
 
# 检查邻居发现(需要类型 135/136)
ip -6 neigh show
 
# 验证路由(需要类型 133/134)
ip -6 route show

从另一台主机,测试未经授权的端口实际上被阻止:

# 应该超时或返回「连接被拒绝」
telnet -6 your:server::address 23
 
# 应该工作(如果允许 SSH)
ssh -6 your:server::address

使用在线扫描器,如 IPv6 端口扫描器(ipv6-tools.com)或 test-ipv6.com 从外部网络验证你的防火墙。


IPv6 防火墙需要理解 ICMPv6 的作用。该协议不是可选的或仅用于诊断。允许基本类型,验证邻居发现工作,并使用真实流量测试路径 MTU 发现。正确使用这些,你的 IPv6 防火墙将既安全又实用。

相关文章#