vc++Ping命令模拟进阶----如何嗅探某个IP段_C/C++_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > C/C++ > vc++Ping命令模拟进阶----如何嗅探某个IP段

vc++Ping命令模拟进阶----如何嗅探某个IP段

 2011/9/2 8:03:49  sxjkk  http://sxjkk.iteye.com  我要评论(0)
  • 摘要:上一篇讲了VC++ping命令模拟,那个只是个示例http://sxjkk.iteye.com/admin/blogs/1151740这次我将代码整合后,做一个实战的练习,扫描一个IP段,返回所有活动的IP要完成这个练习,以下有几个步骤,作为程序员的我们就用代码说话首先要做到如何证明一个IP是否在活动,代码如下BOOLIpCheck::IsIPActive(char*addr){//目的IP地址,即要Ping的IP地址char*szDestIp=addr;//127.0.0
  • 标签:VC++ c++ 命令
上一篇讲了VC++ping命令模拟,那个只是个示例http://sxjkk.iteye.com/admin/blogs/1151740
这次我将代码整合后,做一个实战的练习,扫描一个IP段,返回所有活动的IP

要完成这个练习,以下有几个步骤,作为程序员的我们就用代码说话
首先要做到如何证明一个IP是否在活动,代码如下
BOOL IpCheck::IsIPActive(char *addr)
{
	// 目的IP地址,即要Ping的IP地址    
	char *szDestIp = addr;  // 127.0.0.1    

	// 创建原始套节字    
	WSADATA wsaData;  
	WSAStartup(MAKEWORD(2, 2), &wsaData);  
	SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);    

	// 设置接收超时    
	SetTimeout(sRaw, 100, TRUE);    

	// 设置目的地址    
	SOCKADDR_IN dest;    
	dest.sin_family = AF_INET;    
	dest.sin_port = htons(0);    
	dest.sin_addr.S_un.S_addr = inet_addr(szDestIp);    

	// 创建ICMP封包    
	char buff[sizeof(ICMP_HDR) + 32];    
	ICMP_HDR* pIcmp = (ICMP_HDR*)buff;    

	// 填写ICMP封包数据,请求一个ICMP回显    
	pIcmp->icmp_type = 8;        
	pIcmp->icmp_code = 0;    
	pIcmp->icmp_id = (USHORT)GetCurrentProcessId();    
	pIcmp->icmp_checksum = 0;    
	pIcmp->icmp_sequence = 0;    

	// 填充数据部分,可以为任意    
	memset(&buff[sizeof(ICMP_HDR)], 'E', 32);    

	// 开始发送和接收ICMP封包    
	USHORT  nSeq = 0;    
	char recvBuf[1024];    
	SOCKADDR_IN from;    
	int nLen = sizeof(from);    

	static int nCount = 0;    
	int nRet;    

	pIcmp->icmp_checksum = 0;    
	pIcmp->icmp_timestamp = GetTickCount();    
	pIcmp->icmp_sequence = nSeq++;    
	pIcmp->icmp_checksum = checksum((USHORT*)buff, sizeof(ICMP_HDR) + 32);    
	nRet = sendto(sRaw, buff, sizeof(ICMP_HDR) + 32, 0, (SOCKADDR *)&dest, sizeof(dest));    
	if(nRet == SOCKET_ERROR)    
	{    
		printf(" sendto() failed: %d \n", ::WSAGetLastError());    
		return -1;    
	}  
	nRet = recvfrom(sRaw, recvBuf, 1024, 0, (sockaddr*)&from, &nLen);  
	if(nRet == SOCKET_ERROR)  
	{    
		if(WSAGetLastError() == WSAETIMEDOUT)    
		{    
			printf("%s timed out\n", addr);    
			return FALSE;    
		}
		printf("recvfrom() failed: %d\n", WSAGetLastError());    
		return FALSE;
	}    

	// 下面开始解析接收到的ICMP封包    
	int nTick = ::GetTickCount();    
	if(nRet < sizeof(IPHeader) + sizeof(ICMP_HDR))    
	{    
		printf(" Too few bytes from %s \n", inet_ntoa(from.sin_addr));    
	}    

	// 接收到的数据中包含IP头,IP头大小为20个字节,所以加20得到ICMP头    
	// (ICMP_HDR*)(recvBuf + sizeof(IPHeader));    
	ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + 20);     
	if(pRecvIcmp->icmp_type == ICMP_TYPE_REACH_FAIL)    // 回显    
	{    
		printf("%s reach fail, type %d recvd \n", addr, pRecvIcmp->icmp_type);    
		return FALSE;    
	}  

	if(pRecvIcmp->icmp_id != GetCurrentProcessId())    
	{    
		printf(" someone else's packet! \n");    
		return FALSE;    
	}    

	printf("从 %s 返回 %d 字节:", addr,nRet);    
	printf(" 数据包序列号 = %d. \t", pRecvIcmp->icmp_sequence);    
	printf(" 延时大小: %d ms", nTick - pRecvIcmp->icmp_timestamp);    
	printf(" \n");

	s_array->Insert(addr);

	WSACleanup();  
	closesocket(sRaw);

	return TRUE;
}


