한양과학기술고등학교

에듀테크 프로젝트 대시보드

traceroute와 TTL (ICMP)

트레이스라우트 & TTL

"내 컴퓨터에서 offset0xf.com 까지 패킷은 어떤 라우터들을 거쳐 갈까?" — 인터넷은 수많은 라우터가 릴레이로 패킷을 넘겨 목적지에 보낸다. traceroute(윈도우는 tracert)는 이 경로를 한 홉씩 불 켜 가며 보여 준다. 비결은 IP 헤더의 작은 숫자 필드 하나, TTL이다.

한 줄 요약: "몇 정거장만 가세요" 라벨(=TTL)을 붙인 택배를 1정거장, 2정거장, 3정거장… 늘려 가며 계속 보낸다. 라벨이 0이 된 정거장(라우터)이 "여기서 폐기했음" 이라고 반송하는데, 그 반송인 주소를 모으면 전체 경로가 된다.

1. TTL — 패킷의 유통기한

모든 IPv4 패킷 헤더에는 TTL(Time To Live) 8비트 필드가 있다(IPv6에서는 이름이 Hop Limit). 원래 목적은 라우팅 루프에 빠진 패킷이 인터넷을 영원히 떠돌지 못하게 하는 안전장치다.

traceroute는 이 "0이 되면 반송" 규칙을 역이용한다. TTL=1짜리 패킷을 보내면 첫 번째 라우터가 반송한다 → 1번 홉의 IP를 알아냄. TTL=2면 두 번째 라우터가 반송 → 2번 홉. 이렇게 TTL을 1씩 키우며 목적지에 닿을 때까지 반복한다.

목적지 호스트는 TTL이 0이 아니어도 패킷을 받는다. 그래서 마지막에는 "시간 초과"가 아니라 다른 응답이 온다 — 전통적 유닉스 traceroute는 안 쓰는 UDP 포트로 보내 ICMP "포트 도달 불가"(Type 3)를 받고, tracert는 ICMP Echo를 보내 Echo Reply를 받는다. 어느 쪽이든 "도착했다"는 신호다.

2. 직접 돌려 보기

「다음 홉 보내기」를 누르면 현재 TTL 값으로 프로브(작은 노란 상자)를 쏜다. 각 라우터를 지날 때 TTL이 줄고, 0이 되는 라우터가 빨갛게 불이 들어오며 반송 패킷을 되돌려 보낸다. 그 왕복 시간(RTT)을 3번 측정해 아래 표에 기록한다.

1
보낼 TTL 1
확인한 홉 0
상태 대기
홉라우터 이름IP 주소RTT 1RTT 2RTT 3
「다음 홉 보내기」로 TTL=1 프로브부터 시작하세요.
위 시뮬레이션의 4번 홉("백본 A")은 일부러 응답을 안 하도록 만들었다 — 실제로도 흔히 보는 * * * 다. 라우터가 ICMP를 보안상 막았거나, "제어 평면"(CPU)이 바빠서 ICMP 생성을 낮은 우선순위로 미루기(rate-limit) 때문이다. 그 홉을 못 봐도 그다음 홉은 정상적으로 보인다 — 경로가 끊긴 게 아니다.

3. 코드로 보면

핵심은 소켓에 TTL을 직접 지정하고, 돌아오는 ICMP를 raw 소켓으로 받는 것이다(로우 소켓은 보통 관리자 권한 필요). 개념만 추리면:

import socket, time

def traceroute(dest_ip, max_hops=30, probes=3):
    port = 33434                       # 유닉스 traceroute 관례 포트
    for ttl in range(1, max_hops + 1):
        for _ in range(probes):
            recv = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
            send = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
            send.setsockopt(socket.IPPROTO_IP, socket.IP_TTL, ttl)   # ← 여기가 전부
            recv.settimeout(2.0)

            t0 = time.time()
            send.sendto(b'', (dest_ip, port))
            try:
                _, (router_ip, _) = recv.recvfrom(512)
                rtt = (time.time() - t0) * 1000
                print(f'{ttl}\t{router_ip}\t{rtt:.1f} ms')
            except socket.timeout:
                print(f'{ttl}\t*')          # 응답 없음
            finally:
                send.close(); recv.close()

            if router_ip == dest_ip:      # 목적지가 답했다 → 끝
                return

실제 도구는 여기에 ICMP 타입 구분(11=시간 초과 / 3=포트 불가), 역방향 DNS 조회, 병렬 프로브 전송 등을 더한다.

4. traceroute를 읽을 때 조심할 것

RTT가 중간에 튀는 건 정상

표시된 시간은 그 홉까지 왕복 시간이다. 중간 라우터의 "ICMP 만들어 답하기"는 후순위 작업이라, 중간 홉이 목적지보다 느리게 찍히기도 한다. 뒤 홉이 더 빠르면 그 앞 숫자는 무시해도 된다.

경로는 매번 다를 수 있다

ISP는 여러 동등 경로에 트래픽을 나눈다(ECMP 로드 밸런싱). 그래서 홉마다 다른 물리 경로를 탈 수 있고, 두 번 실행하면 중간 라우터가 바뀌기도 한다.

왕복 경로는 비대칭

돌아오는 ICMP는 가던 길과 다른 경로로 올 수 있다. traceroute는 가는 길만 보여 준다고 생각하는 게 안전하다.

* * * = 경로 끊김 아님

방화벽/rate-limit로 ICMP만 막혔을 뿐, 그 뒤 홉이 보이면 트래픽은 잘 지나간 것이다. 마지막 홉부터 계속 * 면 그때 의심한다.

5. ping 과 무엇이 다른가

 pingtraceroute
보는 것목적지까지 연결 여부·지연·손실목적지까지의 경로(홉 목록)
사용하는 메시지ICMP Echo / Echo ReplyTTL을 1씩 늘린 프로브 + ICMP 시간 초과
TTL넉넉히(64 등) 고정1, 2, 3, … 로 의도적으로 증가
한 줄 정의"거기 살아 있어?""거기까지 어떻게 가?"