郁闷的 原始UDP封包发送???

okmnji79513 2010-06-13 04:38:44
Delphi 代码:

const
IP_OPTIONS = 1 ;{ set/get IP options }
IP_HDRINCL = 2 ;{ header is included with data }
IP_TOS = 3 ;{ IP type of service and preced}
IP_TTL = 4 ;{ IP time to live }

type
IPHeader=record // 20字节的IP头
iphVerLen :byte; // 版本号和头长度(各占4位)
ipTOS :byte; // 服务类型
ipLength :WORD; // 封包总长度,即整个IP报的长度
ipID :WORD; // 封包标识,惟一标识发送的每一个数据报
ipFlags :WORD; // 标志
ipTTL :byte; // 生存时间,就是TTL
ipProtocol :byte; // 协议,可能是TCP、UDP、ICMP等
ipChecksum :WORD; // 校验和
ipSource :Cardinal; // 源IP地址
ipDestination :Cardinal; // 目标IP地址
end;
PIPHeader=^IPHeader;

UDPHeader = record
sourcePort :WORD; // 源端口号
destinationPort :WORD; // 目的端口号
len :WORD; // 封包长度
checksum :WORD; // 校验和
end;
PUDPHeader=^UDPHeader;

....

function checksum(const Apc:PChar;Asize:integer):WORD;
var cksum:Cardinal;
buff:array of char;
Index:integer;
W:WORD;
b:byte;
begin
Result:=0;

SetLength(buff,Asize);
CopyMemory(buff,Apc,Asize);

cksum := 0;
Index:=0;
while (Asize>1) do
begin
CopyMemory(@W,@buff[Index],sizeof(W));
cksum := cksum + W;
Asize := Asize - sizeof(WORD);
Index := Index + sizeof(WORD);
end;
// 是奇数
if (Asize mod 2)<>0 then
begin
CopyMemory(@b,@buff[Index],sizeof(b));
cksum:=cksum + b;
end;
// 将32位的chsum高16位和低16位相加,然后取反
cksum:=HIWORD(cksum)+LOWORD(cksum);
cksum:=not cksum;
Result:=cksum;
end;


{
计算UDP伪头校验和。UDP校验和基于如下几个域:
源IP地址
目的IP地址
8位0域
8位协议域
16位UDP长度
16位源端口号
16位目的端口号
16位UDP封包长度
16位UDP校验和(0)
UDP净荷
}
procedure ComputeUdpPseudoHeaderChecksum(
pIphdr:PIPHeader;
pUdphdr:PUDPHeader;
payload:PChar;
payloadlen:integer);
var buff:array[0..1023] of char;
ptr:PChar;
chksumlen:integer;
zero:ULONG;
i:integer;
begin
ptr:=@buff;
chksumlen := 0;
zero := 0;

// 包含源IP地址和目的IP地址
CopyMemory(ptr,@pIpHdr.ipSource,sizeof(pIpHdr.ipSource));
ptr:=ptr+sizeof(pIphdr.ipSource);
chksumlen :=chksumlen+ sizeof(pIphdr.ipSource);

CopyMemory(ptr, @pIphdr.ipDestination, sizeof(pIphdr.ipDestination));
ptr :=ptr + sizeof(pIphdr.ipDestination);
chksumlen :=chksumlen + sizeof(pIphdr.ipDestination);

// 包含8位0域
CopyMemory(ptr, @zero, 1);
ptr :=ptr + 1;
chksumlen := chksumlen + 1;

// 协议
CopyMemory(ptr, @pIphdr.ipProtocol, sizeof(pIphdr.ipProtocol));
ptr := ptr + sizeof(pIphdr.ipProtocol);
chksumlen := chksumlen + sizeof(pIphdr.ipProtocol);

// UDP长度
CopyMemory(ptr, @pUdphdr.len, sizeof(pUdphdr.len));
ptr :=ptr + sizeof(pUdphdr.len);
chksumlen :=chksumlen + sizeof(pUdphdr.len);

// UDP源端口号
CopyMemory(ptr, @pUdphdr.sourcePort, sizeof(pUdphdr.sourcePort));
ptr := ptr + sizeof(pUdphdr.sourcePort);
chksumlen := chksumlen + sizeof(pUdphdr.sourcePort);

