使用Node.js进行IPv6组播

时间:2016-07-19 01:50:48

标签: node.js ipv6 multicast

我正在通过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 Capture

我做错了什么?什么是使用IPv6发送和接收基本多播的方法?

2 个答案:

答案 0 :(得分:7)

范围ID - >接口号

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

在IPv6多播中,此scope_id直接提供给IP_ADD_MEMBERSHIP和IP_MULTICAST_IF,而不是像IPv4那样提供与接口关联的IP。

包装器平滑v6的差异

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

不幸的是,从一个IP开始并获得一个范围并没有多大意义(范围的重点是IP可以在不同的范围内有不同的用途。)所以libuv只能够如果您使用%[scope]格式在地址末尾明确提供,请填写范围。

使用具有显式范围的地址

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

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

其中:

  • 在绑定中使用::(或没有地址)是必要的,因为您要将使用需要普通地址的send过滤多播地址的接收组合起来。

  • 使用%[iface#]强制使用此界面的范围#。

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

  • 通常发送套接字是分开的,并且给定一个不同的端口或一个匿名端口,因为您要么可以配置,要么因为套接字太相似而面临EADDRINUSE错误的危险。

答案 1 :(得分:1)

我按照此答案中的步骤操作,但仍然无法使IPv6多播工作。事实证明我设置socket.setMulticastLoopback(false)来过滤掉来自节点本身的消息,这对于IPv4来说效果很好,但是阻止了IPv6的所有消息。删除此项修复了问题并且消息开始正确显示,无需过滤。