🐡

discord bot 何もしていないのに壊れました... 【解決済み】

に公開

背景

先日,作成中の discord bot を走らせたところ,見慣れないエラーを吐きました.

voice.go:403:wsListen() voice endpoint c-nrt09-777cc959.discord.media:2083 websocket closed unexpectantly, websocket: close 4016: Unknown encryption mode.

この記事ではこのエラーの解決法と,その過程で学習した内容をメモしておきます.

忙しい人向け

自分の環境 (Docker Container from golang:1.24.6-alpine)では以下の2点を実行したところ,正常に動作しました.

  1. discordgo の最新版をインポート
  2. cs-certificates のインストール

エラー発生状況

このエラーは discordgo.ChannelVoiceJoin を実行時に出力されます.この関数自体は bot をボイスチャンネルに接続させるもので,内部で websocket のセッションを開始しています.この時点では,冒頭のエラーメッセージはこの websocket に関係してるっぽいな~程度しかわかりませんでした.(discordgo自体の機能は正常で,ボイスチャネルへの接続についても律儀に再接続とタイムアウトまでしていました.)
つまるところ問題はソースコードではなく,通信にありそうだなと目星をつけました.

エラー文の解読

OSSを勝手に使わせていただいている身分として,頼れるのはサーバが返してくれているエラーメッセージだけなので,こちらを読み解いていきます.とはいってもgoogle の検索窓に投げるだけ...

そこで見つけたのがこちら
https://github.com/bwmarrin/discordgo/issues/1657

内容としては「 discord サーバが websocket 使用時に用いる暗号の種類が変わったので,みんな最新版を使ってね」とのこと.自分の環境はすでに最新版だったので無関係....
ただ気づいたことがあったのはエラーメッセージのこの部分↓

c-nrt09-777cc959.discord.media:2083

上の issue で示されていたのは

warsaw10092.discord.media:443

この番号,もしかしてポート番号?

通信プロトコルとポート番号

通信プロトコルはそれぞれデフォルトのポート番号を持っています. HTTP なら 80 ,ssh なら 20 みたいな感じですね.
ここで,443 はSSL/TLSのポート番号なので,前述の issue のエラーは HTTPS もしくは WSS におけるエラーと推測されます.では 2083 は何かというと,どうやら RADSEC (RADIUS over TLS) サーバで使われているようです.

RADSEC (RADIUS over TLS)

RADSECは初耳だったので,こちらを参考にしました.どうやら インターネット上のサーバに接続する際に RADIUS 認証を行い,これを TLS で暗号化しているようです.
問題となるのは,この TLS 通信による接続要求時に用いる証明書周りの設定

[edit access]
user@host# radsec destination id-number tls-certificate certificate-name

ここで,認証局 (CA) を指定する必要があるんですね.
普通の環境であれば,インターネット接続時に代表的な認証局を記憶しています.が,今回の環境は...

Alpine!

まとめ

discord bot の開発中に (何もしていないのに) 生じたエラーの原因調査,解決の過程を書きました.
何がきっかけかはわかりませんが,サーバ認証時に必要な TLS 接続に設定する CA の情報を失ったことにより生じたエラーでした.
(そういえば先週Claudflareぶっ壊れてたっけ...)
連休が半分くらい消えましたが,解決してよかったです()

おまけ WebSocket Secure (WSS)

HTTPがTLSによる暗号化によってHTTPSを実現するように,WebSocketもTLSによって暗号化されます.これをWSSといいます.
このあたりの融通の利き方から見ても,しばらくはwebの時代が続きそうですね...

GitHubで編集を提案

Discussion