WebRTC 처음 공부할 때 내렸던 결론은 STUN은 가끔 안 될 때가 있고, TURN은 왠만하면 된다 였다. 회사에 인턴 분들이 오시면서 WebRTC과제를 제공하는데, ICE server 설명 자료를 준비하다보니 왜 STUN이 안되는지 궁금해져서 찾아봤다.
STUN의 기본적인 원리는, 본인의 Public IP를 모르는 client에게 Public IP 주소를 알려줌으로써, 이 Public IP를 통해 RTCPeerConnection 들이 소통할 수 있게 하는 것이다.
따라서, STUN 서버로 통신할 수 없다는 것은 STUN server가 알려주는 Public IP의 주소가 제대로 작동하지 않는다는 것이다. 즉 클라이언트의 Private IP와 매핑된 Public IP로 통신이 불가능하다는 것이다.
이걸 이해하기 위해서 NAT의 종류에 대해 찾아봤는데, 총 4가지가 있다고 한다. 순서대로 알아본다.
Full Cone NAT
{NAT internal side} | {NAT external side} | {Remote host}
| |
1. (INT_ADDR, INT_PORT) => [ (EXT_ADDR, INT_PORT) -> (REM_ADDR, REM_PORT) ]
2. (INT_ADDR, INT_PORT) <= [ (EXT_ADDR, INT_PORT) <- ( * , * ) ]
{NAT internal side} | {NAT external side} | {Remote host}
| |
1. (INT_ADDR, INT_PORT) => [ (EXT_ADDR, INT_PORT) -> (REM_ADDR, REM_PORT) ]
2. (INT_ADDR, INT_PORT) <= [ (EXT_ADDR, INT_PORT) <- (REM_ADDR, * ) ]
Port Restricted Cone NAT
{NAT internal side} | {NAT external side} | {Remote host}
| |
1. (INT_ADDR, INT_PORT) => [ (EXT_ADDR, INT_PORT) -> (REM_ADDR, REM_PORT) ]
2. (INT_ADDR, INT_PORT) <= [ (EXT_ADDR, INT_PORT) <- (REM_ADDR, REM_PORT) ]
Symmetric NAT
{NAT internal side} | {NAT external side} | {Remote host}
| |
1. (INT_ADDR, INT_PORT) => [ (EXT_ADDR, EXT_PORT1) -> (REM_ADDR, REM_PORT1) ]
2. (INT_ADDR, INT_PORT) <= [ (EXT_ADDR, EXT_PORT1) <- (REM_ADDR, REM_PORT1) ]
...
3. (INT_ADDR, INT_PORT) => [ (EXT_ADDR, EXT_PORT2) -> (REM_ADDR, REM_PORT2) ]
4. (INT_ADDR, INT_PORT) <= [ (EXT_ADDR, EXT_PORT2) <- (REM_ADDR, REM_PORT2) ]
STUN이 실패하는 가장 큰 이유가 바로 Symmetric NAT 때문이다. RTCPeerConnection이 다른 목적지로 패킷을 적용하면, external side port가 계속 바뀐다. 즉 STUN 서버로 요청을 보낼 때 사용된 external port가 다른 RTCPeerConnection과 소통하기 위해 사용된 external port와 다르기 때문이다. RFC3489에 따르면 STUN은 Full Cone NAT에서만 사용 가능하다. 그리고 Restricted Cone Nat과 Port Restricted Cone NAT의 경우 application 상태에 따라 가능하지만, Symmetric NAT의 경우에는 사용 가능한 public IP 주소를 return하지 않는다고 나와있다.
이를 해결하기 위해 TURN이 사용되는데, TURN은 P2P통신은 아니고, RTCPeerConnection이 전달하는 패킷을 relay—전달 또는 배달—하는 역할을 한다. 다음에는 TURN에 대해 조금 더 자세히 공부해봐야겠다.
참고자료