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