// UDP目的端口号
CopyMemory(ptr, @pUdphdr.destinationPort, sizeof(pUdphdr.destinationPort));
ptr :=ptr + sizeof(pUdphdr.destinationPort);
chksumlen := chksumlen + sizeof(pUdphdr.destinationPort);

// 又是UDP长度
CopyMemory(ptr, @pUdphdr.len, sizeof(pUdphdr.len));
ptr := ptr + sizeof(pUdphdr.len);
chksumlen := chksumlen + sizeof(pUdphdr.len);

// 16位的UDP校验和,置为0
CopyMemory(ptr, @zero, sizeof(WORD));
ptr :=ptr + sizeof(WORD);
chksumlen :=chksumlen + sizeof(WORD);

// 净荷
CopyMemory(ptr, payload, payloadlen);
ptr :=ptr + payloadlen;
chksumlen :=chksumlen + payloadlen;

// 补齐到下一个16位边界
for i:=0 to payloadlen div 2 do
begin
ptr^ := chr(0);
ptr:=ptr + 1;
chksumlen:=chksumlen+1;
end;
// 计算这个校验和,将结果填充到UDP头
pUdphdr.checksum := checksum(PChar(@buff), chksumlen);
end;

procedure TForm1.Button10Click(Sender: TObject);
var bIncl:bool;// 即 longbool;
buff:array[0..1023] of char;
pIpHdr:PIPHeader;
pUdpHdr:PUDPHeader;
destAddr:SOCKADDR_IN;
nRet:integer;

s,szSourceIp,szDestIp:string;
nDestPort,nSourcePort:WORD;

pData:PChar;
begin
ZeroMemory(@buff,1024);

szSourceIp:='192.168.2.137';
szDestIp:='192.168.2.1';
nDestPort:=53;
nSourcePort:=1101;

s:=#$00+#$02 +#$01+#$00 +#$00+#$01 +#$00+#$00 +#$00+#$00 +#$00+#$00
+#$03 +'www' +#$03 +'163' +#$03 +'com' +#$00+#$00 +#$01+#$00 +#$01;

Memo1.Lines.Add('length(s) : '+inttostr(length(s)));

rawSocket:=socket(AF_INET,SOCK_RAW,IPPROTO_UDP);
bIncl:=true;
setsockopt(rawSocket,IPPROTO_IP,IP_HDRINCL,PChar(@bIncl),sizeof(bIncl));

pIpHdr:=PIPHeader(@buff);
pIpHdr.iphVerLen:= 4 shl 4 or (sizeof(IPHeader) div sizeof(ULONG));
pIpHdr.ipLength:=htons(sizeof(IPHeader)+sizeof(UDPHeader)+length(s));
pIpHdr.ipTTL:=128;
pIpHdr.ipProtocol:=IPPROTO_UDP;
pIpHdr.ipSource:=inet_addr(PChar(szSourceIp));
pIpHdr.ipDestination:=inet_addr(PChar(szDestIp));
pIpHdr.ipChecksum:=checksum(PChar(pIpHdr),sizeof(IPHeader));

Memo1.Lines.Add('pIpHdr.ipChecksum : '+inttostr(pIpHdr.ipChecksum));

pUdpHdr:=PUDPHeader(@buff[sizeof(IPHeader)]);
pUdpHdr.sourcePort:=htons(nSourcePort);
pUdpHdr.destinationPort:=htons(nDestPort);
pUdpHdr.len:=htons(sizeof(UDPHeader)+length(s));
pUdpHdr.checksum:=0;

pData:=@buff[sizeof(IPHeader)+sizeof(UDPHeader)];
CopyMemory(pData,PChar(s),length(s));
ComputeUdpPseudoHeaderChecksum(pIpHdr,pUdpHdr,pData,length(s));

Memo1.Lines.Add('pUdpHdr.checksum : '+inttostr(pUdpHdr.checksum));

ZeroMemory(@destAddr,sizeof(SOCKADDR_IN));
destAddr.sin_family:=AF_INET;
destAddr.sin_port:=htons(nDestPort);
destAddr.sin_addr.S_addr:=inet_addr(PChar(szDestIp));

