📚 네트워크 · 패킷 분석 › 01. TCP/IP 구조 이해 — 34편
이전 글: 33. ARP Cache · 다음 글: 35. Ping의 동작 원리
참고(리눅스 시스템 기초): Firewalld 이해 — ICMP 차단 설정(icmp-block)이 있는 곳
ICMP(Internet Control Message Protocol)를 "ping에 쓰는 프로토콜" 정도로만 알고 있으면 관제에서 두 가지를 놓칩니다.
반대로 "ICMP는 위험하니 전부 막는다"도 정답이 아닙니다. 필요한 오류 메시지까지 막으면 경로 MTU 탐색(PMTUD)이 깨져 특정 사이트만 접속이 멈추는 장애가 생길 수 있습니다. 이번 글은 ICMP 메시지의 구조와 종류, 그리고 관제에서 어떤 ICMP를 주목해야 하는지를 다룹니다. 패킷 필드 단위 해석은 03. Wireshark 패킷 분석 시리즈의 10. ICMP 패킷 분석에서 이어갑니다.
ICMP는 IP 위에 실려 가지만(IP 헤더의 Protocol 번호 1) TCP·UDP처럼 애플리케이션 데이터를 나르는 프로토콜이 아니라, IP 계층의 제어·오류 보고용 프로토콜입니다(RFC 792). 따라서 포트 번호가 없습니다. 대신 Type(메시지 종류)과 Code(세부 사유)로 의미를 구분합니다. IPv6에서는 별도의 ICMPv6(Protocol 58)가 쓰이며, 이는 13편 IPv6 기초에서 다룹니다.
| Type | 이름 | 주요 Code | 누가 보내는가 / 의미 |
|---|---|---|---|
| 0 | Echo Reply | 0 | ping에 대한 응답 |
| 3 | Destination Unreachable | 0 Net, 1 Host, 2 Protocol, 3 Port, 4 Fragmentation Needed and DF set, 13 Communication Administratively Prohibited | 목적지까지 전달 불가. 사유가 Code에 담김 |
| 5 | Redirect | 0 Network, 1 Host | "더 좋은 게이트웨이가 있다"는 라우터의 안내 |
| 8 | Echo Request | 0 | ping 요청 |
| 11 | Time Exceeded | 0 TTL exceeded in transit, 1 Fragment reassembly time exceeded | TTL이 0이 되어 폐기됨 (traceroute의 원리) |
Type 3의 Code는 관제에서 특히 유용합니다.
| Type 3 Code | 해석 |
|---|---|
| 1 Host Unreachable | 마지막 라우터가 대상 호스트를 찾지 못함 (ARP 응답 없음 등) |
| 3 Port Unreachable | 호스트는 살아 있으나 해당 UDP 포트가 닫혀 있음 (TCP는 이 경우 RST로 응답) |
| 4 Fragmentation Needed | 경로상 MTU보다 큰데 DF 비트가 켜져 있음 → PMTUD에 필수 (12편에서 다룸) |
| 13 Administratively Prohibited | 방화벽·ACL이 정책으로 거부하면서 알려줌 |
| 구분 | 예 | 특징 |
|---|---|---|
| 조회(Query)형 | Echo Request/Reply (8/0) | 요청과 응답 쌍. Identifier·Sequence 필드로 짝을 맞춤 |
| 오류(Error)형 | Unreachable(3), Time Exceeded(11), Redirect(5) | 문제를 일으킨 원래 패킷의 IP 헤더와 앞부분 데이터를 본문에 담아 되돌려 보냄 |
오류 메시지에 원래 패킷 일부가 들어 있다는 점이 중요합니다. ICMP 오류 하나만 보고도 "어떤 IP·포트로 가던 패킷이 실패했는지"를 알 수 있습니다. 또한 ICMP 오류에 대해서는 다시 ICMP 오류를 보내지 않도록 규정되어 있어 오류가 무한히 반복되지 않습니다.
같은 "접속 시도"라도 결과에 따라 돌아오는 ICMP가 달라집니다. 클라이언트 192.168.10.10이 여러 대상에 패킷을 보낸 경우입니다.

