2009-01-07 36 views
33

¿Cómo hago eso?Cómo almacenar una dirección compatible con IPv6 en una base de datos relacional

En este momento, IPv6 no se utilizará, pero tengo que diseñar la aplicación para que esté lista para IPv6. Es necesario almacenar direcciones IP y bloques CIDR (también BGP NLRI, pero esta es otra historia) en una base de datos MySQL. Siempre he usado una INT para IPv4 + una TINYINT para masklen, pero IPv6 es de 128 bits.

¿Qué enfoque será mejor para eso? 2xBIGINT? CHAR(16) para almacenamiento binario? CHAR(39) para el almacenamiento de texto? 8xSMALLINT en una mesa dedicada?

¿Qué recomendarías?

Respuesta

19

no estoy seguro de que es el derecho respuesta para MySQL dado que todavía no soporta formatos de dirección IPv6 de forma nativa (aunque al mismo tiempo "WL#798: MySQL IPv6 support" sugiere que iba a ser en MySQL v6.0, actual la documentación no respalda eso).

Sin embargo, propongo ir por 2 * BIGINT, pero asegúrate de que NO ESTÉ FIRMADO. Hay una especie de división natural en el límite de dirección/64 en IPv6 (ya que a/64 es el tamaño de bloque de red más pequeño) que se alinearía muy bien con eso.

+3

Decisión final tomada: 2xBIGINT si el segundo bigint es NULL, entonces significa IPv4 – azerole

+9

en realidad - si estuviera haciendo esto, dejaría el _primero_ bigint como NULL para IPv4, o usaría un campo separado. De esta forma, la parte IPv4 aparece en la palabra menos significativa. – Alnitak

+8

Y si estuviera haciendo esto, almacenaría direcciones IPv4 en el formato V4COMPAT de direcciones IPv6, es decir, en el rango ::/96. –

1

¿La dirección IP va a ser utilizada por un programa para el que tiene sentido binario? ¿O preferiría almacenar una representación de texto? Además, con IPv6, es menos probable que use la dirección en general y que tenga más probabilidades de usar nombres de host. Si eso es relevante depende de la aplicación, en parte. CHAR (16) sería una mala elección; char es para datos de caracteres y no le gustan las grandes transmisiones de cero bytes que prevalecen en las direcciones IPv6. 2 x BIGINT sería incómodo: dos campos que son realmente uno (además, ¿es el valor almacenado big-endian o little-endian?). Utilicé un tipo BINARIO de tamaño fijo o, si no está disponible, un tipo de blob.

+1

Si lo almacena en un BINARIO, entonces nunca va a tener alguna posibilidad de hacer operadores bit a bit dentro del propio DB para encontrar direcciones coincidentes (es decir, todas aquellas direcciones que coinciden con una subred particular) – Alnitak

+3

Es por eso que sugerí formato de texto, en el que puedes hacer correspondencias de expresiones regulares (aunque no mencioné eso) . Almacenarlo en cualquier formato binario va a ser complicado, a menos que lo actualice a un tipo definido por el usuario (¿MySQL lo admite?) Y proporcione los operadores adecuados. –

6

Si se inclina hacia char (16), definitivamente use binary (16) en su lugar. binary (n) no tiene un concepto de colación o conjunto de caracteres (o más bien, es un char (n) con un conjunto de caracteres/colación de 'binary'). El valor predeterminado para char en mysql es latin1_swedish_ci, lo que significa que intentará hacer una selección insensible a mayúsculas y minúsculas y comparaciones para valores de bytes que son puntos de código válidos en latin1, lo que le causará todo tipo de problemas inesperados.

Otra opción es usar decimal (39, 0) zerofill unsigned, no tan eficiente como dos bigints (decimal usará 4 bytes por nueve dígitos en las versiones actuales de mysql), pero le permitirá mantener todo en una columna e imprimir muy bien.

+0

En un proyecto que estoy trabajando ahora estamos usando el enfoque decimal (39,0) y funciona bien, con algunas excepciones. Algunas veces tienes que TOMAR los valores para las comparaciones. es decir, WHERE ipv6 = CAST ('cadena que contiene numv ipv6' AS decimal (39,0)). Especialmente en lenguajes que no admiten tipos numéricos de 128 bits, y el enlace de parámetros de la biblioteca mysql no es lo suficientemente inteligente. – Diego

4

me gustaría ir para el 39 completo de caracteres "estándar" formato impreso: -

 
"2001:0db8:85a3:0000:0000:8a2e:0370:7334" 

40 con un terminador nulo.

Este es el formato utilizado por las herramientas de línea de comandos * nix, y el formato de una dirección IPv6 es normaly (?) Registrados en.

+25

No lo haría. Las direcciones IPv6 a menudo se muestran en formato abreviado, y también sería bastante ineficiente buscar en la tabla cualquier dirección que esté en una subred particular, particularmente si la subred abarca un límite de nybble. – Alnitak

+0

@James Anderson: Y lo que es peor es que no se puede comparar si un determinado IPv6 se encuentra en un rango específico (geolocalización, prohibición de rango de IP). –

+0

@Quandary Eso fue cierto con el formato de puntos IPv4. Sin embargo, el formato impreso IPv6 en la forma expandida (39 caracteres) se puede usar para las comparaciones. –

1

estoy trabajando con un proyecto de más largo emparejamiento de prefijo, por lo separo la dirección en 4 enteros para direcciones IPv4. Funciona bien. Extendería eso a las direcciones IPv6.

6

Tenga en cuenta que la longitud máxima de una dirección IPv6, incluido el identificador de ámbito, es de 46 bytes, tal como lo define INET6_ADDRSTRLEN en los encabezados C estándar. Para el uso de Internet, debe poder ignorar el zone identifier (% 10, # eth0, etc.), pero tenga en cuenta que getaddrinfo devuelve un resultado más largo que el esperado.

Cuestiones relacionadas