포스트

NAT와 사설망 — 주소 하나로 수백 대가 인터넷을 쓰는 법, 그리고 P2P가 막히는 이유

NAT가 IPv4 고갈을 푸는 방법, NAPT 포트 다중화 변환 테이블, NAT 종류(full-cone·symmetric), 포트포워딩과 홀펀칭(STUN·TURN), conntrack, AWS NAT Gateway까지 사설망 통신을 다룹니다.

NAT와 사설망 — 주소 하나로 수백 대가 인터넷을 쓰는 법, 그리고 P2P가 막히는 이유

“공인 IP는 한 개인데, 집 안 기기는 열 개”

집 공유기에 노트북·폰·TV·콘솔이 다 붙어 있어도, ISP가 준 공인 IP는 보통 한 개입니다. 그런데 다들 동시에 인터넷이 됩니다. 이걸 가능하게 하는 게 NAT(Network Address Translation) 입니다.

NAT는 단순한 “주소 바꿔치기”가 아닙니다. IPv4 주소 고갈을 20년 넘게 버티게 한 핵심 기술이자, 동시에 P2P·화상통화·게임이 그렇게 고생하는 근본 원인이며, AWS에서 사설 서브넷이 인터넷에 나가는 유일한 통로(NAT Gateway)이기도 합니다. 이 글은 NAT의 변환 테이블을 들여다보고, 왜 어떤 NAT는 P2P가 되고 어떤 건 절대 안 되는지까지 내려갑니다.

NAPT 변환 테이블: NAT의 심장

집에서 쓰는 NAT는 정확히는 NAPT(Network Address Port Translation), 흔히 PAT라 부릅니다. 핵심은 포트 번호로 여러 내부 호스트를 구분한다는 것입니다.

내부 호스트가 패킷을 내보내면 NAT는 ① 출발지 주소·포트를 자신의 공인 IP·새 포트로 재작성하고 ② 그 매핑을 변환 테이블에 기록합니다. 응답이 돌아오면 그 테이블을 역조회해 원래 내부 호스트로 되돌립니다.

내부 호스트 192.168.0.10:51000 NAT (공유기) 웹 서버 93.184.216.34:443 src 51000 src→203.0.113.5:40001 변환 테이블 (conntrack) 내부 → 공인(변환) 192.168.0.10:51000 → 203.0.113.5:40001 프로토콜 TCP · 상태 ESTABLISHED · TTL

이 테이블 덕분에 NAT 뒤의 모든 기기가 같은 공인 IP를 공유하면서도, 응답이 엉뚱한 기기로 가지 않습니다. 구분자는 NAT가 새로 배정한 포트 번호(위에서 40001)입니다. 포트가 16비트라 이론상 한 공인 IP로 6만여 개의 동시 흐름을 다중화할 수 있습니다.

flowchart LR
    A["사설 192.168.0.10:51000"] -->|out| N["NAT<br/>src 재작성 + 테이블 기록"]
    N -->|"203.0.113.5:40001"| S[웹 서버]
    S -->|"to 203.0.113.5:40001"| N2["NAT<br/>테이블 역조회"]
    N2 -->|"to 192.168.0.10:51000"| A

NAT는 한 종류가 아니다 — P2P의 운명을 가르는 분류

NAT가 응답 패킷을 받아들이는 조건이 얼마나 까다로운지에 따라 동작이 갈립니다. 이 분류가 화상통화·게임의 P2P 성공률을 결정합니다.

유형매핑 재사용외부에서 들어오는 패킷 허용 조건P2P
Full-cone같은 내부 (IP:port) → 항상 같은 공인 포트누구든 그 공인 포트로 보내면 통과쉬움
Restricted-cone〃내가 먼저 보낸 적 있는 IP에서 온 것만가능
Port-restricted〃내가 먼저 보낸 IP:port에서 온 것만가능
Symmetric목적지마다 다른 공인 포트 배정그 목적지에서 온 것만거의 불가

왜 symmetric NAT에서 P2P가 막히나. symmetric NAT는 목적지가 다르면 외부 포트도 다르게 배정합니다. 그래서 STUN 서버에 물어 알아낸 내 공인 포트가, 실제 상대에게 보낼 때는 다른 포트로 바뀝니다. 상대가 STUN으로 안 포트는 이미 무효 — 구멍이 안 뚫립니다. 통신사 모바일망·기업망이 흔히 이 유형이라, WebRTC가 TURN 릴레이로 폴백하는 이유가 됩니다.

