linux macos solaris ipv6

linux - Identificación de la dirección de origen IPv6 preferida para un adaptador



macos solaris (1)

Si tiene un host habilitado para IPv6 que tiene más de una dirección de alcance global, ¿cómo puede identificar mediante programación la dirección preferida para bind() ?

Ejemplo de lista de direcciones:

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

En Solaris puede indicar una dirección preferida con un indicador de interfaz y está disponible mediante programación a través de SIOCGLIFCONF :

/usr/include/net/if.h: #define IFF_PREFERRED 0x0400000000 /* Prefer as source address */

Como se enumera en la lista de la interfaz:

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

Sin embargo, esto no es portátil a OSX, Linux, FreeBSD o Windows. Sin embargo, Windows es fácil de usar ya que tiene nombres de adaptadores basados ​​en UUID totalmente inútiles, desde la perspectiva de los administradores (según la versión de Windows).

Para Linux, este artículo detalla cómo el parámetro preferred_lft , donde lft es corto para "vida útil", puede ser modificado para ponderar el proceso de selección por parte del núcleo. Esta configuración no aparece convenientemente disponible en los resultados de SIOCGIFCONF o getifaddrs() sin embargo.

Así que quiero enlazar a eth0 , eri0 , o cualquier nombre de interfaz disponible. Las opciones son un poco crudas:

  1. Fallo en nombres de adaptadores que se resuelven en múltiples interfaces. OpenPGM este enfoque para manejar los transportes de multidifusión ( OpenPGM ) ya que el protocolo DEBE tener una dirección de envío única.
  2. Se unen a todo. Esto es una salida y sería inesperado para los usuarios.
  3. Enlazar al adaptador con SO_BINDTODEVICE . Esto requiere la capacidad del sistema CAP_NET_RAW en Linux, que puede ser una sobrecarga bastante incómoda para los administradores.
  4. Enlazar a la primera interfaz IPv6 en el adaptador. El ordenamiento suele ser completamente falso.
  5. Enlazado a la última interfaz. El artículo de David Croft implica que Linux hace esto, pero también es un poco falso.
  6. Enumerar en cada interfaz y crear un nuevo socket explícitamente para cada una.

Con la opción # 6 esperaría que normalmente fuera más inteligente y adopte el enfoque de que si solo hay una dirección de alcance local de enlace disponible, de lo contrario, vincule solo a las direcciones de alcance de enlace global disponibles.

Al conectarse a otro host, se puede usar RFC 3484 , pero como puede ver, todas las opciones dependen de la coincidencia con la dirección de destino:

  1. Prefiero la misma dirección. (es decir, el destino es la máquina local)
  2. Prefiero el alcance apropiado. (es decir, el alcance más pequeño compartido con el destino)
  3. Evite direcciones desaprobadas.
  4. Prefiere direcciones de casa. Prefiere la interfaz saliente. (es decir, prefiera una dirección en la interfaz que estamos enviando)
  5. Prefiero la etiqueta a juego.
  6. Prefiere direcciones públicas.
  7. Utilice el prefijo más largo de coincidencia.

En algunas circunstancias, podemos usar el número 7 aquí, pero en el ejemplo de interfaz anterior, ambas interfaces de alcance global tienen una longitud de prefijo de 64 bits.

RFC 3484 tiene las siguientes líneas pertinentes:

La arquitectura de direccionamiento IPv6 5 permite múltiples unicast
Direcciones a asignar a las interfaces. Estas direcciones pueden tener
diferentes ámbitos de accesibilidad (enlace local, sitio local o global).
Estas direcciones también pueden ser "preferidas" o "en desuso" 6 .

El enlace es a 6 , expandido de manera similar:

dirección preferida: una dirección asignada a una interfaz cuyo uso por los protocolos de capa superior no está restringido. Las direcciones preferidas se pueden usar como la dirección de origen (o destino) de los paquetes enviados desde (o hacia) la interfaz.

Pero no hay métodos para adquirir programáticamente este detalle.

Los apoyos a la API de Win32 que exponen un SIO_ADDRESS_LIST_SORT ioctl que permite a un desarrollador usar no solo la clasificación RFC 3484 sino también tener en cuenta las anulaciones del administrador del sistema. Linux tiene /etc/gai.conf como se usa para la ordenación RFC 3484 en getaddrinfo() pero no tiene API para acceder directamente a la clasificación. Solaris tiene el comando ipaddrsel . OSX está siguiendo a FreeBSD agregando ip6addrctl en 10.7.

edición: Algunas preocupaciones con la clasificación RFC 3484 se enumeran y se mencionan en este borrador de documento adicional del IETF:

http://tools.ietf.org/html/draft-axu-addr-sel-01

Solaris, por ejemplo, crea nuevas interfaces de alias para cada nueva
Dirección asignada a una interfaz física. Así que if_index también podría ser
utilizado para identificar de forma única una tabla de enrutamiento específica de la dirección de origen en
esa plataforma Otros sistemas operativos no funcionan de la misma manera.

Al autor le gusta el enfoque de Solaris de darle a cada interfaz IPv6 adicional un nuevo alias, de modo que eri0 se convierta en la dirección de alcance local del enlace, y eri0:1 o eri0:2 , etc., deben especificarse para usar una dirección de alcance global.

Claramente, aunque es una buena idea, no se puede esperar ver otros cambios de sistema operativo durante bastante tiempo.


No estoy seguro de que esta sea en la dirección que estás buscando, pero ...

Hurgando en el código ip del paquete iproute ( ip/ipaddress.c ) en linux, se muestra que el comando ip extrae los indicadores de interfaz como primary y secondary de una struct ifaddrmsg , miembro ifa_flags . El ifaddmsg parece adquirirse a través de una struct nlmsghdr documentada en man 7 netlink , y se usa a través de la interacción sendmsg y recvmsg con el kernel, que en general suena como un dolor real, pero al menos es programático. Si la primaria y la secundaria serían suficientes para ser útiles es una pregunta aparte.