|
|
Winsock Programmer's FAQ |
|
WsControl() 内部解析解説
winipcfg.exe が使用しているモードでは基本的に、
どのように解析を行ったのかまずフックDLLを使って全てのパラメータをダンプして、その入力と 出力のパターンを探し出しました。そしてその理論上のパターンを検証 するテストプログラムを書きました。この結果を Thomas Divine氏に見せたと ころ、私が見つけ出したパラメータは、NT4 DDK に入っているWSHelper サンプルのパラメータに似ていることに彼は気がつきました。私はその サンプルを見てみて、さらにたくさんのパラメータを探り出すことがで きました。詳細については「パラメータ解析ノート」というタイトルの 章を参照して下さい。 なぜ解析を行ったのかえーとですね、Microsoft からの公式な情報では、この情報を Winsock 2 無しの Windows 95 アプリケーションからプログラム的に必 要としている場合、あなたのアプリケーションから winipcfg.exe をバッ チモードで実行し(そう、バッチモードがあるんです)、その出力をファ イルに渡して、そのファイルをアプリケーションから読み出す、という ことをしなければならないのです。そんなことをするのは Tcl インター プリタを埋め込むのとほとんど同じくらい楽しそうな作業なので、私は winipcfg.exe がどうやっているのかを調べるほうが面白そうだと思っ たからなのです。 DDKを取得する必要なヘッダファイルを準備するには、NT4 DDK の最新バージョン を入手する必要があります(プログラムが Windows 95/98 用のもので あってもです)。関連するヘッダファイルは次の通りです:
\ddk\src\network\inc\tdiinfo.h
\ddk\src\network\wshsmple\smpletcp.h
これらのヘッダファイルが再配布可能なのかどうかは私は良く分か りませんが、この文章を書いている時点では、Microsoft から NT4 DDK をダウンロー ド することができます。 ダウンロードバージョンのヘッダファイルでも問題なく動作するは ずです。NT4 DDK 全体を引っ張り出したくなければ、上記のヘッダファ イルをプロジェクトのディレクトリにコピーしてください。 WsControl() 呼出し
int WsControl(
DWORD protocol,
DWORD action,
LPVOID pRequestInfo,
LPDWORD pcbRequestInfoLen,
LPVOID pResponseInfo,
LPDWORD pcbResponseInfoLen
);
返却値
パラメータ
protocol = IPPROTO_TCP;
action = WSCTL_TCP_QUERY_INFORMATION;
winipcfg.exe で行われる問い合わせに対する出力構造体が全て存在
しているわけではありません。ですので私がいくつか作っています。私
が作ったものは以下のサンプルコードの中で定義されています。注記:
最新の
プラットフォームSDKから、SNMP、 ここでもう一度、NT4 DDK の最新の wshsmple を示してくださった Thomas Divine 氏に深く 感謝いたします。このサンプルのヘッダによって、最終的に入力パラメ タを解析することができたのです。 サンプルコード以下のサンプルコードは Windows 95 と Windows 98 の両者で動作 します。このサンプルは、起動すると winipcfg.exe が行う問い合わせ を全て真似して実行します。 wsctl.cpp
// wsctl.cpp
// Demonstrates possible calling params for the undocumented wsock32.dll
// api "WsControl", which is used by winipcfg.exe on win95/98. wsock32.dll
// is the 32-bit thunk to old winsock implementations (I think).
// Gets ip info for the current interface list.
// Tom Sanfilippo
// tsanfilippo@earthlink.net
// December 12, 1999
// Thanks are due to Thomas F. Divine <tdivine@pcausa.com>
// for pointing out the updated wshsmple in the NT4DDK.
// The headers in that sample allowed the input parameters
// to finally be discovered.
#include <windows.h>
#include <stdio.h>
#include <winsock.h>
#include <crtdbg.h>
#include "tdiinfo.h" // from recent NT4DDK "\ddk\src\network\inc\tdiinfo.h"
#include "smpletcp.h" // from recent NT4DDK "\ddk\src\network\wshsmple\smpletcp.h"
typedef int (__stdcall * WsControlProc) (DWORD, DWORD, LPVOID, LPDWORD,
LPVOID, LPDWORD);
typedef int (__stdcall * WSAGetLastErrorProc) (void);
typedef int (__stdcall * WSAStartupProc) (WORD wVersionRequested,
LPWSADATA lpWSAData);
typedef int (__stdcall * WSACleanupProc) (void);
WsControlProc WsControl = NULL;
WSAGetLastErrorProc WSAGetLastError1 = NULL;
WSAStartupProc WSAStartup1 = NULL;
WSACleanupProc WSACleanup1 = NULL;
#define WSCTL_TCP_QUERY_INFORMATION 0
#define WSCTL_TCP_SET_INFORMATION 1 //??
#define IP_MIB_ROUTETABLE_ENTRY_ID 0x101
#pragma pack(push,1)
typedef struct IPRouteEntry {
ulong ire_addr;
ulong ire_index; //matches if_index in IFEntry and iae_index in IPAddrEntry
ulong ire_metric;
ulong ire_unk1; //??
ulong ire_unk2; //??
ulong ire_unk3; //??
ulong ire_gw;
ulong ire_unk4; //??
ulong ire_unk5; //??
ulong ire_unk6; //??
ulong ire_mask;
ulong ire_unk7; //??
} IPRouteEntry;
#pragma pack(pop)
int main(int argc, char **argv)
{
int result = 0;
HMODULE hModule;
WSADATA WSAData;
hModule = LoadLibrary("wsock32.dll");
if (!hModule) {
fprintf(stderr, "LoadLibrary failed for wsock32.dll (%ld)\n",
GetLastError());
return EXIT_FAILURE;
}
WsControl = (WsControlProc) GetProcAddress(hModule, "WsControl");
if (!WsControl) {
fprintf(stderr, "GetProcAddress failed for WsControl (%ld)\n",
GetLastError());
FreeLibrary(hModule);
return EXIT_FAILURE;
}
WSAGetLastError1 =
(WSAGetLastErrorProc) GetProcAddress(hModule, "WSAGetLastError");
if (!WSAGetLastError1) {
fprintf(stderr,
"GetProcAddress failed for WSAGetLastError (%ld)\n",
GetLastError());
FreeLibrary(hModule);
return EXIT_FAILURE;
}
WSAStartup1 = (WSAStartupProc) GetProcAddress(hModule, "WSAStartup");
if (!WSAStartup1) {
fprintf(stderr, "GetProcAddress failed for WSAStartup (%ld)\n",
GetLastError());
FreeLibrary(hModule);
return EXIT_FAILURE;
}
WSACleanup1 = (WSACleanupProc) GetProcAddress(hModule, "WSACleanup");
if (!WSACleanup1) {
fprintf(stderr, "GetProcAddress failed for WSACleanup (%ld)\n",
GetLastError());
FreeLibrary(hModule);
return EXIT_FAILURE;
}
result = WSAStartup1(MAKEWORD(1, 1), &WSAData);
if (result) {
fprintf(stderr, "WSAStartup failed (%ld)\n", result);
FreeLibrary(hModule);
return EXIT_FAILURE;
}
TCP_REQUEST_QUERY_INFORMATION_EX tcpRequestQueryInfoEx;
memset(&tcpRequestQueryInfoEx, 0, sizeof(tcpRequestQueryInfoEx));
tcpRequestQueryInfoEx.ID.toi_entity.tei_entity = GENERIC_ENTITY;
tcpRequestQueryInfoEx.ID.toi_entity.tei_instance = 0;
tcpRequestQueryInfoEx.ID.toi_class = INFO_CLASS_GENERIC;
tcpRequestQueryInfoEx.ID.toi_type = INFO_TYPE_PROVIDER;
tcpRequestQueryInfoEx.ID.toi_id = ENTITY_LIST_ID;
DWORD tcpRequestBufSize = sizeof(tcpRequestQueryInfoEx);
//this probably allocates too much space; not sure if MAX_TDI_ENTITIES
//represents the max number of entities that can be returned or, if it
//is the highest entity value that can be defined.
DWORD entityIdsBufSize = MAX_TDI_ENTITIES * sizeof(TDIEntityID);
TDIEntityID *entityIds = (TDIEntityID *) calloc(entityIdsBufSize, 1);
result = WsControl(IPPROTO_TCP,
WSCTL_TCP_QUERY_INFORMATION,
&tcpRequestQueryInfoEx,
&tcpRequestBufSize, entityIds, &entityIdsBufSize);
if (result) {
fprintf(stderr, "%s(%d) WsControl failed (%ld)\n", __FILE__,
__LINE__, WSAGetLastError1());
WSACleanup1();
FreeLibrary(hModule);
return EXIT_FAILURE;
}
//...after the call we compute:
DWORD entityCount = entityIdsBufSize / sizeof(TDIEntityID);
DWORD i;
DWORD ifCount = 0;
//print out the interface info for the generic interfaces
for (i = 0; i < entityCount; i++) {
if (entityIds[i].tei_entity == IF_ENTITY) {
++ifCount;
//see if the iterface supports snmp mib-2 info
memset(&tcpRequestQueryInfoEx, 0,
sizeof(tcpRequestQueryInfoEx));
tcpRequestQueryInfoEx.ID.toi_entity = entityIds[i];
tcpRequestQueryInfoEx.ID.toi_class = INFO_CLASS_GENERIC;
tcpRequestQueryInfoEx.ID.toi_type = INFO_TYPE_PROVIDER;
tcpRequestQueryInfoEx.ID.toi_id = ENTITY_TYPE_ID;
ULONG entityType;
DWORD entityTypeSize = sizeof(entityType);
result = WsControl(IPPROTO_TCP,
WSCTL_TCP_QUERY_INFORMATION,
&tcpRequestQueryInfoEx,
&tcpRequestBufSize,
&entityType, &entityTypeSize);
if (result) {
fprintf(stderr, "%s(%d) WsControl failed (%ld)\n",
__FILE__, __LINE__, WSAGetLastError1());
WSACleanup1();
FreeLibrary(hModule);
return EXIT_FAILURE;
}
if (entityType == IF_MIB) { // Supports MIB-2 interface.
//get snmp mib-2 info
tcpRequestQueryInfoEx.ID.toi_class = INFO_CLASS_PROTOCOL;
tcpRequestQueryInfoEx.ID.toi_id = IF_MIB_STATS_ID;
//note: win95 winipcfg use 130 for MAX_IFDESCR_LEN while
//ddk\src\network\wshsmple\SMPLETCP.H defines it as 256
//we are trying to dup the winipcfg parameters for now
DWORD ifEntrySize = sizeof(IFEntry) + 128 + 1;
IFEntry *ifEntry = (IFEntry *) calloc(ifEntrySize, 1);
result = WsControl(IPPROTO_TCP,
WSCTL_TCP_QUERY_INFORMATION,
&tcpRequestQueryInfoEx,
&tcpRequestBufSize,
ifEntry, &ifEntrySize);
if (result) {
fprintf(stderr, "%s(%d) WsControl failed (%ld)\n",
__FILE__, __LINE__, WSAGetLastError1());
WSACleanup1();
FreeLibrary(hModule);
return EXIT_FAILURE;
}
//print interface index and description
*(ifEntry->if_descr + ifEntry->if_descrlen) = 0;
fprintf(stdout, "IF Index %lu %s\n", ifEntry->if_index,
ifEntry->if_descr);
}
}
}
//find the ip interface
for (i = 0; i < entityCount; i++) {
if (entityIds[i].tei_entity == CL_NL_ENTITY) {
//get ip interface info
memset(&tcpRequestQueryInfoEx, 0,
sizeof(tcpRequestQueryInfoEx));
tcpRequestQueryInfoEx.ID.toi_entity = entityIds[i];
tcpRequestQueryInfoEx.ID.toi_class = INFO_CLASS_GENERIC;
tcpRequestQueryInfoEx.ID.toi_type = INFO_TYPE_PROVIDER;
tcpRequestQueryInfoEx.ID.toi_id = ENTITY_TYPE_ID;
ULONG entityType;
DWORD entityTypeSize = sizeof(entityType);
result = WsControl(IPPROTO_TCP,
WSCTL_TCP_QUERY_INFORMATION,
&tcpRequestQueryInfoEx,
&tcpRequestBufSize,
&entityType, &entityTypeSize);
if (result) {
fprintf(stderr, "%s(%d) WsControl failed (%ld)\n",
__FILE__, __LINE__, WSAGetLastError1());
WSACleanup1();
FreeLibrary(hModule);
return EXIT_FAILURE;
}
if (entityType == CL_NL_IP) { // Entity implements IP.
//get ip snmp info
tcpRequestQueryInfoEx.ID.toi_class = INFO_CLASS_PROTOCOL;
tcpRequestQueryInfoEx.ID.toi_id = IP_MIB_STATS_ID;
IPSNMPInfo ipSnmpInfo;
DWORD ipSnmpInfoSize = sizeof(ipSnmpInfo);
result = WsControl(IPPROTO_TCP,
WSCTL_TCP_QUERY_INFORMATION,
&tcpRequestQueryInfoEx,
&tcpRequestBufSize,
&ipSnmpInfo, &ipSnmpInfoSize);
if (result) {
fprintf(stderr, "%s(%d) WsControl failed (%ld)\n",
__FILE__, __LINE__, WSAGetLastError1());
WSACleanup1();
FreeLibrary(hModule);
return EXIT_FAILURE;
}
//print ip snmp info
fprintf(stdout, "IP NumIfs: %lu\n", ipSnmpInfo.ipsi_numif);
fprintf(stdout, "IP NumAddrs: %lu\n",
ipSnmpInfo.ipsi_numaddr);
fprintf(stdout, "IP NumRoutes: %lu\n",
ipSnmpInfo.ipsi_numroutes);
//get ip address list
tcpRequestQueryInfoEx.ID.toi_id =
IP_MIB_ADDRTABLE_ENTRY_ID;
DWORD ipAddrEntryBufSize = sizeof(IPAddrEntry) * ifCount;
IPAddrEntry *ipAddrEntry = (IPAddrEntry
*) calloc(ipAddrEntryBufSize,
1);
result = WsControl(IPPROTO_TCP,
WSCTL_TCP_QUERY_INFORMATION,
&tcpRequestQueryInfoEx,
&tcpRequestBufSize,
ipAddrEntry, &ipAddrEntryBufSize);
if (result) {
fprintf(stderr, "%s(%d) WsControl failed (%ld)\n",
__FILE__, __LINE__, WSAGetLastError1());
WSACleanup1();
FreeLibrary(hModule);
return EXIT_FAILURE;
}
//print ip address list
DWORD j;
for (j = 0; j < ifCount; j++) {
unsigned char *addr = (unsigned char
*) &ipAddrEntry[j].iae_addr;
unsigned char *mask = (unsigned char
*) &ipAddrEntry[j].iae_mask;
fprintf(stdout, "IF Index %ld "
"Address %ld.%ld.%ld.%ld "
"Mask %ld.%ld.%ld.%ld\n",
ipAddrEntry[j].iae_index,
addr[0], addr[1], addr[2], addr[3],
mask[0], mask[1], mask[2], mask[3]);
}
//get route table
tcpRequestQueryInfoEx.ID.toi_id =
IP_MIB_ROUTETABLE_ENTRY_ID;
DWORD ipRouteEntryBufSize = sizeof(IPRouteEntry) *
ipSnmpInfo.ipsi_numroutes;
IPRouteEntry *ipRouteEntry = (IPRouteEntry
*)
calloc(ipRouteEntryBufSize, 1);
result = WsControl(IPPROTO_TCP,
WSCTL_TCP_QUERY_INFORMATION,
&tcpRequestQueryInfoEx,
&tcpRequestBufSize,
ipRouteEntry, &ipRouteEntryBufSize);
if (result) {
fprintf(stderr, "%s(%d) WsControl failed (%ld)\n",
__FILE__, __LINE__, WSAGetLastError1());
WSACleanup1();
FreeLibrary(hModule);
return EXIT_FAILURE;
}
//print route table
for (j = 0; j < ipSnmpInfo.ipsi_numroutes; j++) {
unsigned char *addr = (unsigned char
*) &ipRouteEntry[j].ire_addr;
unsigned char *gw = (unsigned char
*) &ipRouteEntry[j].ire_gw;
unsigned char *mask = (unsigned char
*) &ipRouteEntry[j].ire_mask;
fprintf(stdout,
"Route %ld.%ld.%ld.%ld "
"IF %ld "
"GW %ld.%ld.%ld.%ld "
"Mask %ld.%ld.%ld.%ld "
"Metric %ld\n",
addr[0], addr[1], addr[2], addr[3],
ipRouteEntry[j].ire_index,
gw[0], gw[1], gw[2], gw[3],
mask[0], mask[1], mask[2], mask[3],
ipRouteEntry[j].ire_metric);
}
}
}
}
WSACleanup1();
FreeLibrary(hModule);
return EXIT_SUCCESS;
}
//end of code
[Ed. Tom included a bunch of notes from tracing calls winipcfg.exe made. For various reasons, I've made them available in a separate file.] Copyright © 1999 by Tom Sanfilippo. All rights reserved. |
| << Winsock と BSD ソケットとの互換性 | CSocket はなぜ有害か? >> |
| Last modified: $Id: wscontrol.html,v 1.6 2002/11/09 20:40:33 ksk Exp $ | Go to the original FAQ page |
| < Go to the main FAQ page | << Go to the Home Page |