Pregunta

Para la aplicación de mi servidor, necesito verificar si hay una dirección IP en nuestra lista negra.

¿Cuál es la forma más eficiente de comparar direcciones IP? ¿Convertir la dirección IP a entero y compararlos sería eficiente?

¿Fue útil?

Solución

Depende del idioma que use, 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 en el rendimiento. Evite la optimización prematura: diseñe su programa para su capacidad de prueba y escalabilidad y, si tiene problemas de rendimiento, puede usar 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 una longitud de 128 bits.

Otros consejos

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

¿Quieres decir si debes compararlo como una cadena de texto o convertir int a int y comparar como int?

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

El problema real con la búsqueda de direcciones IP suele ser 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 trie LC y tal vez este artículo

Obviamente, esto debería interesarte solo si tu lista negra contiene decenas de miles o millones de entradas. Si tiene solo 10-20 entradas, se debería 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.

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 te entiendo correctamente, este es un código para comparar dos direcciones IP. ¿Quieres esto? Además puedes hacer cosas como:

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

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

porque tienes los bytes de la dirección.

Sí, he encontrado que, para ser eficiente, será un proceso largo, y por supuesto, tiene que indexar las IP de la lista negra en forma de enteros.

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

He hecho esto y lo he probado, usar un int sin signo (32 bits) es el más rápido, supongo que lo estás comparando con la representación de la cadena.

Otra cosa que podría ayudarte es al crear la tabla, en el pasado he tenido 2 columnas: LowIP y HighIP; de esa manera, he podido incluir en la lista negra todos los rangos de IP con una entrada de registro y aún así obtener un buen rendimiento al verificar el IP en el rango.

Una vez heredé el código donde alguien pensó que almacenar las direcciones IP como 4 int era algo realmente bueno, excepto que pasaban todo su tiempo convirtiendo a / desde int's.

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

Si una base de datos es una exageración, guárdela en un diccionario en la memoria, pero eso es solo una suposición ya que no tenemos idea de cuántos necesita comparar. Dado que 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 código hash.

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

Si eres el que intenta crear algún software dentro de un enrutador, entonces necesitarás recuperar tu libro de estructuras de datos y crear algo como un b-tree.

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

Echa un vistazo a la fuente de C para herramientas de flujo: http://www.splintered.net/sw/flow-tools/

Trabajé en esto hace años.

¿Tiene un problema existente con la eficiencia?

Si es así, entonces por todos los medios publique el código (o pseudo-código) y podemos seleccionar el cadáver.

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

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

Si almacena los enteros en una lista ordenada, puede encontrarlos más rápido que en una lista sin clasificar.

Si recibe la dirección IP como una cadena, compararla con una cadena puede ser más eficiente que convertirla en una representación entera

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top