我的提供商互联网路由器使用 IPv6 地址时出现了问题,我意识到我并不真正了解如何使用 IPv6 地址。为了了解情况,我喜欢问如何使用不同的 IPv6 地址类型,例如,在它们之间只有一个路由器的情况下将流量从一个主机路由到另一个主机。
Using three nodes:
┏━━━━━━━━━┓ addr: 2001:db8:0:10::1/64 addr: 2001.db8:0:20::1/64 ┏━━━━━━━━━┓
┃ host-a ┃ ╲ ┏━━━━━━━━━━┓ ╱ ┃ host-b ┃
┃ eth0┣════════════════════════┫eth0 eth1┣════════════════════════┫eth0 ┃
┗━━━━━━━━━┛ ╲ ┃ router ┃ ╱ ┗━━━━━━━━━┛
addr: 2001:db8:0:10::2/64 ┗━━━━━━━━━━┛ addr: 2001:db8:0:20::2/64
subnet: 2001:db8:0:10::/64 subnet: 2001:db8:0:20::/64
我该如何设置它?
答案1
到目前为止,我还没有找到像这样的简单示例,可以通过参考资料来了解基础知识。这更像是一个概念证明,但我花了一些精力,所以我将逐步与社区分享。
准备工作
我在 KVM(基于内核的虚拟机)上使用三台虚拟机,全部使用 Debian 11(bullseye,当前为测试版本),并使用来自RFC 2460:
节点是启用 IPv6 的接口。
路由器是转发未明确发送给它的 IPv6 数据包的任何节点。
主持人是任何非路由器的节点。
我们需要一些辅助程序,只要我们在节点上有互联网访问,就应该安装这些程序,然后再重新配置其网络接口以进行测试。在所有节点上安装radvdump
,在路由器上安装radvd
。确保已radvd
禁用,否则会使测试混乱。我将使用它tcpdump
来查看网络上发生的事情,因此将其安装在路由器上。在 Debian 上,我使用以下方法完成所有这些操作:
~$ sudo apt install radvdump # on hosts and router
router ~$ sudo apt install radvd # only on the router
router ~$ sudo systemctl disable --now radvd.service
router ~$ sudo apt install tcpdump # only on the router
我使用 IPv6 地址前缀2001:DB8::/32保留用于文档 (RFC 3849) 可用于有效的全球单播地址,但不能路由到互联网。
为了方便使用,这里有一些规格:
有一些地址类型可用(RFC 4291)
Unspecified ::/128
Loopback ::1/128
default route ::/0
Multicast FF00::/8
Unique Local unicast FD00::/8
Global Unicast (everything else)
Global Anycast (same as Global Unicast) not used in this example
多播地址的范围(RFC 4291):
FF00:: reserved
FF01:: Interface-Local scope
FF02:: Link-Local scope
FF03:: reserved
FF04:: Admin-Local scope
FF05:: Site-Local scope
FF06:: to FF07:: (unassigned)
FF08:: Organization-Local scope
FF09:: to FF0D:: (unassigned)
FF0E:: Global scope
FF0F:: reserved
众所周知的 IPv6 多播地址(摘录 - 完整列表位于互联网号码分配机构):
ff02::1 all nodes
ff02::2 all routers
ff02::5 all OSPF (Open Shortest Path First) routers
ff02::6 all OSPF DRs (OSPF Designated Routers)
ff02::9 all RIP (Routing Information Protocol) routers
ff02::a all EIGRP (Enhanced Interior Gateway Routing Protocol) routers
ff02::c SSDP (Simple Service Discovery Protocol)
ff02::d all PIM (Protocol Independent Multicast) routers
ff02::f UPNP (Universal Plug and Play) devices
ff02::11 all homenet nodes
ff02::12 VRRP (Virtual Router Redundancy Protocol)
ff02::16 all MLDv2-capable routers
ff02::1a all RPL (Routing Protocol for Low-Power and Lossy Networks) routers (used in Internet of Things (IoT) devices)
ff02::fb multicast DNS IPv6
ff02::101 network time (NTP)
ff02::1:2 all DHCP agents
ff02::1:3 LLMNR (Link-Local Multicast Name Resolution)
ff02:0:0:0:0:1:ff00::/104 solicited node address
ff02:0:0:0:0:1-2:ff00::/104 node information query
ff05::1:3 all DHCP server (site)
ff05::101 all NTP server (site)
使能够systemd-networkd依照指示
部分快步在使用 systemd-networkd 进行常规网络通信,然后回到这里。
我将禁用所有内容,以便我们可以看到需要什么,并逐步启用它。打开host-a
并host-b
使用此网络文件:
host-? ~$ sudo -Es # if not already done
host-? ~# cat > /etc/systemd/network/04-wired.network <<EOF
[Match]
Name=eth0
[Network]
# on host-a uncomment
#Address=2001:db8:0:10::2/64
# on host-b uncomment
#Address=2001:db8:0:20::2/64
IPv6AcceptRA=no
LinkLocalAddressing=no
EOF
在路由器上使用这些:
router ~$ sudo -Es # if not already done
router ~# cat > /etc/systemd/network/04-eth0.network <<EOF
[Match]
Name=eth0
[Network]
Address=2001:db8:0:10::1/64
IPv6AcceptRA=no
LinkLocalAddressing=no
EOF
router ~# cat > /etc/systemd/network/06-eth1.network <<EOF
[Match]
Name=eth1
[Network]
Address=2001:db8:0:20::1/64
IPv6AcceptRA=no
LinkLocalAddressing=no
EOF
简单的链路本地连接
首先,我将查看host-a
和 之间的直接连接router
。路由器已启动,我启动host-a
。tcpdump
子网 2001:db8:0:10/64 上显示:
host-a ~$ sudo tcpdump -n --number --interface=eth0 ip6 2>/dev/null
1 23:25:28.211331 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28
2 23:25:28.227326 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 2 group record(s), length 48
3 23:25:28.671386 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28
4 23:25:28.735354 IP6 :: > ff02::1:ff00:2: ICMP6, neighbor solicitation, who has 2001:db8:0:10::2, length 32
- 包 1-3
host-a
作为侦听器加入多播组ff02::16
- 所有支持 MLDv2 的路由器。路由器现在知道它想要接收路由消息。 - 对于包 4,它询问是否有另一个节点的 IP 地址为 2001:db8:0:10::2。没有,因为没有回复。
host-a
可以使用该地址。
ping 至router
工作区:
host-a ~$ ping6 -n 2001:db8:0:10::1
PING 2001:db8:0:10::1(2001:db8:0:10::1) 56 data bytes
64 bytes from 2001:db8:0:10::1: icmp_seq=1 ttl=64 time=0.829 ms
64 bytes from 2001:db8:0:10::1: icmp_seq=2 ttl=64 time=0.863 ms
64 bytes from 2001:db8:0:10::1: icmp_seq=3 ttl=64 time=0.858 ms
--- snip ---
链路本地单播地址
下一步我想连接到第二个接口eth1为此router
,我们需要一条静态路由:
host-a ~$ sudo ip -6 route add 2001:db8:0:20::/64 via 2001:db8:0:10::1
但ping6 -n 2001:db8:0:20::1
不能稳定工作:
host-a ~$ ping6 -n 2001:db8:0:20::1
PING 2001:db8:0:20::1(2001:db8:0:20::1) 56 data bytes
64 bytes from 2001:db8:0:20::1: icmp_seq=1 ttl=64 time=0.881 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=2 ttl=64 time=0.784 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=3 ttl=64 time=0.898 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=4 ttl=64 time=0.799 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=5 ttl=64 time=0.805 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=6 ttl=64 time=1.13 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=7 ttl=64 time=0.795 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=8 ttl=64 time=0.790 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=9 ttl=64 time=0.793 ms
^^^^^^^^^^
64 bytes from 2001:db8:0:20::1: icmp_seq=55 ttl=64 time=1025 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=56 ttl=64 time=3.26 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=57 ttl=64 time=0.793 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=58 ttl=64 time=0.792 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=59 ttl=64 time=0.789 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=60 ttl=64 time=0.776 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=61 ttl=64 time=0.803 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=62 ttl=64 time=0.801 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=63 ttl=64 time=0.774 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=64 ttl=64 time=0.802 ms
^^^^^^^^^^^
64 bytes from 2001:db8:0:20::1: icmp_seq=110 ttl=64 time=2049 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=111 ttl=64 time=1025 ms
--- snip ---
^C
--- 2001:db8:0:20::1 ping statistics ---
170 packets transmitted, 35 received, 79.4118% packet loss, time 172432ms
rtt min/avg/max/mdev = 0.774/205.826/2048.843/536.218 ms, pipe 3
如果您跟踪该seq
数字,您将看到 ping 延迟为 1 秒,大约 10 秒后中断,大约 45 秒后重复,数据包丢失率约为 80%。这不能称为稳定。我不太明白,但在查找故障排除时了解这种行为很有用。无论如何,它超出了规范,因为对于链路上的连接(2001:db8:0:10:2 到 2001:db8:0:10:1),必须使用链路本地地址指定于RFC 4291 - 链路本地 IPv6 单播地址:
链路本地地址旨在用于单个链路上的寻址,以实现自动地址配置、邻居发现或不存在路由器等目的。
检查接口上的链路本地地址。没有:
host-a ~$ ip -6 -br addr
lo UNKNOWN ::1/128
eth0 UP 2001:db8:0:10::2/64
LinkLocalAddressing=ipv6
我在所有节点的所有文件中启用它/etc/systemd/network/*.network
,然后重新启动、检查并 ping:
host-a ~$ ip -6 -br addr
lo UNKNOWN ::1/128
eth0 UP 2001:db8:0:10::2/64 fe80::5054:ff:febc:adbe/64
router ~$ ip -6 -br addr
lo UNKNOWN ::1/128
eth0 UP 2001:db8:0:10::1/64 fe80::5054:ff:fe0f:194e/64
eth1 UP 2001:db8:0:20::1/64 fe80::5054:ff:fe0f:194e/64
host-b ~$ ip -6 -br addr
lo UNKNOWN ::1/128
eth0 UP 2001:db8:0:20::2/64 fe80::5054:ff:fe9b:34b9/64
host-a ~$ sudo ip -6 route add 2001:db8:0:20::/64 via 2001:db8:0:10::1
host-a ~$ ping6 -n 2001:db8:0:20::1
PING 2001:db8:0:20::1(2001:db8:0:20::1) 56 data bytes
64 bytes from 2001:db8:0:20::1: icmp_seq=9 ttl=64 time=2.08 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=10 ttl=64 time=0.780 ms
64 bytes from 2001:db8:0:20::1: icmp_seq=11 ttl=64 time=0.783 ms
--- snip ---
作品。
静态路由
如果我尝试从 连接host-a
到 ,host-b
则ping6 -n 2001:db8:0:20::2
失败。这是因为router
不在其接口之间转发包。我们必须启用它。只需附加IPForward=ipv6
到*.network
文件即可。我们还需要一个静态路由,host-b
以便它知道将回复发送到哪里host-a
。我们现在将持久化。因此您将获得以下.network
文件:
主机a
host-a ~$ cat /etc/systemd/network/04-wired.network
[Match]
Name=eth0
[Network]
Address=2001:db8:0:10::2/64
IPv6AcceptRA=no
LinkLocalAddressing=ipv6
[Route]
Destination=2001:db8:0:20::/64
Gateway=2001:db8:0:10::1
路由器
router ~$ cat /etc/systemd/network/04-eth0.network
[Match]
Name=eth0
[Network]
Address=2001:0DB8:0:10::1/64
IPv6AcceptRA=no
LinkLocalAddressing=ipv6
IPForward=ipv6
router ~$ cat /etc/systemd/network/06-eth1.network
[Match]
Name=eth1
[Network]
Address=2001:0DB8:0:20::1/64
IPv6AcceptRA=no
LinkLocalAddressing=ipv6
IPForward=ipv6
主机-b
host-b ~$ cat /etc/systemd/network/04-wired.network
[Match]
Name=eth0
[Network]
Address=2001:db8:0:20::2/64
IPv6AcceptRA=no
LinkLocalAddressing=ipv6
[Route]
Destination=2001:db8:0:10::/64
Gateway=2001:db8:0:20::1
路由器通告
静态路由不太方便。这通常是自动完成的。主机可以向路由器询问其配置。要支持它,您必须IPv6AcceptRA=yes
在其/etc/systemd/*.network
文件中启用它。如果您这样做,您会在tcpdump
启动主机时发现:
host-a ~$ sudo tcpdump -n --number --interface=eth0 ip6 2>/dev/null
1 18:06:20.965014 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28
2 18:06:20.976965 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 2 group record(s), length 48
4 18:06:21.701148 IP6 :: > ff02::1:ffbc:adbe: ICMP6, neighbor solicitation, who has fe80::5054:ff:febc:adbe, length 32
5 18:06:21.861153 IP6 :: > ff02::1:ff00:2: ICMP6, neighbor solicitation, who has 2001:db8:0:10::2, length 32
7 18:06:22.725190 IP6 fe80::5054:ff:febc:adbe > ff02::16: HBH ICMP6, multicast listener report v2, 3 group record(s), length 68
9 18:06:24.225649 IP6 fe80::5054:ff:febc:adbe > ff02::2: ICMP6, router solicitation, length 16
10 18:06:27.851217 IP6 fe80::5054:ff:febc:adbe > ff02::2: ICMP6, router solicitation, length 16
11 18:06:35.087287 IP6 fe80::5054:ff:febc:adbe > ff02::2: ICMP6, router solicitation, length 16
--- snip ---
除了已知的软件包之外,我们multicast listener report v2
还找到了其他软件包。通过此消息,主机正在向路由器请求接口配置。但是路由器没有响应,因此主机继续询问。在 Linux 上,IPv6 路由器不会立即回复路由器请求。它需要额外的服务来管理这一点。我们已经安装了它,但已禁用它。使用 Debian 中的简单示例,我们现在配置并启用它:neighbor solicitation
router solicitation
router
radvd
/usr/share/doc/radvd/examples/simple-radvd.conf
router ~$ sudo -Es # if not already done
router ~# cat > /etc/radvd.conf <<EOF
interface eth0
{
AdvSendAdvert on;
prefix 2001:db8:0:10::/64
{
};
};
interface eth1
{
AdvSendAdvert on;
prefix 2001:db8:0:20::/64
{
};
};
EOF
~# systemctl enable radvd.service
因为我们希望主机现在从路由器获取其配置,所以我们必须从其.network
文件中删除手动设置。它们应该如下所示:
主机a和主机-b:
host-? ~$ cat /etc/systemd/network/04-eth0.network
[Match]
Name=eth0
[Network]
IPv6AcceptRA=yes
LinkLocalAddressing=ipv6
路由器:
router ~$ cat /etc/systemd/network/04-eth0.network
[Match]
Name=eth0
[Network]
Address=2001:db8:0:10::1/64
IPv6AcceptRA=no
LinkLocalAddressing=ipv6
IPForward=ipv6
router ~$ cat /etc/systemd/network/06-eth1.network
[Match]
Name=eth1
[Network]
Address=2001:db8:0:20::1/64
IPv6AcceptRA=no
LinkLocalAddressing=ipv6
IPForward=ipv6
重新启动所有节点,您应该有一个自动配置的运行简单网络。
简化
为了说明需要什么,我明确地将选项写入了网络配置文件。但大多数都是默认设置,所以我们可以忽略它们。
主机a和主机-b:
host-? ~$ cat /etc/systemd/network/04-eth0.network
[Match]
Name=eth0
路由器:
router ~$ cat /etc/systemd/network/04-eth0.network
[Match]
Name=eth0
[Network]
Address=2001:db8:0:10::1/64
IPForward=ipv6
router ~$ cat /etc/systemd/network/06-eth1.network
[Match]
Name=eth1
[Network]
Address=2001:db8:0:20::1/64
IPForward=ipv6
调试
您可能需要检查主机是否从路由器获取了正确的设置,或者是否存在路由器(例如来自您的互联网提供商),您必须知道它发送的具体设置。然后,您可以开始radvdump
查看收到的路由器广告。如果启动它,请稍等片刻,直到收到路由器广告。这是使用默认设置的路由器广告router
:
host-a ~$ sudo radvdump
#
# radvd configuration generated by radvdump 2.18
# based on Router Advertisement from fe80::5054:ff:fe0f:194e
# received by interface eth0
#
interface eth0
{
AdvSendAdvert on;
# Note: {Min,Max}RtrAdvInterval cannot be obtained with radvdump
AdvManagedFlag off;
AdvOtherConfigFlag off;
AdvReachableTime 0;
AdvRetransTimer 0;
AdvCurHopLimit 64;
AdvDefaultLifetime 1800;
AdvHomeAgentFlag off;
AdvDefaultPreference medium;
AdvSourceLLAddress on;
prefix 2001:db8:0:10::/64
{
AdvValidLifetime 86400;
AdvPreferredLifetime 14400;
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr off;
}; # End of prefix definition
}; # End of interface definition
名称解析
只有使用 DNS 服务器才能在整个网络上进行名称解析。它的设置是一个新问题,超出了本文的范围。在这个简单的网络上没有可用的 DNS 服务器也是我们总是使用带有选项的 ping6 的原因,-n
该选项会抑制查询 DNS 服务器来转换 IP 地址。如果没有-n
,ping6 会尝试为每个请求连接到 DNS 服务器,并且会超时。这会大大减慢 ping 速度并且无法使用。
对于本地链接,启用多播DNS没有问题(移动DNS)以便您能够对直接连接的节点进行名称解析。只需添加选项
MulticastDNS=yes
到[Network]
每个节点/etc/systemd/network/*.network
文件的部分。然后你应该能够
host-a ~$ ping6 -n router.local
PING router.local(fe80::5054:ff:fe0f:194e%eth0) 56 data bytes
64 bytes from fe80::5054:ff:fe0f:194e%eth0: icmp_seq=1 ttl=64 time=2.37 ms
64 bytes from fe80::5054:ff:fe0f:194e%eth0: icmp_seq=2 ttl=64 time=0.799 ms
64 bytes from fe80::5054:ff:fe0f:194e%eth0: icmp_seq=3 ttl=64 time=0.823 ms
--- snip ---
但ping6 -n host-b.local
不会起作用,host-a
因为移动DNS是不可路由的。
参考:
- 射频识别 4291- IP 版本 6 寻址架构
- 射频识别 4193- 唯一本地 IPv6 单播地址 (ULA)
- 射频识别 3849- 为文档保留的 IPv6 地址前缀
- 射频识别标准 3810- IPv6 的多播侦听器发现版本 2 (MLDv2)
- 射频识别 4862- IPv6 无状态地址自动配置
- 射频识别标准 4864- IPv6 的本地网络保护(无需 NAT)
- 互联网号码分配机构- IPv6 多播地址空间注册表
- Linux IPv6 指南
- IPv6 - 地址类型和格式