nRet:=sendto(rawSocket,buff,sizeof(IPHeader)+sizeof(UDPHeader)+length

(s),0,destAddr,sizeof(destAddr));
if nRet=SOCKET_ERROR then
begin
nRet:=WSAGetLastError;
memo1.Lines.Add('Send failed : '+inttostr(nRet));
end
else
Memo1.Lines.Add('Send '+inttostr(nRet)+' bytes');

CloseSocket(rawSocket);
end;

点击 Button10 ,打印出:
length(s) : 29
pIpHdr.ipChecksum : 55732
pUdpHdr.checksum : 8523
Send failed : 10049

但是 C++ 代码,运行是 OK的。

查了 好久,查不出Delphi代码出错的原因,请指教。

PS:长度 原因,C++代码 与楼下 贴出。
...全文
721 41 打赏 收藏 转发到动态 举报
写回复
用AI写文章
41 条回复
切换为时间正序
请发表友善的回复…
发表回复
a1052104 2011-03-06
  • 打赏
  • 举报
回复
原始UDP数据包发送:
将目的IP填写为虚拟机的192.16.117.129
主机IP192.168.1.121
目的端口139
源端口139

用wireshark抓包,怎么抓不到?
a1052104 2011-02-27
  • 打赏
  • 举报
回复
您好,我要写Windows环境下实现原始UDP数据包的发送这个论文...但是不怎么会,想请教您 原始UDP数据包发送的意义,研究前景
251556537@qq.com
okmnji79513 2010-06-14
  • 打赏
  • 举报
回复
[Quote=引用 35 楼 sanguomi 的回复:]
不要怀疑包,我抓包试了下,包发送,IP,其他都没问题
只是使用API的问题
sendto 在你原来的代码中用的是winsock里的sendto
那份C++代码 使用的是 winsock2里的sendto
1和2 参数有点点小区别,需要做次强制转换
[/Quote]
观察真仔细啊

[Quote=引用 38 楼 sanguomi 的回复:]
引用 37 楼 okmnji79513 的回复:
引用 36 楼 sanguomi 的回复:
楼主人呢 等下我看世界杯去拉

十分感谢

还不行?我测试没问题的
[/Quote]
OK 了,再次感谢,又上了一课啊。
sanguomi 2010-06-14
  • 打赏
  • 举报
回复
[Quote=引用 37 楼 okmnji79513 的回复:]
引用 36 楼 sanguomi 的回复:
楼主人呢 等下我看世界杯去拉

十分感谢
[/Quote]
还不行?我测试没问题的
okmnji79513 2010-06-14
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 sanguomi 的回复:]
楼主人呢 等下我看世界杯去拉
[/Quote]
十分感谢
sanguomi 2010-06-14
  • 打赏
  • 举报
回复
楼主人呢 等下我看世界杯去拉
sanguomi 2010-06-14
  • 打赏
  • 举报
回复
不要怀疑包,我抓包试了下,包发送,IP,其他都没问题
只是使用API的问题
sendto 在你原来的代码中用的是winsock里的sendto
那份C++代码 使用的是 winsock2里的sendto
1和2 参数有点点小区别,需要做次强制转换
okmnji79513 2010-06-14
  • 打赏
  • 举报
回复
[Quote=引用 32 楼 sanguomi 的回复:]
我把楼主的问题解决了
[/Quote]
讲讲啊...
sanguomi 2010-06-14
  • 打赏
  • 举报
回复
引用改成
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Winsock2;
不需要 winsock;
winsock 不要和 Winsock2一起用
另外其他地方做些小改动,全改成Winsock2格式的
修改后的DELPHI代码

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Winsock2;

const
IP_OPTIONS = 1 ;{ set/get IP options }
IP_HDRINCL = 2 ;{ header is included with data }
IP_TOS = 3 ;{ IP type of service and preced}
IP_TTL = 4 ;{ IP time to live }

