在不同接口上接收具有相同源地址的不同组播

Receiving different multicast with same source address on different interfaces

在一个有多个网络接口的系统上,我可以在不同的网络上使用相同的多播地址和端口组合,但它们上面有不同的数据。我希望能够通过多个网卡连接到它们,并在每个接口上接收不同的数据。

为此,我使用 IP_MULTICAST_IF 选项绑定到我想要接收的接口:

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

并通过设置具有相同结构的 IP_ADD_MEMBERSHIP 确保仅在该接口上发送加入请求:

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

虽然 IP_ADD_MEMBERSHIP 代码有效(加入请求仅在指定的接口上发送),但 IP_MULTICAST_IF 无效。相反,一旦它能够在任何接口上加入多播,我就会通过所有套接字接收相同的数据,即使它们设置了不同的 imr_ifindex

IP_MULTICAST_IF ioctl 不控制传入选择,它正在为其传出多播数据包设置套接字的默认接口。

IP_ADD_MEMBERSHIP 是配置传入多播的唯一机制,它创建的成员资格适用于整个主机,主机不会根据请求的成员资格定制对单个套接字的传送。 (您可以使用 netstat -gn 观察主机成员资格,并且引用计数用于确定主机何时可以停止观察,而不是确定哪些套接字正在接收扇出。如果您有来自任何套接字的匹配成员资格,则所有应用 bind(2) 的套接字将开始接收该多播,即使它们从未使用过 IP_ADD_MEMBERSHIP。)

在不更改系统设置的情况下区分这些数据包的常用方法是使用辅助数据在套接字上接收它们,以识别它们的接口。在 Linux 上,此辅助数据设置是使用 IP_PKTINFO 完成的,如 ip(7) 中所述。