问题稍微有点复杂,请大神耐心看完。
我的主机在工作日的某个时间段会收到UDP广播数据包,我用C语言做了个简单的应用程序来接收这些UDP广播数据包。
因为只有在某个特定时间才能接收数据包,为了测试程序,我先用tcpdump把数据包保存下来,然后用tcpreplay工具重放这些抓到的数据包。分条总结一下如下:
# 1. 用tcpdump抓包
tcpdump -i enp0s25 -s 1600 -w /home/user/log/capture.pcap
# 2. 用tcpreplay重放这些抓到的数据包
tcpreplay -i p1p2 --pktlen /home/user/log/capture.pcap
ifconfig命令的输出如下:
enp0s25: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.3.6 netmask 255.255.255.0 broadcast 192.168.3.255 inet6 2400:2410:2a41:2e00:1d6f:2fde:2436:608f prefixlen 64 scopeid 0x0<global> inet6 fe80::555d:f7f2:a114:51df prefixlen 64 scopeid 0x20<link> ether 98:90:96:a7:6f:f3 txqueuelen 1000 (Ethernet) RX packets 45031 bytes 50053845 (47.7 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 14129 bytes 1784865 (1.7 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 device interrupt 20 memory 0xf9100000-f9120000
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
p1p1: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether 00:02:c9:5a:77:62 txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 218 dropped 207 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
p1p2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::2acf:23a9:3c1a:89a0 prefixlen 64 scopeid 0x20<link> ether 00:02:c9:5a:77:63 txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 329583 bytes 50655424 (48.3 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
p4p1: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether 00:0f:53:29:e9:30 txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 device interrupt 26
p4p2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether 00:0f:53:29:e9:31 txqueuelen 1000 (Ethernet) RX packets 329583 bytes 51973756 (49.5 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 device interrupt 35
我的机器上装有3张网卡,其中有两张是光卡,每张光卡都有两个port,p1p1和p1p2属于同一张卡, p4p1和p4p2属于同一张卡。我的接线方式是:
p1p2的光纤接到了p4p2上,所以这样就可以通过p1p2把数据包发送到p4p2上了。
结下泪用tcpdump命令查看p4p2上的数据包,发现确实有数据输出
tcpdump -i p4p2 -nnn
18:05:21.062023 IP 10.10.31.31.3131 > 239.239.31.31.3131: UDP, length 97
18:05:21.062035 IP 10.10.31.31.3131 > 239.239.31.31.3131: UDP, length 97
问题是我的应用程序却无法监听到数据包,我的应用程序的部分代码如下:
#pragma pack(1)
#include <stdio.h>
#include <string.h>
#include <float.h>
#include <stdlib.h>
#include <ctype.h>
#include <signal.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/socket.h>#define MAXBUFSIZE 65536 // Max UDP Packet size is 64 Kbyte
int main() {
int sock, status, socklen; uint8_t buffer[MAXBUFSIZE]; struct sockaddr_in saddr; struct ip_mreq imreq; memset(&saddr, 0x00, sizeof(saddr)); memset(&imreq, 0x00, sizeof(imreq)); memset(buffer, 0x00, MAXBUFSIZE); // open a UDP socket sock = socket(AF_INET, SOCK_DGRAM, 0); if ( sock < 0 ) { perror("Error creating socket"); return(0); } imreq.imr_multiaddr.s_addr = inet_addr("239.239.31.31"); imreq.imr_interface.s_addr = INADDR_ANY; // use DEFAULT interface // JOIN multicast group on default interface setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&imreq, sizeof(struct ip_mreq)); saddr.sin_family = AF_INET; saddr.sin_port = htons(3131); saddr.sin_addr.s_addr = htonl(INADDR_ANY); status = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)); if ( status < 0 ) { perror("Error binding socket to interface"); return(0); } socklen = sizeof(struct sockaddr_in); // receive 500 packets from socket int m = 0; for (; m < 500; m++) { status = recvfrom(sock, buffer, MAXBUFSIZE, 0, (struct sockaddr *)&saddr, &socklen); if(status < 0) { perror("receive error!\n"); } else if (status > 0) { // DO sth usefully here. } } // shutdown socket shutdown(sock, 2); // close socket close(sock); return 0;
}
运行程序后,程序会停在recvfrom方法上。为什么tcpdump能看到,而我的应用程序却看不到数据包呢?
求指教。
你可以用tcpdump的-e参数来看看数据包的源和目的mac地址,我没用过多播,不确定多播这种情况下目的mac地址是不是广播地址,如果目的mac地址是你enp0s25的mac地址的话,你这样子操作肯定不行,p4p2收到数据包后发现目的mac地址不是自己,会丢弃该包。
你这里tcpdump能在p4p2上面看到数据包,是因为tcpdump会开启网卡的混杂模式,于是能看到网卡收到的所有数据包,但由于数据包的目的mac地址不是当前网卡,协议栈收到网卡驱动的数据包之后会将数据包丢弃掉。
建议在和enp0s25同网段的其它机器上用tcpreplay试试,看enp0s25能不能收到相应的数据包,或者在当前机器上用tcpreplay试试-i enp0s25,看从这个网卡出去后能不能被交换机再发送回来。
另外你这里没有过滤数据包,capture.pcap里面应该包含这个网卡收到的和发送出去的所有数据包,我没用过tcpreplay,不确定tcpreplay有没有区分请求和应答包,建议过滤一下,只包含自己需要的数据包,避免不必要的麻烦。