type
IPHeader=record // 20字节的IP头
iphVerLen :byte; // 版本号和头长度(各占4位)
ipTOS :byte; // 服务类型
ipLength :WORD; // 封包总长度,即整个IP报的长度
ipID :WORD; // 封包标识,惟一标识发送的每一个数据报
ipFlags :WORD; // 标志
ipTTL :byte; // 生存时间,就是TTL
ipProtocol :byte; // 协议,可能是TCP、UDP、ICMP等
ipChecksum :WORD; // 校验和
ipSource :Cardinal; // 源IP地址
ipDestination :Cardinal; // 目标IP地址
end;
PIPHeader=^IPHeader;

UDPHeader = record
sourcePort :WORD; // 源端口号
destinationPort :WORD; // 目的端口号
len :WORD; // 封包长度
checksum :WORD; // 校验和
end;
PUDPHeader=^UDPHeader;

TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var wVersionRequested:DWORD;
wsaData1:tWSADATA;
err:integer;
begin
wVersionRequested:=MAKEWORD(2,2);
err:=WSAStartup(wVersionRequested,wsaData1);
if err<>0 then
begin
showmessage('WSAStartup failed');
exit;
end;

if (HIBYTE(wsaData1.wVersion)<>2)or(LOBYTE(wsaData1.wVersion)<>2) then
begin
showmessage('(HIBYTE(wsaData1.wVersion)<>2)||(LOBYTE(wsaData1.wVersion)');
exit;
end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
WSACleanup();
end;

function checksum(const Apc:PChar;Asize:integer):WORD;
var cksum:Cardinal;
buff:array of char;
Index:integer;
W:WORD;
b:byte;
begin
Result:=0;

SetLength(buff,Asize);
CopyMemory(buff,Apc,Asize);

cksum := 0;
Index:=0;
while (Asize>1) do
begin
CopyMemory(@W,@buff[Index],sizeof(W));
cksum := cksum + W;
Asize := Asize - sizeof(WORD);
Index := Index + sizeof(WORD);
end;
// 是奇数
if (Asize mod 2)<>0 then
begin
CopyMemory(@b,@buff[Index],sizeof(b));
cksum:=cksum + b;
end;
// 将32位的chsum高16位和低16位相加,然后取反
cksum:=HIWORD(cksum)+LOWORD(cksum);
cksum:=not cksum;
Result:=cksum;
end;


{
计算UDP伪头校验和。UDP校验和基于如下几个域:
源IP地址
目的IP地址
8位0域
8位协议域
16位UDP长度
16位源端口号
16位目的端口号
16位UDP封包长度
16位UDP校验和(0)
UDP净荷
}
procedure ComputeUdpPseudoHeaderChecksum(
pIphdr:PIPHeader;
pUdphdr:PUDPHeader;
payload:PChar;
payloadlen:integer);
var buff:array[0..1023] of char;
ptr:PChar;
chksumlen:integer;
zero:ULONG;
i:integer;
begin
ptr:=@buff;
chksumlen := 0;
zero := 0;

// 包含源IP地址和目的IP地址
CopyMemory(ptr,@pIpHdr.ipSource,sizeof(pIpHdr.ipSource));
ptr:=ptr+sizeof(pIphdr.ipSource);
chksumlen :=chksumlen+ sizeof(pIphdr.ipSource);

CopyMemory(ptr, @pIphdr.ipDestination, sizeof(pIphdr.ipDestination));
ptr :=ptr + sizeof(pIphdr.ipDestination);
chksumlen :=chksumlen + sizeof(pIphdr.ipDestination);

// 包含8位0域
CopyMemory(ptr, @zero, 1);
ptr :=ptr + 1;
chksumlen := chksumlen + 1;

// 协议
CopyMemory(ptr, @pIphdr.ipProtocol, sizeof(pIphdr.ipProtocol));
ptr := ptr + sizeof(pIphdr.ipProtocol);
chksumlen := chksumlen + sizeof(pIphdr.ipProtocol);

// UDP长度
CopyMemory(ptr, @pUdphdr.len, sizeof(pUdphdr.len));
ptr :=ptr + sizeof(pUdphdr.len);
chksumlen :=chksumlen + sizeof(pUdphdr.len);

// UDP源端口号
CopyMemory(ptr, @pUdphdr.sourcePort, sizeof(pUdphdr.sourcePort));
ptr := ptr + sizeof(pUdphdr.sourcePort);
chksumlen := chksumlen + sizeof(pUdphdr.sourcePort);

