본문 바로가기
TYLER SONGBlog
← Blog index
CS8 min read

ICMP: IP 네트워크의 오류 보고와 상태 진단

인터넷 제어 메시지 프로토콜(ICMP)은 IP 패킷 전달 중 발생한 오류와 네트워크 상태를 알리는 네트워크 계층 프로토콜이다. `ping`은 에코 요청과 응답으로 도달 가능성과 왕복 시간(RTT)을 확인하고, `traceroute`는 TTL 만료 메시지로 경로를 추적한다. ICMP는 오류를 보고하지만 손실된 패킷을 직접 복구하지 않는다.

By 송민성

1. 개념

인터넷 제어 메시지 프로토콜(ICMP, Internet Control Message Protocol)은 인터넷 프로토콜(IP)의 전달 결과와 네트워크 상태를 알리는 제어 프로토콜이다.

IP는 최선형 전달(Best-effort Delivery)만 제공한다. 패킷이 목적지에 도착하지 못해도 재전송하거나 연결 상태를 관리하지 않는다. 라우터나 목적지 호스트는 전달 과정에서 문제를 발견하면 ICMP 메시지로 원래 송신자에게 상황을 알릴 수 있다.

ICMP는 전송 계층 프로토콜이 아니므로 TCP나 UDP처럼 포트 번호를 사용하지 않는다. IPv4에서는 IP 프로토콜 번호 1, IPv6에서는 다음 헤더 번호 58을 사용한다. IPv4용 ICMP와 ICMPv6는 서로 다른 프로토콜이다.

ICMP 메시지의 공통 헤더는 다음 필드로 시작한다.

필드크기역할
유형(Type)1바이트메시지 종류
코드(Code)1바이트유형 내부의 세부 원인
체크섬(Checksum)2바이트ICMP 메시지 오류 검출
유형별 데이터가변식별자, 순서 번호, 원본 패킷 정보 등

대표적인 IPv4 ICMP 유형은 다음과 같다.

유형이름용도
0에코 응답(Echo Reply)에코 요청에 대한 응답
3목적지 도달 불가(Destination Unreachable)목적지나 서비스에 전달할 수 없음
5리다이렉트(Redirect)더 적절한 다음 경로 안내
8에코 요청(Echo Request)도달 가능성 확인
11시간 초과(Time Exceeded)TTL 만료 또는 재조립 시간 초과

2. 왜 사용하는가

ICMP는 IP만으로 알 수 없는 전달 실패 원인을 송신자에게 전달한다.

  • 목적지 네트워크나 호스트에 도달할 수 없음
  • UDP 목적지 포트가 열려 있지 않음
  • 라우터에서 패킷의 TTL이 소진됨
  • 경로의 최대 전송 단위(MTU)보다 패킷이 큼
  • 호스트가 에코 요청에 응답함

대표적인 활용 도구는 ping과 traceroute다.

ping은 에코 요청(ICMP Echo Request)을 보내고 에코 응답(ICMP Echo Reply)을 기다린다. 응답 여부로 도달 가능성을 확인하고, 요청부터 응답까지 걸린 시간으로 왕복 시간(RTT, Round-Trip Time)을 측정한다.

traceroute는 작은 TTL 값부터 패킷을 반복 전송한다. 각 라우터는 패킷을 전달할 때 TTL을 1씩 줄인다. TTL이 0이 되면 해당 라우터가 시간 초과 메시지를 보내므로 경로에 있는 라우터를 순서대로 확인할 수 있다.

3. 동작 원리

에코 요청과 응답

IPv4 에코 메시지는 공통 필드 뒤에 다음 값을 포함한다.

text
유형 | 코드 | 체크섬 | 식별자 | 순서 번호 | 데이터
  8  |  0   |        |        |           |       에코 요청
  0  |  0   |        |        |           |       에코 응답

동작 순서는 다음과 같다.

  1. 송신자가 유형 8인 에코 요청을 만든다.
  2. ICMP 헤더와 데이터 전체를 대상으로 체크섬을 계산한다.
  3. 목적지 호스트가 요청을 받는다.
  4. 목적지는 식별자, 순서 번호, 데이터를 유지한 에코 응답을 만든다.
  5. 송신자는 식별자와 순서 번호를 비교해 요청과 응답을 연결한다.
  6. 전송 시각과 수신 시각의 차이로 왕복 시간을 구한다.

ICMP 체크섬은 메시지를 16비트 단위로 더한 뒤 발생한 올림을 다시 더하고, 결과의 1의 보수를 취해 계산한다.

TTL 만료

TTL(Time To Live)은 IPv4 패킷이 통과할 수 있는 라우터 수를 제한하는 8비트 필드다.

