The first 12 learning network security - to optimize port scanning tool (to achieve: the domain name into an IP address, host survival test and delayed scan function) + multithreading

Please combine the contents of the document, prepared by the use of a multithreaded port scanning tool technology. (Based on previous blog network security 12)

Experimental .rar file and reference documentation


related information:

Port scanning the background and significance

 

Network, each computer is like a castle, the castle, some of which are outside completely open, some are closed doors. How to find the intruder who is, and open their gates it? Where these gates leading to what? In the network, these castle "gates" of a computer called "port." Port scanning is one of several common methods intruders searching for information, it is also a way most likely to expose the intruder's identity and intentions. In general, scanning port has the following objectives: to determine open on the target host operating system to determine what services, if the target host intruder mastered the target host open what services, what operating system is running, they will be able to use the appropriate means to achieve invasion. If the administrator first mastered the security vulnerabilities of these ports and services, we will be able to take effective security measures to prevent the corresponding invasion.

 

Status port scan

Development of computer information network to accelerate the process of the information age, but with the increase in the degree of social networks, reliance on computer networks is also growing, network security issues are also increasingly apparent. Port scanning technology is an important means of detection of safety problems. A port is a potential communication channel is a channel invasion. Port scan on the target computer, get a lot of useful information. Scanner optional remote TCP / IP services to different ports, and record the answers given target, this way, you can collect a lot of variety of useful information about the target host, which found some inherent weaknesses of the target machine . 

 

 

Port scanning tool (Port Scanner) refers to the detection server or host open port tool case. Often computer administrator to confirm the security policy, and can be used by an attacker on the operation of identifying the target host network services.

 

Port scanning is defined asthe clientsends a range request to a corresponding server port, the port may be used to confirm this. Although not in itself malicious network activity, but also to detect network attacks target host services to take advantage of an important means of known vulnerabilities of the service. The main purpose of port scans to confirm the availability of the remote machine is still just a service.

Scanning multiple hosts for a specific port is called a port cleaning (Portsweep), in order to obtain a specific service. For example, based on SQL services computer worm will sweep the same port to establish a large number of hosts on port 1433 TCP connection. [1] 

 

TCP scan

The most simple port scanning tools to use operating system native networking capabilities, and is often used as SYN alternative to scan. Nmap Such a scanning mode is referred to connection, since similar the Unix Connect System () command. If the port is open, the operating system will be able to complete the TCP three-way handshake, then port scanning tool will immediately close the connection you just created to prevent denial of service attacks . The advantage of this scan mode is user without special privileges. But using the native operating system underlying network control function can not be achieved, so that scanning is not popular. And TCP scans can easily be found, especially as a means of cleaning ports: These services will record the sender's IP address, intrusion detection system may trigger an alarm. [1] 

SYN scan

TCP SYN scanning is another scan. Port scanning tool does not use the native operating system functions of the network, but rather self-generating, transmitting IP packets , and monitor its response. This pattern is called "semi-open scanning", because it never establish a complete TCP connection. Port scanning tool to generate a SYN packet, if the destination port is open, it will return SYN-ACK packet. End of a scan response RST packet, then close the connection before the handshake is complete. If the port is closed but did not use a filter, destination port should be sustainable return RST packets.

Use of this coarse network has several advantages: control packets transmitted and response wait long full power to the scan tool, allowing a more detailed analysis of responses. Which scan mode on the target host does not have the more invasive presence of some controversy, but the advantage is that SYN scan does not establish a complete connection from. However, the RST packets may cause network congestion, especially simple network device such as a printer. [1] 

UDP scanning

UDP scanning is also possible, although there are some technical challenges. UDP is a connectionless protocol, so there is no equivalent to the TCP SYN packet. However, if the UDP packet to the transmission port is not open, the target will respond to ICMP port unreachable message. Most UDP port scanners use this scanning method, and use the lack of response to infer the port is open. However, if the port is blocked by a firewall, this method incorrectly reports that the port is open. If the port unreachable message is blocked, then all ports will be displayed as open. This method is also affected by ICMP rate limiting.

Another method is to send an application-specific UDP packets, it is desirable to generate an application layer response. For example, if the DNS server is present, the port 53 is transmitted DNS query result in response. This method is more reliable in terms of identifying open ports. However, it is limited to a port scan application specific probes available. Some tools (for example, NMAP) usually have fewer than 20 UDP services of the probe, and a number of commercial tools (for example, NESUS) there are as many as 70. In some cases, the service can be listened in on the port, but is configured not to respond to specific probes.

 

