Подтвердить что ты не робот

Идентификация предпочтительного адреса источника 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<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 на адаптере. Заказ имеет тенденцию быть полностью фиктивным.
  • Привязать к последнему интерфейсу. Дэвид Крофт подразумевает, что Linux делает это, но также немного фиктивный.
  • Перечислите все интерфейсы и создайте новый ящик явно для каждого.

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

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

  • Предпочитайте тот же адрес. (то есть адресат является локальной машиной)
  • Предпочитают подходящую область. (т.е. наименьшая область, совместно используемая с пунктом назначения).
  • Избегайте устаревших адресов.
  • Предпочитаете домашние адреса. Предпочитаю исходящий интерфейс. (т.е. предпочитают адрес на интерфейсе, который мы отправляем из)
  • Предпочитает совпадение метки.
  • Предпочитают публичные адреса.
  • Используйте самый длинный соответствующий префикс.

В некоторых случаях мы можем использовать # 7 здесь, но в примере интерфейса выше оба интерфейса глобальной области имеют длину 64-битного префикса.

RFC 3484 имеет следующие соответствующие строки:

Архитектура адресации IPv6 5 позволяет использовать несколько одноадресных объявлений адреса, назначаемые интерфейсам. Эти адреса могут иметь различные области достижимости (локальная связь, локальная локальная или глобальная).
Эти адреса также могут быть "предпочтительными" или "устаревшими" 6.

Ссылка, относящаяся к RFC 2462, аналогично расширена:

предпочтительный адрес - адрес, назначенный интерфейсу, использование которого от         протоколы верхнего уровня не ограничены. Предпочтительные адреса могут         использоваться в качестве исходного (или целевого) адреса отправленных пакетов         от (или до) интерфейса.

Но никакие методы программно не приобретают эту деталь.

Подходит для API Win32, который предоставляет 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 и т.д. должен быть указан для использования глобального -scope адрес.

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

4b9b3361

Ответ 1

Я не уверен, что это в том направлении, которое вы ищете, но...

Прошивка в пакете iproute ip code (ip/ipaddress.c) в Linux показывает, что команда ip выкапывает интерфейсные флаги, такие как primary и secondary от struct ifaddrmsg, member ifa_flags. ifaddmsg, по-видимому, получен через struct nlmsghdr, который документирован в man 7 netlink и используется через sendmsg и recvmsg взаимодействие с ядром, что в целом звучит как королевская боль, но, по крайней мере, программная. Независимо от того, будет ли первичный и вторичный, чтобы быть полезным, это отдельный вопрос.