TRawSocket = class(TObject)
private
buf: array[0..BUFLEN - 1] of char;
FdwNotifyWnd: Cardinal;
hsocket: Cardinal;
str: string;
public
constructor Create;
destructor Destroy; override;
function createSocket: Integer;
procedure destroySocket;
function IsOk: Boolean;
//function sendTcpData(srcIP, dstIP: string; srcPort, dstPort: word; data:
//pchar; dataLen: integer): Integer;
function sendUdpData(srcIP, dstIP: string; srcPort, dstPort: word; data:
pchar; dataLen: integer): Integer;
function sendUdpDataFrag(srcIP, dstIP: string; srcPort, dstPort: word;
data: pchar; dataLen: integer): Integer;
published
property dwNotifyWnd: Cardinal read FdwNotifyWnd write FdwNotifyWnd;
end;
constructor TRawSocket.Create;
begin
inherited Create;
hsocket := INVALID_SOCKET;
end;destructor TRawSocket.Destroy;
begin
if IsOk then destroySocket;
inherited Destroy;
end;function TRawSocket.createSocket: Integer;
var
flag: Integer;
ret: Integer;
begin
// 创建raw socket,自己构造ip包头
result := -1; // Create socket
// IPPROTO_RAW 只能用来发送IP包,而不能接收任何数据.
//*发送的数据需要自己填充IP包头,TCP/UDP头并且自己计算校验和
hsocket := Socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (hsocket = INVALID_SOCKET) then begin
str := 'Socket() failed: ' + IntToStr(WSAGetLastError);
SendMessage(FdwNotifyWnd, WM_STRINFO, integer(str), 0);
exit;
end;flag := 1; // Option: Header Include
ret := SetSockOpt(hsocket, IPPROTO_IP, IP_HDRINCL, @flag, SizeOf(flag));
if ret = SOCKET_ERROR then begin
str := 'setsockopt IP_HDRINCL failed: ' + IntToStr(WSAGetLastError);
SendMessage(FdwNotifyWnd, WM_STRINFO, integer(str), 0);
exit;
end;flag := 5000; // Option: Send OverTime;
ret := SetSockOpt(hsocket, SOL_SOCKET, SO_SNDTIMEO, @flag, SizeOf(flag));
if ret = SOCKET_ERROR then begin
str := 'setsockopt SO_SNDTIMEO failed: ' + IntToStr(WSAGetLastError);
SendMessage(FdwNotifyWnd, WM_STRINFO, integer(str), 0);
exit;
end;
result := 1;
end;procedure TRawSocket.destroySocket;
begin
shutdown(hsocket, SD_BOTH);
CloseSocket(hsocket);
hsocket := INVALID_SOCKET;
end;function TRawSocket.IsOk: Boolean;
begin
result := not (hsocket = INVALID_SOCKET);
end;
function TRawSocket.sendUdpData(srcIP, dstIP: string; srcPort, dstPort: word;
data: pchar; dataLen: integer): Integer;
var
ipHdr: _ipHead;
udpHdr: _udpHead;
pseudoHdr: _pseudoHead;
ipSize, udpSize: Word;
iphdrlen, pseudohdrlen, udphdrlen: Word;
lpipHdr: pipHead;
lpudpHdr: pudpHead;
p, p0: PChar;
Local: TSockAddrIn;
Remote: TSockAddrIn;
begin
// 功能:打包发送UDP包
Local.sin_family := AF_INET;
Local.sin_addr.S_addr := inet_Addr(PChar(srcIP));
Local.sin_port := htons(srcPort);Remote.sin_family := AF_INET;
Remote.sin_addr.S_addr := inet_Addr(PChar(dstIP));
Remote.sin_port := htons(dstPort);iphdrlen := sizeof(_ipHead);
udphdrlen := sizeof(_udpHead);
pseudohdrlen := sizeof(pseudoHdr);
ipSize := iphdrlen + udphdrlen + datalen;
udpSize := ipSize - iphdrlen;
inc(idt); // test
// 初始化 IP 头
ipHdr.ver_IHL := (4 shl 4) or (sizeof(ipHdr) div 4);
ipHdr.serverType := 0; // IP type of service
ipHdr.totalLen := htons(ipSize); // Total packet len
ipHdr.ident := htons(idt); // Unique identifier: set to 0
ipHdr.flags_off := 0; // Fragment offset field
ipHdr.ttl := 128; // Time to live
ipHdr.protocol := 17; // Protocol(UDP)
ipHdr.ipchksum := 0; // IP checksum
ipHdr.srcAddr := Local.sin_addr.S_addr; // Source address
ipHdr.dstAddr := Remote.sin_addr.S_addr; // Destination address// 初始化 UDP 头
udpHdr.srcPort := Local.sin_port;
udpHdr.dstPort := Remote.sin_port;
udpHdr.Length := htons(udpSize);
udpHdr.checksum := 0;// 初始化 伪ip 头
pseudoHdr.srcAddr := ipHdr.srcAddr;
pseudoHdr.dstAddr := ipHdr.dstAddr;
pseudoHdr.unused := 0;
pseudoHdr.protocol := ipHdr.protocol;
pseudoHdr.Length := udpHdr.Length;p := buf + iphdrlen - pseudohdrlen;
p0 := P; // 备份伪ip头指针p0,checksum 运算用
move(pseudoHdr, p^, pseudohdrlen);
inc(p, pseudohdrlen);
lpudpHdr := pudpHead(p);
move(udpHdr, p^, udphdrlen);
inc(p, udphdrlen);
move(data^, p^, datalen);
inc(p, datalen);
lpudpHdr^.checksum := checksum(p0, p - p0);
// copy ip头;覆盖伪ip头
p := buf;
lpipHdr := pipHead(p);
move(ipHdr, p^, iphdrlen);
lpipHdr^.ipchksum := checksum(buf, iphdrlen); // ip头// Send the raw socket packet
result := sendto(hsocket, buf, ipSize, 0, @Remote, SizeOf(Remote));
if result = SOCKET_ERROR then
begin
str := 'sendto() failed: ' + IntToStr(WSAGetLastError);
SendMessage(FdwNotifyWnd, WM_STRINFO, integer(str), 0);
exit;
end;
end;
function TRawSocket.sendUdpDataFrag(srcIP, dstIP: string; srcPort, dstPort:
word; data: pchar; dataLen: integer): Integer;
const
fraglen = 1472; // 分片的数据长度 1500(以太网MTU)-20(IP头长)-8(UDP头长)
var
ipHdr: _ipHead;
udpHdr: _udpHead;
pseudoHdr: _pseudoHead;
ipSize, udpSize: Word;
iphdrlen, pseudohdrlen, udphdrlen: Word;
lpipHdr: pipHead;
lpudpHdr: pudpHead;
p, p0: PChar;
Local: TSockAddrIn;
Remote: TSockAddrIn;
i, j, k: integer;
begin
inc(idt); // test
// 功能:分片发送ip 分片包UDP协议
Local.sin_family := AF_INET;
Local.sin_addr.S_addr := inet_Addr(PChar(srcIP));
Local.sin_port := htons(srcPort);Remote.sin_family := AF_INET;
Remote.sin_addr.S_addr := inet_Addr(PChar(dstIP));
Remote.sin_port := htons(dstPort);iphdrlen := sizeof(_ipHead);
udphdrlen := sizeof(_udpHead);
pseudohdrlen := sizeof(pseudoHdr);j := datalen div fraglen;
if (datalen mod fraglen) = 0 then j := j - 1;
for i := 0 to j do
begin
if datalen > (i + 1) * fraglen then k := fraglen + udpHdrLen
else k := datalen - i * fraglen;
ipSize := iphdrlen + udphdrlen + k;
udpSize := ipSize - iphdrlen;
// 初始化 IP 头
ipHdr.ver_IHL := (4 shl 4) or (sizeof(ipHdr) div 4);
ipHdr.serverType := 0; // IP type of service
ipHdr.totalLen := htons(ipSize); // Total packet len
ipHdr.ident := htons(idt); // Unique identifier: set to 0
// Fragment offset field
if i = 0 then ipHdr.flags_off := htons($2000) // 第一片
else if i < j then ipHdr.flags_off := htons($2000 or (fraglen + udpHdrLen) * i) // 中间片
else ipHdr.flags_off := htons((fraglen + udpHdrLen) * i); // 最后一片
ipHdr.ttl := 128; // Time to live
ipHdr.protocol := 17; // Protocol(UDP)
ipHdr.ipchksum := 0; // IP checksum
ipHdr.srcAddr := Local.sin_addr.S_addr; // Source address
ipHdr.dstAddr := Remote.sin_addr.S_addr; // Destination address// 初始化 UDP 头
udpHdr.srcPort := Local.sin_port;
udpHdr.dstPort := Remote.sin_port;
udpHdr.Length := htons(udpSize);
udpHdr.checksum := 0;// 初始化 伪ip 头
pseudoHdr.srcAddr := ipHdr.srcAddr;
pseudoHdr.dstAddr := ipHdr.dstAddr;
pseudoHdr.unused := 0;
pseudoHdr.protocol := ipHdr.protocol;
pseudoHdr.Length := udpHdr.Length; p := buf + iphdrlen - pseudohdrlen;
p0 := P; // 备份伪ip头指针p0,checksum 运算用
move(pseudoHdr, p^, pseudohdrlen);
inc(p, pseudohdrlen);
lpudpHdr := pudpHead(p);
move(udpHdr, p^, udphdrlen);
inc(p, udphdrlen);
move(data^, p^, k);
inc(p, k);
lpudpHdr^.checksum := checksum(p0, p - p0);
// copy ip头;覆盖伪ip头
p := buf;
lpipHdr := pipHead(p);
move(ipHdr, p^, iphdrlen);
lpipHdr^.ipchksum := checksum(buf, iphdrlen); // ip头// Send the raw socket packet
result := sendto(hsocket, buf, ipSize, 0, @Remote, SizeOf(Remote));
if result = SOCKET_ERROR then
begin
str := 'sendto() failed: ' + IntToStr(WSAGetLastError);
SendMessage(FdwNotifyWnd, WM_STRINFO, integer(str), 0);
exit;
end;end;
result := datalen;
end;