Slide 1

Slide 1 text

STUN・TURNを ちょっとだけ深掘りしてみた WebRTC Meetup Tokyo #24 2023/06/23

Slide 2

Slide 2 text

自己紹介 ● @sublimer ● NTT CommunicationsでSkyWayを作るお仕事をしています ● 自宅サーバー運用をしたりアプリケーション開発をするのが趣味 ● STUN・TURNサーバーをC#で書いたので、その時に得られた知見をお話します (⭐付けていただけると喜びます)

Slide 3

Slide 3 text

本日お話すること・しないこと ● お話すること ○ STUN・TURN概要 ○ STUN・TURNのパケットについて ● お話しないこと ○ NAT越えの仕組み ○ STUN・TURNサーバーのコードについて ● 今日のゴール ○ 0x2112A442という値を見て、「あ ! WebRTC Meetupで見たやつだ!!」になる

Slide 4

Slide 4 text

STUN・TURNとは ● STUN ○ STUNサーバーから見たクライアントの情報を教えてくれる ○ LANからインターネットに出ていく際に NATされている場合、自分のグローバル IPアドレス等が分か る ● TURN ○ 相手と直接通信できない場合に、通信を中継してくれる ○ クライアントとサーバーの間は UDP、TCPが使える ○ サーバーと送信先の間は、 WebRTCの場合はUDPが使われる

Slide 5

Slide 5 text

GoogleのSTUNサーバーに対して、Trickle ICEのサンプルからリクエストを送信 STUNのパケットキャプチャーの結果を見てみる Binding Request STUN Header Binding Success Response STUN Header XOR-MAPPED-ADDRESS Attribute

Slide 6

Slide 6 text

● STUNのパケットは、ヘッダーと0個以上の属性で構成されている ● STUNヘッダーは、以下の値が含まれた20 Byteのフィールド ○ Type(14bit): クラス(2bit)とメソッド(12bit)を組み合わせた値 ○ Length(16bit): ヘッダーのサイズを除いたメッセージのサイズ ○ Magic Cookie(32bit): 0x2112A442(固定値) ○ Transaction ID(96bit): クライアント側で生成されたランダムな値 ● XOR-MAPPED-ADDRESS属性は、STUNサーバーから見た クライアントのIPアドレス & ポート番号 ○ Magic CookieとのXORを取っている ○ 「一部のNATの実装は、STUNのパケットの中身までアドレスを変換してしまう」 (らしい) [1] STUNのパケットについて [1]. https://datatracker.ietf.org/doc/html/rfc8489#section-14.2

Slide 7

Slide 7 text

TURNの通信における登場人物 ● TURNクライアント ○ NATを越えて通信したいユーザー ● TURNサーバー ○ 通信を中継するサーバー ● ピア ○ クライアントが最終的にデータを届ける先 ○ ピアが別のTURNサーバーの場合もある TURN クライアント TURNサーバー ピア N A T ここはSTUNのプロトコルで通信 ここはただのUDPの通信

Slide 8

Slide 8 text

SkyWayのTURNサーバーを使うように改造したWebRTC Troubleshooterで、 「Relay connectivity」のテストを実行 TURNのパケットキャプチャーの結果(抜粋)を見てみる

Slide 9

Slide 9 text

TURNでデータを送るまで 1. Binding Request → Binding Success Response 2. Allocate Request → Allocate Error Response a. TURNサーバーとピアの間の通信に UDPを使うことを要求 (REQUESTED-TRANSPORT) b. このタイミングでは認証情報は送らない c. 認証情報がないのでエラーレスポンスが返される d. エラーレスポンスには NONCE等の追加の情報が含まれる

Slide 10

Slide 10 text

TURNでデータを送るまで 3. Allocate Request → Allocate Success Response a. TURNの認証情報と 2. で得られたNONCEなどを用いて、MESSAGE-INTEGRITYを計算する b. MESSAGE-INTEGRITY属性を追加して再度リクエスト c. 認証が成功し、XOR-RELAYED-ADDRESSが得られる 4. CreatePermission Request → CreatePermission Success Response a. 実際にデータをやり取りするための許可を得るための処理 b. 「ピアである〇〇からのデータを転送して欲しい」と尋ねる c. 許可が得られればSuccessのレスポンスが返される

Slide 11

Slide 11 text

TURNとの間のデータのやり取り 1. Channel-Bind Request → Channel-Bind Success Response a. TURNでメッセージを送受信する方法は、 Send、Data methodを使う方法とChannelを使う方法の2 つがある b. WebRTCの通信では、オーバーヘッドが少ない後者が使われる c. どのピアと通信するかを、 Channel Number(0x4000〜0x4FFF)で識別する 2. ChannelData a. STUNヘッダーは持たず、Channel NumberとMessage Length、Dataのみを持つ b. Dataの中身をそのままピアに送信する c. ピアから来たデータは、そのまま Dataに入れてクライアントに送る

Slide 12

Slide 12 text

接続終了の処理 1. Refresh Request → Refresh Success Response a. Refresh RequestのLIFETIME属性を0として送ることで、通信終了を表す b. 通常、Refresh RequestはAllocationの有効期間延長のために使われる

Slide 13

Slide 13 text

STUNの属性を一部紹介 ● SOFTWARE ○ STUN・TURNサーバーのソフトウェア名が入っている ○ coturnの場合、「Coturn-TURN_SERVER_VERSION…」のような文字列になる ○ SOFTWARE属性を見ると、どんな TURNサーバーを使っているか分かる (かも) ● MESSAGE-INTEGRITY ○ STUNメッセージのSHA1-HMACのデータ ○ ヘッダーも含めて計算するが、 MESSAGE-INTEGRITY自身は含めないため、ヘッダーの Lengthを 書き換えて計算したりするのでちょっと面倒 ● FINGERPRINT ○ STUNメッセージのCRC-32のデータ ○ ヘッダーも含めて計算するが、 FINGERPRINT自身は含めないため、ヘッダーの Lengthを書き換え て計算したりするのでちょっと面倒

Slide 14

Slide 14 text

まとめ 1. STUNのパケットは、ヘッダーと属性で構成されている 2. STUNが返すアドレス・ポート番号は、0x2112A442とのXORを計算して、NATによ るデータの書き換えを回避している 3. WebRTCでは、オーバーヘッドの少ない方式でTURNを利用している 4. STUNのパケットを見てみると、いろいろ分かる!!

Slide 15

Slide 15 text

参考文献 1. https://datatracker.ietf.org/doc/html/rfc8489 2. https://datatracker.ietf.org/doc/html/rfc8656 3. https://datatracker.ietf.org/doc/html/rfc8445 4. https://github.com/coturn/coturn/blob/master/src/ns_turn_defs.h#L39 5. https://sublimer.hatenablog.com/entry/2021/12/12/000000 6. https://github.com/kadoshita/doturn