-----------------------------------------------------------------------------

By the last test procedures can be found mainly in the last three shortcomings :

① does not support scanning directly enter the domain name: IP addresses are not particularly good memory, we usually remember are the domain of this URL, or by querying the need to obtain an IP address by a ping cmd in order, which is very inconvenient.

②connect () function is blocked by default, port scanning will take some time, especially not open ports, not online for a host of such scanning becomes meaningless, and it also takes a lot of time, so before scanning to determine the host is online program to do some useful work can be avoided.

③ take advantage of a connect port scan, when connected to an open port required time is about 0.05s, and not open ports on the big appointments consume 21s, almost stuck when a scan that is not open port 21 seconds . To connect () function to set a default timeout to avoid multiple retransmissions to save time, improve the scanning speed

For optimizing the port scanning tool you can know the following:

Point 1: domain name into an IP address function

Point 2: The host survival test

Host survival test that is to determine whether the host is online, that is, whether the test can ping.

Point 3: the delay scan nonblocking

The experiment can be found here relates to a structure of two functions:

FD_SET

This is an array macro definition, in fact, is a long-type array , each array element can be opened with a file handle (socket, file, pipe, equipment, etc.) to establish contacts , to establish working contacts done by the programmer when calling select (), modify the contents of IO fd_set according to the state by the kernel, thus to inform the implementation of select () process which handles readable.

Mainly its operating system provides a function of:

int ioctlsocket( int s, long cmd, u_long * argp);

s: identifying a set of interface descriptor.

cmd: Operation command socket of s.

argp: pointer pointing brought cmd command parameters.

int select( int nfds, fd_set FAR* readfds,fd_set * writefds, fd_set * exceptfds,const struct timeval * timeout);

nfds: is an integer value in the range is the set of all file descriptors, i.e., the maximum value of all file descriptors plus 1, the value of the parameter does not matter in Windows, you can be set correctly.

readfds :( optional) pointer to a set waiting to check the readability of the socket.

writefds :( optional) pointer to a set of write check waiting sockets.

exceptfds :( optional) pointer to a waiting group of error checking sockets.

timeout: select () to wait for the most time on the blocking operation is NULL.

Note: Use non-blocking connect issues to note are :

Will immediately establish the connection (for example, client and server on the same machine), 1. must deal with this situation is likely to call connect.

2. Posix define two related and select non-blocking connect provisions :

A. When the connection is successfully established, socket descriptor becomes writable . (When the connection is established, the write buffer is free, it is possible to write)

B. When the connection fails, socket descriptor is both readable and writeable . (Since the error is pending, so readable and writeable)

 

Multithreading

 

·   Conditions: open 2000 threads, around the turn of the host port scanning, scan time of 40 seconds.

·   Bottleneck: Whether to open 5000 or more, can not significantly speed up the scanning time.

·   Bottleneck Solution: You can use most often open 1000 ports scanned the list, there should be online, sociology + programming.

*   Note: socket is precious system resources, do not have to be shut down; multi-threaded resource in the critical area to be locked.

Reference: https://www.cnblogs.com/woniu-felix/p/10826157.html


// PortScanf.cpp : 定义控制台应用程序的入口点。
//
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include <WinSock2.h>
#include <cstdio>
#include <iostream>
#include <ws2tcpip.h> 
#include <stdio.h>

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

using namespace std;

//获取超时时间
unsigned long nTimeout;

//#include <winsock2.h>
//#pragma comment(lib, "WS2_32")



//线程个数
#define THREADCOUNT 2000
DWORD WINAPI ThreadProc(LPVOID lpParameter);

char IP[32] = "";

