STUN 에 대한 설명

리눅스/OS 일반|2019. 5. 16. 18:01
반응형

STUN을 쓰려면 각 플레이어의 호스트는 공인 IP로 공개된 중개 호스트, Xbox 라이브나 플레이스테이션 네트워크 서버에 연결해야 한다. 중개 호스트는, 여러 호스트가 서로 직접 연결하기 위해 필요한 작업을 중개해 주는데, 이를테면 라우터 테이블에 항목을 개설하는 방법 등을 알려준다. 그 절차는 그림 2-22와 비슷한 순서로 진행되는데, 그림 2-23은 이 과정에서 오가는 패킷의 예제와 NAT 테이블의 모습을 보여준다. 우리 게임이 UDP 200번 포트에서 구동 중이라 게임 호스트 간 통신이 모두 200번 포트에서 이루어진다고 가정해 보자.

 

 

 

 

 

먼저 호스트 A는 게임 서버를 개설할 의도를 IP 4.6.5.10의 중개 서버(호스트 N)에 알리는 패킷을 보낸다. 패킷이 라우터 A를 거쳐 갈 때, 라우터 ANAT 테이블에 항목을 만들고 공인 IP를 발신자 주소로, 그리고 발신자 포트를 임의의 숫자 60000번으로 할당하여 재기입한다. 그다음 수정한 패킷을 호스트 N으로 보내는데, 호스트 N이 이걸 받으면 플레이어 A가 공인 IP 주소 18.19.20.21:60000의 호스트 A에 멀티플레이어 게임 서버를 띄워두었다는 사실을 기억해 둔다.

다음 호스트 B는 플레이어 A의 게임에 참가하고 싶다고 호스트 N에 알리는 패킷을 보낸다. 패킷이 라우터 B를 거쳐 갈 때, 라우터 B 역시 NAT 테이블을 갱신하고 패킷을 재기입하여 호스트 N에 보낸다. 호스트 N이 패킷을 받으면 공인 IP 12.12.6.5:62000의 호스트 B가 호스트 A에 접속하려 한다는 사실을 알게 된다.

이 시점에 호스트 N은 라우터 A를 거쳐 호스트 A에 전달하기 위한 공인 IP와 포트 정보를 알고 있는데, 이 정보를 호스트 B에 응답으로 보내면 호스트 B가 호스트 A에 직접 연결할 수 있을 것 같기도 하다. 하지만 앞서 언급한 바와 같이, 대부분 라우터는 패킷의 발신자를 검사하여 원래의 발신자가 아닌 경우에는 차단한다. 라우터 A는 이 포트를 통해 들어오는 패킷 중 오로지 호스트 N의 것만 통과시킨다. 호스트 B가 이 포트로 호스트 A에 접속하려 하면 라우터 A는 그 포트로 호스트 B와 통신한 적이 없으므로 패킷을 막아버린다.

다행히도 호스트 N은 라우터 B를 거쳐 호스트 B에 전달하기 위한 공인 IP와 포트 역시 알고 있다. 이 정보를 호스트 A에 보내면, 라우터 ANAT 테이블에 호스트 N이 있으므로 라우터 A는 이 패킷을 통과시킨다. 이제 호스트 A는 호스트 N이 공유해준 정보로 호스트 B에 패킷을 하나 보낸다. 이 부분이 좀 이상하게 여겨질 수 있다. 호스트 A는 게임 서버요 호스트 B는 클라이언트인데, 클라이언트가 서버에 접속하는 대신, 게임 서버가 클라이언트에 접속하다니 말이다. 게다가 라우터 B는 호스트 A를 아직 모르고 있으므로 패킷을 보내보았자 막혀버릴 것이 뻔하다. 쓸데없는 패킷을 왜 보내는 걸까. 이런 작업을 하는 이유는 바로 이 과정을 거치며 라우터 A가 테이블에 항목 하나를 만들기 때문이다.

패킷이 호스트 A를 출발해 호스트 B로 가는 동안 라우터 A를 거친다. 라우터 ANAT 테이블에는 이미 192.168.10.2:200 항목이 외부 포트 60000에 매핑되어 있다. 그래서 패킷을 내보낼 때 60000번 포트로 내보낸다. 그리고 그 항목에 추가로 호스트 B의 정보 12.12.6.5:62000 항목을 하나 더 매핑한다. 매핑 항목을 이렇게 추가하게 만드는 것이 이 기법의 핵심이다. 패킷은 비록 호스트 B에 도달하기 전 라우터 B에서 막혀버리지만, 이제 호스트 N이 호스트 B에게 18.19.20.21:60000으로 연결하라고 알려주어, 호스트 B가 그 주소로 패킷을 보내면 라우터 AB가 보낸 패킷을 순순히 통과시킨다. 앞서 호스트 B에게 보내면서 12.12.6.5:62000 항목을 기억해 둔 상태이기 때문이다. 라우터 A는 수신자를 192.168.10.2:200으로 재기입하여 호스트 A에 전달한다. 이제부터 호스트 AB는 중개 서버를 거치지 않고도 서로 공유한 공인 IP와 포트로 통신할 수 있다.



Note ≣

NAT에 관해 몇 가지 더 알아두어야 할 것이 있다. 첫째, 앞에서 설명한 기법이 모든 NAT에서 동작하는 건 아니다. 일부 NAT는 할당한 포트 번호를 계속 유지하지 않는 것도 있는데, 이를 대칭형 NAT(symmetric NAT)라 한다. 대칭형 NAT는 밖으로 나가는 요청마다 고유한 외부 포트를 할당한다. 해당 IP 주소와 포트가 이미 NAT 테이블에 있을 경우라도 그렇다. 이 때문에 STUN 메커니즘이 깨지는데, 라우터 A가 첫 패킷을 호스트 B에 보내려 할 때 새로운 외부 포트를 할당하기 때문이다. 호스트 N이 썼던 외부 포트로 호스트 B가 라우터 A와 접촉해 호스트 A에 접근하려 할 때, NAT 테이블에 해당 정보가 없으므로 패킷이 버려진다.

대칭형 NAT 중 보안이 강하지 않은 것도 있어 이들 NAT는 예측 가능한 순서로 외부 포트를 할당하는데, 이 점을 노려 포트 할당 예측(port assignment prediction)이라는 기법으로 STUN과 비슷한 트릭을 써서 대칭형 NAT를 투과하기도 한다. 보안이 강화된 NAT는 아예 임의로 포트를 할당하므로 쉽게 예측하기 어렵다.

STUNUDP에서만 동작한다3장 버클리 소켓에서 설명하겠지만, TCP는 포트 할당 체계가 다르고 접속을 리스닝하는 포트와 데이터를 주고받는 포트가 다르므로 다른 방법을 써야 한다. TCP 홀 펀칭(TCP hole punching)이라는 기법을 쓰면 이를 지원하는 NAT 라우터를 투과할 수 있다2.11 더 읽을거리 절의 RFC 5128에 이외에도 다양한 NAT 투과 기법을 소개하고 있으며, TCP 홀 펀칭도 찾아볼 수 있다.

마지막으로, NAT 라우터를 투과하는 데 많이 쓰는 방법이 또 있다. IGDP(Internet gateway device protocol)라는 방법으로, 일부 UPnP(Universal Plug and Play) 라우터가 채용하여 랜 호스트로 하여금 외부와 내부 포트 사이에 매핑을 수동으로 설정토록 하는 프로토콜이다. 항상 지원되는 것도 아니며 학술 가치도 덜하므로 굳이 여기서 다루진 않겠다. 구체적인 내용은 2.11 더 읽을거리 절을 참고하자.

 

반응형

댓글()