がねこまさし

そして壁の向こうへ。 NAT/Firewallを越えて通信しよう―WebRTC入門2016

連載: WebRTC入門2016 (6)

こんにちは! 2014年に連載した「WebRTCを使ってみよう!」シリーズのアップデート記事も番外編を含めて6回目となりました。2016年の最後として、実際の通信では欠かせないNAT越えと、企業ネットワークで使うために必要なFirewallを通過する方法について見ていきましょう。

NATを越えて

NATの役割

NAT(+IPマスカレード)は企業だけでなく、一般家庭でも使われています。ブロードバンドルーターやWiFiルーターでは、1つのグローバルIPアドレスを、複数のPCやデバイスで共有することができます。このとき、NATには2つの役割があります。

  • インターネットにつながったグローバルなIPアドレスと、家庭内/社内のローカルなネットワークでのIPアドレスの変換
  • 複数のPC/デバイスが同時に通信できるように、ポートマッピングによるポート変換

WebRTCでNAT越しに通信すること考えてみましょう。

ブラウザが知っている情報

  • ローカルネットワークのIPアドレス
  • 自分が使う(動的に割り振った)UDPポート

ブラウザでは分からない情報

  • グローバルIPアドレス
  • NATによってマッピングされた、外部に向けたUDPポート

例えば

次の架空の例を見てみましょう。二つのPCのブラウザでは、それぞれ自分のローカルIPアドレス、UDPは知ることができます。

nat_address

  • 左のPCのブラウザが分かること
    • ローカルIPアドレス 192.168.10.11
    • ローカルUDPポート 4001/UDP
  • 右のPCのブラウザが分かること
    • ローカルIPアドレス 10.2.100.51
    • ローカルUDPポート 5001/UDP

しかし、NATの外側から見たグローバルの情報は自分では分かりません。

  • 左のPCのブラウザが知らないこと
    • グローバルIPアドレス 178.50.111.222
    • グローバルUDPポート 51111/UDP
  • 右のPCのブラウザが知らないこと
    • グローバルIPアドレス 200.100.50.81
    • グローバルUDPポート 52222/UDP

NATを越えてPeer-to-Peer通信を行うには、シグナリング処理でお互いに自分の知らないグローバルの情報を交換する必要があります。

STUNが教えてくれること

自分で知らない情報は、誰かから教えてもらうしかありません。それを可能にするのがSTUN(Session Traversal Utilities for NATs)です。

STUNの仕組みはシンプルです。NATで変換されたIPアドレス/ポートを、外側にいるSTUNサーバーに教えてもらいます。先ほどの例で言えば、このようになります。

stun

自分のグローバル情報が分かったら、それをシグナリングサーバー経由で相手に渡します。

stun_signaling

