网络编译----发现网络中的活动主机

参考:https://blog.csdn.net/skullsky/article/details/52244770

实验目的:
根据协议规定的ICMP数据包的标准格式,编写程序向指定子网中的目的主机(例如从192.168.1.1到192.168.1.10)发送ICMP数据包进行解析,所发现处于活动状态的主机。在本练习中只显示活动主机的IP地址,并采用多线程来提高主机扫描速度。

实验要求:
要求程序为命令行程序。例如可执行文件名为ScanHost.exe,则程序的命令行格式为: ScanHost start_addr end_addr
其中,start_addr为开始搜索的IP地址,end_addr为结束搜索的IP地址。
(2) 要求将计算的子网地址显示在控制台,具体格式为:
开始主机扫描;
活动主机:xx.xx.xx.xx
活动主机:xx.xx.xx.xx

(3) 要求有良好的编程规范与注释。编程所使用的操作系统、语言和编译环境不限,但是在提交的文档中需要加以注明。
(4) 要求撰写说明文档,包括程序的开发思路、工作流程、关键问题、解决思路以及进一步的改进等内容。

实际原理以及其他的代码功能介绍可参考:https://blog.csdn.net/skullsky/article/details/52244770

在这里本人把代码整理了下,外加稍微修改,代码如下:

#include <stdio.h>
#include <winsock.h>
#pragma comment(lib,"Ws2_32.lib")
 
int qq=0;
USHORT checksum(USHORT* buff, int size)
{
	unsigned long cksum = 0;
	while(size>1)
	{
		cksum += *buff++;
		size -= sizeof(USHORT);
	}
	// 是奇数
	if(size)
	{
		cksum += *(UCHAR*)buff;
	}
	// 将32位的chsum高16位和低16位相加,然后取反
	cksum = (cksum >> 16) + (cksum & 0xffff);
	cksum += (cksum >> 16);    // ??? 
	return (USHORT)(~cksum);
}
 
 typedef struct iphdr{                  //IP头
    unsigned int headlen:4;            //IP头长度
    unsigned int version:4;            //IP版本号
    unsigned char tos;                 //服务类型
    unsigned short id;                 //ID号
    unsigned short flag;               //标记
    unsigned char ttl;                 //生存时间
    unsigned char prot;                //协议
    unsigned short checksum;           //效验和
    unsigned int sourceIP;             //源IP
    unsigned int destIP;               //目的IP
}IpHeader;
 
typedef struct icmp_hdr
{
    unsigned char   icmp_type;   // 消息类型
    unsigned char   icmp_code;   // 代码
    unsigned short icmp_checksum; // 校验和
// 下面是回显头
    unsigned short icmp_id;   // 用来惟一标识此请求的ID号,通常设置为进程ID
    unsigned short icmp_sequence; // 序列号
    unsigned long   icmp_timestamp; // 时间戳
} ICMP_HDR, *PICMP_HDR;
 
 
 //SOCKET sRaw=::socket(AF_INET,SOCKET_RAW,TPPROTO_ICMP);
 //SetTimeout(sRaw,1000,TRUE);
  
int SetTimeout(SOCKET s, int nTime, BOOL bRecv)
{
int ret = ::setsockopt(s, SOL_SOCKET, bRecv ? SO_RCVTIMEO : SO_SNDTIMEO, (char*)&nTime, sizeof(nTime));
return ret != SOCKET_ERROR;
}
 
int Computer(char szDestIP[30])                   //扫描主机是否存活
{
	WSADATA wsaData;
	WORD wVersionRequested=MAKEWORD(1,1);
	if (WSAStartup(wVersionRequested , &wsaData))
	{
		printf("Winsock Initialization failed.\n");
		exit(1);
	}
	SOCKET sRaw=::socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
	SetTimeout(sRaw,1000,TRUE);
	SOCKADDR_IN dest;
	dest.sin_family=AF_INET;
	dest.sin_port=htons(0);
	dest.sin_addr.S_un.S_addr=inet_addr(szDestIP);
 
	char buff[sizeof(ICMP_HDR)+32];
	ICMP_HDR * pIcmp=(ICMP_HDR *)buff;
 
	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);
 
	USHORT nSeq=0;
	char revBuf[1024];
	SOCKADDR_IN from;
	int nLen=sizeof(from);
		static int nCount=0;
		int nRet;