// UDP目的端口号
CopyMemory(ptr, @pUdphdr.destinationPort, sizeof(pUdphdr.destinationPort));
ptr :=ptr + sizeof(pUdphdr.destinationPort);
chksumlen := chksumlen + sizeof(pUdphdr.destinationPort);

// 又是UDP长度
CopyMemory(ptr, @pUdphdr.len, sizeof(pUdphdr.len));
ptr := ptr + sizeof(pUdphdr.len);
chksumlen := chksumlen + sizeof(pUdphdr.len);

// 16位的UDP校验和,置为0
CopyMemory(ptr, @zero, sizeof(WORD));
ptr :=ptr + sizeof(WORD);
chksumlen :=chksumlen + sizeof(WORD);

// 净荷
CopyMemory(ptr, payload, payloadlen);
ptr :=ptr + payloadlen;
chksumlen :=chksumlen + payloadlen;

// 补齐到下一个16位边界
for i:=0 to payloadlen div 2 do
begin
ptr^ := chr(0);
ptr:=ptr + 1;
chksumlen:=chksumlen+1;
end;
// 计算这个校验和,将结果填充到UDP头
pUdphdr.checksum := checksum(PChar(@buff), chksumlen);
end;

procedure TForm1.Button1Click(Sender: TObject);
var bIncl:bool;// 即 longbool;
buff:array[0..1023] of char;
pIpHdr:PIPHeader;
pUdpHdr:PUDPHeader;
destAddr: TSOCKADDRIN;
nRet:integer;

s,szSourceIp,szDestIp:string;
nDestPort,nSourcePort:WORD;

pData:PChar;
rawSocket:TSocket;
begin
ZeroMemory(@buff,1024);

szSourceIp:='10.0.0.138';
szDestIp:='10.0.0.138';
nDestPort:=53;
nSourcePort:=1101;

s:=#$00+#$02 +#$01+#$00 +#$00+#$01 +#$00+#$00 +#$00+#$00 +#$00+#$00
+#$03 +'www' +#$03 +'163' +#$03 +'com' +#$00+#$00 +#$01+#$00 +#$01;
{
s:=#$00+#$02+#$01+#$00+#$00+#$01+#$00+#$00+#$00+#$00+#$00+#$00+#$03+#$77+#$77+#$77+#$03+#$31
+#$6+#$33+#$03+#$63+#$6f+#$6d+#$00+#$00+#$01+#$00+#$01;
}
Memo1.Lines.Add('length(s) : '+inttostr(length(s)));

rawSocket:=socket(AF_INET,SOCK_RAW,IPPROTO_UDP);
bIncl:=true;
setsockopt(rawSocket,IPPROTO_IP,IP_HDRINCL,PChar(@bIncl),sizeof(bIncl));

pIpHdr:=PIPHeader(@buff);
pIpHdr.iphVerLen:= 4 shl 4 or (sizeof(IPHeader) div sizeof(ULONG));
pIpHdr.ipLength:=htons(sizeof(IPHeader)+sizeof(UDPHeader)+length(s));
pIpHdr.ipTTL:=128;
pIpHdr.ipProtocol:=IPPROTO_UDP;
pIpHdr.ipSource:=inet_addr(PChar(szSourceIp));
pIpHdr.ipDestination:=inet_addr(PChar(szDestIp));
pIpHdr.ipChecksum:=checksum(PChar(pIpHdr),sizeof(IPHeader));

Memo1.Lines.Add('pIpHdr.ipChecksum : '+inttostr(pIpHdr.ipChecksum));

pUdpHdr:=PUDPHeader(@buff[sizeof(IPHeader)]);
pUdpHdr.sourcePort:=htons(nSourcePort);
pUdpHdr.destinationPort:=htons(nDestPort);
pUdpHdr.len:=htons(sizeof(UDPHeader)+length(s));
pUdpHdr.checksum:=0;

pData:=@buff[sizeof(IPHeader)+sizeof(UDPHeader)];
CopyMemory(pData,PChar(s),length(s));
ComputeUdpPseudoHeaderChecksum(pIpHdr,pUdpHdr,pData,length(s));

Memo1.Lines.Add('pUdpHdr.checksum : '+inttostr(pUdpHdr.checksum));

