一。原理
端口扫描器是一种程序,它可以对目标主机的端口进行连接,并记录目标端口的应答。端口扫描器通过选用远程TCP/IP协议不同的端口的服务,记录目标计算机端口给予回答的方法,可以收集到很多关于目标计算机的各种有用信息(比如是否有端口在侦听,是否允许匿名登录,是否有可写的FTP目录,是否能用Telnet等)。
网络中的每一台计算机如同一座城堡,在这些城堡中,有的对外完全开放,有的却是紧锁城门。入侵者们是如何找到,并打开它们的城门的呢?这些城门究竟通向城堡的何处呢?在网络技术中,把这些城堡的“城门”称之为计算机的“端口”。端口扫描是入侵者搜集信息的几种常用手法之一。端口相当于两台计算机进程间的大门,可以随便定义,其目的只是为了让两台计算机能够找到对方的进程。计算机就像一座大楼,这个大楼有好多入口(端口),进到不同的入口中就可以找到不同的公司(进程)。如果要和远程主机A的程序通信,那么只要把数据发向A端口就可以实现通信了。
可见,端口与进程是一一对应的,如果某个进程正在等待连接,称之为该进程正在监听,那么就会出现与它相对应的端口。由此可见,通过扫描端口,便可以判断出目标计算机有哪些通信进程正在等待连接。
端口扫描的原理其实非常简单,只是简单的利用JAVA提供库函数Socket进行调用,与每一个感兴趣的目标计算机的端口进行连接。如果对方端口处于监听状态,那么连接就能成功。否则,这个端口不能用,既没有提供服务。这个技术的一个最大的优点是,不需要任何权限,系统中的任何用户都有权利使用这个调用。
引入多线程机制,利用多线程扫描的好处就是速度快,如果对每个目标端口以线性的方式使用单独的连接调用,那么将会花费相当长的时间。多线程同时打开多个套接字,从而加速扫描。在本设计中用户可以自定义线程的个数。此处用户还可以自定义扫描方式。
二。代码实现(为了深入理解 ,代码设置有错误,请勿直接使用,仅作参考)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef struct _port_segment
{
struct in_addr dest_ip; //destination ip address;
unsigned short int min_port; //begin port
unsigned short int max_port;// end port
}port_segment;
void my_err(const char *err_string int line)
{
fprintf(stderr, "line %d ",line);
perror(error_string);
exit(1);
}
//description scan one port on one ip
int do_scan(struct sockaddr_in serv_addr)
{
int conn_fd;
int ret;
conn_fd=socket(AF_INET,SOCK_STREAM,0);
if(conn_fd<0)
{
my_err("socket" ,__LINE__);
}
if((ret=connect(conn_fd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr)))<-)
{
if(errno==ECONNREUSED)
{
//target port close
close(conn_fd);
return 0;
}
else
{
close(conn_fd);
return -1
}
}else if(ret==0)
{
printf("port %d found in %s \n",ntohs(serv_addr.sin_port),inet_ntoa(serv_addr.sin_addr));
close(conn_fd);
return 1
}
return -1
}
void *scaner(void *arg)
{
unsigned short int i;
struct sockaddr_in serv_addr;
port_segment portinfo;//port information
memcpy(&portinfo,arg,sizeof(struct _port_segment));
memset(&serv_addr,0,sizeof(struct sockaddr_in));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=portinfo.dest_ip.s_addr;
for(i=portinfo.min_port;i<=portinfo.max_port;+i++)
{
serv_addr.sin_port=htons(i);
if(do_scan(serv_addr)<0)
continue;
}
return NULL;
}
int main(int argc, char **argv)
{
pthread_t *thread; //thread id
int max_port; //max port number
int thread_num; //max thread number
int seg_len; //port length
struct in_addr dest_ip;//destination ip
if(argc!=7)
{
printf("Usage :]-m [max_port] -a [serv_addr] -n thread_number\n");
exit(1);
}
for(i=1;i<argc;i++)
{
if(strcmp("-m",argv[1]])==0)
{
max_port=atoi(argv[i+1]);
if(max_port<||max_port>65535)
{
printf("Usage: invalid max destination port \n");
exit(1);
}
continue;
}
if(strcmp("-a",argv[i])==0)
{
if(inet_aton(argv[i+1]),&dest_ip)==0)
{
printf("Ysage :invalid destination ip address \n");
exit(1);
}
continue;
}
if(strcmp("-n",argv[i])==0)
{
thread_num=atoi(argv[i+1]);
if(thread_num<=0)
{
printf("Usage invalid thread number \n");
exit(1);
}
continue;
}
}
if(max_port<thread_num)
{
thread_num=max_port;
}
seg_len=max_port; //
if((max_port%thread_num)!=0)
{
thread_num+=1;
}
thread=(pthread_t *)malloc(thread_num*sizeof(pthread_t));
for(i=0;i<pthread_num;i++)
{
port_segment portinfo;
portinfo.dest_ip=dest_ip;
portinfo.min_port=i*seg_len+1;
if(i=pthread_num-1)
{
portinfo.max_port=max_port;
}
else
{
portinfo.max_port=portinfo.min_port+seg_len-1;
}
if(pthread_create(&thread[i],NULL,scanner,(void *)&portinfo)!=0)
{
my_err("thread create ",__LINE__);
}
//wait for child thread ended
pthread_join(thread[i],NULL);
}
return 0;
}