"unknown service", MSNメッセンジャー7.5の診断ツールには、「気をつけろ!」

仕事の関係のwebページについて、Meadowで編集してcygwinのlftpでアップしているが、ある日突然lftpを起動したらsocketをopenできないというエラーが表示された。おかしいと思い、色々試してみたらlftpだけでなくftptelnetも"unknown service"と言われて使えない。しかし、WindowsXPffftpDOS窓ftp.exeや、cygwin上のapacheは動作する、というわけのわからないトラブルに遭遇した。(そのときの日記)

状況をまとめておくと

  • cygwinからソケットを使うプログラムが動作しない
  • apache等のように設定ファイルでポート番号を指定するものは問題なく動作しているし、コマンドラインでポート番号を指定すると動作する
  • 何故か"%SystemRoot%\System32\drivers\etc\services"が参照できなくなってしまっている(perlやCなどでgetservbynameするプログラムを書くと確認できる)

この状況に対して、以下のような対処をしたが無効だった

  • %SystemRoot%\System32\drivers\etc\servicesのファイルを改行コードを変えて編集しなおしたりする
  • %SystemRoot%\System32\drivers\etc\servicesのファイルはcygwinではシンボリックリンクとなっているが、実体をコピーしてみる
  • %SystemRoot%\System32\drivers\etc\servicesのファイルの内容を編集して、ftp等を先頭に持っていってみる
  • cygwinを再インストールしてみる

情報を求めて世界中のwebやblogを探したが、解決策は見つけられなかった。しかし、同じ症状を経験している人が国内に数名存在していた。

ここにメッセージを残しておいたところ、りばにしさんより11/5にコメントをいただいた。それによると犯人はcygwinではなくMSNメッセンジャーで、それも「診断ツール」だった。

上のリンクに書かれている内容に従い解決した。(T T)

MSNメッセンジャー7.5の診断ツールを実行すると、「"マイ コンピュータ\HKEY_LOCAL_MACHINES\SYSTEM\CurrentControlSet\Services\Tcpip\Parametersに存在する"DataBasePath"という変数("services"の置かれている場所を格納している)の型」が、本来「REG_EXPAND_SZ(展開可能な文字列値)」でなければならないのが「REG_SZ(文字列値)」に変更されてしまうらしい(極悪!!!)。その結果、getservbynameはサービス名からポート番号を調べることができず、getservbynameを呼び出したアプリケーションがサーバへの接続を確立できずエラーとなる。

もし、同じ症状でこのページに飛んでこられた方は以下の手順をおためしください。

  1. レジストリエディタを起動する
  2. マイ コンピュータ\HKEY_LOCAL_MACHINES\SYSTEM\CurrentControlSet\Services\Tcpip\Parametersをたどる
  3. DataBasePathという変数が存在し、型がREG_SZとなっていることを確認する
  4. DataBasePathの変数の値(多くの場合は"%SystemRoot%\System32\drivers\etc"のようになっているはず)をコピーしておく
  5. 同じ場所にREG_EXPAND_SZ(展開可能な文字列値)という型の変数を新規作成する
  6. 作成した変数の値にコピーしておいた値を貼り付ける
  7. DataBasePath(REG_SZ)を削除する
  8. 新規に作成した変数は「新しい変数 #1」という名前になっているはずなので、DataBasePathに名前を変更する

この問題を解決してくれたりばにしさん(river24)に大感謝!

参考

推測だが、おそらくREG_EXPAND_SZとREG_SZの違いは%SystemRoot%を評価してC:\Windowsに展開してくれるかどうかの違いなのだろう。"messenger reg_expand_sz"のように検索すると上記のような情報が見つかるが、問題は症状からそのキーワードが思いつかない点にあるし、感染していても自覚しにくい点もやっかいだ。今回の件でわかったのだが、cygwin環境では/etc/servicesはWindowsのservicesへのシンボリックリンクにしているが、実際にはそのファイルを参照していない(より正確には、cygwinのgetservbynameライブラリは/etc/servicesを参照していない)。仕様と言ってしまえばそれまでだが、本来/etc/servicesを参照すべきだと思う。