text
송신자 ── TTL 3 ──> 라우터 A
                     TTL 2
                       │
                       ▼
                   라우터 B
                     TTL 1
                       │
                       ▼
                   라우터 C
                     TTL 0
                       │
                       └── ICMP 시간 초과 ──> 송신자

TTL이 0이 된 라우터는 패킷을 폐기하고 일반적으로 ICMP 시간 초과 메시지를 원래 송신자에게 보낸다. traceroute는 이 동작을 이용한다.

목적지 도달 불가

라우터나 목적지 호스트가 패킷을 전달할 수 없으면 목적지 도달 불가 메시지를 보낼 수 있다. 유형은 같아도 코드에 따라 원인이 달라진다.

예를 들어 IPv4 ICMP 유형 3, 코드 3은 목적지 UDP 포트에 수신 중인 애플리케이션이 없음을 뜻한다. 유형 3, 코드 4는 단편화 금지(DF) 상태에서 다음 링크의 MTU보다 패킷이 커서 전달할 수 없음을 뜻한다.

4. 코드 예제

다음 코드는 Linux에서 ICMP 에코 요청을 직접 생성하고 응답의 왕복 시간을 측정한다. 원시 소켓(Raw Socket)을 사용하므로 root 권한이나 CAP_NET_RAW 권한이 필요하다.

python
import os import socket import struct import time ICMP_ECHO_REPLY = 0 ICMP_ECHO_REQUEST = 8 def calculate_checksum(data: bytes) -> int: if len(data) % 2: data += b"\x00" total = 0 for offset in range(0, len(data), 2): word = (data[offset] << 8) + data[offset + 1] total += word total = (total & 0xFFFF) + (total >> 16) return (~total) & 0xFFFF def create_echo_request(identifier: int, sequence: int) -> bytes: payload = struct.pack("!d", time.monotonic()) + b"icmp-example" empty_header = struct.pack( "!BBHHH", ICMP_ECHO_REQUEST, 0, 0, identifier, sequence, ) checksum = calculate_checksum(empty_header + payload) header = struct.pack( "!BBHHH", ICMP_ECHO_REQUEST, 0, checksum, identifier, sequence, ) return header + payload def ping(host: str, timeout: float = 2.0) -> None: destination_ip = socket.gethostbyname(host) identifier = os.getpid() & 0xFFFF sequence = 1 packet = create_echo_request(identifier, sequence) with socket.socket( socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP, ) as sock: sock.settimeout(timeout) started_at = time.monotonic() sock.sendto(packet, (destination_ip, 0)) while True: received_packet, sender = sock.recvfrom(65535) received_at = time.monotonic() version_and_ihl = received_packet[0] ihl = version_and_ihl & 0x0F ip_header_length = ihl * 4 icmp_packet = received_packet[ip_header_length:] if len(icmp_packet) < 8: continue ( message_type, code, _checksum, reply_identifier, reply_sequence, ) = struct.unpack("!BBHHH", icmp_packet[:8]) if calculate_checksum(icmp_packet) != 0: continue if ( message_type == ICMP_ECHO_REPLY and code == 0 and reply_identifier == identifier and reply_sequence == sequence ): rtt_ms = (received_at - started_at) * 1000 print( f"{host} ({sender[0]}) 응답: " f"순서={reply_sequence}, 왕복 시간={rtt_ms:.3f} ms" ) return if __name__ == "__main__": try: ping("1.1.1.1") except PermissionError: print("원시 소켓 권한이 필요합니다.") except socket.timeout: print("제한 시간 안에 ICMP 응답을 받지 못했습니다.") except socket.gaierror as error: print(f"이름 해석 실패: {error}")

Linux에서 실행한다.

shell
sudo python3 icmp_ping.py

운영체제의 ping 명령으로 확인할 때는 다음처럼 실행한다.

shell
ping -c 4 1.1.1.1

출력의 패킷 손실률은 응답을 받지 못한 요청의 비율이고, time 또는 rtt 값은 왕복 시간이다.

5. 시간 복잡도 또는 성능 특성

ICMP 자체는 알고리즘처럼 입력 크기에 따른 실행 시간을 분석하는 대상이 아니다. 메시지 처리 비용과 네트워크 측정 특성을 구분해야 한다.

  • 체크섬 계산은 ICMP 메시지 길이를 n바이트라고 할 때 시간복잡도 O(n), 추가 공간복잡도 O(1)이다.
  • 에코 요청 한 건은 요청 패킷 1개와 응답 패킷 1개를 사용한다. 손실이나 재시도는 제외한다.
  • 왕복 시간은 송신자에서 목적지까지의 전달 시간과 돌아오는 전달 시간을 합친 값이다. 편도 지연 시간의 정확한 두 배로 볼 수 없다. 왕복 경로가 서로 다를 수 있기 때문이다.
  • traceroute는 최대 홉 수를 h, 홉마다 보내는 탐사 패킷 수를 p라고 할 때 최대 h × p개의 탐사 패킷을 전송한다.
  • ICMP 메시지 크기가 커지면 전송량과 체크섬 계산량도 증가하지만, 실제 지연은 경로 길이, 혼잡, 큐잉, 라우터 정책의 영향을 더 크게 받는다.

