[참고]
본 글은 인프런 널널한 개발자님의 「Docker가 쉬워지는 운영체제 이야기」 강의를 수강한 뒤 개인적으로 재구성한 학습 기록입니다.
이번 시간에는 NAT(Network Address Translation) 에 대해 알아보려고 한다.
호스트에서 Mac 기준 ifconfig로 확인한 IP는 192.168.x.x인데, 외부에서 조회한 내 IP는 전혀 다른 주소가 나온다.
이 차이를 만드는 게 공유기의 NAT 기능이다.

NAT란?
NAT(Network Address Translation) 는 패킷이 네트워크 경계를 통과할 때 IP 헤더의 주소를 다른 값으로 변환하는 기술이다.
IPv4 주소는 32비트로 약 43억 개뿐이라 모든 기기에 공인 IP를 줄 수 없다.
그래서 네트워크 내부에서는 사설(private) IP를 쓰고, 인터넷으로 나갈 때만 공인(public) IP로 바꾸는 방식이 등장했다.
사설 IP와 공인 IP
| 구분 | 공인 IP (Public IP) | 사설 IP (Private IP) |
| 유일성 | 인터넷 전체에서 유일 | 내부망에서만 유일 |
| 할당 주체 | ISP | 공유기 (DHCP) |
| 인터넷 라우팅 | 가능 | 불가 |
사설 IP 대역은 RFC 1918에 정의되어 있다.
| 대역 | CIDR | 주요 사용처 |
| 10.0.0.0 ~ 10.255.255.255 | 10.0.0.0/8 | 기업망, 클라우드 VPC |
| 172.16.0.0 ~ 172.31.255.255 | 172.16.0.0/12 | Docker 기본 네트워크 |
| 192.168.0.0 ~ 192.168.255.255 | 192.168.0.0/16 | 가정용 공유기 |
사설 IP는 네트워크마다 중복 사용되기 때문에 인터넷에서 목적지를 특정할 수 없다.
그래서 인터넷 라우터는 사설 IP 대역을 라우팅하지 않고, 외부와 통신하려면 경계에서 공인 IP로의 변환이 필요하다.
공유기의 위치
공유기는 LAN(내부망)과 WAN(외부망)의 경계에 있다.

