[BlueLeaf1336]> PROBLEMS> WinSock>
history | TOP |
2004/05/02:作成
2004/05/05:スレッド停止時に shutdown() 関数で送受信処理を中断するように修正。ログ出力方法を変更。従来の簡略ダンプに加えてフルダンプを可能に。
2004/05/06:このプログラムでパケットをモニタするとパケットおかしくなるような...
reference | TOP |
comment | TOP |
まあ、動いてます。それだけです。本当に大丈夫か? と思ってます。WSARecv とか Delphi のサンプルがどこにもない!
WinSock2.2 からこのような処理が可能になったということで、WinSock2.pas をもらってきてます。これが再配布可能かどうかは疑問ですが多分大丈夫かと。オリジナルの圧縮ファイルに含まれてたすべてのファイルを一切触らずに同梱してますし。
今回もお約束、信じないように。(もちろん参考にさせていただいたサイトのことではありません。Delphiに翻訳したこのページの以下のコードを、です。)
(2004/05/05)基本的な処理は全然変わってないので、HTML化したコードは以前のままですが、ダウンロード用のコードは修正しています。ただし以前のコード(HTML化したものに対応するもの)もダウンロードできるようにしています。
これを使って、完敗した ICMP ページのリベンジに役立てたいというか...。
code | TOP |
unit Main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, WinSock2; type TForm1 = class(TForm) Panel1: TPanel; Button1: TButton; ComboBox1: TComboBox; Memo1: TMemo; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button1Click(Sender: TObject); private public wsd: TWSAData; sock: TSocket; hThread: TThread; ThreadId: DWORD; function ListAdapter(): Boolean; function InitAdapter(): Boolean; procedure Print(const buf: array of Byte; const len: integer); end; var Form1: TForm1; implementation {$R *.dfm} const Protocol: array[0..99] of string = ( 'Reserved', // 0 'ICMP', // 1 'IGMP', // 2 'GGP', // 3 'IP', // 4 'ST', // 5 'TCP', // 6 'UCL', // 7 'EGP', // 8 'IGP', // 9 'BBN-RCC-MON', // 10 'NVP-II', // 11 'PUP', // 12 'ARGUS', // 13 'EMCON', // 14 'XNET', // 15 'CHAOS', // 16 'UDP', // 17 'MUX', // 18 'DCN-MEAS', // 19 'HMP', // 20 'PRM', // 21 'XNS-IDP', // 22 'TRUNK-1', // 23 'TRUNK-2', // 24 'LEAF-1', // 25 'LEAF-2', // 26 'RDP', // 27 'IRTP', // 28 'ISO-TP4', // 29 'NETBLT', // 30 'MFE-NSP', // 31 'MERIT-INP', // 32 'SEP', // 33 '3PC', // 34 'IDPR', // 35 'XTP', // 36 'DDP', // 37 'IDPR-CMTP', // 38 'TP++', // 39 'IL', // 40 'SIP', // 41 'SDRP', // 42 'SIP-SR', // 43 'SIP-FRAG', // 44 'IDRP', // 45 'RSVP', // 46 'GRE', // 47 'MHRP', // 48 'BNA', // 49 'SIPP-ESP', // 50 'SIPP-AH', // 51 'I-NLSP', // 52 'SWIPE', // 53 'NHRP', // 54 'unknown', // 55 'unknown', // 56 'unknown', // 57 'unknown', // 58 'unknown', // 59 'unknown', // 60 'unknown', // 61 'CFTP', // 62 'unknown', // 63 'SAT-EXPAK', // 64 'KRYPTOLAN', // 65 'RVD', // 66 'IPPC', // 67 'unknown', // 68 'SAT-MON', // 69 'VISA', // 70 'IPCV', // 71 'CPNX', // 72 'CPHB', // 73 'WSN', // 74 'PVP', // 75 'BR-SAT-MON', // 76 'SUN-ND', // 77 'WB-MON', // 78 'WB-EXPAK', // 79 'ISO-IP', // 80 'VMTP', // 81 'SECURE-VMTP', // 82 'VINES', // 83 'TTP', // 84 'NSFNET-IGP', // 85 'DGP', // 86 'TCF', // 87 'IGRP', // 88 'OSPFIGP', // 89 'Sprite-RPC', // 90 'LARP', // 91 'MTP', // 92 'AX.25', // 93 'IPIP', // 94 'MICP', // 95 'SCC-SP', // 96 'ETHERIP', // 97 'ENCAP', // 98 // 'unknown', // 98(?) 'GMTP' // 99 ); SIO_RCVALL = $98000001; MAX_IP_SIZE = 65535; LIST_SIZE = 4096; // --------------------------------------------------------------------------- // アダプタ一覧 function TForm1.ListAdapter(): Boolean; var Temp: string; slist: LPSOCKET_ADDRESS_LIST; d: DWORD; s: TSocket; i, ret: integer; begin ComboBox1.Clear; Result := false; // ソケット作成 s := WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, nil, 0, WSA_FLAG_OVERLAPPED); // 失敗 if (INVALID_SOCKET = s) then begin Temp := Format('WSASocket(AF_INET,SOCK_RAW) failed', []); Memo1.Lines.Add(Temp); end // 成功 else begin // メモリ確保 GetMem(slist, LIST_SIZE); try // WSAIoctl失敗 ret := WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, nil, 0, slist, LIST_SIZE, @d, nil, nil); if (SOCKET_ERROR = ret) then begin Temp := Format('WSAIoctl(SIO_ADDRESS_LIST_QUERY) faild.', []); Memo1.Lines.Add(Temp); end // 成功 else begin // 列挙 for i := 0 to slist.iAddressCount - 1 do begin Temp := Format('%d. (%s)', [i, inet_ntoa((slist.Address[i].lpSockaddr).sin_addr)]); ComboBox1.Items.Add(Temp); end; // ここまで来たら Result := true; end; finally // メモリ解放 FreeMem(slist, LIST_SIZE); // ソケット破棄 closesocket(s); end; end; if (ComboBox1.Items.Count > 0) then ComboBox1.ItemIndex := 0; end; // --------------------------------------------------------------------------- // アダプタの初期化 function TForm1.InitAdapter(): Boolean; var Temp: string; ret: integer; optval: integer; d: DWORD; slist: LPSOCKET_ADDRESS_LIST; addr_in: TSockAddrIn; begin Result := false; // SOCKETの生成 sock := WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, nil, 0, WSA_FLAG_OVERLAPPED); if (INVALID_SOCKET = sock) then begin Temp := Format('WSASocket(AF_INET,SOCK_RAW) failed', []); Memo1.Lines.Add(Temp); end else begin // メモリ確保 GetMem(slist, LIST_SIZE); try // アダプタのリスト取得 ret := WSAIoctl(sock, SIO_ADDRESS_LIST_QUERY, nil, 0, slist, LIST_SIZE, @d, nil, nil); if (SOCKET_ERROR = ret) then begin Temp := Format('WSAIoctl(SIO_ADDRESS_LIST_QUERY) faild.', []); Memo1.Lines.Add(Temp); end else begin // SOCKET のデータセット FillChar(addr_in, SizeOf(addr_in), 0); addr_in.sin_addr.S_addr := slist.Address[ComboBox1.ItemIndex].lpSockaddr.sin_addr.S_addr; addr_in.sin_family := AF_INET; addr_in.sin_port := htons(0); // bind ret := bind(sock, @addr_in, SizeOf(addr_in)); if (SOCKET_ERROR = ret) then begin Temp := Format('bind failed', []); Memo1.Lines.Add(Temp); end else begin optval := 1; ret := WSAIoctl(sock, SIO_RCVALL, @optval, sizeof(optval), nil, 0, @d, nil, nil); if (SOCKET_ERROR = ret) then begin Temp := Format('WSAIoCtl(SIO_RCVALL) failed', []); Memo1.Lines.Add(Temp); end else begin Result := true; end; end; end; finally // メモリ解放 FreeMem(slist, LIST_SIZE); end; end; end; // --------------------------------------------------------------------------- // ダンプ procedure TForm1.Print(const buf: array of Byte; const len: integer); // c's isprint function IsPrint(const c: Char): Boolean; begin Result := (c in [#$20..#$7E]); end; var t: SYSTEMTIME; Tmp: string; i, j: integer; d: integer; c: char; begin GetLocalTime(t); Tmp := '-----------------------------------------------------------'; Memo1.Lines.Add(Tmp); // 時刻 Tmp := Format('%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d Protocol: %s', [t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond, Protocol[buf[9]]]); Memo1.Lines.Add(Tmp); // 送信元アドレス Tmp := Format('Source Address: %d.%d.%d.%d', [buf[12], buf[13], buf[14], buf[15]]); Memo1.Lines.Add(Tmp); // 送信先アドレス Tmp := Format('Destination Address: %d.%d.%d.%d', [buf[16], buf[17], buf[18], buf[19]]); Memo1.Lines.Add(Tmp); // ポート Tmp := Format('Source Port: %d Destination Port: %d', [buf[20] * 256 + buf[21], buf[22] * 256 + buf[23]]); Memo1.Lines.Add(Tmp); Memo1.Lines.Add('-- dump --'); // 16進ダンプ for i := 0 to 3 - 1 do begin d := len - i * 16; if (d > 16) then d := 16; if (d <= 0) then break; // バイナリ表示 Tmp := Format('%8.8x : ', [i]); for j := 0 to d - 1 do begin Tmp := Tmp + Format('%2.2x ', [buf[i * 16 + j]]); end; for j := d to 16 - 1 do Tmp := Tmp + ' '; // 文字列表示 for j := 0 to d - 1 do begin c := Chr(buf[i * 16 + j]); if not IsPrint(c) then c := '.'; Tmp := Tmp + Format('%s ', [c]); end; Memo1.Lines.Add(Tmp); if (d <> 16) then break; end; end; // --------------------------------------------------------------------------- // コンストラクタ procedure TForm1.FormCreate(Sender: TObject); begin // Ver2.2 でWinSockを初期化する WSAStartup(MAKEWORD(2, 2), wsd); hThread := nil; //アダプタのリストをコンボボックに取得 ListAdapter(); end; // --------------------------------------------------------------------------- // デストラクタ procedure TForm1.FormDestroy(Sender: TObject); begin // キャプチャスレッドが走行中の場合ストップする if (hThread <> nil) then begin hThread.Terminate; hThread.Free; hThread := nil; end; // WinSockの終了処理 WSACleanup(); end; // --------------------------------------------------------------------------- // キャプチャスレッド type TCaputureThread = class(TThread) private Msg: string; Buf: array[0..MAX_IP_SIZE - 1] of Byte; Len: Cardinal; procedure DoError(); procedure DoPrint(); protected procedure Execute; override; end; // --------------------------------------------------------------------------- procedure TCaputureThread.DoError(); begin Form1.Memo1.Lines.Add(Msg); end; // --------------------------------------------------------------------------- procedure TCaputureThread.DoPrint(); begin Form1.Print(Buf, Len); end; // --------------------------------------------------------------------------- // キャプチャスレッド本体 procedure TCaputureThread.Execute; var wsb: PWSABUF; ret: integer; Flags: Cardinal; begin // メモリ確保 New(wsb); wsb.buf := @Buf; wsb.len := MAX_IP_SIZE; while not Terminated do begin Sleep(1); Application.ProcessMessages(); FillChar(Buf, SizeOf(Buf), 0); Flags := 0; // パケット取得 ret := WSARecv(Form1.sock, wsb, 1, Len, Flags, nil, nil); if (SOCKET_ERROR = ret) then begin Msg := Format('WSARecv failed. Code %d', [WSAGetLastError(), Form1.sock]); if not Terminated then Synchronize(DoError); continue; end; // パケット表示 if not Terminated then Synchronize(DoPrint); end; // メモリ解放 Dispose(wsb); end; // --------------------------------------------------------------------------- // キャプチャ開始・終了(キャプチャスレッドの生成・破棄) procedure TForm1.Button1Click(Sender: TObject); begin // キャプチャ開始処理 if (hThread = nil) then begin if (InitAdapter()) then begin // キャプチャスレッド生成 hThread := TCaputureThread.Create(true); hThread.Resume; Button1.Caption := 'Stop'; end; end // キャプチャ終了処理 else begin // ひとこと ShowMessage('Stop に切り替わらない場合は、WSARecv で処理がとまってます' + #13#10'何か通信すればとまります' + #13#10'ブラウザを開いてどこかのサイトを見るとか...'); // キャプチャスレッドの破棄 hThread.Terminate; hThread.Free; hThread := nil; Button1.Caption := 'Start'; end; end; end.
screenshot & download | TOP |
ソースダウンロード
20040502PacketDump.zip(33,019bytes)
こちらは記念に保存。
ソースダウンロード
20040505PacketDump.zip(205,143bytes)
EOF | TOP |