라우터는 데이터 전달을 우선하기 위해 ICMP 생성이나 응답에 속도 제한(Rate Limiting)을 적용할 수 있다. 높은 ICMP 지연이나 손실이 실제 애플리케이션 트래픽의 동일한 지연이나 손실을 뜻하지는 않는다.

6. 실무 사용 사례

서버 도달 가능성 확인

shell
ping -c 4 api.example.com

DNS 이름 해석과 IP 수준의 왕복 응답을 함께 확인한다. 응답이 없다고 서버 장애로 단정할 수는 없다. 방화벽이 ICMP만 차단했을 수 있다.

네트워크 경로 추적

shell
traceroute api.example.com

경로 중 어느 구간부터 응답이 사라지거나 지연이 증가하는지 확인한다. 일부 라우터는 시간 초과 메시지를 보내지 않으므로 *가 표시되어도 이후 경로가 정상일 수 있다.

경로 MTU 발견

경로 MTU 발견(PMTUD, Path MTU Discovery)은 목적지까지 단편화 없이 전달할 수 있는 최대 패킷 크기를 찾는다.

IPv4에서는 단편화 금지(DF) 비트를 설정한 패킷이 링크 MTU보다 클 때 반환되는 ICMP 목적지 도달 불가 메시지를 이용한다. ICMP가 차단되면 송신자가 패킷 크기를 줄이지 못해 연결이 멈추는 PMTU 블랙홀(Black Hole)이 발생할 수 있다.

IPv6에서는 라우터가 패킷을 단편화하지 않는다. 패킷이 링크 MTU보다 크면 ICMPv6 패킷 너무 큼(Packet Too Big) 메시지가 경로 MTU 발견에 사용된다.

UDP 서비스 상태 확인

닫힌 UDP 포트로 데이터그램을 보내면 목적지 호스트가 ICMP 포트 도달 불가 메시지를 반환할 수 있다. UDP 기반 traceroute와 일부 네트워크 진단 도구가 이 특성을 이용한다.

7. 주의할 점

  • ping 성공은 대상 호스트가 ICMP 에코에 응답했다는 뜻이다. HTTP, 데이터베이스 같은 애플리케이션 서비스의 정상 동작을 보장하지 않는다.
  • ping 실패는 대상 호스트가 꺼졌다는 뜻이 아니다. 방화벽, 보안 그룹, 라우터가 ICMP 요청이나 응답을 차단할 수 있다.
  • ICMP 전체를 차단하면 오류 보고와 경로 MTU 발견까지 방해할 수 있다. 필요한 유형과 코드만 정책적으로 허용해야 한다.
  • ICMP 오류 메시지에는 문제를 일으킨 원본 IP 패킷 일부가 포함된다. 네트워크 주소 변환(NAT)과 방화벽은 이 내부 정보를 함께 해석해야 연결 상태를 정확히 처리할 수 있다.
  • 출발지 IP 주소는 위조될 수 있다. ICMP 응답만으로 송신자의 신원을 인증할 수 없다.
  • ICMP 플러드(Flood) 공격은 대량의 요청으로 네트워크와 호스트 자원을 소모시킨다. 속도 제한과 방화벽 정책으로 완화한다.
  • ICMP 오류 메시지 자체에 다시 ICMP 오류 메시지를 생성하지 않는다. 오류 메시지가 연쇄적으로 발생하는 상황을 막기 위한 규칙이다.

8. 핵심 정리

  • ICMP는 IP 패킷 전달 오류와 네트워크 상태를 알리는 네트워크 계층 프로토콜이다.
  • ICMP는 포트 번호 대신 유형(Type)과 코드(Code)로 메시지 목적을 구분한다.
  • ping은 에코 요청과 응답으로 도달 가능성과 왕복 시간을 측정한다.
  • traceroute는 TTL 만료와 ICMP 시간 초과 메시지를 이용해 경로를 추적한다.
  • ICMP는 문제를 보고하지만 손실된 패킷을 복구하거나 재전송하지 않는다.
  • 무조건적인 ICMP 차단은 경로 MTU 발견과 장애 진단을 방해할 수 있다.