LINUX.ORG.RU

Не работает прием Multicast сообщения на втором интрфейсе

 


0

1

Не могу понять, почему не считать сообщения с помощью recvfrom(recv_s, message, MAXLEN, 0, (struct sockaddr*)&from, &len)) .

В системе две сетевые карточки(eth0,eth1). Eth0 имеет адрес 192.168.4.218 Eth1 имеет адрес 192.168.4.228

Если сообщения multicast приходят на интерфейс eth0, то работает все штатно.

Если сообщения multicast приходят на интерфейс eth1, то считать сообщение не получается.

Операционная система ubuntu 12.

 #define MAXLEN 1024
 
 
 int main(int argc, char* argv[])
 {
     u_char no = 0;
     u_int yes = 1;      
	int send_s, recv_s;     
	u_char ttl;
	struct sockaddr_in mcast_group;
	struct ip_mreq mreq= {};
	struct utsname name;
	int n;
        socklen_t len;
        struct sockaddr_in from;
        char message [MAXLEN+1];
 
     if (argc != 3) {
         fprintf(stderr, "Usage: %s mcast_group port\n", argv[0]);
         exit(1);
     }
 
     memset(&mcast_group, 0, sizeof(mcast_group));
     mcast_group.sin_family = AF_INET;
     mcast_group.sin_port = htons((unsigned short int)strtol(argv[2], NULL, 0));
    mcast_group.sin_addr.s_addr = inet_addr(argv[1]);
//       mcast_group.sin_addr.s_addr = INADDR_ANY;
     
     if ( (recv_s=socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
         perror ("recv socket");
         exit(1);
     }
 
     if (setsockopt(recv_s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
         perror("reuseaddr setsockopt");
         exit(1);
     }
 
     if (bind(recv_s, (struct sockaddr*)&mcast_group, sizeof(mcast_group)) < 0) {
         perror ("bind");
         exit(1);
     }

    	/* Preparatios for using Multicast */ 
	//mreq.imr_multiaddr = mcast_group.sin_addr;
	mreq.imr_multiaddr.s_addr = inet_addr("239.192.100.1");
//        mreq.imr_interface.s_addr = INADDR_ANY;
      	mreq.imr_interface.s_addr = inet_addr("192.168.4.228");

	if (setsockopt(recv_s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
	perror ("add_membership setsockopt");
	exit(1);
	}
 
	len=sizeof(from);
                if ( (n=recvfrom(recv_s, message, MAXLEN, 0, 
                                 (struct sockaddr*)&from, &len)) < 0) {
                     perror ("recv");
                     exit(1);
                 }
                 message[n] = '\0'; 
                 printf("%s: Received message from %s, size=%d !!\n", 
                         name.nodename,
                         inet_ntoa(from.sin_addr), n);
                 printf("\t%s \n", message);


}

На мой взгляд есть несоответствие между

mcast_group.sin_addr.s_addr = inet_addr(argv[1]);

и

mreq.imr_interface.s_addr = inet_addr("192.168.4.228");

imho mreq.imr_interface.s_addr должен совпадать с mcast_group.sin_addr.s_addr

Но думаю, что проблема глубже. Несколько интерфейсов в одной сети - это источник граблей. В такой конфигурации нужно настраивать arp_filter arp_announce, arp_ignore и возможно rp_filter.

Запусти tcpdump на обоих интерфейсах и посмотри что происходит.

vel ★★★★★
()
Ответ на: комментарий от MKuznetsov

Мне не нужно два. Я присоединяюсь к интерфейсу с 192.168.4.228. На данный интерфейс идут мультикастовые сообщения и хочу их получить. Но почему то recvfrom их не видит. tcpdump- регистрирует наличие сообщений на этом интрефейсе.

AndyZot
() автор топика
Ответ на: комментарий от AndyZot

А причем тут арп??

При том. По умолчанию, настройки очень не строгие. Если есть несколько интерфейсов в одной ip-сети, то есть проблемы, когда ip-адрес одного интерфейса легко анонсится через другой интерфейс.

При нестрогих настройках у тебя может ip-адрес второго интерфейса анонсироваться через первый интерфейс с его mac-адресом.

Убедись tcpdump-ом, что arp отрабатывается правильно.

Вроде mcast_group.sin_addr.s_addr, по всем документам что я читал, должен содержать мультикаст адрес.

Схрена ли! Ты ведь используешь его для bind() на сокет. Это не групповой адрес, это локальный адрес! То, что ты переменную обозвал mcast_group - это твоё право, хоть горшком обзови.

Подключение к групповому адресу идет позже через setsockopt(recv_s, IPPROTO_IP, IP_ADD_MEMBERSHIP)

Кстати, IP_ADD_MEMBERSHIP умеет использовать индекс интерфейса вместо его ip-адреса.

vel ★★★★★
()