터널링
고친 사람 github-actions[bot]
터널링은 한 망의 데이터 덩이를 다른 망의 덩이 속에 넣어서 원래는 못 지나가는 망을 건너가게 합니다. 떨어진 두 사무실의 사내망을 인터넷 너머로 잇는 일이 대표적입니다. 게임에서 빨리 움직이는 물체가 벽을 뚫고 지나가는 현상도 같은 이름으로 부릅니다. 이 항목은 네트워크의 뜻을 중심으로 다룹니다.
쉽고 빠른 이해
터널링은 보낼 데이터 덩이를 다른 덩이 속에 넣어 나르는 일입니다. 서울 사무실에서 부산 사무실의 사내 주소로 보낸 덩이를, 인터넷에서 통하는 덩이에 넣어 부산까지 보내는 것이 그렇습니다.
사내 주소는 인터넷의 장비들이 모릅니다. 감싸지 않고 내보내면 길을 못 찾고 버려집니다.
- 입구 장비가 덩이를 속에 넣고 겉에 인터넷에서 통하는 주소를 적습니다
- 인터넷의 장비들은 겉 주소만 보고 출구 장비까지 나릅니다
- 출구 장비가 겉을 벗기고 속 덩이를 사내망에 풀어놓습니다
대가는 크기입니다. 겉을 한 겹 더 붙이는 만큼 한 번에 실을 수 있는 양이 줄어듭니다. 크기를 못 맞추면 짧은 요청은 오가도 큰 응답만 멈추는 고장이 납니다.
상세
이 절은 터널링이 무엇을 싸서 어디로 나르는지를 다룹니다. 서울과 부산 두 사무실의 사내망을 인터넷 너머로 잇는 예를 줄곧 씁니다.
섬으로 가는 차를 떠올리면 가깝습니다. 차는 바다 앞에서 배에 실려 건넙니다. 건너편 항구에 닿으면 배에서 내려 다시 도로를 달립니다. 배는 실린 차가 어디로 갈지 몰라도 항구까지 나릅니다.
네트워크로 보내는 데이터는 덩이로 잘려서 나갑니다. 이 덩이가 패킷입니다. 웹 요청 하나도 패킷 여러 개로 나뉘어 상대에게 갑니다.
패킷 앞머리에는 어디서 와서 어디로 가는지를 적은 안내 정보가 붙습니다. 이 안내 정보가 헤더입니다. 헤더 뒤에 실려 가는 본문은 페이로드입니다.
터널링은 패킷 하나를 다른 패킷의 페이로드에 넣어 나르는 일입니다. 서울 서버가 부산 서버에 보낸 패킷이 인터넷용 패킷 속에 들어가 부산까지 가는 것이 그 예입니다.
안에 든 패킷을 내부 패킷(inner packet), 감싼 패킷을 외부 패킷(outer packet)이라고 합니다. 두 패킷의 헤더도 같은 식으로 내부 헤더와 외부 헤더라고 합니다. 앞의 비유에서 차가 내부 패킷입니다. 배는 외부 패킷입니다.
사내 주소가 인터넷을 못 건너는 까닭
서울 서버가 부산 서버로 패킷을 그냥 보내면 어디서 막힐까요. 이 소절은 그 길을 따라가며 터널이 필요한 까닭을 찾습니다.
인터넷에서 패킷에 주소를 붙여 나르는 규칙이 IP(Internet Protocol, 인터넷 프로토콜)입니다. 패킷의 헤더에 적히는 출발지와 목적지가 IP 주소입니다.
패킷이 갈 길을 고르는 장비는 라우터입니다. 라우터는 헤더의 목적지 주소를 보고 다음에 넘길 장비를 정합니다. 목적지로 가는 길을 모르면 그 패킷을 버립니다.
사무실 안에서는 대개 사설 IP 주소를 씁니다. 사내망 안에서만 쓰기로 따로 떼어 둔 주소입니다. 10 으로 시작하는 주소가 그렇습니다.
사설 주소는 수많은 회사가 겹쳐 씁니다. 그래서 인터넷의 라우터는 사설 주소로 가는 길을 모릅니다. 서울 서버가 부산 서버의 사설 주소로 패킷을 내보내면 인터넷에 들어서자마자 버려집니다.
터널링은 이 패킷을 외부 패킷에 넣어서 풉니다. 외부 헤더에는 인터넷 어디서나 길이 통하는 주소를 적습니다. 이런 주소가 공인 IP 주소입니다.
주소 체계가 달라서 못 건너는 경우도 있습니다. 먼저 나와 지금도 널리 쓰는 주소 체계가 IPv4(Internet Protocol version 4, 인터넷 프로토콜 4판)입니다.
그 뒤를 잇는 새 체계가 IPv6(Internet Protocol version 6, 인터넷 프로토콜 6판)입니다. IPv6 패킷은 IPv4 만 아는 구간을 지나지 못합니다. 이때도 IPv6 패킷을 IPv4 패킷에 넣어 그 구간을 건너보냅니다.
패킷 하나가 터널을 지나는 순서
서울 서버가 보낸 패킷 하나를 따라가 봅시다. 헤더 두 벌이 어디서 붙고 어디서 떨어지는지가 초점입니다. 터널의 양 끝에는 감싸고 벗기는 장비가 하나씩 섭니다. 이 둘을 입구와 출구라고 합니다.
먼저 헤더 두 벌에 적히는 주소를 표로 봅니다. 주소 값은 설명용으로 고른 것입니다.
| 헤더 | 출발지 | 목적지 |
|---|---|---|
| 내부 헤더 | 10.1.0.5 · 서울 서버 | 10.2.0.7 · 부산 서버 |
| 외부 헤더 | 203.0.113.1 · 서울 입구 | 198.51.100.1 · 부산 출구 |
내부 헤더에는 사설 주소가 적혔습니다. 외부 헤더에는 공인 주소가 적혔습니다. 인터넷 구간의 라우터가 읽는 것은 아래 줄뿐입니다. 위 줄은 외부 패킷의 페이로드 안에 들어 있어서 라우터에게는 뜻 모를 바이트입니다.
패킷 하나는 네 단계를 거칩니다.
- 서울 서버가 부산 서버의 사설 주소로 패킷을 보냅니다. 이 패킷은 서울 입구로 갑니다
- 입구가 이 패킷을 외부 패킷의 페이로드에 넣고 외부 헤더를 붙입니다
- 인터넷의 라우터들이 외부 헤더만 보고 부산 출구까지 나릅니다
- 출구가 외부 헤더를 떼어 냅니다. 남은 내부 패킷을 부산 사내망에 내보내면 부산 서버에 닿습니다
네 단계 가운데 외부 헤더가 붙어 있는 구간은 입구와 출구 사이뿐입니다. 아래 그림은 그 구간을 따로 표시했습니다.
sequenceDiagram
participant 서울서버 as 서울 서버
participant 입구 as 서울 입구
participant 출구 as 부산 출구
participant 부산서버 as 부산 서버
서울서버->>입구: 내부 패킷
Note over 입구: 외부 헤더를 붙인다
입구->>출구: 외부 패킷
Note over 입구,출구: 외부 헤더가 있는 구간 · 인터넷
Note over 출구: 외부 헤더를 뗀다
출구->>부산서버: 내부 패킷
서울 서버와 부산 서버는 그 구간 밖에 있어서 외부 헤더를 한 번도 보지 않습니다. 두 서버에게는 같은 사내망에 붙어 있는 것처럼 보입니다. 터널이 두 사내망을 한 망처럼 이어 주는 까닭이 이것입니다.
캡슐화와 가르는 선
캡슐화는 덩이를 다른 덩이 안에 싣는 동작입니다. 터널링은 그 동작을 망을 건너는 데 쓰는 것입니다. 이 소절은 둘이 어디서 갈리는지를 싣는 순서로 확인합니다.
통신 규칙은 한 덩어리가 아니라 여러 겹으로 나뉘어 있습니다. 그 한 겹이 계층입니다. 겹으로 나누면 각 겹이 제 일만 맡을 수 있습니다.
보통의 캡슐화에서는 위 계층이 만든 덩이를 바로 아래 계층이 받아 자기 헤더를 붙여 싣습니다. 순서는 위에서 한 칸 아래로만 내려갑니다. 웹 요청의 데이터는 연결을 관리하는 전송 계층의 덩이에 먼저 들어갑니다. 그 덩이가 다시 IP 패킷에 들어갑니다.
터널링은 망을 건너려고 이 순서를 벗어나서 싣습니다. IP 패킷 안에 또 IP 패킷이 들어가는 것이 앞의 예입니다. IP 패킷보다 한 계층 아래 덩이인 프레임을 IP 패킷 안에 넣기도 합니다.
프레임을 싣는 터널은 여러 서버에 흩어진 가상 머신이나 컨테이너를 잇는 데 씁니다. 서버 사이에 깔린 실제 망 위에 터널로 가상의 망을 한 겹 더 까는 것입니다. 이런 망이 오버레이 네트워크입니다.
프레임을 싣는 대표적인 터널 방식이 VXLAN(Virtual Extensible LAN, 가상 확장 근거리망)입니다. 흩어진 가상 머신들이 한 사내망에 붙은 것처럼 서로를 봅니다.
외부 헤더만큼 줄어드는 크기
헤더를 한 겹 더 붙이면 한 번에 실을 수 있는 크기가 줄어듭니다. 줄어든 크기가 어떻게 알아보기 어려운 고장으로 번지는지 따라갑니다.
망의 한 구간이 한 번에 실어 나를 수 있는 패킷 크기에는 상한이 있습니다. 이 상한이 MTU(Maximum Transmission Unit, 최대 전송 단위)입니다.
유선 사내망에 흔히 쓰는 규칙이 이더넷입니다. 이더넷 구간의 MTU 는 보통 1500바이트입니다.
터널을 지나는 외부 패킷도 이 상한을 지켜야 합니다. 그런데 외부 헤더가 1500바이트 안에서 제 몫을 먼저 가져갑니다. 방식에 따라서는 외부 헤더와 내부 패킷 사이에 터널 자신의 헤더가 하나 더 낍니다. 안에 든 것이 어떤 종류의 덩이인지를 출구에 알려 주는 헤더입니다.
네 겹을 늘어놓으면 아래와 같습니다. 가운데 줄이 MTU 전체이고, 맨 아래 줄이 내부 패킷의 몫입니다.
block-beta columns 4 a["외부 헤더"] b["터널 헤더"] c["내부 헤더"] d["데이터"] e["MTU 1500바이트"]:4 space:2 f["내부 패킷 몫"]:2
외부 헤더와 터널 헤더를 합쳐 24바이트라고 해 봅시다. 내부 패킷은 1476바이트까지만 실립니다.
서버가 이것을 모르고 1500바이트짜리 패킷을 만든다고 합시다. 입구가 감싼 외부 패킷은 1524바이트가 됩니다. 상한을 넘습니다.
상한을 넘은 패킷은 잘게 쪼개져서 가거나 버려집니다. 보낸 쪽이 쪼개지 말라는 표시를 붙였으면 중간 장비는 쪼개지 않고 버립니다.
쪼개서 보내는 일이 단편화입니다. 쪼갠 조각은 받는 쪽이 다시 이어 붙입니다. 조각 하나만 잃어도 패킷 전체를 못 쓰게 됩니다.
버리는 장비는 보낸 쪽에 「너무 크다」는 알림을 돌려보냅니다. 이런 오류 알림을 싣는 규칙이 ICMP(Internet Control Message Protocol, 인터넷 제어 메시지 프로토콜)입니다. 보낸 쪽은 알림을 받고 패킷 크기를 줄여 다시 보냅니다.
이렇게 알림을 받아 가며 가는 길 전체에서 통하는 가장 큰 크기를 알아내는 절차가 경로 MTU 탐색입니다. 터널이 낀 길에서는 이 크기가 외부 헤더만큼 작아집니다.
고장은 알림이 중간에서 막힐 때 납니다. 망 경계에서 트래픽을 걸러 내는 방화벽이 ICMP 를 전부 막아 두었다고 합시다. 보낸 쪽은 패킷이 버려진 줄 모르고 같은 크기로 계속 보냅니다.
연결은 맺어집니다. 짧은 요청도 오갑니다. 큰 응답만 멈춥니다. 이 증상이 경로 MTU 블랙홀입니다.
백엔드 개발자는 터널이 낀 구간에서 이 증상을 자주 만납니다. 사무실 밖에서 사내망에 붙는 통로나 앞에서 본 오버레이 네트워크가 그런 구간입니다.
그래서 터널을 세울 때는 크기를 미리 줄여 둡니다. 첫째 방법은 터널 쪽 MTU 를 외부 헤더만큼 낮게 잡는 것입니다.
둘째 방법은 연결 단위로 크기를 줄이는 것입니다. 연결을 맺고 데이터를 순서대로 나르는 규칙이 TCP(Transmission Control Protocol, 전송 제어 프로토콜)입니다. TCP 가 데이터를 잘라 담은 한 덩이를 세그먼트라고 합니다.
TCP 는 연결을 맺을 때 세그먼트 하나에 받을 수 있는 데이터 크기를 서로 알립니다. 이 값이 MSS(Maximum Segment Size, 최대 세그먼트 크기)입니다.
입구 장비가 이 값을 외부 헤더만큼 줄여 적어 주면 서버가 처음부터 작은 패킷을 만듭니다. 그러면 감싼 뒤에도 상한을 넘지 않습니다. 이 방법이 MSS 클램핑입니다.
감싸는 것과 가리는 것
이 소절은 터널이 내부 패킷을 숨겨 주는지를 따져 봅니다.
외부 헤더를 한 겹 씌웠을 뿐이라 내부 패킷은 원래 모습대로 들어 있습니다. 중간에서 누가 외부 패킷의 페이로드를 열어 보면 내부 헤더의 사설 주소와 데이터가 다 읽힙니다.
내부를 가리려면 암호화를 더합니다. 입구가 내부 패킷을 암호화해서 외부 패킷에 넣습니다. 열쇠를 가진 출구만 그것을 풉니다. 중간에서 보이는 것은 외부 헤더와 뜻 모를 바이트뿐입니다.
터널링에 암호화를 더해 공용 인터넷 위에 사내망을 세운 것이 VPN(Virtual Private Network, 가상 사설망)입니다. 앞에서 본 서울과 부산의 예에 암호화만 더하면 사무실 둘을 잇는 VPN 이 됩니다.
터널을 세우는 방식도 이 둘로 갈립니다. 싸기만 하는 방식으로 GRE(Generic Routing Encapsulation, 일반 라우팅 캡슐화)가 있습니다. 싸면서 잠그는 방식으로 IPsec(IP Security, IP 보안)과 WireGuard가 있습니다.
연결 하나 위에 여는 터널
지금까지는 패킷을 통째로 싣는 터널이었습니다. 이 소절은 연결 하나를 통로로 삼는 터널을 다룹니다. 백엔드 개발자가 가장 자주 손으로 여는 터널이 이쪽입니다.
SSH 터널이 그 예입니다. SSH(Secure Shell)는 원격 서버에 암호화된 연결로 접속하는 규칙입니다. SSH 터널은 이 연결 위에 다른 연결의 바이트를 실어 나릅니다.
쓰는 모습은 이렇습니다. 내 컴퓨터의 한 포트로 들어온 연결을 SSH 연결에 실어 원격 서버 너머의 데이터베이스까지 잇습니다. 한 포트로 들어온 연결을 다른 곳으로 넘겨 주는 이 일을 포트 포워딩이라고 부릅니다.
외부에서 바로 붙을 수 없는 데이터베이스에 붙을 때 이 방법을 씁니다. 접속을 허락받은 중계 서버 하나까지만 SSH 로 들어갑니다. 거기서부터는 터널이 데이터베이스까지 이어 줍니다.
프록시에도 같은 방식이 있습니다. 프록시는 클라이언트 대신 요청을 보내 주는 중간 서버입니다.
클라이언트가 HTTP(HyperText Transfer Protocol) 프록시에 CONNECT 라는 요청을 보내 목적지를 알립니다. 프록시는 그 목적지로 연결을 엽니다. 그 뒤로는 오가는 바이트를 읽지 않고 양쪽으로 넘겨 줍니다.
뼈대는 패킷 터널과 같습니다. 통로 양 끝이 싣고 내립니다. 중간은 내용을 모른 채 나릅니다. 다른 것은 싣는 단위가 패킷이냐 연결의 바이트냐뿐입니다.
게임 물리의 터널링
게임에서는 같은 이름이 전혀 다른 현상을 가리킵니다. 게임은 물체의 위치를 화면을 한 번 그릴 때마다 띄엄띄엄 검사합니다.
아주 빨리 나는 총알은 한 번 검사한 뒤 다음 검사 전에 얇은 벽 너머로 넘어갑니다. 그래서 벽과 겹친 순간이 한 번도 잡히지 않습니다.
이렇게 충돌을 놓치고 빠져나가는 일을 게임 쪽에서는 터널링이라고 부릅니다. 이 뜻은 충돌 처리와 연속 충돌 감지가 다룹니다.
관련 항목
터널링이 기대는 캡슐화 개념
캡슐화 · 역캡슐화 · 패킷 · 헤더 · 페이로드 · 프레임 · 계층 · 프로토콜 스택
터널을 세우는 프로토콜
GRE · IP-in-IP · IPsec · WireGuard · VXLAN · Geneve · L2TP · OpenVPN
터널링 위에 세우는 망 구성
VPN · 오버레이 네트워크 · 사이트 간 VPN · 원격 접속 VPN · 분할 터널링 · 전체 터널링 · 터널 인터페이스
터널이 건너게 해 주는 주소 체계
IP · IP 주소 · 사설 IP 주소 · 공인 IP 주소 · IPv4 · IPv6 · NAT · 라우터 · 라우팅
터널에서 줄어드는 크기와 그 증상
MTU · 경로 MTU 탐색 · PMTU 블랙홀 · 단편화 · ICMP · MSS · MSS 클램핑 · 방화벽 · 이더넷
연결 하나 위에 여는 터널 도구
SSH 터널 · 포트 포워딩 · CONNECT 메서드 · HTTP · 프록시 · SOCKS · 배스천 호스트
터널링을 악용하는 우회 통로
ICMP 터널링 · DNS 터널링 · 방화벽 우회 · 데이터 유출
같은 이름을 쓰는 게임 물리 현상
다른 이름: Tunneling · 네트워크 터널링