如何实现本地ICMPv6邻居发现?

时间:2018-03-28 12:12:32

标签: networking erlang ipv6 lxc icmpv6

我正在实施自己的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协议实现中缺少什么使容器接受虚拟地址作为有效路由?

0 个答案:

没有答案