がねこまさし

壁を越えろ!WebRTCでNAT/Firewallを越えて通信しよう

こんにちは!がねこまさしです。前回は複数人の同時通話まで実現しました。社内で使うには十分なレベルです。
しかし本格的な企業ユースとなると、まだまだ障害があります。会社と家、自社と別の会社さんなど、実際に通信しようとするとNATやFirewallといった壁が立ちはだかります。

NATを越えよう

NATの役割は

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

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

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

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

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

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

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

Peer-to-Peer通信を行うには、シグナリング処理でお互いに(ローカルネットワーク内の情報ではなく)インターネット側から見た情報を通知する必要があります。
webrtc_nat_0
ブラウザーが、インターネット側から見た情報を知るための仕組みが、STUNになります。

STUNの仕組みは

STUNの仕組みは意外とシンプルです。インターネット側にいる誰か(STUNサーバー)に、自分(ブラウザ)がどう見えるか教えてもらうだけです。
webrtc_nat_1
STUNは元々WebRTCのために作られた仕組みではなく、より汎用的なUDP通信の補助として生まれました。VoIPやネットワークゲームの世界でも使われているようです。

自分を外側から見た情報が分かったら、それをシグナリングサーバー経由で通信相手に渡します。
webrtc_nat_2
お互いの情報が伝わったら、そこを目掛けて通信を行います。間にNATが挟まりますが、ポートを直接マッピングしているのであくまでもPeer-to-Peerです。
webrtc_nat_3

STUNサーバーを動かそう

それでは実際にSTUNサーバーを動かしてみましょう。Linuxで動作するオープンソースのものがあるので、そちらを使います。
rfc5766-turn-server
このサーバはSTUNだけでなく、後程説明するTURNにも対応しています。
DownloadページからOSに合わせたgzファイルをダウンロードし、INSTALL手順に従ってビルド、インストールしてください。参考までに以前私が実施した手順を載せておきます。※ちょっと古いバージョンです。最新のものを取得してインストールしてください。

CentOSの場合、以下の場所に導入されました。

次に設定ファイル( /etc/turnserver/turnserver.conf )を見てみましょう。ポイントとなるのは次の箇所です。

TCPとUDPの両方で待ち受けできますが、STUNはUDPのみが有効なので注意が必要です。※つまりUDPが通らない環境ではSTUNは使えません。

STUNはPeer-to-Peer通信が始まればサーバーのCPU負荷、ネットワーク負荷はかかりません。それに対して後述するTURNでは特にネットワーク負荷がかかります。サーバーを借りていてネットワーク通信量で課金されるようなケースでは、stun-onlyを設定してTURNは無効にしておいた方が良いかもしれません。

設定がすんだらSTUNサーバーを起動してみましょう。画面にエラーが出なければ無事に起動成功です。エラーが出る場合は turnserver.conf を確認してみてください。

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

ここまでで準備したSTUNサーバーを使うように、クライアント側のソースを修正しましょう。前回のソースの一部を変更します。
STUNサーバーが stun.yourdomain.com で、デフォルトのポート3478で動いていると仮定します。その情報をPeerConnectionに教えてあげます。

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

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

NATにはグローバルIPアドレスを共有するだけでなく、セキュリティ対策としての役割もあります。内部の端末を隠したり、通信できるポートを制限したり、一種の簡易Firewallとして利用されているケースもあります。その場合はFirewallの場合と同じく、次に説明するTURNを利用する必要があります。
また、NATの構造によっては、接続先によって(今回の場合、STUNサーバーとPeer-to-Peerの通信相手)別のポートが割り当てられる Symmetric NAT という物があります。この場合もSTUNの仕組みでは通信することができません。やはりTURNの出番ということになります。

Firewallを越えよう

一般家庭のようにブロードバンドルーターなどでNATがある環境では、STUNを使えば通信が可能になります。次は一般的な企業で使えるようにしましょう。
企業ではFirewallが設置されているケースがほとんどです。その場合、外部と通信できるポートも制限されます。STUNではUDPポートは動的に割り振られるままなので、Firewallにとても大きな穴を空けないと通信ができません。きっとセキュリティ管理者に怒られてしまいます。こんなケースに対応するのが、TURNの仕組みです。TURNもWebRTCのために生まれたのではなく、VoIPやネットワークゲームの世界で使われていたものです。

