您的位置:首页 > 其它

SOCK_RAW, icmp, ping实现

2016-08-23 09:21 423 查看
// ICMP_study.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include <winsock2.h>  

#include <WS2tcpip.h>  

#include <stdio.h>  

#include <stdlib.h>  

#define ICMP_ECHO 8  

#define ICMP_ECHOREPLY 0  

#define ICMP_MIN 8 //Minimum 8-byte ICMP packet (header)  

#define DEF_PACKET_SIZE 32  

#define MAX_PACKET 1024  

#define MAX_IP_HDR_SIZE 60  

#pragma comment(lib, "ws2_32.lib")

//IP header structure  

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;//Time to live  
unsigned char proto;//Protocol (TCP,UDP,etc.)  
unsigned short checksum;//IP checksum  

unsigned int sourceIP;  
unsigned int destIP;  

} IpHeader;  

//ICMP header structure  

typedef struct _icmphdr  

{  
BYTE i_type;  
BYTE i_code;//Type sub code  
USHORT i_cksum;  
USHORT i_id;  
USHORT i_seq;  

//This is not the standard header, but we reserve space for time  
ULONG timestamp;  

} IcmpHeader;  

//IP option header--use with socket option IP_OPTIONS  

typedef struct _ipoptionhdr  

{  
unsigned char code;//Option type  
unsigned char len;//Length of option hdr  
unsigned char ptr;//Offset into optons  
unsigned long addr[9];//List of IP addrs  

} IpOptionHeader;  

//Helper function to fill in various fields for our ICMP request  

void FillICMPData(char* icmp_data, int datasize)  

{  
//此结构体的填充是根据协议来的
IcmpHeader* icmp_hdr = (IcmpHeader*)icmp_data;  
icmp_hdr->i_type = ICMP_ECHO;//Request an ICMP echo  
icmp_hdr->i_code = 0;  
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();  
icmp_hdr->i_cksum = 0;  
icmp_hdr->i_seq = 0;  

}  

//This function calculates the 16-bit one's complement sum  

//of the supplied buffer (ICMP) header  

USHORT checksum(USHORT* buffer, int size)  

{  
unsigned long cksum = 0;  

while (size > 1)  
{  
cksum += *buffer++;  
size -= sizeof(USHORT);  
}  

if (size)  
{  
cksum += *(UCHAR*)buffer;  
}  

cksum = (cksum>>16) + (cksum & 0xffff);  
cksum += (cksum>>16);  

return (USHORT)(~cksum);  

}  

//If the IP option header is present, find the IP options  

//within the IP header and print the record route option values  

void DecodeIPOptions(char* buf, int bytes)  

{  
IpOptionHeader* ipopt = (IpOptionHeader*)(buf + 20);  

printf("RR:    ");  
for (int i = 0; i < (ipopt->ptr / 4) - 1; i++)  
{  
IN_ADDR inaddr;  
inaddr.S_un.S_addr = ipopt->addr[i];  

if (i != 0)  
{  
printf("        ");  
}  

HOSTENT* host = gethostbyaddr((char*)&inaddr.S_un.S_addr,  
sizeof(inaddr.S_un.S_addr), AF_INET);  
if (host)  
{  
printf("(%-15s) %s\n", inet_ntoa(inaddr), host->h_name);  
}  
else  
{  
printf("(%-15s)\n", inet_ntoa(inaddr));  
}  
}  

return;  

}  

//The response is an IP packet. We must decode the IP header to  

//locate the ICMP data.  

void DecodeICMPHeader(char* buf, int bytes, struct sockaddr_in* from)  

