2008-10-02 51 views
12

Para mi aplicación de servidor, necesito verificar si hay una dirección IP en nuestra lista negra.¿Cómo compararías la dirección IP?

¿Cuál es la forma más eficiente de comparar direcciones IP? ¿Convertiría la dirección IP a un número entero y los compararía de manera eficiente?

+1

es su lista negra un archivo, cargado en la memoria, en una base de datos, ¿qué? –

+1

No importa dónde se encuentre la lista negra. Todavía sería comparado por la CPU. Pero si cree que debería mencionar esto en mi pregunta, por favor infórmeme sobre por qué la ubicación de la lista negra es importante. – MrValdez

+1

@MrValdez: El tiempo para recuperar una lista negra del disco excedería por mucho el tiempo para convertir todas sus entradas de int a cadena o viceversa. – MSalters

Respuesta

27

Depende del idioma que esté utilizando, pero una dirección IP generalmente se almacena como un entero sin signo de 32 bits, al menos en la capa de red, lo que hace que las comparaciones sean bastante rápidas. Incluso si no lo es, a menos que esté diseñando una aplicación de conmutación de paquetes de alto rendimiento, no es probable que sea un cuello de botella de rendimiento. Evite la optimización prematura: diseñe su programa para la capacidad de prueba y la escalabilidad y, si tiene problemas de rendimiento, puede utilizar un generador de perfiles para ver dónde están los cuellos de botella.

Editar: para aclarar, las direcciones IPv4 se almacenan como enteros de 32 bits, más una máscara de red (que no es necesaria para las comparaciones de direcciones IP). Si está utilizando el IPv6 más nuevo y actualmente más raro, las direcciones tendrán 128 bits de longitud.

+0

"Actualmente es más raro" quizás necesite una actualización 9.5 años después? – MichaelChirico

4

Sí, he encontrado que para ser eficiente, será un largo tiempo, y por supuesto tiene que indexar IPs en lista negra en forma de número entero.

7

Los enteros de 32 bits son el camino a seguir, hasta que empiece a ocuparse de las direcciones IPv6 de 128 bits.

3

Utilice una herramienta como PeerGuardian que no permite las conexiones entrantes de TCP/IP en el nivel del controlador a IP en una lista negra. Altamente seguro, no se requiere código (posiblemente: muy seguro, porque no se requiere código).

1

Si recibe la dirección IP como una cadena, comparándolo con una cadena puede ser más eficiente que la conversión a un entero representación

pero me gustaría perfil ambas soluciones para estar seguro, si unos pocos milisegundos (nanosegundos !) van a importar en esta operación ;-)

2

¿Tiene un problema existente con la eficiencia?

Si es así, por supuesto, publique el código (o pseudo-código) y podemos recoger el cadáver.

Si no, sugeriría intentar algo tan simple como almacenar las entradas en una lista ordenada y utilizar las existentes Sort() y Find() de su entorno.

5

¿Quiere decir si debería compararlo como una cadena de texto o convertir int a int y comparar como un int?

Eso no suele ser el cuello de botella en este tipo de búsquedas. simplemente puede intentar implementar ambos métodos y ver cuál funciona más rápido.

El verdadero problema con la búsqueda de direcciones IP generalmente es realizar consultas eficientes, aprovechando el hecho de que se trata de direcciones IP y no solo de números aleatorios. para lograr esto puede buscar LC trie y quizás this article

Obviamente, esto debería interesarle solo si su lista negra contiene decenas de miles o millones de entradas. Si tiene solo 10-20 entradas, se debe preferir una búsqueda lineal y, de hecho, la pregunta más interesante es la comparación textual frente a la comparación de enteros.

2

Las comparaciones enteras son mucho más rápidas que las comparaciones de cadenas.

Si almacena los enteros en una lista ordenada, puede encontrarlos más rápidamente que en una lista desordenada.

3

He hecho esto y lo he probado, utilizando un int sin firmar (32 bit) es el más rápido - Supongo que está comparando esto con la representación de cadena.

Otra cosa que podría ayudarte es cuando creaste la tabla, en el pasado he tenido 2 columnas: LowIP y HighIP; De esa manera, he podido poner en la lista negra rangos enteros de IP con 1 entrada de registro y todavía obtener un buen rendimiento al verificar la IP en el rango.

3

He heredado un código en el que alguien pensó que almacenar direcciones IP como 4 int era algo realmente bueno, excepto que pasaban todo el tiempo convirtiendo a/desde int.

Mantenerlas como cadenas en la base de datos fue mucho más fácil, y solo requería un índice único. Te sorprendería lo bien que el servidor SQL puede indexar cadenas en lugar de 4 columnas de números enteros. Pero esta lista de IP no era para listas negras. Una base de datos de ida y vuelta es bastante costosa.

Si una base de datos es exagerada, guárdelas en un diccionario en la memoria, pero eso es solo una suposición, ya que no tenemos idea de cuántas necesita comparar. Como la mayoría de los códigos hash son int de 32 bits, y las direcciones IPv4 son de 32 bits, la dirección IP en sí misma podría ser un buen hashcode.

Pero, como otros señalan, la mejor opción podría ser reducir la carga en su servidor y comprar hardware especializado. Tal vez conserve las IP de la lista negra en la memoria y periódicamente publique una nueva en el enrutador.

Si usted es el que está tratando de hacer algo de software dentro de un enrutador, entonces tendrá que pescar su libro de estructuras de datos y crear algo así como un b-tree.

+1

Comparar una mala representación (4 ints) con otra (cadena) no es una comparación justa realmente. – MSalters

+1

Fue una respuesta anecdótica del principio KISS, y almacenar una dirección IP como una cadena fue suficiente para el propósito en cuestión. –

3

La Radix o PATRICIA Trie es la estructura óptima para esto.

Mira la fuente C para herramientas de flujo: http://www.splintered.net/sw/flow-tools/

he trabajado en esto hace años.

+0

¡El sitio de Flow-Tools es bastante bueno!Hay muchos buenos enlaces allí, por ejemplo, esto: http://www.splintered.net/sw/flow-tools/SECURITY ¡Gracias! –

5
static public bool IsEqual(string ToCompare, 
             string CompareAgainst) 
    { 

    return IPAddressToLongBackwards(ToCompare)==IPAddressToLongBackwards(CompareAgainst); 
    } 

static private uint IPAddressToLongBackwards(string IPAddr) 
    { 
    System.Net.IPAddress oIP=System.Net.IPAddress.Parse(IPAddr); 
    byte[] byteIP=oIP.GetAddressBytes(); 


    uint ip=(uint)byteIP[0]<<24; 
    ip+=(uint)byteIP[1]<<16; 
    ip+=(uint)byteIP[2]<<8; 
    ip+=(uint)byteIP[3]; 

    return ip; 
    } 

Si entiendo correctamente que este es el código para comparar dos direcciones IP, ¿Quieres esto? que puede hacer más cosas tales como ...

static public bool IsGreater(string ToCompare, 
           string CompareAgainst) 
    { 

    return IPAddressToLongBackwards(ToCompare)> 
     IPAddressToLongBackwards(CompareAgainst); 
    } 

porque tienes los bytes de dirección ... Si así, entonces yo voto a favor, pero por favor no vota me negativa