使用 ICMP 和 RAW Sockets实现 ping 类
2017-12-15 20:47
495 查看
PS: Qt环境,实验可行。
来源:http://blog.csdn.net/frankiewang008/article/details/38010695
[cpp] view
plaincopy
//
// Ping.h
//
#pragma pack(push)
#pragma pack(1)
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <winsock.h>
class CPing
{
#define ICMP_ECHOREPLY 0
#define ICMP_ECHOREQ 8
// IP Header -- RFC 791
typedef struct tagIPHDR
{
u_char VIHL; // Version and IHL
u_char TOS; // Type Of Service
short TotLen; // Total Length
short ID; // Identification
short FlagOff; // Flags and Fragment Offset
u_char TTL; // Time To Live
u_char Protocol; // Protocol
u_short Checksum; // Checksum
struct in_addr iaSrc; // Internet Address - Source
struct in_addr iaDst; // Internet Address - Destination
}IPHDR, *PIPHDR;
// ICMP Header - RFC 792
typedef struct tagICMPHDR
{
u_char Type; // Type
u_char Code; // Code
u_short Checksum; // Checksum
u_short ID; // Identification
u_short Seq; // Sequence
char Data; // Data
}ICMPHDR, *PICMPHDR;
// ICMP Echo Request
#define REQ_DATASIZE 32 // Echo Request Data size
typedef struct tagECHOREQUEST
{
ICMPHDR icmpHdr;
DWORD dwTime;
char cData[REQ_DATASIZE];
}ECHOREQUEST, *PECHOREQUEST;
// ICMP Echo Reply
typedef struct tagECHOREPLY
{
IPHDR ipHdr;
ECHOREQUEST echoRequest;
char cFiller[256];
}ECHOREPLY, *PECHOREPLY;
private:
bool bInitWinSockOK;
u_short in_cksum(u_short *addr, int len);
int SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr);
DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL);
int WaitForEchoReply(SOCKET s);
void Report(LPCTSTR format, ...);
public:
CPing();
virtual ~CPing();
void ping(LPCSTR pstrHost);
};
#pragma pack(pop)
[cpp] view
plaincopy
//
// PING.CPP -- Ping program using ICMP and RAW Sockets
//
#include "ping.h"
#pragma comment(lib, "ws2_32.lib")
CPing::CPing()
{
bInitWinSockOK = false;
// Init WinSock
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(1,1);
if ( WSAStartup(wVersionRequested, &wsaData) )
{
Report("/nError initializing WinSock/n");
}
else if (wsaData.wVersion != wVersionRequested)// Check version
{
Report("/nWinSock version not supported/n");
}
else
{
bInitWinSockOK = true;
}
}
CPing::~CPing()
{
if(bInitWinSockOK)
WSACleanup();// Free WinSock
}
// ping()
// Calls SendEchoRequest() and
// RecvEchoReply() and retport results
void CPing::ping(LPCSTR pstrHost)
{
SOCKET rawSocket;
LPHOSTENT lpHost;
struct sockaddr_in saDest;
struct sockaddr_in saSrc;
DWORD dwTimeSent;
DWORD dwElapsed;
u_char cTTL;
int nLoop;
int nRet;
if(!bInitWinSockOK)
{
Report("/nWinSock must be initializing/n");
return;
}
// Create a Raw socket
rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (rawSocket == SOCKET_ERROR)
{
Report("socket() error: %d/n", WSAGetLastError());
return;
}
// Lookup host
lpHost = gethostbyname(pstrHost);
if (lpHost == NULL)
{
Report("/nHost not found: %s/n", pstrHost);
return;
}
// Setup destination socket address
saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
saDest.sin_family = AF_INET;
saDest.sin_port = 0;
// Tell the user what we're doing
Report("/nPinging %s [%s] with %d bytes of data:/n",
pstrHost,
inet_ntoa(saDest.sin_addr),
REQ_DATASIZE);
// Ping multiple times
for (nLoop = 0; nLoop < 4; nLoop++)
{
// Send ICMP echo request
SendEchoRequest(rawSocket, &saDest);
// Use select() to wait for data to be received
nRet = WaitForEchoReply(rawSocket);
if (nRet == SOCKET_ERROR)
{
Report("select() error: %d/n", WSAGetLastError());
break;
}
if (!nRet)
{
Report("/nTimeOut");
break;
}
// Receive reply
dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL);
// Calculate elapsed time
dwElapsed = GetTickCount() - dwTimeSent;
Report("/nReply from: %s: bytes=%d time=%ldms TTL=%d",
inet_ntoa(saSrc.sin_addr),
REQ_DATASIZE,
dwElapsed,
cTTL);
}
Report("/n");
nRet = closesocket(rawSocket);
if (nRet == SOCKET_ERROR)
Report("closesocket() error: %d/n", WSAGetLastError());
}
void CPing::Report(LPCSTR format, ...)
{
char _Buff[8192];
memset(_Buff, 0, sizeof(_Buff));
va_list arg;
va_start(arg, format);
int charSize = _vsnprintf(_Buff, sizeof(_Buff), format, arg);
va_end(arg);
OutputDebugStringA(_Buff);
}
//
// Checksum routine for Internet Protocol family headers (C Version)
u_short CPing::in_cksum(u_short *addr, int len)
{
register int nleft = len;
register u_short *w = addr;
register u_short answer;
register int sum = 0;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum),
* we add sequential 16 bit words to it, and at the end, fold
* back all the carry bits from the top 16 bits into the lower
* 16 bits.
*/
while( nleft > 1 )
{
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if( nleft == 1 )
{
u_short u = 0;
*(u_char *)(&u) = *(u_char *)w ;
sum += u;
}
/*
* add back carry outs from top 16 bits to low 16 bits
*/
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}
// SendEchoRequest()
// Fill in echo request header
// and send to destination
int CPing::SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr)
{
static ECHOREQUEST echoReq;
static u_short nId = 1;
static u_short nSeq = 1;
int nRet;
// Fill in echo request
echoReq.icmpHdr.Type = ICMP_ECHOREQ;
echoReq.icmpHdr.Code = 0;
echoReq.icmpHdr.Checksum = 0;
echoReq.icmpHdr.ID = nId++;
echoReq.icmpHdr.Seq = nSeq++;
// Fill in some data to send
for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
echoReq.cData[nRet] = ' '+nRet;
// Save tick count when sent
echoReq.dwTime = GetTickCount();
// Put data in packet and compute checksum
echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST));
// Send the echo request
nRet = sendto(s, /* socket */
(LPSTR)&echoReq, /* buffer */
sizeof(ECHOREQUEST),
0, /* flags */
(LPSOCKADDR)lpstToAddr, /* destination */
sizeof(SOCKADDR_IN)); /* address length */
if (nRet == SOCKET_ERROR)
Report("sendto() error: %d/n", WSAGetLastError());
return (nRet);
}
// RecvEchoReply()
// Receive incoming data
// and parse out fields
DWORD CPing::RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL)
{
ECHOREPLY echoReply;
int nRet;
int nAddrLen = sizeof(struct sockaddr_in);
// Receive the echo reply
nRet = recvfrom(s, // socket
(LPSTR)&echoReply, // buffer
sizeof(ECHOREPLY), // size of buffer
0, // flags
(LPSOCKADDR)lpsaFrom, // From address
&nAddrLen); // pointer to address len
// Check return value
if (nRet == SOCKET_ERROR)
Report("recvfrom() error: %d/n", WSAGetLastError());
// return time sent and IP TTL
*pTTL = echoReply.ipHdr.TTL;
return(echoReply.echoRequest.dwTime);
}
// WaitForEchoReply()
// Use select() to determine when
// data is waiting to be read
int CPing::WaitForEchoReply(SOCKET s)
{
struct timeval Timeout;
fd_set readfds;
readfds.fd_count = 1;
readfds.fd_array[0] = s;
Timeout.tv_sec = 5;
Timeout.tv_usec = 0;
return(select(1, &readfds, NULL, NULL, &Timeout));
}
[cpp] view
plaincopy
//test code
CPing ping;
ping.ping( "www.sina.com.cn" );
//output
Pinging www.sina.com.cn [61.172.201.194] with 32 bytes of data:
Reply from: 61.172.201.194: bytes=32 time=15ms TTL=249
Reply from: 61.172.201.194: bytes=32 time=16ms TTL=249
Reply from: 61.172.201.194: bytes=32 time=0ms TTL=249
Reply from: 61.172.201.194: bytes=32 time=15ms TTL=249
使用 ICMP 和 RAW Sockets实现 ping 类
来源:http://blog.csdn.net/frankiewang008/article/details/38010695
[cpp] view
plaincopy
//
// Ping.h
//
#pragma pack(push)
#pragma pack(1)
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <winsock.h>
class CPing
{
#define ICMP_ECHOREPLY 0
#define ICMP_ECHOREQ 8
// IP Header -- RFC 791
typedef struct tagIPHDR
{
u_char VIHL; // Version and IHL
u_char TOS; // Type Of Service
short TotLen; // Total Length
short ID; // Identification
short FlagOff; // Flags and Fragment Offset
u_char TTL; // Time To Live
u_char Protocol; // Protocol
u_short Checksum; // Checksum
struct in_addr iaSrc; // Internet Address - Source
struct in_addr iaDst; // Internet Address - Destination
}IPHDR, *PIPHDR;
// ICMP Header - RFC 792
typedef struct tagICMPHDR
{
u_char Type; // Type
u_char Code; // Code
u_short Checksum; // Checksum
u_short ID; // Identification
u_short Seq; // Sequence
char Data; // Data
}ICMPHDR, *PICMPHDR;
// ICMP Echo Request
#define REQ_DATASIZE 32 // Echo Request Data size
typedef struct tagECHOREQUEST
{
ICMPHDR icmpHdr;
DWORD dwTime;
char cData[REQ_DATASIZE];
}ECHOREQUEST, *PECHOREQUEST;
// ICMP Echo Reply
typedef struct tagECHOREPLY
{
IPHDR ipHdr;
ECHOREQUEST echoRequest;
char cFiller[256];
}ECHOREPLY, *PECHOREPLY;
private:
bool bInitWinSockOK;
u_short in_cksum(u_short *addr, int len);
int SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr);
DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL);
int WaitForEchoReply(SOCKET s);
void Report(LPCTSTR format, ...);
public:
CPing();
virtual ~CPing();
void ping(LPCSTR pstrHost);
};
#pragma pack(pop)
[cpp] view
plaincopy
//
// PING.CPP -- Ping program using ICMP and RAW Sockets
//
#include "ping.h"
#pragma comment(lib, "ws2_32.lib")
CPing::CPing()
{
bInitWinSockOK = false;
// Init WinSock
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(1,1);
if ( WSAStartup(wVersionRequested, &wsaData) )
{
Report("/nError initializing WinSock/n");
}
else if (wsaData.wVersion != wVersionRequested)// Check version
{
Report("/nWinSock version not supported/n");
}
else
{
bInitWinSockOK = true;
}
}
CPing::~CPing()
{
if(bInitWinSockOK)
WSACleanup();// Free WinSock
}
// ping()
// Calls SendEchoRequest() and
// RecvEchoReply() and retport results
void CPing::ping(LPCSTR pstrHost)
{
SOCKET rawSocket;
LPHOSTENT lpHost;
struct sockaddr_in saDest;
struct sockaddr_in saSrc;
DWORD dwTimeSent;
DWORD dwElapsed;
u_char cTTL;
int nLoop;
int nRet;
if(!bInitWinSockOK)
{
Report("/nWinSock must be initializing/n");
return;
}
// Create a Raw socket
rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (rawSocket == SOCKET_ERROR)
{
Report("socket() error: %d/n", WSAGetLastError());
return;
}
// Lookup host
lpHost = gethostbyname(pstrHost);
if (lpHost == NULL)
{
Report("/nHost not found: %s/n", pstrHost);
return;
}
// Setup destination socket address
saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
saDest.sin_family = AF_INET;
saDest.sin_port = 0;
// Tell the user what we're doing
Report("/nPinging %s [%s] with %d bytes of data:/n",
pstrHost,
inet_ntoa(saDest.sin_addr),
REQ_DATASIZE);
// Ping multiple times
for (nLoop = 0; nLoop < 4; nLoop++)
{
// Send ICMP echo request
SendEchoRequest(rawSocket, &saDest);
// Use select() to wait for data to be received
nRet = WaitForEchoReply(rawSocket);
if (nRet == SOCKET_ERROR)
{
Report("select() error: %d/n", WSAGetLastError());
break;
}
if (!nRet)
{
Report("/nTimeOut");
break;
}
// Receive reply
dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL);
// Calculate elapsed time
dwElapsed = GetTickCount() - dwTimeSent;
Report("/nReply from: %s: bytes=%d time=%ldms TTL=%d",
inet_ntoa(saSrc.sin_addr),
REQ_DATASIZE,
dwElapsed,
cTTL);
}
Report("/n");
nRet = closesocket(rawSocket);
if (nRet == SOCKET_ERROR)
Report("closesocket() error: %d/n", WSAGetLastError());
}
void CPing::Report(LPCSTR format, ...)
{
char _Buff[8192];
memset(_Buff, 0, sizeof(_Buff));
va_list arg;
va_start(arg, format);
int charSize = _vsnprintf(_Buff, sizeof(_Buff), format, arg);
va_end(arg);
OutputDebugStringA(_Buff);
}
//
// Checksum routine for Internet Protocol family headers (C Version)
u_short CPing::in_cksum(u_short *addr, int len)
{
register int nleft = len;
register u_short *w = addr;
register u_short answer;
register int sum = 0;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum),
* we add sequential 16 bit words to it, and at the end, fold
* back all the carry bits from the top 16 bits into the lower
* 16 bits.
*/
while( nleft > 1 )
{
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if( nleft == 1 )
{
u_short u = 0;
*(u_char *)(&u) = *(u_char *)w ;
sum += u;
}
/*
* add back carry outs from top 16 bits to low 16 bits
*/
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}
// SendEchoRequest()
// Fill in echo request header
// and send to destination
int CPing::SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr)
{
static ECHOREQUEST echoReq;
static u_short nId = 1;
static u_short nSeq = 1;
int nRet;
// Fill in echo request
echoReq.icmpHdr.Type = ICMP_ECHOREQ;
echoReq.icmpHdr.Code = 0;
echoReq.icmpHdr.Checksum = 0;
echoReq.icmpHdr.ID = nId++;
echoReq.icmpHdr.Seq = nSeq++;
// Fill in some data to send
for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
echoReq.cData[nRet] = ' '+nRet;
// Save tick count when sent
echoReq.dwTime = GetTickCount();
// Put data in packet and compute checksum
echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST));
// Send the echo request
nRet = sendto(s, /* socket */
(LPSTR)&echoReq, /* buffer */
sizeof(ECHOREQUEST),
0, /* flags */
(LPSOCKADDR)lpstToAddr, /* destination */
sizeof(SOCKADDR_IN)); /* address length */
if (nRet == SOCKET_ERROR)
Report("sendto() error: %d/n", WSAGetLastError());
return (nRet);
}
// RecvEchoReply()
// Receive incoming data
// and parse out fields
DWORD CPing::RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL)
{
ECHOREPLY echoReply;
int nRet;
int nAddrLen = sizeof(struct sockaddr_in);
// Receive the echo reply
nRet = recvfrom(s, // socket
(LPSTR)&echoReply, // buffer
sizeof(ECHOREPLY), // size of buffer
0, // flags
(LPSOCKADDR)lpsaFrom, // From address
&nAddrLen); // pointer to address len
// Check return value
if (nRet == SOCKET_ERROR)
Report("recvfrom() error: %d/n", WSAGetLastError());
// return time sent and IP TTL
*pTTL = echoReply.ipHdr.TTL;
return(echoReply.echoRequest.dwTime);
}
// WaitForEchoReply()
// Use select() to determine when
// data is waiting to be read
int CPing::WaitForEchoReply(SOCKET s)
{
struct timeval Timeout;
fd_set readfds;
readfds.fd_count = 1;
readfds.fd_array[0] = s;
Timeout.tv_sec = 5;
Timeout.tv_usec = 0;
return(select(1, &readfds, NULL, NULL, &Timeout));
}
[cpp] view
plaincopy
//test code
CPing ping;
ping.ping( "www.sina.com.cn" );
//output
Pinging www.sina.com.cn [61.172.201.194] with 32 bytes of data:
Reply from: 61.172.201.194: bytes=32 time=15ms TTL=249
Reply from: 61.172.201.194: bytes=32 time=16ms TTL=249
Reply from: 61.172.201.194: bytes=32 time=0ms TTL=249
Reply from: 61.172.201.194: bytes=32 time=15ms TTL=249
使用 ICMP 和 RAW Sockets实现 ping 类
相关文章推荐
- 使用 ICMP 和 RAW Sockets实现 ping 类
- 使用 ICMP 和 RAW Sockets实现 ping 类
- 使用zabbix3.0.4的ICMP Ping模版实现对客户端网络状态的监控
- 使用zabbix3.0.4的ICMP Ping模版实现对客户端网络状态的监控
- 使用zabbix的ICMP Ping模版实现对客户端网络状态的监控
- luyikk 的C# PING 工具 与 传统的不一样的是 他可以修改你的 IP地址实现伪造ICMP数据包 ,当然 XP下无法使用 2003下才可以使用
- 使用zabbix的ICMP Ping模版实现对客户端网络状态的监控
- ICMP协议规范:一种用于网络管理的协议。对照它您可以想一想PING命令实现的机理
- [转]使用java简单模拟ping和telnet的实现
- ICMP协议之ping实现
- Linux下使用原始套接字实现ping 功能
- ping 实现设计---ICMP
- Zabbix中使用ICMP ping来判断主机是否存活的问题
- ICMP协议之ping实现
- 使用iphlpapi动态链接库函数实现ping功能
- icmp的程序(ping的实现)
- C# ping命令的实现方法:Ping类的使用
- ICMP协议之ping实现
- 使用java简单模拟ping和telnet的实现
- 使用java简单模拟ping和telnet的实现