Определение предпочтительного исходного адреса IPv6 для адаптера

Если у вас есть хост с поддержкой 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 или любое другое доступное имя интерфейса. Варианты немного суровы:

  1. Ошибка при разрешении имен адаптеров в несколько интерфейсов. Я использую этот подход для обработки многоадресных транспортов ( OpenPGM ), поскольку протокол ДОЛЖЕН иметь только один адрес отправки.
  2. Привязать ко всему. Это отговорка и неожиданность для пользователей.
  3. Подключитесь к адаптеру с помощью SO_BINDTODEVICE . Для этого требуется возможность системы CAP_NET_RAW в Linux, что может быть довольно обременительным для администраторов.
  4. Привязка к первому интерфейсу IPv6 на адаптере. Упорядочивание имеет тенденцию быть полностью фиктивным.
  5. Привязка к последнему интерфейсу. Статья Дэвида Крофта подразумевает, что Linux делает это, но это также немного подделка.
  6. Перечислить по каждому интерфейсу и создать новый сокет явно для каждого.

С вариантом №6 я ожидал бы вас обычно может быть умнее и использовать подход, согласно которому, если доступен только адрес локальной области связи, привязывайтесь к нему, в противном случае привязывайтесь только к доступным адресам области глобальной связи.

При подключении к другому узлу тогда RFC 3484 , но, как вы можете видеть, все варианты зависят от совпадения адреса назначения:

  1. Предпочитать тот же адрес. (т. е. адресатом является локальный компьютер)
  2. Предпочитайте соответствующую область. (т.е. наименьшая область, совместно используемая с местом назначения)
  3. Избегайте устаревших адресов.
  4. Предпочитайте домашние адреса. Предпочитаю исходящий интерфейс. (т.е. предпочитаю адрес в интерфейсе, который мы отправляем out of)
  5. Предпочитать соответствующую метку.
  6. Предпочитать общедоступные адреса.
  7. Использовать самый длинный совпадающий префикс.

В некоторых случаях мы можем использовать здесь # 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 и т. д.должен быть указан для использования адреса в глобальной области.

Очевидно, что, хотя это хорошая идея, нельзя было ожидать увидеть другие изменения ОС в течение некоторого времени.

16
задан Steve-o 26 August 2011 в 09:32
поделиться