TURNの仕組みは

TURNを使った通信では、TURNサーバが実際のストリームデータを受け渡す間に入ります。すべてのパケットをTURNサーバーがリレーすることになり、もはやPeer-to-Peer通信ではなくなります。この際TURNサーバーでは動画のエンコーディングは行わないので、CPU負荷よりもネットワーク負荷が高くなりやすいです。
webrtc_fw_1

Firewallに穴を空けよう

TURNを使うには、Firewallに1つ穴を空ける必要があります。標準では3478/UDPを使うので、そのポートが通過可能になるように設定して(してもらって)ください。
もう1つ、シグナリングサーバーと通信するための穴も空ける必要があります。例えば9000番を使うのであれば、9000/TCPも同様に通過可能になるように設定して(してもらって)ください。
会社間で通信するのは、両方の会社でFirewallに穴を空ける必要があります。
※これを読んで「結局Firewallをいじるのかよー」とがっかりした人もいますよね? Firewallをいじらない方法もあるので、最後までお楽しみに。

TURNサーバーを動かそう

TURNサーバーは先ほどSTUNサーバーとしてインストールしたrfc5766-turn-server
がそのまま使えます。/etc/turnserver/turnserver.conf の設定を変更してTURNとして使える様にします。

デフォルトのポートは3478ですが、自由に設定できます。

TLS/DTLSは今回は使わない設定にしておきます。また先ほどのSTUNを動かす際に stun-only を設定した場合は、再びコメントアウトしてTURNも使える様にして下さい。


そして、WebRTCでTURNを使う際のキモはこちらの設定です。

なかなか lt-cred-mech が必須だとは分からず、とても長い間悩んでしまいました。lt-cred-mech で使用するアカウント情報はPostgreSQL, MySQL, Redisなどで管理できますが、今回はシンプルにファイル管理にします。

/etc/turnserver/turnuserdb.conf を使うことにしたので、その内容も変更します。

例としてユーザID: yourid 、パスワード: yourpassword としました。 ※実際にはもっと強度の高いパスワードにしてくださいね。

これで turnserverを再起動すれば、TURNでの通信が有効になります。

※ちなみに turnserverを安全に停止させる手段が分かりません。仕方がないので kill で殺しています…。

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

ここまでで準備したTURNサーバーを使うように、クライアント側のソースを修正しましょう。STUNで修正した部分と同じ個所になります。 STUN/TURNサーバーが turn.yourdomain.com で、デフォルトのポート3478で動いていると仮定します。その情報をPeerConnectionに教えてあげます。(STUNとTURNの両方を候補にすることができます)

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

Firewallはそのままで

実際の企業ではセキュリティ上の制約や手続き上の問題で、Firewallに穴を空けるのが大変なことも多々あります。お客様の会社だったらなおさらですよね。そんな時のために、TURN over TCP という規格があり、rfc5766-turn-server と Chrome の両方ともサポートしてます。これを使えば、Firewallはそのままで、通信が可能になります。

TURNサーバを設定し直そう

設定が終わったら、turnserverを再起動してください。

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

ここでは省略しますが、シグナリングサーバーも 80/TCP で動かす必要があります。サーバー側のNode.jsのポート番号と、クライアント側のsocket.ioのつなぎ先のポート番号を80番に変更してください。※Webサーバー、シグナリングサーバー、TURNサーバーの3つをすべて80/TCPで動かすので、サーバーを3つ別々に立てる必要があります。頑張ってください。
webrtc_fw_80
さあ、これで最後です。ブラウザをリロードしてください。きっと壁を越えて対話ができることと思います。

最後に

これまで全5回、WebRTCの使いかたを説明してきました。開発者向けにコードを一から書いてきましたが、世の中には便利なライブラリやサービスも数多くあります。

こちらを利用するのもありですね。日本でWebRTCが盛り上がって、企業ユースでも認知されるのを期待しています。
おつきあいいただき、どうもありがとうございました。
thankyou

Powered byNTT Communications

tag list

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