NAT 트래버설: 막힌 문에 구멍 뚫기 (홀 펀칭)

서버는 공인 IP로 가만히 기다리면 되지만, NAT 뒤 두 피어가 서로 직접 연결하려면 문제가 생깁니다. 둘 다 사설망 안이라 상대가 먼저 들어올 수 없습니다. 해법이 홀 펀칭입니다. 공개된 랑데부(STUN) 서버로 서로의 공인 (IP:port)를 알아낸 뒤, 동시에 서로에게 패킷을 쏘아 각자의 NAT에 “나간 적 있음” 매핑을 만들어 구멍을 뚫습니다.

피어 A (NAT 뒤) 피어 B (NAT 뒤) STUN 서버 공인 주소 알려줌 직접 연결(구멍 뚫림)

이게 안 되면(symmetric NAT 등) TURN 서버가 트래픽을 중계합니다 — 직접 연결 실패 시의 보험입니다. WebRTC의 ICE는 이 후보들(직접/STUN/TURN)을 순서대로 시도합니다.

디버깅: 변환 테이블을 직접 보라

NAT 문제는 추측하지 말고 테이블을 봐야 합니다. 리눅스에서 NAT는 netfilter의 conntrack이 상태를 추적합니다.

1
2
3
4
5
6
7
8
9
10
11
# NAT 규칙(어떤 트래픽이 MASQUERADE/SNAT/DNAT 되는지)
sudo iptables -t nat -L -n -v

# 살아있는 변환(연결 추적) 테이블 — 실제 매핑이 여기 있다
sudo conntrack -L | head
# tcp  6 431999 ESTABLISHED src=192.168.0.10 dst=93.184.216.34
#   sport=51000 dport=443 src=93.184.216.34 dst=203.0.113.5
#   sport=443 dport=40001 ...

# 현재 추적 중인 연결 수 / 한도
sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max

프로덕션 함정 — conntrack 테이블 고갈. 트래픽이 폭증하면 nf_conntrack_count가 nf_conntrack_max에 닿고, 그 순간 새 연결이 조용히 드롭됩니다(nf_conntrack: table full, dropping packet 로그). 증상은 “간헐적 연결 실패”라 원인 찾기가 고약합니다. AWS NAT Gateway도 동시 연결·포트 배정에 한도가 있어, 한 목적지로 동시 연결이 폭주하면 ErrorPortAllocation이 납니다 → 목적지를 분산하거나 NAT GW를 늘립니다.

AWS에서의 NAT: 사설 서브넷의 유일한 바깥문

AWS VPC에서 사설 서브넷의 인스턴스(예: 내부 DB·배치 서버)는 공인 IP가 없어 인터넷에 직접 못 나갑니다. 그런데 OS 패치·외부 API 호출은 해야 하죠. 이때 NAT Gateway가 공인 서브넷에 놓여 아웃바운드만 대신 내보내고 응답을 받아 돌려줍니다.

  • 왜 아웃바운드 전용인가: 외부에서 먼저 들어오는 연결은 막아 사설 자원을 보호하면서, 안에서 시작한 연결의 응답만 통과시킵니다(상태 추적). NAT의 본질이 곧 보안 경계가 됩니다.
  • 포트포워딩(DNAT) 은 반대 방향: 외부 → 내부 특정 호스트로 들여보내기. 집 공유기의 “포트 개방”, AWS에선 로드 밸런서/타깃 그룹이 그 역할을 합니다.

자세한 서브넷·라우팅 테이블 배치는 VPC 글, 인바운드 차단 규칙은 방화벽·보안그룹 글에서 다룹니다. NAT가 사설/공인 주소를 다루는 토대는 IP 주소·서브넷팅, 변환 후 패킷이 길을 찾는 과정은 라우팅에 있습니다.

면접/리뷰 단골 질문

  • Q. NAT 하나로 어떻게 수백 대가 동시에 인터넷을 쓰나? → NAPT가 포트 번호로 흐름을 구분해 다중화한다. 응답은 변환 테이블 역조회로 원래 호스트에 돌아간다.
  • Q. symmetric NAT에서 P2P가 왜 안 되나? → 목적지마다 외부 포트를 다르게 배정해서, STUN으로 알아낸 포트가 실제 상대에게 보낼 땐 무효가 된다 → 홀 펀칭 실패 → TURN 릴레이로 폴백.
  • Q. 간헐적 연결 실패, NAT가 의심된다. 첫 확인은? → nf_conntrack_count vs max, AWS면 NAT GW의 ErrorPortAllocation/연결 수 메트릭. 테이블 고갈이면 새 연결만 드롭된다.
  • Q. NAT는 방화벽인가? → 부수효과로 인바운드를 막지만, 보안 기능이 아니다. 명시적 방화벽/보안그룹과 함께 써야 한다.

정리

  • NAT(정확히 NAPT)는 포트로 흐름을 구분해 공인 IP 하나에 수많은 사설 호스트를 다중화한다 — 변환 테이블이 심장.
  • NAT 유형(cone/symmetric)이 P2P 성공 여부를 가른다. symmetric은 홀 펀칭 실패 → STUN/TURN으로 보완.
  • 리눅스는 conntrack으로 상태 추적 → 테이블 고갈이 간헐적 드롭의 단골 원인.
  • AWS NAT Gateway는 사설 서브넷의 아웃바운드 전용 통로. 인바운드는 포트포워딩(DNAT)/LB가 담당.

다음 글: NAT 뒤에서 여러 서버로 트래픽을 고르게 나누는 로드 밸런싱으로 이어집니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

시리즈 · 네트워크 A-Z (20편)

  1. 네트워크란 무엇인가 — 회선 교환 vs 패킷 교환, 왜 인터넷은 패킷을 선택했나
  2. OSI 7계층과 TCP/IP — 왜 네트워크를 굳이 층으로 쪼갰나
  3. 이더넷·MAC·스위치 — 스위치는 어떻게 "어느 포트로 보낼지" 스스로 배우나
  4. IP 주소와 서브넷팅 — /24를 /26으로 쪼갠다는 게 비트 단위로 무슨 뜻인가
  5. 라우팅은 어떻게 길을 찾나 — 라우팅 테이블, Longest Prefix Match, 그리고 BGP
  6. ARP와 L2/L3 경계 — IP는 아는데 왜 MAC을 또 묻나
  7. TCP는 어떻게 신뢰를 만드나 — 3-way handshake, 상태 머신, 그리고 TIME_WAIT
  8. TCP는 얼마나 빨리 보낼까 — 흐름 제어 vs 혼잡 제어, 그리고 톱니파의 비밀
  9. UDP와 QUIC — TCP를 버려야 더 빨라지는 순간
  10. DNS는 어떻게 이름을 주소로 바꾸나 — 루트부터 권한 서버까지, 그리고 캐시의 마법
  11. HTTP의 진화 — 1.1의 줄 서기에서 HTTP/2 멀티플렉싱, HTTP/3까지
  12. TLS/HTTPS는 어떻게 도청 불가능한 채널을 만드나 — 핸드셰이크부터 인증서 체인까지
  13. NAT와 사설망 — 주소 하나로 수백 대가 인터넷을 쓰는 법, 그리고 P2P가 막히는 이유 지금 보는 글
  14. 로드 밸런싱 — L4와 L7은 무엇이 다르며, 왜 헬스체크가 서비스를 살리고 죽이나
  15. 프록시·리버스 프록시·CDN — 콘텐츠를 사용자 코앞으로 옮기는 기술
  16. 방화벽·보안그룹·네트워크 ACL — stateful과 stateless가 가르는 모든 것
  17. VPC & 클라우드 네트워킹 — 라우팅 테이블 한 줄이 퍼블릭과 프라이빗을 가른다
  18. 소켓과 커널 네트워크 스택 — accept 한 줄 뒤에서 벌어지는 일
  19. 네트워크 성능 — 대역폭은 왜 빠름이 아닌가 (RTT·BDP·처리량의 진실)
  20. 현대 네트워킹 — 사이드카, eBPF, 그리고 경계가 사라진 신뢰