//端口号
int PortNum = 0;
//临界区变量
CRITICAL_SECTION cs;
//线程函数
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
	//创建套接字
	//SOCKET TryConnect;

	SOCKET s;

	WSADATA wsa;
	//SOCKET s;
	struct sockaddr_in server;

	int CurrPort;    //当前端口
	//int ret;

	WSAStartup(MAKEWORD(2, 2), &wsa);    //使用winsock函数之前,必须用WSAStartup函数来装入并初始化动态连接库

	server.sin_family = AF_INET;    //指定地址格式,在winsock中只能使用AF_INET
	server.sin_addr.s_addr = inet_addr(IP); //指定被扫描的IP地址

	while (1)
	{
		if (PortNum > 65535)
		{
			break;
		}
		//进入临界区
		EnterCriticalSection(&cs);
		int tmpport = PortNum;
		PortNum++;
		//DWORD threadID=GetCurrentThreadId();
		//printf("线程%d正在检测端口%d\n",threadID,PortNum);//所有使用临界区资源的代码都要加锁
		//离开临界区
		LeaveCriticalSection(&cs);

		WSADATA wsa;
		//SOCKET s;
		struct sockaddr_in server;

		//int CurrPort;    //当前端口
		//int ret;

		WSAStartup(MAKEWORD(2, 2), &wsa);    //使用winsock函数之前,必须用WSAStartup函数来装入并初始化动态连接库

		server.sin_family = AF_INET;    //指定地址格式,在winsock中只能使用AF_INET
		server.sin_addr.s_addr = inet_addr(IP); //指定被扫描的IP地址

		SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
		server.sin_port = htons(tmpport); //指定被扫描IP地址的端口号

		TIMEVAL TimeOut;
		FD_SET mask;
		unsigned long mode = 1; //ipctlsocket函数的最后一个参数

		//设置超时毫秒数
		TimeOut.tv_sec = 0;
		TimeOut.tv_usec = nTimeout;
		FD_ZERO(&mask);
		FD_SET(s, &mask);

		//设置为非阻塞模式
		ioctlsocket(s, FIONBIO, &mode);

		connect(s, (struct sockaddr *)&server, sizeof(server)); //连接
		int ret = select(0, NULL, &mask, NULL, &TimeOut);

		if (ret != 0 && ret != -1) //判断连接是否成功
		{
			printf("%s:%d Success O(∩_∩)O~~\n", IP, tmpport);
			closesocket(s);
		}
		else {
			//printf("%s:%d Failed\n", Ip, CurrPort);
		}

		closesocket(s);//防止开启太多socket连接,导致后面socket分配无效
	}
	return 0;
}

typedef struct _IPHeader
{
	unsigned char      iphVerLen;
	unsigned char      ipTOS;
	unsigned short     ipLength;
	unsigned short     ipID;
	unsigned short     ipFlags;
	unsigned char     ipTTL;
	unsigned char     ipProtocol;
	USHORT    ipChecksum;
	ULONG     ipSource;
	ULONG     ipDestination;
} IPHeader, *PIPHeader;
typedef struct icmp_hdr
{
	unsigned char   icmp_type;
	unsigned char   icmp_code;
	unsigned short  icmp_checksum;
	unsigned short  icmp_id;
	unsigned short  icmp_sequence;
	unsigned long   icmp_timestamp;
} ICMP_HDR, *PICMP_HDR;

typedef struct _EchoRequest {
	ICMP_HDR icmphdr;
	char cData[32];
}ECHOREQUEST, *PECHOREQUEST;

#define REQ_DATASIZE 32
typedef struct _EchoReply {
	IPHeader iphdr;
	ECHOREQUEST echoRequest;
}ECHOREPLAY, *PECHOREPLAY;

USHORT checksum(USHORT* buff, int size)
{
	u_long cksum = 0;
	while (size > 1)
	{
		cksum = cksum + *buff;
		buff = buff + 1;
		size = size - sizeof(USHORT);
	}
	if (size == 1)
	{
		USHORT u = 0;
		u = (USHORT)(*(UCHAR*)buff);
		cksum = cksum + u;
	}

	cksum = (cksum >> 16) + (cksum & 0x0000ffff);
	cksum = cksum + (cksum >> 16);
	u_short  answer = (u_short)(~cksum);
	return (answer);
}

