18,356
社区成员
发帖
与我相关
我的任务
分享
//IP报文首部结构
typedef struct _tagIPHeader
{
u_char ip_ihl:4; // 首部长度 (4 bits)
u_char ip_ver:4; // 版本 (4 bits)
u_char ip_tos; // 服务类型(Type of service)
u_short ip_tlen; // 总长(Total length)
u_short ip_id; // 标识(Identification)
u_short ip_flags_fo; // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits)
u_char ip_ttl; // 存活时间(Time to live)
u_char ip_proto; // 协议(Protocol)
u_short ip_crc; // 首部校验和(Header checksum)
u_int ip_saddr; // 源地址(Source address)
u_int ip_daddr; // 目的地址(Destination address)
//u_int ip_opandpad; // 选项与填充(Option + Padding)
}IP_HEADER, *PIP_HEADER;
//ICMP报文首部结构(ICMP请求和应答报文)
typedef struct _tagICMPHeader
{
u_char icmp_type; //类型
u_char icmp_code; //代码
u_short icmp_chksum; //校验和
u_short icmp_id; //标识符
u_short icmp_seq; //序列号
u_long icmp_timestamp; //时间戳
}ICMP_HEADER, *PICMP_HEADER;
void Fill_ICMPHeader(char *pBuffer, int nSize, u_short SeqNo)
{
PICMP_HEADER pICMPHeader = (PICMP_HEADER)pBuffer;
pICMPHeader->icmp_type = ICMP_TYPE_ECHO;
pICMPHeader->icmp_code = 0;
pICMPHeader->icmp_chksum = 0;
pICMPHeader->icmp_id = (unsigned short)GetCurrentProcessId();
pICMPHeader->icmp_seq = SeqNo;
pICMPHeader->icmp_timestamp = (unsigned long)::GetTickCount();
pICMPHeader->icmp_chksum = CheckSum((unsigned short*)pICMPHeader, nSize);
}
void Analyze_ICMPPacket(HANDLE hOutputConsole, char *pBuffer, int nSize)
{
DWORD dwTimeStamp = GetTickCount();
PIP_HEADER pIPHeader = (PIP_HEADER)pBuffer;
//计算IP首部长度
u_short nIpHdrSize = pIPHeader->ip_ihl * 4;
if(nSize < nIpHdrSize + 8)
{
//ICMP报文不完整
return;
}
PICMP_HEADER pICMPHeader = (PICMP_HEADER)(pBuffer + nIpHdrSize);
if(ICMP_TYPE_REPLY != pICMPHeader->icmp_type ||
(u_short)GetCurrentProcessId() != pICMPHeader->icmp_id
)
{
//不是ICMP应答报文
return;
}
TCHAR szOutputString[100], szAddrString[16];
QH_AddrToString(AF_INET, (ULONG *)&pIPHeader->ip_saddr, szAddrString);
_stprintf_s(
szOutputString, 100, "来自 %s 的回复:时间=%dms TTL=%d\n",
szAddrString,
dwTimeStamp - pICMPHeader->icmp_timestamp,
pIPHeader->ip_ttl
);
DWORD dwNumOfCharsWritten;
WriteConsole(hOutputConsole, szOutputString, _tcslen(szOutputString), &dwNumOfCharsWritten, NULL);
}
void QH_Ping(DWORD dwAddress, DWORD dwMillsecons)
{
AllocConsole();
DeleteMenu(GetSystemMenu(GetConsoleWindow(), FALSE), SC_CLOSE, MF_BYCOMMAND);
DrawMenuBar(GetConsoleWindow());
sockaddr_in ToAddr = {0}, FromAddr = {0};
DWORD dwNumOfCharsWritten;
HANDLE hOutputConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if(INVALID_HANDLE_VALUE == hOutputConsole)
{
goto _exitprogress;
}
TCHAR szTitleString[100], szAddrString[20];
if(QH_AddrToString(AF_INET, &dwAddress, szAddrString))
{
WriteConsole(hOutputConsole, TRANS_STR, _tcslen(TRANS_STR), &dwNumOfCharsWritten, NULL);
goto _exitprogress;
}
_stprintf_s(szTitleString, 100, PING_STR, szAddrString);
SetConsoleTitle(szTitleString);
//为了设置发送/接收超时,创建的套接字必须使用WSA_FLAG_OVERLAPPED标志
SOCKET hRawSocket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED);
if(INVALID_SOCKET == hRawSocket)
{
goto _exitprogress;
}
setsockopt(hRawSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&dwMillsecons, sizeof(DWORD));
setsockopt(hRawSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&dwMillsecons, sizeof(DWORD));
DWORD dwAlloc = sizeof(ICMP_HEADER) + 5;
char* pAlloc = new char[dwAlloc];
ToAddr.sin_addr.S_un.S_addr = dwAddress;
ToAddr.sin_family = AF_INET;
ToAddr.sin_port = htons(0);
int i = 0, nSize, nFromLen;
char szRcvBuff[1024];
char szData[] = {
0x41, 0x42, 0x43, 0x44, 0x45
};
while(i < 4)
{
Fill_ICMPHeader(pAlloc, dwAlloc, i);
memcpy(pAlloc + sizeof(ICMP_HEADER), szData, 5);
nSize = sendto(hRawSocket, pAlloc, dwAlloc, 0, (struct sockaddr *)&ToAddr, sizeof(ToAddr));
if(SOCKET_ERROR == nSize)
{
WriteConsole(hOutputConsole, SEND_STR, _tcslen(SEND_STR), &dwNumOfCharsWritten, NULL);
break;
}
nFromLen = sizeof(FromAddr);
nSize = recvfrom(hRawSocket, szRcvBuff, 1024, 0, (struct sockaddr *)&FromAddr, &nFromLen);
if(SOCKET_ERROR == nSize)
{
TCHAR *pErrorStr = RECV_STR;
if(WSAETIMEDOUT == WSAGetLastError())
{
pErrorStr = TMOUT_STR;
}
WriteConsole(hOutputConsole, pErrorStr, _tcslen(pErrorStr), &dwNumOfCharsWritten, NULL);
}
else
{
Analyze_ICMPPacket(hOutputConsole, szRcvBuff, nSize);
}
i++;
}
closesocket(hRawSocket);
delete []pAlloc;
_exitprogress:
system("pause");
FreeConsole();
}
//数据部分应先于计算校验和填充即可
memcpy(pAlloc + sizeof(ICMP_HEADER), szData, 5);
Fill_ICMPHeader(pAlloc, dwAlloc, i);