Board index » delphi » TCP Packet Sender
Martin Meier
Delphi Developer |
TCP Packet Sender2004-10-15 11:19:12 PM delphi106 hi, i want to build my own tcp packet incl. the header, after a couple of hourse i got this source, but i think there is a small bug in the checksum calculation, so i can not send the generated packet. can someone help me please? unit unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, OleCtrls, Registry; const SrcIP = '192.168.0.1'; SrcPort = 4086; DestIP = '192.168.0.2'; DestPort = 6969; Max_Message = 4068; Max_Packet = 4096; type TPacketBuffer = array[0..Max_Packet-1] of byte; TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } procedure SendIt; end; // Заголово?IP пакета type T_IP_Header = record ip_verlen : Byte; ip_tos : Byte; ip_totallength : Word; ip_id : Word; ip_offset : Word; ip_ttl : Byte; ip_protocol : Byte; ip_checksum : Word; ip_srcaddr : LongWord; ip_destaddr : LongWord; end; // Заголово?TCP пакета type T_TCP_Header = record src_portno : Word; dst_portno : Word; turn_num:longword; conf_num:longword; data_offset:byte; tcp_flags:byte; tcp_window:word; tcp_checksum:word; tcp_priority:word; end; type TPseudo= record saddr:longword; daddr:longword; mbz:Byte; proto:Byte; tcplength:word; end; // Некоторы?об?влен? типо?для Winsock 2 u_char = Char; u_short = Word; u_int = Integer; u_long = Longint; SunB = packed record s_b1, s_b2, s_b3, s_b4: u_char; end; SunW = packed record s_w1, s_w2: u_short; end; in_addr = record case integer of 0: (S_un_b: SunB); 1: (S_un_w: SunW); 2: (S_addr: u_long); end; TInAddr = in_addr; Sockaddr_in = record case Integer of 0: (sin_family: u_short; sin_port: u_short; sin_addr: TInAddr; sin_zero: array[0..7] of Char); 1: (sa_family: u_short; sa_data: array[0..13] of Char) end; TSockAddr = Sockaddr_in; TSocket = u_int; const WSADESCRIPTION_LEN = 256; WSASYS_STATUS_LEN = 128; type PWSAData = ^TWSAData; WSAData = record // !!! also WSDATA wVersion: Word; wHighVersion: Word; szDescription: array[0..WSADESCRIPTION_LEN] of Char; szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char; iMaxSockets: Word; lpVendorInfo: PChar; end; TWSAData = WSAData; // Опреде?ем необходимы?функци?winsock 2 function closesocket(s: TSocket): Integer; stdcall; function socket(af, Struct, protocol: Integer): TSocket; stdcall; function sendto(s: TSocket; var Buf; len, flags: Integer; var addrto: TSockAddr; tolen: Integer): Integer; stdcall;{} function setsockopt(s: TSocket; level, optname: Integer; optval: PChar; optlen: Integer): Integer; stdcall; function inet_addr(cp: PChar): u_long; stdcall; {PInAddr;} { TInAddr } function htons(hostshort: u_short): u_short; stdcall; function WSAGetLastError: Integer; stdcall; function WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer; stdcall; function WSACleanup: Integer; stdcall; const AF_INET = 2; // internetwork: UDP, TCP, etc. IP_HDRINCL = 2; // включаем заголово?IP пакета SOCK_RAW = 3; // интерфей?raw-протокол? IPPROTO_IP = 0; // dummy for IP IPPROTO_TCP = 6; // tcp IPPROTO_UDP = 17; // user datagram protocol IPPROTO_RAW = 255; // raw IP паке? INVALID_SOCKET = TSocket(not(0)); SOCKET_ERROR = -1; var Form1: TForm1; implementation // Импортируе?функци?Winsock 2 const WinSocket = 'WS2_32.DLL'; function closesocket; external winsocket name 'closesocket'; function socket; external winsocket name 'socket'; function sendto; external winsocket name 'sendto'; function setsockopt; external winsocket name 'setsockopt'; function inet_addr; external winsocket name 'inet_addr'; function htons; external winsocket name 'htons'; function WSAGetLastError; external winsocket name 'WSAGetLastError'; function WSAStartup; external winsocket name 'WSAStartup'; function WSACleanup; external winsocket name 'WSACleanup'; {$R *.DFM} // // Function: checksum // // Description: // This function calculates the 16-bit one's complement sum // for the supplied buffer // function CheckSum(var Buffer; Size : integer) : Word; type TWordArray = array[0..1] of Word; var ChkSum : LongWord; i : Integer; begin ChkSum := 0; i := 0; while Size>1 do begin ChkSum := ChkSum + TWordArray(Buffer)[i]; inc(i); Size := Size - SizeOf(Word); end; if Size=1 then ChkSum := ChkSum + Byte(TWordArray(Buffer)[i]); ChkSum := (ChkSum shr 16) + (ChkSum and $FFFF); ChkSum := ChkSum + (Chksum shr 16); Result := Word(ChkSum); end; procedure BuildHeaders(FromIP : string; iFromPort : Word; ToIP : string; iToPort : Word; StrMessage : string; var Buf : TPacketBuffer; var remote : TSockAddr; var iTotalSize: Word); var dwFromIP : LongWord; dwToIP : LongWord; iIPVersion : Word; iIPSize : Word; ipHdr : T_IP_Header; tcpHdr : T_TCP_Header; pHdr:TPseudo; iTcpSize : Word; iTcpChecksumSize : Word; cksum : Word; Ptr : ^Byte; procedure IncPtr(Value : Integer); begin ptr := pointer(integer(ptr) + Value); end; begin // преобразуе?ip адреса dwFromIP := inet_Addr(PChar(FromIP)); dwToIP := inet_Addr(PChar(ToIP)); // Инициализируем заголово?IP пакета // iTotalSize := sizeof(ipHdr) + sizeof(tcpHdr) + length(strMessage); iIPVersion := 4; iIPSize := sizeof(ipHdr) div sizeof(LongWord); // // IP version goes in the high order 4 bits of ip_verlen. The // IP header length (in 32-bit words) goes in the lower 4 bits. // ipHdr.ip_verlen := (iIPVersion shl 4) or iIPSize; ipHdr.ip_tos := 0; // IP type of service ipHdr.ip_totallength := htons(iTotalSize); // Total packet len ipHdr.ip_id := 0; // Unique identifier: set to 0 ipHdr.ip_offset := htons($4000); // Fragment offset field ipHdr.ip_ttl := 128; // время жизн?пакета ipHdr.ip_protocol := $06; // Protocol(TCP) ipHdr.ip_checksum := 0 ; // IP checksum ipHdr.ip_srcaddr := dwFromIP; // Source address ipHdr.ip_destaddr := dwToIP; // Destination address // // Инициализируем заголово?TCP пакета // iTcpSize := sizeof(tcpHdr) + length(strMessage); tcpHdr.src_portno := htons(iFromPort) ; tcpHdr.dst_portno := htons(iToPort) ; tcpHdr.turn_num:= random($FFFFFFFF); tcpHdr.conf_num:= random($FFFFFFFF); tcpHdr.data_offset:=$50; tcpHdr.tcp_flags:=$18; tcpHdr.tcp_window:=$F0FA; tcpHdr.tcp_checksum:={$A2B6}0; tcpHdr.tcp_priority:=0; // pHdr.saddr:=ipHdr.ip_srcaddr; pHdr.daddr:=ipHdr.ip_destaddr; pHdr.mbz:=0; pHdr.proto:=IPPROTO_TCP; pHdr.tcplength:=htons(iTcpSize); // ptr := @buf[0]; FillChar(Buf, SizeOf(Buf), 0); Move(pHdr,ptr^,SizeOf(pHdr)); IncPtr(SizeOf(pHdr)); { Move(ipHdr, ptr^, SizeOf(ipHdr)); IncPtr(SizeOf(ipHdr));} Move(tcpHdr, ptr^, SizeOf(tcpHdr)); IncPtr(SizeOf(tcpHdr)); Move(StrMessage[1], ptr^, length(StrMessage)); cksum := checksum(buf, Sizeof(pHdr)+SizeOf(tcpHdr)+Length(strMessage)); tcpHdr.tcp_checksum:= cksum; // // FillChar(Buf, SizeOf(Buf), 0); Ptr := @Buf[0]; Move(ipHdr, ptr^, SizeOf(ipHdr)); IncPtr(SizeOf(ipHdr)); Move(tcpHdr, ptr^, SizeOf(tcpHdr)); IncPtr(SizeOf(tcpHdr)); Move(StrMessage[1], ptr^, length(StrMessage)); // Apparently, this SOCKADDR_IN structure makes no difference. // Whatever we put as the destination IP addr in the IP header // is what goes. Specifying a different destination in remote // will be ignored. // remote.sin_family := AF_INET; remote.sin_port := htons(iToPort); remote.sin_addr.s_addr := dwToIP; end; procedure TForm1.SendIt; var sh : TSocket; bOpt : Integer; ret : Integer; Buf : TPacketBuffer; Remote : TSockAddr; Local : TSockAddr; iTotalSize : Word; wsdata : TWSAdata; begin // Startup Winsock 2 ret := WSAStartup($0002, wsdata); if ret<>0 then begin memo1.lines.add('WSA Startup failed.'); exit; end; with memo1.lines do begin add('WSA Startup:'); add('Desc.: '+wsData.szDescription); add('Status: '+wsData.szSystemStatus); end; try // Создаё?соке? sh := Socket(AF_INET, SOCK_RAW, IPPROTO_UDP); if (sh = INVALID_SOCKET) then begin memo1.lines.add('Socket() failed: '+IntToStr(WSAGetLastError)); exit; end; Memo1.lines.add('Socket Handle = '+IntToStr(sh)); // Option: Header Include bOpt := 1; ret := SetSockOpt(sh, IPPROTO_IP, IP_HDRINCL, @bOpt, SizeOf(bOpt)); if ret = SOCKET_ERROR then begin Memo1.lines.add('setsockopt(IP_HDRINCL) failed: '+IntToStr(WSAGetLastError)); exit; end; // строим паке? BuildHeaders( SrcIP, SrcPort, DestIP, DestPort, 'Test', Buf, Remote, iTotalSize ); // Отправ?ем паке? ret := SendTo(sh, buf, iTotalSize, 0, Remote, SizeOf(Remote)); if ret = SOCKET_ERROR then Memo1.Lines.Add('sendto() failed: '+IntToStr(WSAGetLastError)) else Memo1.Lines.Add('send '+IntToStr(ret)+' bytes.'); // Закрывае?соке? CloseSocket(sh); finally // Закрывае?Winsock 2 WSACleanup; end; end; procedure TForm1.Button1Click(Sender: TObject); begin SendIt; end; end. |