그림 1. 정상 응답(Echo)과 오류 보고(Time Exceeded, Destination Unreachable)의 흐름
[클라이언트 192.168.10.10]
│
├─ ping 192.168.10.20 (살아 있음)
│ Echo Request (8/0) ──────────────→ 192.168.10.20
│ ←──────────────── Echo Reply (0/0)
│
├─ UDP 192.168.10.20:9999 (닫힌 UDP 포트)
│ UDP 데이터 ──────────────────────→ 192.168.10.20
│ ←──── Dest Unreachable 3/3 (Port) + 원래 UDP 헤더 포함
│
├─ 외부 203.0.113.50 에 TTL=1 로 전송 (traceroute 첫 홉)
│ 패킷 ──→ 게이트웨이 192.168.10.1 (TTL 1 → 0, 폐기)
│ ←──── Time Exceeded 11/0 (출발지: 게이트웨이)
│
└─ 방화벽이 reject 정책인 대상
패킷 ──→ 방화벽
←──── Dest Unreachable 3/13 (Administratively Prohibited)
※ drop 정책이면 아무 응답도 없음 → 타임아웃
여기서 관제 관점의 요점은 다음과 같습니다.
net.ipv4.icmp_ratelimit). 따라서 짧은 시간에 많은 닫힌 UDP 포트로 보내면 일부에만 Port Unreachable이 돌아옵니다.실습 환경: 본인 소유 Linux VM (Rocky Linux 또는 Ubuntu) 2대(192.168.10.10, 192.168.10.20 예시). 인터페이스 이름은 ens33을 예시로 사용합니다(환경에 따라 다름).
# Rocky Linux
sudo dnf install -y tcpdump nmap-ncat traceroute
# Ubuntu
sudo apt install -y tcpdump netcat-openbsd traceroute
# [터미널 1] ICMP만 캡처
sudo tcpdump -nn -i ens33 icmp
# [터미널 2] 4회 ping
ping -c 4 192.168.10.20
# [터미널 1] Echo 계열을 제외한 ICMP만 캡처 (오류 메시지만 보기)
sudo tcpdump -nn -i ens33 'icmp and icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply'
# [터미널 2] 닫힌 UDP 포트로 데이터 1회 전송
echo test | nc -u -w1 192.168.10.20 9999
# 외부 대상까지의 경로 (UDP 기반 기본 traceroute)
traceroute -n 203.0.113.50
# ICMP Echo 기반으로 경로 확인
sudo traceroute -n -I 203.0.113.50
traceroute의 동작 원리(TTL 증가)는 04편에서 설명했습니다. 여기서는 돌아오는 메시지가 Type 11이라는 점만 확인합니다. (203.0.113.50은 문서용 예시 주소이므로 실제 실습에서는 본인이 접근 가능한 대상을 사용합니다.)
# Echo 요청 무시 여부 (0 = 응답함)
sysctl net.ipv4.icmp_echo_ignore_all
# 브로드캐스트 Echo 무시 여부 (1 = 무시, 기본값)
sysctl net.ipv4.icmp_echo_ignore_broadcasts
# Redirect 수신 허용 여부
sysctl net.ipv4.conf.all.accept_redirects
# firewalld에서 차단 중인 ICMP 타입
sudo firewall-cmd --zone=public --list-icmp-blocks
# firewalld가 인식하는 ICMP 타입 이름 목록
sudo firewall-cmd --get-icmptypes
📷 [실습 화면 삽입]
tcpdump -nn -i ens33 icmp화면 — echo request / echo reply 쌍과 id·seq 값
tcpdump 출력 형식 예시(값은 환경마다 다름):
IP 192.168.10.10 > 192.168.10.20: ICMP echo request, id 3021, seq 1, length 64
IP 192.168.10.20 > 192.168.10.10: ICMP echo reply, id 3021, seq 1, length 64
IP 192.168.10.20 > 192.168.10.10: ICMP 192.168.10.20 udp port 9999 unreachable, length 41
IP 192.168.10.1 > 192.168.10.10: ICMP time exceeded in-transit, length 36
| 출력 요소 | 읽는 법 |
|---|---|
id 3021, seq 1 | Echo 요청·응답 짝 맞추기. 같은 id의 seq가 1, 2, 3… 증가 |
length 64 | ICMP 부분 길이. Linux ping 기본 데이터 56바이트 + ICMP 헤더 8바이트 |
udp port 9999 unreachable | Type 3 Code 3. 원래 패킷(UDP 9999)이 본문에 포함되어 있어 이렇게 표시됨 |
time exceeded in-transit | Type 11 Code 0. 출발지는 중간 라우터 |
ping 자체의 출력(64 bytes from 192.168.10.20: icmp_seq=1 ttl=64 time=0.41 ms)에서 ttl 값은 응답한 호스트의 초기 TTL에서 거쳐 온 홉 수를 뺀 값입니다(04편 참고).
icmp_echo_ignore_all, accept_redirects 현재 값을 확인했다📷 [실습 화면 삽입] 오류 메시지 필터 캡처 결과 —
udp port 9999 unreachable라인
| 관찰 | 정상일 수 있는 경우 | 의심해야 하는 경우 |
|---|---|---|
| 한 출발지의 Echo Request가 여러 목적지로 순차 발생 | 모니터링 서버(NMS)의 가용성 점검 | 등록되지 않은 단말이 대역 전체(.1~.254)를 짧은 시간에 훑음 → 호스트 탐색 (05. 네트워크 스캔 · 공격 징후 분석 시리즈에서 다룸) |
| 특정 대상으로 Echo Request 대량 | 장애 확인 중 연속 ping (ping 기본 1초 간격) | 초당 수백~수천 개, 출발지 다수 → flood 가능성 |
| Echo 페이로드 크기·내용 | Linux 기본 56바이트, Windows 기본 32바이트의 고정 패턴 | 크기가 제각각이거나 매번 내용이 바뀜, 응답에도 다른 데이터 → 터널링 가능성 |
| Port Unreachable 다수 수신 | DNS 서버 교체 직후 등 일시적 설정 문제 | 한 호스트가 여러 UDP 포트로 보낸 뒤 대량 수신 → UDP 포트 탐색 흔적 |
| Redirect(Type 5) | 비대칭 경로 구성에서 라우터가 드물게 발생 | 게이트웨이가 아닌 호스트가 Redirect 발송 → 경로 조작 시도 가능성 |
| Fragmentation Needed(3/4) | 터널·VPN 구간에서 정상 발생, PMTUD에 필요 | 없음에 가깝지만, 이 메시지를 방화벽이 막아서 생기는 장애에 주의 |
확인용 필터 예시입니다.
# Echo 요청만 (호스트 탐색·flood 확인용)
sudo tcpdump -nn -i ens33 'icmp[icmptype] == icmp-echo'
# 목적지 도달 불가만
sudo tcpdump -nn -i ens33 'icmp[icmptype] == icmp-unreach'
# Redirect만
sudo tcpdump -nn -i ens33 'icmp[icmptype] == icmp-redirect'
# 페이로드가 큰 ICMP (IP 전체 길이 200바이트 초과)
sudo tcpdump -nn -i ens33 'icmp and ip[2:2] > 200'
ip[2:2]는 IP 헤더의 Total Length 필드(오프셋 2부터 2바이트)입니다. 크기 하나만으로 판단하지 말고 빈도·방향·내용을 함께 봐야 합니다.
흔적이 남는 곳
nstat -az | grep -i icmp로 볼 수 있지만 개별 기록은 아니므로, 판단 근거는 네트워크 쪽 로그와 패킷 캡처가 됩니다.한계와 오탐 주의