//我的ping程序
BOOL MyPing(char *szDestIp) 
{
	WSADATA wsaData;
	WORD version = MAKEWORD(2, 2);
	int ret = WSAStartup(version, &wsaData);
	if (ret != 0) {
		printf(" 加载Winsock库错误! \n");
		return 0;
	}
	/*char szDestIp[100];
	printf("输入所要连接的外网地址:\n");
	scanf("%s", szDestIp);*/


	SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

	int nTimeOut = 1000;

	// 设置接收超时
	setsockopt(sRaw, SOL_SOCKET, SO_RCVTIMEO, (char const*)&nTimeOut, sizeof(nTimeOut));

	SOCKADDR_IN dest;
	dest.sin_family = AF_INET;
	dest.sin_port = htons(0);
	dest.sin_addr.S_un.S_addr = inet_addr(szDestIp);
	ECHOREQUEST echoReq;

	echoReq.icmphdr.icmp_type = 8;
	echoReq.icmphdr.icmp_code = 0;
	echoReq.icmphdr.icmp_id = (USHORT)GetCurrentProcessId();
	echoReq.icmphdr.icmp_checksum = 0;
	echoReq.icmphdr.icmp_sequence = 0;
	memset(&echoReq.cData, 'E', 32);
	USHORT   nSeq = 0;     SOCKADDR_IN from;
	int nLen = sizeof(from);


	int fail = 0;
	int success = 0;

	int i = 0;
	int a[4];

	int isFail = 0;

	int timeQ;
	while (TRUE) {
		printf("正在循环\n");
		static int nCount = 0;   int nRet;
		if (nCount++ == 4)   break;
		echoReq.icmphdr.icmp_checksum = 0;
		echoReq.icmphdr.icmp_timestamp = GetTickCount();
		echoReq.icmphdr.icmp_sequence = nSeq++;
		echoReq.icmphdr.icmp_checksum = checksum((USHORT*)&echoReq, sizeof(echoReq));
		nRet = sendto(sRaw, (char*)&echoReq, sizeof(echoReq), 0, (SOCKADDR *)&dest, sizeof(dest));
		if (nRet == SOCKET_ERROR) {

			printf(" sendto() failed: %d \n", WSAGetLastError());
			//system("pause");
			return false;

		}

		ECHOREPLAY echoReply;
		nRet = recvfrom(sRaw, (char*)&echoReply, sizeof(ECHOREPLAY), 0, (sockaddr*)&from, &nLen);
		if (nRet == SOCKET_ERROR) {
			if (WSAGetLastError() == WSAETIMEDOUT) {
				printf(" timed out\n");
				printf("时间超时\n");
				fail++;
				continue;
			}
			printf(" recvfrom() failed: %d\n", WSAGetLastError());

			isFail = 1;

			printf("来自172.16.4.42的回复:无法访问目标主机\n");


			success++;
			continue;
		}
		if (nRet < sizeof(ECHOREPLAY)) {
			printf(" Too few bytes from %s \n", inet_ntoa(from.sin_addr));
			return false;
		}

		if (echoReply.echoRequest.icmphdr.icmp_type != 0) {
			printf(" nonecho type %d recvd \n", echoReply.echoRequest.icmphdr.icmp_type);
			//system("pause");
			return false;
		}

		if (echoReply.echoRequest.icmphdr.icmp_id != GetCurrentProcessId()) {
			printf(" someone else's packet! \n");
			//system("pause");
			return false;
		}
		printf(" %d bytes Reply from %s: \n", nRet, inet_ntoa(from.sin_addr));


		printf(" icmp_seq = %d. ", echoReply.echoRequest.icmphdr.icmp_sequence);
		int nTick = GetTickCount();
		success++;
		printf(" time: %d ms", nTick - echoReply.echoRequest.icmphdr.icmp_timestamp);

		a[i] = nTick - echoReply.echoRequest.icmphdr.icmp_timestamp;
		i++;

		printf(" TTL= %d ", echoReply.iphdr.ipTTL);
		//printf(echoReply.echoRequest.cData);
		printf(" \n");
		Sleep(1000);
	}

	printf("%s 的ping的统计信息:\n", szDestIp);
	printf("数据包:已发送 = %d,已接收 = %d,丢失 = %d\n", success, success, fail);
	if (isFail != 1) {

		printf("往返程的估计时间:(以毫秒记)\n");
		int timeC = a[0];
		int timeD = a[0];
		int timeA = a[0];
		int j;

		for (j = 1; j < 4; j++) {

			if (timeC < a[j]) {

				timeC = a[j];
			}
			if (timeD > a[j]) {

				timeD = a[j];

			}

			timeA = timeA + a[j];

		}
		timeA = timeA / 4;
		printf("最短 = %d 最长 = %d 平均 = %d\n", timeD, timeC, timeA);
	}
	else {

	}
	printf("跳出循环!\n");
	if (fail == 4)
	{
		return false;
	}
	closesocket(sRaw);
	WSACleanup();
	//system("pause");
	return true;
}

