분석 · 관제심화 · 16분 읽기
ALPACA: 센서와 중앙 분석의 설계 사례
수업의 ALPACA 설계를 통해 패킷·경보 수집과 중앙 상관분석을 분리해 이해한다. 설계 문서는 완성된 운영 성능의 증거와 구분해서 읽는다.
개념부터 찾아보기
정의·역할·동작 원리를 독립 페이지에서 확인하세요. 본문의 밑줄 용어에도 설명이 있습니다.
이 노트에서 설명할 수 있게 되는 것
- PKLP 헤더 필드와 TCP 바이트 스트림의 관계를 설명한다.
- 부분 수신·길이 상한·연결 종료에 대한 수신 상태를 추적한다.
- 큐와 재전송 정책의 지연·유실·중복 영향을 구분한다.
01개념과 구성 요소
- 설계 목적Packet과 Alert를 독립 수집·전송하고 중앙 분석에서 시간·통신·출처로 연결하는 프로젝트 구조다.
- 센서 구성PacketCapture·AlertRead·각 SendToSiem의 네 스레드와 두 가 수집과 송신을 분리한다.
- 10바이트 공통 헤더와 타입별 payload를 사용하는 위의 애플리케이션 프레임이다.
02PKLP 패킷 배치가 중앙 수신기에 도달하는 순서
- 패킷 수집libpcap에서 번호·timestamp·raw bytes를 얻어 Packet 에 넣는다. 항목 수 한도는 바이트 한도와 다르다.
- 배치 구성송신기가 개수·바이트·최대 대기시간 조건으로 배치를 모은다.
- 프레임 직렬화!4sBBI 공통 헤더에 magic·version·type·payload 바이트 길이를 쓰고 type2의 count와 레코드들을 연결한다.
- 에서 재구성수신기는 10바이트 헤더를 모아 검사한 뒤 지정된 payload를 정확히 읽는다. 한 recv가 한 프레임이라는 전제는 사용하지 않는다.
- 내부 경계 검증Count·각 raw_length·남은 바이트·전체 상한을 검사한 뒤 저장 큐에 전달한다.
- 확인·재전송 관리Send 성공과 DB commit을 구분하고 센서·세션·레코드 키로 중복을 다룬다. 재전송만으로 exactly-once가 보장되지는 않는다.
03센서와 중앙 분석을 나눈 구조
- 프로젝트 범위ALPACA는 Packet·Alert를 독립 수집하여 중앙 에서 연결하는 수업 프로젝트다. 센서는 원시 데이터 확보·버퍼링·전송을 맡고 자세한 파싱과 상관분석은 중앙으로 옮긴다.
- Packet·Alert 관계패킷과 fast alert는 생성 시점과 표현이 달라 같은 사건을 직접 같은 번호로 나타내지 않는다. 시각·통신 정보·출처를 연결하는 구조가 필요하다.
- 설계 층센서의 클래스·큐·프레임 구조와 중앙의 분석 모델은 서로 다른 설계 층이다. 센서 전송 구조가 정해졌다는 사실만으로 중앙의 모든 분석 모델이 운영 검증된 것은 아니다.
- 검증 범위확정된 전달 방향, 비교용 스키마 초안, 그 구조에서 추가로 필요한 신뢰성 조건을 구분한다.
044개 스레드와 두 Queue
- 수집 스레드PacketCapture는 libpcap 핸들과 BPF 필터를 준비하고 번호·timestamp·raw bytes를 Packet 에 넣는다. AlertRead는 파일의 읽은 위치 이후 새 줄을 Alert 에 넣는다.
- 전송 스레드각 SendToSiem은 해당 에서 배치를 모아 전송한다. 패킷 수집·패킷 송신·경보 읽기·경보 송신 네 흐름을 나누어 한쪽의 짧은 지연이 즉시 모든 수집을 멈추지 않도록 한 것이다.
- 한도DataBuffer의 max_size=10000은 항목 수이며 바이트 수가 아니다. 패킷 크기에 따라 같은 항목 수도 메모리량이 달라진다.
- 영속성는 영구 저장소가 아니므로 종료 때의 미전송 자료는 별도 대책이 필요하다. 가득 찼을 때 producer 대기·drop·디스크 저장 중 무엇을 선택하는지에 따라 손실 위치와 지연이 달라진다.
05개수·용량·대기시간으로 배치 만들기
- 배치 한도collect는 개수·용량·대기시간 한도까지 레코드를 모은다. 개수만 제한하면 큰 패킷이 많은 배치가 과도하게 커지고, 바이트만 제한하면 트래픽이 적을 때 오래 기다릴 수 있다.
- 최대 대기시간최대 대기시간이 작은 배치의 전달 지연을 제한한다.
- 처리량·지연배치는 socket 호출과 헤더 반복 비용을 줄이지만 개별 기록의 도착이 늦어질 수 있다. 큐 대기·배치 대기·전송·저장 시간을 따로 관찰해야 느린 화면의 원인을 구분할 수 있다.
- 시간 분해총 throughput만 높고 가장 오래 대기한 자료가 계속 남아 있는 상황도 있으므로 배치 단위와 레코드 단위 지연은 별개다.
06PKLP 공통 헤더의 10바이트
- 공통 헤더(Packet Log Protocol)는 이 프로젝트가 정의한 애플리케이션 프로토콜이다. 모든 타입은 Magic 4B·version 1B·type 1B·payload length 4B의 공통 헤더를 쓴다.
- 바이트 순서 struct의 !4sBBI에서 !는 network byte order인 big-endian과 표준 크기·정렬을 뜻한다.
- Payload Lengthpayload length는 뒤따르는 전체 바이트 수이고 packet_count와 같은 레코드 수가 아니다. 아래는 type2에 count 필드만 있는 빈 배치 예다.
- 프레임 경계길이를 잘못 계산하면 수신자가 다음 메시지 헤더까지 현재 payload로 읽어 이후 모든 경계가 틀어진다.
text
!4sBBI → 10 bytes
50 4b 4c 50 | 01 | 02 | 00 00 00 04
P K L P v1 type2 payload 4B
payload: 00 00 00 00 # packet_count=0원리를 설명하는 가상 학습 예시입니다.
07타입 1·3: UTF-8 문자열 길이
- 세션 문자열타입1은 sensor_id·capture_id·interface, 타입3은 sensor_id·alert_session_id·ids_type·interface 문자열을 순서대로 담는다. 각 문자열 앞의 !H 2바이트는 로 인코딩한 바이트 길이다.
- 고정 헤더 구분별도 고정 payload 헤더가 있는 구조가 아니다.
- 길이“가”는 문자 하나지만 에서 3바이트이므로 문자 수를 넣고 바이트를 보내면 다음 필드의 시작이 어긋난다. 길이 범위 초과·잘못된 ·남은 payload 부족을 구분해야 한다.
- 재연결 문맥재연결 후 세션 정보를 다시 보내는 이유는 수신자가 후속 순번을 어느 센서·실행 문맥에 연결할지 알아야 하기 때문이다.
08타입 2: Packet 레코드의 20바이트 고정부
- 레코드 필드payload는 packet_count 4B로 시작한다. 각 레코드는 packet_no 8B(!Q), timestamp 8B(!d), raw_length 4B(!I), raw_packet 가변 바이트다.
- 총 길이전체 길이는 4 + 각 레코드의 (20+raw_length) 합이다. 디코더는 count만큼 읽되 각 raw_length가 남은 바이트 안에 있는지 검사해야 한다.
- 세션별 순번packet_no는 캡처 세션 안의 순번이므로 sensor·capture_id와 묶어야 다른 실행의 1번과 구분된다. timestamp는 libpcap의 Unix 시각을 double로 표현한 값이다.
- 시간 정밀도부동소수점과 캡처 해상도 때문에 표시 자릿수가 실제 측정 정밀도를 보증하지 않는다.
| 필드 | 크기 | 역할 |
|---|---|---|
| packet_count | 4B | 배치 개수 |
| packet_no | 8B | 세션 안 순번 |
| timestamp | 8B | double Unix 시각 |
| raw_length | 4B | 다음 원시 바이트 수 |
| raw_packet | 가변 | 캡처 바이트 |
원리 심화
09PKLP 길이 필드와 중첩 레코드의 검증 경계
- 외부 프레임공통 헤더 !4sBBI는 표준 크기·네트워크 바이트 순서에서 10바이트다. 헤더를 완성한 뒤 선언된 payload 길이를 검증한다.
- 내부 개수타입 2 payload의 패킷 개수는 뒤 레코드 수와 일치해야 한다. 외부 길이가 정상이어도 내부 count·각 raw 길이의 합이 맞지 않을 수 있다.
- 고정부 크기!QdI의 8+8+4=20바이트는 각 레코드의 고정부다. 그 뒤 raw 길이만큼 패킷 바이트가 따라오므로 다음 레코드 위치를 계산할 수 있다.
- 자원 제한count·개별 길이·합계 길이·완료 대기시간을 각각 제한한다. 길이 필드를 읽었다는 이유만으로 무제한 메모리를 할당하지 않는다.
- 완료 의미recv_exact가 프레임을 완성하는 것과 DB 적재 완료는 다르다. ACK·재전송·중복 제거는 애플리케이션 프로토콜에서 별도로 설계해야 한다.
예제로 추적
10가상 60·100바이트 패킷 배치의 길이 계산
- 레코드 조건타입 2 배치에 raw 길이가 60바이트와 100바이트인 패킷 두 개가 있다고 가정한다. 실제 통신을 생성하지 않는 포맷 계산이다.
- 레코드 길이첫 레코드는 20+60=80바이트, 두 번째는 20+100=120바이트다. 고정부가 각 패킷마다 반복된다.
- Payload 길이개수 필드 4바이트를 더하면 payload는 4+80+120=204바이트다. 헤더의 payload 길이 필드는 이 값을 나타낸다.
- 전체 프레임10바이트 공통 헤더를 더하면 총 214바이트다. 분할 때문에 실제 recv 횟수나 세그먼트 수는 달라질 수 있다.
- 불일치 입력count=3인데 payload가 두 레코드에서 끝나면 정상 완료로 넘기지 않는다. 미완성·잘못된 선언을 구분하여 연결·레코드 처리 정책을 적용한다.
| 구성 | 바이트 수 | 누적 payload |
|---|---|---|
| 패킷 개수 | 4 | 4 |
| 첫 레코드 고정부+raw | 20+60=80 | 84 |
| 두 번째 레코드 고정부+raw | 20+100=120 | 204 |
| 공통 헤더 | 10 | payload 밖: 전체 214 |
검증·예외
11중앙에 일부 레코드만 나타날 때의 진단
- 단계별 개수센서 생성·큐 입력·프레임 송신·중앙 파싱·적재 개수를 같은 ID 범위로 비교한다. 서로 다른 시점의 총계는 직접 같지 않을 수 있다.
- 문자열 길이타입 1·3의 길이가 바이트 기준인지 확인한다. 한글 한 글자가 1바이트라는 가정은 이후 필드 경계를 깨뜨린다.
- 미완성 꼬리연결 종료 때 헤더·payload 중 어디까지 받았는지 기록한다. 정상 연결 수와 정상 프레임 수를 동일시하지 않는다.
- 중복 복구ACK 전에 재연결되어 같은 배치가 재전송되었는지 확인한다. 도착 순서·개수만으로 exactly-once를 입증하지 않는다.
12타입 4: 줄바꿈으로 끝나는 Alert
- Alert 레코드타입4는 alert_count 4B 뒤에 alert_no 4B와 raw_alert를 반복한다. Alert마다 별도의 문자열 길이 필드가 없고 fast alert 한 건이 한 줄이라는 전제에서 줄바꿈으로 경계를 찾는다.
- Newline 경계Packet 레코드의 길이 기반 구조와 다르다.
- 부분 줄다른 logger의 여러 줄 출력이나 아직 쓰기 중인 부분 줄을 그대로 넣으면 경계가 깨진다. reader는 완성되지 않은 줄을 다음 읽기까지 보관할 수 있어야 한다.
- 종료 검증count개를 읽은 뒤 payload가 정확히 끝나는지, 지나치게 긴 줄이나 누락된 newline이 있는지도 상태로 다뤄야 한다.
13TCP 스트림에서 프레임을 완성하기
- 스트림는 send의 메시지 경계를 보존하지 않는다. 한 번의 recv가 헤더 일부만 주거나 여러 프레임을 합쳐 줄 수 있다.
- 헤더·Payload먼저 10바이트를 모으고 Magic·version·type·길이 상한을 검사한 뒤 지정한 payload를 정확히 모아 타입별로 해석한다. 중간 EOF는 미완성 프레임이며 정상 메시지로 저장하지 않는다.
- 길이 상한길이 필드를 그대로 믿고 메모리를 할당하면 비정상 입력이 자원을 소진할 수 있다. 전체 길이 상한, 레코드 수 상한, 내부 길이의 합을 함께 검증한다.
- Framing과 인증프로토콜 framing은 원시 바이트를 구조로 바꾸는 규칙이며 암호화·발신자 인증을 대신하지 않는다.
text
NEED_HEADER(10)
→ magic/version/type/길이 상한 검사
→ NEED_PAYLOAD(length)
→ count·레코드 경계 검사
→ 저장 큐에 전달
→ 다음 HEADER
중간 EOF → 미완성 프레임으로 종료원리를 설명하는 가상 학습 예시입니다.
14재전송에서 exactly-once가 자동으로 나오지 않는다
- 연결 재시도연결을 재시도할 때 세션 정보를 다시 보내고 실패 배치를 재전송할 수 있다. send 성공은 중앙 DB의 영구 저장 완료와 다르다.
- 중복 가능성서버가 저장한 직후 연결이 끊기면 송신자는 성공 여부를 몰라 같은 배치를 다시 보낼 수 있다. 재전송은 손실 위험을 줄이지만 중복 가능성을 만든다.
- 확인 지점센서·세션·레코드 순번 같은 안정된 키와 저장 중복 제어가 필요하다. 애플리케이션 ACK가 수신·큐 적재·DB commit 중 어디까지를 확인하는지도 정해야 한다.
- 설계·구현 범위디스크 spool과 확정 은 이런 문제를 해결하는 설계 요소이며 자료에서 모두 구현·검증되었다는 뜻은 아니다.
15copytruncate 대응과 복구의 한계
- 감지AlertRead는 파일 크기가 보다 작아지면 회전을 추정하고 최근 비압축 회전 파일에서 남은 구간을 읽은 뒤 현재 파일 처음으로 돌아간다. 그러나 크기 비교만으로 모든 파일 교체나 빠른 재성장을 구분할 수 없다.
- 파일 식별회전 파일 선택도 수정 시각뿐 아니라 파일 정체성과 처리 기록이 필요하다.
- 손실 창copy와 truncate 사이에서 사라진 기록은 사후 조정으로 복원할 수 없는 경우가 있다. Alert 파일의 레코드 누락과 NIC의 패킷 drop은 다른 수집 경로의 문제다.
- 별도 수집 경로원시 파일 범위·순번 공백· 상태를 함께 읽어야 어느 단계에서 자료가 없어졌는지 설명할 수 있다.
16중앙 필드와 원본으로 돌아가는 참조
- 중앙 필드통합 문서는 소스별 파싱·1차 분석 뒤 공통 Event를 중앙으로 보내는 방향을 명시한다. event_time·received_time·주소·포트·protocol은 의미를 맞추고 Packet·Alert·· 고유 필드는 상세 구조에 보존한다.
- Flow ID 구분중앙 flow_id와 external_flow_id를 같은 값으로 취급하지 않는다.
- 원본 참조최종 사건은 원본 테이블·행 또는 raw file의 ·길이로 돌아갈 수 있어야 한다. 대량 payload를 모두 검색 DB에 복제하기보다 파일의 checksum·record_count와 색인을 연결하면 조사 가능성을 유지하면서 저장 목적을 나눌 수 있다.
- 설계 선택지비교용 테이블 목록은 설계 선택지이며 실제 배포된 구조와 구분한다.
176개 패킷의 timestamp 실험이 보여 준 범위
- 여섯 표본별도 시험은 같은 NIC의 HTTP 요청3개·응답3개에서 두 수집 경로의 시각 차이가 0 또는 1마이크로초였다고 기록한다. 소수 표본의 연결 가능성을 보여 주지만 고부하·시계 변경·장기 운영의 무손실을 입증하지 않는다.
- 시각 의미캡처 시각과 프로그램이 파일에 쓴 시각은 구분해야 한다.
- 병목 지표초당 입력량, 깊이, 가장 오래 기다린 레코드, 재시도·중복·순번 공백, 중앙 저장률을 연결하면 부하 증가 시 어느 단계가 막히는지 알 수 있다. 프로젝트의 학습 가치는 센서에서 저장까지 바이트·상태·확인 지점을 직접 설계한 데 있다.
설명과 함께 보는 보조 도식
구조 살펴보기
PKLP 공통 헤더와 본문
수업 프로젝트 자료에 기록된 형식을 단순화한 모식도다. 공개 표준 프로토콜이 아니며 본문 형식은 Type에 따라 달라진다.
Magic 4바이트
프로토콜 식별 문자열을 확인한다.
PKLPVersion 1바이트
지원하는 해석 규칙의 버전인지 확인한다.
1Type 1바이트
본문의 메시지 종류를 구분한다.
Payload length 4바이트
네트워크 바이트 순서로 본문 바이트 수를 읽고 상한을 검사한다.
Payload Length만큼
헤더 뒤에서 선언한 바이트 수만큼 누적한 뒤 해당 유형으로 해석한다.
각 필드를 누르면 역할과 예시를 확인할 수 있습니다. 칸의 너비는 실제 바이트 비율과 다릅니다.
학습 확인
이해했는지 확인하기
- 수집·큐·전송·저장 단계의 책임과 큐 포화 정책을 설명한다.
- PKLP 길이·버전과 TCP 부분 수신 처리를 확인한다.
- 재연결·순환 시험에서 누락·중복·지연을 별도로 측정한다.