Multicast: receiving my own streams

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

Please redirect me to another list if this is not the correct place to ask.

I am seeing an issue with multicast routing which I didn't expect and
can't explain. Basically, I have an application which receives a
multicast stream and resends it to another multicast address.

If the application then tries to listen on the new stream it just
generated, the kernel routes the stream back again to the application
layer. Note that the source ip address for this new stream is my own
ip address.

Is this expected behaviour? Is there any way to avoid the kernel from
sending back packets which originated locally (apart from iptables or
source address filtering at the application layer).

I enclose a short snippet which can reproduce it.

Regards,
Alex

------------------------------------------------------------------

#define _GNU_SOURCE
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "signal.h"
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>

#define TX_MC_IP "225.4.3.1"
#define TX_MC_PORT 5001

#define RX_MC_IP "225.5.1.4"
#define RX_MC_PORT 5001

int rx_sd;
int tx_sd;

int sd;

int skt_open( char * ip , int port  , int rx )
 {
   int sd;
   char ipstr[strlen("xxx.yyy.zzz.yyy")];
        unsigned char * poctet = NULL;
   int ttl = 64;
   int ttl_size = sizeof(ttl);
   struct  sockaddr_in addr;

       memset(&addr, 0, sizeof(addr));

   sd = socket(AF_INET, SOCK_DGRAM, 0);
   if (sd >= 0)
   {
       int value = 1;
       setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
   }
   else
    {
       printf("Cannot open socket: %s\n",strerror(errno));
       return(errno);
    }

   if( fcntl( sd , F_SETFL , O_NONBLOCK ) < 0 )
   {
       printf("Unable to make socket %d non blocking:
%s\n",sd,strerror(errno));
       return errno;
   }

       addr.sin_family = AF_INET;
       addr.sin_port = htons(port);
       addr.sin_addr.s_addr = inet_addr(ip);
       printf("Binding skt %d to %s:%d\n",sd,ip,port);

   if( bind(sd, (struct sockaddr *) &addr, sizeof(addr)) != 0 )
   {
       printf("Error binding socket %d: %s\n",sd,strerror(errno) );
       return(errno);
   }

   if(rx)
   {
       poctet = (unsigned char *)&addr.sin_addr.s_addr;
       if( (*poctet > 0xE0) && (*poctet < 0xEF) )
       {
           struct ip_mreq mreq;

           inet_aton(ip, &mreq.imr_multiaddr);
           mreq.imr_interface.s_addr = INADDR_ANY;
           if( setsockopt(sd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) == 0 )
               {
               printf("Joined multicast group for %s\n",ip);
               }
               else
               {
               printf("Unable to join multicast group for %s\n",ip);
               }
              }
        }
        else
       {
            int ttl_type = IP_TTL;
       poctet = (unsigned char *)&addr.sin_addr.s_addr;
           if( (*poctet > 0xE0) && (*poctet < 0xEF) )
               ttl_type = IP_MULTICAST_TTL;
           if( 0 != setsockopt( sd , SOL_IP , ttl_type , (void *)&ttl
, ttl_size ) )
           {
               ttl = -1;
               getsockopt( sd , SOL_IP , IP_TTL , (void *)&ttl ,
(socklen_t *)&ttl_size);
           printf("Unable to set ttl %s - default %d
hops\n",strerror(errno),ttl);
           }
           else
           {
                   ttl = -1;
                    getsockopt( sd , SOL_IP , IP_TTL , (void *)&ttl ,
(socklen_t *)&ttl_size);
           printf("Set ttl %d hops\n",ttl);
            }
        }
   printf("Opened socket %d for %s:%d\n",sd,ip,port);
   return sd;
 }

 static void skt_print( int signo , siginfo_t *info , void *context )
 {
    struct  sockaddr_in addr;
    int     addr_len = sizeof(addr);
    char    buffer[1400] = "";
    int     length = 0;
    static int      count = 0;

    memset(&addr, 0, sizeof(addr));

    if( info->si_code != POLL_IN )
    {
        printf("Unhandled event %d\r\n", (int)info->si_band);
        return;
    }

    if ( length = recvfrom(info->si_fd, buffer, sizeof(buffer), 0,
(struct sockaddr *) &addr, (socklen_t*)&addr_len) )
    {
        if( count == 0 || count >= 10000 )
        {
            printf("Seeing packets from socket %d:
%08x:%d\n",info->si_fd,addr.sin_addr.s_addr,addr.sin_port);
           count = 0;
        }
        count ++;
    }
    return;
 }

 static void skt_rx( int signo , siginfo_t *info , void *context )
 {
    struct  sockaddr_in addr;
    int     addr_len = sizeof(addr);
    char    buffer[1400] = "";
    int     length = 0;

    memset(&addr, 0, sizeof(addr));

    if( info->si_code != POLL_IN )
    {
        printf("Unhandled event %d\r\n", (int)info->si_band);
        return;
    }

    if ( length = recvfrom(info->si_fd, buffer, sizeof(buffer), 0,
(struct sockaddr *) &addr, (socklen_t*)&addr_len) )
    {
        addr.sin_family = AF_INET;
        addr.sin_port = htons(TX_MC_PORT);
        addr.sin_addr.s_addr = inet_addr(TX_MC_IP);
        if( length != sendto(tx_sd, buffer, length, MSG_DONTWAIT ,
(struct sockaddr *) &addr, sizeof(addr)) )
            printf("Send to %d failed\n",tx_sd);
    }
    return;
 }

 int receivefrom( unsigned int skt , void(*fcn)(int, siginfo_t *, void
*) , int signo )
 {
    struct sigaction signal_action;
    int flags;

    /* Set socket flags to asynchronous */
    flags = fcntl(skt, F_GETFL);
    if( fcntl(skt, F_SETFL, flags | O_ASYNC) < 0 )
    {
        printf("Unable to make socket %d non blocking:
%s\n",skt,strerror(errno));
        return errno;
    }

        // Request packet signal handler
    signal_action.sa_flags = SA_SIGINFO | SA_RESTART;
    signal_action.sa_sigaction = fcn;
    sigemptyset(&signal_action.sa_mask);
    sigaction(signo, &signal_action, NULL);

    /* Set process id to send signal to */
    if( fcntl( skt , F_SETOWN , getpid() ) < 0 )
    {
        printf("Can't adquire SIGIO for skt %d: %s\n",skt,strerror(errno));
        return errno;
    }

    /* Set signal number >= SIGRTMIN to send a RealTime signal */
    if( fcntl( skt, F_SETSIG, signo) < 0 )
    {
        printf("Can't assign signal to skt %d\n",skt);
        return errno;
    }
    printf("Receiving from socket %d in pid %d\n",skt,getpid());
    return 0;
 }

 static void signal_handler( int sig_num )
 {
   close(tx_sd);
   close(rx_sd);
   exit(1);
 }

int main(int argc, char *argv[])
{
   if(( signal(SIGTERM,&signal_handler) == SIG_ERR ) ||(
signal(SIGINT, &signal_handler) == SIG_ERR ) )
       printf("Error registering signal.\n");

   // Open socket to send to
   tx_sd = skt_open( TX_MC_IP , TX_MC_PORT , 0 /*tx*/ );
   // Open socket to receive on
   rx_sd = skt_open( RX_MC_IP , RX_MC_PORT , 1 /*rx*/ );
   receivefrom(rx_sd , skt_rx , 38);

   // Do I see the relay I'm outputting?
   sd = skt_open( TX_MC_IP , TX_MC_PORT , 1 /*rx*/ );
   receivefrom(sd , skt_print, 39);

   //Wait for signals
   while (1)
   {
       sched_yield();
   }
   return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-net" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux