오늘은 지난 시간에 이어 NAT Traversal 기법 중 하나인 UDP Hole Punching에 대해서 소개해 드리겠습니다. RFC 5128에 따르면 Relaying이나 Connection Reversal 방식의 경우 효율성/환경 제약 등으로 인해 최선의 선택이 될 수 없으며 오늘 소개 드리는 UDP Hole Punching 방식이 가장 효율적인 NAT Traversal 기법이라고 합니다.
시작하기에 앞서 NAT의 Mapping Behavior와 Filtering Behavior에 대한 이해가 (반드시) 선행되어야 합니다. 자세한 내용은 예전 블로그 글을 참고 하시고 여기서는 간단한 개념도로 대신하겠습니다.
위 그림에 따르면 NAT의 Mapping & Filtering Behavior는 총 9가지 조합이 나올 수 있겠네요.
3. UDP Hole Punching
RFC 5128에 따르면 UDP Hole Punching은 Endpoint-Independent Mapping을 지원하는 NAT(이하 EIM-NAT)에서만 동작을 한다고 합니다. 위 그림을 보시면 EIM-NAT는 Any Type of Filtering Behavior(Endpoint-Independent Filtering, Address-Dependent Filtering, Address and Port-Dependent Filtering)를 가질 수 있습니다.
UDP Hole Punching 기법은 Filtering Behavior에 따라 "아주" 약간의 동작 차이가 있어 Endpoint-Independent Filtering과 Endpoint-Dependent Filtering(Address-Dependent Filtering, Address and Port-Dependent Filtering)으로 나누어 설명 드리겠습니다.
3.1 EIM-NAT의 Filtering Behavior가 Endpoint-Independent인 경우
3.1.1 단말의 Private Endpoint와 Public Endpoint 정보를 Server에 등록하기
1. | Host A와 Host B는 Server S로 Registry Session 메시지를 전송하는데, 이 메시지의 Payload에는 자신이 사용하는 사설 IP와 포트 번호가 기록되어 있습니다. 즉, Host가 보내는 Registry Session 메시지 Payload의 {Source IP, Source Port}에는 IP/UDP 헤더의 {Source IP, Source Port}와 동일한 값이 들어갑니다. | ||
2. | 이 메시지는 NAT A/B를 통해 Server S로 전달되는데, 이때 NAT A/B에는 다음과 같이 Binding 및 Filtering Entry가 생성되고 Host로 부터 수신한 패킷 IP/UDP 헤더의 {Source IP, Source Port} 정보가 변경되어 전달됩니다. (Payload내 정보는 변경되지 않음)
|
||
3. | Server S가 Host로 부터 수신한 Registry Session 메시지에는 (1) NAT에 의해 변경된 Host의 {Source IP, Source Port} 정보(IP/UDP 헤더 내에 포함)와 (2) NAT가 변경하지 않은 Host의 {Source IP, Source Port} 정보(Payload 내에 포함)가 함께 들어 있으며, (1)을 Public Endpoint(NAT 변환 후 소스 정보), (2)를 Private Endpoint(NAT 변환 전 소스 정보)라 부르겠습니다. 이제 Server S는 Host A와 Host B의 Public Endpoint 및 Private Endpoint를 저장합니다. |
3.1.2 Server로 부터 P2P 통신을 위한 정보 받아 오기
4. | Host B(6.2.2.2)와 P2P 통신을 하고자 하는 Host A는 "Host B 주소를 포함한 Connection Request 메시지를 Server S로 보내고 | ||
5. | 이 메시지는 NAT A를 통과하여 Server S가 수신하게 되는데, 그 과정에서 NAT A는 2번 과정에서 생성된 Binding Entry = {10.1.1.1:4000, 5.1.1.1:60000}에 따라 패킷의 {Source IP:Source Port}를 {10.1.1.1:4000}에서 {5.1.1.1:60000}로 변경하여 전송합니다. | ||
6. | 이를 수신한 Server S는 Host B의 Public Endpoint(6.2.2.2:30000)와 Private Endpoint(10.2.2.2:5000) 정보가 포함된 메시지를 Host A로 전송하고 | ||
7. | 그 메시지는 NAT A가 수신하는데, NAT A의 Filtering Rule에 따라 {Destination IP:Destination Port}가 {5.1.1.1:60000}인 패킷은 모두 허용하게 되어 이 패킷은 Host A로 전달됩니다. 이제 Host A는 통신하고자 하는 Host B의 Public Endpoint와 Private Endpoint 정보를 알게 되었습니다. | ||
8. | 6번과 동시에 Server S는 Host A의 정보(Public Endpoint = 5.1.1.1:60000, Private Endpoint = 10.1.1.1:4000)가 포함된 Connection Request 메시지를 Host B로 전송하고, | ||
9. | 이 메시지는 NAT B가 수신합니다. NAT B 역시 Filtering Rule에 따라 {Destination IP:Destination Port}가 {6.2.2.2:30000}인 패킷은 모두 허용하여 이 패킷은 Host B로 전달됩니다. 따라서 Host B도 Host A의 Public Endpoint와 Private Endpoint 정보를 알게 되었습니다. 6번과 8번 과정에서 Server S가 Public Endpoint 외에 Private Endpoint 정보를 전달하는 이유는 Host A와 B가 동일 NAT 장비에 연결되어 있는 경우에 NAT에 의한 주소/포트 변환 없이 사설 IP 주소를 이용해 P2P 통신을 하기 위함이며, 본 설명에서 이 부분은 제외하겠습니다. |
3.1.3 NAT를 뚫고 P2P 통신하기
10. | 이제 Host A와 Host B는 P2P 통신을 위한 상대방의 Public Endpoint 및 Private Endpoint 정보를 알게 되었고, 이제 서로간에 P2P 데이터 통신을 거의 동시에(simultaneously) 시도합니다. 여기서는 Host A가 조금 먼저 P2P 데이터 패킷을 보낸다고 가정하겠습니다. Host A는 Server S로 부터 받은 Host B의 Public Endpoint = {6.2.2.2:30000}을 목적지로 하여 패킷을 전송하고, | ||
11. | 이 패킷은 NAT A 통과 후 인터넷(IP 라우팅)을 거쳐 NAT B가 수신합니다. NAT A는 Endpoint-Independent Mapping을 지원하고 2번 과정에서 Binding Entry = {10.1.1.1:4000, 5.1.1.1:60000}가 이미 생성되어 있으므로 이 룰에 따라 {Source IP:Source Port}를 {10.1.1.1:4000}에서 {5.1.1.1:60000}으로 변경하여 전송합니다. | ||
12. | 이를 수신한 NAT B는 Endpoint-Independent Filtering 룰에 따라 즉, Inbound Packet의 소스 정보는 상관없이 목적지 정보가 {6.2.2.2:30000}인 패킷은 모두 허용을 하여 이 패킷은 Host B로 전달됩니다. | ||
13. | 반대 방향 역시 마찬가지 입니다. Host B는 Host A의 Public Endpoint = {5.1.1.1:60000}을 목적지로 하여 패킷을 보내고, | ||
14. | 이 패킷은 NAT B를 통과하여 NAT A가 수신합니다. | ||
15. | NAT A 역시 Endpoint-Independent Filtering 룰에 따라 즉, Inbound Packet의 소스 정보를 확인하지 않기 때문에 NAT A를 통과하여 Host A가 수신할 수 있게 됩니다. |
3.2 EIM-NAT의 Filtering Behavior가 Endpoint-Dependent인 경우
EIM-NAT의 Filtering Behavior가 Address-Dependent Filtering이든 Address and Port-Dependent Filtering이든 그 동작은 동일하므로 여기서는 Address and Port-Dependent Filtering을 예로 설명을 드리겠습니다.
3.2.1 단말의 Private Endpoint와 Public Endpoint 정보를 Server에 등록하기
위 과정(3.1.1)과 동일하므로 설명은 생략하며, 다만 NAT A/B에 생성되는 Filtering Rule이 다릅니다.
3.1.1의 NAT는 Endpoint-Independent Filtering이었으므로 수신 패킷(Inbound Packet)의 소스 정보를 확인하지 않지만, 이 경우Address and Port-Dependent Filtering이므로 NAT A/B 모두 소스 정보가 {100.1.1.1:1234}인 패킷만 허용하는 Filtering Rule이 생성됩니다.
3.2.2 Server로 부터 P2P 통신을 위한 정보 받아 오기
위 과정(3.1.2)과 동일하므로 설명은 생략하겠습니다.
3.2.3 NAT를 뚫고 P2P 통신하기
이 부분이 위 과정(3.1.3)과 다릅니다. Host A, Host B가 동시에 P2P 통신을 시도하지만(위 그림에서 10번, 13번), 설명을 위해 Host A가 조금 먼저 P2P 데이터 패킷을 보낸다고 가정하겠습니다.
10. | Host A가 Host B의 Public Endpoint = {6.2.2.2:30000}를 목적지로 하여 P2P 데이터 패킷을 전송하고, | ||
11. | 이 패킷은 NAT A가 수신하여 다음과 같은 동작을 수행합니다.
|
||
12. | 이 패킷은 NAT A를 거쳐 NAT B가 수신하지만 NAT B에 의해 이 패킷은 폐기됩니다. 왜냐? 수신된 패킷의 소스 정보가 현재 NAT B의 Filtering Table에 없기 때문입니다. (NAT B가 Endpoint-Independent Filtering을 지원하는 3.1.3의 경우 이 패킷은 허용됨)
|
||
13. | 하지만 괜찮습니다. 이제 Host B가 Host A의 Public Endpoint = {5.1.1.1:60000}을 목적지로 하여 P2P 데이터 패킷을 전송합니다. | ||
14. | 이 패킷은 NAT B가 수신하여 다음과 같은 동작을 수행합니다.
|
||
15. | 이제 이 패킷(6.2.2.2:30000 to 5.1.1.1:60000)은 NAT A가 수신하고, 11번 과정에서 생성된 Filtering Rule {6.2.2.2:30000 to 5.1.1.1:60000}에 매칭되어 NAT A를 통과하여 Host A가 수신합니다. | ||
16. | Host A가 보내는 패킷에 대해서도 | ||
17. | NAT A 통과 후 | ||
18. | 14번 과정을 통해 생성된 Filtering Rule에 의해 NAT B는 이 패킷을 폐기하지 않고 Host B로 전달합니다. |
요약
앞서 소개드린 EIM-NAT의 Filtering 방식에 따른 UDP Hole Punching의 차이를 요약한 그림입니다.
안녕하세요. NAT 관련 자료를 찾다가 들어왔습니다.
정말 깔끔하고, 초보자도 이해하기 쉽게 잘 정리해서 보여주고 계시네요~~~! 좋은 자료 감사합니다.
한가지 궁금한게 있어서 문의드립니다. 초보라 질문 남기는 것도 쉽지 않네요.
내용중에는 없는데, keepalive 패킷이 TCP 연결시에만 사용되는지 알았는데, UDP 연결시에도 keepalive 패킷을
사용하는지 찾는 중 여기까지 오게 되었습니다.
UDP hole punching 기술에 NAT에서 mapping 정보를 유지하기 위해서 keepalive 패킷을 사용하는지요?
그리고, Cisco 등 모든 네트워크 장비(?)에 UDP 홀 펀칭이 구현되나요?
NAT 장비에 mapping 정보를 유지시키기 위해서는 UDP를 사용하는 응용에 대해서도 keep alive 패킷을 주기적으로 전송해야 합니다.
Cisco, Juniper와 같은 장비 제조사가 제공하는 대용량 NAT 장비는 그 설정에 따라 UDP hole punching이 가능 할 수도, 가능하지 않을 수도 있습니다. 또한 어떤 Firewall 장비의 경우 UDP hole punching이 불가능한 경우도 있습니다.
글 잘 읽었습니다. 간단하게 구현해보려고 시도하던 중 잘 되지 않아 이렇게 질문 몇 가지 드립니다.
해당 NAT는 주소나 포트에 의존 적인 것 같습니다.
Host A, B 구현 시 소켓에 특정 Port를 바인딩하고 Server에 자신의 정보 등록하는 패킷 전송 시
Sever가 받게 되는 패킷의 정보를 보면 NAT에 의해 변경된 주소와 Port가 있다고 생각합니다
서버측에서 이 외부 주소와 Port로 패킷 전송 시 Host A, B가 받을 수 있었습니다.
1.바인딩 하지 않는 경우는 랜덤으로 Port가 결정되긴 하는데 Host A, B의 내부주소와 연결된 Port가 NAT Port가 다른게 맞는 건가요?? 혹시 다르다면 Host의 내부 주소와 연결된 Port번호는 어떻게 알수 있는 건가요??
2.hole Punching이 100% 성공하지 않는다는 것은 아는데 서버, 포트에 의존적인 NAT의 경우 서버와 Host사이 hole이 뚫린다면 Host끼리도 Hole이 100% 뚫리는 것은 아닌가요??
3. 만약 Host A,B의 내부, 외부 정보를 미리 알고 있어 A, B 프로그램 내부에 주소를 저장해두고 위의 방법을 시도 하는 것과 서버 측에서 상대방의 정보를 받아오는 것이 차이가 있나요?
4. Hole Puching 의 경우 포트포워딩 여부에 상관없이 통신이 가능한 기술이죠??
1. NAT 장비 특성에 따라(구현에 따라, Port 충돌 유무에 따라) 내부 port 값을 그대로 외부 port로 할당하는 경우도 있고, 그렇지 않은 경우도 있는 것으로 압니다. 전자를 Port reservation이라 부릅니다.
2. '서버, 포트에 의존적인 NAT'가 Address/Port Dependent Mapping & Filtering NAT를 말씀하시는 건지요? 이건 질문의 의미를 잘 모르겠네요.
3. Host A, B의 내부, 외부 정보(IP & Port)를 각 Host가 미리 알 수 없기 때문에 서버를 통해 상대방의 정보를 받아 오는 것으로 알고 있습니다. 왜냐면 외부 정보는 그때 그때 달라질 수 있기 때문입니다.
4. 만약 NAT에 특정 Host간 통신을 위한 포트포워딩 설정을 해 놓았다면 UDP hole puching은 불필요할 것입니다. 즉, 포트포워딩 설정이 안되어 있다는 가정하에 hot punching을 시도하는 것으로 알고 있습니다.
안드로이드와 외부 네트워크안에 있는 데스크탑 간의 통신을 구현중인데 큰 도움이 되었습니다.
감사합니다.
좋은 글 정말 감사드립니다. UDP Hole Punching 을 테스트 해보기 위한 Open Source 가 있을까요? 조언 부탁 드립니다.
STUNTMAN(http://www.stunprotocol.org/)이란 open source가 있습니다.
본 프로그램은 RFC 5780 기반의 NAT 타입을 조사하는 프로그램으로, NAT 타입이 ADM/EIF 또는 APDM/EIF인 경우 UDP hole punching이 불가하고, 나머지 경우는 가능하다고 보시면 될 것 같습니다 (NAT 타입 관련 글: https://www.netmanias.com/ko/?m=view&id=blog&no=5856).
참고: STUNTMAN은 제가 6년 전에 사용했던 것이라 지금은 좀 더 좋은 툴이 있을 수도 있으니 구글링 해 보시기 바랍니다.
이런 자료 처음보네요.
어떻게 꽤나 복잡한 내용을 담당하게, 정확히 설명하실수 있는지?
많이, 많이 배우고 갑니다.
좋은 글 정말, 정말 감사합니다.
좋은 칭찬 감사히 받겠습니다.
UDP hole punching 기술을 읽다가 EIM-NAT, EDM-NAT 관련해서 RFC설명은 너무 이해하기 벅찼는데요
이렇게 너무 잘 정리해주셔서 감탄이 저절로 나오네요
좋은자료 너무 감사드립니다 ㅎ
회사에 2개의 public ip에 연결된 2개의 공유기로 테스트 하는데요 ~ stunman으로 2개의 공유기가 동일한 type 인것을 확인했습니다.
그런데 실제로 holepunching은 안됩니다.
집과 회사의 하나의 A ip로는 holepunching이 되고 , 집과 회사의 다른 B ip는 holepunching이 안됩니다.
같은 type의 공유기면 holepunching이 가능할꺼라고 생각했는데요 ~
공유기 모델에 따라 안된는 경우가 있나요??
좋은글 너무 감사드립니다.
게임 서버 공부 중에 홀펀칭에 대해서 확실히 이해하고 싶었는데, 이렇게 좋은 글이 있다니..
구구절절 좋은 글을 써주셔서 감사합니다!
남은 하루도 좋은 하루되시고 항상 건승하시길 빕니다!
다시 한 번 정말 감사합니다!!