Pregunta

Algo así como

  

SELECT COUNT(*) AS c FROM BANS WHERE typeid=6 AND (SELECT ipaddr,cidr FROM BANS) MATCH AGAINST 'this_ip';

Así que no traes primero todos los registros de base de datos y, a continuación coinciden con ellos uno por uno.

Si c> 0 entonces fueron emparejados.

prohibiciones tabla:

id int auto incr PK
typeid TINYINT (1=hostname, 4=ipv4, 6=ipv6)
ipaddr BINARY(128)
cidr INT
host VARCHAR(255)

DB: MySQL 5

IP y el tipo IPV (4 o 6) es conocido cuando se consulta.

IP es, por ejemplo :: 1 en el formato binario

IP no permitidas es, por ejemplo :: 1/64

¿Fue útil?

Solución

Recuerde que los PI no son una dirección de texto, sino una identificación numérica. Tengo una situación similar (que estamos haciendo operaciones de búsqueda de geo-IP), y si almacena todas las direcciones IP como números enteros (por ejemplo, mi dirección IP es 192.115.22.33 por lo que se almacena como 3228767777), entonces usted puede buscar IPs fácilmente mediante el uso de los operadores de desplazamiento a la derecha.

La desventaja de todos estos tipos de operaciones de búsqueda es que no puede beneficiarse de los índices y hay que hacer un escaneo completo de tabla cada vez que haces una búsqueda. El esquema anterior se puede mejorar mediante el almacenamiento tanto la dirección IP de red de la red CIDR (el comienzo de la gama) y la dirección de difusión (el extremo de la gama), así que por ejemplo para almacenar 192.168.1.0/24 puede almacenar dos columnas:

network     broadcast
3232235776, 3232236031 

Y entonces usted puede hacerlo coincidir sólo tiene que hacer

SELECT count(*) FROM bans WHERE 3232235876 >= network AND 3232235876 <= broadcast

Esto permitirá almacenar redes CIDR en la base de datos y el partido contra direcciones IP de forma rápida y eficiente mediante el aprovechamiento de los índices numéricos rápidos.

Nota de discusión a continuación

MySQL 5.0 incluye una optimización de la consulta a distancia denominado " combinación de índice se cruzan ", que permite acelerar este tipo de consultas (y evitar recorridos de tablas completas), siempre que:

  • Hay un índice de varias columnas que coincide exactamente con las columnas de la consulta, con el fin. Por lo tanto -. Para la consulta de ejemplo anterior, sería necesario que el índice sea (network, broadcast)
  • Todos los datos se pueden recuperar a partir del índice. Esto es cierto para COUNT(*), pero no es cierto para SELECT * ... LIMIT 1.

MySQL 5.6 incluye una optimización llamada MRR que también acelerar la recuperación de fila completa, pero que está fuera del alcance de esta respuesta.

Otros consejos

Las direcciones IPv4, direcciones y máscaras de red de la red son todos los números de UINT32 y se presentan en forma legible por humanos como "puntos"-quads. El código de la tabla de enrutamiento en el kernel lleva a cabo de forma rápida comparación bit a bit Y al comprobar si una dirección está en un espacio de red determinado (red / máscara de red). El truco aquí es para almacenar las direcciones IP de cuatro segmentos, direcciones y máscaras de red de la red en las tablas como UINT32, y luego realizar la misma de 32 bits AND de bits para su juego. por ejemplo,

SET @test_addr = inet_aton('1.2.3.4');
SET @network_one = inet_aton('1.2.3.0');
SET @network_two = inet_aton('4.5.6.0');
SET @network_netmask = inet_aton('255.255.255.0');

SELECT (@test_addr & @network_netmask) = @network_one AS IS_MATCHED;
+------------+
| IS_MATCHED |
+------------+
|          1 |
+------------+

SELECT (@test_addr & @network_netmask) = @network_two AS IS_NOT_MATCHED;
+----------------+
| IS_NOT_MATCHED |
+----------------+
|              0 |
+----------------+

Para IPv4, puede utilizar:

SET @length = 4;

SELECT  INET_NTOA(ipaddr), INET_NTOA(searchaddr), INET_NTOA(mask)
FROM  (
  SELECT
        (1 << (@length * 8)) - 1 & ~((1 << (@length * 8 - cidr)) - 1) AS mask,
        CAST(CONV(SUBSTR(HEX(ipaddr), 1, @length * 2), 16, 10) AS DECIMAL(20)) AS ipaddr,
        CAST(CONV(SUBSTR(HEX(@myaddr), 1, @length * 2), 16, 10) AS DECIMAL(20)) AS searchaddr
  FROM  ip
) ipo
WHERE ipaddr & mask = searchaddr & mask

Hmmm. Se puede construir una tabla de las máscaras CIDR, unirse a ella, y luego comparar la ip anded (& en MySQL) con la máscara con la dirección ip bloque de prohibición. Habría que hacer lo que quiere?

Si no desea construir una tabla de máscaras, se podría calcular la máscara como -1 << (x-cidr) con x = 64 o 32 función.

generador de direcciones IP Ranges como enteros

  

Si su base de datos no soporta operaciones bit a bit de lujo, se puede utilizar un enfoque basado en el número entero simplificado.

El siguiente ejemplo está utilizando PostgreSQL:

select (cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 1) as bigint) * (256 * 256 * 256) +
        cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 2) as bigint) * (256 * 256      ) +
        cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 3) as bigint) * (256            ) +
        cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 4) as bigint)) 
        as network,

       (cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 1) as bigint) * (256 * 256 * 256) +
        cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 2) as bigint) * (256 * 256      ) +
        cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 3) as bigint) * (256            ) +
        cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 4) as bigint)) + cast(
          pow(256, (32 - cast(split_part('4.0.0.0/8', '/', 2) as bigint)) / 8) - 1 as bigint
        ) as broadcast;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top