traceroute
고친 사람 github-actions[bot]
traceroute 는 내 컴퓨터에서 상대 서버까지 패킷이 어떤 라우터들을 거쳐 가는지 보여 주는 명령입니다. 거쳐 간 라우터를 차례대로 한 줄씩 찍습니다. 줄마다 거기까지 다녀오는 데 걸린 시간도 함께 적습니다. 연결이 끊기거나 늦어질 때 어느 구간에서 그런지 짚는 데 씁니다.
쉽고 빠른 이해
traceroute 는 목적지까지 가는 길에 선 라우터를 하나씩 불러내는 명령입니다. traceroute example.com 이라고 치면 첫째 라우터, 둘째 라우터 하는 식으로 주소가 한 줄씩 찍힙니다.
서버에 안 닿을 때 끝에서 끝까지만 재면 어디가 문제인지 모릅니다. 길 중간의 라우터를 하나씩 보면 문제 구간을 좁힐 수 있습니다.
- 패킷에 「첫째 라우터에서 버려라」라고 적어 보냅니다
- 첫째 라우터가 그 패킷을 버리고 「버렸다」는 알림을 돌려보냅니다. 알림을 보낸 주소가 첫째 라우터입니다
- 「둘째 라우터에서 버려라」, 「셋째 라우터에서 버려라」로 한 칸씩 늘려 가며 목적지가 답할 때까지 되풀이합니다
대가가 있습니다. 알림을 안 보내는 라우터는 주소 대신 별표로만 찍힙니다. 보이는 것도 가는 길뿐이라 돌아오는 길은 모릅니다.
상세
traceroute 는 목적지 주소를 받아, 거기까지 가는 동안 패킷을 넘겨준 라우터의 주소를 차례로 알려 주는 명령입니다. 한 라우터에서 다음 라우터로 넘어가는 한 걸음을 홉이라 부릅니다. 출력의 줄 하나가 홉 하나입니다.
백엔드 개발자가 이 명령을 꺼내는 때는 대개 「서버에 붙지 않는다」나 「어느 날부터 응답이 늦다」를 들었을 때입니다. 그럴 때 먼저 치는 ping 은 상대까지 닿는지와 왕복 시간만 알려 줍니다. 왕복 시간은 보낸 패킷의 답이 돌아오기까지 걸린 시간입니다.
ping 의 값은 끝에서 끝까지 잰 값 하나입니다. 문제가 내 회사 망에 있는지, 중간의 통신사 망에 있는지, 상대 쪽 망에 있는지는 이 값만으로 알 수 없습니다. traceroute 는 길 중간을 한 칸씩 보여 주므로 문제 구간을 좁힐 수 있습니다.
리눅스와 맥에서는 traceroute, 윈도에서는 tracert 라는 이름으로 같은 일을 합니다. 두 명령은 길을 알아내는 원리가 같습니다. 보내는 패킷의 종류만 다릅니다.
아래에서는 먼저 이 명령이 길을 알아내는 원리를 봅니다. 그다음 출력의 줄을 읽는 법과, 읽다가 흔히 헷갈리는 별표와 튀는 시간을 차례로 봅니다.
TTL 을 하나씩 늘려 보내는 방법
인터넷에서 오가는 패킷은 IP(Internet Protocol, 인터넷 프로토콜)라는 규칙을 따릅니다. IP 패킷 앞머리에는 주소 같은 정보를 담는 헤더가 붙습니다. traceroute 가 기대는 것은 이 헤더의 칸 하나입니다. 그 칸의 이름이 TTL(Time To Live, 생존 시간)입니다.
TTL 은 패킷이 최대 몇 번째 라우터까지 갈 수 있는지 정하는 수입니다. 라우터는 패킷을 받을 때마다 이 수를 1 줄입니다. 0 이 되면 그 라우터는 패킷을 넘기지 않고 버립니다. 그래서 TTL 이 1 인 패킷은 첫째 라우터에서 버려집니다.
TTL 은 길이 꼬였을 때를 대비해 둔 칸입니다. 라우터들이 가진 경로 정보가 서로 어긋나면 패킷이 라우터 사이를 끝없이 맴돌 수 있습니다. TTL 이 다 닳으면 그 패킷은 버려집니다. 덕분에 망이 맴도는 패킷으로 차지 않습니다.
패킷을 버린 라우터는 보낸 쪽에 알림을 돌려보냅니다. 이 알림은 ICMP(Internet Control Message Protocol, 인터넷 제어 메시지 프로토콜)의 메시지입니다. ICMP 는 망에서 생긴 문제를 보낸 쪽에 알리는 프로토콜입니다. TTL 이 다 닳았다는 메시지의 이름은 시간 초과(Time Exceeded)입니다.
시간 초과 알림의 출발 주소는 패킷을 버린 라우터의 주소입니다. traceroute 는 이 주소로 거쳐 간 라우터를 알아냅니다.
길을 알아보려고 보내는 패킷을 탐침(probe)이라 부릅니다. traceroute 는 탐침의 TTL 을 1 부터 하나씩 늘려 보냅니다. TTL 을 1 로 둔 탐침은 첫째 라우터가 버립니다. TTL 을 2 로 둔 탐침은 둘째 라우터가 버립니다.
탐침마다 돌아온 알림의 출발 주소를 차례로 늘어놓으면 목적지까지 가는 길이 됩니다. 아래 그림은 라우터 둘을 지나 목적지에 닿는 길입니다.
sequenceDiagram
participant 나 as 내 컴퓨터
participant 라우터1
participant 라우터2
participant 목적지
나->>라우터1: 탐침 · TTL 1
Note over 라우터1: TTL 0 이 되어 버린다
라우터1-->>나: 시간 초과 · 출발 주소 = 라우터1
나->>라우터2: 탐침 · TTL 2 · 라우터1 을 지나며 1 이 된다
Note over 라우터2: TTL 0 이 되어 버린다
라우터2-->>나: 시간 초과 · 출발 주소 = 라우터2
나->>목적지: 탐침 · TTL 3 · 라우터1·2 를 지나며 1 이 된다
목적지-->>나: 목적지의 알림 · 여기서 멈춘다
IPv6(Internet Protocol version 6, 인터넷 프로토콜 6판)에서는 같은 칸을 홉 제한이라고 부릅니다. 이름만 다를 뿐 하는 일은 같습니다. traceroute 도 IPv6 에서 같은 원리로 동작합니다.
목적지에 닿았는지 아는 방법
목적지 자신이 탐침을 받으면 시간 초과 알림은 오지 않습니다. 목적지는 패킷을 넘기지 않고 받아들이기 때문입니다. 그래서 traceroute 는 목적지가 시간 초과와는 다른 알림을 돌려보내게 만드는 탐침을 보냅니다. 그 알림이 오면 끝에 닿았다고 보고 멈춥니다.
리눅스와 맥의 traceroute 는 UDP(User Datagram Protocol, 사용자 데이터그램 프로토콜) 패킷을 탐침으로 보냅니다. 받는 쪽 포트 번호는 서버에서 쓰일 일이 없는 높은 번호로 고릅니다.
그 포트를 연 프로그램이 없으니 목적지는 포트 도달 불가(Port Unreachable) 알림을 돌려보냅니다. 이것도 ICMP 메시지입니다. traceroute 에게는 이 알림이 「끝에 닿았다」는 신호입니다.
윈도의 tracert 는 UDP 대신 ICMP 에코 요청을 탐침으로 보냅니다. ping 이 쓰는 것과 같은 메시지입니다. 목적지는 에코 응답이라는 알림을 돌려보냅니다. tracert 는 이 알림을 보고 멈춥니다.
두 방식을 나란히 놓으면 이렇습니다. 중간 라우터의 알림은 같습니다. 목적지의 알림만 다릅니다.
| 보내는 탐침 | 중간 라우터가 돌려보내는 알림 | 목적지가 돌려보내는 알림 | |
|---|---|---|---|
| 리눅스·맥의 traceroute | UDP · 쓰이지 않는 포트 | 시간 초과 | 포트 도달 불가 |
| 윈도의 tracert | ICMP 에코 요청 | 시간 초과 | 에코 응답 |
출력 한 줄을 읽는 법
출력은 아래 모양입니다. 주소를 이름으로 바꿔 함께 적는 구현도 있습니다. 이 예에서는 주소만 남겼습니다.
$ traceroute example.com
1 192.0.2.1 0.5 ms 0.4 ms 0.4 ms
2 198.51.100.1 3.1 ms 2.9 ms 3.0 ms
3 * * *
4 198.51.100.9 3.4 ms 3.6 ms 3.5 ms
5 203.0.113.9 12.4 ms 12.1 ms 12.6 ms
6 203.0.113.80 12.9 ms 12.7 ms 13.0 ms
맨 앞의 숫자는 홉 번호입니다. 그 줄을 만든 탐침의 TTL 과 같습니다. 그 뒤는 알림을 보낸 라우터의 주소입니다.
뒤에 붙은 시간 셋은 같은 TTL 로 탐침을 보통 세 번 보내 각각 잰 왕복 시간입니다. 탐침을 떠나보낸 때부터 알림이 돌아온 때까지를 잽니다. 한 번만 재면 우연히 튄 값인지 알 수 없어서 여러 번 잽니다.
맨 마지막 줄이 목적지입니다. 위 예에서는 다섯째 줄에서 시간이 크게 뜁니다. 여섯째 줄에서도 높게 이어집니다. 뛴 값이 끝까지 이어지면 넷째 줄과 다섯째 줄 사이 구간에서 시간이 든다고 봅니다. 바다를 건너는 회선이나 붐비는 구간이 그렇습니다.
별표가 찍힌 줄
* * * 는 기다리는 시간 안에 알림이 안 왔다는 뜻입니다. 탐침 세 번이 모두 알림을 못 받으면 별표가 셋 찍힙니다.
별표가 곧 고장은 아닙니다. 라우터는 시간 초과 알림을 아예 안 보내도록 설정되기도 합니다. 보내는 개수를 제한하기도 합니다. 그런 라우터도 패킷은 멀쩡히 넘깁니다. 그래도 traceroute 에는 별표로만 나옵니다.
가르는 방법은 뒷줄을 보는 것입니다. 위 예처럼 별표 뒤에 다시 주소가 찍히면 탐침은 그 라우터를 지나갔습니다. 그 라우터는 알림만 안 보냈습니다.
별표가 목적지까지 끝없이 이어지면 두 경우가 남습니다. 목적지에 ping 이 닿는다면 방화벽이 탐침이나 그 알림만 버리고 있습니다. ping 도 안 닿는다면 별표가 시작된 근처에서 패킷이 막혔을 가능성이 큽니다.
flowchart TD
A["별표가 찍힌 줄"] --> B{"뒷줄에 주소가 다시 찍히나"}
B -->|"찍힌다"| C["그 라우터가 알림만 안 보냈다 · 탐침은 지나갔다"]
B -->|"끝까지 별표"| D{"목적지에 ping 이 닿나"}
D -->|"닿는다"| E["방화벽이 탐침이나 그 알림만 버린다"]
D -->|"안 닿는다"| F["별표가 시작된 근처에서 막혔다"]
중간 한 줄만 시간이 튈 때
어느 한 줄의 시간만 유독 높고 그 뒷줄은 다시 낮아지는 출력도 자주 나옵니다. 이것도 대개 문제가 아닙니다. 그 라우터가 알림을 늦게 만들었을 뿐입니다. 그 라우터를 지나가는 패킷은 늦어지지 않았습니다.
라우터 안에서 패킷을 넘기는 일과 알림을 만드는 일은 따로 처리됩니다. 넘기는 일은 대개 그 일만 하는 하드웨어가 곧바로 합니다. 알림을 만드는 일은 라우터의 일반 처리기가 짬이 날 때 합니다. 알림이 늦게 온다고 해서 패킷을 넘기는 일까지 늦은 것은 아닙니다.
그래서 볼 것은 한 줄이 아니라 뒤로 이어지는 흐름입니다. 어느 줄에서 뛴 시간이 목적지까지 계속 높게 이어질 때라야 그 구간에서 패킷이 늦어진다고 봅니다.
출력이 보여 주지 않는 길
traceroute 의 출력은 길을 다 보여 주지 않습니다. 이 소절은 출력에 안 나오는 길 둘을 봅니다. 하나는 돌아오는 길입니다. 다른 하나는 여러 갈래로 나뉜 길입니다.
traceroute 가 보여 주는 것은 내 쪽에서 목적지로 가는 길입니다. 인터넷에서는 가는 길과 돌아오는 길이 다를 수 있습니다. 가는 길과 돌아오는 길이 다른 것을 비대칭 라우팅이라 합니다.
줄마다 찍힌 왕복 시간에는 화면에 안 나온 돌아오는 길의 시간도 섞여 있습니다. 돌아오는 길을 보려면 상대 쪽에서 내 쪽으로 traceroute 를 돌려야 합니다.
라우터는 한 갈래에 트래픽이 몰리지 않게 여러 경로로 나눠 보내기도 합니다. 이를 부하 분산이라 합니다. 부하 분산을 하는 망에서는 탐침마다 다른 길을 탈 수 있습니다. 그래서 같은 홉 번호에 주소가 둘 이상 찍히기도 합니다.
출력의 줄을 이으면 실제로 없는 길이 그려지기도 합니다. 라우터1 이 뒤쪽을 라우터A→라우터C 와 라우터B→라우터D 두 갈래로 나눠 보낸다고 합시다. TTL 2 탐침이 A 쪽으로 가면 출력의 둘째 줄은 라우터A 입니다. TTL 3 탐침이 B 쪽으로 가면 셋째 줄은 라우터D 입니다.
둘째 줄과 셋째 줄을 이으면 라우터A 다음이 라우터D 인 길이 됩니다. 그런 연결은 망에 없습니다.
flowchart TD
ME["내 컴퓨터"] --> R1["라우터1"]
R1 -->|"TTL 2 탐침"| RA["라우터A · 출력의 둘째 줄"]
R1 -->|"TTL 3 탐침"| RB["라우터B"]
RA --> RC["라우터C"]
RB --> RD["라우터D · 출력의 셋째 줄"]
RC --> DST["목적지"]
RD --> DST
RA -.->|"두 줄을 이으면 생기는 길 · 실제로는 없다"| RD
탐침이 막히는 망
회사 방화벽이나 클라우드의 보안 설정은 흔히 쓰이지 않는 UDP 포트나 ICMP 를 막아 둡니다. 그러면 탐침이 중간에 버려져 별표만 이어집니다.
이때는 탐침을 TCP(Transmission Control Protocol, 전송 제어 프로토콜) 연결 요청으로 바꿔 보내는 방법이 있습니다. 목적지가 실제로 열어 둔 포트로 보내면 방화벽이 통과시킵니다. 웹 서버라면 대개 443 번 포트가 열려 있습니다. 많은 traceroute 구현이 이 방식을 옵션으로 둡니다.
TTL 을 늘려 가며 중간 라우터의 시간 초과 알림을 모으는 원리는 같습니다. 다른 것은 목적지에 닿았을 때입니다. 목적지는 포트가 열려 있으면 연결을 받아 주는 응답을, 닫혀 있으면 거절하는 응답을 돌려보냅니다. traceroute 는 어느 쪽이든 이 응답을 보고 멈춥니다.
ping · mtr 과 나눠 맡는 일
비슷한 진단 명령이 둘 더 있습니다. 무엇을 알려 주는지로 가르면 아래와 같습니다.
| 명령 | 알려 주는 것 | 보내는 방식 |
|---|---|---|
| ping | 목적지까지 닿는지 · 끝에서 끝까지의 왕복 시간 | 에코 요청을 되풀이한다 |
| traceroute | 거쳐 가는 라우터 · 각 라우터까지의 왕복 시간 | TTL 을 늘려 가며 한 차례 돈다 |
| mtr | 홉마다의 [[패킷 손실 | 손실]]과 시간 변화 |
traceroute 는 한 차례 돌고 끝나므로 잠깐 생겼다 사라지는 손실을 놓치기 쉽습니다. 끊겼다 붙었다 하는 문제를 볼 때 mtr 로 오래 지켜보는 까닭입니다.
관련 항목
traceroute 가 기대는 프로토콜과 헤더 칸
ICMP · TTL · 홉 제한 · IP · IPv6 · UDP · TCP · 헤더
traceroute 가 받아 보는 알림 메시지
Time Exceeded · 포트 도달 불가 · Destination Unreachable · 에코 요청 · 에코 응답
traceroute 와 나란히 쓰는 진단 명령
ping · mtr · tracepath · tcpdump · Wireshark · netstat · dig
traceroute 가 찍어 보이는 경로의 구성 요소
라우터 · 홉 · 다음 홉 · 기본 게이트웨이 · 라우팅 · 라우팅 테이블
traceroute 출력으로 재는 지표
traceroute 결과를 흐리는 망의 성질
비대칭 라우팅 · 부하 분산 · ECMP · ICMP 속도 제한 · 방화벽 · 제어 평면
TTL 과 패킷 크기로 다루는 경로 문제와 해법
다른 이름: traceroute 명령 · tracert · 경로 추적