NAT
고친 사람 github-actions[bot]
NAT 는 패킷이 네트워크 경계를 지날 때 그 안에 적힌 주소를 바꿔 적는 일입니다. 집이나 회사 안의 컴퓨터 여러 대가 바깥에 나갈 때 주소 하나를 함께 쓰게 해 줍니다. 집 공유기가 하는 일이 이것입니다. 대가로 바깥에서 안쪽 컴퓨터를 먼저 찾아올 수 없게 됩니다.
쉽고 빠른 이해
NAT 는 안쪽 컴퓨터의 주소를 바깥용 주소로 바꿔 내보내는 일입니다. 집에서 노트북과 휴대폰이 동시에 웹을 써도, 웹 서버에는 둘 다 공유기의 주소 하나로 보입니다.
인터넷에서 쓰는 주소는 모자랍니다. 기기마다 바깥용 주소를 하나씩 줄 수는 없습니다. 그래서 안에서는 안에서만 통하는 주소를 씁니다. 바깥에 나갈 때만 주소를 바꿔 적습니다.
어떻게 도는가:
- 안쪽 컴퓨터가 바깥 서버로 패킷을 보냅니다
- 공유기가 출발지 주소와 포트를 자기 것으로 바꿉니다. 무엇을 무엇으로 바꿨는지는 표에 적어 둡니다
- 응답이 오면 표를 보고 원래 주소로 되돌려 안쪽 컴퓨터에 넘깁니다
대가도 있습니다. 표에 적힌 적 없는 패킷은 누구에게 줄지 몰라 버려집니다. 바깥에서 먼저 연결을 걸 수 없는 것이 이 때문입니다. 오래 조용한 연결은 표에서 지워져 끊깁니다.
공인 주소가 모자란 IPv4 네트워크의 경계에서 씁니다. 기기마다 공인 주소를 줄 수 있는 IPv6 에서는 주소를 아끼려고 NAT 를 쓸 까닭이 없습니다.
상세
회사 책상 전화로 바깥에 걸면 받는 사람 화면에는 그 책상의 번호 대신 회사 대표번호가 뜹니다. 책상 전화가 수십 대여도 바깥에 보이는 번호는 그 하나입니다. 받은 사람이 끊은 뒤 그 번호로 되걸면 누가 걸었던 것인지 몰라 처음 건 책상까지 닿지 않습니다.
NAT(Network Address Translation, 네트워크 주소 변환)는 라우터가 패킷을 넘기면서 IP 주소(Internet Protocol address, 인터넷 프로토콜 주소)를 다른 값으로 고쳐 적는 기능입니다. 주로 안쪽 네트워크와 바깥 인터넷이 만나는 경계의 장비가 이 일을 맡습니다. 집의 공유기가 가장 흔한 예입니다.
NAT 가 생긴 이유
IPv4(Internet Protocol version 4, 인터넷 프로토콜 버전 4) 주소는 32비트입니다. 만들 수 있는 주소는 43억 개 남짓이라, 세상의 모든 기기에 하나씩 주기에는 모자랍니다. 인터넷에서 서로를 찾는 데 쓰는 이런 주소가 공인 주소입니다.
안쪽 네트워크에서는 바깥과 겹쳐도 상관없는 주소를 따로 씁니다. 이것이 사설 주소입니다. 사설 주소는 인터넷의 라우터들이 넘겨 주지 않으므로, 집집마다 같은 주소를 써도 부딪히지 않습니다.
사설 주소로 쓰는 범위는 셋입니다. 아래 표에서 / 뒤의 숫자는 주소 앞쪽에서 고정된 비트 수입니다. 나머지 비트가 바뀌면서 범위를 이룹니다.
| 사설 주소 범위 | 흔히 보는 곳 |
|---|---|
10.0.0.0/8 |
회사망 · 클라우드의 가상 네트워크 |
172.16.0.0/12 |
회사망 · 컨테이너 네트워크 |
192.168.0.0/16 |
집 공유기 |
문제는 사설 주소를 단 기기가 바깥에 나갈 때입니다. 출발지가 사설 주소인 패킷에는 응답이 돌아올 길이 없습니다. NAT 는 경계에서 이 주소를 공인 주소로 바꿔 적어 응답이 돌아오게 만듭니다.
아래 그림은 기기 여럿이 경계 하나를 지나 주소 하나로 나가는 배치입니다.
flowchart TD
subgraph 안쪽["안쪽 사설망"]
L["노트북 192.168.0.10"]
M["휴대폰 192.168.0.22"]
end
L --> R["공유기 · 바깥 주소 203.0.113.5"]
M --> R
R --> W["인터넷 · 웹 서버"]
주소를 바꿔 적는 순서
집 노트북 한 대가 바깥 웹 서버에 요청을 보내는 장면으로 봅니다. 노트북의 사설 주소는 192.168.0.10, 공유기가 받은 공인 주소는 203.0.113.5 라고 둡니다.
공유기는 주소를 바꿀 때마다 무엇을 무엇으로 바꿨는지 표에 적어 둡니다. 이 표가 변환 테이블입니다. 응답이 돌아오면 이 표를 보고 주소를 되돌립니다.
sequenceDiagram
participant 노트북 as 노트북 192.168.0.10
participant 공유기 as 공유기 203.0.113.5
participant 서버 as 웹 서버
노트북->>공유기: 출발지 192.168.0.10:50000
Note over 공유기: 변환 테이블에 항목 하나를 적는다
공유기->>서버: 출발지 203.0.113.5:40001
서버-->>공유기: 목적지 203.0.113.5:40001
Note over 공유기: 표를 보고 되돌린다
공유기-->>노트북: 목적지 192.168.0.10:50000
나가는 길에 공유기는 출발지 주소와 포트를 자기 것으로 바꿉니다. 그리고 「40001 번으로 돌아오는 것은 192.168.0.10 의 50000 번 것」이라는 항목을 변환 테이블에 적어 둡니다.
돌아오는 길에는 반대로 합니다. 목적지가 203.0.113.5:40001 인 패킷이 오면 표에서 그 항목을 찾아 목적지를 원래 값으로 고쳐 적습니다. 서버는 끝까지 노트북의 사설 주소를 모릅니다.
패킷 앞머리에는 출발지·목적지 주소 같은 값이 적혀 있습니다. 이 부분이 헤더입니다. 헤더에는 체크섬도 들어 있습니다. 체크섬은 헤더 값이 깨지지 않았는지 확인하는 검산 값입니다.
주소를 고치면 이 체크섬이 맞지 않게 됩니다. 그대로 두면 받는 쪽이 패킷을 깨진 것으로 보고 버립니다. NAT 장비가 주소를 바꿀 때마다 체크섬도 다시 계산해 적는 까닭입니다.
포트까지 바꾸는 NAPT
위 장면에서 공유기는 주소와 함께 포트도 바꿨습니다. 이렇게 포트까지 바꾸는 방식이 NAPT(Network Address Port Translation, 네트워크 주소 포트 변환)입니다. PAT(Port Address Translation, 포트 주소 변환)나 IP 마스커레이드라는 이름으로도 부릅니다.
포트를 바꿔야 하는 까닭은 공인 주소가 하나뿐이기 때문입니다. 노트북과 휴대폰이 우연히 같은 포트로 같은 서버에 나가면, 주소만 바꿔서는 돌아온 응답을 누구에게 줄지 가를 수 없습니다. 바깥용 포트를 기기마다 다르게 붙이면 표의 항목이 겹치지 않습니다.
| 안쪽 주소:포트 | 바깥 주소:포트 | 상대 서버 |
|---|---|---|
192.168.0.10:50000 |
203.0.113.5:40001 |
웹 서버 |
192.168.0.22:50000 |
203.0.113.5:40002 |
웹 서버 |
두 항목은 안쪽 포트가 같습니다. 바깥 포트가 40001 과 40002 로 갈렸으므로, 돌아온 응답이 어느 기기 것인지 표만 보고 정해집니다. 오늘날 "NAT" 라고 하면 대개 이 방식을 가리킵니다.
주소만 바꾸는 NAT
포트는 그대로 두고 주소만 일대일로 바꾸는 방식도 있습니다. 안쪽 주소 하나에 바깥 주소 하나를 짝지어 둡니다. 짝을 어떻게 정하느냐에 따라 둘로 나뉩니다.
짝을 미리 고정해 두는 방식이 정적 NAT입니다. 바깥에서 보이는 주소가 기기마다 늘 같습니다. 그래서 정적 NAT 로 짝지은 서버는 바깥에서 그 공인 주소로 찾아올 수 있습니다.
나갈 때마다 남는 바깥 주소에서 하나를 골라 주는 방식은 동적 NAT입니다. 공인 주소 몇 개를 안쪽 기기 여럿이 돌려 쓸 때 씁니다. 동시에 나갈 수 있는 기기는 공인 주소 수만큼입니다.
두 방식 모두 기기 하나가 공인 주소 하나를 차지합니다. 주소를 아끼는 효과는 NAPT 보다 훨씬 작습니다.
변환 테이블 항목이 지워지는 때
표의 항목을 영원히 둘 수는 없습니다. 끝난 통신의 항목이 쌓이면 표가 넘치고 바깥 포트도 바닥납니다. NAT 장비는 쓰이지 않는 항목을 지웁니다.
TCP(Transmission Control Protocol, 전송 제어 프로토콜)는 연결을 닫는 신호가 오갑니다. NAT 장비는 그 신호를 보고 항목을 지울 수 있습니다. 신호 없이 조용하기만 한 연결은 정해 둔 시간이 지나면 지웁니다.
UDP(User Datagram Protocol, 사용자 데이터그램 프로토콜)에는 연결이라는 것이 없습니다. 언제 통신이 끝났는지 알려 주는 신호도 없습니다. UDP 의 항목은 마지막 패킷이 지나간 뒤 일정 시간이 흐르면 지웁니다. 이 시간은 장비마다 다릅니다.
항목이 지워진 뒤에 늦게 온 패킷은 갈 곳을 잃고 버려집니다. 오래 말없이 열어 둔 연결이 어느 순간 끊기는 까닭이 이것입니다. 이를 막으려고 주기적으로 작은 패킷을 흘려 항목을 살려 두는 킵얼라이브를 씁니다.
항목 하나가 생기고 지워지기까지를 그리면 이렇습니다.
stateDiagram-v2
state "항목 있음" as 있음
state "항목 지워짐" as 지워짐
[*] --> 있음 : 안쪽에서 나갈 때 생김
있음 --> 있음 : 패킷이 지나가면 시간 초기화 (킵얼라이브 포함)
있음 --> 지워짐 : TCP 연결을 닫는 신호
있음 --> 지워짐 : 정해 둔 시간 동안 조용함
지워짐 --> [*] : 늦게 온 패킷은 버림
바깥에서 먼저 거는 연결
변환 테이블의 항목은 안쪽에서 나갈 때 생깁니다. 바깥에서 처음 날아온 패킷에는 맞는 항목이 없습니다. NAT 장비는 이 패킷을 안쪽의 누구에게 줄지 몰라 버립니다.
집 컴퓨터에 서버를 띄워도 바깥에서 접속이 안 되는 까닭입니다. 이를 풀려면 「바깥 8080 번으로 오는 것은 192.168.0.10 의 8080 번으로」처럼 규칙을 미리 적어 둡니다. 이 설정이 포트 포워딩입니다.
flowchart TD
P["바깥에서 패킷이 온다"] --> Q{"변환 테이블에 맞는 항목이 있나"}
Q -->|있다| R["목적지를 안쪽 주소로 고쳐 넘긴다"]
Q -->|없다| S{"포트 포워딩 규칙이 있나"}
S -->|있다| R
S -->|없다| T["버린다"]
이 성질 때문에 바깥에서 NAT 뒤의 기기로 먼저 연결을 걸 수 없습니다. 보안 장치처럼 보이지만 막는 것이 목적인 기능은 아닙니다. 무엇을 막을지 정하는 일은 방화벽이 따로 맡습니다.
NAT 뒤의 두 기기가 서로 잇는 법
화상 통화나 온라인 게임은 두 사람의 기기가 직접 데이터를 주고받으려 합니다. 그런데 양쪽 다 NAT 뒤에 있으면 어느 쪽도 먼저 들어갈 수 없습니다. 이 벽을 넘는 기법을 묶어 NAT 통과라고 합니다.
흔한 기법은 홀 펀칭입니다. 두 기기가 먼저 바깥의 STUN(Session Traversal Utilities for NAT) 서버에 패킷을 보냅니다. STUN 서버는 받은 패킷의 출발지를 보고 각 기기의 바깥 주소와 포트를 알려 줍니다. 그다음 두 기기가 동시에 상대의 바깥 주소로 패킷을 보냅니다.
이렇게 보내면 양쪽 NAT 에 상대를 향한 항목이 생깁니다. 상대가 보낸 패킷은 이 항목에 맞으므로 버려지지 않고 들어옵니다.
sequenceDiagram
participant A as 기기 A
participant S as STUN 서버
participant B as 기기 B
A->>S: 패킷을 보낸다
B->>S: 패킷을 보낸다
Note over A,B: 각자의 NAT 에 나가는 항목이 생긴다
S-->>A: B 의 바깥 주소:포트
S-->>B: A 의 바깥 주소:포트
A->>B: 상대 바깥 주소로 보낸다
B->>A: 상대 바깥 주소로 보낸다
Note over A,B: 양쪽 NAT 에 상대를 향한 항목이 생긴다
B->>A: 그 항목을 타고 들어온다
홀 펀칭이 끝내 안 되는 NAT 도 있습니다. 그때는 TURN(Traversal Using Relays around NAT) 서버를 씁니다. TURN 서버는 주소를 알려 주는 데서 그치지 않고, 두 기기 사이의 데이터를 직접 받아 대신 날라 줍니다.
이 기법들은 대개 UDP 위에서 돕니다. UDP 는 연결 수립 없이 패킷 하나로 항목을 만들 수 있기 때문입니다.
백엔드 서버에서 NAT 를 만나는 경우
서버 쪽에서도 NAT 의 흔적이 보입니다. 첫째는 클라이언트 주소입니다. 한 회사나 한 통신사 가입자 여럿이 같은 공인 주소로 나오면, 서버에는 그들이 한 주소로 보입니다.
flowchart TD
subgraph 가입자들
U1["사용자 1"]
U2["사용자 2"]
U3["사용자 3"]
end
U1 --> N["통신사 NAT · 공인 주소 하나"]
U2 --> N
U3 --> N
N --> V["서버 · 한 주소로 보인다"]
IP 주소 하나를 한 사용자로 치고 요청 수를 제한하면 여러 사람이 함께 막힐 수 있습니다.
둘째는 나가는 연결입니다. 클라우드의 사설 네트워크 안 서버가 외부 API(Application Programming Interface, 응용 프로그램 인터페이스)를 부를 때 NAT 를 거치는 구성이 흔합니다.
바깥 포트 번호는 16비트라 공인 주소 하나가 동시에 쓸 수 있는 포트는 6만 5천 개 남짓입니다. 짧은 연결을 끝없이 새로 열면 이 포트가 바닥나 새 연결이 실패합니다. 커넥션 풀로 연결을 다시 쓰면 이 부담이 줄어듭니다.
셋째는 오래 쉬는 연결입니다. 커넥션 풀에 놀고 있던 연결이 NAT 장비의 표에서 지워지면, 다음 요청에서야 끊긴 것이 드러납니다. 시간 순서로 보면 이렇습니다.
sequenceDiagram
participant 앱 as 애플리케이션 서버
participant N as NAT 장비
participant API as 외부 API
앱->>N: 연결을 연다
N->>API: 연결을 연다
Note over 앱,API: 풀에서 연결이 오래 쉰다
Note over N: 오래 조용해서 항목을 지운다
앱->>N: 다음 요청
Note over N: 맞는 항목이 없어 버린다
Note over 앱: 여기서야 실패가 드러난다
킵얼라이브를 켜거나 풀이 쉬는 연결을 먼저 닫게 설정해 이를 피합니다.
주소를 바꿔 적는 대가
인터넷은 원래 양 끝이 서로의 주소를 알고 직접 주고받는다는 전제로 설계됐습니다. 이 전제가 종단 간 원칙입니다. NAT 는 중간에서 주소를 바꾸므로 이 전제가 깨집니다. 바깥에서 먼저 연결하지 못하는 것도 여기서 나옵니다.
주소를 헤더가 아니라 데이터 안에 적어 보내는 프로토콜도 곤란해집니다. NAT 는 헤더만 고치므로 데이터 안의 사설 주소는 그대로 남습니다. 옛 FTP(File Transfer Protocol, 파일 전송 프로토콜)가 대표 사례입니다.
flowchart TD
subgraph 패킷
H["헤더 · 출발지 203.0.113.5 (NAT 가 고침)"]
D["데이터 · 내 주소는 192.168.0.10 (그대로 남음)"]
H --- D
end
이런 프로토콜을 위해 데이터 안까지 고쳐 주는 ALG(Application Level Gateway, 응용 계층 게이트웨이)를 NAT 장비에 따로 둡니다.
IPv6(Internet Protocol version 6, 인터넷 프로토콜 버전 6)는 주소가 128비트라 기기마다 공인 주소를 줄 수 있습니다. 주소를 아끼려고 NAT 를 쓸 까닭이 사라집니다. 다만 IPv4 와 IPv6 가 함께 쓰이는 동안에는 둘 사이를 잇는 변환이 필요합니다. IPv6 만 쓰는 기기가 IPv4 서버에 닿도록 주소를 바꿔 주는 NAT64 가 그 예입니다.
관련 항목
NAT 가 바꿔 적는 주소와 값
IP 주소 · 공인 IP 주소 · 사설 IP 주소 · 포트 번호 · 체크섬 · IP 헤더
NAT 가 동작하는 방식의 종류
NAPT · 정적 NAT · 동적 NAT · SNAT · DNAT · CGNAT · NAT64
NAT 가 들고 있는 상태
변환 테이블 · 연결 추적 · 유휴 타임아웃 · 킵얼라이브 · NAT 재바인딩
NAT 를 맡는 네트워크 장비
라우터 · 공유기 · 기본 게이트웨이 · NAT 게이트웨이 · 방화벽
NAT 뒤로 연결을 들이는 기법
포트 포워딩 · NAT 통과 · 홀 펀칭 · STUN · TURN · ICE · UPnP
NAT 를 지나가는 프로토콜
IPv4 · IPv6 · TCP · UDP · ICMP · FTP · QUIC · WebRTC
NAT 때문에 생기는 문제와 우회 장치
종단 간 원칙 · 포트 고갈 · ALG · X-Forwarded-For · 커넥션 풀
NAT 와 함께 네트워크 경계에 서는 기술
다른 이름: Network Address Translation · 네트워크 주소 변환 · 주소 변환 · NAPT · PAT · IP 마스커레이드