2017-01-26 18 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のマルチキャストアドレスは、インターフェイスlocalを意味する1のスコープを持ちます。このようなパケットは、ネットワークリンクを介して送信されないことがあります。だからこそ、このようなアドレスのパケットは他のホストから受信できません。

異なるスコープ値を持つアドレスを使用する必要があります。 2のスコープはローカルネットワーク経由で送信されますが、ルータ間では送信されませんが、e(15)のスコープはグローバルにルーティング可能です。

また、適切なインターフェイスで適切なマルチキャストグループに加入していることを確認するために、プログラムが実行されているときにnetstat -ngを実行します。

詳細については、multicast addressesのWikipediaページを参照してください。

+0

これは、コードの何が間違っているかを判断するのに役立ちました。しかし、他のホストから送られてきたパケットはすべて "ff01 :: 1"に宛てられているので、私は非常に奇妙な状況に陥っています。したがって、自分のNICに送信されるパケット自体がリンクローカルです。これは良く見えません。 –

関連する問題