
네트워크 플로우를 식별자로 해싱하기 위한 개방형 표준, 일명 "Community IDs".
Zeek 및 Suricata와 같은 다양한 모니터링 애플리케이션에서 플로우 데이터를 처리할 때, 한 데이터셋에서 다른 데이터셋으로 빠르게 피벗(pivot)하는 것이 바람직한 경우가 많습니다. 필요한 플로우 튜플 정보는 일반적으로 데이터셋에 존재하지만, 이러한 "조인(join)"의 세부 사항은 특히 코너 케이스에서 번거로울 수 있습니다. 이 스펙은 특정 네트워크 플로우를 나타내는 문자열 식별자 생성을 표준화하여 피벗을 단순한 문자열 비교로 줄여주는 "커뮤니티 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);
}
커뮤니티 ID는 추가적인 플로우 식별자이며, 모니터가 이미 지원하는 기존 플로우 식별 메커니즘을 대체할 필요는 없습니다. 다만, 원한다면 모니터가 커뮤니티 ID만 기록하도록 구성하는 것도 괜찮습니다.
커뮤니티 ID는 모니터가 플로우를 생성할 때 계산하거나, 해당 레코드에 필요한 모든 플로우 엔드포인트 정보가 포함되어 있다는 가정 하에 나중 단계에서 기존 플로우 레코드에 추가할 수도 있습니다.
커뮤니티 ID의 충돌은 바람직하지 않지만 치명적이지는 않습니다. 사용자는 여전히 플로우 타이밍 정보와, 경우에 따라 모니터 고유의 ID 메커니즘(가급적 커뮤니티 ID보다 더 강력한)을 통해 충돌을 식별할 수 있기 때문입니다.
해싱 메커니즘은 커뮤니티 ID 사용 "도메인"에 대한 추가적인 제어를 가능하게 하기 위해 시딩(seeding)을 사용합니다. 시드(seed)는 기본값이 0이므로, 이 메커니즘은 관심이 없는 운영자의 작업에 영향을 주지 않습니다.
ID 버전 1에서 해시 알고리즘은 SHA1입니다. 향후 해시 버전에서는 알고리즘을 변경하거나 추가 구성을 허용할 수 있습니다.
이진 20바이트 SHA1 결과는 일반적인 ASCII 기반 SHA1 표현에 비해 출력 크기를 줄이기 위해 base64로 인코딩됩니다. 이는 계산 시간이 아닌 공간이 주요 관심사라고 가정하며, 이후 버전에서 구성 가능해질 수 있습니다.
결과 플로우 ID에는 기본 커뮤니티 ID 구현을 명시적으로 나타내는 버전 번호가 포함됩니다. 이를 통해 사용자는 알고리즘의 향후 변경을 지원하면서 동일한 기준으로 비교하고 있는지 확인할 수 있습니다. 예를 들어, 한 모니터의 ID 버전이 VLAN ID를 포함하지만 다른 모니터의 버전은 포함하지 않는 경우, 해시 값 비교는 확실히 실패해야 합니다. 이 기능의 더 복잡한 형태는 구현 버전 외에도 구성 설정을 캡처할 수 있게 해줍니다.
버전 관리 방식은 현재 단순히 해시 값 앞에 ":"을 붙이며, 현재 버전 1에서는 다음과 같은 결과가 생성됩니다:
1:hO+sN4H+MG5MY/8hIrXPqc4ZQz0=
해시 입력은 32비트 경계에 정렬됩니다. 플로우 튜플 구성 요소는 호스트 하드웨어와 무관하게 순서를 표준화하기 위해 네트워크 바이트 순서(빅엔디언)를 사용합니다.
해시 입력은 플로우 튜플에서 방향성을 제거하기 위해 정렬됩니다: 필요한 경우 엔드포인트를 교체하여 숫자상 더 작은 IP:포트 튜플이 먼저 오도록 합니다. IP 주소가 같으면 포트가 결정합니다. 예를 들어, 다음 netflow 5-튜플은 둘 다 10.0.0.1, 127.0.0.1, 1234, 80 순서로 정렬되므로 동일한 커뮤니티 ID 해시를 생성합니다.
이 버전에는 다음 프로토콜과 필드가 포함됩니다:
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" 또는 code
ICMP type 및 code의 정확한 처리는 Zeek에서 가져온 것입니다; 구현은 여기를 참조하세요:
완전한 구현은 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 디렉토리에는 커뮤니티 ID 구현이 올바르게 작동하는지 확인하는 데 도움이 되는 데이터셋이 포함되어 있습니다.
커뮤니티 ID의 다양한 측면에 대해 GitHub에서 자유롭게 논의하세요: https://github.com/corelight/community-id-spec/issues
기타 IP 기반 프로토콜:
IP src / IP dst / IP proto
위 내용은 현재 중첩(nesting, IP in IP, v6 over v4 등) 및 VLAN, MPLS와 같은 캡슐화를 처리하는 방법을 다루지 않습니다.
네트워크 모니터가 위의 프로토콜 구성 중 어떤 것도 지원하지 않는 경우, 플로우 ID에 대해 빈 문자열(또는 충돌하지 않는 다른 값)을 안전하게 보고할 수 있습니다.
v1은 프로토타입으로 간주하십시오. 커뮤니티, 특히 ID의 구현자와 운영 사용자로부터의 피드백을 크게 환영합니다. https://github.com/corelight/community-id-spec의 GitHub 프로젝트에 직접 이슈를 생성하거나 Christian Kreibich([email protected])에게 연락해 주십시오.
유용한 논의와 피드백을 제공해 주신 Victor Julien, Johanna Amann, Robin Sommer, 그리고 모든 구현자와 지지자들에게 감사드립니다.