-
Notifications
You must be signed in to change notification settings - Fork 0
KR_Net_Packet_Analysis
계층별 캡슐화 구조:
┌─────────────────────────────────────────────────────────┐
│ Ethernet Frame (Layer 2) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ IP Packet (Layer 3) │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ TCP Segment (Layer 4) │ │ │
│ │ │ ┌─────────────────────────────────────────────┐ │ │ │
│ │ │ │ Application Data (Layer 7) │ │ │ │
│ │ │ └─────────────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Ethernet Frame 구조 (총 최소 64 bytes ~ 최대 1518 bytes):
┌──────────┬─────┬──────────┬──────────┬──────┬─────────┬─────┐
│ Preamble │ SFD │ Dst MAC │ Src MAC │ Type │ Payload │ FCS │
│ 7 bytes │1 byte│ 6 bytes │ 6 bytes │2 bytes│46-1500 │4 bytes│
└──────────┴─────┴──────────┴──────────┴──────┴─────────┴─────┘
Preamble: 10101010... (동기화 신호)
SFD: 10101011 (Start Frame Delimiter)
Dst MAC: 목적지 MAC 주소 (예: aa:bb:cc:dd:ee:ff)
Src MAC: 출발지 MAC 주소
Type: 0x0800 (IPv4), 0x0806 (ARP), 0x86DD (IPv6)
Payload: 상위 계층 데이터 (최소 46 bytes - 패딩 포함)
FCS: CRC-32 오류 검출 (Frame Check Sequence)
IP Packet 구조 (IPv4, 최소 20 bytes):
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
┌───────┬───────┬───────────────┬───────────────────────────────┐
│Version│ IHL │ TOS/DSCP │ Total Length │
│ (4) │ (4) │ (8 bits) │ (16 bits) │
├───────────────────────────────┼───┬───────────────────────────┤
│ Identification │Flg│ Fragment Offset │
│ (16 bits) │(3)│ (13 bits) │
├───────────────┬───────────────┼───────────────────────────────┤
│ TTL │ Protocol │ Header Checksum │
│ (8 bits) │ (8 bits) │ (16 bits) │
├───────────────┴───────────────┴───────────────────────────────┤
│ Source IP Address │
│ (32 bits) │
├───────────────────────────────────────────────────────────────┤
│ Destination IP Address │
│ (32 bits) │
├───────────────────────────────────────────────────────────────┤
│ Options (if IHL > 5) │
└───────────────────────────────────────────────────────────────┘
Version: 4 (IPv4)
IHL: Header Length (5 = 20 bytes, 최대 15 = 60 bytes)
TOS/DSCP: Quality of Service (우선순위)
Total Len: 헤더 + 데이터 전체 길이
ID: 단편화 시 패킷 식별
Flags: bit 0: Reserved (0)
bit 1: DF (Don't Fragment)
bit 2: MF (More Fragments)
TTL: 패킷 수명 (홉마다 1 감소, 0이 되면 폐기)
Protocol: 6 (TCP), 17 (UDP), 1 (ICMP)
Checksum: IP 헤더 오류 검출
TCP Segment 구조 (최소 20 bytes):
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
┌───────────────────────────────┬───────────────────────────────┐
│ Source Port │ Destination Port │
│ (16 bits) │ (16 bits) │
├───────────────────────────────┴───────────────────────────────┤
│ Sequence Number │
│ (32 bits) │
├───────────────────────────────────────────────────────────────┤
│ Acknowledgment Number │
│ (32 bits) │
├───────┬───────┬─┬─┬─┬─┬─┬─┬─┬─┬───────────────────────────────┤
│ Offset│ Res. │C│E│U│A│P│R│S│F│ Window Size │
│ (4) │ (3) │W│C│R│C│S│S│Y│I│ (16 bits) │
│ │ │R│E│G│K│H│T│N│N│ │
├───────┴───────┴─┴─┴─┴─┴─┴─┴─┴─┴───────────────────────────────┤
│ Checksum │ Urgent Pointer │
│ (16 bits) │ (16 bits) │
├───────────────────────────────┴───────────────────────────────┤
│ Options (if Offset > 5) │
│ (variable) │
└───────────────────────────────────────────────────────────────┘
Seq Number: 데이터의 첫 바이트 위치
Ack Number: 다음에 받을 데이터의 위치
Flags:
- CWR (Congestion Window Reduced): 혼잡 윈도우 감소
- ECE (ECN-Echo): 혼잡 알림
- URG (Urgent): 긴급 데이터
- ACK (Acknowledgment): 확인 응답
- PSH (Push): 즉시 전달
- RST (Reset): 연결 강제 종료
- SYN (Synchronize): 연결 시작
- FIN (Finish): 연결 종료
Window Size: 수신 버퍼 크기 (Flow Control)
실제 패킷 분석 (tcpdump):
# HTTP GET 요청 캡처
sudo tcpdump -i eth0 -nn -X 'tcp port 80 and host example.com'
출력:
14:30:15.123456 IP 192.168.1.10.54321 > 93.184.216.34.80: Flags [S], seq 1234567890
0x0000: 4500 003c 1c46 4000 4006 b1e6 c0a8 010a E..<.F@.@.......
0x0010: 5db8 d822 d431 0050 499d 162a 0000 0000 ]..".1.PI..*....
0x0020: a002 7210 e32d 0000 0204 05b4 0402 080a ..r..-..........
분석:
0x4500: Version=4, IHL=5, TOS=00
0x003c: Total Length = 60 bytes
0x1c46: Identification
0x4000: Flags=DF (Don't Fragment)
0x40: TTL = 64
0x06: Protocol = TCP (6)
0xc0a8010a: Source IP = 192.168.1.10
0x5db8d822: Dest IP = 93.184.216.34
0xd431: Source Port = 54321
0x0050: Dest Port = 80
0xa002: Flags = SYN, Window Size = 7210Wireshark 디스플레이 필터:
TCP 3-Way Handshake:
tcp.flags.syn==1 && tcp.flags.ack==0 # SYN
tcp.flags.syn==1 && tcp.flags.ack==1 # SYN-ACK
tcp.flags.syn==0 && tcp.flags.ack==1 && tcp.seq==1 # ACK
HTTP 요청:
http.request.method == "GET"
http.response.code == 200
재전송 패킷:
tcp.analysis.retransmission
느린 응답:
tcp.time_delta > 0.1
패킷 손실:
tcp.analysis.lost_segment
MTU vs MSS:
MTU (Maximum Transmission Unit):
┌─────────────────────────────────────────────┐
│ Ethernet Header (14) │ IP Packet (1500) │ FCS (4) │
└─────────────────────────────────────────────┘
↑
MTU = 1500 bytes
MSS (Maximum Segment Size):
┌──────────────────────────────────────────────────────┐
│ IP Header (20) │ TCP Header (20) │ TCP Data (1460) │
└──────────────────────────────────────────────────────┘
↑
MSS = 1460 bytes
공식: MSS = MTU - IP Header(20) - TCP Header(20)
일반적인 MTU 값:
Ethernet: 1500 bytes
802.1Q VLAN: 1504 bytes (VLAN tag 4 bytes)
PPPoE: 1492 bytes (PPPoE header 8 bytes)
VPN (IPsec): 1400 bytes (암호화 오버헤드 약 100 bytes)
GRE Tunnel: 1476 bytes (GRE header 24 bytes)
VXLAN: 1450 bytes (VXLAN header 50 bytes)
Jumbo Frame: 9000 bytes (데이터센터)
패킷 단편화 문제:
시나리오: Client MTU=1500, 중간 경로 MTU=1400
Client → Router1 (MTU 1500) → Router2 (MTU 1400) → Server
1. Client: 1500 bytes 패킷 전송
2. Router2: MTU 초과, 단편화 필요
DF Flag = 0 (단편화 허용):
Original: [IP Header | 1480 bytes data]
Fragment1: [IP Header | 1380 bytes | MF=1]
Fragment2: [IP Header | 100 bytes | MF=0]
DF Flag = 1 (단편화 금지):
Router2: ICMP "Fragmentation Needed" 전송
패킷 폐기
PMTUD (Path MTU Discovery) 동작:
1. Client: DF 플래그 설정하여 1500 bytes 패킷 전송
2. MTU 1400 라우터 도달:
→ ICMP Type 3 Code 4 (Fragmentation Needed and DF set) 응답
→ Next-Hop MTU: 1400
3. Client: MTU를 1400으로 조정
→ 1400 bytes 패킷 재전송
4. 경로상 모든 구간 통과 성공
→ Path MTU = 1400 확정
5. TCP Connection에 MSS 조정:
MSS = 1400 - 20(IP) - 20(TCP) = 1360 bytes
PMTUD 실습:
# Ping으로 MTU 테스트
ping -M do -s 1472 8.8.8.8
# -M do: DF 플래그 설정
# -s 1472: 1472 bytes 데이터 (1500 - 20 IP - 8 ICMP)
성공: 1472 bytes 전송 가능 → MTU 1500
실패: ICMP "Frag needed" → MTU < 1500
# Binary Search로 Path MTU 찾기
ping -M do -s 1400 8.8.8.8 # 성공
ping -M do -s 1450 8.8.8.8 # 성공
ping -M do -s 1470 8.8.8.8 # 실패
ping -M do -s 1460 8.8.8.8 # 성공
→ Path MTU = 1488 (1460 + 20 IP + 8 ICMP)PMTUD Black Hole 문제:
문제: 방화벽이 ICMP "Fragmentation Needed" 차단
Client ─── Router (MTU 1400, ICMP 차단) ─── Server
│ │
└──── 1500 bytes (DF=1) ────X (폐기) │
│ │
└──── ICMP 응답 기다림 ────X (타임아웃) │
│ │
└──── 재전송 ────X (반복) │
결과: 연결 불가 또는 극도로 느림
해결 방법:
1. TCP MSS Clamping (권장):
# iptables로 MSS 강제 조정
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss 1360
# Cisco 라우터
interface GigabitEthernet0/0
ip tcp adjust-mss 1360
원리:
SYN 패킷의 MSS 옵션을 강제로 낮춤
→ 양쪽 모두 작은 세그먼트 사용
→ 단편화 발생 안 함2. MTU 수동 조정:
# Linux
ip link set dev eth0 mtu 1400
# Windows
netsh interface ipv4 set subinterface "Ethernet" mtu=1400
# 영구 설정 (Linux /etc/network/interfaces)
auto eth0
iface eth0 inet dhcp
mtu 14003. PLPMTUD (Packetization Layer PMTUD):
TCP의 자체 PMTUD (RFC 4821):
- ICMP에 의존하지 않음
- Probe 패킷으로 MTU 탐색
- 더 안정적이지만 느림
VPN 환경 MSS 계산:
IPsec VPN:
Physical MTU: 1500
IPsec Overhead: ~100 (ESP header, IV, Padding, Auth)
Effective MTU: 1400
TCP MSS: 1400 - 20(IP) - 20(TCP) = 1360
VXLAN:
Physical MTU: 1500
VXLAN Overhead: 50 (Outer Ethernet 14 + Outer IP 20 + Outer UDP 8 + VXLAN 8)
Effective MTU: 1450
TCP MSS: 1450 - 20 - 20 = 1410
모니터링:
# 단편화된 패킷 확인
tcpdump -i eth0 'ip[6:2] & 0x3fff != 0'
# Path MTU 확인 (Linux)
ip route get 8.8.8.8 | grep mtu
# TCP MSS 확인 (Wireshark)
tcp.options.mss시나리오 1: 느린 웹사이트 응답
증상: 웹페이지 로딩이 5초 이상 소요
tcpdump 캡처:
# 80 포트 HTTP 트래픽 캡처, 타임스탬프 마이크로초 단위
sudo tcpdump -i eth0 -nn -tttt -s 65535 'tcp port 80' -w slow-web.pcap
# 실시간 분석 (타임스탬프 포함)
sudo tcpdump -i eth0 -nn -tttt 'host example.com and tcp port 80'
출력:
2024-01-15 14:30:00.123456 IP 192.168.1.10.54321 > 93.184.216.34.80: Flags [S]
2024-01-15 14:30:00.323456 IP 93.184.216.34.80 > 192.168.1.10.54321: Flags [S.]
↑ 200ms 지연 (SYN-ACK)
2024-01-15 14:30:00.323789 IP 192.168.1.10.54321 > 93.184.216.34.80: Flags [.]
2024-01-15 14:30:00.324567 IP 192.168.1.10.54321 > 93.184.216.34.80: ... HTTP GET
2024-01-15 14:30:05.123456 IP 93.184.216.34.80 > 192.168.1.10.54321: ... HTTP 200
↑ 4.8초 지연 (서버 응답)Wireshark 분석:
1. Statistics → Conversations → TCP
→ Duration 4.8초, Bytes 확인
2. Statistics → I/O Graph
→ 시간대별 트래픽 시각화
→ 응답 대기 구간 확인
3. Display Filter:
tcp.time_delta > 1.0
→ 1초 이상 지연 패킷만 필터링
4. Expert Info (Analyze → Expert Information)
→ "TCP Window Full" 경고 확인
→ 서버 윈도우 크기 부족 (수신 버퍼 작음)
원인: 서버 TCP Window Size 부족 (16KB) 해결: 서버 수신 버퍼 증가
sysctl -w net.ipv4.tcp_rmem='4096 87380 6291456'시나리오 2: 간헐적인 패킷 손실
증상: VoIP 통화 품질 저하, 끊김 현상
tcpdump 캡처:
# RTP 트래픽 캡처 (일반적으로 UDP 10000-20000 포트)
sudo tcpdump -i eth0 -nn -s 65535 'udp portrange 10000-20000' -w voip.pcap
# Packet Loss 계산
sudo tcpdump -i eth0 -nn 'udp port 10000' | \
awk '{print $NF}' | \
awk -F. '{if (prev && $1-prev!=1) print "Lost:", prev+1, "to", $1-1; prev=$1}'Wireshark 분석:
1. Telephony → RTP → RTP Streams
→ Packet Loss: 3.5% (정상 < 1%)
→ Jitter: 50ms (정상 < 30ms)
2. Display Filter:
rtp
→ RTP Sequence Number 확인
→ 증가 패턴에서 누락 탐지
3. I/O Graph:
Y Axis: SUM(rtp.timestamp)
→ 균일하지 않은 패턴 = Jitter
4. Expert Info:
→ "Out-of-Order" 경고 다수
원인 추가 분석:
# 네트워크 인터페이스 에러 확인
ethtool -S eth0 | grep -E 'err|drop|fifo'
rx_dropped: 12345 ← 수신 버퍼 오버플로우
tx_errors: 678 ← 송신 에러
# 인터페이스 통계
ip -s link show eth0
RX errors 12345
# 시스템 로그
dmesg | grep -i 'network\|eth0'
[ 123.456] eth0: RX buffer overflow해결:
# Ring Buffer 크기 증가
ethtool -G eth0 rx 4096 tx 4096
# QoS 설정 (VoIP 우선순위)
tc qdisc add dev eth0 root handle 1: prio bands 3
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
match ip dport 10000 0xffff flowid 1:1시나리오 3: TCP 재전송 폭증
증상: 애플리케이션 응답 지연, CPU 사용률 정상
tcpdump 패턴 분석:
# 재전송 패킷 캡처
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 or \
(tcp[13] & 0x07 != 0)' -w retrans.pcap
# SYN Flood 감지
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] == tcp-syn' | \
awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -nr | head
출력:
5432 192.168.1.100 ← 비정상적으로 많은 SYN
234 192.168.1.101
123 192.168.1.102Wireshark Expert Analysis:
1. Statistics → TCP StreamGraph → Time-Sequence (Stevens)
→ 수평 라인 다수 = 재전송 대기
2. Display Filter:
tcp.analysis.retransmission
tcp.analysis.fast_retransmission
tcp.analysis.duplicate_ack
3. 재전송 비율:
Statistics → Protocol Hierarchy
→ TCP Retransmission: 15% (정상 < 3%)
4. Follow TCP Stream:
→ 3-Way Handshake 후 RST
→ SYN Flood 공격 의심
공격 확인:
# 반쯤 열린 연결 수 확인
netstat -an | grep SYN_RECV | wc -l
12345 ← 비정상 (정상 < 100)
# SYN Cookie 활성화 (임시 방어)
sysctl -w net.ipv4.tcp_syncookies=1
# 연결 타임아웃 단축
sysctl -w net.ipv4.tcp_synack_retries=1
# iptables Rate Limiting
iptables -A INPUT -p tcp --syn -m limit --limit 10/s --limit-burst 20 -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP시나리오 4: DNS 쿼리 실패
tcpdump DNS 분석:
# DNS 쿼리/응답 캡처
sudo tcpdump -i eth0 -nn -s 65535 'udp port 53' -w dns-issue.pcap
# 실시간 모니터링
sudo tcpdump -i eth0 -nn 'port 53'
출력:
14:30:00.123 IP 192.168.1.10.54321 > 8.8.8.8.53: 12345+ A? example.com
14:30:05.123 IP 192.168.1.10.54321 > 8.8.8.8.53: 12345+ A? example.com
↑ 5초 후 재시도
(응답 없음)Wireshark 분석:
1. Display Filter:
dns.flags.response == 0 && !dns.flags.response == 1
→ 응답 없는 쿼리만 필터링
2. Statistics → DNS
→ Query Rate: 100/s
→ Response Rate: 0/s
→ 100% 손실
3. Follow UDP Stream:
→ DNS 서버 방화벽 차단 확인
→ ICMP "Port Unreachable" 수신
문제 진단:
# DNS 서버 연결 테스트
dig @8.8.8.8 example.com +trace
# 방화벽 확인
sudo iptables -L -n -v | grep -i dns
0 0 DROP udp -- * * 0.0.0.0/0 8.8.8.8 udp dpt:53
# 대체 DNS 테스트
dig @1.1.1.1 example.com # Cloudflare DNS 정상해결:
# 방화벽 규칙 수정
iptables -D OUTPUT -p udp --dport 53 -d 8.8.8.8 -j DROP
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
# /etc/resolv.conf 업데이트
nameserver 1.1.1.1
nameserver 8.8.8.8유용한 tcpdump 필터:
# HTTP 요청만
tcpdump -i eth0 -A 'tcp port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420)'
# GET 문자열 (0x47455420)
# SYN 패킷만
tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0'
# RST 패킷만
tcpdump -i eth0 'tcp[tcpflags] & tcp-rst != 0'
# 특정 MAC 주소
tcpdump -i eth0 ether host aa:bb:cc:dd:ee:ff
# VLAN 태그
tcpdump -i eth0 'vlan and host 192.168.1.10'
# 큰 패킷 (1400 bytes 이상)
tcpdump -i eth0 'ip[2:2] > 1400'
# ICMP Redirect
tcpdump -i eth0 'icmp[icmptype] == 5'Wireshark 고급 필터:
# TCP Window가 0인 패킷 (흐름 제어)
tcp.window_size == 0
# TCP Zero Window Probe
tcp.analysis.zero_window_probe
# Delayed ACK
tcp.analysis.ack_rtt > 0.2
# TCP Out-of-Order
tcp.analysis.out_of_order
# HTTP 특정 User-Agent
http.user_agent contains "bot"
# SSL/TLS Handshake 실패
ssl.alert_message.desc == 40 # Handshake Failure
TCP Flow Control vs Congestion Control:
Flow Control (흐름 제어):
- 목적: 수신자 버퍼 오버플로우 방지
- 메커니즘: TCP Window Size (Receiver Advertised Window)
- 범위: Point-to-Point (송신자 ↔ 수신자)
Congestion Control (혼잡 제어):
- 목적: 네트워크 혼잡 방지
- 메커니즘: Congestion Window (cwnd)
- 범위: End-to-End (전체 경로)
TCP Congestion Control 상태 머신:
┌─────────────────────────────────────────────────────────┐
│ Slow Start │
│ cwnd: 1 MSS → 2 → 4 → 8 → 16 ... (Exponential) │
│ 매 ACK마다 cwnd += 1 MSS │
└────────────────┬────────────────────────────────────────┘
│ cwnd >= ssthresh (Slow Start Threshold)
↓
┌─────────────────────────────────────────────────────────┐
│ Congestion Avoidance │
│ cwnd 증가: Linear (매 RTT마다 1 MSS) │
│ 매 ACK마다 cwnd += MSS * MSS / cwnd │
└────────────────┬────────────────────────────────────────┘
│ Packet Loss 감지
↓
┌───────┴────────┐
│ │
3 Dup ACK Timeout
│ │
↓ ↓
┌─────────────┐ ┌──────────────────┐
│ Fast │ │ Slow Start │
│ Recovery │ │ (처음부터 재시작)│
│ ssthresh= │ │ ssthresh= │
│ cwnd/2 │ │ cwnd/2 │
│ cwnd= │ │ cwnd= 1 MSS │
│ ssthresh+3 │ │ │
└─────────────┘ └──────────────────┘
구체적인 예시:
초기 상태:
cwnd = 1 MSS (1460 bytes)
ssthresh = 64 KB
RTT = 100ms
Round 1 (Slow Start):
- 1 MSS 전송 → ACK 수신 → cwnd = 2 MSS
Round 2:
- 2 MSS 전송 → 2 ACK 수신 → cwnd = 4 MSS
Round 3:
- 4 MSS 전송 → 4 ACK 수신 → cwnd = 8 MSS
...
Round 7:
- cwnd = 64 MSS = 93,440 bytes
- cwnd >= ssthresh → Congestion Avoidance 전환
Round 8 (Congestion Avoidance):
- 64 MSS 전송 → 64 ACK 수신
- cwnd += 64 * 1460 / 93440 = 1 MSS
- cwnd = 65 MSS
Round 9:
- cwnd = 66 MSS (Linear 증가)
Round 15:
- Packet Loss (3 Duplicate ACK)
- Fast Retransmit 실행
- ssthresh = cwnd / 2 = 36 MSS
- cwnd = ssthresh + 3 = 39 MSS
- Fast Recovery 진입
주요 Congestion Control 알고리즘:
1. Reno (Classic):
- Fast Retransmit: 3 Duplicate ACK → 즉시 재전송
- Fast Recovery: cwnd를 절반으로 줄이고 Congestion Avoidance
- Timeout: cwnd = 1, Slow Start 재시작
2. Cubic (Linux 기본값):
- Window 증가가 Cubic 함수 따름
- Loss 발생 지점(Wmax)을 기억
- Wmax 근처에서 신중하게 증가
- 고속 네트워크(Long Fat Network)에 최적화
K = cubic_root((Wmax - cwnd) / C)
cwnd = C * (t - K)³ + Wmax
장점: RTT가 길어도 빠른 대역폭 활용
3. BBR (Bottleneck Bandwidth and RTT):
- Google 개발 (2016)
- Loss 기반이 아닌 Bandwidth와 RTT 측정 기반
- 4가지 상태: Startup, Drain, ProbeBW, ProbeRTT
장점:
- 버퍼 블로트(Bufferbloat) 해결
- Packet Loss 환경에서도 안정적
- YouTube, Google Cloud 등에서 사용
sysctl -w net.ipv4.tcp_congestion_control=bbr
TCP Window Scaling (RFC 1323):
문제:
TCP Window Size 필드: 16 bits → 최대 65,535 bytes
고속 네트워크 (1 Gbps, RTT 100ms):
- BDP (Bandwidth-Delay Product) = 1Gbps * 100ms = 12.5 MB
- 기본 Window Size로는 처리량 제한
Throughput = Window Size / RTT = 65KB / 0.1s = 650 KB/s
→ 1 Gbps 회선에서 5 Mbps만 활용
해결: Window Scale Option
TCP SYN 패킷에 포함:
┌────────────────────────────────┐
│ Option Kind: 3 (Window Scale) │
│ Option Length: 3 │
│ Shift Count: 7 │ ← 2^7 = 128 배 확장
└────────────────────────────────┘
실제 Window Size = (TCP Header Window) << (Shift Count)
예: Header Window = 65,535
Shift Count = 7
Actual Window = 65,535 * 128 = 8,388,480 bytes (8 MB)
Window Scaling 확인:
# tcpdump로 SYN 패킷 확인
sudo tcpdump -i eth0 -nn -vv 'tcp[tcpflags] & tcp-syn != 0'
출력:
IP 192.168.1.10.54321 > 93.184.216.34.80: Flags [S], seq 123, win 65535,
options [mss 1460,nop,wscale 7,nop,nop,TS val 123 ecr 0,sackOK,eol]
↑ wscale 7 = 128배 확장
# Wireshark 분석
tcp.options.wscale.shift
tcp.window_size_scalefactor실무 설정 (Linux):
# TCP 수신 버퍼 크기
sysctl -w net.ipv4.tcp_rmem='4096 87380 6291456'
# min default max (6 MB)
# TCP 송신 버퍼 크기
sysctl -w net.ipv4.tcp_wmem='4096 16384 4194304'
# min default max (4 MB)
# Window Scaling 활성화 (기본값 1)
sysctl -w net.ipv4.tcp_window_scaling=1
# SACK (Selective Acknowledgment) 활성화
sysctl -w net.ipv4.tcp_sack=1
# Timestamps 활성화 (RTT 측정)
sysctl -w net.ipv4.tcp_timestamps=1
# 처리량 계산
# BDP = Bandwidth * RTT
# 1 Gbps * 100ms = 125 MB/s * 0.1s = 12.5 MB
# Window Size >= BDP성능 측정:
# iperf3로 처리량 테스트
iperf3 -c server.example.com -t 60 -P 4
출력 (최적화 전):
[ 5] 0.00-60.00 sec 5.12 GBytes 734 Mbits/sec receiver
↑ Window Size 부족
# Window Scaling 후:
[ 5] 0.00-60.00 sec 65.3 GBytes 9.35 Gbits/sec receiver
↑ 거의 전체 대역폭 활용
# cwnd 모니터링
ss -i | grep -i cwnd
cubic wscale:7,7 rto:204 rtt:3.5/2 cwnd:10 send 33.1Mbps
↑ Window Scale ↑ Congestion WindowWireshark로 성능 문제 진단:
1. TCP Window Full:
→ 수신자 윈도우 크기 부족
→ 송신자가 대기해야 함
tcp.analysis.window_full
2. TCP Zero Window:
→ 수신자 버퍼 가득 참
→ 송신 중단
tcp.window_size == 0
3. TCP Window Update:
→ 수신자가 윈도우 확장 알림
tcp.analysis.window_update
해결:
- 수신 버퍼 크기 증가
- Window Scaling 활성화
- 애플리케이션 처리 속도 개선
BPF (Berkeley Packet Filter) 문법:
기본 구조:
[protocol] [direction] [type] [value]
protocol: ip, ip6, arp, tcp, udp, icmp
direction: src, dst, src and dst, src or dst
type: host, net, port, portrange
실전 예제:
1. 특정 호스트 간 통신:
# 양방향
tcpdump host 192.168.1.10
# 출발지만
tcpdump src host 192.168.1.10
# 목적지만
tcpdump dst host 192.168.1.10
# 두 호스트 간 통신
tcpdump host 192.168.1.10 and host 192.168.1.202. 네트워크 범위:
# 서브넷
tcpdump net 192.168.1.0/24
tcpdump net 192.168.1.0 mask 255.255.255.0
# 여러 서브넷
tcpdump 'net 192.168.1.0/24 or net 10.0.0.0/8'3. 포트 필터링:
# 단일 포트
tcpdump port 80
tcpdump dst port 443
# 포트 범위
tcpdump portrange 10000-20000
# 여러 포트
tcpdump 'port 80 or port 443 or port 8080'
# 특정 포트 제외
tcpdump 'not port 22'4. TCP 플래그 필터:
# SYN 패킷만
tcpdump 'tcp[tcpflags] & tcp-syn != 0'
tcpdump 'tcp[13] & 2 != 0' # 동일 (13번째 바이트, bit 1)
# SYN-ACK
tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)'
tcpdump 'tcp[13] == 18' # SYN(2) + ACK(16) = 18
# FIN 패킷
tcpdump 'tcp[tcpflags] & tcp-fin != 0'
# RST 패킷
tcpdump 'tcp[tcpflags] & tcp-rst != 0'
# PSH-ACK (데이터 전송)
tcpdump 'tcp[tcpflags] & (tcp-push|tcp-ack) == (tcp-push|tcp-ack)'
# ACK만 (SYN, FIN, RST 제외)
tcpdump 'tcp[tcpflags] == tcp-ack'5. IP 헤더 필터:
# TTL 특정 값
tcpdump 'ip[8] == 64' # TTL = 64
# TTL < 10 (의심스러운 패킷)
tcpdump 'ip[8] < 10'
# IP 옵션이 있는 패킷
tcpdump 'ip[0] & 0x0f > 5' # IHL > 5 (옵션 존재)
# DF (Don't Fragment) 플래그
tcpdump 'ip[6] & 0x40 != 0'
# MF (More Fragments) 플래그
tcpdump 'ip[6] & 0x20 != 0'
# 단편화된 패킷
tcpdump 'ip[6:2] & 0x1fff != 0'
# ToS/DSCP 값
tcpdump 'ip[1] & 0xfc == 0xb8' # EF (Expedited Forwarding)6. 페이로드 검색:
# HTTP GET 요청
tcpdump -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'
# "GET " ASCII
# HTTP POST
tcpdump -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354'
# "POST"
# HTTP 응답 200
tcpdump -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x48545450'
# "HTTP"
# SSH 프로토콜 식별
tcpdump -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x5353482d'
# "SSH-"7. 복합 필터:
# 외부 → 내부 웹 트래픽 (포트 80, 443)
tcpdump 'dst net 192.168.0.0/16 and (port 80 or port 443)'
# SSH를 제외한 모든 트래픽
tcpdump 'not port 22'
# 특정 호스트로의 DNS 쿼리
tcpdump 'src host 192.168.1.10 and dst port 53'
# ICMP Echo Request/Reply
tcpdump 'icmp[icmptype] == 8 or icmp[icmptype] == 0'
# ARP 요청만
tcpdump 'arp[6:2] == 1' # ARP opcode = 1 (request)성능 최적화:
1. Capture Filter vs Display Filter:
# 좋음: Capture Filter (BPF, 커널 레벨)
tcpdump -i eth0 'host 192.168.1.10'
→ 불필요한 패킷은 캡처 안 함
→ CPU/메모리 절약
# 나쁨: 모든 패킷 캡처 후 필터링
tcpdump -i eth0 -w all.pcap
wireshark all.pcap # Display Filter 사용
→ 디스크 I/O 과다
→ 대용량 파일 생성2. 스냅샷 길이 최적화:
# 헤더만 필요한 경우 (기본값 262144)
tcpdump -i eth0 -s 96 'tcp'
# Ethernet(14) + IP(20) + TCP(20) + 옵션(42) = 96 bytes
# 전체 패킷 (페이로드 분석 필요)
tcpdump -i eth0 -s 65535 'port 80'
# 최소 크기 (헤더만)
tcpdump -i eth0 -s 0 'tcp' # 0 = 전체3. 버퍼 크기 조정:
# 기본 버퍼: 2 MB
tcpdump -i eth0 -B 16384 'port 80'
# 16 MB 버퍼 (고속 네트워크)
# 드롭 패킷 확인
tcpdump -i eth0 -vv 'port 80'
^C
1000 packets captured
950 packets received by filter
50 packets dropped by kernel ← 버퍼 부족4. Ring Buffer 사용 (파일 로테이션):
# 10MB 파일 5개 순환 (총 50MB)
tcpdump -i eth0 -C 10 -W 5 -w capture.pcap 'port 80'
# capture.pcap0, capture.pcap1, ..., capture.pcap4
# 시간 기반 로테이션 (5분마다)
tcpdump -i eth0 -G 300 -w 'capture-%Y%m%d-%H%M%S.pcap'5. 멀티코어 활용:
# CPU Affinity 설정
taskset -c 0 tcpdump -i eth0 -w cpu0.pcap 'port 80'
taskset -c 1 tcpdump -i eth1 -w cpu1.pcap 'port 443'
# PF_RING (고성능 패킷 캡처)
tcpdump -i eth0@1 -w capture.pcap # PF_RING 채널 16. 실시간 분석 vs 파일 저장:
# 실시간 분석 (화면 출력)
tcpdump -i eth0 -l 'port 80' | grep "GET"
# -l: Line Buffered (즉시 출력)
# 파일 저장 후 분석 (권장)
tcpdump -i eth0 -w capture.pcap 'port 80'
wireshark capture.pcap7. 샘플링:
# 1/10 패킷만 캡처 (통계 목적)
tcpdump -i eth0 -w capture.pcap \
'tcp and (tcp[13] & 0x17 = 0x02) and (rand() % 10 = 0)'고급 BPF 예제:
웹 트래픽 분석:
# HTTP 헤더만 (첫 1024 bytes)
tcpdump -i eth0 -s 1024 -A 'tcp port 80 and (
(tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420) or
(tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x48545450)
)'
# HTTPS ClientHello (TLS Handshake)
tcpdump -i eth0 '(tcp[((tcp[12:1] & 0xf0) >> 2)] = 0x16) and
(tcp[((tcp[12:1] & 0xf0) >> 2) + 1] = 0x03) and
(tcp[((tcp[12:1] & 0xf0) >> 2) + 5] = 0x01)'보안 분석:
# Port Scan 감지 (SYN만 많은 경우)
tcpdump -i eth0 'tcp[tcpflags] == tcp-syn and src host 192.168.1.0/24'
# SYN Flood
tcpdump -i eth0 -nn -q 'tcp[tcpflags] == tcp-syn' | \
awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | \
awk '$1 > 100 {print "Possible SYN flood from", $2, "with", $1, "SYNs"}'
# DNS Amplification
tcpdump -i eth0 'udp port 53 and ip[2:2] > 512'성능 테스트:
# 고속 네트워크 (10 Gbps)
# 일반 tcpdump: ~1 Gbps 처리 가능
# PF_RING: ~10 Gbps
# DPDK: ~40 Gbps
# tcpdump 성능 측정
time tcpdump -i eth0 -c 100000 -w /dev/null 'tcp'
real 0m2.345s
user 0m0.123s
sys 0m1.234s
→ ~42,000 pps (packets per second)💡 용어 설명:
- 패킷 분석 관련 질문들(Q19-Q23)에서 사용된 용어들(Ethernet Frame, IP Packet, TCP Segment, MTU/MSS, PMTUD, TCP Window Scaling, BPF 등)에 대한
- 상세한 설명은 문서 상단의 주요 용어 통합 정리 > 패킷 분석 & 트러블슈팅 섹션을 참고하세요.