mDN Wrapper
実現方法 - Wrapper DLL
ラッパーDLLは、アプリケーションと元のDLLとの間に割り込んで、 アプリケーションからのDLLの呼び出しを横取りして、 本来のDLLとは異なった処理をさせるものです。
アプリケーションからのDLLの呼び出しはラッパーに渡されます。 ラッパーはそこで、付加的な処理を行なって、 元のDLLのエントリを呼び出します。 また、元のDLLの処理結果は一旦ラッパーに返され、 ここでも付加的な処理を行なって、 最終的な結果がアプリケーションに返されることになります。
mDN wrapperでは、WINSOCK DLLの
WSOCK32.DLL(WINSOCK V1.1)WS2_32.DLL(WINSOCK V2.0)
に対するラッパーDLLを提供して、 多言語ドメイン名の名前解決ができるようにします。
注: 16ビット版のWINSOCK (WINSOCK.DLL)は対象外です。
処理対象のAPI
mDN WrapperはWINSOCKの名前解決に関連したAPIについてのみ付加的な処理を行ないます。 処理の対象となるWINSOCK APIは以下のものです。
WINSOCK 1.1, WINSOCK 2.0 の両方にあるもの:
gethostbyaddrgethostbynameWSAAsyncGetHostByAddrWSAAsyncGetHostByName
WINSOCK 2.0 だけにあるもの:
WSALookupServiceBeginAWSALookupServiceNextAWSALookupServiceEnd
アプリケーションによっては、 これらのAPIを使わないで独自にドメイン名の解決を行なうものもあります。 例えば、nslookupは、これらのAPIを使わないで、 内部で独自にDNSリクエストの生成、解釈を行なっています。 当然のことながら、これらのアプリケーションについては、 mDN Wrapperでは多言語化対応させることはできません。
それに対して、mdnsproxyはネットワーク上でDNSのリクエスト、 レスポンスについて多言語化しますので、 これらのアプリケーションについても多言語化させることができます。 必要に応じて適時使い分けるといいでしょう。
注: WINSOCK 2.0には、
WIDE CHARACTER ベースの名前解決のAPIとして
WSALookupServiceBeginW、
WSALookupServiceNextW
もありますが、これらについてはラップしません。
これらのAPIはマイクロソフト仕様による国際化に対応したものですから、
そのフレームワーク上で使うべきものです。
これらについてはmDNkitによって他の多言語フレームワークに変換してしまうのは危険ではないか、
と判断しました。
処理対象外のAPI
上記以外のWINSOCK APIについては、mDN Wrapperは何もせず、 元のWINSOCK APIを呼び出します。
mDN Wrapperでは、元のWINSOCK DLLを名前を変えてコピーし、 それを呼び出すように作られています。
wsock32.dllwsock32o.dllに改名ws2_32.dllws2_32o.dllに改名
ラッパーDLLは元のWINSOCK DLLと同じ名前で作成されます。 従ってmDN wrapperがインストールされた状態では、
wsock32.dll- mDN Wrapper for WINSOCK V1.1
ws2_32.dll- mDN Wrapper for WINSOCK V2.0
wsock32o.dll- Original WINSOCK V1.1 DLL
ws2_32o.dll- Original WINSOCK V2.0 DLL
となります。
非同期 API
ドメイン名の変換は、以下のタイミングで行なわれる必要があります。
- DNSへのリクエスト時
- ローカルエンコーディングから DNSエンコーディングへ変換
- DNSからの応答受信時
- DNSエンコーディングからローカルエンコーディングへ変換
同期APIにおいては、 ローカルエンコーディングからDNSエンコーディングへの変換は、 元のAPIを呼び出す前に行われ、 DNSエンコーディングからローカルエンコーディングへの変換は、 元のAPIから復帰してきたところで行なわれます。
しかし、WINSOCKの以下のAPIは非同期APIで、 DNSからの応答受信前に復帰してしまいます。
WSAAsyncGetHostByAddrWSAAsyncGetHostByName
これらのAPIにおいては、名前解決の完了は、 Windows へのメッセージによって通知されます。 このため、 DNSエンコーディングからローカルエンコーディングへの変換を行なうには、 ラッパーは通知先のウィンドウプロシジャのメッセージキューをフックして、 この完了メッセージを捕獲する必要があります。
そこで、非同期APIが呼び出された場合には、mDN Wrapperは、 通知先のウィンドウプロシジャ(これはAPIのパラメタで指示されます)にフックを設定します。 フックが完了メッセージ(これもAPIのパラメタで指示されます)を検出したなら、 フックは結果の格納領域(これもAPIのパラメタで指示されています)のドメイン名を、 DNS側のエンコーディングからローカルエンコーディングに変換するものとします。
Wrapper DLLのインストール
WINSOCK DLLはWindowsのシステムディレクトリに置かれています。 WINSOCKを確実にラップするには、システムディレクトリにおいて 次のことを行なう必要があります。
オリジナルWINSOCK DLLの名前の変更:
ren wsock32.dll wsock32o.dll
ren ws2_32.dll ws2_32o.dll
ラッパーDLLの導入:
copy somewhere\wsock32.dll wsock32.dll
copy somewhere\ws2_32.dll ws2_32.dll
copy another DLLs also
しかし、 システムディレクトリでこのようなDLLの置き換えを行なうのは大変危険な操作になります。
- DLLを入れ替えた状態でもういちど同じ操作を行なうと、 オリジナルのWINSOCK DLLが失われてしまうことになります。
- サービスパックやアプリケーションなどでWINSOCK DLLを再導入するものがありますが、 これによってもWINSOCKが利用不能になる ことがあります。
このような状態になると、ネットワーク機能が全く使えなくなったり、 最悪はWindowsの起動すらできなくなる可能性があります。
そこで、mDN Wrapperでは、 上のようなシステムレベルのラップではなく、 アプリケーションに対するラップを基本機能として提供するものとします。
Windowsにおいて、DLLは基本的には
- アプリケーションのロードディレクトリ
%SystemRoot%\System32%SystemRoot%PATHで指示されるディレクトリ
の順序で検索されて、最初に見つかったものがロードされます。 ですから、一般的には、 DLLをアプリケーションのロードディレクトリにインストールすれば、 そのアプリケーションからのWINSOCKの呼び出しをラップすることができます。
ただし、いくつかのアプリケーション、DLLでは、 検索パスを経由せずに特定のDLLをリンクするようになっているものがあります。 このような構成のアプリケーション、 DLLが使われた場合にはmDN Wrapperでは対処することはできません。
注: Netscapeは特定DLLにバインドされているようで、 アプリケーションディレクトリへのインストールではラップできません。 WINSOCK DLL自体もシステムディレクトリの関連DLLにバインドされているようです。 一方、Internet ExploreやWindows Media Playerは標準のサーチパスに従っているので、 ラップすることができます。
エンコーディングの変換位置
WINSOCK 2.0をサポートしているWindowsには、 WINSOCKの1.1と2.0のそれぞれに対応するDLLがあり、 WINSOCK 1.1のAPIの呼び出しは 2.0の同じエントリにリダイレクトされるようになっています。
この場合には1.1に対する呼び出しも2.0に対する呼び出しも、 ともにV2.0用のDLLに渡されるので、 2.0用のラッパーDLL側だけで エンコーディングの変換を行なうようにするべきでしょう。
一方、WINSOCK 1.1しかサポートしていない場合(Win95)には、 1.1に対応したDLLしかありません。
この場合には必然的に1.1用のラッパーDLLで エンコーディングを変換しなければなりません。
mDN Wrapeprがwindowsのシステムディレクトリにインストールされた場合には、 上の通りに動作するので、
- WINSOCK 2.0がある場合は、2.0ラッパーで変換
- WINSOCK 1.1だけしかない場合は、1.1ラッパーで変換
とする必要があります。
しかし、アプリケーションディレクトリにインストールされた場合には動作が変わってきます。 Windows付属のWINSOCK 1.1 DLLは、 システムディレクトリのWINSOCK 2.0にバインドされているため、 アプリケーションディレクトリ側のWINSOCK 2.0ラッパーDLLにはリダイレクトされてきません。 このため、アプリケーションディレクトリへのインストールにおいては、 1.1 DLL、2.0 DLLの両方でエンコーディングを変換する必要があります。 ただしWindows2000付属のWINSOCK 1.1 DLLは動作が異なり、 アプリケーションディレクトリ側のWINSOCK 2.0ラッパーDLLにリダイレクトされるようです。
このようなDLL間のバインディングはドキュメントされていませんので、 環境、バージョンによっては異なった動作をするかも知れません。 そこでmDN Wrapperでは、レジストリ値によって、 ラッパーDLLのどこで変換を行なうかを決定するようにして、 インストール先による差異、 あるいはバージョンによる差異を吸収するようにします。
mDN Wrapper用のレジストリ設定は
HKEY_LOCAL_MACHINE\SOFTWARE\JPNIC\MDN
HKEY_CURRENT_USER\SOFTWARE\JPNIC\MDN
以下に配置されます。
エンコーディング変換を行なう位置については、
この直下のレジストリ値 Where(REG_DWORD) によって決定します。
- 0
- WINSOCK 1.1、WINSOCK 2.0の両方で変換する
- 1
- WINSOCK 2.0があれば、WINSOCK 2.0だけで変換する。WINSOCK 1.1だけの場合にはWINSOCK 1.1で変換する
- 2
- WINSOCK 1.1だけで変換する
- 3
- WINSOCK 2.0だけで変換する
Windows2000以外で アプリケーションディレクトリにインストールする場合には「0」を、 システムディレクトリにインストールする場合およびWindows2000でアプリケーションディレクトリにインストールする場合には「1」を設定する必要があります。 もしレジストリ値が存在しない場合には「0」を想定します。 これはアプリケーションディレクトリへのインストールを標準としたものです。
変換元/先のエンコーディング
ラッパーDLLでは、解決しようとするドメイン名を、 マシンのローカルエンコーディングからDNSサーバのエンコーディングに変換し、 また、DNSが返してきたドメイン名 (DNSサーバのエンコーディング) をマシンのローカルエンコーディングに戻します。
現在、DNS側の多言語化エンコーディングについては、 いくつもの方式が提案されています。 ラッパーDLLはそれらのDNS側エンコーディングのどれかひとつに変換するように構成されます。 このDNS側エンコーディングは設定ファイルで指定することができます。
一方、アプリケーションが使用しているローカルエンコーディングは、 通常はプロセスのコードページから求めます。 ラッパーDLLが使用するiconvライブラリは、 windowsのコードページ名をエンコーディング名として受付けることができるので、 コードページ名をそのままローカルエンコーディング名として使用します。
しかし、アプリケーションによっては、 特定の多言語化エンコーディングでドメイン名をエンコーディングしてしまうものもあります。 例えば、IEではドメイン名をUTF-8 で表記するように指示することができるようになっています。 UTF-8 によるエンコーディングは、 提案されている多言語化方式のひとつですが、 多言語化されたDNSサーバは他のエンコーディングしか受付けないかも知れません。
このような状況に対処するため、mDN Wrapperは、 ローカルエンコーディングとしてプログラム特有のエンコーディングも受付けることができるようにします。 このようなプログラム特有のローカルエンコーディングはレジストリ記載されるものとします。
mDN Wrapper用のプログラム特有のレジストリ設定は
HKEY_LOCAL_MACHINE\SOFTWARE\JPNIC\MDN\PerProgHKEY_CURRENT_USER\SOFTWARE\JPNIC\MDN\PerProg
以下に、
プログラム名(実行モジュールファイル名)をキーとして配置されます。
例えば、Internet Explore の場合には、
実行モジュール名の IEXPLORE をキーとして
HKEY_LOCAL_MACHINE\SOFTWARE\JPNIC\MDN\PerProg\IEXPLORE
以下に置かれます。 ローカルエンコーディング名は、
レジストリ値
Encoding(REG_SZ)
で指定します。これもlibmdnで認識されるものでなければなりません。 アプリケーションプログラム特有のエンコーディング名(デフォルトのエンコーディング以外を必要とする場合)を指定します。
ログ
mDN Wrapperが期待した動作をしない場合、 動作のログは問題解決に非常に役立ちます。 mDN Wrapperでは、レジストリの設定により、 以下の設定が可能です。
- ログレベル
- ログファイル
ログレベル、ログファイルともに次のレジストリの下で設定されます。
HKEY_LOCAL_MACHINE\SOFTWARE\JPNIC\MDN
HKEY_CURRENT_USER\SOFTWARE\JPNIC\MDN
ログレベルは
レジストリ値
LogLevel(REG_DWORD)
で指定します。定義されている値は次の通りです。
- -1 (0xFFFFFFFF)
- [None] ログを一切出力しない
- 0
- [Fatal] 致命的エラーのみ出力
- 1
- [Error] 致命的でないエラーも出力
- 2
- [Warning] 警告メッセージも出力
- 3
- [Info] エラー以外の情報も出力
- 4
- [Trace] プログラムのトレース情報も出力
なお、このレベル指定はmDN Wrapperが使用しているMDNライブラリの出力するログのレベル指定です。 ログにはこの他mDN Wrapper自身が出力するものがありますが、 こちらはレベル指定はできず、 単にオン・オフを切り替えるだけです。 -1を指定した場合にはオフ、 それ以外の値を指定した場合にはオンになります。 デフォルトは-1です。
ログファイルはログを出力するファイルのパス名を指定するもので、
レジストリ値 LogFile (REG_SZ) で指定します。
デフォルトはmDN
Wrapperをインストールしたディレクトリの下のmdn_wrapper.log です。
なお、 ログレベルとログファイルは設定プログラムを使用しても設定することができます。
レジストリ設定 - まとめ
レジストリの優先順位
mDN Wrapperの設定情報は、HKEY_LOCAL_MACHINE、
HKEY_CURRENT_USERの
Software\JPNIC\MDN
以下に格納されます。
mDN Wrapperは最初にHKEY_LOCAL_MACHINEの設定を読み込み、
HKEY_CURRENT_USER側にも設定があれば、
これで上書きします。
通常は、HKEY_LOCAL_MACHINE側だけを設定します。
ユーザ個別に異なった設定を使いたい場合のみ、
HKEY_CURRENT_USERを設定するようにしてください。
特に、設定プログラムは常にHKEY_LOCAL_MACHINEの設定しか読み書きしません。
設定ファイルを使用して設定を行う場合には気をつけてください。
レジストリキー
全体の共通の設定と、プログラム個別設定とがあります。
共通定義:
Software\JPNIC\MDN\Where変換位置 Software\JPNIC\MDN\ConFile設定ファイル名 Software\JPNIC\MDN\LogLevelログレベル Software\JPNIC\MDN\LogFileログファイル
プログラム個別設定:
Software\JPNIC\MDN\PerProg\<name>\Where変換位置 Software\JPNIC\MDN\PerProg\<name>\EncodingDNS側エンコーディング名
プログラム個別設定が指定されていない場合には、
Where 共通定義の設定値 Encoding プロセスのコードページ
とみなします。




