[WebRTC] 🖥️ 1. Connecting

2025. 10. 10. 23:25도메인/WebRTC

WebRTC는 왜 연결을 위해 서브 시스템이 필요할까?

요즘 배포되는 서비스들은 클라이언트/서버 연결;이하 C/S 연결 위에 작동한다. C/S 연결은 안정된 전송 주소를 필요로 하는데 클라이언트가 서버에 접촉하면 서버가 응답한다.

 

WebRTC는 C/S 연결 모델을 사용하지 않고, P2P 연결 위해 동작한다. P2P 연결에서, 연결 작업이 Peer들에게 분산된다. WebRTC에서 전송 주소 즉, IP/Port를 가정할 수 없기 때문인데, 심지어 세션 동작 중에 변경되기도 한다. WebRTC는 양방향 통신을 위해 agents간 정보를 수집한다.

 

P2P 연결을 수립하는 것은 어렵다. agents들이 다른 네트워크에 존재할 수도 있고, 같은 네트워크에 있더라도 다른 이슈가 있을 수 있다. 예를 들어 클라이언트들이 같은 프로토콜(UDP <-> TCP)를 사용하지 않거나 다른 IP 버전을 사용할 수 있다.

 

P2P 연결을 위한 이러한 어려움이 있지만, 기존의 C/S 연결 보다 큰 이점을 얻을 수 있는데, 다음의 WebRTC가 제공해주는 점들 떄문이다.

저렴한 Bandwidth(대역폭) 비용 - P2P Direct
Lower Latency - P2P Direct
안전한 E2E 통신 - Routing이 필요없기 때문에 변조될 가능성 적음

그럼 어떻게 동작할까?

위에서 설명한 과정들이 바로 ICE(Interactive Connectivity Establishment)이다. WebRTC 이전에 만들어진 또 다른 하나의 프로토콜이다.

 

ICE 프로토콜은 두 ICE Agents간의 최적의 연결을 찾기 위해 시도한다. 각각의 Agent는 지원하는 정보를 publish하는데 이를 candidates라고 한다. candiate는 필수적인 전송 주소를 말하는데 이는 상대방이 연결이 가능할거라고 예상되는 것이다. ICE는 여기서 최적의 paring을 결정한다.

 

ICE가 왜 존재하는지, 그리고 왜 유용한지 다음의 네트워크 연결 과정을 살펴보자

Real-world의 네트워크 제약

ICE는 실세계의 네트워크 제약을 해결하기 위한 것이다. 문제는 다음과 같다.

Case: Not in the same network

대부분의 경우에서 WebRTC Agent들은 같은 네트워크가 아니다. 아래는 다른 네트워크 host가 있을 때의 상황이다.

Network A안의 두 agent는 아무런 제약 없이 연결이 가능하다. 그러나, Network B의 agent는 Network A의 agent에게 직접적으로 연결할 수 있는 방법이 없다. 심지어 IP도 똑같은데 private ip이기 때문이다. Router B는 Router A에게 전송할 수 있지만 거기서 종료되는데 Network상에서 누구에게 보낼지 모르기 때문이다.

Protocol Restrictions and Firewall/IDS Rules

UDP를 지원하지 않는 네트워크도 존재하고, TCP를 허용하지 않을 수도 있다. 또 다른 네트워크는 매우 낮은 전송 대역을 가질 수도 있다.

관리자마다 매우 다양한 변수가 있기 때문에 연결에 어려움이 있다.

 

또 다른 장애물은 Deep Packet Inspection과 intelligent filtering이다. 네트워크 관리자가 모든 패킷을 검사하기 위한 Sw를 돌릴 수도 있다. 대부분은 WebRTC를 이해하지 못하기 때문에 차단한다.

NAT Mapping


NAT(Network Address Translation) 매핑은 WebRTC 연결을 가능하게 해주는 마법같은 것이다. 위에서 설명한 다른 서브넷에 있어도 WebRTC가 P2P 통신을 가능하게 해주는 지에 대한 해답이다.

 

relay, proxy 또는 server를 사용하지 않는다. 다른 서브넷에 agent 1번, 2번이 존재한다고 가정해보자.

그림과 같은 통신을 하기 위해 NAT 매핑을 해보자. WebRTC 연결을 위해 1번은 7000포트를 사용한다. 다음과 같은 연결이 발생한다.

192.168.0.1:7000 to 5.0.0.1:7000. 이는 2번이 5.0.0.1:7000에 패킷을 보낼 때 1번에게 연결이 닿게 해준다. 지금과 같은 예시는 router가 제공해주는 자동 버전의 port-forwarding이다.

 

