徐龙
unit NetSendPacket;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
const
IP_HDRINCL=2;
type
TPacket = array [0..8192] of byte;
var
// net send 消息的网络封包头格式,按此格式填充UDP包并发送到目标机的 135 端口.对方能收到信息.需要启动windows的消息服务.
packet_header:array[0..79] of byte =(
$04,$00,$28,$00
,$10,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
,$00,$00,$00,$00,$f8,$91,$7b,$5a,$00,$ff,$d0,$11,$a9,$b2,$00,$c0
,$4f,$b6,$e6,$fc
,$ff,$ff,$ff,$ff // @40 : unique id over 16 bytes
,$ff,$ff,$ff,$ff
,$ff,$ff,$ff,$ff
,$ff,$ff,$ff,$ff
,$00,$00,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00
,$00,$00,$ff,$ff,$ff,$ff
,$ff,$ff,$ff,$ff // @74 : fields length
,$00,$00);
field_header :array [0..11]of byte =
($ff,$ff,$ff,$ff // @0 : field length
,$00,$00,$00,$00
,$00,$00,$00,$00); // @8 : field length
function sd( FromIp:string; Toip:string;ToPort:integer;FromName:string; ToName:string; msg:string ):bool ;
implementation
uses RawHeaders,WinSock;
//构造IP包时需要自已计算校验码,并填充到包.此函数负责计算校验码
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;
//发送封包函数
function sd( FromIp:string; Toip:string; ToPort:integer ;FromName:string; ToName:string; msg:string ):bool ;
var
DwFromIP:LongWord;
DwToIP :longWord;
wsaData:TWSADATA ;
s,ret :integer;
addr:TSockAddr ;
bOpt:integer;
packet : array [0..8192] of byte ;
fields_size,packet_size:integer;
pw:pdword;
len:longint;
IpHdr: TIpHdr;
IpVersion :Word;
IpSize: Word;
udpHdr: TUdpHdr;
udpsize:word;
psendHdr:^TSendHdr ;
udb_checkSum:word;
ip_packet: array [0..4095] of byte ;
ip_packet_size:integer;
pb:pbyte;
begin
WSAStartup(makeword(2,2), wsaData);
DwFromIP:=inet_Addr(pchar(FromIp)) ;
DwToIP:=inet_Addr(pchar(Toip)) ;
fillchar(addr, sizeof(addr),0);
addr.sin_addr.s_addr := DwToIP;
addr.sin_port := htons(ToPort);
addr.sin_family := AF_INET;
fillchar(packet,sizeof(packet),0);
packet_size:=0;
move(packet_header,packet[packet_size],sizeof(packet_header));
inc(packet_size,sizeof(packet_header));
len:=length(FromName)+1;
fillchar(field_header,sizeof(field_header),0);
field_header[0]:=len;
field_header[8]:=len;
move(field_header,packet[packet_size],sizeof(field_header));
inc(packet_size,sizeof(field_header));
StrCopy(@packet[packet_size], PAnsiChar(fromName));
inc(packet_size,(((len - 1) shr 2) + 1) shl 2); // align to 4 bytes
len:=length(ToName)+1;
fillchar(field_header,sizeof(field_header),0);
field_header[0]:=len;
field_header[8]:=len;
move(field_header,packet[packet_size],sizeof(field_header));
inc(packet_size,sizeof(field_header));
StrCopy(@packet[packet_size], PAnsiChar(ToName));
inc(packet_size,(((len - 1) shr 2) + 1) shl 2); // align to 4 bytes
len:=length(msg)+1;
fillchar(field_header,sizeof(field_header),0);
field_header[0]:=len;
field_header[8]:=len;
move(field_header,packet[packet_size],sizeof(field_header));
inc(packet_size,sizeof(field_header));
StrCopy(@packet[packet_size], PChar(msg));
inc(packet_size,len);
fields_size := packet_size - sizeof(packet_header);
pw:=@packet[40];
pw^:=gettickcount();
pw:=@packet[74] ;
pw^:= fields_size;
ip_packet_size:=sizeof(TIpHdr)+sizeof(TUdpHdr)+packet_size;
IpVersion:=4;
IpSize:=sizeof(TIpHdr) div sizeof(LongWord);
IpHdr.ip_verlen:=(IpVersion shl 4) or IpSize;
IpHdr.ip_tos:=0;
IpHdr.ip_len:=htons(ip_packet_size);
IpHdr.ip_id:=0;
IpHdr.ip_off:=0;
IpHdr.ip_ttl:=128;
IpHdr.ip_p:=IPPROTO_UDP;
IpHdr.ip_sum:=0;
IpHdr.ip_src:=dwFromIP;
IpHdr.ip_dst:=DwToIP;
udpsize:=sizeof(TudpHdr)+packet_size;
udpHdr.udp_sport:=htons(135);
udpHdr.udp_dport:=htons(135);
udpHdr.udp_ulen:=htons(udpsize);
udpHdr.udp_sum:=0;
//以下创建套接字时,采用了IPPROTO_UDP,所以不用做checksum
{
fillChar(ip_packet,sizeof(ip_packet),0);
pb:=@ip_packet[0];
psendHdr:= @ip_packet[0];
psendHdr^.send_src:=IpHdr.ip_src;
psendHdr^.send_dst:=IpHdr.ip_dst;
psendHdr^.send_P:=IpHdr.ip_p;
psendHdr^.send_len:= udpHdr.udp_ulen;
inc(pb,sizeof(TSendHdr));
move(udpHdr,pb^,sizeof(TudpHdr));
inc(pb,sizeof(TudpHdr));
Move(packet,pb^,packet_size);
udpHdr.udp_sum:=CheckSum(ip_packet,sizeof(TSendHdr)+sizeof(TudpHdr)+packet_size);
IpHdr.ip_sum:=checksum(ip_packet,ip_packet_size);
}
fillChar(ip_packet,sizeof(ip_packet),0);
pb:=@ip_packet[0];
Move(IpHdr,pb^,sizeof(TIpHdr));
inc(pb,sizeof(TIpHdr));
Move(udpHdr,pb^,sizeof(TudpHdr));
inc(pb,sizeof(TudpHdr));
Move(packet,pb^,packet_size);
//创建RawSocket
s :=socket(AF_INET,SOCK_RAW,IPPROTO_UDP);
if (s=INVALID_SOCKET) then
begin
showmessage('创建Socket错误');
exit;
end;
bOpt:=1;
//设置要以 IP 包传输
ret:=SetSockOpt(s,IPPROTO_IP,IP_HDRINCL,@bOpt,sizeof(bopt));
if ret=SOCKET_ERROR then
begin
showmessage('设置Socket错误');
exit;
end;
ret:=sendto(s, ip_packet, ip_packet_size, 0, TSOCKADDR(addr), sizeof(addr));
if ret=SOCKET_ERROR then showmessage('sendto 错误');
CloseHandle(s);
WSACleanup;
end;
end.
评论