我为工具编写了一个基于套接字的 udp 侦听器,它也应该能够接收多播。 对于 IPv6 这很好用,但 IPv4 就不行了。
我使用带有 IPv4 多播数据包的日志,并通过 tcpreplay 从另一台机器将其发送到我运行侦听器的 ubuntu 机器。我在 wireshark 上看到数据包。
我要找的包来源是10.21.1.98 30490端口 数据包的目的地是 239.21.0.2 端口 30490
我的代码编译工作正常,运行时也没有错误。 我把它放在一个独立文件中进行测试,所以它可能包含一些对这个问题无用的包含。
#include <sys/timerfd.h>
#include <stdlib.h>
#include <linux/sockios.h> // for SIOCGSTAMP
#include <sys/ioctl.h> // for ioctl
#include <errno.h>
#include <ifaddrs.h>
#include <signal.h>
#include <pthread.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <pthread.h>
#define MAX_PACKET_SIZE 2048
int main(int argc,char **argv)
{
struct sockaddr_in server_in, client_in;
struct ip_mreq mreq;
int sockfd, n, i;
char msgbuf[MAX_PACKET_SIZE];
char src_ip[INET_ADDRSTRLEN];
socklen_t client_len;
// create socket and bind to IP & port
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd < 0) {
perror("Openening socket");
pthread_exit(NULL);
}
printf("Socket created.\n");
server_in.sin_family = AF_INET;
server_in.sin_port = htonl(30490);
server_in.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr *)&server_in, sizeof(server_in)) < 0) {
perror("Binding socket");
pthread_exit(NULL);
}
printf("Socket bound successful.\n");
// zero out structure
bzero(&client_in, sizeof(client_in));
client_len = sizeof(struct sockaddr_in);
// join multicast group
mreq.imr_interface.s_addr = inet_addr("169.254.255.10"); // interface ip address
mreq.imr_multiaddr.s_addr = inet_addr("239.21.0.2"); // multicast dst group
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
perror("setsock multicast");
pthread_exit(NULL);
}
printf("Joined Ipv4 Multicast group.\n");
while(1) {
printf("Listening...\n");
n = recvfrom(sockfd, msgbuf, MAX_PACKET_SIZE, 0,
(struct sockaddr *)&client_in, &client_len);
msgbuf[MAX_PACKET_SIZE] = '\0'; // add null terminator to end of buffer
inet_ntop(AF_INET, &(client_in.sin_addr.s_addr), src_ip, INET_ADDRSTRLEN);
printf("Message received. Src IP is %s\n", src_ip);
}
}
我也不确定我是否需要将 ip 路由添加到所使用的接口,因为 IPv6 多播在没有和添加它的情况下工作得很好似乎并不能解决我的问题。
一个人可以从一个人的代码中强制混杂:
struct ifreq ifopts;
//Set Promiscuous Mode
strncpy(ifopts.ifr_name, interface, IFNAMSIZ-1);
ioctl(sockfd, SIOCGIFFLAGS, &ifopts);
ifopts.ifr_flags |= IFF_PROMISC;
ioctl(sockfd, SIOCSIFFLAGS, &ifopts);
或在界面上设置
allmulti
:
ifconfig enp3s0 allmulti
https://serverfault.com/questions/679272/multicast-works-only-in-promiscuous-mode