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
поле структуры запроса псевдонима интерфейса.