views:

540

answers:

2

How do you get a socket to receive packets destined for the IPv6 Subnet-Routers Anycast address?

I haven't been able to find any informationn on how to do this.

In a fit of desparation, I've tried using socket.setsockopt as you would to join a multicast group:

# 7 is the interface number 
s = socket(AF_INET6, SOCK_DGRAM)
packed_iface_num = struct.pack("I", 7) 
group = inet_pton(AF_INET6, 'fd36:d00d:d00d:47cb::') + packed_iface_num

# socket.error: (22, 'Invalid argument')
s.setsockopt(IPPROTO_IPV6, IPV6_JOIN_GROUP,  group)

And also using bind

# socket.error: (99, 'Cannot assign requested address')
s.bind(('fd36:773e:6b4c:47cb::', 9876))

As expected, neither of these worked. Is there a way to do this?

+1  A: 

Instead of IPV6_JOIN_GROUP, try passing IPV6_JOIN_ANYCAST to your s.setsockopt() code. Unfortunately the Python socket module doesn't define it but you should be able to pass the integer equivalent instead. In Linux IPV6_JOIN_ANYCAST is 27 and IPV6_LEAVE_ANYCAST is 28. (defined in /usr/include/linux/in6.h)

The best documentation I could find is from this lkml e-mail describing the anycast patch to the Linux kernel:

The application interface for joining and leaving anycast groups is 2 new setsockopt() calls: IPV6_JOIN_ANYCAST and IPV6_LEAVE_ANYCAST. The arguments are the same as the corresponding multicast operations.

May the dancing kame be with you!

joeforker
A: 

The IPV6_JOIN_ANYCAST and IPV6_LEAVE_ANYCAST socket options are non-standard Linux-isms.

If you'd like your code to be portable, then you should probably do it the standard way, i.e. assign the subnet routers anycast address to the appropriate interface, then bind your socket to the wildcard address and discard everything not sent to the subnet router anycast address. Remember, you're not supposed to send packets with the anycast address in the source field, and you can't open a read-only socket in the standard sockets API.

Assigning an interface address should be a privileged operation on any reasonable operating system, and that's the part that isn't going to be standard whatever you do. If you must do that programmatically, then it will mean (on BSD for example) using something like the SIOCAIFADDR_IN6 code and the ioctl() system call. Make sure to set the IN6_IFF_ANYCAST flag in the ifra_flags field of the interface alias request structure.

james woodyatt