ZeroMemory(@destAddr,sizeof(TSOCKADDRIN));
destAddr.sin_family:=AF_INET;
destAddr.sin_port:=htons(nDestPort);
destAddr.sin_addr.S_addr:=inet_addr(PChar(szDestIp));


nRet:=sendto(rawSocket,buff,sizeof(IPHeader)+sizeof(UDPHeader)+length(s),0, PSockAddr(@destAddr), sizeof(destAddr));
if nRet=SOCKET_ERROR then
begin
nRet:=WSAGetLastError;
memo1.Lines.Add('Send failed : '+inttostr(nRet));
end
else
Memo1.Lines.Add('Send '+inttostr(nRet)+' bytes');

CloseSocket(rawSocket);
end;

end.
sanguomi 2010-06-14
  • 打赏
  • 举报
回复
我把楼主的问题解决了
okmnji79513 2010-06-14
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 qq286251099 的回复:]
0
没玩过.
你试试根据VC 的 setsockopt 定义 在D里重新定义下 看
[/Quote]

setsockopt 就那几个参数 。
直接写成 setsockopt(rawSocket,0,2,@bIncl,sizeof(bIncl)); 还是 10049 。
QQ286251099 2010-06-14
  • 打赏
  • 举报
回复
0
没玩过.
你试试根据VC 的 setsockopt 定义 在D里重新定义下 看
okmnji79513 2010-06-14
  • 打赏
  • 举报
回复
To QQ286251099 :
你搞错了,我发的是 原始UDP包,你把 setsockopt 注释掉后,我自己定义的 IPHeader 数据就被当成UDP的一部分给发出去了。

你可以抓包看,长度都变了,变长了sizeof(IPHeader)。
okmnji79513 2010-06-14
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 sqldebug_fan 的回复:]
10049是请求的地址无效,是不是DNS解析和服务器有问题。
[/Quote]
我出现 10049 时,数据包就根本没发出去(我用抓包软件看的,数据包没有发出去),
"nRet:=sendto(rawSocket,buff,sizeof(IPHeader)+sizeof(UDPHeader)+length
(s),0,destAddr,sizeof(destAddr));"这句不成功,WSAGetLastError返回 10049

如果是 "DNS解析和服务器有问题" 的话,那为何 C++ 代码就 OK??如何解释??
QQ286251099 2010-06-14
  • 打赏
  • 举报
回复

program Project1;

{$APPTYPE CONSOLE}

uses
SysUtils,
Windows,
WinSock;
const
IP_OPTIONS = 1 ;{ set/get IP options }
IP_HDRINCL = 2 ;{ header is included with data }
IP_TOS = 3 ;{ IP type of service and preced}
IP_TTL = 4 ;{ IP time to live }

type
IPHeader=record // 20字节的IP头
iphVerLen :byte; // 版本号和头长度(各占4位)
ipTOS :byte; // 服务类型
ipLength :WORD; // 封包总长度,即整个IP报的长度
ipID :WORD; // 封包标识,惟一标识发送的每一个数据报
ipFlags :WORD; // 标志
ipTTL :byte; // 生存时间,就是TTL
ipProtocol :byte; // 协议,可能是TCP、UDP、ICMP等
ipChecksum :WORD; // 校验和
ipSource :Cardinal; // 源IP地址
ipDestination :Cardinal; // 目标IP地址
end;
PIPHeader=^IPHeader;

UDPHeader = record
sourcePort :WORD; // 源端口号
destinationPort :WORD; // 目的端口号
len :WORD; // 封包长度
checksum :WORD; // 校验和
end;
PUDPHeader=^UDPHeader;



function checksum(const Apc:PChar;Asize:integer):WORD;
var cksum:Cardinal;
buff:array of char;
Index:integer;
W:WORD;
b:byte;
begin
Result:=0;

SetLength(buff,Asize);
CopyMemory(buff,Apc,Asize);

cksum := 0;
Index:=0;
while (Asize>1) do
begin
CopyMemory(@W,@buff[Index],sizeof(W));
cksum := cksum + W;
Asize := Asize - sizeof(WORD);
Index := Index + sizeof(WORD);
end;
// 是奇数
if (Asize mod 2)<>0 then
begin
CopyMemory(@b,@buff[Index],sizeof(b));
cksum:=cksum + b;
end;
// 将32位的chsum高16位和低16位相加,然后取反
cksum:=HIWORD(cksum)+LOWORD(cksum);
cksum:=not cksum;
Result:=cksum;
end;