//扫描端口
int scant(char *Ip, int StartPort, int EndPort)
{
	

	WSADATA wsa;
	//SOCKET s;
	struct sockaddr_in server;

	int CurrPort;    //当前端口
	//int ret;

	WSAStartup(MAKEWORD(2, 2), &wsa);    //使用winsock函数之前,必须用WSAStartup函数来装入并初始化动态连接库

	server.sin_family = AF_INET;    //指定地址格式,在winsock中只能使用AF_INET
	server.sin_addr.s_addr = inet_addr(Ip); //指定被扫描的IP地址

	cout << "设置超时时间:" << endl;
	cout << ">>";
	//获取超时时间
	unsigned long nTimeout;
	cin >> nTimeout;

	//逐个连接从开始端口到结束端口
	for (CurrPort = StartPort; CurrPort <= EndPort; CurrPort++)
	{
		SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
		server.sin_port = htons(CurrPort); //指定被扫描IP地址的端口号

		TIMEVAL TimeOut;
		FD_SET mask;
		unsigned long mode = 1; //ipctlsocket函数的最后一个参数

		//设置超时毫秒数
		TimeOut.tv_sec = 0;
		TimeOut.tv_usec = nTimeout;
		FD_ZERO(&mask);
		FD_SET(s, &mask);
		
		//设置为非阻塞模式
		ioctlsocket(s, FIONBIO, &mode);

		connect(s, (struct sockaddr *)&server, sizeof(server)); //连接
		int ret = select(0, NULL, &mask, NULL, &TimeOut);

		if (ret != 0 && ret != -1) //判断连接是否成功
		{
			printf("%s:%d Success O(∩_∩)O~~\n", Ip, CurrPort);
			closesocket(s);
		}
		else {
			//printf("%s:%d Failed\n", Ip, CurrPort);
		}
	}
	//printf("Cost time:%f second\n", CostTime); //输出扫描过程中耗费的时间
	//closesocket(server);
	WSACleanup();    //释放动态连接库并释放被创建的套接字
	return 1;
}


//扫描端口
int scant2(char *Ip, int StartPort, int EndPort)
{


	WSADATA wsa;
	//SOCKET s;
	struct sockaddr_in server;

	int CurrPort;    //当前端口
	//int ret;

	WSAStartup(MAKEWORD(2, 2), &wsa);    //使用winsock函数之前,必须用WSAStartup函数来装入并初始化动态连接库

	server.sin_family = AF_INET;    //指定地址格式,在winsock中只能使用AF_INET
	server.sin_addr.s_addr = inet_addr(Ip); //指定被扫描的IP地址

	cout << "设置超时时间:" << endl;
	cout << ">>";
	//获取超时时间
	unsigned long nTimeout;
	cin >> nTimeout;

	//逐个连接从开始端口到结束端口
	for (CurrPort = StartPort; CurrPort <= EndPort; CurrPort++)
	{
		SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
		server.sin_port = htons(CurrPort); //指定被扫描IP地址的端口号

		TIMEVAL TimeOut;
		FD_SET mask;
		unsigned long mode = 1; //ipctlsocket函数的最后一个参数

		//设置超时毫秒数
		TimeOut.tv_sec = 0;
		TimeOut.tv_usec = nTimeout;
		FD_ZERO(&mask);
		FD_SET(s, &mask);

		//设置为非阻塞模式
		ioctlsocket(s, FIONBIO, &mode);

		connect(s, (struct sockaddr *)&server, sizeof(server)); //连接
		int ret = select(0, NULL, &mask, NULL, &TimeOut);

		if (ret != 0 && ret != -1) //判断连接是否成功
		{
			printf("%s:%d Success O(∩_∩)O~~\n", Ip, CurrPort);
			closesocket(s);
		}
		else {
			//printf("%s:%d Failed\n", Ip, CurrPort);
		}
	}
	//printf("Cost time:%f second\n", CostTime); //输出扫描过程中耗费的时间
	//closesocket(server);
	WSACleanup();    //释放动态连接库并释放被创建的套接字
	return 1;
}


