nest: TCPのTURNでWebRTCのVPN越えができるか検証したい

汎用のトランスポートとしてWebRTCをブラウザから使ううえで障碍になるのは、ローカル同士の接続にmDNSを使っていることで、これがVPNを通過できないのでUDPが相互に疎通する環境でも通信ができないという点がある。
mDNS自体は無効にできるが、事前セットアップ必須なのでユーザビリティが悪い & Safariで安定して効かせる良い方法がない:
というわけで、いっその事TURNサーバーを配置してそこ経由で直接通信させるのが良いのではないか説。どうせVPN経由で同じところに集合しているからトラフィックとしては大きなロスは無いし。。ただ、VPN接続を提供しているのが4G(or 5G)ネットワークなのでパケットロス自体がそれなりにあり、リアルタイム性という意味ではあんまり旨くない。

coTurn の起動 と proxy
docker run --rm -it -p 3478:3478 docker.io/coturn/coturn turnserver \
-n -v --no-udp --no-stun \
-u user:pass -a \
-L 0.0.0.0 -E 0.0.0.0 -X 192.168.1.10/0.0.0.0
ProxyはとりあえずSSHのポート転送で。ポート転送したポートをサーバーにするには SSHサーバー側で GatewayPorts
https://man.openbsd.org/sshd_config#GatewayPorts の設定が必要。
ssh -R 192.168.1.10:3478:127.0.0.1:3478 -N oku@192.168.1.10
とりあえず専用のcodePen https://codepen.io/okuoku/pen/emNGmBL を書いて試してみた。これでdataChannelが確立できるのは確認した。
const ICE_SERVERS =
{"iceServers":
[{"urls":
["turn:192.168.1.10:3478?transport=tcp"],
"username":"user","credential":"pass"}],
"iceTransportPolicy":"relay"};
こういう感じでturnだけ指定して、 iceTransportPolicy
を relay
にすると、TURN経由でのみ接続する。
UDP relayが必須
34: (16): INFO: session 001000000000000001: realm <localdomain> user <>: incoming packet ALLOCATE processed, error 442: UDP Transport is not allowed by the TURN Server configuration
34: (16): INFO: session 001000000000000001: realm <localdomain> user <>: incoming packet message processed, error 442: UDP Transport is not allowed by the TURN Server configuration
34: (18): INFO: session 003000000000000001: realm <localdomain> user <>: incoming packet ALLOCATE processed, error 442: UDP Transport is not allowed by the TURN Server configuration
34: (18): INFO: session 003000000000000001: realm <localdomain> user <>: incoming packet message processed, error 442: UDP Transport is not allowed by the TURN Server configuration
WebRTCではTCPでTURNに接続できるけど実際にリレーさせるのは常にUDPなので、 coturn側で --no-udp-relay
できない。
UsernameとPasswordが必須!?
Chromeでは以下のようなエラーが出ることがあった。
Error creating offer: InvalidAccessError: Failed to construct 'RTCPeerConnection': ICE server parsing failed: TURN server with empty username or password
とりあえず user
と pass
でどうにか。。Firefoxでも特にエラーは出ないものの、 user
と pass
が無いTURNサーバーは拒否するようだ。
403
NAT配下でcoturnを動かすと403エラーになる。
490: (21): INFO: session 005000000000000001: realm <localdomain> user <user>: incoming packet ALLOCATE processed, success
490: (21): INFO: session 005000000000000001: realm <localdomain> user <user>: incoming packet CREATE_PERMISSION processed, error 403: Forbidden IP
490: (21): INFO: session 005000000000000001: realm <localdomain> user <user>: incoming packet message processed, error 403: Forbidden IP
516: (17): INFO: session 001000000000000001: realm <localdomain> user <user>: incoming packet CREATE_PERMISSION processed, error 403: Forbidden IP
516: (17): INFO: session 001000000000000001: realm <localdomain> user <user>: incoming packet message processed, error 403: Forbidden IP
SOにそのものズバリの回答があった https://stackoverflow.com/questions/44996545/why-my-turn-server-doesnt-work/67180626#67180626 。マッピングを明示的に指定する必要がある。 -X 192.168.1.10
→ -X 192.168.1.10/0.0.0.0
。

FirefoxでTURNサーバーを使ってくれない
WebRTC: ICE failed, add a STUN server and see about:webrtc for more details
のようなメッセージがコンソールに出るのに、TURNサーバーを使う様子がない。で、 https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ を使ってねっとり試したところ、 "Acquire microphone/camera permissions" のチェックで挙動がかわるようだ。
というわけで、コンソールで
await navigator.mediaDevices.getUserMedia({audio: true});
を実行してから再度試すと正常に接続した。 ...どういう事。。?RFC8828で言うところのdefault routeしか使わないモード https://www.rfc-editor.org/rfc/rfc8828.html (Mode 2) になるって事なのかな。。つまり、TURNサーバーがLAN上で、かつ、default routeに居ない場合は使われないということになる。今回はWSL2上にTURNサーバーを置いたのでこの条件に合致する。