头文件声明:
class ScanICMP
{
public:
/* @接口 默认构造函数
* @邮箱 575814050@qq.com
* @时间 2018年12月13号
*/
ScanICMP();
/* @接口 默认析构函数
* @邮箱 575814050@qq.com
* @时间 2018年12月13号
*/
~ScanICMP();
/* @接口
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
* @时间 2018年12月19号
*/
virtual void stopICMP();
/* @接口
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
* @时间 2018年12月13号
*/
virtual bool beginICMP(ulong);
/* @接口
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
* @时间 2018年2018月12号
*/
virtual void setTimeout(ulong);
/* @接口
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
* @时间 2018年2018月12号
*/
virtual bool beginICMP(ulong, ulong);
/* @接口
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
* @时间 2018年12月18号
*/
virtual void setSyntonyFunc(const DoxSyntonyParam &);
private:
/* @接口
* @邮箱 575814050@qq.com
* @时间 2018年12月13号
*/
void buildICMP(char *, int);
/* @接口
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
* @时间 2018年10月26号
*/
ulong getTickCountCalibrate();
/* @接口
* @邮箱 575814050@qq.com
* @时间 2018年12月6号
*/
static ulong icmpThread(void *);
/* @接口
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
* @时间 2018年11月30号
*/
ushort calCheckSum(ushort *, int);
/* @接口
* @邮箱 575814050@qq.com
* @时间 2018年12月18号
*/
void buildAddr(ulong, SOCKADDR_IN &);
/* @接口
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
* @时间 2018年12月18号
*/
bool recvAndSendInfo(char *, SOCKADDR_IN &, char *);
/* @接口
* @返回 bool 成功返回值为true,否则返回值为false
* @邮箱 575814050@qq.com
* @时间 2018年12月21号
*/
bool isSameICMPReport(const ICMPHeader *, const ICMPHeader *);
public:
ulong m_sip;
ulong m_eip;
bool m_stop;
ulong m_sRaw;
ulong m_dwTimeout;
DoxSyntonyParam m_send;
};
源代码定义:
ScanICMP::ScanICMP()
, m_stop(false)
, m_dwTimeout(128)
{
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
if(WSAStartup(wVersionRequested, &wsaData))
{
DoxLogger("Winsock Initialization failed");
exit(1);
}
m_sRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED);
int fromlen = sizeof(SOCKADDR_IN); int timeout = m_dwTimeout;
int bread = setsockopt(m_sRaw, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
if(bread == SOCKET_ERROR)
{
DoxLogger("setsockopt(SO_RCVTIMEO) failed;");
exit(1);
}
}
ScanICMP::~ScanICMP()
{
closesocket(m_sRaw);
WSACleanup();
}
void ScanICMP::stopICMP()
{
m_stop = true;
}
bool ScanICMP::beginICMP(ulong ip)
{
static int seq = 0; Object<IDoxPointer> info(NIL);
char pIcmp[sizeof(ICMPHeader) + 32] = { 0 };
SOCKADDR_IN dest; buildAddr(ip, dest); buildICMP(pIcmp, seq++);
int nRet = sendto(m_sRaw, pIcmp, sizeof(ICMPHeader) + 32, 0, (SOCKADDR *)&dest, sizeof(dest));
if(nRet == SOCKET_ERROR)
{
DoxLogger("sendto() failed;"); return false;
}
char recBuf[65536] = { 0 }; int nLen = sizeof(SOCKADDR_IN);
ICMPHeader *srcICMP = (ICMPHeader *)pIcmp;
while(true)
{
if(m_stop) { Sleep(100); break; }
ulong timeStamp = getTickCountCalibrate();
nRet = recvfrom(m_sRaw, recBuf, 65536, 0, (sockaddr *)&dest, &nLen);
if(nRet == SOCKET_ERROR) break;
IPHeader *pIPHeader = (IPHeader*)recBuf;
ushort usIPHeaderLen = (ushort)((pIPHeader->m_byVerHLen & 0x0f) * 4);
ICMPHeader *desICPMP = (ICMPHeader *)(recBuf + usIPHeaderLen);
ulong timeDiff = timeStamp - srcICMP->m_ulTimeStamp;
if(timeDiff > m_dwTimeout) break;
if(!isSameICMPReport(desICPMP, srcICMP)) continue;
// if(desICPMP->m_usID != srcICMP->m_usID) continue;
// if(desICPMP->m_byType != ECHO_REPLY) continue;
// if(desICPMP->m_usSeq != srcICMP->m_usSeq) continue;
in_addr inaddr; inaddr.s_addr = ip;
QString address = QS("%1:Byte = %2 Time = %3ms TTL = %4").arg(inet_ntoa(inaddr)).arg(nRet).arg(timeDiff).arg(pIPHeader->m_byTTL);
info->setString(address); m_send(info); Sleep(5);
return true;
}
return false;
}
ulong ScanICMP::icmpThread(void *param)
{
ScanICMP *pIcmp = (ScanICMP *)param;
for(ulong ip = pIcmp->m_sip; ip < pIcmp->m_eip + 1; ++ip)
pIcmp->beginICMP(htonl(ip));
return 0;
}
ulong ScanICMP::getTickCountCalibrate()
{
static ULONG s_ulFirstCallTick = 0;
static LONGLONG s_ullFirstCallTickMS = 0;
SYSTEMTIME systemtime;
FILETIME filetime;
GetLocalTime(&systemtime);
SystemTimeToFileTime(&systemtime, &filetime);
LARGE_INTEGER liCurrentTime;
liCurrentTime.HighPart = filetime.dwHighDateTime;
liCurrentTime.LowPart = filetime.dwLowDateTime;
LONGLONG llCurrentTimeMS = liCurrentTime.QuadPart / 10000;
if(s_ulFirstCallTick == 0)
s_ulFirstCallTick = GetTickCount();
if(s_ullFirstCallTickMS == 0)
s_ullFirstCallTickMS = llCurrentTimeMS;
return s_ulFirstCallTick + (ULONG)(llCurrentTimeMS - s_ullFirstCallTickMS);
}
void ScanICMP::setTimeout(ulong timeout)
{
m_dwTimeout = timeout;
}
bool ScanICMP::beginICMP(ulong sip, ulong eip)
{
m_sip = sip; m_eip = eip;
HANDLE handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)icmpThread, this, 0, NULL);
if(handle == INVALID_HANDLE_VALUE)
{
DoxLogger("创建线程失败");
return false;
}
CloseHandle(handle);
return true;
}
void ScanICMP::buildICMP(char *buff, int nSeq)
{
//初始化ICMP包
ICMPHeader *pIcmp = (ICMPHeader *)buff;
pIcmp->m_byType = ECHO_REQUEST; pIcmp->m_byCode = 0;
pIcmp->m_usID = (ushort)::GetCurrentProcessId();
pIcmp->m_usChecksum = 0; pIcmp->m_usSeq = 0;
pIcmp->m_ulTimeStamp = getTickCountCalibrate();
pIcmp->m_usSeq = nSeq;
pIcmp->m_usChecksum = calCheckSum((ushort *)buff, sizeof(ICMPHeader) + 32);
}
void ScanICMP::buildAddr(ulong ip, SOCKADDR_IN &dest)
{
dest.sin_family = AF_INET;
dest.sin_port = htons(0);
dest.sin_addr.s_addr = ip;
}
ushort ScanICMP::calCheckSum(ushort *pBuffer, int nSize)
{
unsigned long ulCheckSum = 0;
while(nSize > 1)
{
ulCheckSum += *pBuffer++;
nSize -= sizeof(ushort);
}
if(nSize)
ulCheckSum += *(uchar*)pBuffer;
ulCheckSum = (ulCheckSum >> 16) + (ulCheckSum & 0xffff);
ulCheckSum += (ulCheckSum >> 16);
return (ushort)(~ulCheckSum);
}
void ScanICMP::setSyntonyFunc(const DoxSyntonyParam &recvFunc)
{
m_send = recvFunc;
}
bool ScanICMP::recvAndSendInfo(char *pIcmp, SOCKADDR_IN &dest, char *recBuf)
{
int nRet = sendto(m_sRaw, pIcmp, sizeof(ICMPHeader) + 32, 0, (SOCKADDR *)&dest, sizeof(dest));
if(nRet == SOCKET_ERROR)
{
DoxLogger("sendto() failed;");
return false;
}
int nLen = sizeof(SOCKADDR_IN);
nRet = recvfrom(m_sRaw, recBuf, 65536, 0, (sockaddr *)&dest, &nLen);
return nRet > 0;
}
bool ScanICMP::isSameICMPReport(const ICMPHeader *icmp1, const ICMPHeader *icmp2)
{
if(icmp1->m_usID != icmp2->m_usID) return false;
if(icmp1->m_byType != ECHO_REPLY) return false;
if(icmp1->m_usSeq != icmp2->m_usSeq) return false;
return true;
}
源程序下载地址:https://download.youkuaiyun.com/download/yangfahe1/10909507
示例程序运行方式:https://blog.youkuaiyun.com/yangfahe1/article/details/84028318