Если у вас есть хост с поддержкой 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<UP,RUNNING,MULTICAST,DHCP,ROUTER,IPv6> mtu 1500 index 2
inet6 fe80::203:baff:fe4e:6cc8/10
eri0:1: flags=402100841<UP,RUNNING,MULTICAST,ROUTER,IPv6,PREFERRED> mtu 1500 index 2
inet6 2002:dce8:d28e::36/64
Этоне переносится на OSX, Linux, FreeBSD или Windows.Windows легко выпустить, хотя она совершенно бесполезна, с точки зрения администраторов, имен адаптеров на основе UUID (в зависимости от версии Windows).
Для Linux эта статья подробно описывает, как параметр preferred_lft
, где lft
- сокращение от «времени жизни», может быть изменено ядром для взвешивания процесса выбора.Этот параметр не всегда доступен в результатах SIOCGIFCONF
или getifaddrs()
.
Поэтому я хочу привязать к eth0
, eri0
или какому-либо доступному имени интерфейса.Возможны некоторые варианты:
- Сбой при разрешении имен адаптеров для нескольких интерфейсов.Я использую этот подход для обработки многоадресных транспортов ( OpenPGM ), так как протокол ДОЛЖЕН иметь только один адрес отправки.
- Привязать ко всему.Это отскок и будет неожиданным для пользователей.
- Привязать к адаптеру с помощью
SO_BINDTODEVICE
.Для этого требуется CAP_NET_RAW
системная возможность в Linux, что может быть довольно громоздким для администраторов. - Привязка к первому интерфейсу IPv6 на адаптере.Порядок, как правило, ложный.
- Привязка к последнему интерфейсу. Дэвид Крофт * Статья 1042 * подразумевает, что 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
и т. Д. Должны быть указаны для использования адреса глобальной области действия.
Очевидно, что, хотя это хорошая идея, никто не может ожидать изменения других ОС в течение достаточно долгого времени.