2017-01-26 20 views
2

Я имею дело со старой кодовой базой, в которой ipv6 multicast не работает. Когда я пытаюсь связать() сокет с ff01 :: 1, он терпит неудачу. Сокет создается в моем интерфейсе ethernet.Каковы требования для многоадресной рассылки ipv6 с использованием простых сокетов?

Привязка сокета к in6addr_any, которая является «::», приводит к успешному связыванию, но пакет не принимается, кроме тех, которые отправляются самим приложением, используя данный сокет (установлен IPV6_MULTICAST_LOOP) , Эти пакеты никогда не покидают приложение. Они не видны в wirehark при попытке захвата пакетов в интерфейсе ethernet. Видимы только входящие внешние многоадресные пакеты. Никто из них не доходит до моего заявления.

Система Ubuntu 16.04 с Linux 4.4.0.

Образец кода установки:

#define MCASTADDRC "ff01::1" 

    int mcast::bind_mcast(const char *interface) { 

    this->net = socket(AF_INET6, SOCK_DGRAM, 0);   
    inet_pton(AF_INET6,MCASTADDRC,&this->multicast.ipv6mr_multiaddr); 

    this->ifaceaddr.sin6_family = AF_INET6; 
    this->ifaceaddr.sin6_port = htons(SRVPORT); 
    this->ifaceaddr.sin6_addr = in6addr_any; 

    // interface for multicast 
    this->mcastaddr.sin6_family = AF_INET6; 
    this->mcastaddr.sin6_port = htons(SRVPORT); 
    this->mcastaddr.sin6_addr = this->multicast.ipv6mr_multiaddr; 


    int opcoes = fcntl(this->net, F_GETFL, 0); 

    if (fcntl(this->net, F_SETFL, opcoes | O_NONBLOCK) == -1) { 
     // fail 
     return(false); 
    } 

    if (bind(net, (struct sockaddr *) &this->ifaceaddr, sizeof(this->ifaceaddr)) == -1) { 
     // fail      
     return(false); 
    } 

    this->ifaceindex = if_nametoindex(interface); 
    this->multicast.ipv6mr_interface = this->ifaceindex; 
    this->ifaceaddr.sin6_scope_id = this->ifaceindex; 

    int mcast_loop = 1; 
    if (setsockopt(this->net, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &mcast_loop, sizeof(mcast_loop))) { 
     //fail 
     return(false); 
    } 

    if (setsockopt(this->net, IPPROTO_IPV6, IPV6_MULTICAST_IF, &this->ifaceindex, sizeof(this->ifaceindex))) { 
     //fail 
     return(false); 
    } 

    if (setsockopt(this->net, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &this->multicast, sizeof(this->multicast))) { 
     //fail 
     return(false); 
    } 
    int optval = 6000000; 
    int optlen = sizeof(optval); 
    if (setsockopt(this->net, SOL_SOCKET, SO_RCVBUF, &optval, sizeof(optval))) { 

     exit(0); 
    } 
    if (getsockopt(this->net, SOL_SOCKET, SO_RCVBUF, &optval, (socklen_t *)&optlen)) { 
     // fail 
     exit(0); 
    } 

    if(optval < 262142) { 
     // buffer is too small, we failed 
     exit(0); 
    } 

    return(true); // success 

} 
+0

Это C++, а не c! – Olaf

+0

@Olaf Вы правы, просто потому, что функции, которые я использую, имеют связь C, это не значит, что мой код - C. Я отредактировал вопрос соответствующим образом. –

ответ

4

Биты 12-15 (начиная с 0) в групповой адрес IPv6 определяет многоадресной области.

Многоадресный адрес формы ff01::/16 имеет область 1, которая означает интерфейс локальный. Такие пакеты не могут быть отправлены по любой сетевой ссылке. Вот почему вы не можете получать пакеты с таким адресом с других хостов.

Вам нужно использовать адрес с другим значением области. Объем 2 может быть отправлен по локальной сети, но не через маршрутизаторы, а область e (15) - глобально маршрутизируемая.

Кроме того, запустите netstat -ng, когда ваша программа запущена, чтобы убедиться, что вы присоединились к соответствующей группе многоадресной передачи на соответствующем интерфейсе.

Дополнительную информацию см. На странице Википедии по адресу multicast addresses.

+0

Это было полезно при определении того, что было не так в коде. Но тогда у меня такая странная ситуация, потому что пакеты, отправленные с других хостов, адресованы «ff01 :: 1». Таким образом, пакеты, отправленные в мою сетевую карту, сами являются локальными. Это выглядит не очень хорошо. –