采用Node.js的IPv6组播

我正在通过VPN试验IPv6 UDP多播。 我已经尝试了下面的代码:

const dgram = require('dgram'); let sock = dgram.createSocket('udp6', { reuseAddr: true }); sock.on('message', (data, source) => { console.log('on message', arguments); }); sock.bind('36912', '2620:9b::1944:e598', () => { sock.addMembership('ff02::1:3', '2620:9b::1944:e598'); }); setInterval(() => { let buf = Buffer.from((new Date()).toString()); sock.send(buf, 0, buf.length, 36912, 'ff02::1:3'); }, 500); 

脚本运行,我看到数据包是用Wireshark发送/接收的,但是两端都没有显示在控制台中。

Wireshark UDP捕获

我究竟做错了什么? 使用IPv6发送和接收基本组播的方式是什么?

范围编号 – >接口编号

在IPv6中,有一个地址scope_id的概念,该地址应该表示IP地址的上下文,通常只是指它可以到达的接口。 虽然作用域具有特定于操作系统的名称,但每个名称都只是转换为接口号,其中0通常表示系统的默认值。

在IPv6组播中,这个scope_id直接提供给IP_ADD_MEMBERSHIP和IP_MULTICAST_IF,而不是象IPv4那样提供与接口相关的IP。

封装平滑的V6的差异

节点(通过libuv)通过查找您提供的“接口地址”中的scope_id,在addMembership为您隐藏了这种差异。

不幸的是,从一个IP开始,得到一个范围并没有什么意义(整个范围的观点是,IP可能在不同的范围内有不同的用途)。所以libuv只能填写一个范围if您可以在地址的末尾使用%[scope]格式明确提供。

使用明确范围的地址

解决这个问题的方法似乎是:

  sock.bind('36912', '::', () => { sock.addMembership('ff02::1:3', '::%eth2'); ... sock.send(buf, 0, buf.length, 36912, 'ff02::1:3%eth2'); 

哪里:

  • 在绑定中使用:: :(或无地址)是必要的,因为你正在组合接收,它将filter上的多播地址与需要普通地址的发送。

  • 使用%[iface#]强制该接口#的作用域。

  • addMembership的第二个参数可以从任何地址开始,因为我们强制范围,其余的都被丢弃。

  • 通常情况下,发送套接字是分开的,并给予不同的端口或匿名端口,因为您可能configuration的内容有限,或者有可能因为套接字太相似而导致EADDRINUSE错误。

我按照这个答案中的步骤,但仍然无法让IPv6组播工作。 事实certificate,我设置了socket.setMulticastLoopback(false)来过滤掉来自节点本身的消息,这对于IPv4来说效果很好,但是阻止了IPv6的所有消息。 删除这个固定的问题和消息开始正确显示,无需过滤。