{
计算UDP伪头校验和。UDP校验和基于如下几个域:
源IP地址
目的IP地址
8位0域
8位协议域
16位UDP长度
16位源端口号
16位目的端口号
16位UDP封包长度
16位UDP校验和(0)
UDP净荷
}
procedure ComputeUdpPseudoHeaderChecksum(
pIphdr:PIPHeader;
pUdphdr:PUDPHeader;
payload:PChar;
payloadlen:integer);
var buff:array[0..1023] of char;
ptr:PChar;
chksumlen:integer;
zero:ULONG;
i:integer;
begin
ptr:=@buff;
chksumlen := 0;
zero := 0;

// 包含源IP地址和目的IP地址
CopyMemory(ptr,@pIpHdr.ipSource,sizeof(pIpHdr.ipSource));
ptr:=ptr+sizeof(pIphdr.ipSource);
chksumlen :=chksumlen+ sizeof(pIphdr.ipSource);

CopyMemory(ptr, @pIphdr.ipDestination, sizeof(pIphdr.ipDestination));
ptr :=ptr + sizeof(pIphdr.ipDestination);
chksumlen :=chksumlen + sizeof(pIphdr.ipDestination);

// 包含8位0域
CopyMemory(ptr, @zero, 1);
ptr :=ptr + 1;
chksumlen := chksumlen + 1;

// 协议
CopyMemory(ptr, @pIphdr.ipProtocol, sizeof(pIphdr.ipProtocol));
ptr := ptr + sizeof(pIphdr.ipProtocol);
chksumlen := chksumlen + sizeof(pIphdr.ipProtocol);

// UDP长度
CopyMemory(ptr, @pUdphdr.len, sizeof(pUdphdr.len));
ptr :=ptr + sizeof(pUdphdr.len);
chksumlen :=chksumlen + sizeof(pUdphdr.len);

// UDP源端口号
CopyMemory(ptr, @pUdphdr.sourcePort, sizeof(pUdphdr.sourcePort));
ptr := ptr + sizeof(pUdphdr.sourcePort);
chksumlen := chksumlen + sizeof(pUdphdr.sourcePort);

// UDP目的端口号
CopyMemory(ptr, @pUdphdr.destinationPort, sizeof(pUdphdr.destinationPort));
ptr :=ptr + sizeof(pUdphdr.destinationPort);
chksumlen := chksumlen + sizeof(pUdphdr.destinationPort);

// 又是UDP长度
CopyMemory(ptr, @pUdphdr.len, sizeof(pUdphdr.len));
ptr := ptr + sizeof(pUdphdr.len);
chksumlen := chksumlen + sizeof(pUdphdr.len);

// 16位的UDP校验和,置为0
CopyMemory(ptr, @zero, sizeof(WORD));
ptr :=ptr + sizeof(WORD);
chksumlen :=chksumlen + sizeof(WORD);

// 净荷
CopyMemory(ptr, payload, payloadlen);
ptr :=ptr + payloadlen;
chksumlen :=chksumlen + payloadlen;

// 补齐到下一个16位边界
for i:=0 to payloadlen div 2 do
begin
ptr^ := chr(0);
ptr:=ptr + 1;
chksumlen:=chksumlen+1;
end;
// 计算这个校验和,将结果填充到UDP头
pUdphdr.checksum := checksum(PChar(@buff), chksumlen);
end;

var bIncl:Integer;// 即 longbool;
buff:array[0..1023] of char;
pIpHdr:PIPHeader;
pUdpHdr:PUDPHeader;
destAddr:SOCKADDR_IN;
nRet:integer;

s,szSourceIp,szDestIp:string;
nDestPort,nSourcePort:WORD;
rawSocket:TSocket;
pData:PChar;
WSData: TWSAData;
begin
ZeroMemory(@buff,1024);
WSAStartup(MakeWord(1,1),WSData);
szSourceIp:='192.168.2.137';
szDestIp:='192.168.2.1';
nDestPort:=53;
nSourcePort:=1101;

