Python: получение сокета IPv6 для приема пакетов, предназначенных для адреса Anycast маршрутизаторов подсети

Как получить сокет для приема пакетов, предназначенных для адреса Anycast для подсети-маршрутизаторов IPv6?

Я не смог найти никакой информации о том, как это сделать.

В отчаянии я попытался использовать socket.setsockopt, как если бы вы присоединились к многоадресной группе:

# 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)

А также с помощью связывания

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

Как и ожидалось, ни один из них не сработал. Есть ли способ сделать это?

2 ответа

Решение

Вместо IPV6_JOIN_GROUP попробуйте пройти IPV6_JOIN_ANYCAST на ваш s.setsockopt() код. К сожалению питон socket модуль не определяет его, но вы должны быть в состоянии передать целочисленный эквивалент. В линуксе IPV6_JOIN_ANYCAST является 27 а также IPV6_LEAVE_ANYCAST является 28, (определено в /usr/include/linux/in6.h)

Лучшая документация, которую я смог найти - это электронное письмо lkml, описывающее патч anycast для ядра Linux:

Интерфейс приложения для присоединения к группам anycast и выхода из них - это два новых вызова setsockopt(): IPV6_JOIN_ANYCAST и IPV6_LEAVE_ANYCAST. Аргументы совпадают с соответствующими операциями многоадресной рассылки.

Да пребудет с тобой танец каме!

IPV6_JOIN_ANYCAST а также IPV6_LEAVE_ANYCAST Опции сокетов - это нестандартные Linux-измы.

Если вы хотите, чтобы ваш код был переносимым, вам, вероятно, следует сделать это стандартным способом, то есть назначить произвольный адрес маршрутизаторов подсети соответствующему интерфейсу, затем привязать сокет к подстановочному адресу и отбросить все, что не отправлено маршрутизатору подсети. произвольный адрес. Помните, что вы не должны отправлять пакеты с произвольным адресом в поле источника, и вы не можете открыть сокет только для чтения в стандартном API сокетов.

Назначение адреса интерфейса должно быть привилегированной операцией в любой разумной операционной системе, и это та часть, которая не будет стандартной, что бы вы ни делали. Если вы должны сделать это программно, то это будет означать (например, на BSD) использование чего-то вроде SIOCAIFADDR_IN6 код и ioctl() системный вызов. Обязательно установите IN6_IFF_ANYCAST флаг в ifra_flags поле структуры запроса псевдонима интерфейса.

Другие вопросы по тегам