2011-08-26 19 views
16

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()?Identificación de la dirección de origen de IPv6 preferida para un adaptador

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 una bandera 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 */ 

Tal como se recoge en la lista de interfaces:

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 

Esto no es portátil para OSX, Linux, FreeBSD, o Windows sin embargo. Sin embargo, Windows es fácil de usar, ya que es completamente inútil, desde la perspectiva de los administradores, los nombres de los adaptadores basados ​​en UUID (dependiendo de la versión de Windows).

Para Linux this article detalles de cómo el parámetro de preferred_lft, donde lft es la abreviatura de "vida útil", puede ser alterado para ponderar el proceso de selección por el núcleo. Esta configuración no aparece convenientemente disponible en los resultados de SIOCGIFCONF o getifaddrs().

Por lo tanto, quiero enlazar a eth0, eri0, o cualquier nombre de interfaz disponible. Las opciones son un poco austeras:

  1. Falla en los nombres de los adaptadores que se resuelven en varias interfaces. Tomo este enfoque para manejar transportes de multidifusión (OpenPGM) ya que el protocolo DEBE tener una dirección de envío única.
  2. Enlace a todo. Esta es una excepción y sería inesperado para los usuarios.
  3. Enlace al adaptador con SO_BINDTODEVICE. Esto requiere la capacidad del sistema CAP_NET_RAW en Linux, lo que puede ser una tarea bastante engorrosa para los administradores.
  4. Enlace a la primera interfaz IPv6 en el adaptador. El orden tiende a ser completamente falso.
  5. Enlace a la última interfaz. El artículo de David Croft implica que Linux hace esto, pero también es un poco falso.
  6. Enumere sobre cada interfaz y cree un nuevo socket explícitamente para cada una.

Con la opción n. ° 6, podría esperar ser más inteligente y adoptar el enfoque de que si solo está disponible una dirección de alcance de enlace local, enlace a las direcciones de alcance de enlace global disponibles.

Cuando se conecta a otro host a continuación RFC 3484 se puede utilizar, pero como se puede ver todas las opciones que dependen de la dirección de destino a juego:

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

En algunas circunstancias podemos usar el n. ° 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:

El IPv6 arquitectura de direccionamiento 5 permite múltiples unidifusión
direcciones a asignar a interfaces. Estas direcciones pueden tener
alcances de accesibilidad diferentes (link-local, site-local o global).
Estas direcciones también pueden ser "preferidas" o "obsoletas" 6.

El enlace siendo a RFC 2462, expandido parecida:

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

Pero no hay ningún método para adquirir este detalle mediante programación.

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

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

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

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

El autor le gusta el enfoque de dar a cada interfaz de IPv6 adicional de un nuevo alias de Solaris, de manera que eri0 se convertiría en la dirección de alcance de enlace local, y eri0:1 o eri0:2, etc., se deben especificar para utilizar una dirección de alcance mundial .

Claramente, aunque era una buena idea, uno no podía esperar ver otro sistema operativo cambiar durante bastante tiempo.

+0

¿Cuál es la razón por la que desea enlazar a una dirección específica en lugar de dejar que el sistema operativo elija para usted? –

+1

Implementación @Sander en entornos con varias NIC, por ejemplo, puede tener Internet, DMZ, intranet o tener redes dedicadas a ciertos flujos de tráfico, como datos entrantes sin procesar, datos procesados ​​y tráfico del cliente. –

+0

Entiendo. Por lo general, trato de asegurarme de que el comportamiento predeterminado funciona, por ejemplo, usando direcciones globales para comunicación externa y ULA para la NIC interna, de modo que la coincidencia de prefijo más larga funcione, pero eso no siempre es posible. Y no funciona cuando se envía a un destino de multidifusión porque ULA siempre tiene una coincidencia más larga. Especificar la dirección de origen para enlazar en un archivo de configuración es una opción. –

Respuesta

2

No estoy seguro de que esto es en la dirección que usted está buscando, pero ...

hurgando en el código ip del paquete iproute (ip/ipaddress.c) bajo Linux muestra que el comando ip desentierra banderas de interfaz como primary y secondary de struct ifaddrmsg, miembro ifa_flags. El ifaddmsg parece ser adquirido a través de struct nlmsghdr que está documentado en man 7 netlink, y se usa a través de sendmsg y recvmsg interacción con el kernel, que en general suena como un dolor real pero al menos es programático. Ya sea primario y secundario sería suficiente para ser útil es una pregunta separada.

+1

Al final del hoyo del conejo, se puede enviar una solicitud 'RTM_GETADDR' a través de netlink para devolver una lista de direcciones para IPv6 con un atributo' IFA_CACHEINFO' que incluye el parámetro 'ifa_preferred' que si es cero no es preferido. –

Cuestiones relacionadas