我有一个守护进程,我正在努力监听UDP广播数据包,并通过UDP进行响应.当数据包进入时,我想知道数据包来自哪个IP地址(或NIC),以便我可以使用该IP地址作为源. (由于涉及很多痛苦的原因,我们系统的一些用户想要将同一台机器上的两个NIC连接到同一个子网.我们告诉他们不要,但是他们坚持.我不需要提醒我有多难看.)
似乎无法检查数据报并直接找出其目标地址或其所在的接口.基于大量的谷歌搜索,我发现找出数据报目标的唯一方法是每个接口有一个监听套接字,并将套接字绑定到各自的接口.
首先,我的监听套接字以这种方式创建:
s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
要绑定套接字,我尝试的第一件事就是这样,其中nic是接口名称的char *:
// Bind to a single interface
rc=setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, nic, strlen(nic));
if (rc != 0) { ... }
这根本没有效果,并且无声地失败. ASCII名称(例如eth0)是否是传递给此调用的正确名称类型?为什么会无声地失败?根据man 7 socket,“请注意,这仅适用于某些套接字类型,尤其是AF_INET套接字.数据包套接字不支持(在那里使用普通bind(8)).”我不确定“数据包套接字”是什么意思,但这是一个AF_INET套接字.
struct sockaddr_ll sock_address;
memset(&sock_address, 0, sizeof(sock_address));
sock_address.sll_family = PF_PACKET;
sock_address.sll_protocol = htons(ETH_P_ALL);
sock_address.sll_ifindex = if_nametoindex(nic);
rc=bind(s, (struct sockaddr*) &sock_address, sizeof(sock_address));
if (rc < 0) { ... }
这也失败了,但这次错误无法分配请求的地址.我也尝试将系列更改为AF_INET,但它失败并出现相同的错误.
仍有一个选项,即将套接字绑定到特定的IP地址.我可以查找接口地址并绑定到那些地址.不幸的是,这是一个糟糕的选择,因为由于DHCP和热插拔以太网电缆,地址可以随时更改.
广播和多播时,此选项也可能不好.我担心绑定到特定地址将意味着我无法接收广播(这些广播不是我所绑定的地址).我实际上将在今晚晚些时候测试这个并更新这个问题.
问题:
>是否可以将UDP侦听套接字专门绑定到接口?
>或者,是否有一种我可以使用的机制,它将通知我的程序接口的地址发生了变化,此时发生了变化(与轮询相反)?
>是否有我可以创建的另一种侦听套接字(我有root权限),我可以绑定到特定的接口,其行为与UDP相同(即除了原始套接字,我基本上必须自己实现UDP) ?例如,我可以将AF_PACKET与SOCK_DGRAM一起使用吗?我不明白所有的选择.
任何人都可以帮我解决这个问题吗?谢谢!
更新:
绑定到特定IP地址无法正常工作.具体来说,我不能接收广播数据包,这是我想要接收的.
更新:
我尝试使用IP_PKTINFO和recvmsg来获取有关正在接收的数据包的更多信息.我可以获取接收接口,接收接口地址,发送方的目标地址和发送方的地址.以下是收到一个广播数据包后收到的报告示例:
Got message from eth0
Peer address 192.168.115.11
Received from interface eth0
Receiving interface address 10.1.2.47
Desination address 10.1.2.47
真正奇怪的是,eth0的地址是10.1.2.9,而ech1的地址是10.1.2.47.那么为什么世界上eth0接收应该由eth1接收的数据包呢?这绝对是个问题.
请注意,我启用了net.ipv4.conf.all.arp_filter,但我认为这仅适用于外出数据包.