STUNサーバーから得られた情報は、シグナリングの過程でICE Candidateとして取得できます。これをシグナリングサーバーなどを経由して相手に送ることになります。(参考: シグナリングサーバーを動かそうシグナリングを拡張して、複数人で通信してみよう

首尾よくNATとポート変換を潜り抜ければ、Peer-to-Peerで通信を行うことができます。

STUNサーバーを使ってみよう

STUNサーバーを自分で動かすこともできますが、幸い公開されているSTUNサーバーがあります。まず、そちらを使ってみましょう。Googleが公開しているサーバーがよく利用されているようです。

  • stun.l.google.com:19302
  • stun1.l.google.com:19302
  • stun2.l.google.com:19302
  • stun3.l.google.com:19302
  • stun4.l.google.com:19302

通常はどれか1つ指定すればOKですが、複数指定することもできます。それでは、実際に以前のソースの一部を修正してみましょう。

さあ、これで接続を試してください。上手く行けば、例えば自宅と友人の家で通信が可能になっているはずです。

STUNでNATを越えられないとき

NATにはグローバルIPアドレスを共有するだけでなく、セキュリティ対策としての役割もあります。内部の端末を隠したり、通信できるポートを制限したり、一種の簡易Firewallとして利用されているケースもあります。その場合はFirewallの場合と同じく、次に説明するTURNを利用する必要があります。

またNATの構造によっては、接続先によって(今回の場合、STUNサーバーとPeer-to-Peerの通信相手)別のポートが割り当てられる Symmetric NAT という物があるようです。この場合もSTUNの仕組みでは通信することができません。やはりTURNの出番ということになります。

Firewallを越えたい

一般家庭のようにブロードバンドルーターなどでNATがある環境では、STUNを使えば通信が可能になります。

それに対して一般的な企業では、Firewallにより通信できるポートが制限されるケースが多いようです。STUNを使った場合でもUDPポートは動的に割り振られるままなので、通信をするためにはFirewallにとても大きな穴を空ける必要があります。それではきっとセキュリティ管理者に怒られてしまいます。

こんなケースに対応するのが、TURN(Traversal Using Relays around NAT)の仕組みです。先ほどのSTUNもTURNもどちらもWebRTCのために生まれたのではなく、以前からVoIPやネットワークゲームの世界で使われていたものです。

TURNの仕組み

TURNを使った通信では、TURNサーバが実際のストリームデータを受け渡す間に入ります。すべてのパケットをTURNサーバーがリレーすることになり、もはや厳密にはPeer-to-Peer通信ではなくなります。

turn

ただしこの際、TURNサーバーではパケットをそのままリレーし、内容については一切変更はしません。

  • 動画のデコード、エンコードは行わない
  • データはそのまま受け渡し、両端のPeerで施された暗号は解除しない

そのため個人的には、アプリケーション的に見た場合にはPeer-to-Peerを維持していると考えていいと思っています。

TURNサーバーでは暗号化処理や動画のデコード/エンコーディングは行わないので、CPU負荷よりもネットワーク負荷が高くなりやすいです。

TURNサーバーを用意するには

それでは、実際にTURNサーバーを動かしてみましょう。2014年の記事ではrfc5766-turn-serverを使いましたが、今回はその後継であるcoturnを使います。coturnが生まれた背景は、こちらの記事に詳しく書かれています。

今回は、OSはUbuntu 16.04 LTSを使って導入してみました。 なるべくOSセットアップ直後の素の状態から自分でビルドしてみましょう。

自分でビルドする手順

まずは、依存ツールやライブラリを導入します。

次にcoturnのソースを、こちらのサイトからダウンロードします。

私が試したときは4.5.0.4が最新でしたが、2016年12月現在は4.5.0.5が最新のようです。 利用したいバージョンのソースをダウンロードして、解凍してください。

それではビルドしてみましょう。

もし途中で依存ライブラリ不足でエラーが出た場合には、追加でインストールしてからビルドし直してみてください。ビルドに成功すると、Ubuntu16の場合は次の場所に関連ファイルがインストールされます。

  • バイナリ → /usr/local/bin/turnserver
  • 設定ファイル(ひな形) → /usr/local/etc/turnserver.conf.default

設定ファイルは適宜 turnserver.conf にコピーして、それを編集して利用してください。

※こちらの手順はcoturn 4.5.0.4 をビルドした際のものです。最新のものでは手順が変更されている可能性がありますので、もし何か見つけたらコメントいただけると嬉しいです。

coturn を動かすまで

coturnをTURNサーバーとして動かす際に、通信方法を2種類を使うことがことができます。

  • TURN … 特定のUDPポートを利用する
  • TURN over TCP … 特定のTCPポートを利用する

企業で使う場合は、後者を利用したいケースが多いと思います。今回は両方使えるように設定しましょう。

tunserver.conf の設定

まず、/usr/local/etc/turnserver.conf.default を /usr/local/etc/turnserver.conf にコピーし、それを編集します。たくさんの設定項目がありますが、TURNをWebRTCで使う際のポイントを見ておきましょう。

ポートの指定

デフォルトでは3478/UDP を使いますが、それを変更して80/TCPを使うようにします。コメントアウトを外してポート番号80を指定してください。

資格証明方法(クレデンシャル)

WebRTCで使うには、lt-cred-mech を有効にする必要があります。デフォルトではコメントアウトされているので、これを有効にしてください。ユーザアカウントは外部のDBを使うのが適切ですが、今回はシンプルに設定ファイルに直接記入しました。ご利用のシステムに合わせて、外部ファイルや外部DBをご利用ください。

同時にrealmも指定します。自分のサーバーのドメインに合わせて、適宜指定してください。

通信プロトコルの指定(変更不要)

プロトコルの指定で no-tcp のコメントアウトを外すとTURN over TCPを利用しなくなります。今回はTCPを使いますので、コメントアウトのままにしておきます。もしUDPを使いたくない場合は no-udp のコメントアウトを外してください。

以前試したときはブラウザでの実装の不十分でtlsやdtlsを利用できなかったのですが、今回試したところデフォルトのまま(有効のまま)で通信できました。もしうまく通信できない場合は、コメントアウトを消してtlsやdtlsを無効にして試してみてください。

coturnを起動しよう

それではcoturnを起動しましょう。今回は80ポートを利用しているため、環境によってはroot権限が必要となりますので、sudoを利用してください。

ここで指定しているコマンドライン引数は次の意味です。

  • -o .. デーモンとして起動
  • -v .. verboseモード。ログを多く出す
  • -c .. 設定ファイルのパスを指定

クライアントのソースを修正しよう

それでは準備したcoturnサーバーを使うように、にクライアント側のソースを修正しましょう。STUNで修正した部分と同じ個所になります。 coturnサーバーが coturn.yourdomain.com で、ポート80で動いていると仮定します。その情報をPeerConnectionに教えてあげましょう。

また、企業内から外部のシグナリングサーバーを利用するには、そちらも80/TCPや443/TCPを使う必要があるかもしれません。環境に応じてご準備ください。

ここまでできたら、無事Firewallを越えて通信ができるはずです。企業内のブラウザと、外のブラウザ(自宅のPCやアンドロイドのブラウザ)で試してみてください。

最後に

WebRTC入門も2016年中になんとか予定していた記事を書き終えることができました。書いている間にもどんどんブラウザがバージョンアップし、新しいAPIが使えるようになっています。最新情報はブラウザのリリースノートやブログをご覧いただくとよいと思います。

みなさんもWebRTCを活用した素敵なアプリケーションを作ってくださいね。ここまでお付き合いいただき、どうもありがとうございました!

Powered byNTT Communications

tag list

アクセシビリティ イベント エンタープライズ デザイン ハイブリッド パフォーマンス ブラウザ プログラミング マークアップ モバイル 海外 高速化 Angular2 AngularJS Chrome Cordova CSS de:code ECMAScript Edge Firefox Google Google I/O 2014 HTML5 Conference 2013 html5j IoT JavaScript Microsoft Mozilla Node.js PhoneGap Polymer React Safari SkyWay TypeScript UI UX W3C W3C仕様 Webアプリ Web Components WebGL WebRTC WebSocket