IPv6
在 Arch Linux 中,IPv6 是默认开启的。
tldp Linux+IPv6-HOWTO 这篇文章比较旧, 且缺乏维护。不过其涵盖了本文所提及的许多主题,从基础的东西讲起并且循序渐进到高级配置。而且还有很多命令的例子。初学者可以先读一读这篇文章再接着阅读本文。
邻居发现(Neighbor discovery,ND)[编辑 | 编辑源代码]
使用 Ping 命令来 ping ff02::1
这个多播地址,会得到本地链路层的所有主机的响应。需要手动指定接口(%eth0
)
$ ping ff02::1%eth0
Ping 完之后,您可以用如下命令来获取本地子网中的所有主机。
$ 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。只要您的网络配置好了「无状态地址自动配置」(Stateless address autoconfiguration,简称SLAAC),您的设备就会自动根据路由器广播(Router Advertisement,RA)的前缀为自己配置一个地址。既不需要进一步配置,也不需要专门的软件(如DHCP客户端)
客户端配置[编辑 | 编辑源代码]
如果您正在使用 netctl,您要做的只是往接口配置文件里加上这么一行:
IP6=stateless
如果您使用的是 NetworkManager,那么只要网络内有路由器广播,它就会自动配置上 IPv6 地址。
不过需要注意的是,SLAAC只有在网络允许 IPv6 ICMP 包通过的时候才能工作。所以你需要在客户端防火墙上允许 ipv6-icmp
类型的数据包传入。如果您用的是 Simple stateful firewall/iptables,加上下面这行就可以了:
-A INPUT -p ipv6-icmp -j ACCEPT
如果您用的是其他防火墙,请参考对应的文档来放行 ipv6-icmp
数据包。
如果你选择的网络管理方案不支持通过SLAAC配置DNS(比如netctl),那么你可以考虑用ndisc6包包里的rdnssd(8)命令来配置DNS。
路由器(网关)配置[编辑 | 编辑源代码]
要正确给网络内的客户端分配 IPv6,我们要用到一个广播守护进程,一般是radvd包。其配置过程其实相当简单。参考下面的配置来编辑 /etc/radvd.conf
文件。
# 把LAN替换为你实际的局域网接口 interface LAN { AdvSendAdvert on; MinRtrAdvInterval 3; MaxRtrAdvInterval 10; prefix ::/64 { AdvOnLink on; AdvAutonomous on; AdvRouterAddr on; }; };
以上配置会让客户端自己从 /64 地址段中选择地址来使用。请注意如果配置了 prefix ::/64
,RADVD会向局域网广播那个接口上的所有可用的前缀。如果您想要广播指定的前缀,请手动指定,比如 prefix 2001:DB8::/64
。prefix
节可以根据需要多次重复来广播多个不同前缀。
您可以通过 RDNSS 功能向客户端广播 DNS,以 Google DNS 为例,配置如下:
RDNSS 2001:4860:4860::8888 2001:4860:4860::8844 { };
网关必须在所有链上允许 ipv6-icmp
类型数据包通过。以 Simple stateful firewall/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 地址计算而得出的。这可能会引起隐私问题,因为别人可以轻易通过 IPv6 SLAAC 地址反推客户端 MAC。为了解决这个问题,RFC 4941 中提出了 IPv6 隐私拓展标准。启用隐私扩展后,内核会生成一个临时地址,这个地址是原来的 SLAAC 地址经过二次计算得出的随机地址。当主动连接到远程服务器时,会优先选择使用私有地址,从而帮助隐藏原始的 SLAAC地址。启用隐私扩展的步骤如下:
向 /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.nic0.use_tempaddr = 2 ... net.ipv6.conf.nicN.use_tempaddr = 2
上面的 nic0
到 nicN
是你的网络接口。你可以参考网络配置#Listing network interfaces 来列出你的设备上的接口。 all.use_tempaddr
或者 default.use_tempaddr
参数对于执行 sysctl 设置时已经存在的接口无效,也就是说不会即时生效。
不过当您重启设备之后,隐私拓展应该就会生效了。
dhcpcd[编辑 | 编辑源代码]
dhcpcd 的默认配置已经包括了 slaac private
,这会启用 RFC 7217 中定义的「稳定的私有IPv6地址而不是基于硬件的地址」功能。因此,您无需修改任何设置,除非您希望更频繁地获得新的随机地址,而不仅在连接到新网络的时候改变IPv6地址。您还可以设置 slaac hwaddr
来使用普通的基于 MAC 生成的固定 IPv6 后缀。
NetworkManager[编辑 | 编辑源代码]
您可以修改 NetworkManager 的全局配置文件 NetworkManager.conf(5) 或连接配置中的 ipv6.ip6-privacy
选项,来决定是否启用 IPv6 隐私拓展。如果全局配置和连接配置都没有设置该选项,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/
目录下的 keyfile,并把 ip6-privacy=2
添加到 [ipv6]
一节下方,示例如下:
/etc/NetworkManager/system-connections/example_connection.nmconnection
... [ipv6] method=auto ip6-privacy=2 ...
最后,重新加载连接配置并再次连接。
scope global temporary
IPv6 地址看上去永远不会被更新(在其 valid_lft
所显示的生命周期内,该地址永远不会变为 deprecated
状态),但经过较长时间的验证,这个地址 确实 会发生变化。systemd-networkd[编辑 | 编辑源代码]
systemd-networkd 同样不遵守 /etc/sysctl.d/40-ipv6.conf
中配置的 net.ipv6.conf.xxx.use_tempaddr
内核参数,除非您在 .network 文件中指定 IPv6PrivacyExtensions
选项的值为 kernel
。
不过 systemd-networkd 遵守其他 IPv6 隐私拓展的内核参数,比如:
net.ipv6.conf.xxx.temp_prefered_lft net.ipv6.conf.xxx.temp_valid_lft
temp_prefered_lft
才是正确的变量名,「preferred」应该是拼错了请参考 systemd-networkd 和 systemd.network(5) 以了解更多信息。
ConnMan[编辑 | 编辑源代码]
在服务文件(比如 /var/lib/connman/service/settings
)中设置:
IPv6.privacy=preferred
请参考 ConnMan 以了解更多信息。
稳定的隐私地址[编辑 | 编辑源代码]
另外一个选择,是使用 RFC 7217 中定义的稳定隐私地址。它可以在不暴露 MAC 地址的情况下固定住网络中的 IPv6 地址。
Another option is a stable private IP address (RFC 7217). This allows for IPs that are stable within a network without exposing the MAC address of the interface.
以 wlan0
接口为例,使用以下命令来让内核为其生成一个密钥:
# sysctl net.ipv6.conf.wlan0.addr_gen_mode=3
把接口关闭再启用,然后运行 ip addr show dev wlan0
,您应该会看到每个 IPv6 地址旁边会有 stable-privacy
标志。内核已经为该接口生成了一个 128 位的密钥用于产生稳定 IPv6 地址,您可以运行 sysctl net.ipv6.conf.wlan0.stable_secret
来查看这一密钥。我们需要固定这个密钥以让他每次重启后都获得同样的地址,所以请在 /etc/sysctl.d/40-ipv6.conf
中进行如下配置:
# Enable IPv6 stable privacy mode net.ipv6.conf.wlan0.stable_secret = 刚才查看的密钥 net.ipv6.conf.wlan0.addr_gen_mode = 2
stable-privacy
标志 不会 被应用到由 dhcpcd 获得的 IPv6 地址上NetworkManager[编辑 | 编辑源代码]
NetworkManager 不遵守以上设置,但是它默认已经启用了稳定隐私地址。[1][2]
静态地址[编辑 | 编辑源代码]
有些情况下使用静态地址可以增强安全性。使用SLAAC分配动态地址时,你的计算机的地址会由其网卡MAC推算出,这不利于安全,因为即使地址的网络号改变,你的电脑依然可以被追踪到。
要想用netctl分配一个静态地址,可以参照/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'
DNS=('6666:6666::1' '6666:6666::2')如果你的ISP没有告诉你IPv6的DNS服务器地址,并且你也没有自己的服务器,你可以从resolv.conf这篇文章中选一个。
IPv6与PPPoE[编辑 | 编辑源代码]
PPPoE的软件包pppd
提供了对PPPoE之上的IPv6的支持(前提是你的ISP和调制解调器支持)。只需要将如下内容加入/etc/ppp/pppoe.conf
:
+ipv6
如果你使用netctl,那么就向你的netctl配置文件加入如下内容:
PPPoEIP6=yes
地址委派 (DHCPv6-PD)[编辑 | 编辑源代码]
地址委派是一种常见的 IPv6 部署方式,被许多 ISP 所采用。具体的做法是将一个地址前缀分配给用户(局域网),即路由器配置为将不同的前缀分配给不同的子网;ISP 通过 DHCPv6 将地址前缀(通常是/56
或/64
)分发出去,DHCP 客户端再将前缀分配给局域网。对于一个拥有两个网卡的简单网关来说,它的工作就是将从 WAN 口(或虚拟接口,比如ppp)获取的前缀分配给局域网。
DHCPv6 客户端需要在 UDP 546 接口上接受传入的连接。对于基于 nftables 的防火墙,可以编辑 /etc/nftables.conf
:
table inet filter { chain input { udp dport dhcpv6-client accept ... } ... }
使用dhcpcd[编辑 | 编辑源代码]
Dhcpcd在 IPv4 之外也提供了一个完整的支持 DHCPv6-PD 的客户端。如果你使用 dhcpcd
,需要修改 /etc/dhcpcd.conf
。你可能已经在用dhcpcd来配置 IPv4,,所以只需要对现有的配置进行小幅修改:
duid noipv6rs waitip 6 # Uncomment this line if you are running dhcpcd for IPv6 only. #ipv6only # use the interface connected to WAN interface WAN ipv6rs iaid 1 # use the interface connected to your LAN ia_pd 1 LAN #ia_pd 1/::/64 LAN/0/64
这种配置下,客户端会从WAN
接口获取一个前缀,分配给LAN
接口。
如果ISP分配的是/64
的地址,你需要用第二个ia_pd
选项。
这也会禁用除WAN
接口之外的所有路由器请求。
dhcpcd(8)
与dhcpcd.conf(5)
获得更多信息。使用WIDE-DHCPv6[编辑 | 编辑源代码]
WIDE-DHCPv6是原本由KAME计划开发的DHCPv6开源实现。它在AUR中: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-prefix) + (sla-len) = 64
的值。这里示范的情况是针对一个长度/56
的前缀,56+8=64。对于前缀长度/64
的网络,sla-len
应为0
。要启用或运行wide-dhcpv6,使用如下命令。把WAN
改为连接到ISP的网卡:
# systemctl enable/start 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
其他客户端[编辑 | 编辑源代码]
dhclient 也可以请求前缀;但想要把整个或者部分前缀分配到接口上则需要使用 dhclient 退出脚本来完成。请参考 https://github.com/jaymzh/v6-gw-scripts/blob/master/dhclient-ipv6 中的例子。
NAT64[编辑 | 编辑源代码]
Wikipedia:NAT64 是让只有 IPv6 地址的主机通过使用 NAT 来和 IPv4 主机通信的过渡机制。
Linux 内核并不原生支持 NAT64,但您可以使用以下这些软件包来添加 NAT64 支持:
- Jool — SIIT and NAT64 for Linux
- https://nicmx.github.io/Jool/ || jool-dkmsAUR, jool-toolsAUR
- TAYGA — NAT64 daemon (unmaintained)
禁用 IPv6[编辑 | 编辑源代码]
关闭 IPv6 功能[编辑 | 编辑源代码]
如果您遇到一些问题,可以试着向内核参数加入 ipv6.disable=1
,来完全关闭 IPv6 功能, 参考内核参数来了解更多信息.
此外,只加入ipv6.disable_ipv6=1
内核参数可以保留IPv6功能,但不会向网卡分配IPv6地址。
也可以通过向/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
单元来应用上述设置。
注意你必须在这里清楚地列出所有不需要分配IPv6地址的网卡,仅仅设置all.disable_ipv6
并不会立刻对已经连接的网卡起作用。
/etc/hosts
中删除所有的IPv6主机,否则当你使用主机名连接它们的时候会解析到不通的IPv6地址其他应用程序[编辑 | 编辑源代码]
在内核中关闭 IPv6 功能不会阻止应用程序尝试使用 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
看看还有没有显示 IPv6 地址(inet6)。或者检查 /proc/sys/net/ipv6/conf/interface/disable_ipv6
这个内核参数,其值应该为 1。
ntpd[编辑 | 编辑源代码]
依照Systemd#Drop-in files,修改ntpd.service
的启动方式。
# systemctl edit ntpd.service
这样会产生一个drop-in snippet,替代原有的ntpd.service
来加载ntpd。参数-4
关闭了ntpd的IPv6支持。向drop-in snippet中加入如下内容:
[Service] ExecStart= ExecStart=/usr/bin/ntpd -4 -g -u ntp:ntp
第一行清除了之前的ExecStart
配置,接下来的一行将该配置设置为带有-4
参数的ntpd。
GnuPG[编辑 | 编辑源代码]
在 dirmngr 配置文件中设置如下参数:
~/.gnupg/dirmngr.conf
disable-ipv6
然后重启 dirmngr.service
服务.
sshd[编辑 | 编辑源代码]
修改 sshd_config
来让 sshd 只使用 IPv4:
/etc/ssh/sshd_config
AddressFamily inet
然后重启 sshd.service
服务
systemd-timesyncd[编辑 | 编辑源代码]
有时 Systemd-timesyncd 会尝试查询IPv6时间服务器,即使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。所以将 2.arch.pool.ntp.org
和 2.pool.ntp.org
从配置文件 /etc/systemd/timesyncd.conf
的 NTP 和 FallbackNTP 部分中删去即可避免这一现象。
systemd-networkd[编辑 | 编辑源代码]
networkd 支持按接口禁用IPv6。当网络单元的 [Network]
部分的 LinkLocalAddressing=ipv4
或 LinkLocalAddressing=no
时,networkd不会尝试在匹配的接口上配置IPv6。
然而,请注意,即使在使用上述选项时,如果 IPv6 未被全局禁用,networkd 仍会收到路由器通告。如果接口未接收到IPv6流量(例如,由于 sysctl 或 ip6tables 设置),它将保持在配置状态,并可能导致等待网络完全配置的服务超时。为了避免这种情况,还应在 [Network]
部分设置 IPv6AcceptRA=no
选项。
参见[编辑 | 编辑源代码]
- IPv6 — kernel.org documentation
- IPv6 temporary addresses — a summary about temporary addresses and privacy extensions
- IPv6 prefixes — a summary of prefix types
- net.ipv6 options — documentation of kernel parameters