//发送控制器
void sendController(char ip[])
{
	if (MyPing(ip) == false) //ping失败
	{
		cout << "ping失败!" << endl;
		return;
	}
	else
	{
		cout << "ping成功!" << endl;
	}

	cout << "选择:(1.单线程扫描指定端口范围   2.多线程扫描全部端口)" << endl;
	cout << ">>";
	int option;
	cin >> option;

	if (option == 1)
	{
		cout << "输入你要查询的起始端口:" << endl;
		cout << ">>";
		int startPort;
		cin >> startPort;

		cout << "输入你要查询的结束端口:" << endl;
		cout << ">>";
		int endPort;
		cin >> endPort;

		cout << "设置超时时间:" << endl;
		cout << ">>";
		cin >> nTimeout;

		scant(ip, startPort, endPort);
	}
	else if (option == 2)
	{

		cout << "设置超时时间:" << endl;
		cout << ">>";
		cin >> nTimeout;

		char tempIp[32];
		strcpy(IP, ip); //OK

		//初始化套接字
		WSADATA ws;
		::WSAStartup(MAKEWORD(2, 0), &ws);

		DWORD start = GetTickCount();
		//初始化临界区
		InitializeCriticalSection(&cs);

		//多线程扫描
		HANDLE hThread[THREADCOUNT];
		for (int i = 0; i < THREADCOUNT; i++)
		{
			hThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (LPVOID)0, 0, NULL);
		}

		//当thread数量超过64的处理
		int tempNumThreads = THREADCOUNT;
		int tempMax = 0;
		while (tempNumThreads >= MAXIMUM_WAIT_OBJECTS)
		{
			tempNumThreads -= MAXIMUM_WAIT_OBJECTS;
			WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, &hThread[tempMax], false, INFINITE);
			tempMax += MAXIMUM_WAIT_OBJECTS;
		}
		WaitForMultipleObjects(tempNumThreads, &hThread[tempMax], false, INFINITE);

		//删除临界区
		DeleteCriticalSection(&cs);

		DWORD end = GetTickCount();
		printf("use time(s):%f\n", (end - start) / 1000.0);
	}
}

//域名装换ip函数
int hostnameToIp()
{
	//使用Ws2_32.dll的初始化 
	WORD wVersionRequested = 0;
	WSADATA wsaData = {};
	int err = 0;
 
	wVersionRequested = MAKEWORD( 2, 2 );
 
	err = WSAStartup( wVersionRequested, &wsaData );
	if ( err != 0 ) 
	{                       
		return -1;
	}                                  
 
	if ( LOBYTE( wsaData.wVersion ) != 2 ||
		HIBYTE( wsaData.wVersion ) != 2 ) 
	{
 
		WSACleanup( );
		return -1; 
	}
 
	//////////////////////////
	char** pptr = NULL;
	char szHostName[256] = {};
	cout << "--------------------------------------" << endl;
	cout << "输入域名:";
	//while( cin.getline( szHostName, sizeof(szHostName) ) )
	//{
	cin.getline(szHostName, sizeof(szHostName));
	HOSTENT* pHostEntry = gethostbyname( szHostName );
	if( NULL != pHostEntry && szHostName[0] != '\0' )
	{
		//将主机的规范名输出
		cout << "主机规范名:" << pHostEntry->h_name << endl;
 
		//主机别名。可含多个
		int i = 0;
		for ( i = 1, pptr = pHostEntry->h_aliases; *pptr != NULL; ++pptr )
		{
			cout << "主机别名" << i++ << ":" << *pptr << endl;
		}
 
 
		//将主机地址列表输出,可含多个
		char szIpBuff[32] = {0};
		for ( i = 1, pptr = pHostEntry->h_addr_list; *pptr != NULL; ++pptr )
		{
			cout << "A" << endl;
			if (i == 1) //只使用一个ip
			{
				memset(szIpBuff, 0, sizeof(szIpBuff));
				//inet_ntop的返回值为NULL,则表示失败。否则返回对应的IP地址(此时szIpRet指向的是szIpBuff)
				const char* szIpRet = inet_ntop(pHostEntry->h_addrtype, *pptr, szIpBuff, sizeof(szIpBuff));
				if (szIpBuff != NULL)
				{
					cout << "解析IP地址" << i++ << ":" << szIpRet << endl;
					char *buf = new char[strlen(szIpRet) + 1];
					strcpy(buf, szIpRet);
					sendController(buf);
				}
			}
			else
			{
				break;
			}
		}
			
	}
	else
	{
		cout << "解析失败。" << endl;
	}
		
 
	cout << "hostnameToip结束" << endl;
	memset( szHostName, 0, sizeof(szHostName) );
	cout << "--------------------------------------" << endl;
	//cout << "输入域名:";
	
	WSACleanup();
	return 0;
}


