我有两个程序:

  • 服务器...它在选定的多播
  • 上生成UDP流量
  • 监听器...它在选定的多播上打印UDP流量
    (它订阅多播并打印
    无论收到什么)。

  • 当我在一台计算机上运行服务器,而在某些(其他)计算机上运行监听器时,监听器会看到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  [email protected]'....
        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  [email protected]'....
        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  [email protected]'....
        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");
         }
    }
    

    最佳答案

    我们有同样的问题。使用tcpdump,我们看到了数据;但是,多播客户端/监听器未拾取数据。然后我们意识到反向路径过滤器(rp_filter)正在拒绝数据包。

    禁用rp过滤器后,客户端/监听器应用程序开始拾取数据包。使用以下命令禁用rp_filter:
    echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter
    在上述内容中,如果不是eth0,则用接收多播的接口(interface)替换'eth0'

    关于UDP多播客户端看不到tcpreplay生成的UDP多播流量,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13471680/

    10-13 01:10