在看网上一段关于原始socket时碰到的一个udp包不能截取的问题,有经验的进来看看(200分)

T

thread_

Unregistered / Unconfirmed
GUEST, unregistred user!
最近在网络上看到一段代码,是用来截获局域网内通信包,因为原始的内容只包括了tcp包的截取,没看到udp的截取,想搞个udp的,但一直都试不成功,有做过的帮忙看看
//以下是创建套接字的函数
procedure TMainForm.FormCreate(Sender: TObject);
var
WSAData: TWSAData;
ServerAddr: TSockAddrIn;
OptVal: Integer;
OptRet: DWord;
Ret: Integer;
begin
Ret:=WSAStartup($202, WSAData);
if Ret<>0 then
begin
ShowMessage('WSAStartup failed with error '+IntToStr(Ret));
Exit
end;
s:=WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, nil, 0, WSA_FLAG_OVERLAPPED);//这里创建的是原生的socket
if s=INVALID_SOCKET then
begin
ShowMessage('WSASocket failed with error '+IntToStr(WSAGetLastError));
Exit
end;
ServerAddr.sin_family:=AF_INET;
ServerAddr.sin_port:=htons(59613);
ServerAddr.sin_addr.S_addr:=inet_addr('10.0.1.66');//这个需要改成自己的ip,且不能用htonl(INADDR_ANY),否则会报错,只能截一个网卡的包
if bind(s, @ServerAddr, SizeOf(ServerAddr))=SOCKET_ERROR then
begin
ShowMessage('bind failed with error '+IntToStr(WSAGetLastError));
Exit
end;
OptVal:=1;
if WSAIoctl(s, SIO_RCVALL, @OptVal, SizeOf(OptVal), nil, 0, @OptRet, nil, nil)=SOCKET_ERROR then
begin
ShowMessage('WSAIoctl failed with error '+IntToStr(WSAGetLastError));
Exit
end;
if WSAAsyncSelect(s, Handle, WM_Socket, FD_READ)=SOCKET_ERROR then//消息模型
ShowMessage('WSAAsyncSelect failed with error '+IntToStr(WSAGetLastError))
end;

type
//TCP抱文结构如下表:
//TCP源端口号(16位) TCP目的端口号(16位)
//序列号(32位) //确认号(32位)
//头长度(4位) 保留位(4位) 标记位(8位) 窗口大小(16位)
//检验和(16位) 紧急指针(16位)
//可选项+填充
//数据区(最大1460字节)
PIPv4_HDR = ^TIPv4_HDR;
TIPv4_HDR = record
VerLen: Byte;
TOS: Byte;
TotalLength: Word;
ID: Word;
Offset: Word;
TTL: Byte;
Protocol: Byte;
CheckSum: Word;
SrcAddr: Cardinal;
DestAddr: Cardinal
end;

PTCP_HDR = ^TTCP_HDR;
TTCP_HDR = record
SrcPort: Word;
DestPort: Word;
SEQ: Cardinal;
ACK: Cardinal;
LenFlag: Word;
WinSize: Word;
CheckSum: Word;
URG: Word
end;
//UDP抱文结构如下表:
//UDP源端口号(16位) UDP目标端口号(16位)
//这个报文长度(16位) UDP校验和(16位) //数据区(最大1472字节)
PUDP_HDR = ^TUDP_HDR;
TUDP_HDR = record
SrcPort : Word;
DestPort: Word;
LenFlag : Word;
CheckSum: Word;
end;
截获udp包的函数:

procedure TMainForm.WMSocket(var Msg: TMessage);
const
BufSize = 65535;
var
Buf: array [0..BufSize] of Char;
IPHeader: PIPv4_HDR;
IPHeaderLen: Byte;
TCPHeader: PTCP_HDR;
UDPHeader: PUDP_HDR;
TCPHeaderLen: Byte;
Data: PChar;
Ret: Integer;
str : string;
begin
ZeroMemory(@Buf, BufSize);
Ret:=recv(s, Buf, BufSize, 0);
if Ret=SOCKET_ERROR then
begin
ShowMessage('recv failed with error '+IntToStr(WSAGetLastError));
Exit
end;
IPHeader:=PIPv4_HDR(@Buf[0]);//ip包的头部
if IPHeader.Protocol=IPPROTO_TCP then
begin
IPHeaderLen:=(IPHeader.VerLen and $F)*4;//ip头的宽度,每四字节一个单位最大等于1111=15*4=60字节
TCPHeader:=PTCP_HDR(@Buf[IPHeaderLen]);
//if (ntohs(TCPHeader.SrcPort)=2969) or (ntohs(TCPHeader.DestPort)=2969) then
//begin
TCPHeaderLen:=(ntohs(TCPHeader.LenFlag) shr 12)*4;//tcp包头部的长度
Data:=@Buf[IPHeaderLen+TCPHeaderLen];
str := UTF8ToAnsi(Data);//问题一,这里tcp/ip在通讯时用utf8这种格式的编码来转换吗?
str := Trim(str);
if str <> '' then
memoTCP.Lines.Add(str);
end
else if IPHeader.Protocol=IPPROTO_UDP then
begin
IPHeaderLen:= (IPHeader.VerLen and $F)*4;
UDPHeader := PUDP_HDR(@Buf[IPHeaderLen]);
if (htons(UDPHeader.SrcPort) = 6789) or (htons(UDPHeader.SrcPort) = 9876) then//在这里判断端口是因为我另外写了一个在6789及9876端口上互发udp包的程序,
//问题二,这里的判断永远不会为true,这个是什么原因?
begin
Data := @Buf[IPHeaderLen + SizeOf(TUDP_HDR)];
str := UTF8ToAnsi(Data); //问题三,UDP的包是否也需做此处理? 目前在我的局域网测试的时候,几乎90%的包转换以后都变成空字符串了
//str := data;
//str := Trim(str);
// if str <> '' then
memoUDP.Lines.Add(str);
//end;
end;
end;
 
顶部