LoginSignup
2
0

More than 1 year has passed since last update.

Windows標準のssh.exeで謎のエラーが表示される理由を探る

Last updated at Posted at 2022-11-15

状況

最近のWindowsではコンパネ経由でOpenSSH(クライアント・サーバともに)をインストール1することが出来ます。

さっそく使ってみたんですがいい感じに辛いログが出る。

PS > ssh -V
OpenSSH_for_Windows_8.1p1, LibreSSL 3.0.2
PS > ssh hoge
ssh: Could not resolve hostname hoge: \202\273\202\314\202\346\202\244\202\310\203z\203X\203g\202\315\225s\226\276\202\305\202\267\201B
PS >

WindowsだしShift_JIS吐いていると踏んでdecodeしてみた。

Python 3.11.0 (main, Oct 24 2022, 18:26:48) [MSC v.1933 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> msg = b"\202\273\202\314\202\346\202\244\202\310\203z\203X\203g\202\315\225s\226\276\202\305\202\267\201B"
>>> print(msg.decode('shift_jis'))
そのようなホストは不明です。

はい。

原因

どこでエラー吐いてるのか、GitHubでエラーメッセージをキーにして検索するとシュッと見つかる。

		do_log2(loglevel, "%s: Could not resolve hostname %.100s: %s",
		    __progname, name, ssh_gai_strerror(gaierr));

で、このssh_gai_strerrorが何をしているかですが実装を見ると基本的にgai_strerrorを呼んでるだけ。WinSock版のgai_strerror2がMBCS返すと踏んだので試してみる。

#include <stdio.h>
#include <ws2tcpip.h>

int main()
{
    printf("[%s]\n", gai_strerrorA(EAI_NONAME));
}

実行結果は以下。

[そのようなホストは不明です。 ]

MBCS文字列の出自はわかった。

でもこれだと\202\273\202...って出てくる理由にはならないのでdo_logの呼び出しを追いかけていくと、strnvis()を呼んでるところが見つかる。これの実装はvis.cにあって、こいつがMBCS文字列を\0xxへ書き換えている。

どうなればいいか

WinSockのgai_strerrorは内部でFormatMessageを呼んでいると想定できて、FormatMessageが英語メッセージを返してくれれば良い。

FormatMessagedwLanguageId=0で呼ばれるとスレッドロケールを参照するので、SetThreadUILanguage を使って試してみる。

#include <stdio.h>
#include <ws2tcpip.h>

int main()
{
    SetThreadUILanguage(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
    printf("[%s]\n", gai_strerrorA(EAI_NONAME));
}
[No such host is known. ]

なのでスレッドロケールをen-USとかにすれば良くて、現状のソースを見ると、setlocale3してるところはあるけど呼ばれていない4

なので実装をいじるしかないわけですが、この謎表示は非ASCII圏では誰もが遭遇するので既に2020年(2年前…)にはissueが立っていました。

ということで、SetThreadUILanguageしてくれ~というコメントを書いておいたがどうなることやら。

  1. やり方についてはOpenSSH をインストールするを参照。

  2. MSDNのドキュメントはgai_strerrorA関数 (ws2tcpip.h)にある(ANSI版)。

  3. MSVCではsetlocaleしてもgai_strerrorの返事に変化がなかったので、CRTランタイムでスレッドロケールをいじってないように見える。

  4. main()で呼ばれるmsetlocale()utf8.cでの実装はsetlocale()を呼んでいますが、こいつはVSプロジェクトで弾かれていて、実際に呼ばれるのはcontrib/win32/win32compat/win32-utf8.cにある実装。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0