#include <winsock2.h>
#include <iostream>
#include <windows.h>
using namespace std;
#define DATA_SIZE 32
#define RECV_MAX_SZIE 1024
#pragma comment(lib, "ws2_32.lib")
typedef struct tag_icmphdr //icmp头
{
unsigned char icmp_type;
unsigned char icmp_code;
unsigned short icmp_checksum;
unsigned short icmp_id;
unsigned short icmp_sequence;
unsigned long icmp_timestamp;
} ICMPHDR, *PICMPHDR;
typedef struct tag_iphdr //ip头
{
UCHAR iphVerLen;
UCHAR ipTOS;
USHORT ipLength;
USHORT ipID;
USHORT ipFlags;
UCHAR ipTTL;
UCHAR ipProtacol;
USHORT ipChecksum;
ULONG ipSource;
ULONG ipDestination;
} IPHDR;
USHORT CheckSum(USHORT *buf,int size)
{
USHORT cksum=0;
while(size>1)
{
cksum+=*buf++;
size-=sizeof(USHORT);
}
if(size)
cksum+=*buf++;
cksum=(cksum>>16)+(cksum&0xffff);
cksum+=(cksum>>16);
return (USHORT)(~cksum);
}
void FillIcmp(PICMPHDR p)
{
p->icmp_type = 8;
p->icmp_code = 0;
p->icmp_checksum = 0;
p->icmp_id = (unsigned short)::GetCurrentProcessId();
p->icmp_sequence = 0;
p->icmp_timestamp = 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
WORD version = MAKEWORD(2,2);
WSADATA data;
WSAStartup(version, &data);
if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2)
{
cout << "WSAStartup failed" << endl;
WSACleanup();
return 0;
}
char ip[20];
cout << "ping: ";
cin >> ip;
SOCKADDR_IN addr; //目标主机地址
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = inet_addr(ip);
addr.sin_port = htons(0);
SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); //创建原始套接字
int outTime = 1000;
int rst;
rst = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&outTime, sizeof(int)); //设置发送超时
if (SOCKET_ERROR == rst)
{
cout << "setsockopt erro" << endl;
closesocket(sock);
WSACleanup();
return -1;
}
rst = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&outTime, sizeof(int)); //设置接收超时
if (SOCKET_ERROR == rst)
{
cout << "setsockopt erro" << endl;
closesocket(sock);
WSACleanup();
return -1;
}
char *icmp = (char*)malloc(sizeof(ICMPHDR)+DATA_SIZE); //为icmp包申请内存
memset(icmp, 0, sizeof(ICMPHDR)+DATA_SIZE); //内存空间置零
PICMPHDR picmp = (PICMPHDR)icmp;
FillIcmp(picmp); //填充icmp包
unsigned short sequence = 0; //序列号
int count = 4; //发送请求次数
char recvbuf[RECV_MAX_SZIE]; //接收buf
SOCKADDR_IN addrfrom; //接收地址
int len = sizeof(SOCKADDR); //地址大小
int ipTTL = 0; //TTL
while (count--)
{
picmp->icmp_checksum = 0;
picmp->icmp_timestamp = ::GetTickCount();
picmp->icmp_sequence = sequence++;
picmp->icmp_checksum = CheckSum((USHORT*)icmp, sizeof(ICMPHDR)+DATA_SIZE);
int result;
result = sendto(sock, icmp, sizeof(ICMPHDR)+DATA_SIZE, 0, (SOCKADDR*)&addr, sizeof(SOCKADDR)); //向目标主机发送icmp请求包
if (SOCKET_ERROR == result)
{
if (WSAETIMEDOUT == WSAGetLastError())
{
cout << "time out" << endl;
continue;
}
else
{
cout << "sendto error" << endl;
closesocket(sock);
WSACleanup();
return -1;
}
}
result = recvfrom(sock, recvbuf, RECV_MAX_SZIE, 0, (SOCKADDR*)&addrfrom, &len); //接收目标主机的icmp应答包
if (SOCKET_ERROR == result)
{
if (WSAETIMEDOUT == GetLastError())
{
cout << "time out" << endl;
continue;
}
else
{
cout << "recvform error" << endl;
closesocket(sock);
WSACleanup();
return -1;
}
}
int nTick = ::GetTickCount();
if (result < sizeof(IPHDR) + sizeof(ICMPHDR) + DATA_SIZE)
{
cout << "too few bytes" << endl;
}
IPHDR *pIP = (IPHDR*)recvbuf;
ipTTL = (int)pIP->ipTTL; //获取目标主机TTL
PICMPHDR p = (PICMPHDR)(recvbuf+sizeof(IPHDR));
if (p->icmp_type != 0)
{
cout << "error type " << p->icmp_type << " receved" << endl;
return -1;
}
if (p->icmp_id != (USHORT)::GetCurrentProcessId())
{
cout << "someone else's packet" << endl;
return -1;
}
cout << "reply from: " << inet_ntoa(addrfrom.sin_addr);
cout << " data: " << DATA_SIZE << "bytes ";
cout << " time: " << nTick-p->icmp_timestamp << "ms";
cout << " TTL=" << ipTTL << endl;
}
return 0;
}