0

我正在实现自己的 IPv6 网络堆栈,但在让 ICMPv6 邻居发现工作时遇到问题。堆栈的工作原理是捕获现有接口的数据包,挑选寻址到它的数据包并从堆栈的“虚拟”地址发送新数据包。

为了测试这一点,我有一台 Ubuntu 机器,它使用一个 LXC 容器作为测试客户端来发送流量。Ubuntu 主机具有以下用于 LXC 容器的桥接接口:

ubuntu:~$ ifconfig
...
lxcbr0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.3.1  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::216:3eff:fe00:0  prefixlen 64  scopeid 0x20<link>
        ether 00:16:3e:00:00:00  txqueuelen 1000  (Ethernet)
        RX packets 522282  bytes 85867541 (85.8 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 554574  bytes 51636337 (51.6 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
...

该容器具有以下网络接口:

my-continer:~$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.3.40  netmask 255.255.255.0  broadcast 10.0.3.255
        inet6 fe80::216:3eff:fe72:dc1c  prefixlen 64  scopeid 0x20<link>
        ether 00:16:3e:72:dc:1c  txqueuelen 1000  (Ethernet)
        RX packets 554722  bytes 51647709 (51.6 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 522297  bytes 93181219 (93.1 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
...

如果我从 LXC 容器 ping Ubuntu 主机,它当然可以工作:

my-continer:~$ sudo tcpdump -i eth0 -nn icmp6 -vv
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

11:56:44.435633 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) fe80::216:3eff:fe72:dc1c > ff02::1:ff00:0: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has fe80::216:3eff:fe00:0
          source link-address option (1), length 8 (1): 00:16:3e:72:dc:1c
            0x0000:  0016 3e72 dc1c
11:56:44.435649 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) fe80::216:3eff:fe00:0 > fe80::216:3eff:fe72:dc1c: [icmp6 sum ok] ICMP6, neighbor advertisement, length 32, tgt is fe80::216:3eff:fe00:0, Flags [solicited, override]
          destination link-address option (2), length 8 (1): 00:16:3e:00:00:00
            0x0000:  0016 3e00 0000
11:56:44.435652 IP6 (flowlabel 0x4fb04, hlim 64, next-header ICMPv6 (58) payload length: 64) fe80::216:3eff:fe72:dc1c > fe80::216:3eff:fe00:0: [icmp6 sum ok] ICMP6, echo request, seq 1
11:56:44.435660 IP6 (flowlabel 0xbb56b, hlim 64, next-header ICMPv6 (58) payload length: 64) fe80::216:3eff:fe00:0 > fe80::216:3eff:fe72:dc1c: [icmp6 sum ok] ICMP6, echo reply, seq 1
11:56:45.465749 IP6 (flowlabel 0x4fb04, hlim 64, next-header ICMPv6 (58) payload length: 64) fe80::216:3eff:fe72:dc1c > fe80::216:3eff:fe00:0: [icmp6 sum ok] ICMP6, echo request, seq 2
11:56:45.465768 IP6 (flowlabel 0xbb56b, hlim 64, next-header ICMPv6 (58) payload length: 64) fe80::216:3eff:fe00:0 > fe80::216:3eff:fe72:dc1c: [icmp6 sum ok] ICMP6, echo reply, seq 2
11:56:46.490187 IP6 (flowlabel 0x4fb04, hlim 64, next-header ICMPv6 (58) payload length: 64) fe80::216:3eff:fe72:dc1c > fe80::216:3eff:fe00:0: [icmp6 sum ok] ICMP6, echo request, seq 3
11:56:46.490204 IP6 (flowlabel 0xbb56b, hlim 64, next-header ICMPv6 (58) payload length: 64) fe80::216:3eff:fe00:0 > fe80::216:3eff:fe72:dc1c: [icmp6 sum ok] ICMP6, echo reply, seq 3

我自己的堆栈配置了 mac 地址0c:22:38:4e:9a:bc和 IPv6 地址fe80::216:3eff:fe00:1234

使用 Erlang 实现,处理邻居请求包的代码如下:

process(#ipv6{headers = [#icmpv6{type = neighbor_solicitation, payload = {IP6, _}}|_]} = Packet, {IP6, Mac}) ->
    #ipv6{src = Src} = Packet,
    send(#ipv6{
        src = IP6,
        dst = Src,
        next = ?IP_PROTO_ICMPv6,
        hlim = 16#FF,
        headers = [
            {icmpv6, #icmpv6{
                type = neighbor_advertisement,
                code = 0,
                payload = {IP6, #{source_link_layer_addr => Mac}}
            }}
        ]
    });

Packet是传入的邻居请求请求,{IP6, Mac}是堆栈已配置的 IPv6 地址和 MAC 地址。

ping 它时,数据包到达主机上的接口并被 libpcap 拾取。我生成了对地址解析的响应,但 ping 从未成功:

my-continer:~$ ping6 -I eth0 fe80::216:3eff:fe00:1244
PING fe80::216:3eff:fe00:1244(fe80::216:3eff:fe00:1244) from fe80::216:3eff:fe72:dc1c%eth0 eth0: 56 data bytes
From fe80::216:3eff:fe72:dc1c%eth0 icmp_seq=1 Destination unreachable: Address unreachable
From fe80::216:3eff:fe72:dc1c%eth0 icmp_seq=2 Destination unreachable: Address unreachable
From fe80::216:3eff:fe72:dc1c%eth0 icmp_seq=3 Destination unreachable: Address unreachable
^C
--- fe80::216:3eff:fe00:1244 ping statistics ---
4 packets transmitted, 0 received, +3 errors, 100% packet loss, time 3065ms

跟踪显示邻居广告数据包到达容器:

my-continer:~$ sudo tcpdump -i eth0 -nn icmp6 -vv
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

12:04:23.751427 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) fe80::216:3eff:fe72:dc1c > ff02::1:ff00:1234: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has fe80::216:3eff:fe00:1234
          source link-address option (1), length 8 (1): 00:16:3e:72:dc:1c
            0x0000:  0016 3e72 dc1c
12:04:23.753662 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) fe80::216:3eff:fe00:1234 > fe80::216:3eff:fe72:dc1c: [icmp6 sum ok] ICMP6, neighbor advertisement, length 32, tgt is fe80::216:3eff:fe00:1234, Flags [solicited, override]
          source link-address option (1), length 8 (1): 0c:22:38:4e:9a:bc
            0x0000:  0c22 384e 9abc
