- Counter-Strikeの古い
No user logon 切断はCS2でも再現し、ゲーム開始直後にサーバーへあまりに早く接続すると、Steam IDの検証が始まらない可能性がある
- 核心は、
CS2.exe 起動中の levelload ループ がSteam3検証を終える前に早期終了し、サーバーが未検証のSteam IDで接続を処理してしまう点にある
- Esportalのログでは正常なユーザーでも
STEAM USERID validated が接続後約 1分20秒 で記録され、失敗したユーザーは2〜3分後に STEAMAUTH failure code 8 と NETWORK_DISCONNECT_STEAM_LOGON で切断された
- ゲームの再インストール、ファイル検証、Steam再起動、PC再起動、WiFi無効化では 根本原因 を直せず、CS2を先に起動してからメインメニューで5〜10秒待つ必要がある
- Esportalは2024年1月10日に
CS2.exe が完全に初期化される前に steam://connect/<IP>:<Port> を実行していた動作を修正し、その後この関連チケットの比率は0%に落ちた
長年繰り返されてきた No user logon 現象
- Counter-Strikeの
No user logon 切断は、プレイ中にランダムに発生する問題として知られており、2008年から2023年まで複数のフォーラムやValve公式サポートフォーラムで繰り返し報告されてきた
No user logon と一部の投稿で見られる No steam logon は、技術的には同じ根本原因の別名である可能性がある
- インターネット上で広く出回っている解決策では根本原因を直せない
- ゲームの再インストール
- ゲームファイルの検証
- Steamの再起動
- コンピューターの再起動
- WiFiの無効化
- CS2は2023年9月27日にCS:GOを置き換え、一般ユーザーはCS:GOをもうプレイできなくなった
- ValveのHackerOneバグバウンティ対象には
cs2.exe が含まれておらず、CS2 Limited Testの報告も対象外と表示されていた
Esportalで急増した報告
- Esportalは過去のCS:GOでもこの問題に悩まされており、記録上の最初の発生は 2019-11-15 19:15:32 CET、最後のCS:GOでの発生はCS2に置き換えられる前日の 2023-09-26 21:38:01 CET だった
- CS2初期には問題が消えたように見えたが、2024年1月第1週にユーザー報告が増加した
- 2024-01-03: 1日のチケットのうち6%
- 2024-01-05〜06: 18%
- 2024-01-07: 23%
- 2024-01-08: 10%
- 2024-01-09: 9%
- 報告時間帯は主に 13〜17時 CET に集中しており、Valveのあるワシントン時間では 04〜08時 に相当した
- 以前は報告が1日全体に均等に分布していたが、新たに観測された問題は特定時間帯に集中していた
- Esportal外のプレイヤーも同じ問題に遭遇しており、特定プラットフォーム固有の問題ではなかった
症状: 遅れるSteam検証と消えるスキン
- 観測された
No user logon エラーは、プレイヤーがゲームサーバーに接続した 2〜3分 後に発生し、この時間間隔はかなり一定していた
- 同僚は「ゲームに入ってから数分間、CS2でスキンが表示されない」と話しており、Esportal外のプレイヤーもスキン欠落を報告していた
- スキンはSteam IDの所有権と結びついているため、個人スキンが見える前までは、プレイヤーがSteam経由で正しく認証されていない可能性がある
- 正常なユーザーのログでは、接続後約 1分20秒 で
STEAM USERID validated が記録されていた
16:39:55: "Alice<1><>" connected
16:41:14: "Alice<1><>" STEAM USERID validated
17:17:32: "Alice<1><CT>" disconnected (reason "NETWORK_DISCONNECT_DISCONNECT_BY_USER")
- 2024年1月3日以前の古いログでは、Steam検証は接続後 2〜3秒 以内に完了していた
- ワシントンの夜間帯では直接再現できたが、ワシントンの日中には再現しなかった
NETWORK_DISCONNECT_STEAM_LOGON と failure code 8
- 失敗したユーザーのログでは、
STEAMAUTH: Client Bob received failure code 8 の直後に NETWORK_DISCONNECT_STEAM_LOGON で接続が切られていた
16:40:13: "Bob<6><>" connected
16:43:02: STEAMAUTH: Client Bob received failure code 8
16:43:02: "Bob<6><TERRORIST>" disconnected (reason "NETWORK_DISCONNECT_STEAM_LOGON")
NETWORK_DISCONNECT_STEAM_LOGON は、ユーザーが目にする No user logon メッセージの内部識別子だと推定される
libengine2.so で STEAMAUTH: Client %s received failure code %d という文字列を見つけ、CS:GO流出ソースの sv_steamauth.cpp とリバースエンジニアリング結果をあわせて比較した
- CS2の関連関数は
eAuthSessionResponse 値に応じてクライアントを切断する
1: k_EAuthSessionResponseUserNotConnectedToSteam
7: k_EAuthSessionResponseAuthTicketInvalidAlreadyUsed
8: k_EAuthSessionResponseAuthTicketInvalid
- failure code
8 は、Steam3検証失敗時に見られる k_EAuthSessionResponseAuthTicketInvalid に対応するとみられる
Steam3検証フロー
- ゲームクライアント
CS2.exe はゲームサーバーへ接続する際、自分の Steam ID を送る
- ゲームサーバーは、そのSteam IDが有効か、ゲームを所有しているかを確認するためSteam3サーバーに問い合わせる構造になっている
- 検証応答を待っている間も、プレイヤーはサーバー上でプレイを続けられるが、個人スキンは表示されない可能性がある
- Steam3サーバーが「yes」を返すと、ゲームサーバーはその情報を信頼し、スキンのような個人情報を適用できる
- Steam3サーバーが「no」を返すと、ゲームサーバーはクライアントを
NETWORK_DISCONNECT_STEAM_LOGON で切断する
- ワシントンの夜間帯にSteam3応答が遅くなる状況では、検証完了まで約 1分20秒 かかっていた
CS2.exe の信頼検証とSteamクライアント
- Steam IDが有効であることだけでは、その
CS2.exe インスタンスが同じマシンでログイン中のSteamアカウントのゲームであることを証明できない
CS2.exe は同じマシン上の Steam.exe と接続し、自分が送ったSteam IDが現在ログイン中のSteamアカウントと一致するか確認してもらう必要がある
Steam.exe が一致を確認すると、Steam3サーバーにそのSteam IDがCS2に対して有効だという情報を一時保存する
- Steam3が「no」を返しうる候補のうち、実際の問題に近いものは次の2つに絞られる
CS2.exe インスタンスが信頼されていない
- Steam3サーバーがその
CS2.exe インスタンスに対するSteam ID情報をまだ知らない
クライアント側の手がかり: NETWORK_DISCONNECT_LOOPSHUTDOWN
- 失敗ログには
NETWORK_DISCONNECT_STEAM_LOGON の前に NETWORK_DISCONNECT_LOOPSHUTDOWN が先に現れる
16:40:03: "Bob<6><>" connected
16:40:08: "Bob<6><Unassigned>" disconnected (reason "NETWORK_DISCONNECT_LOOPSHUTDOWN")
16:40:13: "Bob<6><>" connected
16:43:02: STEAMAUTH: Client Bob received failure code 8
16:43:02: "Bob<6><TERRORIST>" disconnected (reason "NETWORK_DISCONNECT_STEAM_LOGON")
NETWORK_DISCONNECT_LOOPSHUTDOWN の後、ゲームは5秒後に自動で再接続を試みる
- この最初の切断はゲームサーバーではなく、
CS2.exe 自身 が開始した切断だった
- したがって根本原因はゲームサーバー側ではなく、ゲームクライアント側にあった
Source 2の levelload ループと初期化順序
- Source 2エンジンは一度に1つのアクティブループを実行し、ループは特定の目標が完了するまでバックグラウンド作業とユーザー入力処理を繰り返す
CS2.exe 起動後、最終的に実行されるループは、実際のメニュー操作とゲームプレイを担当する game ループ である
- コンソール出力では、
game ループへ切り替わる直前にSteam認証状態が OK と表示される
[SteamNetSockets] AuthStatus (steamid:<redacted>): OK (OK)
[Client] CL: CLoopModeLevelLoad::MaybeSwitchToGameLoop switching to "game" loopmode with addons ()
[EngineServiceManager] SwitchToLoop game requested: id [1] addons []
levelload はCS2起動時に実行される初期化ループで、実際のマップでなくてもイントロ動画やメインメニューのような初期画面を読み込んでいるとみられる
levelload の最後の作業の1つが、CS2.exe から Steam.exe を経由してSteam3検証を開始することだった
バグの直接原因
- CS2は
levelload ループが正常に終了して初めて完全に初期化された状態とみなせる
levelload 初期化が終わる前に早期終了すると、Steam3検証が始まらない
- この状態の
CS2.exe インスタンスは壊れた状態になり、単純にCS2を再起動するまで回復しない
- バグの流れは次のとおり
CS2.exe 起動
levelload ループ開始
- Steam3検証を開始する前に
levelload が早期終了
game ループが未検証のSteam IDでゲームサーバーへ接続
- ゲームサーバーがSteam3へ確認
- 最大約 2分50秒 後に失敗応答を受けて
No user logon で切断
- この問題はCS2の例と名称を基準に扱っているが、CS:GOやCounter-Strike: Sourceにも同等のバグがあり、技術名と方式だけが異なる
バグを引き起こす接続方法
- 問題はCS2の起動方法による 競合状態(race condition) である
- バグをほぼ確実に引き起こす方法は、CS2が開いていない状態からすぐゲームサーバーへ接続することだ
- 危険な接続方法は次のとおり
- ゲーム外部のサーバーブラウザーから、CS2が起動していないか起動直後の状態でサーバー接続
- Steamフレンドリストから、CS2が起動していないか起動直後の状態でフレンドに接続
steam://connect/127.0.0.1:27015 のようなSteamブラウザープロトコルで外部から直接接続
- CS2を起動したあと完全に初期化される前に上記の操作を行うと、発生しやすくなる
- 原因比率は「Counter-Strikeの起動方法90%、コンピューター速度3%、ユーザーの速さ3%、月の状態3%、実際のユーザー設定問題1%」という比喩でまとめられている
実際の解決方法
- やってはいけない対処
- ゲームの再インストール
- ゲームファイルの検証
- Steamの再起動
- コンピューターの再起動
- WiFiの無効化
- CS2起動前に外部からゲームサーバーへ接続
- その代わり、CS2を先に起動し、ゲームサーバーへ接続する前に十分待つ必要がある
- 目安はゲームコンソールが見えるまで待つか、イントロ動画が表示されたあと 5〜10秒 待つことだ
- 確実に確認するには、CS2起動後にゲームコンソールで
status を入力し、次の行を確認すればよい
[EngineServiceManager] @ Current : game
Esportalの修正結果
- 失敗したユーザー
Bob が最初の試行から9分後に検証成功した理由は、CS2を再起動しており、そのときは運悪くバグが発生しなかったからである
- 一度Steam IDが検証されれば、同じゲームインスタンスではSteamクライアントを閉じない限り後から失敗することはない
- Esportalは2024年1月10日まで、
CS2.exe プロセスが出現した直後、完全初期化前でも steam://connect/<IP>:<Port> でマッチメイキングサーバーへ接続させていた
- その動作を修正して全Esportalプレイヤーに展開すると、関連するユーザーチケットは止まった
- 1日のチケットに占める
No user logon の比率は2024-01-07に 23% まで上がったが、2024-01-10から2024-01-12までは 0% に落ちた
1件のコメント
Hacker News の意見
図のフローは、Steam が Session Tickets と呼んでいる方式に近く、実際にはもう少し微妙です。
ゲームクライアントが Steam サーバーにセッションチケットを要求したあと、ゲームサーバーには自分が特定の Steam ID であることを証明するチケットを渡します。
その後ゲームサーバーは、Steam の Web API にオンラインで確認し、チケットが複数回使われていないか、改ざんされていないかを検証する必要があります。
CS2 クライアントがセッションチケットを取得する過程での遅延レスポンスを適切に処理できていないように聞こえます。
フローはこちらに詳しく載っています: https://partner.steamgames.com/doc/features/auth#3
記事の図のように動作するなら、攻撃者が被害者の Steam ID でサーバー参加を競合できることになり、かなり懸念されます。
問題は、ゲームが実際にセッションチケットを作る前、または遅い Steam サーバーの応答を待っている間に中断され、チケットなしでゲームサーバーに接続してしまう点にあるようです。
記事は素晴らしいですが、追跡過程と結論が完全にはかみ合っていません。
「Counter-Strike の起動方式: 責任比率 90%」と言いつつ、世界中のプレイヤーが Esportal の外でも同じ問題を経験し、ワシントンの深夜メンテナンスが原因だと確認したという部分は、同時に真であるとは考えにくいです。
責任の 90% が起動方式にあるなら、問題がメンテナンス時間帯に分布することはなかったはずです。
核心は「ゲームループが始まる直前に Steam ID 検証が開始される」と「levelload の初期化が終わらないと Steam3 検証は最後の段階なので開始されない」という部分に見えます。
つまりメンテナンス時間帯に steam3 サーバーが非常に遅くなると、この処理が長引き、その間にゲームを開始してループを断ち切ってしまう可能性が高まります。
なので「Counter-Strike の起動方式」も正しいのですが、「月の状態: 責任比率 3%」のような表現は、実質的にはメンテナンス時間帯を指していることになるので、少しずれています。
助言にも「CET 13〜17時は Valve のメンテナンス時間帯なので数分余計に待て」を含めるとよさそうです。
いずれにせよこの問題は経験したことがあり、「少し待ってロードを終わらせる」という解決策は、これまで聞いた中で最も実用的で筋が通っています。
CS:GO でもメンテナンス時間帯とは関係なく同じ問題があり、CS2 ではメンテナンス時間帯にだけ観測されました。
結局 CS:GO と CS2 のバグの性質が違っていた可能性もありますが、CS:GO は CS2 に置き換えられてしまったため、もう証明する方法がありません。
昔、Steam がなかった頃、友人が接続しているサーバーを見てすぐ入れるように、アクティブプレイヤーとスコア一覧を表示するツールを作ったことがあります。
そのツールを作っている途中、テストしていたサーバーに不正なパケットを送ったらサーバーが落ちました。
Delphi で書いたソースコードがまだあるのですが、10年前のバグが残っているなら、これが今でもサーバーを落とせるのか気になります。
本当のバグは、認証完了が非 LAN マルチプレイヤー開始の必須条件になっていない点です。
より高速で堅牢な方式は、Steam クライアントが Valve から数時間有効な署名付きトークンを受け取って保持し、ゲームサーバーに接続するたびにそのトークンを送ることかもしれません。
ゲームサーバーは、Valve が発行しサーバーコンテンツと一緒に配布される公開証明書でローカルに検証すればよいのです。
いくつかの段落は「帽子の上にさらに帽子を載せている」感じです。
すでにミームっぽい段落の上に皮肉をさらに積み重ねていて、控えめなときのほうが効く要素が過剰に感じられます。
他の人も言っているように、もっと早く本題に入ったほうがよいです。
とても楽しく読みました。ゲームクライアントが突然クラッシュする理由も同じ方法で調査できるのか気になります。
実行ファイルの整合性チェックが実行中にも走るのか、そのうちの一つが実行中に失敗すると別の切断メッセージが出るのかも気になります。
GTA V のロード時間が長すぎた問題を分析した記事のように、報われる価値がありそうです: https://nee.lv/2021/02/28/How-I-cut-GTA-Online-loading-times...
クラッシュは理論上調査できますが、Valve はクラッシュレポートをディスクに保存せず、サーバーへ送ります。
デバッガを付けた状態でリアルタイムに捕まえられなければ分析はより難しく、VAC のせいで厄介ですが不可能ではありません。VAC を無効にすればよいです。
記事の冒頭に、問題解決を検索してたどり着いた人向けの要約を置いているのは配慮があるように見えます。
しかしその直後に「やってはいけないこと」を述べ、実際にできる対処はキロメートル級の記事の真ん中にある一文に隠している形です。
回避策を要約に入れたほうがよいです。
Strunk and White 式の文章作法の好みが頭に染み付いているので言うだけで、望むなら無視して構いません。
フィードバックを求めているなら、文章をはるかに直接的で簡潔に強く編集することを勧めます。
長い記事を書くことはできますが、数分経つと補足説明や逸話が積み重なり、中心の流れをかなり早く見失いました。
そこに Inception 参照画像まで入ると、情報伝達記事というより、互いに関係のない内容が集まっている感じが強くなります。
何を言いたいのかを考え、それを言い、その後戻って本当にそれだけを言ったか確認すればよいです。
残りは文章執筆ではなくタイピング練習に近いです。言うことが3〜4個なら、ただそれだけを言えばよいです。
記事は素晴らしかったですが、いくつか疑問が残ります。
levelloadloop はゲーム起動時にだけ実行され、サーバー参加やマップロード時には実行されないのでしょうか?
問題が Steam 認証プロセスが始まる前にループが終了することなら、メンテナンスによる遅延はなぜ重要になるのでしょうか?
このループ名は Portal のようなシングルプレイヤーゲームと関係しているように見え、そうしたゲームではレベルを切れ目なく切り替えるため、この名前のほうがずっと自然です。
2つ目は説明に穴があるのは確かで、答えは分かりません。
ただしこの方法で問題が直ることは確かです。結論の細部が不完全である可能性は高いですが、今はこれ以上深く掘り下げる必要は感じていません。
Valve の報奨金プログラムの文言には「Steam プラットフォームと、Valve が開発・配信した現在のゲーム」が含まれると書かれています。
また、2023年6月14日午前10時 PDT 以降の CS:GO の新規報告は対象外で、CS2 Limited Test の報告も現在は対象外だと書かれています。
Valve がセキュリティに弱いのは確かですが、HackerOne の説明全体を広めに読むと、個人的には対象内と見ます。
「Scope」タブで
csgo.exeを除外するよう更新していないので、そのタブだけでは信頼しにくいという意味です。それでも Valve はぜひその部分を更新すべきです。
それでも結論には同意しますし、筋は通っています。