0
votes

On a system with several network interfaces, I can have the same multicast address and port combination used on different networks, with different data on them. I want to be able to connect to them with several network cards and receive different data on each interface.

To do so, I bind to the interface I want to receive on using the IP_MULTICAST_IF option:

ip_mreqn mreqn;
memset(&mreqn, 0, sizeof (ip_mreqn));
mreqn.imr_multiaddr.s_addr = inet_addr(mc);
mreqn.imr_address.s_addr = INADDR_ANY;
mreqn.imr_ifindex = if_nametoindex(device);
if (setsockopt(mct->fd, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn)) < 0) {
  perror("setsockopt multicast if");
  return 1;
}

and make sure the join request is only sent on that interface by setting IP_ADD_MEMBERSHIP with the same structure:

if (setsockopt(mct->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0) {
  perror("setsockopt add membership");
  return 1;
}

While the IP_ADD_MEMBERSHIP code works (the join request is only sent on the interface specified), the IP_MULTICAST_IF does not. Instead once it is able to join the multicast on any of the interfaces, I receive the same data through all sockets, even if they have different imr_ifindex set.

1
Try it without the IP_MULTICAST_IF step.user207421

1 Answers

1
votes

The IP_MULTICAST_IF ioctl does not control incoming selection, it is setting the socket's default interface for its outgoing multicast packets.

IP_ADD_MEMBERSHIP is the only mechanism for configuring incoming multicast and the memberships it creates are for the entire host, the host does not tailor delivery to individual sockets based on their requested memberships. (You can observe the hosts memberships with netstat -gn and the reference count is being used to determine when the host can stop observing, but not which sockets are receiving fan-out. If you have a matching membership from any socket, all sockets that made an applicable bind(2) will start receiving that multicast, even if they have never used IP_ADD_MEMBERSHIP.)

The usual method to differentiate these packets with out changing the system setup, is to receive them all on a socket using ancillary data to identify their interface. On Linux, this ancillary data setup is done with IP_PKTINFO as described in ip(7).