※ 예시의 공인 IP(203.0.113.10)는 문서 작성용 예약 대역(RFC 5737)을 사용했다.
| 기능 | 설명 |
| DHCP 서버 | 내부 호스트에 사설 IP 할당 |
| Default Gateway | 외부로 나가는 패킷의 출구 |
| NAT | 사설 IP ↔ 공인 IP 변환 |
※ Mac 기준 netstat -nr | grep default 결과의 기본 게이트웨이가 공유기의 LAN 쪽 주소다.
NAT 변환 과정
Host A(192.168.0.10)가 웹서버(198.51.100.20:443)에 접속하는 경우를 예로 들어보자.
1. Host A → 공유기
목적지가 외부 네트워크이므로 패킷을 Default Gateway로 보낸다.
출발지 포트는 OS가 임시 포트(Ephemeral Port) 중 하나를 할당한다.
Src: 192.168.0.10:50000
Dst: 198.51.100.20:443
2. 공유기 → 인터넷 (SNAT)
공유기는 출발지 주소를 자신의 공인 IP와 외부 포트로 변환해서 내보낸다.
Src: 203.0.113.10:40001
Dst: 198.51.100.20:443
이때, 이 변환 정보를 NAT 변환 테이블(Translation Table) 에 기록한다.
| Internal | External | Remote |
| 192.168.0.10:50000 | 203.0.113.10:40001 | 198.51.100.20:443 |
3. 서버 → 공유기
서버는 요청을 확인하고 응답을 생성하여 패킷의 출발지인 공인 IP로 응답한다. Host A의 사설 IP는 알 수 없다.
Src: 198.51.100.20:443
Dst: 203.0.113.10:40001
4. 공유기 → Host A (역변환)
공유기는 변환 테이블을 조회해 목적지를 원래 내부 주소로 되돌린다.
Src: 198.51.100.20:443
Dst: 192.168.0.10:50000
정리하면 나갈 때 변환하면서 테이블에 기록하고, 응답이 오면 테이블을 보고 역변환하는 구조다.
※ 웹서버 접속 로그에 클라이언트 IP가 공인 IP로 남는 이유도 이 때문이다.
NAPT: 포트로 호스트 구분하기
공인 IP가 하나뿐이면 응답이 왔을 때 IP만으로는 어느 호스트의 요청인지 알 수 없다.
그래서 공유기는 포트까지 함께 변환한다. 이를 NAPT(Network Address Port Translation) 또는 PAT라고 한다.
| 호스트 | Internal | External |
| Host A | 192.168.0.10:50000 | 203.0.113.10:40001 |
| Host B | 192.168.0.11:50000 | 203.0.113.10:40002 |
| Host A (다른 연결) | 192.168.0.10:50001 | 203.0.113.10:40003 |
내부 포트가 같아도 외부 포트를 다르게 할당하므로 충돌 없이 구분된다.
포트는 0 ~ 65535까지 있어서 공인 IP 하나로 수만 개의 연결을 처리할 수 있다.
※ 변환 테이블의 항목은 일정 시간 통신이 없으면 만료된다. SSH 연결을 오래 방치하면 끊기는 원인 중 하나이고, 이를 막기 위해 Keep-Alive를 사용한다.
포트포워딩
변환 테이블은 내부에서 먼저 요청해야 생성된다.
외부에서 먼저 들어온 요청은 매칭되는 항목이 없으니 공유기가 폐기한다.
내부 서버를 외부에 공개하려면 규칙을 직접 등록해야 하는데, 이게 포트포워딩이다.
| External Port | Internal IP | Internal Port | 용도 |
| 8080 | 192.168.0.20 | 80 | 웹서버 |
| 2222 | 192.168.0.20 | 22 | SSH |
※ 포트포워딩 대상 서버는 DHCP 예약으로 내부 IP를 고정해야 규칙이 깨지지 않는다.
변환하는 대상에 따라 다음과 같이 구분한다.
| 구분 | 변환 대상 | 방향 | 예시 |
| SNAT (Source NAT) | 출발지 주소 | 내부 → 외부 | 일반적인 인터넷 사용 |
| DNAT (Destination NAT) | 목적지 주소 | 외부 → 내부 | 포트포워딩 |
여기서 변환 대상은 패킷 헤더에서 어느 칸을 고쳐 쓰느냐를 말한다.
예를 들어, 위 규칙이 등록된 상태에서 외부 클라이언트가 203.0.113.10:8080으로 접속하면, 공유기에 도착하는 패킷 헤더는 다음과 같다.
Src: 198.51.100.50:51000
Dst: 203.0.113.10:8080
공유기는 규칙에 따라 Dst를 192.168.0.20:80으로 고쳐 써서 내부 서버로 전달한다.
Src: 198.51.100.50:51000
Dst: 192.168.0.20:80
Src는 그대로 두고 Dst(목적지)를 변환하기 때문에 DNAT이다. 반대로 내부에서 인터넷으로 나갈 때는 Src를 공인 IP로 바꾸므로 SNAT이다.
마무리
NAT는 네트워크 경계에서 IP 주소를 변환하는 기술이고, 공유기는 포트까지 변환하는 NAPT 방식으로 하나의 공인 IP를 여러 호스트가 함께 쓰게 해준다.
호스트가 아는 IP와 외부에서 보이는 IP가 다른 것도, 같은 공유기에 연결된 기기들이 같은 공인 IP로 조회되는 것도 이 때문이다.
포트 번호(0~65535)로 연결을 구분하기 때문에 공인 IP 하나로도 수만 개의 연결을 동시에 처리할 수 있어 주소를 효율적으로 사용할 수 있다.
변환 테이블은 아웃바운드 요청으로 생성되기 때문에, 외부에서 내부로 접속하려면 포트포워딩(DNAT) 설정이 필요하다.