int main()
{
	
	hostnameToIp();
	
		//cout << "请输入你要扫描的ip:" << endl;
		//cout << ">>";
		//char * ip = new char[50];
		//cin >> ip;
		//char szIpBuff[32] = { 0 };
		//cout << "域名转ip:" << szIpBuff << endl;

		//cout << "输入你要查询的起始端口:" << endl;
		//cout << ">>";
		//int startPort;
		//cin >> startPort;

		//cout << "输入你要查询的结束端口:" << endl;
		//cout << ">>";
		//int endPort;
		//cin >> endPort;

		//scant(ip, startPort, endPort);

	system("pause");
	return 0;
}


Through this experimental study, we completed the optimization of port scanning tool. It includes four parts: the domain name into an IP address, host survival test and delay scanning capabilities, multi-threaded scanning. Relative to the first multi-use multi-threaded scanning, you can speed up your port scan.

Multi-threaded implementation:

Design a thread function

 

// thread function

DWORD WINAPI ThreadProc(LPVOID lpParameter)

Thread function which set the number of ports, the port number from 0-65535, constantly on the rise, the use of the critical area to ensure that no repeat visits a port when using multiple threads.

// enter critical section

EnterCriticalSection(&cs);

int tmpport = PortNum;

PortNum ++;

//DWORD threadID=GetCurrentThreadId();

// printf ( "% d thread is detecting port% d \ n", threadID, PortNum); // all the code resource use critical sections to be locked

// leave critical region

LeaveCriticalSection(&cs);

使用多线程扫描临界区,当线程数量超过64时,可以使用WaitForMultipleObjects函数处理,这个函数其实作用其实就是可以不让在一瞬间创建一大堆线程,而是以64个线程为一个单位,当其中某个线程结束时,再触发下一个单位的线程,放缓线程的创建速度。

 

//初始化临界区

InitializeCriticalSection(&cs);

//多线程扫描

HANDLE hThread[THREADCOUNT];

for (int i = 0; i < THREADCOUNT; i++)

{

hThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (LPVOID)0, 0, NULL);

}

 

//当thread数量超过64的处理

int tempNumThreads = THREADCOUNT;

int tempMax = 0;

while (tempNumThreads >= MAXIMUM_WAIT_OBJECTS)

{

tempNumThreads -= MAXIMUM_WAIT_OBJECTS;

WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, &hThread[tempMax], false, INFINITE);

tempMax += MAXIMUM_WAIT_OBJECTS;

}

WaitForMultipleObjects(tempNumThreads, &hThread[tempMax], false, INFINITE);

 

//删除临界区

DeleteCriticalSection(&cs);

 

 

(2)域名转换ip地址使用gethostbyname这个函数得到域名的相关信息,然后使用inet_ntop解析IP地址

const char* szIpRet = inet_ntop(pHostEntry->h_addrtype, *pptr, szIpBuff, sizeof(szIpBuff));

(3)存活测试适应ping程序看是否ping通,但是在此期间我遇到了一个问题,就是发送的数据包时间过长,没有接到回复,所以要设置超时时间。

// 设置接收超时

    setsockopt(sRaw, SOL_SOCKET, SO_RCVTIMEO, (char const*)&nTimeOut, sizeof(nTimeOut));

4非阻塞与延时扫描使用

    TIMEVAL TimeOut;

FD_SET mask;

unsigned long mode = 1; //ipctlsocket函数的最后一个参数

 

//设置超时毫秒数

TimeOut.tv_sec = 0;

TimeOut.tv_usec = nTimeout;

FD_ZERO(&mask);

FD_SET(s, &mask);

 

//设置为非阻塞模式

ioctlsocket(s, FIONBIO, &mode);

 

connect(s, (struct sockaddr *)&server, sizeof(server)); //连接

int ret = select(0, NULL, &mask, NULL, &TimeOut);

 

Guess you like

Origin blog.csdn.net/guanshanyue96/article/details/92991609