使用 ICMP 和 RAW Sockets实现 ping 类
2010-05-19 22:28
507 查看
// // 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)); }
//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 类
- 使用zabbix3.0.4的ICMP Ping模版实现对客户端网络状态的监控
- 使用zabbix的ICMP Ping模版实现对客户端网络状态的监控
- 使用zabbix3.0.4的ICMP Ping模版实现对客户端网络状态的监控
- 使用zabbix的ICMP Ping模版实现对客户端网络状态的监控
- luyikk 的C# PING 工具 与 传统的不一样的是 他可以修改你的 IP地址实现伪造ICMP数据包 ,当然 XP下无法使用 2003下才可以使用
- ICMP,原始套接字,ping实现
- Visual Basic での ICMP を使用した ping
- C#使用命令行方式实现Ping简单功能 http://www.cnblogs.com/kevinton/archive/2007/06/28/798581.html
- 使用 Ping++ 实现支付功能
- 使用java简单模拟ping和telnet的实现
- 解决:Ubuntu12.04下使用ping命令返回ping:icmp open socket: Operation not permitted的解决
- 使用Wireshark简单分析ICMP报文(ping)
- Zabbix使用ICMP ping监控网络状况
- 使用java简单模拟ping和telnet的实现
- ICMP协议规范:一种用于网络管理的协议。对照它您可以想一想PING命令实现的机理
- 使用java简单模拟ping和telnet的实现
- ICMP协议之ping实现