2009-03-02 17 views
10

ソケットがIN6ADDR_ANYまたはINADDR_ANYにバインドされ、recvfrom()などの呼び出しを使用してソケット上のメッセージを受信する場合。メッセージがどのインタフェースから来たのかを知る方法はありますか?ソケットがメッセージを受信したインターフェイスを特定する方法は?

IPv6リンクスコープメッセージの場合、fromの引数recvfrom()は、scope_idフィールドがインターフェイスIDに初期化されることを期待していました。残念ながら、私のテストプログラムでは0に設定されています。

誰でもこの情報を見つける方法を知っていますか?

答えて

3

各インターフェイスへのバインディングとは別に、私はIPv4自体の方法を認識していません。

IPv6は、この欠点に対処するためにIPV6_PKTINFOソケットオプションを追加しました。このオプションを有効にすると、補助データとしてstruct in6_pktinfoが返されます。

+0

ありがとう、これは私が探していたものです。あまりにも悪いことに、Pythonソケットのモジュールではまだサポートされていません - 私はこの質問でlibcを指定しましたが。 :) – Readonly

0

私はC/C++ TCP/IPコーディングを行っていますが、これまでのところ、すべてのメッセージ(または派生したソケット)について覚えている限り、IPヘッダ情報に入ることができました。これらのヘッダーには、お求めのインターフェイスのIPアドレスとなる受信アドレスが含まれている必要があります。

-1

それぞれがこのソケットから受信例えばWindows上で決定的にこれを行うには、私が知っている唯一の方法は、生のソケットを使用することですGlomekが示唆したように、各インターフェイスに別のソケットを開くの外では、、、

SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_IP); 

になりますIP packetであり、送信元アドレスと宛先アドレスの両方を含んでいます。私が作業しているプログラムでは、ソケットをSIO_RCVALLオプションを使用してプロミスキャスモードにする必要があります。これは、ネットワーク上のインターフェイスが「見ている」すべてのIPパケットを取得することを意味します。私のアプリケーション用に明示的にパケットを抽出するには、IPとTCP/UDPヘッダーのアドレスとポートを使用してデータをフィルタリングする必要があります。明らかに、それはおそらくあなたが興味を持っている以上のオーバヘッドです。私はこれを言うために言及します - 私は生のソケットをプロミスキャスモードにすることはありませんでした。あなたがINADDR_ANYにバインドして、それを通常のソケットとして使用するかどうかは分かりません。あなたができることは私には分かります。私はそれを試したことはありません。

EDIT: Windowsのrawソケットに関する制限については、articleを参照してください。私のプロジェクトで直面した最大のハードルは、Windows 2000以降でrawソケットを開くためのAdministratorsグループのメンバーでなければならないということでした。

7

dwcが正しい場合、IPV6_PKTINFOはLinuxのIPv6で動作します。あなたは、私が送信元、送信先、およびインタフェースのアドレスを抽出し、例を構築してきたマンページIP(7)

+1

Linuxは全世界ではありません。移植性の問題を認識することは良いことです。 – dwc

+2

@dwc:Linuxをお持ちでない場合は、それをエミュレートする必要があります:P –

2

で詳細を見ることができます -

また、IP_PKTINFOは、IPv4のために動作します。簡潔にするため、エラーチェックは行われません。この重複を参照してください:Get destination address of a received UDP packet

// sock is bound AF_INET socket, usually SOCK_DGRAM 
// include struct in_pktinfo in the message "ancilliary" control data 
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)); 
// the control data is dumped here 
char cmbuf[0x100]; 
// the remote/source sockaddr is put here 
struct sockaddr_in peeraddr; 
// if you want access to the data you need to init the msg_iovec fields 
struct msghdr mh = { 
    .msg_name = &peeraddr, 
    .msg_namelen = sizeof(peeraddr), 
    .msg_control = cmbuf, 
    .msg_controllen = sizeof(cmbuf), 
}; 
recvmsg(sock, &mh, 0); 
for (// iterate through all the control headers 
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mh); 
    cmsg != NULL; 
    cmsg = CMSG_NXTHDR(&mh, cmsg)) 
{ 
    // ignore the control headers that don't match what we want 
    if (cmsg->cmsg_level != IPPROTO_IP || 
     cmsg->cmsg_type != IP_PKTINFO) 
    { 
     continue; 
    } 
    struct in_pktinfo *pi = CMSG_DATA(cmsg); 
    // at this point, peeraddr is the source sockaddr 
    // pi->ipi_spec_dst is the destination in_addr 
    // pi->ipi_addr is the receiving interface in_addr 
} 
関連する問題