infra
Platform

모듈 맵

[Linux] 네트워크 트러블슈팅 심화 — tcpdump와 패킷 분석

0 / 20 완료

펼치기

Linux-master · 20 / 20

[Linux] 네트워크 트러블슈팅 심화 — tcpdump와 패킷 분석

ss/netstat 소켓 상태 분석과 tcpdump 패킷 캡처로 실제 네트워크 장애를 레이어별로 진단합니다

🚨INCIDENT ALERT
HIGH

오후 2시, "API가 갑자기 안 된다"는 슬랙 메시지가 날아옵니다. 서버는 살아 있고 애플리케이션 로그에도 에러가 없습니다. 그런데 클라이언트에서는 계속 타임아웃입니다. ping은 되는데 실제 포트로 연결이 안 되고, 어느 구간에서 패킷이 사라지는지 알 수 없습니다. 이런 상황에서 ss로 소켓 상태를 읽고 tcpdump로 실제 패킷을 잡아볼 수 있다면 10분 안에 어디가 문제인지 특정할 수 있습니다.

네트워크 트러블슈팅 심화 — tcpdump와 패킷 분석

서버 로그에는 아무것도 없는데 연결이 안 된다. 애플리케이션은 멀쩡한데 응답이 느리다. 이런 상황에서 필요한 건 실제 패킷을 들여다보는 능력입니다. ss로 소켓 상태를 읽고, tcpdump로 패킷을 잡아서 무슨 일이 일어나는지 직접 확인하는 것이 이 모듈의 목표입니다.


이번 챕터에서 배울 것

네트워크 문제는 "안 된다"는 증상 하나로 시작합니다. 계층을 내려가면서 어디서 막혔는지 좁혀가는 것이 핵심입니다.

  • 1TCP 상태 머신 — SYN_SENT/ESTABLISHED/TIME_WAIT 상태가 말하는 것
  • 2ss -tnp — 소켓 상태, Recv-Q/Send-Q, 프로세스 매핑
  • 3tcpdump 기초 — 필터 문법과 실시간 캡처
  • 4tcpdump → Wireshark 파일로 저장해 심층 분석
  • 5레이어별 진단 플로우 — 어디서 막혔는지 5분 안에 특정
  • 6실제 장애 패턴 — SYN 타임아웃, TIME_WAIT 고갈, 비대칭 라우팅
실습 환경 준비

💡개념

TCP 상태 머신 — ss 출력으로 지금 무슨 일이 일어나는지 읽기

로컬 터미널
# 실행 중인 TCP 연결 전체 확인 (프로세스 포함)
ss -tnp

# LISTEN 중인 포트만 확인
ss -tnlp

# 특정 포트 필터
ss -tnp '( dport = :443 or sport = :443 )'
State     Recv-Q  Send-Q  Local Address:Port  Peer Address:Port  Process
LISTEN         0     128  0.0.0.0:80          0.0.0.0:*          nginx
ESTABLISHED    0       0  10.0.0.1:80         10.0.0.5:54321     nginx
SYN-SENT       0       1  10.0.0.1:45123      10.0.0.9:5432      python
TIME_WAIT      0       0  10.0.0.1:80         10.0.0.7:39201     -

상태별 진단 의미:

상태의미다량 발생 시 의심
SYN-SENT연결 시도 중, 응답 대기대상 서버 방화벽 차단 또는 프로세스 없음
SYN-RECV서버가 SYN 받음, ACK 대기SYN Flood 공격 가능성
ESTABLISHED정상 연결과다 시 Connection Pool 미사용
TIME_WAIT종료 후 대기(2MSL)단기 연결 반복 → 포트 고갈 위험
CLOSE-WAIT원격이 먼저 종료했는데 로컬이 안 닫음애플리케이션 코드 버그 (소켓 미닫힘)

Recv-Q / Send-Q 읽기:

로컬 터미널
# LISTEN 소켓의 Recv-Q = 수락 대기 중인 연결 큐 크기
# ESTABLISHED 소켓의 Recv-Q = 앱이 아직 읽지 않은 데이터 (바이트)
# ESTABLISHED 소켓의 Send-Q = ACK 못 받은 전송 대기 데이터 (바이트)

# Recv-Q 지속적으로 높음 → 앱 처리 속도 부족 (백프레셔)
# Send-Q 지속적으로 높음 → 네트워크 혼잡 또는 수신 측 처리 지연

💡개념

tcpdump — 패킷을 직접 잡아서 보기

로컬 터미널
# 기본 문법
tcpdump [옵션] [필터 표현식]

# 주요 옵션
-i eth0      # 인터페이스 지정 (-i any: 모든 인터페이스)
-n           # DNS 역조회 비활성화 (속도 향상)
-v/-vv       # 상세 출력 (패킷 헤더 포함)
-c 100       # 패킷 100개 캡처 후 종료
-w dump.pcap # 파일로 저장 (Wireshark로 분석 가능)
-r dump.pcap # 저장된 파일 읽기

# 자주 쓰는 필터 조합
sudo tcpdump -i eth0 -n 'tcp port 80'
sudo tcpdump -i eth0 -n 'host 192.168.1.10'
sudo tcpdump -i eth0 -n 'tcp port 5432 and host 10.0.0.9'
sudo tcpdump -i eth0 -n 'tcp[tcpflags] & (tcp-syn) != 0'  # SYN 패킷만

출력 읽기:

14:23:01.123456 IP 10.0.0.5.54321 > 10.0.0.1.80: Flags [S], seq 1234567
14:23:01.123478 IP 10.0.0.1.80 > 10.0.0.5.54321: Flags [S.], seq 9876543, ack 1234568
14:23:01.123490 IP 10.0.0.5.54321 > 10.0.0.1.80: Flags [.], ack 9876544
Flags의미
[S]SYN (연결 시작)
[S.]SYN-ACK (연결 응답)
[.]ACK
[P.]PSH+ACK (데이터 전송)
[F.]FIN (연결 종료 시작)
[R]RST (연결 강제 초기화)

