|
|
#include "network.h"
#include "diagnostics.h"
#include "util.h"
//SOCKET sockRaw = INVALID_SOCKET;
#define DEF_PACKET_SIZE 32
#define MAX_PACKET 1024
#define ICMP_ECHO 8
#define ICMP_ECHOREPLY 0
#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)
// ICMP header
//
typedef struct _ihdr { BYTE i_type; BYTE i_code; // type sub code
USHORT i_cksum; USHORT i_id; USHORT i_seq; ULONG timestamp; // This is not the std header, but we reserve space for time
}IcmpHeader;
// The IP header
//
typedef struct iphdr { unsigned int h_len:4; // length of the header
unsigned int version:4; // Version of IP
unsigned char tos; // Type of service
unsigned short total_len; // total length of the packet
unsigned short ident; // unique identifier
unsigned short frag_and_flags; // flags
unsigned char ttl; unsigned char proto; // protocol (TCP, UDP etc)
unsigned short checksum; // IP checksum
unsigned int sourceIP; unsigned int destIP;
}IpHeader;
void CDiagnostics::FillIcmpData( IN OUT CHAR *pIcmp, IN DWORD dwDataSize ) /*++
Routine Description Creates a ICMP packet by filling in the fields of a passed in structure
Arguments pIcmp Pointer to an ICMP buffer dwDataSize Size of the buffer
Return Value none
--*/ { IcmpHeader *pIcmpHdr; PCHAR pIcmpData;
pIcmpHdr = (IcmpHeader*)pIcmp;
// Fill in the IMCP buffer
//
pIcmpHdr->i_type = ICMP_ECHO; pIcmpHdr->i_code = 0; pIcmpHdr->i_id = (USHORT)GetCurrentProcessId(); pIcmpHdr->i_cksum = 0; pIcmpHdr->i_seq = 0;
// Append the size of the ICMP packet
//
pIcmpData = pIcmp + sizeof(IcmpHeader);
// Place some junk in the buffer.
//
memset(pIcmpData,'E', dwDataSize - sizeof(IcmpHeader)); }
DWORD CDiagnostics::DecodeResponse( IN PCHAR pBuf, IN int nBytes, IN struct sockaddr_in *pFrom, IN int nIndent ) /*++
Routine Description The response is an IP packet. We must decode the IP header to locate the ICMP data
Arguments pBuf Pointer to the recived IP packet nBytes Size of the recived buffer pFrom Information about who the packet is from nIndent How much to indent the text by
Return Value none
--*/ { IpHeader *pIphdr; IcmpHeader *pIcmphdr; USHORT uIphdrLength;
pIphdr = (IpHeader *)pBuf;
// number of 32-bit words *4 = bytes
//
uIphdrLength = pIphdr->h_len * 4 ; if ( nBytes < uIphdrLength + ICMP_MIN) { // Invalid length
//
return ERROR_INVALID_DATA; }
// Extract the ICMP header
//
pIcmphdr = (IcmpHeader*)(pBuf + uIphdrLength);
if (pIcmphdr->i_type != ICMP_ECHOREPLY) { // Invalid type
//
return ERROR_INVALID_DATA; } if (pIcmphdr->i_id != (USHORT)GetCurrentProcessId()) { // Invalid process ID
//
return ERROR_INVALID_DATA; }
WCHAR szw[5000];
wsprintf(szw,ids(IDS_PING_PACKET),nBytes,inet_ntoa(pFrom->sin_addr),pIcmphdr->i_seq,GetTickCount() - pIcmphdr->timestamp); FormatPing(szw);
return S_OK; }
USHORT CDiagnostics::CheckSum( IN USHORT *pBuffer, IN DWORD dwSize ) /*++
Routine Description Computes the checksum for the packet
Arguments pBuffer Buffer containing the packet dwSize Size of the buffer
Return Value Checksum value
--*/ {
DWORD dwCheckSum=0;
while(dwSize >1) { dwCheckSum+=*pBuffer++; dwSize -= sizeof(USHORT); } if( dwSize ) { dwCheckSum += *(UCHAR*)pBuffer; }
dwCheckSum = (dwCheckSum >> 16) + (dwCheckSum & 0xffff); dwCheckSum += (dwCheckSum >>16);
return (USHORT)(~dwCheckSum); }
BOOL CDiagnostics::IsInvalidIPAddress( IN LPCWSTR pszHostName ) { CHAR szIPAddress[MAX_PATH];
if( lstrlen(pszHostName) > 255 ) { return TRUE; } for(INT i=0; pszHostName[i]!=L'\0'; i++) { szIPAddress[i] = pszHostName[i]; } szIPAddress[i] = 0; return IsInvalidIPAddress(szIPAddress); }
BOOL CDiagnostics::IsInvalidIPAddress( IN LPCSTR pszHostName ) /*++
Routine Description Checks to see if an IP Host is a in valid IP address 0.0.0.0 is not valid 255.255.255.255 is not valid "" is not valid
Arguments pszHostName Host Address
Return Value TRUE Is invalid IP address FALSE Valid IP address
--*/ { BYTE bIP[4]; int iRetVal; LONG lAddr;
if( NULL == pszHostName || strcmp(pszHostName,"") == 0 || strcmp(pszHostName,"255.255.255.255") ==0) { // Invalid IP Host
//
return TRUE; }
lAddr = inet_addr(pszHostName);
if( INADDR_NONE != lAddr ) { // Formatted like an IP address X.X.X.X
//
if( lAddr == 0 ) { // Invalid IP address 0.0.0.0
//
return TRUE; } } return FALSE; }
int CDiagnostics::Ping( IN LPCTSTR pszwHostName, IN int nIndent ) /*++
Routine Description Pings a host
Arguments pszwHostName Host to ping nIndent How much to indent when displaying the ping text
Return Value TRUE Successfully pinged FALSE Failed to ping
--*/ { SOCKET sockRaw; DWORD dwTimeout; struct sockaddr_in dest,from; hostent * pHostent; DWORD dwRetVal; int lDataSize, lFromSize = sizeof(from); CHAR bIcmp[MAX_PACKET], bRecvbuf[MAX_PACKET]; CHAR szAscii[MAX_PATH + 1]; BOOL bPinged = TRUE; WCHAR szw[5000];
sockRaw = INVALID_SOCKET;
FormatPing(NULL);
// Convert the wide string into a char string, the winsock functions can not handle wchar stuff
//
if( !wcstombs(szAscii,pszwHostName,MAX_PATH) ) { // Could not convert the string from wide char to char, might be empty, thus invalid IP
//
wsprintf(szw,ids(IDS_INVALID_IP),pszwHostName); FormatPing(szw); return FALSE; }
// Check if the IP address is pingable
//
if( IsInvalidIPAddress(szAscii) ) { // We refuse to waste time on ping the IP address
//
wsprintf(szw,ids(IDS_INVALID_IP),pszwHostName); FormatPing(szw); return FALSE; }
// Create a winsock socket
//
sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED);
if( INVALID_SOCKET == sockRaw ) { // Unable to create socket
//
wsprintf(szw,ids(IDS_SOCKET_CREATE_FAIL)); FormatPing(szw); return FALSE; }
// Set recieve timeout to 1 second
//
dwTimeout = 1000; dwRetVal = setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIMEO, (char*)&dwTimeout, sizeof(dwTimeout));
if( SOCKET_ERROR == dwRetVal ) { // Unable to set socket options
//
wsprintf(szw,ids(IDS_SOCKET_CREATE_FAIL)); FormatPing(szw); closesocket(sockRaw); sockRaw = INVALID_SOCKET; return FALSE; }
// Set send timeout to one second
//
dwTimeout = 1000; dwRetVal = setsockopt(sockRaw, SOL_SOCKET, SO_SNDTIMEO, (char*)&dwTimeout, sizeof(dwTimeout));
if( SOCKET_ERROR == dwRetVal ) { // Unable to set socket options
//
wsprintf(szw,ids(IDS_SOCKET_CREATE_FAIL)); FormatPing(szw); sockRaw = INVALID_SOCKET; closesocket(sockRaw); return FALSE; }
// Set the destination info
//
memset(&dest, 0, sizeof(dest));
dest.sin_family = AF_INET; pHostent = gethostbyname(szAscii); if( !pHostent ) { // Unable to resolve name
//
wsprintf(szw,ids(IDS_RESOLVE_NAME_FAIL)); FormatPing(szw); closesocket(sockRaw); sockRaw = INVALID_SOCKET; return FALSE; }
// Create the ICMP packet
//
ULONG ulAddr;
memcpy(&ulAddr,pHostent->h_addr,pHostent->h_length); dest.sin_addr.s_addr = ulAddr;
lDataSize = DEF_PACKET_SIZE; lDataSize += sizeof(IcmpHeader);
// Fill the ICMP packet
//
FillIcmpData(bIcmp,lDataSize);
int nFailPingCount = 0;
// Send four ICMP packets and wait for a response
//
for(DWORD dwPacketsSent = 0; dwPacketsSent < 4; dwPacketsSent++) { int nWrote, nRead;
if( ShouldTerminate() ) goto end; // Fillin the ICMP header
//
((IcmpHeader*)bIcmp)->i_cksum = 0; ((IcmpHeader*)bIcmp)->timestamp = GetTickCount();
((IcmpHeader*)bIcmp)->i_seq = (USHORT) dwPacketsSent; ((IcmpHeader*)bIcmp)->i_cksum = CheckSum((USHORT*)bIcmp,lDataSize);
// Send the ICMP packet
//
nWrote = sendto(sockRaw, bIcmp, lDataSize, 0, (struct sockaddr*)&dest, sizeof(dest));
if( SOCKET_ERROR == nWrote ) { // Unable to send packet
//
nFailPingCount++; bPinged = FALSE; wsprintf(szw,ids(IDS_SEND_FAIL),dwPacketsSent); FormatPing(szw); continue; }
BOOLEAN bTryAgain = FALSE; do {
bTryAgain = FALSE;
if( ShouldTerminate() ) goto end; // Recive the packet
//
nRead = recvfrom(sockRaw, bRecvbuf, MAX_PACKET, 0, (struct sockaddr*)&from, (int *)&lFromSize);
if( nRead != SOCKET_ERROR && lFromSize!=0 && memcmp(&dest.sin_addr,&from.sin_addr,sizeof(IN_ADDR))!=0 ) { // This is not who we sent the packet to.
// try again.
//
bTryAgain = TRUE; } } while(bTryAgain);
if( ShouldTerminate() ) goto end;
if (nRead == SOCKET_ERROR) { // Did not receive response
//
bPinged = FALSE; nFailPingCount++; wsprintf(szw,ids(IDS_UNREACHABLE)); FormatPing(szw); continue; }
if (S_OK != DecodeResponse(bRecvbuf, nRead, &from,nIndent)) { nFailPingCount++ ; bPinged = FALSE; wsprintf(szw,ids(IDS_UNREACHABLE)); FormatPing(szw); continue; } } end: // Close the socket
//
if( sockRaw != INVALID_SOCKET ) { closesocket(sockRaw); }
return nFailPingCount == 0 ? TRUE:FALSE; }
BOOL CDiagnostics::Connect( IN LPCTSTR pszwHostName, IN DWORD dwPort ) /*++
Routine Description Establish a TCP connect
Arguments pszwHostName Host to ping dwPort Port to connect to
Return Value TRUE Successfully connected FALSE Failed to establish connection
--*/
{ SOCKET s; SOCKADDR_IN sAddr; CHAR szAscii[MAX_PATH + 1]; hostent * pHostent;
// Create the socket
//
s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC); if (INVALID_SOCKET == s) { return FALSE; }
// Bind this socket to the server's socket address
//
memset(&sAddr, 0, sizeof (sAddr)); sAddr.sin_family = AF_INET; sAddr.sin_port = htons((u_short)dwPort); wcstombs(szAscii,(WCHAR *)pszwHostName,MAX_PATH); pHostent = gethostbyname(szAscii); if( !pHostent ) { return FALSE; }
// Set the destination info
//
ULONG ulAddr;
memcpy(&ulAddr,pHostent->h_addr,pHostent->h_length); sAddr.sin_addr.s_addr = ulAddr;
// Attempt to connect
//
if (connect(s, (SOCKADDR*)&sAddr, sizeof(SOCKADDR_IN)) == 0) { // Connection succeded
//
closesocket(s); return TRUE; } else { // Connection failed
//
closesocket(s); return FALSE; } }
|