{  
static int icmpcount = 0;  
IpHeader* iphdr = (IpHeader*)buf;  

//Number of 32-bit words * 4 = bytes  
unsigned short iphdrlen = iphdr->h_len * 4;
//这是在分析ip包
DWORD tick = GetTickCount();  

if ((iphdrlen == MAX_IP_HDR_SIZE) && (!icmpcount))  
{  
DecodeIPOptions(buf, bytes);  
}  

if (bytes < iphdrlen + ICMP_MIN)  
{  
printf("Too few bytes from %s\n", inet_ntoa(from->sin_addr));  
}  

IcmpHeader* icmphdr = (IcmpHeader*)(buf + iphdrlen);  
if (icmphdr->i_type != ICMP_ECHOREPLY)  
{  
printf("nonecho type %d recvd\n", icmphdr->i_type);  
return;  
}  

//Make sure this is an ICMP reply to something we sent!  
if (icmphdr->i_id != (USHORT)GetCurrentProcessId())  
{  
printf("someone else's packet!\n");  
return;  
}  

//此处算出来的timestamp,是发送与接收之间的间隔
printf("%d bytes from %s:", bytes, inet_ntoa(from->sin_addr));  
printf("  icmp_seq = %d. ", icmphdr->i_seq);  
printf("  time:%d ms", tick - icmphdr->timestamp);  
printf("\n");  

icmpcount++;  
return;  

}  

BOOL fgInitSocket()

{
WSADATA wsaData;  
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)  
{  
printf("WSAStartup() failed:%d\n", GetLastError());  
return FALSE;  
}  
return TRUE;

}

SOCKET sCreateRawSocket()

{
SOCKET sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED);  
if (sockRaw == INVALID_SOCKET)  
{  
printf("WSASocket() failed:%d\n", WSAGetLastError());  
return INVALID_SOCKET;  
}  

//Set the send/recv timeout values  
int timeout = 1000;  

int bread = setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));  
if (bread == SOCKET_ERROR)  
{  
printf("setsockopt(SO_RCVTIMEO) failed:%d\n", WSAGetLastError());  
return INVALID_SOCKET;  
}  

timeout = 1000;  
bread = setsockopt(sockRaw, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));  
if (bread == SOCKET_ERROR)  
{  
printf("setsockopt(SO_SNDTIMEO) failed:%d\n", WSAGetLastError());  
return INVALID_SOCKET;  

return sockRaw;

}

int _tmain(int argc, _TCHAR* argv[])

{
if (!fgInitSocket())
{
return -1;
}

SOCKET sockRaw = sCreateRawSocket();
if (sockRaw == INVALID_SOCKET)
{
return -1;
}

struct sockaddr_in from;  
int fromlen = sizeof(from);  

struct sockaddr_in dest;  
memset(&dest, 0, sizeof(dest));  
dest.sin_family = AF_INET;  
dest.sin_addr.s_addr = inet_addr("101.226.103.106");  

//Create the ICMP packet  
char icmp_data[MAX_PACKET] = {0};
memset(icmp_data, 0, MAX_PACKET);  
FillICMPData(icmp_data, sizeof(IcmpHeader));  

char recvbuf[MAX_PACKET] = {0};

//Start sending/receiving ICMP packets  
USHORT seq_no = 0;  
while (true)  
{  
static int nCount = 0;  
int bwrote;  

if (nCount++ == 4)  
{  
break;  
}  

((IcmpHeader*)icmp_data)->i_cksum = 0;  
((IcmpHeader*)icmp_data)->timestamp = GetTickCount();  
((IcmpHeader*)icmp_data)->i_seq = seq_no++;  
((IcmpHeader*)icmp_data)->i_cksum =  checksum((USHORT*)icmp_data, sizeof(IcmpHeader));  

bwrote = sendto(sockRaw, icmp_data, sizeof(IcmpHeader), 0, (struct sockaddr*)&dest, sizeof(dest));  
if (bwrote == SOCKET_ERROR)  
{  
if (WSAGetLastError() == WSAETIMEDOUT)  
{  
printf("timed out\n");  
continue;  
}  

printf("sendto() failed:%d\n", WSAGetLastError());  
return -1;  
}  

if (bwrote < sizeof(IcmpHeader))  
{  
printf("Wrote %d bytes\n", bwrote);  
}  

int bread = recvfrom(sockRaw, recvbuf, MAX_PACKET, 0,  (struct sockaddr*)&from, &fromlen);  
if (bread == SOCKET_ERROR)  
{  
int iErr = GetLastError();
if (iErr == WSAETIMEDOUT)  
{  
printf("timed out\n");  
continue;  
}  

printf("revefrom() failed:%d\n", iErr);  
return -1;  
}  

DecodeICMPHeader(recvbuf, bread, &from);  

Sleep(1000);  
}  

//Cleanup  
if (sockRaw != INVALID_SOCKET)  
{  
closesocket(sockRaw);  
}  

WSACleanup(); 
return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: