valida - Convertir aplicaciones C++ TCP/IP de IPv4 a IPv6. ¿Difícil? ¿Vale la pena?
que es ipv4 y ipv6 (4)
Agregué el soporte de IPv6 a mi biblioteca de redes solo para IPv4 hace aproximadamente un año, y no me resultó muy difícil ni traumático hacerlo.
La única gran diferencia es cómo almacena las direcciones IP :
En IPv4 , los almacena como sockaddr_in
''s (o si eres travieso, como yo, como uint32_t''s).
Para IPv6 , debe almacenarlos como sockaddr_in6
''s (o alguna estructura equivalente de 128 bits).
Un buen paso previo a la conversión sería revisar su código y encontrar todos los lugares donde actualmente se almacenan las direcciones IPv4 , y abstraerlas en una clase de dirección IP genérica que luego se puede reimplementar internamente como una dirección IPv4 o una Dirección IPv6 .
Luego, vuelva a realizar la prueba para asegurarse de que no se haya roto nada en el modo IPv4 ... una vez que se haya verificado, debería poder cambiar a IPv6 con solo unos pocos cambios más (principalmente, cambiar PF_INET
a PF_INET6
, inet_aton()
a inet_pton()
, etc ...).
Mi biblioteca aún se distribuye como IPv4 solo de forma predeterminada, pero con la opción de definir una macro del preprocesador ( -DMUSCLE_USE_IPV6
) para recompilarla en modo compatible con IPv6 .
De esa manera, todavía se puede compilar en sistemas que no admiten IPv6. Una característica muy útil que encontré en el camino son las direcciones IPv6 asignadas a IPv4 : al especificar una de estas (esencialmente una dirección IPv4 con 0xFFFF
prefijada), obtienes un socket que puede hablar tanto de IPv4 como de IPv6, y por lo tanto un servidor que puede hablar con clientes IPv4 e IPv6 simultáneamente , sin tener que escribir rutas de código IPv4 e IPv6 separadas para todo.
En cuanto a si vale la pena el esfuerzo, eso realmente depende de lo que intenta hacer con el código. Yo diría que es una buena experiencia educativa y nada más, y permite que su software se use en entornos IPv6, lo que se volverá más común con el tiempo.
A lo largo de los años he desarrollado una pequeña cantidad de aplicaciones de servidor / cliente C ++ para Windows utilizando WinSock (enrutadores, servidores web / correo / FTP, etc ... etc ...).
Estoy empezando a pensar cada vez más en crear una versión IPv6 de estas aplicaciones (aunque también mantengo la versión original IPv4, por supuesto).
Preguntas:
- ¿Qué trampas puedo encontrar?
- ¿Es la portabilidad / conversión difícil?
- ¿Vale la pena la conversión?
Para una referencia (o para la diversión), puede despreciar un pico del código IPv4 en el núcleo de mis aplicaciones.
Mire los registros de cambios de algunos de los proyectos de código abierto que han implementado IPv6. La mayor parte es código Unix pero Winsock es muy similar a los sockets BSD.
Exim, Courier, Squid, Apache, BIND DNS son algunos lugares para comenzar a buscar.
Ulrich Drepper, el mantenedor de glibc, tiene un buen artículo sobre el tema,
http://people.redhat.com/drepper/userapi-ipv6.html
Pero no olvide el libro de Richard Steven, Unix Network Programming, Volume 1: La API de Sockets Networking para una buena práctica.
getaddrinfo y getnameinfo son tus amigos. En la medida de lo posible, sugiero que sean tus mejores amigos en tu búsqueda para proporcionar compatibilidad con IPv4 e IPv6 en una aplicación existente.
Si se hace correctamente agregando soporte de IPv6, también terminará abstrayendo el sistema hasta el punto en que se pueda ejecutar un futuro protocolo de IP desconocido sin modificación del código.
Normalmente, cuando se conecte, completará una estructura de socket, puerto, familia de direcciones, dirección IP, conversión de direcciones / puertos a orden de bytes de red, etc.
Con getaddrinfo
usted envía una dirección IP o nombre de host y puerto o nombre de puerto, y devuelve una lista enlazada con las estructuras y todo lo que está listo para pasar directamente a socket()
y connect()
.
getaddrinfo
es fundamental para trabajar con ambos protocolos IP, ya que sabe si el host tiene conectividad IPv6 o IPv4 y sabe si el interlocutor también lo hace al mirar DNS AAAA
vs A
registros y determina de forma dinámica qué protocolo (s) están disponibles para el servicio La solicitud de conexión específica.
Recomiendo altamente el uso de inet_pton()
, inet_addr()
o smiliar que son específicos de la versión IP. En la plataforma de Windows, específicamente inet_pton()
no es compatible con versiones anteriores de MS Windows (XP, 2003 y otros) a menos que usted se las arregle. También se recomienda no usar versiones separadas para IPv4 e IPv6 ... Esto no es viable como una solución técnica porque en un futuro próximo ambos protocolos deberán usarse simultáneamente y la gente puede no saber de antemano cuál usar. Las interfaces de socket son abstractas y es fácil detectar el soporte dualstack o IPv6 al intentar crear un socket IPv6 o al intentar configurar la opción de socket dualstack IPv6 para los oyentes. No hay razón para que la aplicación resultante no se ejecute en un sistema que no admita o no sepa sobre IPv6.
Para las conexiones salientes, use PF_UNSPEC
en getaddrinfo
modo que la familia de direcciones sea elegida para usted al realizar las conexiones salientes. En mi humilde opinión, esto es mejor que el enfoque dualstack porque permite que las plataformas que no son compatibles con dualstack funcionen.
Para las conexiones entrantes, puede enlazar sockets IPv4 / IPv6 por separado si es razonable dado el diseño o usar dualstack si no puede hacer escuchas por separado. Cuando se usa dualstack, getnameinfo
devuelve una dirección IPv6 para las direcciones IPv4, la cual IMHO termina siendo bastante inútil. Una pequeña rutina de utilidad puede convertir la cadena a una dirección IPv4 normal.
De acuerdo con mi experiencia, cuando termine, eliminó las dependencias de versiones de IP específicas y terminó con menos código de administración de socket de lo que comenzó.