
Un standard ouvert pour le hachage des flux réseau en identifiants, alias "Community IDs".
Lors du traitement de données de flux provenant de diverses applications de surveillance (telles que Zeek et Suricata), il est souvent souhaitable de basculer rapidement d'un ensemble de données à un autre. Bien que les informations de tuple de flux requises soient généralement présentes dans les ensembles de données, les détails de ces « jointures » peuvent être fastidieux, en particulier dans les cas limites. Cette spécification décrit le hachage de flux « Community ID », standardisant la production d'un identifiant de type chaîne représentant un flux réseau donné, afin de réduire la bascule à une simple comparaison de chaînes.
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);
}
Le Community ID est un identifiant de flux supplémentaire et n'a pas besoin de remplacer les mécanismes existants d'identification de flux déjà pris en charge par les moniteurs. Il est toutefois acceptable qu'un moniteur soit configuré pour ne journaliser que le Community ID, si cela est souhaitable.
Le Community ID peut être calculé lorsqu'un moniteur produit des flux, ou peut également être ajouté aux enregistrements de flux existants à un stade ultérieur, à condition que ces enregistrements contiennent toutes les informations nécessaires sur les points d'extrémité du flux.
Les collisions dans le Community ID, bien qu'indésirables, ne sont pas considérées comme fatales, car l'utilisateur devrait toujours disposer des informations de synchronisation du flux et éventuellement du mécanisme d'ID natif du moniteur (idéalement plus robuste que le Community ID) pour la désambiguïsation.
Le mécanisme de hachage utilise un germe (seed) pour offrir un contrôle supplémentaire sur les « domaines » d'utilisation du Community ID. Le germe est par défaut 0, de sorte que ce mécanisme ne gêne pas et n'affecte pas le fonctionnement des opérateurs qui ne s'y intéressent pas.
Dans la version 1 de l'ID, l'algorithme de hachage est SHA1. Les futures versions du hachage pourraient le modifier ou permettre une configuration supplémentaire.
Le résultat binaire SHA1 de 20 octets est encodé en base64 afin de réduire le volume de sortie par rapport à la représentation SHA1 habituelle basée sur l'ASCII. Cela suppose que l'espace, et non le temps de calcul, est la préoccupation principale, et pourrait devenir configurable dans une version ultérieure.
L'identifiant de flux résultant inclut un numéro de version pour rendre explicite l'implémentation sous-jacente du Community ID. Cela permet aux utilisateurs de s'assurer qu'ils comparent des choses comparables tout en soutenant les évolutions futures de l'algorithme. Par exemple, lorsque la version de l'ID d'un moniteur intègre les identifiants VLAN mais pas celle d'un autre, les comparaisons de valeurs de hachage devraient échouer de manière fiable. Une forme plus complexe de cette fonctionnalité pourrait permettre de capturer les paramètres de configuration en plus de la version de l'implémentation.
Le schéma de versionnage actuel préfixe simplement la valeur de hachage avec « : », produisant quelque chose comme ceci dans la version 1 actuelle :
1:hO+sN4H+MG5MY/8hIrXPqc4ZQz0=
L'entrée de hachage est alignée sur des limites de 32 bits. Les composants du tuple de flux utilisent l'ordre des octets du réseau (big-endian) afin de normaliser l'ordre quel que soit le matériel hôte.
Une implémentation complète est disponible dans le paquet pycommunityid. Elle comprend une série de tests pour vérifier le calcul correct pour les différents protocoles. Nous la recommandons pour guider de nouvelles implémentations.
Une implémentation plus réduite est également disponible via le script community-id.py de ce dépôt, incluant l'agencement des octets des valeurs hachées (voir packet_get_comm_id()). Consultez --help et make.sh pour commencer :
$ ./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
Pour le dépannage, l'implémentation permet d'omettre l'opération base64 et peut fournir des détails supplémentaires sur la séquence exacte d'octets entrant dans le calcul du hachage SHA1.
Le répertoire baseline de ce dépôt contient des ensembles de données pour vous aider à vérifier que votre implémentation du Community ID fonctionne correctement.
N'hésitez pas à discuter des aspects du Community ID via GitHub ici : https://github.com/corelight/community-id-spec/issues
L'entrée de hachage est ordonnée pour éliminer la directionnalité dans le tuple de flux : les points d'extrémité sont échangés, si nécessaire, afin que le tuple IP:port numériquement plus petit vienne en premier. Si les adresses IP sont égales, ce sont les ports qui décident. Par exemple, les 5-tuples netflow suivants créent des hachages Community ID identiques parce qu'ils sont tous deux ordonnés dans la séquence 10.0.0.1, 127.0.0.1, 1234, 80.
Cette version inclut les protocoles et champs suivants :
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
Le traitement exact du type et du code ICMP est tiré de Zeek ; voir les implémentations ici :
Autres protocoles transportés par IP :
IP src / IP dst / IP proto
Ce qui précède ne couvre actuellement pas la gestion de l'imbrication (IP dans IP, v6 sur v4, etc.) ni les encapsulations telles que VLAN et MPLS.
Si un moniteur réseau ne prend en charge aucune des constellations de protocoles ci-dessus, il peut signaler en toute sécurité une chaîne vide (ou une autre valeur sans collision) pour l'identifiant de flux.
Considérez v1 comme un prototype. Les retours de la communauté, en particulier des implémenteurs et des utilisateurs opérationnels de l'ID, sont grandement appréciés. Veuillez créer des issues directement dans le projet GitHub à l'adresse https://github.com/corelight/community-id-spec, ou contacter Christian Kreibich ([email protected]).
Un grand merci à Victor Julien, Johanna Amann et Robin Sommer pour leurs discussions et retours utiles, ainsi qu'à tous les implémenteurs et supporters.