s:=#$00+#$02 +#$01+#$00 +#$00+#$01 +#$00+#$00 +#$00+#$00 +#$00+#$00
+#$03 +'www' +#$03 +'163' +#$03 +'com' +#$00+#$00 +#$01+#$00 +#$01;

Writeln('length(s) : '+inttostr(length(s)));

rawSocket:=socket(AF_INET,SOCK_RAW,IPPROTO_UDP);
bIncl:=1;
//nRet:=setsockopt(rawSocket,IPPROTO_IP,IP_HDRINCL,@bIncl,4);
if nRet=SOCKET_ERROR then
begin
nRet:=WSAGetLastError;
Writeln('setsockopt failed : '+inttostr(nRet));
end
else
Writeln('setsockopt '+inttostr(nRet)+'');
pIpHdr:=PIPHeader(@buff);
pIpHdr.iphVerLen:= 4 shl 4 or (sizeof(IPHeader) div sizeof(ULONG));
pIpHdr.ipLength:=htons(sizeof(IPHeader)+sizeof(UDPHeader)+length(s));
pIpHdr.ipTTL:=128;
pIpHdr.ipProtocol:=IPPROTO_UDP;
pIpHdr.ipSource:=inet_addr(PChar(szSourceIp));
pIpHdr.ipDestination:=inet_addr(PChar(szDestIp));
pIpHdr.ipChecksum:=checksum(PChar(pIpHdr),sizeof(IPHeader));

Writeln('pIpHdr.ipChecksum : '+inttostr(pIpHdr.ipChecksum));

pUdpHdr:=PUDPHeader(@buff[sizeof(IPHeader)]);
pUdpHdr.sourcePort:=htons(nSourcePort);
pUdpHdr.destinationPort:=htons(nDestPort);
pUdpHdr.len:=htons(sizeof(UDPHeader)+length(s));
pUdpHdr.checksum:=0;

pData:=@buff[sizeof(IPHeader)+sizeof(UDPHeader)];
CopyMemory(pData,PChar(s),length(s));
ComputeUdpPseudoHeaderChecksum(pIpHdr,pUdpHdr,pData,length(s));

Writeln('pUdpHdr.checksum : '+inttostr(pUdpHdr.checksum));

ZeroMemory(@destAddr,sizeof(SOCKADDR_IN));
destAddr.sin_family:=AF_INET;
destAddr.sin_port:=htons(nDestPort);
destAddr.sin_addr.S_addr:=inet_addr(PChar(szDestIp));

nRet:=sendto(rawSocket,buff,sizeof(IPHeader)+sizeof(UDPHeader)+length(s),0,destAddr,sizeof(destAddr));
if nRet=SOCKET_ERROR then
begin
nRet:=WSAGetLastError;
Writeln('Send failed : '+inttostr(nRet));
end
else
Writeln('Send '+inttostr(nRet)+' bytes');

CloseSocket(rawSocket);
Readln(rawSocket);
WSACleanup;
end.



这样可以
好象不用 setsockopt ....
SQLDebug_Fan 2010-06-14
  • 打赏
  • 举报
回复
10049是请求的地址无效,是不是DNS解析和服务器有问题。
okmnji79513 2010-06-14
  • 打赏
  • 举报
回复
UP一下

注意 3楼 有代码可下载,期待好心人帮忙调试找错
okmnji79513 2010-06-14
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 delphiguy 的回复:]
10093是WSANOTINITIALISED,似乎没有调用WSAStartup或者调用失败。
[/Quote]
我没有 10093 过啊, 我一直是 10049
  • 打赏
  • 举报
回复
10093是WSANOTINITIALISED,似乎没有调用WSAStartup或者调用失败。
okmnji79513 2010-06-14
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 delphiguy 的回复:]
你前面的定义是bIncl:boolean;
boolean1字节,longbool4字节,按照Win32 API setsockopt的说明,“ To enable a Boolean option, optval points to a nonzero integer. To disable the option optval points to an integer equal to zer……
[/Quote]
Sorry,我在 Button7 里写了 boolean ,给忘了...

但按你那样改,还是不行
加载更多回复(21)

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