3流プログラマのメモ書き

元開発職→社内SE→派遣で営業支援の三流プログラマのIT技術メモ書き。 このメモが忘れっぽい自分とググってきた技術者の役に立ってくれれば幸いです。(jehupc.exblog.jpから移転中)

厳しめのFW&プロキシ環境だとGoogleMeetが切断されてしまう

Google Meet というビデオ会議システムの検証をしてみました。(ブラウザは最新のChromeを使ってます。)

しかし、接続後1分くらいで「ネットワークエラーのため、ビデオハングアウトを開始できませんでした。」というエラーが表示され切断されてしまいます。

まず、ネットワーク構成についてです。今回ハマったのは以下の構成のせいでした。

・FW:内→外はプロキシ経由以外は禁止。(端末直ではネットに出れない。FWはFortiGate使用)
・プロキシ:認証付きプロキシ。かつ、ホワイトリストにして許可URL以外通信禁止。(iFilterを使用)

G Suiteヘルプ:2. Meet 用にネットワークを最適化するをみると、プロキシは推奨されていないなのですが、セキュリティポリシー上仕方ありません。

G Suiteヘルプ:1. ネットワーク接続の要件では、以下のURLのホワイトリストが掲載されているので、これをiFilterの許可するURLリストに追加しました。

https://*.google.com/*
https://*.googleapis.com/*
https://*.gstatic.com/*
https://*.googleusercontent.com/*

これで試しましたが、やはり切断されます。少し詳しく調査が必要なようです。

GoogleMeetが使っているプロトコル - WebRTC

GoogleMeetはWebRTCというプロトコルを使っているようです。まずはこれについて少し調査。。。

WebRTCはリアルタイムコミュニケーションをプラグインレスで可能にするプロトコルです。
P2Pでの通信が可能であり、原則UDPを使います。P2Pのため、NAT超えの仕組みもあります。

WebRTCでは、まずSTUNサーバーによって自身の通信環境を確認し(NATのグローバルIPマッピングされたポート等)相手に知らせます。(相手に知らせるときはシグナリングサーバーを使います。) これでP2P相手とのNAT情報がわかるので、後はクライアント同士がP2Pで接続しNAT超えすることができます。

FW等で直接P2Pが難しい場合は、P2PではなくTURNというサーバーがストリームデータの受け渡しに介入します。
つまり、Client - FW - TURNsv - FW - CLient となるわけですね。
しかしTURNもUDPを使いますし、TURNサーバおよびシグナリングサーバーとの通信ポートをFWに開けないといけません。

これを克服するために、さらにTURN over TCPというものがあるようです。TURNのUDPデータをTCPカプセル化したものぽいです。

WebRTCの詳しい話は以下サイトが参考になります。
壁を越えろ!WebRTCでNAT/Firewallを越えて通信しよう | HTML5Experts.jp
エンタープライズ向けWebRTCの外堀が埋まってきている
WebRTCの裏側 · GitHub
WebRTC コトハジメ · GitHub

通信の流れを追ってみた

3流PGの環境ではFWでクライアントは直接ネットに出れず、ホワイトリスト付きプロキシを使っています。
どのようなパケット流れて、どうブロックされてしまっているのかWireSharkで追っかけて見ました。

1.DNSGoogleの複数のSTUNサーバの名前解決依頼。
2.クライアントはSTUNプロトコルで、Googleの複数のSTUNサーバに Binding Request(UDP) を投げる
3.FWでブロック
4.2.がタイムアウトしSTUNサーバ(IP)宛にプロキシ経由で通信試みる。(HTTPS)
5.iFilterにてブロック。
6.通信不可能。。。

WebRTCが利用できるかどうかのチェックサイトhttps://test.webrtc.org/があります。
現状のままでは、Network部分は Udp, Tcp 共に X でした。

対応方法1 FWに穴を開ける

