2017-01-26 9 views
2

ipv6 멀티 캐스트가 작동하지 않는 오래된 코드베이스를 다루고 있습니다. ff01 :: 1에 소켓을 bind()하려고하면 실패합니다. 소켓이 이더넷 인터페이스에서 생성됩니다.일반 소켓을 사용하는 ipv6 멀티 캐스팅의 요구 사항은 무엇입니까?

":"인 in6addr_any에 소켓을 바인드하면 바인딩이 성공하지만 주어진 소켓을 사용하여 응용 프로그램 자체가 보내는 패킷을 제외하고는 패킷이 수신되지 않습니다 (IPV6_MULTICAST_LOOP가 설정 됨) . 이러한 패킷은 응용 프로그램을 벗어나는 것처럼 보이지 않습니다. 그들은 이더넷 인터페이스에서 패킷을 캡처하려고 할 때 wireshark에서 보이지 않습니다. 들어오는 외부 멀티 캐스트 패킷 만 볼 수 있습니다. 그들 중 누구도 내 응용 프로그램에 도달하지 못합니다.

시스템은 Linux 4.4.0의 Ubuntu 16.04입니다.

설정 코드의 샘플 :

#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"로 처리되기 때문에이 매우 이상한 상황이 발생합니다. 따라서 NIC에 전송되는 패킷 자체는 링크 로컬입니다. 이것은 좋지 않습니다. –