12:04:24.761850 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) fe80::216:3eff:fe72:dc1c > ff02::1:ff00:1234: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has fe80::216:3eff:fe00:1234
          source link-address option (1), length 8 (1): 00:16:3e:72:dc:1c
            0x0000:  0016 3e72 dc1c
12:04:24.765901 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) fe80::216:3eff:fe00:1234 > fe80::216:3eff:fe72:dc1c: [icmp6 sum ok] ICMP6, neighbor advertisement, length 32, tgt is fe80::216:3eff:fe00:1234, Flags [solicited, override]
          source link-address option (1), length 8 (1): 0c:22:38:4e:9a:bc
            0x0000:  0c22 384e 9abc
12:04:25.786994 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) fe80::216:3eff:fe72:dc1c > ff02::1:ff00:1234: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has fe80::216:3eff:fe00:1234
          source link-address option (1), length 8 (1): 00:16:3e:72:dc:1c
            0x0000:  0016 3e72 dc1c
12:04:25.789413 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) fe80::216:3eff:fe00:1234 > fe80::216:3eff:fe72:dc1c: [icmp6 sum ok] ICMP6, neighbor advertisement, length 32, tgt is fe80::216:3eff:fe00:1234, Flags [solicited, override]
          source link-address option (1), length 8 (1): 0c:22:38:4e:9a:bc
            0x0000:  0c22 384e 9abc

除了地址本身之外,它们看起来与发送到真实界面和从真实界面发送的那些相同。

检查路由表显示虚拟地址的地址解析由于某种原因不起作用:

my-continer:~$ sudo ip -6 neigh
fe80::216:3eff:fe00:0 dev eth0 lladdr 00:16:3e:00:00:00 STALE
fe80::216:3eff:fe00:1234 dev eth0  FAILED

这里邻居发现失败的原因是什么?我在实现 ICMPv6 协议以使容器接受虚拟地址作为有效路由时缺少什么?

4

0 回答 0