RST가 보이면: 서버가 연결 요청을 거부했거나, 이미 닫힌 포트에 패킷이 도달한 것입니다.


레이어별 진단 플로우

"연결이 안 된다"
    │
    ├─ ping 대상서버IP
    │   ├─ 실패 → L3 문제 (라우팅, 방화벽 ICMP 차단)
    │   └─ 성공 ↓
    │
    ├─ telnet 대상IP 포트  (또는 nc -zv 대상IP 포트)
    │   ├─ 실패 → L4 문제 → 아래 확인
    │   │   ├─ 대상서버: ss -tnlp | grep <포트>  (프로세스 LISTEN 중인가?)
    │   │   └─ 대상서버: iptables -L -n | grep <포트>  (방화벽 차단인가?)
    │   └─ 성공 ↓
    │
    ├─ curl -v http://대상IP  (또는 애플리케이션 직접 요청)
    │   ├─ 실패 → L7 문제 (앱 설정, 인증, SSL)
    │   └─ 느림 → tcpdump로 RTT 분석
    │
    └─ tcpdump -i eth0 -n 'host 대상IP and tcp port <포트>'
        ├─ SYN 후 응답 없음 → 방화벽이 패킷 DROP
        ├─ SYN → RST → 포트 닫힘 또는 프로세스 없음
        └─ 정상 handshake 후 느림 → 앱 레이어 문제

SYN 타임아웃 — 방화벽이 패킷을 DROP하는 경우

로컬 터미널
# 증상: nc -zv 10.0.0.9 5432 → Connection timed out (즉시 Refused 아님)
# "timed out"은 패킷이 사라졌다는 뜻. "refused"는 RST를 받았다는 뜻.

# 제어 노드에서 tcpdump (SYN 패킷이 전송되는지 확인)
sudo tcpdump -i eth0 -n 'host 10.0.0.9 and tcp port 5432'

# → SYN 보냄 [S] 보이지만 [S.] 응답 없음 → 패킷이 대상 서버에 안 도달하거나 DROP됨

# 대상 서버에서 확인
sudo tcpdump -i any -n 'tcp port 5432'  # 패킷이 도달하는가?
sudo iptables -L INPUT -n -v | grep 5432  # 방화벽 DROP 규칙 있는가?
sudo ss -tnlp | grep 5432                 # 프로세스가 LISTEN 중인가?

방화벽 DROP vs REJECT 차이:

  • DROP: 패킷을 조용히 버림 → 클라이언트는 타임아웃까지 기다림
  • REJECT: RST 응답을 즉시 보냄 → 클라이언트는 즉시 "Connection refused" 받음

소켓 누수 — 애플리케이션이 연결을 닫지 않는 버그

로컬 터미널
# 증상 확인
ss -tnp | grep CLOSE-WAIT | wc -l   # 개수 확인
ss -tnp | grep CLOSE-WAIT           # 어떤 프로세스인지 확인

# CLOSE-WAIT의 의미:
# 원격 피어가 FIN을 보내 먼저 연결 종료를 요청했지만
# 로컬 애플리케이션이 소켓을 close()하지 않아 연결이 남아있는 상태

# 원인: 데이터베이스/HTTP 클라이언트에서 connection.close() 누락
# 특히 예외 처리 경로(try/except)에서 close가 호출되지 않는 케이스

# 임시 조치: 해당 프로세스 재시작
# 근본 조치: 코드에서 finally: conn.close() 또는 with 구문 사용 확인

💼
실무 맥락
현업 패턴

실무에서 tcpdump가 쓰이는 순간

API 간헐적 지연 — "로그는 정상인데 왜 느리지?" 케이스:

로컬 터미널
# 1단계: 어느 구간에서 지연이 발생하는지 tcpdump로 확인
sudo tcpdump -i eth0 -n -w /tmp/api-trace.pcap 'tcp port 8080' &
# API 요청 재현
kill %1

# 2단계: RTT 계산 (SYN → SYN-ACK 시간이 정상인가?)
tcpdump -r /tmp/api-trace.pcap -n -tt | head -20

# 3단계: Wireshark에서 pcap 파일 열어 TCP Stream Follow
# → "Time between request and response" 확인

# 자주 발견되는 패턴:
# SYN → SYN-ACK: 0.001ms (네트워크는 정상)
# Request → Response: 800ms (앱 처리 지연)
# → DB 쿼리 슬로우 로그 확인으로 전환

온콜 대응 체크리스트:

1. ss -tnp | wc -l              → 연결 수 급증?
2. ss -tnp | grep -c TIME_WAIT → TIME_WAIT 고갈?
3. ss -tnp | grep -c CLOSE_WAIT → 소켓 누수?
4. ss -tnlp                    → 포트 정상 LISTEN?
5. tcpdump -i any -c 50 -n ... → 패킷 실제 도달?

지식 확인

퀴즈 — 4문제

Q1

ss -tnp 출력에서 State가 SYN-SENT인 소켓이 대량 발생했다. 원인으로 가장 적합한 것은?

Q2

TIME_WAIT 소켓이 수천 개 발생하면 어떤 문제가 생기는가?

Q3

tcpdump -i eth0 'tcp port 80 and host 192.168.1.10' 필터의 의미는?

Q4

애플리케이션 로그에는 오류가 없는데 API 응답이 간헐적으로 느리다. 첫 번째로 확인해야 할 것은?

0 / 4 답변