NAT 매핑의 단점은 하나의 형식의 매핑이 있지 않고, 네트워크 간에 항상 일치하지 않는다. ISP와 HW 제조업체간에 다양한 방식이 존재한다.

 

좋은 소식은 일어나는 모든 과정이 관측 가능하기 때문에, ICE Agent가 NAT 매핑과 속성들을 채택할 수 있다는 점이다. 이 행위는 RFC4787에 나와있다.

매핑 생성하기

NAT 매핑은 단순히 임시적인 public IP/Port이다. 외부로 나가는 메세지는 새롭게 매핑되는 주소로 재작성된다. 메세지가 매핑에게 전송되면 자동으로 NAT이 생성된 라우터로 전송된다. 

매핑 생성의 3가지 시나리오

Endpoint-Independent 매핑 - 😀 Happy Path

NAT 내부에서 매핑이 생성된다.

  • 2개의 다른 원격 주소(different remote address)로 패킷을 보낸다고할 때, NAT 매핑은 재사용된다. 두 원격 호스트는 같은 source IP/Port가 보여진다.

Address Dependent 매핑

새로운 매핑은 새로운 주소에 연결될 때 마다 생성된다.

  • 2개의 패킷을 다른 호스트에게 보낼 때, 2개의 매핑이 생성된다.
  • 2개의 패킷을 같은 원격 호스트이지만 다른 포트로 보낼 때, 새로운 매핑은 발생하지 않는다.

Address/Port Dependent 매핑

새로운 매핑은 원격 IP/Port가 다를 때 생성된다.

  • 2개의 패킷을 같은 원격 호스트이지만, 다른 포트로 보낼 때, 새로운 매핑이 발생한다.

매핑 필터링의 3가지 시나리오

Endpoint-Independent 필터링 - 😀 Happy Path

누구나 매핑 사용이 가능하고, 다른 peer들에게 공유가능하다. 

Address Dependent 매핑

매핑이 생성된 호스트만 매핑을 사용할 수 있다. 호스트 A에게 패킷을 본면, 해당 호스트에게만 응답을 얻을 수 있다. 만약 host B에게 이전 매핑을 사용해서 패킷 전송을 시도하면 무시된다.

Address/Port Dependent 매핑

매핑을 생성한 host와 port만 매핑을 사용할 수 있다. A:5000으로 패킷을 보내면 같은 host와 port를 사용할 때만 응답을 받을 수 있다.

STUN (Session Traversal Utilities for NAT)

STUN은 NAT을 작동하기 위해 만들어진 프로토콜이다. WebRTC 이전 심지어 ICE이전에 만들어졌다. RFC8489에 정의되어있고, STUN packet 구조가 정의되어있다. STUN 프로토콜은 ICE/TURN이 사용한다.

 

STUN은 NAT 매핑을 프로그래매틱하게 생성할 수 있게 만들어준다. STUN 이전에는 만들 수는 있었지만 IP/Port에 대한 고려가 없었다. STUN은 이러한 정보를 공유할 수 있게 해준다.

 

일단 매핑을 위한 Request/Response 과정을 살펴보자. 그릐고 다른 peer들에게 공유하기 위한 이 정보들을 어떻게 얻을 수 있는지 알아보자. 이 과정은 WebRTC Peer 연결을 위해 ICE URL에 stun: 이 있을 때 일어나는 과정이다.

STUN은 NAT 외부의 STUN 서버에 관찰 결과를 report하도록 요청하여, NAT 뒤에 있는 endpoint가 매핑이 생성되었는지 파악하도록 도와주는 역할을 한다.

프로토콜 구조

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0 0|     STUN Message Type     |         Message Length        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Magic Cookie                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                     Transaction ID (96 bits)                  |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             Data                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

STUN Message Type

모든 패킷은 type을 가지고 있는데 일단 지금은 2개만 봐보자

  • BInding Request - 0x0001
  • Binding Response - 0x0101

Message Length

Data Section의 길이를 나타내느데, type에 정의된 임의의 데이터를 포함한다.

Magic Cookie

고정 값을 가지고 있으면 다른 프로토콜과 구별하기 위해 사용된다.

Transaction ID

96bit의 request/response id이며, 요청과 응답 페어링을 위해 사용된다.

Data

STUN attributes의 목록을 포함한다.

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Type                  |            Length             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Value (variable)                ....
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

위의 요청은 attributes를 사용하지 않는데 이는 header만 포함한다는 것을 의미한다.

응답은 IP/Port를 포함하는데 XOR을 이용하여 매핑한다. 이것이 NAT 매핑이 만든 것이다.

NAT 매핑 생성

