views:

306

answers:

4

If a socket is bound to IN6ADDR_ANY or INADDR_ANY and you use a call such as recvfrom() to receive messages on the socket, is there a way to find out which interface the message came from?

In the case of IPv6 link-scope messages, I was hoping that the from argument of recvfrom() would have the scope_id field initialized to the interface id. Unfortunately it's set to 0 in my test program.

Anybody know of a way to find out this information?

A: 

Its been a while since I've been doing C/C++ TCP/IP coding but as far as I remember on every message (or derived socket) you can get into the IP headers information. These headers should include the receiving address which will be the IP of the interface you are asking about.

A: 

Outside of opening a separate socket on each interface as Glomek suggested, the only way I know to do this definitively on Windows is to use a raw socket, e.g.,

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

Each receive from this socket will be an IP packet, which contains both the source and destination addresses. The program I work on requires me to put the socket in promiscuous mode using the SIO_RCVALL option. Doing this means I get every IP packet the interface "sees" on the network. To extract packets expressly for my application requires me to filter the data using the addresses and ports in the IP and TCP/UDP headers. Obviously, that's probably more overhead than you're interested in. I only mention it to say this - I've never used a raw socket without putting it in promiscuous mode. So I'm not sure if you can bind it to INADDR_ANY and just use it as a regular socket from that point forward or not. It would seem to me that you can; I've just never tried it.

EDIT: Read this article for limitations regarding raw sockets on Windows. This biggest hurdle I faced on my project was that one has to be a member of the Administrators group to open a raw socket on Windows 2000 and later.

Matt Davis
+2  A: 

Apart from binding to each interface, I'm not aware of a way with IPv4, per se.

IPv6 has added the IPV6_PKTINFO socket option to address this shortcoming. With that option in effect, a struct in6_pktinfo will be returned as ancillary data.

dwc
Thanks, this is what I was looking for. Too bad it's not supported by the Python socket's module yet--although I did specify libc in this question. :)
Readonly
+2  A: 

dwc is right, IPV6_PKTINFO will work for IPv6 on Linux.

Moreover, IP_PKTINFO will work for IPv4 — you can see details in manpage ip(7)

darkk
Linux is not the whole world. It's good to be aware of portability issues.
dwc