我有两个程序:
当我在一台机器上运行服务器并在某些(其他)机器上运行侦听器时,侦听器会看到UDP流量并正确打印它。所以这些程序应该处于良好的状态。
但是,当我尝试使用tcpdump:
在任何机器上捕获流量时sudo tcpdump -i eth0 'dst 233.65.120.153' -w 0.pcap
当我稍后尝试使用tcpreplay:
在任何机器上重播它sudo tcpreplay -i eth0 0.pcap
没有一个侦听器看到这些捕获的数据包:
09:38:40.975604 IP (tos 0x0, ttl 1, id 0, offset 0, flags [DF], proto UDP (17), length 32)
172.27.6.176.53507 > 233.65.120.153.64968: [udp sum ok] UDP, length 4
0x0000: 4500 0020 0000 4000 0111 6527 ac1b 06b0 E.....@...e'....
0x0010: e941 7899 d103 fdc8 000c 579c 6162 6364 .Ax.......W.abcd
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
09:38:41.975709 IP (tos 0x0, ttl 1, id 0, offset 0, flags [DF], proto UDP (17), length 32)
172.27.6.176.53507 > 233.65.120.153.64968: [udp sum ok] UDP, length 4
0x0000: 4500 0020 0000 4000 0111 6527 ac1b 06b0 E.....@...e'....
0x0010: e941 7899 d103 fdc8 000c 579c 6162 6364 .Ax.......W.abcd
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
09:38:42.975810 IP (tos 0x0, ttl 1, id 0, offset 0, flags [DF], proto UDP (17), length 32)
172.27.6.176.53507 > 233.65.120.153.64968: [udp sum ok] UDP, length 4
0x0000: 4500 0020 0000 4000 0111 6527 ac1b 06b0 E.....@...e'....
0x0010: e941 7899 d103 fdc8 000c 579c 6162 6364 .Ax.......W.abcd
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
请注意,即使没有一个侦听器看到UDP多播流量,我仍然能够在任何机器上看到它,使用tcpdump:
sudo tcpdump -i eth0 'dst 233.65.120.153' -X
我的问题:如果我想要tcpreplay我正在创建的UDP多播流量,以便我可以在应用程序级别(例如我的侦听程序)上看到它,我应该做什么(不同),不仅如此通过tcpdump?
$ cat sender.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define PORT 64968
#define GROUP "233.65.120.153"
main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, cnt;
struct ip_mreq mreq;
char *message="abcd";
/* Create what looks like an ordinary UDP socket:
AF_INET ... IPv4
SOCK_DGRAM ... UDP
0 ... required constant
*/
if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(1);
}
/* Set up destination address:
AF_INET ... IPv4
GROUP ... the IP-address of the multicast group
to which we want to multicast
PORT ... the UDP port that on which we want to multicast
*/
memset(&addr, 0, sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=inet_addr(GROUP);
addr.sin_port=htons(PORT);
/* now just sendto() our destination! */
while (1) {
if (sendto(fd, message, strlen(message), 0, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("sendto");
exit(1);
}
sleep(1);
}
}
$ cat listener.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define PORT 64968
#define GROUP "233.65.120.153"
#define MSGBUFSIZE 1000000
char msgbuf[MSGBUFSIZE];
main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, nbytes,addrlen;
struct ip_mreq mreq;
u_int yes=1;
/* Create what looks like an ordinary UDP socket:
AF_INET ... IPv4
SOCK_DGRAM ... UDP
0 ... required constant
*/
if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(1);
}
/* Allow multiple sockets to use the same PORT number:
SOL_SOCKET ... manipulate properties of the socket API itself
SO_REUSEADDR ... Allow reuse of local addresses for bind
*/
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
perror("Reusing ADDR failed");
exit(1);
}
/* set up destination address */
memset(&addr,0,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY); /* N.B.: differs from sender */
addr.sin_port=htons(PORT);
/* bind to receive address */
if (bind(fd,(struct sockaddr *) &addr,sizeof(addr)) < 0) {
perror("bind");
exit(1);
}
/* use setsockopt() to request that the kernel join a multicast group */
mreq.imr_multiaddr.s_addr=inet_addr(GROUP);
mreq.imr_interface.s_addr=htonl(INADDR_ANY);
if (setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)) < 0) {
perror("setsockopt");
exit(1);
}
/* now just enter a read-print loop */
while (1) {
addrlen=sizeof(addr);
memset(msgbuf, 0, MSGBUFSIZE);
if ((nbytes=recvfrom(fd, msgbuf, MSGBUFSIZE,0,
(struct sockaddr *) &addr, &addrlen)) < 0) {
perror("recvfrom");
exit(1);
}
printf("Incoming message size = %d\n", nbytes);
int i;
for (i=0; i < nbytes; i++)
printf("%02x ", ((unsigned char) msgbuf[i]));
printf("\n");
}
}
答案 0 :(得分:7)
我们遇到了同样的问题。在tcpdump
我们看到了数据;但是,多播客户端/侦听器没有获取数据。然后我们意识到反向路径过滤器(rp_filter)拒绝了数据包。
禁用rp-filter后,客户端/侦听器应用程序开始拾取数据包。使用以下命令禁用rp_filter:
echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter
在上文中,替换&#39; eth0&#39;接收多播的接口(如果不是eth0
)答案 1 :(得分:2)
在我的情况下,我需要通过设置正确的目标MAC地址来调整pcap文件。还应重新计算校验和。是的,&#34; tcpreplay&#34;需要2台主机。如果没有这些,我会争取很长一段时间,但只有&#34; tcpdump&#34;显示重播的流,而不是我的多播监听应用程序:(
以下是我文章的链接:Step by step instructions on Dump/Replay Multicast feed
答案 2 :(得分:1)
据我所知,你不能在同一个盒子里这样做,tcpreplay会绕过主机 路由表并发送流量 out 接口。
你必须在另一个盒子上开始你的听众。并确保启用了多播。因为默认情况下,交换机会丢弃多播流量。
答案 3 :(得分:1)
这只是一个理论,但由于校验和错误,接收方可能会丢弃数据包。
如果运行tcpdump的计算机启用了IP或UDP校验和卸载,则可能发生这种情况。这意味着您在本地捕获的软件包尚未计算其校验和,这是硬件在发送之前所做的。然后,当您tcpreplay这些数据包时,不会计算校验和,因为tcpreplay的工作级别低于用于生成数据包的套接字API。
为了验证校验和的正确性(转储文件的那些以及随后的tcpreplay吐出的数据包),tcpdump -v ...
将警告您错误的校验和。 wireshark还错误地校验错误的帧(除非在wireshark设置中关闭)。
您是否尝试仅在发送主机或接收主机上tcpdump数据包?后者会删除校验和错误,如果这确实是你的问题。
答案 4 :(得分:0)
在Windows中(我写它是因为在主题名称中您未指定不是Windows),使用不同的程序会出现类似的问题。但是此程序可以正常运行Colasoft Packet Player。第一次,您应该以管理权限启动它。
或(对于所有可能的系统),您可以尝试检查此list。