ChromeのWebRTCが使うポートはデフォルトで、19302~19309です。
FWで、宛先:any , UDP:19302~19309 を許可してやるとうまくいきました。

この状態で、test.webrtc.org/ を実行すると、Network部分は Udp, Tcp 共に ○ でした。
この状態だと正常にMeetが使えます。

しかし、接続先はanyなのであまりよろしくないですよね。

接続先も指定できないか検討してみました。
WireSharkで調べると、Meetの時に使用しているのは、上述のMeetヘルプで掲載されているアドレス以外に、以下のホストにアクセスしているようでした。

stun.l.google.com
stun1.l.google.com
stun2.l.google.com
stun3.l.google.com
stun4.l.google.com

これらをFWのアドレスオブジェクトに追加し、ポートと合わせてフィルタするようにしました。
が、そうすると今度は正常に通信できなくなりました。
FQDN指定はだめなようです。おそらく理由は後述のiFilter使用時と同じで、Chrome側がFQDNアクセスではなくIPベースでアクセスしているからだと思います。FortiOSにDNS引きによるフィルタリング機能があればうまくいきそうですが、見つけることはできませんでした。

また、FWには穴を開けたくないので、少々パフォーマンス下がってもプロキシ経由で使えないものか試みました。

対応方法2 iFiter側で許可する(ホスト名DNS引き)

ChromeのWebRTCは直接接続がだめなら自動的にプロキシ経由でしてくれるので、単純にプロキシ(iFilter)側でGoogleMeetの通信を許可すればいいだけなのですが、これが意外と厄介でした。

なぜかというと、URL単位でのホワイトリスト形式を取っているからです。
Chromeがプロキシに送るリクエストは、URLではなくGoogleのSTUN,TRUNサーバのIPを送っています。
現時点でのサーバのホスト名とIPは以下の通りでした。(この中からランダムで接続先を選んでいるようです)

stun.l.google.com    74.125.23.127
stun1.l.google.com   108.177.98.127
stun2.l.google.com   173.194.199.127
stun3.l.google.com   173.194.196.127
stun4.l.google.com   64.233.177.127

Chromeからはstun.l.google.comというURLでアクセスするのではなく、直にIP=74.125.23.127でアクセスに行くわけですね。なので、stun.l.google.comをホワイトリストに登録してもだめなわけです。
まぁそのIPをホワイトリストに付け加えればいいんでしょうが、IPは変わる可能性があるのでなるべく避けておきたいところです。

iFilterの機能をいろいろ探していると、DNS引きした結果についてフィルタリングもしてくれるようです。 つまり、stun.l.google.com を登録すると、DNS引きの結果のIP 74.125.23.127に対してフィルタリングを行う仕組みです。

その設定は、[ルールセット / ルールパーツ / 識別名リスト] にて、タイプ:DNS引きホスト(部分)にて登録できます。 ここに上記のgoogleのサーバホスト名を登録します。

これでMeetが切断されず正常稼働するようになりました。

ただ、stun...のサーバが増えると、その分も登録してやる必要があります。。

余談(対応方法2 iFiter側で許可する(ポート)

余談ですが、iFilterにはポートをフィルタリングに加えることもできます。
その設定は、[ルールセット / ルールパーツ / アクセス情報セット]です。ただし、範囲指定ができないので1ポートずつ設定する必要があります。

ルール設定で、ポート19302ルールパーツ || ..(略).. || ポート19309ルールパーツ と組み合わせれば、切断されずに正常稼動しました。

ポートともにアクセス先をフィルタリングできれば、よりセキュアじゃん!と思ったんですが、iFilterのルール設定側では、複数のルールパーツを組み合わせる際、AND と OR でしか設定できません。
つまり、stun.l.google.comルールパーツ && (ポート19302ルールパーツ || ..(略).. || ポート19309ルールパーツ ) という組み合わせができません。
なんので、DNS引き識別名リスト か、ポートか、どちらかの条件しか設定できないようです。