STUN을 이용한 매핑은 요청을 보내기만 하면 된다. STUN 서버에 STUN Binding Request만 보내면 된다. 응답에는 Mapped Address를 포함한다. 이 매핑된 주소가 다른 agent에게 보낼 정보이다. 매핑된 주소는 public IP 또는 Server Reflexive Candiate라고 불린다.

NAT Type 결정

아쉽게도 모든 케이스에 유용하지는 않다. 만약 Address Dependent하다면, STUN 서버는 나에게만 보낼 수 있고, 공유한 다른 agent가 보낸 메세지는 모두 무시된다. 이 때는 STUN sever를 돌리는 host패킷을 peer에게 포워딩해주면 된다. 이걸 해주는 것이 바로 다음에 설명할 TURN이다.

TURN (Traversal Using Relays around NAT)

TURN은 RFC8656에 정의된 direct 연결이 불가능할 때 사용하는 해결법이다. 호환되지 않는 NAT Type을 가졌거나, 같은 프로토콜을 사용할 수 없을 때 사용할 수 있다. TURN 보안을 위해 사용되기도 한다. TURN을 통해 통신하게 되면 클라이언트의 실제 주소를 숨길 수 있다.

 

TURN은 전용 서버를 사용한다. 프록시 처럼 동작한다. client가 TURN 서버에 연결 후 Allocation을 생성한다. allocation 생성을 통해, client는 트래픽을 전송 받을 임시 IP/Port/Protocol을 얻을 수 있다. 이는 Relayed Transport Address로도 알려져 있다. 이를 통해 다른 사람이 TURN을 통해 메세지를 보낼 수 있다. 각 peer들에게 Relay Transport address를 주기 위해서는, 통신을 하기 위한 권한을 만들어야 한다.

TURN을 통한 메세지를 보내면, Relayed Transport Address를 통해 전송된다. 상대방은 TURN을 통해 메세지를 얻는다.

 

TURN Lifecycle

TURN을 통해 통신을 하기 위해 필요한 것은 불변하는 것이다.

Allocation

Allocationn은 TURN의 핵심 즉, TURN Session이다. 생성하기 위해 TURN Server Transport Address와 통신해야한다. 일반적으로 3478 포트를 사용한다.

 

생성할 떄 다음의 정보를 제공해야한다.

  • Username/Passwerd - 생성을 위해 인증이 필요
  • Allocation Transport - 서버(Relayed Transport Address)와 Peers간의 전송 프로토콜 UDP 또는 TCP
  • Even-Port: WebRTC와 관련 없는 다중 allocation을 위해 sequential ports를 요청할 수 있다.

요청이 성공하면, TURN 서버로부터 Data Section에서 STUN attributes를 얻을 수 있다.

  • XOR-MAPPED-ADDRESS - TURN Client의 매핑된 주소. Relayed Transport Address로 메세지를 보내면 해당 주소로 포워딩된다.
  • RELAYED-ADDRESS - 다른 client에게 보낼 주소로, 이 주소로 패킷을 보내면 TURN Client로 릴레이된다.
  • LIFETIME - TURN Allocation이 제거될 떄 까지 남은 시간. Refresh 요청을 통해 연장할 수 있다.

Permission

원격 호스트는 권한을 부여하지 않는한 Relayed Transport Address로 전송할 수 없다. 권한을 만들면, TURN 서버에게 특정 IP/Port가 inbound 메세지가 허가됐다는 것을 알려줘야한다.

 

워너격 호스트는 TURN 서버에 보이는 IP/Port를 줘야한다. 이는 반드시 STUN Binding RequestTURN 서버에 요청해야한다는 걸 의미한다. 가장 흔한 오류는 원격 호스트가 다른 서버에 STUN Binding Request를 보낸다는 것이다.

 

Address Dependent Mapping인 호스트에게 권한을 생성해야할 떄를 가정해보자. 만약 다른 TURN 서버에서 매핑된 주소를 생성했다면, 모든 인바운드 메세지는 무시된다. 매번 다른 호스트와 통신할 때 마다 새로운 매핑을 만든다. 권한은 연장하지 않으면 5분 후에 만료된다.

SendIndication/ChannelData

이 두 메세지들은 TURN Client가 원격 peer에게 메세지를 보내기 위한 것이다.

 

SendIndication은 자기 참조 메세지인데, 보내고 싶은 데이터와 누구에게 보내고 싶은지가 포함된다. 원격 peer에게 많은 메세지를 보낼 때 이는 불필요한 낭비이다. 1,000명에게 보낸다면 1,000번 반복해야한다.

 

ChannelData는 데이터를 보내지만 IP 주소를 반복하지 않게 해준다. IP/Port를 이용해 채널을 만들 수 있다. 채널 id를 통해 전송하면 IP/Port는 서버 사이드에서 처리된다. 많은 메세지를 보낼 때는 이것이 유용하다.

