原始套接字不能拦截ICMP包
总的意思:可以接收到经原始套接字发送给其他主机后返回的ECHO_RELY回声包,但是拦截不到其他主机发来的请求包,用别的机子ping本机,根本收不到包。。。我的目的是想接收到任何从其他主机发送过来的ICMP包,从意图看,没必要用混杂模式,而且函数设置混杂模式根本不行,返回错误10022。
我怀疑是不系统自己处理了请求包,然后我不能处理。。。跪求大神帮助。
具体说:创建了原始套接字,用以拦截ICMP包,在用sendto发送成功,而且recvfrom可以接受到回应的数据包,而且,用wireshark看发的包和收的包,都是正确的,用writefile把包打印到磁盘。但是从别的主机ping本机却根本收不到ECHO_REQUEST包,用wireshark拦截icmp,可以看到ECHO_REQUEST请求包,而且本机有reply正确包回应,但是recvfrom的循环就是收不到包,如果能收到,可以看到outputdebugstring的消息,也可以看到用writefile写的包文件。
WSADATA wsa;
WSAStartup(MAKEWORD(2,2),&wsa);
SOCKET sockRaw;
static char recvBuffer[1024];
static char sendBuffer[1024];
static int recvCount;
struct sockaddr_in dest,from;
ZeroMemory(&dest,sizeof(dest));
ZeroMemory(&from,sizeof(from));
dest.sin_family=AF_INET;
from.sin_family = AF_INET;
from.sin_addr.S_un.S_addr = INADDR_ANY;
from.sin_port = htons(9999);
int fromlenth = sizeof(from);
int destlenth = sizeof(dest);
sockRaw = WSASocket (AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);
if (sockRaw == INVALID_SOCKET)
{
char temp[500];
sprintf(temp,"INVALID_SOCKET :%d\n",WSAGetLastError());
OutputDebugString(temp);
ExitProcess(0);
}
////虽然是原始套接字,但是如果不绑定,会发生错误代码10022的BUG
if(bind(sockRaw,(const struct sockaddr *)&from,sizeof(from))==SOCKET_ERROR)
{
char temp[500];
sprintf(temp,"Bind Error :%d\n",WSAGetLastError());
OutputDebugString(temp);
}
int ret=0,timeout=2000;
ret = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));
if(ret==SOCKET_ERROR)
{
char temp[500];
sprintf(temp,"SET SO_RCVTIMEO ERROR :%d\n",WSAGetLastError());
OutputDebugString(temp);
}
ret = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));
if(ret==SOCKET_ERROR)
{
char temp[500];
sprintf(temp,"SET SO_SNDTIMEO ERROR :%d\n",WSAGetLastError());
OutputDebugString(temp);
}
char data[1000]="I love you!\n";
for(int icmpcount=0;;icmpcount++)
{
dest.sin_addr.S_un.S_addr = inet_addr("192.168.111.131");
int dasize = FillIcmpPacket(sendBuffer,data,strlen(data)+1);
((IcmpHeader*)sendBuffer)->i_cksum=0;
((IcmpHeader*)sendBuffer)->i_cksum=checksum((USHORT*)sendBuffer,dasize);
sendto(sockRaw,sendBuffer,dasize,0,(struct sockaddr*)&dest,destlenth);
recvCount = recvfrom(sockRaw,recvBuffer,1024,0,(struct sockaddr*)&from,&fromlenth);
if(recvCount==0)
{
OutputDebugString("RecvCount is 0!");
}
else if(recvCount==SOCKET_ERROR)
{
char err[256];
sprintf(err,"SOCKET_ERROR,code:%d\n",WSAGetLastError());
OutputDebugString(err);
if(WSAGetLastError()==WSAETIMEDOUT)
{
continue;
}
else
{
return 0;
}
}
else
{
int dataoffset=0;
dataoffset = DecodeIcmp(recvBuffer,recvCount,from);
//把抓到的包按次序生成文件
char temp[MAX_PATH];
sprintf(temp,"c:\\users\\jay\\desktop\\icmp_packet\\%s_%d.icmp",inet_ntoa(from.sin_addr),icmpcount);
HANDLE File = CreateFile(temp,GENERIC_ALL,0,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
DWORD writen;
if(WriteFile(File,recvBuffer,recvCount,&writen,0)==0)
{
OutputDebugString("WriteFileError!\n");
}
CloseHandle(File);
}
Sleep(50);
}
填报函数:
int FillIcmpPacket(char * icmp_data,void* databuffer,int datasize)
{
/*
功能:填ICMP包,返回填包的大小(含ICMP头),即sendto的发送大小
参数:
char * icmp_data,icmp包的缓冲区,
void* databuffer,指向待写入ICMP包的数据区,
int datasize 待写入数据的长度
返回值:数据包的大小
*/
IcmpHeader *icmp_hdr;
char *datapart;
icmp_hdr = (IcmpHeader*)icmp_data;
icmp_hdr->i_type = ECHO_REQUEST;
icmp_hdr->i_code = 0;
icmp_hdr->i_id = 0x9203;
icmp_hdr->i_cksum = 0;
icmp_hdr->i_seq =0x1234;
icmp_hdr->timestamp = GetTickCount(); //设置时间戳
datapart = icmp_data + sizeof(IcmpHeader);
memcpy(datapart,databuffer,datasize);
return datasize+sizeof(IcmpHeader);
}