1. 랑데뷰 서버
홀펀칭은 클라이언트 A와 B가 이미 랑데뷰 서버 S와 active UDP 세션을 가지고 있다고 가정하고 시작한다.
클라이언트가 서버 S에 등록되면, 서버는 클라이언트의 2개의 endpoint를 기록한다.
(one : private ip/port, two : public ip/port)
클라이언트는 서버에게 자신의 private ip/port를 포함한 등록 패킷을 보내면,
서버는 패킷에 포함된 private ip/port와 실제 UDP 통신상에서 알아낸 public ip/port 2개의 endpoint를 모두 획득하게 된다.
만약, 클라이언트가 NAT 밑에 있지 않은, 즉 공인 IP를 쓴다면 private ip/port는 public ip/port와 일치하게 된다.
2. P2P 세션 연결 시나리오
클라이언트 A가 B와 직접 UDP 세션을 열고 싶어한다고 가정해 보자. 홀펀칭은 다음과 같이 진행된다.
1. 최초 A는 B에게 어떻게 도달해야 하는지 모른다. 따라서 A는 S에게 B와 UDP 세션 연결을 요청한다.
2. S는 A에게 B의 private/public endpoints 정보를 전송해 준다. 이와 동시에, S는 B와 연결된 UDP 세션을 통해 A의 private/public endpoints 정보를 포함하는 접속 요청 패킷을 전송한다.
3. A가 B의 endpoints 정보를 S로부터 받으면 A는 private/public endpoints로 UDP 패킷을 전송하기 시작하며, 두 개의 endpoints 중 어느 쪽으로든 올바른 응답이 B로부터 오기를 대기한다.
이와 유사하게, B가 A의 private/public endpoints 정보를 받으면, B역시 A로 UDP 패킷을 전송하기 시작한다.
이제 세 가지의 네트워크 토폴로지에 대해 UDP 홀펀칭이 어떤 식으로 이루어지는 지 확인할 필요가 있다.
1. 두 클라이언트가 같은 NAT 밑에 있는, 하나의 private network에 소속되어 있는경우.
2. 대부분의 경우인데, 두 클라이언트가 서로 다른 NAT 밑에 있는 경우.
3. 두 클라이언트가 2단계의 NAT 들 밑에 있는 경우 : 통상적으로 첫번째 NAT는 ISP의 그것이...
두번째는 각기 사용하는 home-networking을 위한 가정용 NAT 이다.
일반적으로 어플리케이션 스스로 물리 계층에서의 네크워크가 어떻게 구성되어 있는지 알아내기란 쉽지 않다. STUN과 같은 프로토콜이 통신 통로상에서 NAT 구성에 대한 정보를 줄수도 있으나, 이 정보는 반드시 신뢰될 만한 것이 아니며, 특히 NAT가 다단계인 경우 더더욱 그러하다.
그럼에도 불구하고, NAT가 대체적으로 RFC를 충족하도록 구현되어 있다면, 어플리케이션 상에서 어떤 식으로 네크워크가 구성되어 있는지 몰라도 홀펀칭은 대개의 경우 잘 동작한다.
3. Peers behind a common NAT
두 클라이언트가 같은 NAT 밑에 있는 경우 위 그림과 같이 당연하게도 외부에서 보기에는 public ip가 똑같다.
A가 S로 UDP 세션을 연결하였고, NAT는 A-S 연결에 62000번 포트를 할당, 맵핑하였다.
B도 S랑 세션을 연결하였고, NAT는 B-S 연결에 62500번 포트를 할당, 맵핑하였다.
A가 S를 이용하여, B와의 UDP 세션을 연결하기 위해 홀펀칭을 시도한다고 가정해보자.
1. A는 S에게 B와의 연결 요청을 전송한다.
2. S는 A에게 B의 private/public endpoints 정보를, B에게 A의private/public endpoints 정보를 전송한다.
3. 두 클라이언트 모두 private/public endpoints로 UDP 패킷을 서로에게 직접 전송하기 시작한다.
4. 두 클라이언트 간 public ip/port로의 UDP 패킷 통신은
NAT가 hairpin translation을 지원하느냐 하지 않느냐에 따라 서로에게 도착할 수도 그렇지 않을 수도 있다.
5. 두 private endpoint 간 메시지는 서로 도착할 것이며, 두 클라이언트 간 다이렉트로 전송되는 것이
NAT를 거쳐가는(through public endpoint) 것보다 대부분 빠르므로, 어플리케이션은 private endpoint 통신을 선호한다.
4. Peers behind different NATs (most case)
그림과 같이 A와 B가 서로 다른 NAT 밑에 있는 경우에 대해 알아보자.
A와 B는 4321 포트에서 S의 1234 포트로 UDP 세션을 초기화시켰다.
이 outbound 과정을 핸들링하면서 NAT-A는 A-S 세션에 대해 155.99.25.11:62000 포트를 할당하였고,
NAT-B는 B-S 세션에 대해 138.76.29.7:31000 포트를 할당하였다.
1. A가 S에 등록하는 과정에서, A는 자신의 private endpoint가 10.0.0.1:4321(10.0.0.1은 NAT-A에서의 A의 ip)임을 알리고,
등록과정에서 S가 파악한 A의 public endpoint(155.99.25.11:62000, NAT-A가 할당한)와 함께 이를 A의 정보로 저장한다.
2. B 역시 S에 등록하는 과정에서 자신의 private endpoint가 10.1.1.3:4321임을 알리면,
등록과정에서 S가 파악한 B의 public endpoint(138.76.29.7:31000)와 함께 B의 정보로 저장한다.
3. 이제 A는 위 그림의 "The hole Punching Process"를 따라 B와 직접적인 세션을 연결한다.
4. 우선, A는 S에게 B와 직접 연결을 요청한다. 이에 대한 응답으로 S는 A에게 B의 private/public endpoints에 대한 정보를, B에게 A의 private/public endpoints에 대한 정보를 각각 전송해 준다.
5. A와 B는 서로의 two endpoints에 대해 직접적으로 UDP 패킷을 전송하기 시작한다.
6. A의 첫 메시지가 B의 public endpoint로 발송되었다고 가정해보자.
이 메시지는 NAT-A를 통과하기 때문에, NAT-A는 이 패킷이 새로운 세션(A-B)에 대한 첫 UDP 패킷임을 인지한다.
새로운 세션의 source-endpoint(10.0.0.1:4321)가 A-S 연결의 source endpoint와같지만, destination은 A-S의 그것과 다르다.
여기에서 NAT type 별 양상이 달라지는 데 간단하게 정리하면 다음과 같다.
7.1 Full cone:한 번내부(private endpoint)에서패킷이 전송된 적이 있는 source(public) endpoint로는 외부에서도 자유롭게 패킷을 전송할 수 있다.
7.2 Restricted cone : 한 번 내부에서 destination ip로 패킷이 전송된 적이 있는source endpoint로는 해당 destination ip로부터의 패킷을 전송 받을 수 있다.
7.3 Port restricted cone : 한 번 내부에서 destination ip:port로 패킷이 전송된 적이 있는 source endpoint로는 해당 destination ip:port로부터의 패킷을 전송 받을 수 있다.
7.4 Symmetric cone : 내부에서 외부로 패킷이 나갈 때 destination이 달라질 때마다 NAT가 할당하는 포트가 바뀐다.
예를 들어 1.1.1.1:1000에서 222.222.222.222:1234로 패킷이 나갈 때 NAT가20000번을 할당한다면...
1.1.1.1:1000에서111.111.111.111:4321로 패킷이 나갈 땐private endpoint가 같을 지언정,NAT는다른 포트를 할당하여 결과적으로 public endpoint가 달라지게 된다.
8.A와 B 모두 full cone이 아니라고 가정해 보자.
만약, B->A로의 첫 패킷이 NAT-B를 통과하지 전에,A의 패킷이 NAT-B에 먼저 도착하면,
NAT-B는 A의 incoming message에 대해 unsolicited message라고 판단하여 버려(drop) 버린다.
이 후 A->B도, B->A도 1번씩은 서로 cross하게 NATs를 통해 전달되고 난 이후에야,
A와 B는 직접적으로 열린 hole을 통해 UDP 통신이 정상적으로 이루어 진다.
5. Peers behind multiple levels of NATs
NAT-C는 소수의 ip 주소로 수많은 사용자들을 받아들이기 위한, ISP에 의해 설치된 거대한 산업용 NAT이라고 치고, NAT-A와 NAT-B는 NAT-C로부터 할당받은 ip를 소규모 단위로, 홈 네트워크 구성 등의 이유로 쓰이는 NATs라고 치자.
이 상황에서 서버 S와 NAT-C만이 public ip를 가지고 있다.
즉, NAT-A와 NAT-B에서 쓰이는 "public" ip는실제로 NAT-C 하에서 private 하며,
이 private 한 NAT-A와 NAT-B 밑에 A와 B가 놓여있다.
이제 A와 B가 홀펀칭을 통해서 직접 P2P 연결 구성을 시도한다고 해보자.
아마 최적의 라우팅 방식은A가 NAT-B에 있는B의 "semi-public" 주소, 10.0.1.2:55000으로 메세지를 보내고, B 역시 NAT-A에 있는 A의 "semin-public" 주소, 10.0.1.2:45000 으로 보내는 방식일 것이다.
하지만 불행히도, A와 B가 이 주소를 알 방법은 없다.
왜냐하면 서버 S는 오직 클라이언트의 진정한 전역 public 주소만 보기 때문이다.
또한 A와 B가 이 주소들을 어떻게든 알았다 하여도 이들이 사용 가능할지는 미지수이다.
이는 ISP의 prviate 주소 세계의 IP주소 할당과 클라이언트의 private 세계에서의 IP 주소 할당이 충돌할 수 있기 때문이다.
예를 들어서, NAT-C에서 NAT-A로 할당한 IP주소가 NAT-B에서 B로 할당한 주소인 10.1.1.3 일지도 모르는 것이다.
이러면 B는 자기 자신에게 메세지를 보내는 결과가 나와버린다.
따라서, P2P 통신을 위해 클라이언트들은S에게 보여지는 그들의 전역 public 주소를 이용하는 수 밖에는 없다.
그리고 이는 NAT-C에서 제공하는 hairpin 혹은 loopback 변환에 의존해야한다.
1. A가 B의 public endpoint(155.99.25.11:62005)으로 UDP 패킷을 보낼 때
NAT-A는 먼저 패킷의 source endpoint를10.0.0.1:4321 -> 10.0.1.1:45000으로 변환한다.
2.이 패킷은 NAT-C에 도착하고 이 패킷의 destination이 NAT-C의 변환된 public endpoints 중에 하나라는 것을 알아차린다.
3. 만약 NAT-C가 잘 동작한다면, 패킷의 source endpoint와 destination을 모두 변환하고 이 패킷을 "돌려서" private 네트워크로 보낸다.
4. 이제 패킷의 source endpoint는155.99.25.11:62000이고 destination은 10.0.1.2:55000 이다.
5.B의 private 네트워크로 이 패킷이 들어가면서 NAT-B가 이 패킷의 도착 주소를 변환, B에 도착하게 된다.
위의 procedure는 NAT가 hairpin을 지원할 때 가능한 시나리오이다.
조사에 의하면 거의 대부분의 NAT가 hairpin을 지원하지 않는다고 한다. (특히 가정용은 절망적인...)
따라서 사실상 거의 대부분의 multiple level NAT하에 있는 peer-peer 통신은 불가능한 경우가 많다.
6.UDP Idle timeout
NAT하에서 어플리케이션과 관계없이 UDP 통신은 타임 아웃이 있다.
이 타임 아웃은 일정 기간 서로 통신이 없으면 hole을 닫아버리는 것을 의미한다.
불행하게도 이 타임 아웃에 대한 기준은 없으며, NAT 별로 다 다르다.
심지어 어떤 NAT는 3-4초 동안만 통신이 없어도 hole 이 닫혀버려 다시 홀펀칭을 해야할 수도 있다.
따라서,서로 홀펀칭된 것을 유지하려면 열려 있는 세션들끼리의 최소한의 keep-alive는 보장이 되어야 한다.
UDP를 빈번한 패킷 전송에 사용하는 경우에라도 어느 정도통신이 없는 경우를 대비한 하트비팅이 필요할 듯 하다.
출처: https://devdbref.tistory.com/15 [PHP 및 웹 관련:티스토리]
'유용한 정보' 카테고리의 다른 글
[기타]원격지에서 컴퓨터 재시작 및 종료 명령 (0) | 2024.12.28 |
---|---|
[기타]특정 도메인을 특정 IP 로 바로 이동할 수 있게 시스템에 등록하는 방법 (0) | 2024.12.28 |
[기타]P2P 연결을 위한 기술들..(Hole Punching) (0) | 2024.12.28 |
[Windows Server 2008] FTP Server 구축하기 (0) | 2024.12.28 |
[Windows Server 2008] Core 제품 CLI 설정 메뉴얼 (0) | 2024.12.28 |