//ping.h
#pragma once
#include <winsock2.h>
#pragma comment(lib, "WS2_32")
typedef struct icmp_hdr
{
unsigned char icmp_type; // 消息类型
unsigned char icmp_code; // 代码
unsigned short icmp_checksum; // 校验和
// 下面是回显头
unsigned short icmp_id; // 用来惟一标识此请求的ID号,通常设置为进程ID
unsigned short icmp_sequence; // 序列号
unsigned long icmp_timestamp; // 时间戳
} ICMP_HDR, *PICMP_HDR;
typedef struct _IPHeader // 20字节的IP头
{
UCHAR iphVerLen; // 版本号和头长度(各占4位)
UCHAR ipTOS; // 服务类型
USHORT ipLength; // 封包总长度,即整个IP报的长度
USHORT ipID; // 封包标识,惟一标识发送的每一个数据报
USHORT ipFlags; // 标志
UCHAR ipTTL; // 生存时间,就是TTL
UCHAR ipProtocol; // 协议,可能是TCP、UDP、ICMP等
USHORT ipChecksum; // 校验和
ULONG ipSource; // 源IP地址
ULONG ipDestination; // 目标IP地址
} IPHeader, *PIPHeader;
// 定义TCP标志
#define TCP_FIN 0x01
#define TCP_SYN 0x02
#define TCP_RST 0x04
#define TCP_PSH 0x08
#define TCP_ACK 0x10
#define TCP_URG 0x20
#define TCP_ACE 0x40
#define TCP_CWR 0x80
typedef struct _TCPHeader // 20字节的TCP头
{
USHORT sourcePort; // 16位源端口号
USHORT destinationPort; // 16位目的端口号
ULONG sequenceNumber; // 32位序列号
ULONG acknowledgeNumber; // 32位确认号
UCHAR dataoffset; // 高4位表示数据偏移
UCHAR flags; // 6位标志位
USHORT windows; // 16位窗口大小
USHORT checksum; // 16位校验和
USHORT urgentPointer; // 16位紧急数据偏移量
} TCPHeader, *PTCPHeader;
typedef struct _UDPHeader
{
USHORT sourcePort; // 源端口号
USHORT destinationPort;// 目的端口号
USHORT len; // 封包长度
USHORT checksum; // 校验和
} UDPHeader, *PUDPHeader;
class ping
{
public:
ping(void);
~ping(void);
ICMP_HDR* icmp_head;
SOCKET m_raw;
void init(void);
void start(void);
BOOL setttl(SOCKET s,int ttl);
BOOL settime(SOCKET s,int nTime, BOOL bRecv);
char buff[44];
bool serach(const char* ip);
SOCKADDR_IN dest;
};
//ping.cpp
#include "StdAfx.h"
#include "./ping.h"
#include <winsock2.h>
#include <windows.h>
#include "Ws2tcpip.h"
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);
}
ping::ping(void)
{
this->icmp_head=(ICMP_HDR*)buff;
}
ping::~ping(void)
{
this->icmp_head=NULL;
::closesocket(this->m_raw);
WSACleanup();
}
void ping::init(void)
{
WSADATA data;
if(WSAStartup(MAKEWORD(2,2),&data)!=0)
{
printf("init error");
exit(0);
}
}
void ping::start(void)
{
this->m_raw=::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
this->settime(this->m_raw,300,1);
this->setttl(this->m_raw,2);
icmp_head->icmp_type = 8;
icmp_head->icmp_code = 0;
icmp_head->icmp_id = (USHORT)::GetCurrentProcessId();
icmp_head->icmp_checksum = 0;
icmp_head->icmp_sequence = 0;
memset(&buff[sizeof(ICMP_HDR)], 'E', 32);
dest.sin_family = AF_INET;
dest.sin_port = htons(0);
dest.sin_addr.S_un.S_addr = inet_addr("192.168.0.1");
}
BOOL ping::setttl(SOCKET s,int nValue)
{
int ret = ::setsockopt(s, IPPROTO_IP, IP_TTL, (char*)&nValue, sizeof(nValue));
return ret != SOCKET_ERROR;
}
BOOL ping::settime(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;
}
bool ping::serach(const char* ip)
{
USHORT nSeq = 0;
char recvBuf[1024];
SOCKADDR_IN from;
int nLen = sizeof(from);
dest.sin_addr.S_un.S_addr=::inet_addr(ip);
int nRet;
icmp_head->icmp_checksum = 0;
icmp_head->icmp_timestamp = ::GetTickCount();
icmp_head->icmp_checksum = checksum((USHORT*)buff, sizeof(ICMP_HDR) + 32);
int nTick = ::GetTickCount();
nRet = ::sendto(this->m_raw, buff, sizeof(ICMP_HDR) + 32, 0, (SOCKADDR *)&dest, sizeof(dest));
if(nRet == SOCKET_ERROR)
{
return 0;
}
nRet = ::recvfrom(this->m_raw, recvBuf, 1024, 0, (sockaddr*)&from, &nLen);
int nTick1=::GetTickCount();
if(nRet == SOCKET_ERROR)
{
if(::WSAGetLastError() == WSAETIMEDOUT)
{
return 0;
}
return 0;
}
ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + 20);
if(pRecvIcmp->icmp_type != 0)
{
return 0;
}
if(pRecvIcmp->icmp_id != ::GetCurrentProcessId())
{
return 0;
}
return true;
}