这个是扫描一个指定的IP地址,但是我们想要扫描多个IP地址的话,必须对IP地址进行转化,转化为整数就可以进行累加操作
unsigned long __fastcall IpCheck::InvertIp(unsigned long NormalIp) 
{ 
	unsigned   char   b1,b2,b3,b4; 

	b1   =   NormalIp   &   0x00FF; 
	b2   =   (NormalIp   >>   8)   &   0x00FF;
	b3   =   (NormalIp   >>   16)   &   0x00FF; 
	b4   =   (NormalIp   >>   24)   &   0x00FF;

	return   (b1   <<24)   |   (b2   <<   16)   |   (b3   <<   8)   |   b4;
} 

//多地址扫描
void IpCheck::MutiScan(char *s_ip, char *e_ip)
{
	in_addr   ia; 
	unsigned   long   FirstIp,SecondIp; 
	int   Delta; 
	char*   Addr; 

	FirstIp = inet_addr(s_ip);       //任意的开始地址 
	SecondIp = inet_addr(e_ip);   //任意的结束地址 

	//转换成能直接递增和递减的地址 
	FirstIp = InvertIp(FirstIp); 
	SecondIp = InvertIp(SecondIp); 

	Delta = SecondIp - FirstIp;
	s_array->InitBuf(Delta + 1);

	for(int i = 0; i <= Delta;i++) 
	{ 
		ia.S_un.S_addr = InvertIp(FirstIp++); 

		Addr = inet_ntoa(ia);
		//扫描 
		IsIPActive(Addr);
	}
}


当我们可以扫描IP后,如何记录和打印所有活动的IP呢?一般人可能都想到用STL,我个人以前用STL有点阴影,所以自己写了一个字符串数组存储数据结构。自己写的心里有数,灵活性高,可以随时写些满足自己需求的代码,我就贴出这个存储类

StringArray.h
#pragma once

//这个是自己写的一个char型指针的字符串存储数据结构,使用的是数组,没有用STL是因为还没习惯使用STL,曾经给我带来阴影
//自己写的灵活性大,方便自己使用

class StringArray
{
public:
	StringArray(void);
	StringArray(int length);
	~StringArray(void);

	void InitBuf(int length);
	int Insert(char *str);
	char *GetString(int index);
	char **WrapBuffer();
	int GetLength();
	void Release();

private:
	char **strbuf;
	int length;
	int count;
};



StringArray.cpp
#include "StdAfx.h"
#include "StringArray.h"

StringArray::StringArray(void)
{
	length = 0;
	strbuf = NULL;
	count = 0;
}

StringArray::StringArray(int length)
{
	this->length = length;
	strbuf = (char **)malloc(sizeof(char *) * length);
	count = 0;
}

StringArray::~StringArray(void)
{
	Release();
}

void StringArray::InitBuf(int length)
{
	this->length = length;
	strbuf = (char **)malloc(sizeof(char *) * length);
	for(int i = 0;i < length;i++)
		strbuf[i] = NULL;
}

int StringArray::Insert(char *str)
{
	if(str == NULL || count == length)
		return DEFAULT_ERROR;

	strbuf[count] = (char *)malloc(sizeof(char) * (strlen(str) + 1));
	if(strbuf[count] == NULL)
		return DEFAULT_ERROR;
	memset(strbuf[count], 0, strlen(str) + 1);
	memcpy(strbuf[count], str, strlen(str));
	strbuf[count][strlen(str)] = '\0';
	count++;
	return DEFAULT_SUCCESS;
}

char *StringArray::GetString(int index)
{
	if(index > length || index < -1)
		return NULL;

	return strbuf[index];
}

int StringArray::GetLength()
{
	return length;
}

char **StringArray::WrapBuffer()
{
	return strbuf;
}

void StringArray::Release()
{
	if(strbuf != NULL)
	{
		for(int i = 0;i < length;i++)
		{
			if(strbuf[i] != NULL)
			{
				free(strbuf[i]);
				strbuf[i] = NULL;
			}
		}
		free(strbuf);
		strbuf = NULL;
	}
}


有了这些我们就可以实现主函数了

int _tmain(int argc, _TCHAR* argv[])
{
	if(argc > 3)
		printf("Error parameter:argc > 3\n");

	char *param1 = NULL;
	char *param2 = NULL;
	IpCheck si;
	if(argv[1] != NULL && argv[2] != NULL)
	{
		param1 = w2c(argv[1]);
		param2 = w2c(argv[2]);
		si.MutiScan(param1, param2);
	}
	else if(argv[1] != NULL)
	{
		param1 = w2c(argv[1]);
		si.MutiScan(param1, param1);
	}
	else
	{
		printf("Error parameter\n");
		return 0;
	}

	char **rs = si.GetIps();
	int count = 0;
	printf("存在的IP为:\n");
	for(int i = 0;i < si.IpCounts();i++)
	{
		if(rs[i] == NULL)
			break;
		printf("%s\t\t", rs[i]);
		if(count == 3)
		{
			count = 0;
			printf("\n");
		}
		count++;
	}
	if(param1 !=NULL)
		free(param1);
	if(param2 !=NULL)
		free(param2);
	//system("pause");
	return 0;
}



过程是扫描指定的IP段,最后显示出所有存在的IP
比如:在CMD下输入SCanIP.exe 10.72.0.0 10.72.0.255
在一段时间内会扫描某个网段
效果如下图





以上就是扫描一个IP段的过程
  • SCanIP.rar (931.5 KB)
  • 下载次数: 0
发表评论
用户名: 匿名