typedef struct icmp_hdr
{
unsigned char icmp_type; //消息类型
unsigned char icmp_code; //代码
unsigned short icmp_checksum;
unsigned short icmp_id;
unsigned short icmp_sequence;
unsigned long icmp_timestamp;
}ICMP_HDR,*PICMP_HDR;
typedef struct _IPHeader
{
UCHAR iphVerLen;
UCHAR ipTOS;
USHORT ipLength;
USHORT ipID;
USHORT ipFlags;
UCHAR ipTTL;
UCHAR ipProtocol;
USHORT ipChecksum;
ULONG ipSource;
ULONG ipDestination;
}IPHeader,*PIPHeader;
void Ping()
{
char szDestIp[] = "127.0.0.1";
CString sLog,stemp;
WSADATA wsaData;
WORD sockVersion = MAKEWORD(2,2);
if(WSAStartup(sockVersion,&wsaData) != 0)
{
return ;
}
SOCKET sRaw = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
SetTimeout(sRaw,1000,TRUE);
SOCKADDR_IN dest;
dest.sin_family = AF_INET;
dest.sin_port = htons(0);
dest.sin_addr.S_un.S_addr = inet_addr(szDestIp);
char buff[sizeof(ICMP_HDR)+32];
ICMP_HDR *pIcmp = (ICMP_HDR*)buff;
pIcmp->icmp_type = 8;
pIcmp->icmp_code = 0;
pIcmp->icmp_id = (USHORT)GetCurrentProcessId();
pIcmp->icmp_checksum = 0;
pIcmp->icmp_sequence = 0;
memset(&buff[sizeof(ICMP_HDR)],'E',32);
USHORT nSeq = 0;
char recvBuf[1024];
SOCKADDR_IN from;
int nLen = sizeof(from);
BOOL ret = FALSE;
while(TRUE)
{
static int nCount = 0;
int nRet;
if( nCount++ ==4)
break;
pIcmp->icmp_checksum = 0;
pIcmp->icmp_timestamp = GetTickCount();
pIcmp->icmp_sequence = nSeq;
pIcmp->icmp_checksum = checksum((USHORT*)buff,sizeof(ICMP_HDR)+32);
nRet = sendto(sRaw,buff,sizeof(ICMP_HDR)+32,0,(SOCKADDR*)&dest,sizeof(dest));
if(nRet == SOCKET_ERROR)
{
break;
}
nRet = recvfrom(sRaw,recvBuf,1024,0,(sockaddr*)&from,&nLen);
if(nRet == SOCKET_ERROR)
{
if(WSAGetLastError() == WSAETIMEDOUT)
{
//time out
sLog.Format("Request timed out/n");
GetDlgItemText(IDC_EDIT_TEST,stemp);
SetDlgItemText(IDC_EDIT_TEST,stemp + sLog);
continue;
}
// failed
return ;
}
int nTick = ::GetTickCount();
if(nRet < sizeof(IPHeader)+sizeof(ICMP_HDR))
{
sLog.Format("Too few bytes from %s /n",::inet_ntoa(from.sin_addr));
GetDlgItemText(IDC_EDIT_TEST,stemp);
SetDlgItemText(IDC_EDIT_TEST,stemp + sLog);
}
ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + 20); // (ICMP_HDR*)(recvBuf + sizeof(IPHeader));
if(pRecvIcmp->icmp_type != 0) // 回显
{
sLog.Format("nonecho type %d recvd /n",pRecvIcmp->icmp_type);
GetDlgItemText(IDC_EDIT_TEST,stemp);
SetDlgItemText(IDC_EDIT_TEST,stemp + sLog);
return ;
}
if(pRecvIcmp->icmp_id != ::GetCurrentProcessId())
{
sLog.Format("someone else's packet! /n");
GetDlgItemText(IDC_EDIT_TEST,stemp);
SetDlgItemText(IDC_EDIT_TEST,stemp + sLog);
return ;
}
sLog.Format("%d bytes from %s: /r/n icmp_seq = %d. time: %d ms /r/n",
nRet, inet_ntoa(from.sin_addr), pRecvIcmp->icmp_sequence,
nTick - pRecvIcmp->icmp_timestamp);
GetDlgItemText(IDC_EDIT_TEST,stemp);
SetDlgItemText(IDC_EDIT_TEST,stemp + sLog);
ret |= TRUE;
::Sleep(1000);
}
}
USHORT checksum(USHORT* buff,int size)
{
unsigned long cksum = 0;
while(size>1)
{
cksum += *buff++;
size -= sizeof(USHORT);
}
if(size)
{
cksum += *(UCHAR*)buff;
}
cksum = (cksum>>16)+(cksum & 0xffff);
cksum += (cksum>>16);
return (USHORT)(~cksum);
}
BOOL SetTimeout(SOCKET s,int nTime,BOOL bRecv)
{
int ret = setsockopt(s,SOL_SOCKET,bRecv ? SO_RCVTIMEO : SO_SNDTIMEO,(char*)&nTime,sizeof(nTime));
return ret != SOCKET_ERROR;
}
本文介绍了一个使用C语言实现的自定义Ping程序,该程序详细展示了如何构造和发送ICMP请求包,以及如何解析和处理回应。通过创建原始套接字并设置超时,程序能够向指定的目标IP地址发送ICMP回显请求,并接收回显应答。
1077

被折叠的 条评论
为什么被折叠?



