2024. 10. 31. 22:51 ㆍ개발 이야기/eBPF
최근 네트워크 트래픽을 실시간으로 모니터링하고 분석하기 위해 eBPF(Extended Berkeley Packet Filter)를 활용하는 사례가 증가하고 있습니다. eBPF는 커널 레벨에서 네트워크 패킷을 효율적으로 분석할 수 있는 기능을 제공하며, 높은 성능과 유연성을 제공합니다. 이번 포스팅에서는 eBPF를 이용해 네트워크 트래픽을 모니터링하는 방법을 코드와 함께 설명드리겠습니다.
eBPF란?
eBPF는 리눅스 커널에서 실행되는 프로그램을 작성하고 실행할 수 있는 메커니즘입니다. eBPF 프로그램은 커널에서 특정 이벤트가 발생할 때 실행되며, 이를 통해 네트워크 패킷 분석, 성능 모니터링, 보안 등의 다양한 기능을 수행할 수 있습니다. eBPF의 가장 큰 장점은 커널에서 동작하기 때문에 오버헤드가 적고, 사용자 영역에서의 상세한 모니터링이 가능하다는 것입니다.
환경 준비
eBPF를 사용하기 위해서는 최신 리눅스 커널(4.1 이상)과 eBPF 도구들이 필요합니다. 여기에서는 bcc 및 bpftrace 같은 라이브러리를 사용해 eBPF 프로그램을 작성해 보겠습니다.
우선, eBPF 도구인 BCC를 설치합니다:
sudo apt-get update
sudo apt-get install -y bpfcc-tools linux-headers-$(uname -r) python3-bpfcc
네트워크 트래픽 모니터링 코드 작성
다음으로, eBPF를 사용해 특정 인터페이스에서 네트워크 트래픽을 모니터링하는 간단한 Python 스크립트를 작성해보겠습니다. 이 스크립트는 BCC 라이브러리를 사용해 eBPF 프로그램을 로드하고 네트워크 패킷 정보를 수집합니다.
from bcc import BPF
# eBPF 프로그램 작성
bpf_program = """
#include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/ip.h>
BPF_HASH(packet_count, u32, u64);
int count_packets(struct __sk_buff *skb) {
u32 key = 0;
u64 *value, zero = 0;
// 패킷 수를 key = 0 에 누적
value = packet_count.lookup_or_init(&key, &zero);
if (value) {
(*value)++;
}
return 0;
}
"""
# BPF 객체 생성
b = BPF(text=bpf_program)
# 모든 네트워크 인터페이스에서 패킷을 처리하는 함수 연결
b.attach_kprobe(event="dev_queue_xmit", fn_name="count_packets")
try:
print("Monitoring network traffic... Press Ctrl+C to stop.")
while True:
# packet_count에 저장된 데이터를 읽어옴
total_packets = b["packet_count"].items()
for k, v in total_packets:
print(f"Total Packets: {v.value}")
except KeyboardInterrupt:
print("Stopping network traffic monitoring.")
위 코드에서 count_packets 함수는 커널에서 실행되어 네트워크 패킷을 카운트합니다. 이 함수는 BPF의 해시 맵을 사용하여 특정 키에 패킷의 수를 누적하며, 이를 통해 전체 트래픽 양을 모니터링할 수 있습니다.
주요 함수 설명
- BPF_HASH(packet_count, u32, u64): BPF 해시 맵을 정의합니다. 여기서는 패킷 수를 저장하기 위한 해시 맵으로 사용됩니다.
- count_packets(struct __sk_buff *skb): 네트워크 인터페이스에서 전송되는 모든 패킷을 처리하기 위해 호출되는 함수입니다. 패킷이 수신될 때마다 카운터를 증가시킵니다.
- attach_kprobe(event="dev_queue_xmit", fn_name="count_packets"): 커널 함수 dev_queue_xmit에 eBPF 프로그램을 연결하여 패킷이 네트워크 인터페이스로 전송될 때마다 count_packets 함수가 호출되도록 합니다.
코드 실행 결과
이 스크립트를 실행하면 터미널에서 실시간으로 패킷 수를 확인할 수 있습니다. 네트워크 트래픽을 모니터링하는 동안 특정 인터페이스에서 발생하는 패킷의 수를 간단하게 확인할 수 있으며, 이를 기반으로 네트워크 상태를 평가할 수 있습니다.
확장 예제: 특정 포트 모니터링
이번에는 네트워크 트래픽 중 특정 포트(예: 80번 포트, HTTP 트래픽)를 모니터링하는 예제를 확장해 보겠습니다.
from bcc import BPF
bpf_program = """
#include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/ip.h>
#include <uapi/linux/tcp.h>
BPF_HASH(http_count, u32, u64);
int count_http_packets(struct __sk_buff *skb) {
struct iphdr *ip;
struct tcphdr *tcp;
u32 key = 0;
u64 *value, zero = 0;
ip = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
if (ip->protocol == IPPROTO_TCP) {
tcp = (struct tcphdr *)(skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr));
if (tcp->dest == htons(80)) { // HTTP 포트
value = http_count.lookup_or_init(&key, &zero);
if (value) {
(*value)++;
}
}
}
return 0;
}
"""
b = BPF(text=bpf_program)
b.attach_kprobe(event="dev_queue_xmit", fn_name="count_http_packets")
try:
print("Monitoring HTTP traffic... Press Ctrl+C to stop.")
while True:
total_http_packets = b["http_count"].items()
for k, v in total_http_packets:
print(f"Total HTTP Packets: {v.value}")
except KeyboardInterrupt:
print("Stopping HTTP traffic monitoring.")
위 확장된 코드에서는 TCP 패킷 중 포트 80(HTTP 트래픽)에 해당하는 패킷만을 카운트합니다. 이를 통해 특정 서비스에 대한 트래픽 모니터링도 가능해집니다.
마무리
eBPF를 활용하면 커널 수준에서 네트워크 트래픽을 실시간으로 모니터링할 수 있습니다. 이러한 기능은 네트워크 보안, 성능 분석, 문제 진단 등 다양한 목적에 활용될 수 있습니다. 이번 포스팅에서 소개한 간단한 예제를 바탕으로, 네트워크 분석 및 모니터링 시스템을 직접 구축해 보시길 바랍니다. eBPF는 매우 강력한 도구로, 다양한 응용 분야에 확장될 수 있습니다.
'개발 이야기 > eBPF' 카테고리의 다른 글
eBPF를 활용한 서버 애플리케이션과 인프라 연관 관계 파악하기 (6) | 2024.11.16 |
---|