2009-03-02 108 views
10

如果套接字绑定到IN6ADDR_ANYINADDR_ANY并且您使用诸如recvfrom()之类的调用来在套接字上接收消息。有没有办法找出消息来自哪个接口?如何判断套接字从哪个接口收到消息?

对于IPv6链接范围消息,我希望recvfrom()的from参数可能会将scope_id字段初始化为接口Id。不幸的是,它在我的测试程序中设置为0

有人知道一种方法来找出这些信息吗?

回答

3

除了绑定到每个接口之外,我不知道IPv4本身的一种方式。

IPv6增加了IPV6_PKTINFO套接字选项来解决这个缺点。使用该选项时,struct in6_pktinfo将作为辅助数据返回。

+0

谢谢,这就是我一直在寻找的。太糟糕了,它不被Python套接字模块支持 - 虽然我在这个问题中指定了libc。 :) – Readonly 2009-03-04 23:31:11

0

自从我一直在做C/C++ TCP/IP编码以来,它已经有一段时间了,但据我所知,在每个消息(或派生套接字)中,您都可以获得IP头信息。这些头文件应包含接收地址,该地址将是您所询问的接口的IP地址。

-1

外部接口上打开一个单独的插座为Glomek的建议,我知道要做到这一点明确在Windows上是使用原始套接字,如的唯一途径,

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

每个从此套接字接收会是IP packet,它包含源地址和目标地址。我工作的程序要求我使用SIO_RCVALL选项将套接字置于混杂模式。这样做意味着我可以获得网络上接口“看到”的每个IP数据包。为了明确地为我的应用程序提取数据包,我需要使用IP和TCP/UDP标头中的地址和端口来过滤数据。显然,这可能比你感兴趣的开销更大,我只是提到它 - 我从来没有使用原始套接字而没有将其放入混杂模式。所以我不确定你是否可以将它绑定到INADDR_ANY,并且只是将它作为一个常规套接字从这个点转发或不转发。在我看来,你可以;我从来没有尝试过。

编辑:阅读此article有关Windows上的原始套接字的限制。我在项目中面临的最大障碍是,必须成为Administrators组的成员才能在Windows 2000及更高版本上打开原始套接字。

7

dwc是对的,IPV6_PKTINFO将在Linux上适用于IPv6。

此外,IP_PKTINFO将IPv4的工作 - 你可以看到在手册页的IP(7)

+1

Linux不是全世界。了解可移植性问题是很好的。 – dwc 2009-03-04 16:29:33

2

细节我已经构造提取源,目的地和接口地址的例子。为简洁起见,不提供错误检查。看到这个副本: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 
}