1.实验任务
编写一个利用全连接的端口扫描程序,能显示目标主机的端口开放情况。要求能在命令行输入要扫描的目标主机和端口范围。比如:scan *.*.*.* nnnn-mmmm。
2.实验原理
我们知道完成一次TCP连接需要完成三次握手才能建立。端口扫描正是利用了这个原理,通过假冒正常的连接过程,依次向目标主机的各个端口发送连接请求,并根据目标主机的应答情况判断目标主机端口的开放情况,从而分析并对一些重要端口实施攻击。
3.实验设计
利用理论课实验二()中的客户端程序代码修改而来(记得修改IP地址)
原理是通过connect()函数向主机端发送SYN包,如果主机端端口开放,则会返回SYN+ACK包,客户端再发送ACK包以发送连接请求,加入accept()队列,此过程可通过connect函数的返回值判断是否成功连接,从而判断端口是否开放
运行代码可能导致windows防火墙报错,选择信任即可
#include"stdafx.h"
#include <Winsock2.h>
#include <string>
#include <iostream>
int scanpost(int hp)
{
WSADATA wsd;
WSAStartup(MAKEWORD(2, 2), &wsd);
SOCKET sock_c;
SOCKADDR_IN addr_c;
sock_c = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); //**重要**采用TCP协议
addr_c.sin_family = AF_INET; //指定IPV4地址协议
addr_c.sin_addr.S_un.S_addr = inet_addr("xxx.xxx.153.117"); //目标地址
addr_c.sin_port = htons(hp); //指定端口
int ret = connect(sock_c, (LPSOCKADDR)&addr_c, sizeof(addr_c)); //ret=0 连接成功,ret = -1 连接失败;
if(ret == 0)
{
printf("端口号:%d 端口开放\n",hp);
}
else
{
// printf("端口号:%d 端口关闭\n",hp);
}
WSACleanup();
closesocket(sock_c);
return 0;
}
int main()
{
for(int hp=1;hp<10000;hp++)
{
scanpost(hp);
}
return 0;
}
4.思考题
①阐述全连接扫描的原理
这个属于理论知识,上面的实验原理解释了一部分,但大伙自己搜的肯定比我讲的准确
②你的程序是否考虑了扫描效率?如没有考虑你准备如何改进?
大伙运行上面的基础程序肯定会感觉很慢,这是因为connect的超时时间较长,对于未开放的端口,需要等待很久(大概1秒?)才会确定无法连接,返回-1,我们可以采取select模型+非阻塞套接字限制超时时间(Timeout),从而极大缩短判断超时所需时间
#include"stdafx.h"
#include <Winsock2.h>
#include <string>
#include <iostream>
int scanpost()
{
WSADATA wsd;
WSAStartup(MAKEWORD(2, 2), &wsd);
SOCKET sock_c;
SOCKADDR_IN addr_c;
TIMEVAL TimeOut; //超时时间
FD_SET mask; //管理套接字结构体
TimeOut.tv_sec = 0; //秒
TimeOut.tv_usec = 10000; //微秒
unsigned long mode = 1; //指定模式
for(int hp = 1;hp<10000;hp++)
{
sock_c = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); //**重要**采用TCP协议
addr_c.sin_family = AF_INET; //IPV4地址协议
addr_c.sin_addr.S_un.S_addr = inet_addr("100.98.153.117"); //目标地址
addr_c.sin_port = htons(hp); //端口变量
FD_ZERO(&mask); //清空
FD_SET(sock_c, &mask); //装入sock_c
ioctlsocket(sock_c, FIONBIO, &mode); //将套接字转为非阻塞
connect(sock_c, (struct sockaddr *)&addr_c, sizeof(addr_c)); //发送连接请求
int ret = select(0, 0, &mask, 0, &TimeOut); // 0表示超时,1表示成功,-1表示错误
if(ret != 0 && ret != -1)
{
printf("端口号:%d 端口开放\n",hp);
}
else
{
// printf("端口号:%d 端口关闭\n",hp);
}
}
WSACleanup();
closesocket(sock_c);
return 0;
}
int main()
{
scanpost();
return 0;
}