Exposing the sin6_scope_id parameter in socket_recvfrom, socket_sendto and socket_connect for IPv6 link-local unicast/multicast communications. #220

wants to merge 3 commits into


None yet
3 participants

This patch adds an extra optional parameter to the functions which sets/gets the sin6_scope_id member. The optional parameter is IPv6 only.

int socket_recvfrom(resource socket, string &buf, int len, int flags, string &name [, int &port [, int &ifindex]])
int socket_sendto(resource socket, string buf, int len, int flags, string addr [, int port [, int ifindex]])
bool socket_connect(resource socket, string addr [, int port [, int ifindex]])

When dealing with link-local connections in IPv6 as all interfaces have a connection to the same subnet, knowing which interface a packet was received on or where to send it to has become important.

At the OS layer, the sockaddr_in6 structure carries an extra member called sin6_scope_id (which is set by the OS when receiving packets and is used to determine the interface for outgoing packets). This member exists in all current OS's that implement the sockets functionality.

With connection-less unicast or multicast protcols, the current socket_recvfrom() function has no mechanism for telling you the interface the data was received on, and hence there is no way of replying to a packet reliably. For example, in linux what will happen when sin6_scope_id is not set when sending a packet with a link-local destination depends on the kernel version (v2.4+ drop the packet as invalid, 3.0+ send it via the interface with the lowest index) and as such a packet received on eth1 might mistakenly be replied to via eth0.

There are other mechanisms which have been defined for dealing with this (for eg, an address can be specified as [fe80::1:2:3:4%eth0] which tells the OS to send the packet via eth0. The bind could be done on a per-interface basis, etc etc. However this patch implements a simple mechanism for dealing with it.

The use-case for this is where a service binding to a port (udp for example) receives a packet from another host via either multicast or unicast and the service wishes to reply then it can be done like so:

$socket = socket_create(AF_INET6, SOCK_DGRAM, SOL_UDP);
socket_bind($socket,  "::0", 34000);
$return = socket_recvfrom($socket, $buffer, $length, $flags, $from, $port, $ifindex);
socket_sendto($socket, "somereply", strlen("somereply"), $flags, $from, $port, $ifindex);

The extra argument ($ifindex) is set when socket_recvfrom is called and then can be passed straight into socket_sendto

Alternatively, this could also be used with socket_connect to then setup a TCP connection via

socket_connect($socket, $from, $port, $ifindex);

With the ifindex argument, this ensures the packet will exit via an appropriate interface.


cataphract commented Oct 22, 2012

I must say I really don't like the direction you're giving to to socket_sendto and socket_recvfrom in putting protocol specific parameters in what should be a general interface. It's true the harm is done -- the port is there -- and there is no backward compatible way of fixing that error. However, I don't know if the alternatives are better.

Do not call "interface index" to the scope id. That is an implementation detail, and even then it's not accurate for site-local addresses. When sending, the outgoing interface can be specified with a sticky IPV6_PKTINFO (via setsockopt) or by passing ancillary data to sendmsg (which we currently do not expose). For receiving, using IPV6_RECVPKTINFO and recvmsg would be necessary. This also works for addresses with other scopes. Supporting recvmsg/sendmsg (and some types of ancillary data) would have value in itself.

But in any case, I think this passes a benefit-cost analysis. Add some tests and I'll merge it.

dsp was assigned Oct 23, 2012

Well, it doesnt necessarily have to be done this way and im happy to implement it differently as its not really an urgent piece of functionality (more of a corner case if anything). The other choice I thought of when attempting to achieve the scope settings was to add a flag telling the socket_ calls to parse the scope out of the address (i.e. as [ff12:34::4%1] in the address parameter) but it might cause a little confusion as the OS level calls do implement this already, but it doesnt seem hugely consistent. Currently OS's though do seem to use that sin6_scope_id as an interface index, hence why im using the terms interchangeably.

But, if implementing recvmsg/sendmsg is a better choice then perhaps thats the route to go down?

takigama closed this Dec 27, 2012

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment