IPv6

出自 ArchWiki
(重定向自 Disabling IPv6

在 Arch Linux 中,默认启用 IPv6

tldp Linux+IPv6-HOWTO 文章较旧,维护较少。然而,它尝试涵盖本文中提到的许多主题,从基础知识开始,并以较慢的速度推进。它还包含许多命令行示例。初学者可能希望在阅读这篇 wiki 文章之前阅读或浏览它。

邻居发现

Ping 组播地址 ff02::1 会导致链路本地范围内的所有主机响应。必须指定接口

$ ping ff02::1%eth0

之后,您可以使用以下命令获取本地网络中所有邻居的列表

$ ip -6 neigh

使用 ping 组播地址 ff02::2 只有路由器会响应。

如果您添加选项 -I your-global-ipv6,链路本地主机将使用它们的链路全局范围地址进行响应。在这种情况下,可以省略接口

$ ping -I 2001:4f8:fff6::21 ff02::1

要 ping 所有接口上的所有人,并将您的地址通告给所有人,请使用脚本。

#!/usr/bin/bash
declare -a l_ifs
readarray l_ifs < <(/sbin/ip -6 -j address | jq -r '.[] | .ifname ')
for l_if in ${l_ifs[@]} ; do
 echo $l_if
 declare -a l_addrs
 readarray l_addrs < <(/sbin/ip -6 -j address show dev "$l_if" | \
                        jq -r  '.[0].addr_info[].local')
 for l_addr in ${l_addrs[@]} ; do
   echo $l_addr
   ping -c 4 -6 -I "$l_addr" ff02::1%"$l_if"
 done
done

无状态自动配置 (SLAAC)

只要您的网络已配置,获取 IPv6 地址的最简单方法是通过无状态地址自动配置(简称 SLAAC)。地址从您的路由器通告的前缀自动推断,既不需要进一步配置,也不需要专门的软件,例如 DHCP 客户端。

客户端

如果您使用 netctl,您只需要将以下行添加到您的以太网或无线配置中。

IP6=stateless

如果您使用 NetworkManager,如果网络中有针对 IPv6 地址的通告,它将自动启用 IPv6 地址。

请注意,无状态自动配置工作的条件是 IPv6 icmp 数据包在整个网络中被允许。因此,对于客户端,必须接受 ipv6-icmp 数据包。如果您使用 简单有状态防火墙/iptables,您只需要添加

-A INPUT -p ipv6-icmp -j ACCEPT

如果您使用其他防火墙前端(ufw、shorewall 等),请查阅其文档,了解如何启用 ipv6-icmp 数据包。

如果您选择的网络管理解决方案不支持使用无状态 IPv6 配置 DNS 解析器(例如 netctl),则可以使用 rdnssd(8),它来自 ndisc6 软件包。

网关

为了正确地将 IPv6 分发给网络客户端,我们需要使用通告守护进程。此任务的标准工具是 radvdradvd 的配置相当简单。编辑 /etc/radvd.conf 以包含

# replace LAN with your LAN facing interface
interface LAN {
  AdvSendAdvert on;
  MinRtrAdvInterval 3;
  MaxRtrAdvInterval 10;
  prefix ::/64 {
    AdvOnLink on;
    AdvAutonomous on;
    AdvRouterAddr on;
  };
};

上述配置将告诉客户端使用通告的 /64 区块中的地址自动配置自己。请注意,上述配置通告分配给面向 LAN 接口的所有可用前缀。如果您想限制通告的前缀,而不是 ::/64,请使用所需的前缀,例如 2001:DB8::/64prefix 区块可以重复多次以用于更多前缀。

要将 DNS 服务器通告给您的 LAN 客户端,您可以使用 RDNSS 功能。例如,将以下行添加到 /etc/radvd.conf 以通告 Google 的 DNS v6 服务器

RDNSS 2001:4860:4860::8888 2001:4860:4860::8844 {
};

网关还必须允许 ipv6-icmp 数据包在所有基本链上的流量。对于 简单有状态防火墙/iptables,添加

-A INPUT -p ipv6-icmp -j ACCEPT
-A OUTPUT -p ipv6-icmp -j ACCEPT
-A FORWARD -p ipv6-icmp -j ACCEPT

为其他防火墙前端进行相应调整,并且不要忘记启用 radvd.service

隐私扩展

当客户端通过 SLAAC 获取地址时,其 IPv6 地址是从通告的前缀和客户端网络接口的 MAC 地址派生的。这可能会引起隐私问题,因为计算机的 MAC 地址可以很容易地从 IPv6 地址推导出来。为了解决这个问题,开发了IPv6 隐私扩展标准 (RFC 4941)。使用隐私扩展,内核会生成一个临时地址,该地址是从原始自动配置的地址修改而来的。当连接到远程服务器时,首选私有地址,因此原始地址会被隐藏。要启用隐私扩展,请重现以下步骤

添加以下 sysctl 参数

/etc/sysctl.d/40-ipv6.conf
# Enable IPv6 Privacy Extensions
net.ipv6.conf.all.use_tempaddr = 2
net.ipv6.conf.default.use_tempaddr = 2
net.ipv6.conf.nic.use_tempaddr = 2

其中 nic 是您的。您可以使用网络配置#列出网络接口中的说明找到它们的名称。all.use_tempaddrdefault.use_tempaddr 参数不适用于在执行 sysctl 设置时已存在的网卡。

最迟在重启后,应启用隐私扩展。

dhcpcd

dhcpcd 的默认配置包括选项 slaac private,它启用“稳定的私有 IPv6 地址而不是基于硬件的地址”,实现 RFC 7217。因此,无需更改任何内容,除非希望比每次系统连接到新网络时更频繁地更改 IPv6 地址。将其设置为 slaac hwaddr 以获得稳定的地址。

NetworkManager

可以在 NetworkManager 中使用 ipv6.ip6-privacy 设置控制 IPv6 隐私扩展的使用,该设置位于 NetworkManager.conf(5) 或连接的配置文件中。如果未全局设置或未按连接设置,NetworkManager 将回退到读取 /proc/sys/net/ipv6/conf/default/use_tempaddr

要默认显式启用 IPv6 隐私扩展,请将以下行添加到 NetworkManager.conf(5)

/etc/NetworkManager/conf.d/ip6-privacy.conf
[connection]
ipv6.ip6-privacy=2

应用配置并重新连接到所有活动连接。

要控制针对单个 NetworkManager 管理的连接使用 IPv6 隐私扩展,请编辑 /etc/NetworkManager/system-connections/ 中所需的连接密钥文件,并在其 [ipv6] 部分附加键值对 ip6-privacy=2

/etc/NetworkManager/system-connections/example_connection.nmconnection
...
[ipv6]
method=auto
ip6-privacy=2
...

重新加载连接,然后重新连接。

注意: 尽管启用隐私扩展创建的 scope global temporary IPv6 地址似乎永远不会续订(在其 valid_lft 生存期结束时永远不会转移到 deprecated 状态),但需要在较长一段时间内验证此地址确实会更改。

systemd-networkd

systemd-networkd 默认不启用 IPv6 隐私扩展。要启用它们,请在每个连接的 .network 文件中的 [Network] 部分中设置 IPv6PrivacyExtensions=yes,或使用 /etc/systemd/networkd.conf.d/ 中的配置文件全局设置。例如

/etc/systemd/networkd.conf.d/ipv6-privacy-extensions.conf
[Network]
IPv6PrivacyExtensions=yes

除非 IPv6PrivacyExtensions 选项设置为 kernel,否则 systemd-networkd 不会遵守 sysctl 设置 net.ipv6.conf.nicN.use_tempaddr

IPv6 隐私扩展的其他选项,例如

变量名 描述
net.ipv6.conf.nicN.temp_prefered_lft 首选临时地址生存期,以秒为单位。请注意必须使用错误的拼写。
net.ipv6.conf.nicN.temp_valid_lft 最大临时地址生存期,以秒为单位。

但是,这些选项会被遵守。[1]

有关详细信息,请参阅 systemd-networkdsystemd.network(5)

ConnMan

在您的服务文件中使用以下设置

/var/lib/connman/service/settings
IPv6.privacy=preferred

有关详细信息,请参阅 ConnMan

稳定的私有地址

另一种选择是稳定的私有 IP 地址 (RFC 7217)。这允许 IP 在网络内稳定,而不会暴露接口的 MAC 地址。

为了让内核生成密钥(例如,对于 wlan0),我们可以设置

# sysctl net.ipv6.conf.wlan0.addr_gen_mode=3

将接口关闭并重新启动,运行 ip addr show dev wlan0 后,您应该会在每个 IPv6 地址旁边看到 stable-privacy。内核已为此接口生成 128 位密钥以生成 ip 地址,要查看它,请运行 sysctl net.ipv6.conf.wlan0.stable_secret。我们将持久化此值,因此将以下行添加到 /etc/sysctl.d/40-ipv6.conf

# Enable IPv6 stable privacy mode
net.ipv6.conf.wlan0.stable_secret = output_from_previous_command
net.ipv6.conf.wlan0.addr_gen_mode = 2
注意: 如果您使用 dhcpcd 获取 IPv6 地址,则 stable-privacy 标志将不会归属于此 IP 地址。

NetworkManager

NetworkManager 不遵守上述设置,但 NetworkManager 默认使用稳定的私有地址。[2][3]

systemd-networkd

systemd-networkd 不遵守上述设置。为确保始终使用稳定的私有地址,您可以设置

[IPv6AcceptRA]
Token=prefixstable

以上告诉 systemd-networkd 使用从机器 ID 派生的密钥。您还可以自己指定密钥,甚至仅将设置应用于路由器通告消息中出现的特定前缀。有关详细信息,请参阅 systemd.network(5)

如果需要,您还可以生成稳定的私有链路本地地址

[Network]
IPv6LinkLocalAddressGenerationMode=stable-privacy

静态地址

有时,使用静态地址可以提高安全性。例如,如果您的本地路由器使用邻居发现或 radvd (RFC 2461),您的接口将根据其 MAC 地址自动分配地址(使用 IPv6 的无状态自动配置)。这对于安全性来说可能不太理想,因为它允许即使 IP 地址的网络部分发生更改也能够跟踪系统。

要使用 netctl 分配静态 IP 地址,请查看 /etc/netctl/examples/ethernet-static 中的示例配置文件。以下行很重要

...
# For IPv6 static address configuration
IP6=static
Address6=('1234:5678:9abc:def::1/64' '1234:3456::123/96')
Routes6=('abcd::1234')
Gateway6='1234:0:123::abcd'
注意: 如果您仅连接 IPv6,则需要确定您的 IPv6 DNS 服务器。例如
DNS=('6666:6666::1' '6666:6666::2')
如果您的提供商没有给您 IPv6 DNS,并且您没有运行自己的 DNS 服务器,您可以从 resolv.conf 文章中选择。

IPv6 和 PPPoE

PPPoE 的标准工具 pppd(8) 提供对 PPPoE 上 IPv6 的支持,只要您的 ISP 和您的调制解调器支持它。只需将以下内容添加到 /etc/ppp/options

+ipv6

如果您使用 netctl 进行 PPPoE,那么只需将以下内容添加到您的 netctl 配置中即可

PPPoEIP6=yes

前缀委派 (DHCPv6-PD)

注意: 本节针对自定义网关配置,而不是客户端机器。对于标准市场路由器,请查阅路由器的文档,了解如何启用前缀委派。

前缀委派是许多 ISP 使用的常见 IPv6 部署技术。这是一种将网络前缀分配给用户站点(即本地网络)的方法。可以将路由器配置为将不同的网络前缀分配给各种子网。ISP 使用 DHCPv6(通常是 /56/64)分配网络前缀,dhcp 客户端将前缀分配给本地网络。对于简单的双接口网关,它实际上是将 IPv6 前缀从通过连接到 WAN 的接口(或伪接口,例如 ppp)获取的地址分配给连接到本地网络的接口。

DHCPv6 要求客户端接收端口 546 UDP 上的传入连接。对于基于 nftables 的防火墙,可以使用 /etc/nftables.conf 中输入链中的一行进行配置

table inet filter {
  chain input {
    udp dport dhcpv6-client accept
    ...
  }
...
}

使用 dhcpcd

dhcpcd 除了 IPv4 dhcp 支持外,还提供了 DHCPv6 客户端标准的相当完整的实现,其中包括 DHCPv6-PD。如果您使用 dhcpcd,请编辑 /etc/dhcpcd.conf。您可能已经在使用 dhcpcd 进行 IPv4,因此只需更新您现有的配置。

duid
noipv6rs
waitip 6
# Uncomment this line if you are running dhcpcd for IPv6 only.
#ipv6only

# The following applies to the interface WAN.
interface WAN
    ipv6rs
    # Assign WAN the iaid 1.
    iaid 1
    # Assign a Normal Address to the interface with iaid 1 (i.e. WAN).
    ia_na 1
    # Delegate a prefix with wan interface iaid 1 (i.e. WAN) and lan interface LAN.
    ia_pd 1 LAN
    #ia_pd 1/::/64 LAN/0/64

此配置将从 WAN 接口 (WAN) 请求前缀,并将其委派给内部接口 (LAN)。如果发出 /64 范围,您将需要使用注释掉的第二个 ia_pd 指令。它还将禁用除 WAN 接口 (WAN) 之外的所有接口上的路由器请求。

提示: 另请阅读 dhcpcd(8)dhcpcd.conf(5)

使用 WIDE-DHCPv6

WIDE-DHCPv6 是 IPv6 (DHCPv6) 的动态主机配置协议的开源实现,最初由 KAME 项目开发。可以使用 wide-dhcpv6AUR 安装

如果您使用 wide-dhcpv6,请编辑 /etc/wide-dhcpv6/dhcp6c.conf

# use the interface connected to your WAN
interface WAN {
  send ia-pd 0;
};

id-assoc pd 0 {
  # use the interface connected to your LAN
  prefix-interface LAN {
    sla-id 1;
    sla-len 8;
  };
};
注意: 应设置 sla-len,以便 (WAN 前缀) + (sla-len) = 64。在本例中,它设置为 /56 前缀 56+8=64。对于 /64 前缀,sla-len 应为 0

可以使用 dhcp6c@interface.service systemd 单元文件启动/启用 wide-dhcpv6 客户端,其中 interface 是配置文件中的接口名称,例如,对于接口名称“WAN”,使用 dhcp6c@WAN.service

提示: 阅读 dhcp6c(8)dhcp6c.conf(5) 了解更多信息。

systemd-networkd

配置您的上游 (wan) 和下游 (lan) 接口。这将启用运行 DHCPv6 客户端的接口上的 DHCPv6-PD。委派的前缀通过下游网络上的 IPv6 路由器通告分发。

/etc/systemd/network/wan.network
[Network]
# Use 'yes' instead of 'ipv6' for both ipv4 and ipv6.
DHCP=ipv6
/etc/systemd/network/lan.network
[Network]
IPv6SendRA=yes
DHCPv6PrefixDelegation=yes
提示: 另请阅读 systemd.network(5) § 示例

其他客户端

dhclient 也可以请求前缀,但将该前缀或该前缀的一部分分配给接口必须使用 dhclient 退出脚本来完成。例如:https://github.com/jaymzh/v6-gw-scripts/blob/master/dhclient-ipv6

NAT64

Wikipedia:NAT64 是 IPv6 过渡机制,其中仅 IPv6 主机能够使用 NAT 与 IPv4 主机通信。

Linux 内核本身不支持 NAT64,但有几个软件包可以添加对 NAT64 的支持。

  • Jool — Linux 的 SIIT 和 NAT64
https://nicmx.github.io/Jool/ || jool-dkmsAUR, jool-toolsAUR
  • TAYGA — NAT64 守护进程(未维护)
http://www.litech.org/tayga/ || taygaAUR

禁用 IPv4

此条目或章节需要扩充。

原因: 添加禁用旧 IP 的说明,尤其是在网络具有 NAT64 和 DNS64 的情况下,我们不需要维护双栈,CGN 的实施也降低了 ipv4 的性能和可用性(例如,现在通常只能使用 ipv6 和 dynv6.com 或 namecheap dyndns 记录等服务在家中托管 nextcloud。这是因为没有公共 ipv4 可用,即使对于 CPE 路由器也是如此)(在Talk:IPv6 中讨论)

在 systemd-networkd 中禁用 IPv4

此条目或章节的事实准确性存在争议。

原因: 这并没有“在 systemd-networkd 中禁用 IPv4”,它只是启用了仅 IPv6 的 DHCP 客户端。(在Talk:IPv6 中讨论)

这是 systemd-networkd 中仅 IPv6 接口的示例配置。

/etc/systemd/network/lan.network
[Match]
Name=eno0

[Link]
RequiredForOnline=routable

[Network]
# Enable IPv6 only
DHCP=ipv6
# Enable SLAAC
IPv6AcceptRA=true

禁用 IPv6

注意: Arch 内核直接内置了 IPv6 支持,因此无法将模块列入黑名单。

对于某些 ISP[4][5],IPv6 流量比 IPv4 流量慢:如果您可以确定您受到此类问题的影响,禁用 IPv6 可能会提高您的网络速度。

不应盲目执行此操作:对于大多数用户来说,仅 IPv4 网络会在 运营商级 NAT 之后降低性能,并妨碍他们使用 P2P 或 WebRTC 应用程序(例如某些游戏)。相反,配置优先使用 IPv4 而不是 IPv6 是两全其美的方法。

禁用功能

ipv6.disable=1 添加到内核行会禁用整个 IPv6 协议栈,如果您遇到问题,这很可能是您想要的。有关更多信息,请参阅 内核参数

或者,添加 ipv6.disable_ipv6=1 将保持 IPv6 协议栈的功能,但不会为您的任何网络设备分配 IPv6 地址。

sysctl

可以通过将以下 sysctl 配置添加到 /etc/sysctl.d/40-ipv6.conf 来禁用所有或特定网络接口的 IPv6 协议栈

# Disable IPv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.nic0.disable_ipv6 = 1
...
net.ipv6.conf.nicN.disable_ipv6 = 1

但是,只有在启动后重启 systemd-sysctl.service 后,此操作才有效,因为 systemd-sysctl.service 在网络接口完全配置之前启动。在启动时,只能设置 lodefaultall 的配置,因为它们是 IPv6 协议栈的内部组成部分。

提示: 如果 IPv6 协议栈未完全禁用,也可以在运行时禁用接口的 IPv6 以测试配置更改。执行 # sysctl -w net.ipv6.conf.all.disable_ipv6=1 会删除所有网络接口上分配的 IPv6 地址及其路由,并且可以撤消。
注意
  • 大多数网络管理器(netplansystemd-networkdNetworkManager 等)根据自己的配置设置已配置网络接口的 IPv6 协议栈状态,而忽略 net.ipv6.conf.default.disable_ipv6 中设置的配置。
  • 如果通过 sysctl 禁用 IPv6,您应该注释掉 /etc/hosts 中的 IPv6 主机。否则,可能会出现一些连接错误,因为主机被解析为其无法访问的 IPv6 地址。

systemd 单元

如果希望在启动时禁用所有网络接口的 IPv6 协议栈,并且能够稍后轻松启用 IPv6,则需要一个在网络管理器之后运行的 systemd 单元。

用于 systemd-networkd 的单元如下所示

/etc/systemd/system/enforce_disable_ipv6.service
[Unit]
Description=enforce default disable_ipv6
AssertPathExists=/proc/sys/net/ipv6/conf/all/disable_ipv6
AssertPathExists=/proc/sys/net/ipv6/conf/default/disable_ipv6
After=systemd-networkd.service
PartOf=systemd-networkd.service

[Service]
Type=oneshot
ExecStart=-/usr/bin/cp --no-preserve=all -T /proc/sys/net/ipv6/conf/default/disable_ipv6 /proc/sys/net/ipv6/conf/all/disable_ipv6

[Install]
WantedBy=systemd-networkd.service

启用此单元后,任何 systemd-networkd 的启动或重启都将强制所有网络接口上的 IPv6 协议栈状态的 default 值。

default 值可以在启动时使用 #sysctl 设置。

要为其他网络管理器调整此单元,需要将所有出现的 systemd-networkd.service 替换为您的网络管理器的配置单元。

其他程序

禁用内核中的 IPv6 功能并不能阻止其他程序尝试使用 IPv6。在大多数情况下,这是完全无害的,但如果您发现自己遇到该程序的问题,您应该查阅该程序的手册页,以了解禁用该功能的方法。

dhcpcd

dhcpcd 将继续无害地尝试执行 IPv6 路由器请求。要禁用此功能,如 dhcpcd.conf(5) 手册页 中所述,将以下内容添加到 /etc/dhcpcd.conf

noipv6rs
noipv6

NetworkManager

要在 NetworkManager 中禁用 IPv6,请右键单击网络状态图标,然后选择编辑连接 > 有线 > 网络名称 > 编辑 > IPv6 设置 > 方法 > 忽略/禁用。然后单击保存

这也可以通过以下方式完成

# nmcli connection modify ConnectionName ipv6.method "disabled"

然后重启网络连接

# nmcli connection up ConnectionName

要确认设置已应用,请使用 ip address show 并检查是否未显示 inet6 条目。或者,/proc/sys/net/ipv6/conf/interface/disable_ipv6 应具有值 1。

ntpd

按照 systemd#Drop-in 文件 中的建议,编辑 ntpd.service 以定义 systemd 如何启动它。

这将创建一个 drop-in 代码段,该代码段将代替默认的 ntpd.service 运行。-4 标志阻止 ntp 守护程序使用 IPv6。将以下内容放入 drop-in 代码段

[Service]
ExecStart=
ExecStart=/usr/bin/ntpd -4 -g -u ntp:ntp

它首先清除之前的 ExecStart,然后将其替换为包含 -4 标志的代码段。

GnuPG

dirmngr 的配置文件中禁用 IPv6

~/.gnupg/dirmngr.conf
disable-ipv6

重启 dirmngr.service 用户单元。

sshd

通过将以下内容添加到 sshd_config 来确保 sshd 正在使用 IPv4

/etc/ssh/sshd_config
AddressFamily inet

并重启 sshd.service

systemd-timesyncd

有时,即使已禁用 IPv6,systemd-timesyncd 也会尝试查询 IPv6 时间服务器。这可能会导致系统时钟未更新,并且日志显示类似于以下的错误

systemd-timesyncd[336]: Failed to set up connection socket: Address family not supported by protocol

systemd-timesyncd单元状态将在其状态条目中显示尝试使用 IPv6 地址连接,类似于

Status: "Connecting to time server [2001:19f0:8001:afd:5400:1ff:fe9d:cba]:123 (2.pool.ntp.org)"

根据 FS#59806,只有 “2.” ntp.org 池提供 IPv6 服务。因此,为防止这种情况,请从 /etc/systemd/timesyncd.conf 文件中的 NTP 和 FallbackNTP 条目中删除 2.arch.pool.ntp.org2.pool.ntp.org

systemd-networkd

networkd 支持在每个接口的基础上禁用 IPv6。当网络单元的 [Network] 部分具有 LinkLocalAddressing=ipv4LinkLocalAddressing=no 时,networkd 将不会尝试在匹配的接口上配置 IPv6。

但请注意,即使使用上述选项,如果未全局禁用 IPv6,networkd 仍然会期望接收路由器通告。如果接口未接收到 IPv6 流量(例如,由于 sysctlip6tables 设置),它将保持在配置状态,并可能导致等待网络完全配置的服务超时。为避免这种情况,还应在 [Network] 部分中设置 IPv6AcceptRA=no 选项。

优先使用 IPv4 而不是 IPv6

取消注释 /etc/gai.conf 中的以下行

#
#    For sites which prefer IPv4 connections change the last line to
#
precedence ::ffff:0:0/96  100

参见