10

I am experimenting with IPv6 UDP multicast over a VPN. I have tried the following code:

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);

The script runs, and I see packets being sent/received with Wireshark, but neither end shows them in the console.

Wireshark UDP Capture

What am I doing wrong? What's a way to send and receive basic multicast with IPv6?

20
  • What exactly are you doing? The multicast group to which you are sending is a reserved multicast group for Link-Local Multicast Name Resolution (RFC 4795). That multicast group will never be sent off the link on which it is originated. Commented Jul 19, 2016 at 3:22
  • @RonMaupin I only need to send multicast packets across the broadcast domain. The VPN takes care of putting everything on the same broadcast domain, and this is indeed working. I can see the multicast packets between machines over the VPN. I tried switching to ff02::2, and that still didn't work. What multicast address should I be using? Commented Jul 19, 2016 at 3:36
  • 1
    There are flags and scopes for IPv6 multicast. The multicast group FF02::1 is the Link-Local All Nodes Address. You could start with that. Beyond that, you should research the various scopes and flags. For instance the scopes are: 0 Reserved, 1 Interface-Local scope, 2 Link-Local scope, 3 Realm-Local scope, 4 Admin-Local scope, 5 Site-Local scope, 6 Unassigned, 7 Unassigned, 8 Organization-Local scope, 9 Unassigned, A Unassigned, B Unassigned, C Unassigned, D Unassigned, E Global scope, F Reserved. Commented Jul 19, 2016 at 3:51
  • @RonMaupin Sorry, that was a typo. I used ff02::1, and that did not work for me. And, thanks for clarifying the scope. I've been getting started by looking at this: txv6tf.org/wp-content/uploads/2013/07/… I suppose if ff02::1 is a valid multicast address, then I have a code problem of some sort. Commented Jul 19, 2016 at 3:54
  • @RonMaupin Another note... if I use ff02::1, I do not receive packets from my remote host over the VPN. If I use ff02::1:3, I do. Could this be due to a quirk/bug of the VPN implementation? Commented Jul 19, 2016 at 3:56

2 Answers 2

8
+250

Scope id -> interface number

In IPv6, there is a concept of a scope_id of an address that is supposed to indicate a context for the IP address, and generally just means what interface it is reachable on. While scopes have OS specific names, each just translates to an interface number, with 0 usually meaning the system's default.

In IPv6 multicast, this scope_id is provided directly to IP_ADD_MEMBERSHIP and IP_MULTICAST_IF instead of providing an ip associated with the interface as IPv4 does.

wrapper smoothing of v6's differences

node (via libuv) hides this difference for you in addMembership by looking up the scope_id from the "interface address" you provide.

Unfortunately, starting from just an IP and getting a scope doesn't make a lot of sense (the whole point of the scope is that the IP could have different uses in different scopes.) So libuv is only able to fill in a scope if you explicitly provide it at the end of the address, using the %[scope] format.

Using Addresses with Explicit Scopes

The way around this seems to be:

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

Where:

  • using :: (or no address) in bind is necessary since you are combining receive which will filter the multicast address on this with send which needs a normal address.

  • using %[iface#] forces the scope of this interface #.

  • The second argument of addMembership could really start with any address since we are forcing the scope and the rest is discarded.

  • Usually the send socket is separated and given a different port or an anonymous port as you are either limited in what you can configure or in danger of getting EADDRINUSE errors for having sockets that are too similar.

Sign up to request clarification or add additional context in comments.

Comments

1

I followed the steps in this answer but still couldn't get IPv6 multicast to work. It turned out I was setting socket.setMulticastLoopback(false) to filter out messages coming from the node itself, which worked well for IPv4, but was blocking all messages for IPv6. Removing this fixed the issue and messages started appearing correctly, with no need to filter.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.