Определение предпочтительного исходного адреса IPv6 для адаптера - PullRequest
16 голосов
/ 26 августа 2011

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

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

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

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

  1. Предпочитают тот же адрес.(т. е. пункт назначения - локальная машина)
  2. Предпочитают соответствующую область.(т. е. наименьшая область общего доступа с адресатом)
  3. Избегать устаревших адресов.
  4. Предпочитать домашние адреса.Предпочитаю исходящий интерфейс.(т. е. предпочитайте адрес в интерфейсе, из которого мы отправляем)
  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 и т. Д. Должны быть указаны для использования адреса глобальной области действия.

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

1 Ответ

2 голосов
/ 04 августа 2013

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

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

...