Если у вас есть хост с поддержкой IPv6, который имеет более одного адреса в глобальной области, как вы можете программно определить предпочтительный адрес для bind ()
?
Пример списка адресов:
eth0 Link encap:Ethernet HWaddr 00:14:5e:bd:6d:da
inet addr:10.6.28.31 Bcast:10.6.28.255 Mask:255.255.255.0
inet6 addr: 2002:dce8:d28e:0:214:5eff:febd:6dda/64 Scope:Global
inet6 addr: fe80::214:5eff:febd:6dda/64 Scope:Link
inet6 addr: 2002:dce8:d28e::31/64 Scope:Global
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
В Solaris вы можете указать предпочтительный адрес с помощью флага интерфейса, и он доступен программно через SIOCGLIFCONF
:
/usr/include/net/if.h:
#define IFF_PREFERRED 0x0400000000 /* Prefer as source address */
Как указано в списке интерфейсов:
eri0: flags=2104841 mtu 1500 index 2
inet6 fe80::203:baff:fe4e:6cc8/10
eri0:1: flags=402100841 mtu 1500 index 2
inet6 2002:dce8:d28e::36/64
Это однако не переносится на OSX, Linux, FreeBSD или Windows. Windows отпущена легко, поскольку она имеет совершенно бесполезные с точки зрения администраторов имена адаптеров на основе UUID (в зависимости от версии Windows).
Для Linux в этой статье подробно описано, как параметр предпочтительный_lft
, где lft
- сокращение от «времени жизни», можно изменить, чтобы взвесить процесс выбора ядром. Однако этот параметр не всегда доступен в результатах SIOCGIFCONF
или getifaddrs ()
.
Поэтому я хочу выполнить привязку к eth0
, ] eri0
или любое другое доступное имя интерфейса. Варианты немного суровы:
SO_BINDTODEVICE
. Для этого требуется возможность системы CAP_NET_RAW
в Linux, что может быть довольно обременительным для администраторов. С вариантом №6 я ожидал бы вас обычно может быть умнее и использовать подход, согласно которому, если доступен только адрес локальной области связи, привязывайтесь к нему, в противном случае привязывайтесь только к доступным адресам области глобальной связи.
При подключении к другому узлу тогда RFC 3484 , но, как вы можете видеть, все варианты зависят от совпадения адреса назначения:
В некоторых случаях мы можем использовать здесь # 7, но в приведенном выше примере интерфейса оба интерфейса глобальной области имеют 64-битная длина префикса.
RFC 3484 содержит следующие подходящие строки:
Архитектура адресации IPv6 5 допускает множественную одноадресную рассылку
адреса, которые будут назначены интерфейсам. Эти адреса могут иметь
различные области достижимости (локальная для ссылки, локальная для сайта или глобальная).
Эти адреса также могут быть «предпочтительными» или «устаревшими» 6 .
Ссылка на RFC 2462 , расширенная аналогично:
предпочтительный адрес - адрес, назначенный интерфейс, использование которого к протоколы верхнего уровня не ограничены. Предпочтительные адреса могут использоваться в качестве адреса отправителя (или получателя) отправленных пакетов из (или в) интерфейс.
Но нет методов для программного получения этой детали.
Реквизит Win32 API, который предоставляет ioctl SIO_ADDRESS_LIST_SORT , который позволяет разработчику использовать не только сортировку RFC 3484, но и принимать во внимание любые переопределения системного администратора. В Linux есть /etc/gai.conf
, который используется для сортировки RFC 3484 в getaddrinfo ()
, но нет API для прямого доступа к сортировке. В Solaris есть команда ipaddrsel
. OSX следует за FreeBSD, добавив ip6addrctl
в 10.7.
edit: Некоторые проблемы с сортировкой RFC 3484 перечислены и упомянуты в этом дополнительном проекте документа IETF:
http: // tools .ietf.org / html / draft-axu-addr-sel-01
Solaris, например, создает новые псевдонимы-интерфейсы для каждого нового
адрес, присвоенный физическому интерфейсу. Таким образом, if_index также может быть
используется для однозначной идентификации конкретной таблицы маршрутизации адреса источника на
эта платформа. Другие операционные системы не работают таким же образом.
Автору нравится подход Solaris, в котором каждому дополнительному интерфейсу IPv6 назначается новый псевдоним, так что eri0
становится адресом локальной связи, а eri0: 1
или eri0: 2
и т. д.должен быть указан для использования адреса в глобальной области.
Очевидно, что, хотя это хорошая идея, нельзя было ожидать увидеть другие изменения ОС в течение некоторого времени.