如何通过接口过滤多播接收套接字?

7
我需要创建两个套接字,它们监听同一个IP:端口,但在不同的接口上:
  1. socket0在eth0接口上接收发送到224.2.2.2:5000的UDP流量
  2. socket1在eth1接口上接收发送到224.2.2.2:5000的UDP流量
这似乎很简单,直到我意识到Linux将所有内容合并为同一流量。例如,假设只有eth1上的流量,eth0上没有活动。当我首先创建socket0时,它将不会接收任何数据,但是一旦我创建socket1(并加入多播组),那么socket0也将开始接收相同的数据。我发现this link可以解释这个问题。
现在,这对我来说实际上是有道理的,因为唯一指定网络接口的时刻是加入多播组setsockopt(socket,IPPROTO_IP,IP_ADD_MEMBERSHIP,...)ip_mreq.imr_interface.s_addr。我认为这指定了哪个接口加入组,但与套接字从哪个接口接收无关。
我尝试过将套接字绑定到多播地址和端口,这会像上面提到的那样行为。我尝试将其绑定到接口地址,但在Linux上无法工作(似乎在Windows上可以),您不会在套接字上接收任何流量。最后,我尝试将其绑定到 INADDR_ANY ,但这不是我想要的,因为我将接收发送到该端口的任何其他数据,而不管目标IP,例如单播,它仍然不会阻止来自其他接口的多播数据。
我不能使用 SO_BINDTODEVICE ,因为它需要root权限。
所以我想知道是否可能实现这一点。如果无法完成,则没关系,我会将其视为答案并继续前进,我只是无法找到任何解决方法。哦,我已将问题标记为 C ,因为这是我们正在使用的语言,但我认为它可能并不特定于该语言。

我没有包含这个代码,因为我认为这更像是一个理论问题,而不是源代码的问题。我们已经使用套接字(多播或其他)工作了一段时间,没有任何问题,只是这是我们第一次处理多个接口。但如果你认为这可能有所帮助,我可以写一些最小化的工作示例。


关于可能的重复问题的编辑:

我认为我正在尝试实现的用例是不同的。套接字应该只从一个特定的接口接收来自相同的多播组和端口(如上例中的224.2.2.2:5000),而不是从两个接口同时接收数据。换句话说,两个接口都从同一个多播组接收数据(但是不同的网络,因此数据不同),我需要每个套接字仅在一个接口上监听。

我认为那个问题涉及同一端口上的多个组,而不是来自不同接口的同一组。除非有什么我没有看到的东西,可能真的可以帮助我解决这个问题。


你的问题是由于socket0在eth0接口上接收到发送到224.2.2.2:5000的UDP流量这句话没有意义:多播流量是在接口上接收,而不是在其上发送。你不能说某些流量被发送到特定的接口。发送方不会选择接收方接口。 - Alexandre Fenyo
1
@Alexandre,也许我在那个短语上使用了错误的措辞。我的意思是,一些其他设备正在向224.2.2.2:5000发送UDP,而我的PC通过eth0连接到该网络。这意味着我在eth0上接收由其他人发送到224.2.2.2:5000的流量。 - sycc90
1个回答

8

是的,在Linux上,即使没有root权限,也可以按照自己的意愿进行操作:

绑定到INADDR_ANY并设置IP_PKTINFO套接字选项。然后,您必须使用recvmsg()来接收多播UDP包,并扫描IP_PKTINFO控制消息。这为您提供了一些有关接收的UDP数据包的附加信息:

struct in_pktinfo {
    unsigned int   ipi_ifindex;  /* Interface index */
    struct in_addr ipi_spec_dst; /* Local address */
    struct in_addr ipi_addr;     /* Header Destination address */
};
ipi_ifindex是接收数据包的网络接口索引。你可以使用if_indextoname()将其转换为接口名称,或者使用if_nametoindex()反向转换。

正如你所说,在Windows上,同样的网络函数具有不同的语义,特别是对于UDP甚至更多的组播。

对于UDP套接字,Linux bind()的IP地址语义大多是无用的。它基本上只是一个目标地址过滤器。你几乎总是想要绑定到INADDR_ANY,因为你要么不关心数据包发送到哪个地址,要么想接收多个地址的数据包(例如接收单播和组播)。


1
我打算选择这个作为答案,因为它直接解决了问题。 我真的想知道是否可以在不过滤自己的情况下完成,因为现在我们必须使套接字处理两倍的数据量,但似乎不可能。唯一的区别是我们仍然加入了多播地址,而不是 INADDR_ANY - sycc90

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接