/*		if (nCount++==4)
		{
			break;
		}*/
		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,revBuf,1024,0,(sockaddr *)&from,&nLen);
		if (nRet==SOCKET_ERROR)
		{
			//printf("%s 主机没有存活!\n",szDestIP);
			return -1;
		}
		printf("活动主机:%s \n",szDestIP);
		closesocket(nRet);
	WSACleanup();
	return 0;
}
 
void Port(char adr[20])               //扫描存活主机端口
{
	int mysocket,m=0;//这里扫描的
	int pcount = 0; 
	struct sockaddr_in my_addr;
	WSADATA wsaData;
	WORD wVersionRequested=MAKEWORD(1,1);
	//printf("请输入要扫描的端口范围(例如1-1024):");
	//scanf("%d-%d",&m,&n);
	if (WSAStartup(wVersionRequested , &wsaData))
	{
		printf("Winsock Initialization failed.\n");
		exit(1);
	}
	for(int i=m; i<qq; i++)
	{
		if((mysocket = socket(AF_INET, SOCK_STREAM,0)) == INVALID_SOCKET)
			exit(1);
		my_addr.sin_family = AF_INET;
		my_addr.sin_port = htons(i);
		my_addr.sin_addr.s_addr = inet_addr(adr);
		if(connect(mysocket, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == SOCKET_ERROR)
		{
			printf("Port %d - 关闭\n", i);
			closesocket(mysocket);
		}
		else
		{
			pcount++;
			printf("Port %d - 打开\n", i);
		}
	}
	//不知道啥,注释掉~ printf("%d ports open on host - %s\n", pcount, adr);
	closesocket(mysocket);
	WSACleanup();
}
 
 
void change(int a,int b,int c,int d,char IP[20])          //IP转换
{
	char IPPort[4][4]={'\0'};
	char temp[2]={'.','\0'};
	itoa(a,IPPort[0],10); 
	itoa(b,IPPort[1],10); 
	itoa(c,IPPort[2],10); 
	itoa(d,IPPort[3],10); 
	strcat(IP,IPPort[0]);
	strcat(IP,temp);
	strcat(IP,IPPort[1]);
	strcat(IP,temp);
	strcat(IP,IPPort[2]);
	strcat(IP,temp);
	strcat(IP,IPPort[3]);

}


int main()
{
	int a[4],b[4];
loop1:
	printf("ScanHost start_addr end_addr:");
	scanf("%d.%d.%d.%d %d.%d.%d.%d",&a[0],&a[1],&a[2],&a[3],&b[0],&b[1],&b[2],&b[3]);
	if (a[0]>255||a[1]>255||a[2]>255||a[3]>255||b[0]>255||b[1]>255||b[2]>255||b[3]>255)
	{
		printf("输入的起始地址有误!请重新输入!\n");
		goto loop1;
	}
	//ip地址的计数次数,只能计算最后一小数点位,当然想更完美的可以修改下代码
	qq=b[0]-a[0];
	while(!(a[0]==b[0]&&a[1]==b[1]&&a[2]==b[2]&&a[3]==(b[3]+1)))
	{
		char IP[20]={'\0'};
		change(a[0],a[1],a[2],a[3],IP);
		if((Computer(IP))==0)
		{
			Port(IP);
		}
		a[3]++;
		if (a[3]>=255)
		{
			a[3]=0;
			a[2]++;
		}
		if (a[2]>=255)
		{
			a[2]=0;
			a[1]++;
		}
		if (a[1]>=255)
		{
			a[1]=0;
			a[0]++;
		}
		if (a[0]>=255)
		{
			printf("地址溢出!\n");
		    break;
		}
	}
}

运行结果截图:
在这里插入图片描述
这个代码只能计算出最后一小数点的数,如果是程序更加完美可以在“qq”出修改~

编译环境:VC 6.0 尝试了DEV C++发现出错,哎。。。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值