Open4

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

okuokuokuoku

汎用のトランスポートとしてWebRTCをブラウザから使ううえで障碍になるのは、ローカル同士の接続にmDNSを使っていることで、これがVPNを通過できないのでUDPが相互に疎通する環境でも通信ができないという点がある。

mDNS自体は無効にできるが、事前セットアップ必須なのでユーザビリティが悪い & Safariで安定して効かせる良い方法がない:

https://zenn.dev/okuoku/scraps/f7778fc9aae3c3

というわけで、いっその事TURNサーバーを配置してそこ経由で直接通信させるのが良いのではないか説。どうせVPN経由で同じところに集合しているからトラフィックとしては大きなロスは無いし。。ただ、VPN接続を提供しているのが4G(or 5G)ネットワークなのでパケットロス自体がそれなりにあり、リアルタイム性という意味ではあんまり旨くない。

okuokuokuoku

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だけ指定して、 iceTransportPolicyrelay にすると、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

とりあえず userpass でどうにか。。Firefoxでも特にエラーは出ないものの、 userpass が無い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

okuokuokuoku

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サーバーを置いたのでこの条件に合致する。