
Un estándar abierto para convertir flujos de red en identificadores mediante hash, también conocido como «Community IDs».
Al procesar datos de flujo de una variedad de aplicaciones de monitorización (como Zeek y Suricata), a menudo resulta deseable pivotar rápidamente de un conjunto de datos a otro. Aunque la información de tupla de flujo necesaria suele estar presente en los conjuntos de datos, los detalles de tales "joins" pueden ser tediosos, especialmente en casos límite. Esta especificación describe el hashing de flujo "Community ID", que estandariza la producción de un identificador de cadena que representa un flujo de red determinado, para reducir el pivot a una simple comparación de cadenas.
function community_id_v1(ipaddr saddr, ipaddr daddr, port sport, port dport, int proto, int seed=0)
{
# Get seed and all tuple parts into network byte order
seed = pack_to_nbo(seed); # 2 bytes
saddr = pack_to_nbo(saddr); # 4 or 16 bytes
daddr = pack_to_nbo(daddr); # 4 or 16 bytes
sport = pack_to_nbo(sport); # 2 bytes
dport = pack_to_nbo(dport); # 2 bytes
# Abstract away directionality: flip the endpoints as needed
# so the smaller IP:port tuple comes first.
saddr, daddr, sport, dport = order_endpoints(saddr, daddr, sport, dport);
# Produce 20-byte SHA1 digest. "." means concatenation. The
# proto value is one byte in length and followed by a 0 byte
# for padding.
sha1_digest = sha1(seed . saddr . daddr . proto . 0 . sport . dport)
# Prepend version string to base64 rendering of the digest.
# v1 is currently the only one available.
return "1:" + base64(sha1_digest)
}
function community_id_icmp(ipaddr saddr, ipaddr daddr, int type, int code, int seed=0)
{
port sport, dport;
# ICMP / ICMPv6 endpoint mapping directly inspired by Zeek
sport, dport = map_icmp_to_ports(type, code);
# ICMP is IP protocol 1, ICMPv6 would be 58
return community_id_v1(saddr, daddr, sport, dport, 1, seed);
}
El Community ID es un identificador de flujo adicional y no necesita reemplazar los mecanismos de identificación de flujo existentes que los monitores ya soportan. No obstante, es aceptable que un monitor esté configurado para registrar solo el Community ID, si se desea.
El Community ID puede calcularse a medida que un monitor produce flujos, o también puede añadirse a los registros de flujo existentes en una fase posterior, asumiendo que dichos registros transmiten toda la información necesaria de los endpoints del flujo.
Las colisiones en el Community ID, aunque indeseables, no se consideran fatales, ya que el usuario debería seguir disponiendo de la información de temporización del flujo y posiblemente del mecanismo de ID nativo del monitor (con suerte más robusto que el Community ID) para la desambiguación.
El mecanismo de hashing utiliza un seed para permitir un control adicional sobre los "dominios" de uso del Community ID. El seed tiene como valor predeterminado 0, de modo que este mecanismo no estorba y no afecta al funcionamiento de los operadores que no estén interesados en él.
En la versión 1 del ID, el algoritmo de hash es SHA1. Las versiones de hash futuras podrían cambiarlo o permitir configuración adicional.
El resultado binario SHA1 de 20 bytes se codifica en base64 para reducir el volumen de salida en comparación con la representación SHA1 habitual basada en ASCII. Esto asume que el espacio, y no el tiempo de cómputo, es la principal preocupación, y podría volverse configurable en una versión posterior.
El ID de flujo resultante incluye un número de versión para hacer explícita la implementación subyacente del Community ID. Esto permite a los usuarios asegurarse de que comparan peras con peras, al tiempo que respalda futuros cambios en el algoritmo. Por ejemplo, cuando la versión del ID de un monitor incorpora IDs de VLAN pero la de otro no, las comparaciones de valores hash deberían fallar de forma fiable. Una forma más compleja de esta función podría permitir capturar los ajustes de configuración además de la versión de la implementación.
El esquema de versionado actualmente simplemente antepone ":" al valor hash, dando como resultado algo así en la versión 1 actual:
1:hO+sN4H+MG5MY/8hIrXPqc4ZQz0=
La entrada del hash está alineada en límites de 32 bits. Los componentes de la tupla de flujo usan el orden de bytes de red (big-endian) para estandarizar el orden independientemente del hardware del host.
La entrada del hash se ordena para eliminar la direccionalidad en la tupla de flujo: intercambia los endpoints si es necesario, de modo que la tupla IP:puerto numéricamente menor quede primero. Si las direcciones IP son iguales, deciden los puertos. Por ejemplo, los siguientes 5-tuplas de netflow crean hashes de Community ID idénticos porque ambos se ordenan en la secuencia 10.0.0.1, 127.0.0.1, 1234, 80.
Esta versión incluye los siguientes protocolos y campos:
TCP / UDP / SCTP:
IP src / IP dst / IP proto / source port / dest port
ICMPv4 / ICMPv6:
IP src / IP dst / IP proto / ICMP type + "counter-type" or code
El manejo exacto del tipo y código de ICMP se toma de Zeek; consulta las implementaciones aquí:
Otros protocolos basados en IP:
IP src / IP dst / IP proto
Lo anterior no cubre actualmente cómo manejar el anidamiento (IP en IP, v6 sobre v4, etc.), así como encapsulaciones como VLAN y MPLS.
Si un monitor de red no soporta ninguna de las constelaciones de protocolo anteriores, puede devolver sin problemas una cadena vacía (u otro valor no colisionante) para el ID de flujo.
Considera v1 un prototipo. Se agradece enormemente la retroalimentación de la comunidad, en particular de los implementadores y usuarios operativos del ID. Crea issues directamente en el proyecto de GitHub en https://github.com/corelight/community-id-spec, o contacta con Christian Kreibich ([email protected]).
Muchas gracias por las útiles discusiones y comentarios a Victor Julien, Johanna Amann y Robin Sommer, y a todos los implementadores y seguidores.
Hay una implementación completa disponible en el paquete pycommunityid. Incluye una serie de pruebas para verificar el cálculo correcto de los distintos protocolos. La recomendamos para guiar nuevas implementaciones.
También hay una implementación más pequeña disponible a través del script community-id.py en este repositorio, incluida la disposición de bytes de los valores hasheados (consulta packet_get_comm_id()). Consulta --help y make.sh para empezar:
$ ./community-id.py --help
usage: community-id.py [-h] [--seed NUM] PCAP [PCAP ...]
Community flow ID reference
positional arguments:
PCAP PCAP packet capture files
optional arguments:
-h, --help show this help message and exit
--seed NUM Seed value for hash operations
--no-base64 Don't base64-encode the SHA1 binary value
--verbose Show verbose output on stderr
Para la resolución de problemas, la implementación permite omitir la operación base64 y puede proporcionar detalles adicionales sobre la secuencia exacta de bytes que entran en el cálculo del hash SHA1.
El directorio baseline de este repositorio contiene conjuntos de datos para ayudarte a verificar que tu implementación de Community ID funciona correctamente.
No dudes en discutir aspectos del Community ID a través de GitHub aquí: https://github.com/corelight/community-id-spec/issues