
Открытый стандарт для хеширования сетевых потоков в идентификаторы, также известный как «Community IDs».
При обработке данных о потоках из различных приложений мониторинга (таких как Zeek и Suricata) часто бывает желательно быстро переключаться с одного набора данных на другой. Хотя необходимая информация о кортеже потока обычно присутствует в наборах данных, детали таких «соединений» могут быть утомительными, особенно в крайних случаях. Данная спецификация описывает хеширование потоков «Community ID», стандартизируя создание строкового идентификатора, представляющего заданный сетевой поток, чтобы свести переключение к простому сравнению строк.
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);
}
Community ID — это дополнительный идентификатор потока, и он не заменяет существующие механизмы идентификации потоков, уже поддерживаемые мониторами. Однако при желании монитор можно настроить так, чтобы он регистрировал только Community ID.
Community ID может вычисляться по мере того, как монитор генерирует потоки, или может быть добавлен к существующим записям потоков на более позднем этапе, при условии, что эти записи содержат всю необходимую информацию о конечных точках потока.
Коллизии в Community ID, хотя и нежелательны, не считаются фатальными, поскольку у пользователя всё равно должны быть информация о времени потоков и, возможно, собственный механизм идентификации монитора (надеюсь, более сильный, чем Community ID) для устранения неоднозначности.
Механизм хеширования использует начальное значение (seed) для обеспечения дополнительного контроля над «доменами» использования Community ID. По умолчанию seed равен 0, поэтому этот механизм не мешает и не влияет на работу операторов, которым он неинтересен.
В версии 1 идентификатора алгоритмом хеширования является SHA1. Будущие версии хеширования могут изменить его или разрешить дополнительную настройку.
Двоичный 20-байтовый результат SHA1 кодируется в base64, чтобы уменьшить объём вывода по сравнению с обычным ASCII-представлением SHA1. Это предполагает, что основным ограничением является объём, а не время вычислений, и в более поздней версии это может стать настраиваемым.
Итоговый идентификатор потока включает номер версии, чтобы явно обозначить базовую реализацию Community ID. Это позволяет пользователям быть уверенными, что они сравнивают сопоставимые значения, и при этом допускает будущие изменения алгоритма. Например, когда версия идентификатора одного монитора включает VLAN ID, а другого — нет, сравнение хеш-значений должно надёжно давать отрицательный результат. Более сложная форма этой функции могла бы позволить фиксировать параметры конфигурации в дополнение к версии реализации.
Схема версионирования в настоящее время просто добавляет префикс «:» к хеш-значению, что в текущей версии 1 даёт нечто вроде:
1:hO+sN4H+MG5MY/8hIrXPqc4ZQz0=
Входные данные хеша выровнены по 32-битным границам. Компоненты кортежа потока используют сетевой порядок байтов (big-endian) для стандартизации порядка независимо от аппаратного обеспечения хоста.
Входные данные хеша упорядочиваются для устранения направленности кортежа потока: при необходимости конечные точки меняются местами, чтобы численно меньший кортеж IP:порт шёл первым. Если IP-адреса равны, решают порты. Например, следующие 5-кортежи netflow создают идентичные хеши Community ID, поскольку оба упорядочиваются в последовательность 10.0.0.1, 127.0.0.1, 1234, 80.
Полная реализация доступна в пакете pycommunityid. Он включает ряд тестов для проверки корректности вычислений для различных протоколов. Мы рекомендуем его в качестве ориентира для новых реализаций.
Меньшая по объёму реализация также доступна через скрипт community-id.py в этом репозитории, включая байтовую схему хешируемых значений (см. packet_get_comm_id()). Чтобы начать, обратитесь к --help и make.sh:
$ ./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
Для устранения неполадок реализация поддерживает отключение операции base64 и может предоставить дополнительные сведения о точной последовательности байтов, поступающих в вычисление хеша SHA1.
Каталог baseline в этом репозитории содержит наборы
данных, которые помогут вам проверить, что ваша реализация Community
ID работает корректно.
Не стесняйтесь обсуждать аспекты Community ID через GitHub здесь: https://github.com/corelight/community-id-spec/issues
Эта версия включает следующие протоколы и поля:
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
Точная обработка типа и кода ICMP взята из Zeek; см. реализации здесь:
Другие протоколы, переносимые через IP:
IP src / IP dst / IP proto
Вышеописанное в настоящее время не охватывает обработку вложенности (IP в IP, v6 поверх v4 и т.д.), а также инкапсуляций, таких как VLAN и MPLS.
Если сетевой монитор не поддерживает ни одну из вышеуказанных комбинаций протоколов, он может безопасно сообщать пустую строку (или другое значение, не создающее коллизий) для идентификатора потока.
Считайте v1 прототипом. Мы очень ценим отзывы сообщества, особенно разработчиков реализаций и операционных пользователей идентификатора. Пожалуйста, создавайте issues непосредственно в проекте GitHub по адресу https://github.com/corelight/community-id-spec или свяжитесь с Christian Kreibich ([email protected]).
Большое спасибо за полезные обсуждения и отзывы Victor Julien, Johanna Amann и Robin Sommer, а также всем разработчикам реализаций и сторонникам.