Refreshing

Allocation은 5분 후 자동으로 없어지기 때문에 client는 반드시 연장해야한다.

 

TURN Usage

TURN은 2가지 형식이 존재한다. 일반적으로 한 쪽 peer가 TURN Client 처럼 동작하고, 다른 하나가 직접적으로 통신한다. 몇몇 케이스에서는 두 가지 모두 사용하는데 예를 들어, 양 쪽 client가 UDP가 차단되어있기 때문에 TURN 서버 연결이 TCP를 통해 연결됐을 때이다.

One TURN Allocation for Communication

Two TURN Allocation for Communication

ICE (Interactive Connectiviy Establishment)

ICE는 어떻게 WebRTC Agent간의 연결을 가능하게 해준다. ICE는 연결을 수립하는 프로토콜로 WebRTC 이전에 만들어졌다. peer간에 가능한 Route를 결정하고 연결을 유지하게 해준다.

 

이러한 Route들을 Candidate Pairs라고 하는데, 이는 local과 remote transport address의 페어링이다. 여기서 STUN과 TURN이 ICE와 같이 동작한다. 이 주소들은 local IP/Port, NAT 매핑 또는 Relayed Transport Address가 될 수 있다. 이 주소들은 연결하기 위해서 사용되고 교환된다.

 

두 ICE Agent는 연결을 위해 ICE Ping 패킷(connectivity checks)을 사용한다. 연결이 수립되고 나면, 일반적인 socket처럼 보내고 싶은 데이터를 보낸다. 이런 검증 과정에서 STUN 프로토콜이 사용된다.

Creating an ICE Agent

ICE Agent는 Controlling 또는 Controlled 중 하나이다. Controlling Agent는 Candidate Pair를 선택한다. 일반적으로 제안을 보내는 peer가  Controlling side이다.

 

각 파트 모두 user fragment와 password를 반드시 가져야한다. 이 두 값들은 연결 체크 시작 전에 반드시 교환되어야 한다. user fragment는 plain text로 전송되고 multiple ICE Sessions을 하나로 합칠 떄(demuxing) 유용하다. password는 MESSAGE-INTEGRITY 속성을 생성하는데 사용된다. 각 STUN Packet 마지막에 패킷 전체를 password를 키로 만든 hash값이 속성으로 존재한다. 이 값은 패킷을 인증하고 조작되지 않았다는 데에 사용된다.

 

WebRTC는 이 모든 값들을 이전 챕터에서 설명한 Session Descriptin을 통해 분배한다.

Candidate Gathering

접속 가능한 모든 주소; Candidate를 모아야한다.

  • Host - local interface 위에서 직접 통신하며(Listening), UDP와 TCP가 될 수 있다.
  • mDNS - Host와 비슷하지만 IP 주소 대신 UUID를 hostname으로 가진다. 이를 통해 multicast가 가능하다.
  • Server Reflexive - STUN Binding Request로 생성된 것으로 XOR-MAPPED-ADDRESS이다.
  • Peer Reflexive - 원격 peer가 나를 모르는 상태에서 요청 받을 때 생성된다. 
  • Relay - TURN 서버에 의해 생성된다. 처음 handshake 이후, RELAYED-ADDRESS를 얻는데, 이것이다.

연결 체크(Connectivity Checks)

이제 원격 호스트의 user fragment, password, candidates를 안다. 이제 연결을 시도해보자! 모든 candidate는 각각의 pair를 가지고 있다. 3개의 candidate를 가지고 있다면 9개의 pair를 가진다.

Candidate Selection

Controlling과 Controlled Agent 각각의 pair에 메세지를 보낸다. 만약 한 Agent가 Address Dependent Mapping이라면, Peer Reflexive Candidate이 생성을 야기한다.

 

각 후보 짝들은 Valid Candidate를 찾기 시작한다. Controlling Agent는 Valid Candidate를 후보에 올린다. 이는 Nominated Pair가 되며, Controlling과 Controlled Agent는 양방향 통신을 시도한다. 성공한다면, Nominated Pair는 Selected Candidate Pair가 된다. 나머지 세션 동안 이 Pair가 사용된다.

Restarts

만약 Selected Candidate Pair가 중지된다면(NAT 매핑 만료, TURN Server 크래쉬 등), iCE Agent는 Failed 상태가 된다. 양 쪽 Agents는 재시작되며, 모든 프롤세스를 한 번 더 수행한다.

'도메인 > WebRTC' 카테고리의 다른 글

[WebRTC] 🖥️ 0. What, Why and How  (0) 2025.10.08