最后一个暑假,因为已经有一个项目在手,不想把自己整得太累,但又不能太闲,于是选择了一个可以拖拖踏踏做的简单事情,做一套端口扫描。这种平时集中精力几天就可以做完的事情,结果真是拖拖踏踏了很久才做完。
进入正题。端口扫描,即是通过一些扫描的手段来探知某些ip的端口情况,主要为探知端口的开放情况与端口的应用类型。
由于各个设备的系统与防火墙的差异,某一单一的端口扫描方式难以应用于所有的系统,而且扫描方并不知道扫描对方的系统情况。为了应对不同情况,有必要采用多种扫描方式协同扫描。在此我使用了connect、tcp syn、tcp fin、helo 这几种方式的扫描。具体的介绍可参考 端口扫描技术。
希望自己的扫描能够高效而准确,于是对扫描策略做了如下设计:
syn、fin扫描方式用于快速端口扫描,使用多线程发送扫描包,另有一处于混杂模式的socket用户接收处理所有的扫描响应。有人说syn扫描方式不适合使用多线程,他的解释是:“使用多线程容易发生数据报的串位现象,也就是原来应该这个线程接收的数据报被另 一个线程接收,接收后,这个数据报就会被丢弃,而等待线程只好在超时之后再发送一个SYN数据报,等待应答。这样,所用的时间反而会增加”。但这并不是问题,注意我这里用的是混杂的原始套接字,所有的数据包都不会漏,只要对这些数据包的处理逻辑写好就没有任何问题。
快速端口扫描设计图:
connect、helo方式用于精确扫描,使用多线程connect端口,同时使用这些线程获取反馈信息。最后处理数据并录入到数据库,这里的重点在于确认端口的开放与判断端口的应用类型。通过helo方式,可以获取到端口返回的应用信息,对返回的信息进行处理识别即可。
精确端口扫描设计图:
扫描结果都将存入数据库:
UI:哈哈,自从在linux上编程,除了我电脑虚拟机的linux,我的服务器上的linux都是没ui的,因此再也没写过任何的C++UI,如果还是用命令行查看端口扫描的结果,未免太寒酸,而且只能自己使用。于是用php粗略地做了个UI。
但是使用php执行端口扫描进程需要http服务具有管理员权限,因为我的c++扫描程序使用到了原始套接字,linux下一般必须有root权限才能使用原始套接字。如果没法通过加sudo的方式执行扫描进程,那么就需要修改httpd的源码重新编译安装后再将httpd配置root权限。具体可参考:httpd转root。
以下讲解一些关键性的代码:
专用数据库代码的封装:
#ifndef SQLUSE_H_INCLUDED
#define SQLUSE_H_INCLUDED
#include <mysql/mysql.h>
#include <string>
using namespace std;
#define LOGINSIZE 32
#define SQLFORMATSIZE 512
#define data_statu_end 0
#define data_statu_wait 1
#define data_statu_rewait 2
#define data_statu_error 3
#define data_statu_run 4
#define data_type_unkonw 0
struct model_data
{
int id;
string created_at;
string updated_at;
string ip;
int port;
string info;
int type;
int statu;
};
char *sqlencode(const char *str,const int len);
class sqluse
{
char sqlhost[LOGINSIZE];
unsigned int sqlport;
char dbname[LOGINSIZE];
char username[LOGINSIZE];
char userpass[LOGINSIZE];
char charset[LOGINSIZE];
MYSQL *con;
public:
char insertdataformat[SQLFORMATSIZE];
char waitdataselectformat[SQLFORMATSIZE];
char statudataupdateformat[SQLFORMATSIZE];
char infodataupdateformat[SQLFORMATSIZE];
char suprunidformat[SQLFORMATSIZE];
char supresultformat[SQLFORMATSIZE];
bool getsqlset();
bool getformatdata();
bool connect();
bool setcharset();
public:
sqluse();
~sqluse();
MYSQL_RES *query(char *sql);
bool insertdata(string ip,int port,int type=1,int statu=1);
int getwaitdata(model_data *arr,int datanum=1);
bool resetdata(int id);
bool seterrordata(int id,int statu);
bool updateinfodata(int id,string info="",int type=data_type_unkonw);
};
#endif
sqluse.h
#include "sqluse.h"
#include <cstdlib>
#include <cstdio>
#include <cstring>
const char encodechar[]="',;";
char *sqlencode(const char *str,const int len)
{
if(str==NULL)
{
puts("vv");
return NULL;
}
int cnt=0;
int elen=strlen(encodechar);
for(int i=0;i<len;i++)
{
for(int j=0;j<elen;j++)
{
if(str[i]==encodechar[j])
{
cnt++;
}
}
}
char *s=new char[len+cnt*2+1];
int slen=0;
for(int i=0;i<len;i++)
{
s[slen]=str[i];
for(int j=0;j<elen;j++)
{
if(str[i]==encodechar[j])
{
s[slen++]='\';
s[slen]=str[i];
break;
}
}
slen++;
}
s[slen]=' ';
//free(str);
return s;
}
sqluse::sqluse()
{
if(!getsqlset())
{
puts("a fail sqluse");
return;
}
if(!getformatdata())
{
return;
}
if(!connect())
{
puts("connect to sqlsever error");
}
setcharset();
}
bool sqluse::getsqlset()
{
FILE *f;
if(!(f=fopen("..//config//sqlset","r")))
{
puts("sqlsetdata read fail!");
return false;
}
fscanf(f,"%s",sqlhost);
fscanf(f,"%u",&sqlport);
fscanf(f,"%s",dbname);
fscanf(f,"%s",username);
fscanf(f,"%s",userpass);
fscanf(f,"%s",charset);
return true;
}
static bool readformat(const char *dir,char *format)
{
FILE *f;
if(!(f=fopen(dir,"r")))
{
puts("formatdata read fail!");
return false;
}
format[0]=' ';
char s[128]="";
while(fgets(s,sizeof(s),f))
{
strcat(format,s);
}
fclose(f);
return true;
}
bool sqluse::getformatdata()
{
readformat("..//sqldata//insertdataformat",insertdataformat);
readformat("..//sqldata//waitdataselectformat",waitdataselectformat);
readformat("..//sqldata//statudataupdateformat",statudataupdateformat);
readformat("..//sqldata//infodataupdateformat",infodataupdateformat);
/*
readformat("..//sqldata//suprunidformat",suprunidformat);
readformat("..//sqldata//supresultformat",supresultformat);
*/
return true;
}
bool sqluse::connect()
{
con=NULL;
con=mysql_init(NULL);
if(con==NULL)
{
puts("sql init error");
return false;
}
if(!mysql_real_connect(con,sqlhost,
username,userpass,
dbname,
sqlport,NULL,0
))
{
printf("sql error: %sn",mysql_error(con));
return false;
}
puts("connect to sqlsever secc");
return true;
}
bool sqluse::setcharset()
{
char s[32];
sprintf(s,"SET NAMES %s",charset);
puts(s);
query(s);
return true;
}
sqluse::~sqluse()
{
mysql_close(con);
}
MYSQL_RES *sqluse::query(char *sql)
{
int state=mysql_query(con,sql);
if(state!=0)
{
connect();
state=mysql_query(con,sql);
}
if(state!=0)
{
printf("sql error: %sn",mysql_error(con));
connect();
return NULL;
}
return mysql_store_result(con);
}
bool sqluse::insertdata(string ip,int port,int type,int statu)
{
char querystr[256];
sprintf(querystr,insertdataformat,ip.c_str(),port,type,statu);
if(NULL==query(querystr))
{
return false;
}
return true;
}
int sqluse::getwaitdata(model_data *arr,int datanum)
{
char querystr[256];
sprintf(querystr,waitdataselectformat);
MYSQL_RES *res=query(querystr);
if(res==NULL)
{
return 0;
}
MYSQL_ROW row;
int i=0;
while((row=mysql_fetch_row(res))!=NULL)
{
if(i>=datanum)
{
break;
}
sscanf(row[0],"%d",&arr[i].id);
arr[i].ip=row[1];
sscanf(row[2],"%d",&arr[i].port);
sscanf(row[3],"%d",&arr[i].statu);
/*
printf("%d %s %d %dn",arr[i].id,
arr[i].ip.c_str(),
arr[i].port,
arr[i].statu);
*/
sprintf(querystr,statudataupdateformat,data_statu_run,arr[i].id);
query(querystr);
/*if(NULL==query(querystr))
{
continue;
}*/
i++;
}
return i;
}
bool sqluse::resetdata(int id)
{
char querystr[64];
sprintf(querystr,statudataupdateformat,data_statu_wait,id);
if(NULL==query(querystr))
{
return false;
}
return true;
}
bool sqluse::seterrordata(int id,int statu)
{
int restatu=data_statu_error;
if(statu==data_statu_wait)
{
restatu=data_statu_rewait;
}
//== restatu=statu+1;
char querystr[64];
sprintf(querystr,statudataupdateformat,restatu,id);
if(NULL==query(querystr))
{
return false;
}
return true;
}
bool sqluse::updateinfodata(int id,string pinfo,int type)
{
pinfo=sqlencode(pinfo.c_str(),pinfo.length());
char querystr[2048];
sprintf(querystr,infodataupdateformat,pinfo.c_str(),type,data_statu_end,id);
if(NULL==query(querystr))
{
return false;
}
return true;
}
sqluse.cpp
对socket进行专门用于syn扫描的封装:
1 class msock_synscan
2 {
3 public:
4 SOCKET sock;
5 sockaddr_in addr;
6 socklen_t addrlen;
7 sockaddr_in saddr;
8
9 char buf[sizeof(PSD_HEADER)+sizeof(TCP_HEADER)+20];
10 char *synbuf;
11
12 char rbuf[2048];
13
14 msock_synscan(unsigned short port=55555,const char *devname = "eth0")
15 {
16 synbuf=buf+sizeof(PSD_HEADER);
17 sock=socket(AF_INET,SOCK_RAW, IPPROTO_TCP);
18 if(sock==INVALID_SOCKET)
19 {
20 puts("socket build error");
21 exit(-1);
22 }
23
24 addr.sin_family=AF_INET;
25
26 saddr.sin_addr.s_addr=getlocalip(devname);
27 saddr.sin_port=htons(port);
28 }
29
30 void setioctl(bool x)
31 {
32 const int flag = 1;
33 if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL, &flag, sizeof(flag)) < 0)
34 {
35 perror("setsockopt fail n");
36 exit(-1);
37 }
38 return;
39
40 #ifdef WIN32
41 if(!x)
42 {
43 return;
44 }
45 unsigned long ul = 1;
46 ioctlsocket(sock, FIONBIO, (unsigned long*)&ul);
47 #else
48 fcntl(sock, F_SETFL, O_NONBLOCK);
49 #endif
50 }
51
52 bool setip(string ip)
53 {
54 hostent *hname=gethostbyname(ip.c_str());
55 if(!hname)
56 {
57 puts("can't find address");
58 return false;
59 }//puts(inet_ntoa(addr.sin_addr));
60 #ifdef WIN32
61 addr.sin_addr.S_un.S_addr=*(u_long *)hname->h_addr_list[0];
62 #else
63 addr.sin_addr.s_addr=*(u_long *)hname->h_addr_list[0];
64 #endif
65 return true;
66 }
67
68 void setport(int port)
69 {
70 addr.sin_port=htons(port);
71 }
72
73 int mbind()
74 {
75 return bind(sock,(struct sockaddr *)&addr,sizeof(sockaddr));
76 }
77
78 bool sendsyn()
79 {
80 TCP_HEADER *th=(TCP_HEADER *)synbuf;
81 th->SourPort=saddr.sin_port;
82 th->DestPort=addr.sin_port;
83 th->SeqNo=0;
84 th->AckNo=0;
85 th->HLen=(char)80;
86 th->Flag=SYN;
87 th->WndSize=htons(8192);
88 th->ChkSum=0;
89 th->UrgPtr=htons(0);
90
91 PSD_HEADER *ph = (PSD_HEADER *)buf;
92 ph->saddr=saddr.sin_addr.s_addr;
93 //inet_addr("192.168.0.4");
94 ph->daddr=addr.sin_addr.s_addr;
95 ph->mbz=(char)0;
96 ph->protocal=IPPROTO_TCP;
97 ph->nextlen=ntohs(20);
98 ph->plug=0;
99
100 th->ChkSum=check_sum((unsigned short *)ph,sizeof(PSD_HEADER)+sizeof(TCP_HEADER));
101 int slen=sendto(sock,synbuf,sizeof(TCP_HEADER),0,(sockaddr *)&addr,sizeof(sockaddr));
102 //printf("(send: %d)n",slen);
103
104 if(slen>=sizeof(TCP_HEADER))
105 {
106 return true;
107 }
108 return false;
109 }
110
111 tcpflag recvack()
112 {
113 tcpflag fg;
114
115 int rlen=recvfrom(sock,rbuf,sizeof(rbuf),0,(sockaddr *)&addr,&addrlen);
116
117 if(rlen>=(sizeof(IP_HEADER)+sizeof(TCP_HEADER)))
118 {
119 IP_HEADER *iph = (IP_HEADER *)rbuf;
120 if(iph->proto==IPPROTO_TCP)
121 {
122 TCP_HEADER *th = (TCP_HEADER *)(rbuf+sizeof(IP_HEADER));
123 //printf("(%02x %02x)n",th->DestPort,saddr.sin_port);
124 if(th->DestPort == saddr.sin_port)
125 {
126 //printf("(_%02x_)",th->Flag);
127
128 fg.ip=iph->sourceIP;
129 fg.port=th->SourPort;
130
131 if(th->Flag&SYN)
132 {
133 //puts("syn");
134 fg.issyn=true;
135 }
136 if(th->Flag&ACK)
137 {
138 //puts("ack");
139 fg.isack=true;
140 }
141 if(th->Flag&RST)
142 {
143 //puts("rst");
144 fg.isrst=true;
145 }
146 }
147
148 }
149 }
150
151 return fg;
152 }
153
154 int mclose()
155 {
156 #ifdef WIN32
157 return closesocket(sock);
158 #else
159 return close(sock);
160 #endif
161 }
162
163 };
1 struct IP_HEADER
2 {
3 unsigned char header_len:4;
4 unsigned char version:4;
5 unsigned char tos;
6 unsigned short total_len;
7 unsigned short ident;
8 unsigned short flags;
9 unsigned char ttl;
10 unsigned char proto;
11 unsigned short cheacksum;
12 unsigned int sourceIP;
13 unsigned int destIP;
14 };
15 struct TCP_HEADER
16 {
17 #define SYN (char)0x02
18 #define ACK (char)0x10
19 #define RST (char)0x04
20 unsigned short SourPort;
21 unsigned short DestPort;
22 unsigned int SeqNo;
23 unsigned int AckNo;
24 unsigned char HLen;
25 unsigned char Flag;
26 unsigned short WndSize;
27 unsigned short ChkSum;
28 unsigned short UrgPtr;
29 };
30 struct PSD_HEADER
31 {
32 unsigned long saddr;
33 unsigned long daddr;
34 char mbz;
35 char protocal;
36 unsigned short nextlen;
37 unsigned int plug;
38 };
39
40
41
42
43 static unsigned long getlocalip(const char *devname)
44 {
45 char ipaddr[20];
46 struct sockaddr_in addr;
47 struct hostent *host;
48 struct ifreq req;
49 int sock;
50 char *temp_ip = NULL;
51 sock = socket(AF_INET, SOCK_DGRAM, 0);
52 strncpy(req.ifr_name, devname, IFNAMSIZ);
53 if ( ioctl(sock, SIOCGIFADDR, &req) < 0 )
54 {
55 printf("get local addr errorn");
56 return NULL;
57 }
58 temp_ip = (char *)inet_ntoa(*(struct in_addr *) &((struct sockaddr_in *) &req.ifr_addr)->sin_addr);
59 strcpy(ipaddr,temp_ip);
60 close(sock);
61 //puts(ipaddr);
62 return inet_addr(ipaddr);
63 }
64
65 struct tcpflag
66 {
67 unsigned long ip;
68 unsigned short port;
69 bool issyn;
70 bool isack;
71 bool isrst;
72 tcpflag()
73 {
74 init();
75 }
76 void init()
77 {
78 issyn=false;
79 isack=false;
80 isrst=false;
81 }
82 bool isdata()
83 {
84 return issyn||isack||isrst;
85 }
86 bool isre()
87 {
88 return isack||isrst;
89 }
90 };
91
92 static unsigned short check_sum(unsigned short *addr, int len)
93 {
94 int nleft = len;
95 int sum = 0;
96 unsigned short *w = addr;
97 short answer = 0;
98 while (nleft > 1)
99 {
100 sum += *w++;
101 nleft -=2;
102 }
103 if (nleft == 1)
104 {
105 *(unsigned char *)(&answer) = *(unsigned char *)w;
106 sum += answer;
107 }
108 sum = (sum >> 16) + (sum & 0xffff);
109 sum += (sum >> 16);
110 answer = ~sum;
111 return answer;
112 }
syn 依赖项
该类可用于进行syn扫描,通过创建原始套接字在ip层之上构造自己的tcp syn包并发送。接收函数会接收所有的包并筛选出所在扫描范围类的应答包,因为接收是混杂的,所以使用时只需要一个单独的类用接收即可。此处需要注意校验和的计算,因为syn包是不带任何数据的,所以值计算伪首部与syn包的校验和。
syn扫描的实现类:
1 #ifndef _SYNSCAN_H_
2 #define _SYNSCAN_H_
3
4 #include "msock.h"
5 #include <pthread.h>
6
7 struct threadinfo_syn//用于线程通讯的结构体
8 {
9 pthread_t thid;
10 unsigned short id;
11
12 string destip;
13 unsigned short destport;
14 void *classptr;
15
16 bool isfree;
17 bool isendthread;
18 tcpflag flag;
19
20 void setwait()
21 {
22 flag.init();
23 isfree = true;
24 }
25 void setcmd(tcpflag _flag)
26 {
27 flag=_flag;
28 }
29 void init(int _id, void *_classptr)
30 {
31 id=_id;
32 classptr=_classptr;
33 setwait();
34 }
35 void setdest(string _destip,unsigned short _destport)
36 {
37 destip=_destip;
38 destport=_destport;
39 isfree = false;
40 }
41 };
42
43 #define syn_threadnum 100
44
45 class scan_syn
46 {
47 public:
48 unsigned short localport;
49 string devname;
50
51 string startip,endip;
52 unsigned short startport,endport;
53
54 unsigned short threadnum;//thread num of synsend
55 threadinfo_syn *info;
56
57 scan_syn(unsigned short port=65222,string dev = "eth0");
58 ~scan_syn();
59 void setworkinfo(string _startip,string _endip,unsigned short _startport,unsigned short _endport);
60 void cmain();
61
62
63
64 int findthreadbyflag(tcpflag flag);
65
66 bool isendackthread;
67 pthread_t ackthid;
68 static void *thread_synsend(void *arg);
69 static void *thread_ackrecv(void *arg);
70
71 threadinfo_syn *waitfreesendthread();
72 };
73
74
75 #endif // _SYNSCAN_H_
#include "synscan.h"
scan_syn::scan_syn(unsigned short port,string dev)
{
devname=dev;
localport=port;
threadnum=syn_threadnum;
info=new threadinfo_syn[threadnum];
for(int i=0;i<threadnum;i++)
{
info[i].init(i,this);
}
}
scan_syn::~scan_syn()
{
delete[](info);
}
int scan_syn::findthreadbyflag(tcpflag flag)
{
for(int i=0;i<threadnum;i++)
{
if(info[i].isfree)
{
continue;
}
if(inet_addr(info[i].destip.c_str())==flag.ip&&
ntohs(info[i].destport)==flag.port)
{
return i;
}
}
return -1;
}
void scan_syn::setworkinfo(string _startip,string _endip,unsigned short _startport,unsigned short _endport)
{
startip=_startip;
endip=_endip;
startport=_startport;
endport=_endport;
}
static bool isipend(string endip,string ip)
{
return ntohl(inet_addr(ip.c_str()))
<=ntohl(inet_addr(endip.c_str()));
}
static string nextip(string ip)
{
in_addr_t temp=ntohl(inet_addr(ip.c_str()));
temp=htonl(temp+1);
in_addr inaddr;
inaddr.s_addr=temp;
ip=inet_ntoa(inaddr);
return ip;
}
void scan_syn::cmain()
{
int error;
error=pthread_create(&ackthid,NULL,scan_syn::thread_ackrecv,this);
if(error!=0)
{
printf("create thread ackrecv error:%sn",strerror(error));
exit(-1);
}
for(int i=0;i<threadnum;i++)
{
error=pthread_create(&info[i].thid,NULL,scan_syn::thread_synsend,&info[i]);
if(error!=0)
{
printf("create thread synsend %d error:%sn",i,strerror(error));
exit(-1);
}
}
for(string ip=startip; isipend(endip,ip); ip=nextip(ip))
{
for(unsigned short port=startport; port<=endport; port++)
{
threadinfo_syn *stinfo=waitfreesendthread();
if(stinfo!=NULL)
{
stinfo->setdest(ip,port);
//printf("%s %dn",ip.c_str(),port);
}
else
{
printf("..n");
}
}
}
getchar();
}
void *scan_syn::thread_synsend(void *arg)
{
threadinfo_syn *info = (threadinfo_syn *)arg;
scan_syn *that = (scan_syn *)info->classptr;
msock_synscan synsock(that->localport,
that->devname.c_str());
//synsock.setioctl(true);
while(!info->isendthread)
{
if(info->isfree)
{
continue;
}
synsock.setip(info->destip);
synsock.setport(info->destport);
int cnt=5;
while(!synsock.sendsyn()&&cnt--)
{
sleep(1);
}
if(cnt>0)
{
//SEND SECC
cnt=5;
while(!info->flag.isdata()&&cnt--)
{
sleep(1);
}
if(cnt>0)
{
//UPLOAD ON SQL
printf("ip:%s port:%d issyn:%d isack:%d isrst:%dn",
info->destip.c_str(),info->destport,
info->flag.issyn,
info->flag.isack,
info->flag.isrst);
}
}
else
{
printf("send syn error ip:%s port:%dn",
info->destip.c_str(),info->destport);
}
info->setwait();
}
synsock.mclose();
}
void *scan_syn::thread_ackrecv(void *arg)
{
scan_syn *that=(scan_syn *)arg;
msock_synscan acksock(that->localport,
that->devname.c_str());
tcpflag reflag;
while(!that->isendackthread)
{
reflag=acksock.recvack();
if(reflag.isre())
{
int threadid = that->findthreadbyflag(reflag);
if(threadid>=0)
{
that->info[threadid].setcmd(reflag);
}
}
}
acksock.mclose();
}
threadinfo_syn *scan_syn::waitfreesendthread()
{
int cnt=60;
while(cnt--)
{
for(int i=0;i<threadnum;i++)
{
if(info[i].isfree)
{
return info+i;
}
}
sleep(1);
}
return NULL;
}
syn_scan.cpp
关于应答处理线程与发送线程的通信与同步,这里我采用的是通过threadinfo_syn结构体来实现双方的通讯与协调,每个发包线程有一个对应的id以及目的ip port,接收线程接收到应答包后,会根据ip port 在threadinfo_syn中查找到对应的线程id并通知其应答结果。当发包线程超时后会将自己从threadinfo_syn中释放掉。
在这里理论上系统能支持多大的线程数和socket数,就能开多大的线程。但实际上过多的并发syn会被一些防火墙所察觉。
connect扫描类实现:
1 #ifndef _SYNSCAN_H_
2 #define _SYNSCAN_H_
3
4 #include "../include/msock.h"
5 #include "../include/sqluse.h"
6 #include <queue>
7 using namespace std;
8
9 struct threadinfo_connect
10 {
11 pthread_t thid;
12 unsigned short id;
13
14 string destip;
15 unsigned short destport;
16
17 model_data model;
18
19 void *classptr;
20
21 bool isfree;
22 bool isendthread;
23
24 void setwait()
25 {
26 isfree = true;
27 }
28 void init(int _id, void *_classptr)
29 {
30 id=_id;
31 classptr=_classptr;
32 setwait();
33 }
34 void setdest(string _destip,unsigned short _destport)
35 {
36 destip=_destip;
37 destport=_destport;
38 isfree = false;
39 }
40 };
41
42 #define connect_threadnum 2
43 #define hellowinfo "lxsb"
44 #define timeoutvalue 2
45
46 class scan_connect
47 {
48 public:
49 unsigned short threadnum;
50 threadinfo_connect *info;
51
52 queue<model_data> taskque;
53
54 scan_connect();
55 ~scan_connect();
56 bool isendmain;
57 void cmain();
58
59 bool isendgettaskthread;
60 pthread_t gettaskthid;
61 static void *thread_gettask(void *arg);
62 static void *thread_connect(void *arg);
63
64 threadinfo_connect *waitfreesendthread();
65 };
66
67 #endif //_SYNSCAN_H_
1 #include "connectscan.h"
2
3 scan_connect::scan_connect()
4 {
5 threadnum=connect_threadnum;
6 info=new threadinfo_connect[threadnum];
7
8 for(int i=0;i<threadnum;i++)
9 {
10 info[i].init(i,this);
11 }
12 }
13
14
15 scan_connect::~scan_connect()
16 {
17 delete[](info);
18 }
19
20 void scan_connect::cmain()
21 {
22 int error;
23 isendgettaskthread=false;
24 error=pthread_create(&gettaskthid,NULL,scan_connect::thread_gettask,this);
25 if(error!=0)
26 {
27 isendgettaskthread=true;
28 printf("create thread gettask error:%sn",strerror(error));
29 exit(-1);
30 }
31
32 for(int i=0;i<threadnum;i++)
33 {
34 error=pthread_create(&info[i].thid,NULL,scan_connect::thread_connect,&info[i]);
35 if(error!=0)
36 {
37 printf("create thread connect %d error:%sn",i,strerror(error));
38 exit(-1);
39 }
40 }
41
42
43 while(!this->isendmain)
44 {
45 if(this->taskque.empty())
46 {
47 sleep(1);
48 continue;
49 }
50 model_data taskdata=taskque.front();
51 taskque.pop();
52
53 threadinfo_connect *stinfo=waitfreesendthread();
54 if(stinfo!=NULL)
55 {
56 stinfo->model=taskdata;
57 stinfo->setdest(taskdata.ip,taskdata.port);
58 }
59 else
60 {
61 printf("..n");
62 }
63 }
64 }
65
66
67 void *scan_connect::thread_gettask(void *arg)
68 {
69 puts("thget st");
70 scan_connect *that=(scan_connect *)arg;
71
72 sqluse sql;
73
74 model_data tdata[10];
75 int num;
76 while(!that->isendgettaskthread)
77 {
78 num=sql.getwaitdata(tdata,sizeof(tdata));
79 //printf("(%d)n",num);
80 for(int i=0;i<num;i++)
81 {
82 printf("%d %s %d %dn",tdata[i].id,
83 tdata[i].ip.c_str(),
84 tdata[i].port,
85 tdata[i].statu);
86 if(that->taskque.size()<connect_threadnum*10)
87 {puts("tdata in");
88 that->taskque.push(tdata[i]);
89 }
90 else
91 {
92 sql.resetdata(tdata[i].id);
93 sleep(1);
94 }
95 }
96 sleep(1);
97 }
98
99 }
100
101 void *scan_connect::thread_connect(void *arg)
102 {
103 threadinfo_connect *info = (threadinfo_connect *)arg;
104 scan_connect *that = (scan_connect *)info->classptr;
105
106 sqluse sql;
107 char rebuf[256];
108 int relen;
109 while(!info->isendthread)
110 {
111 if(info->isfree)
112 {
113 sleep(0.1);
114 continue;
115 }
116 printf("i were gan %s %dn",info->destip.c_str(),info->destport);
117
118 msock_tcp tcpsock;
119 tcpsock.settimeout(timeoutvalue);
120 tcpsock.setip(info->destip);
121 tcpsock.setport(info->destport);
122 if(SOCKET_ERROR==tcpsock.mconnect())
123 {
124 sql.seterrordata(info->model.id,info->model.statu);
125 }
126 else
127 {
128 tcpsock.msend(hellowinfo,sizeof(hellowinfo));
129 relen=tcpsock.mrecv(rebuf,sizeof(rebuf));
130 if(relen<0)
131 {
132 relen=0;
133 }
134 if(relen>=sizeof(rebuf))
135 {
136 relen=sizeof(rebuf)-1;
137 }
138 rebuf[relen]=' ';
139 sql.updateinfodata(info->model.id,rebuf,data_type_unkonw);
140 tcpsock.mclose();
141 }
142
143 info->setwait();
144 }
145 }
146
147 threadinfo_connect *scan_connect::waitfreesendthread()
148 {
149 int cnt=60;
150 while(cnt--)
151 {
152 for(int i=0;i<threadnum;i++)
153 {
154 if(info[i].isfree)
155 {
156 return info+i;
157 }
158 }
159 sleep(1);
160 }
161 return NULL;
162 }
connectscan.cpp
connectscan的线程通信方式和synscan相同。
connectscan通过循环的数据库查询线程来获取connect任务,connect成功后便更新数据库中的该ip poet为开放状态,然后通过helo方式发送tcp helo包,并接收返回的数据,将该数据进行判断处理后更新到数据库中。
这里每个connect线程所要做的就是在接到命令后connect目标并进行通讯,然后上传数据库,因为是是精确扫描,且都被syn已经过滤了大量无效端口,所以connect的任务量很小,对效率要求不高,这里可以采用阻塞的方式来进行connectscan,把超时时间圈定一个稍小的值即可。
最后是UI部分:
1 <?php
2 $dsn = 'mysql:host=xxx;dbname=portscan';
3 $db = new PDO($dsn, 'xxx', 'xxx');
4
5 $selectformat="select * from data
6 where `ip`>='%s' and `ip`<='%s' and `port`>='%s' and `port`<='%s'";
7 $selectbyinfoformat="select * from data
8 where `info` like '%s'";
9 ?>
10
11 <?php
12 $scanthreadnum=100;
13 ?>
14
15
16
17 <?php
18 $startip='0.0.0.0';
19 $endip='255.255.255.255';
20 $startport=0;
21 $endport=65535;
22 $keyinfo='';
23
24 function getdata($name,$data='')
25 {
26 if(isset($_GET[$name]))
27 {
28 if(strlen($_GET[$name])>0)
29 {
30 return $_GET[$name];
31 }
32 }
33 return $data;
34 }
35
36 $startip=getdata('startip',$startip);
37 $endip=getdata('endip',$endip);
38 $startport=getdata('startport',$startport);
39 $endport=getdata('endport',$endport);
40 $keyinfo=getdata('keyinfo',$keyinfo);
41
42 /*
43 echo $startip.'<br/>';
44 echo $endip.'<br/>';
45 echo $startport.'<br/>';
46 echo $endport.'<br/>';
47 echo $keyinfo.'<br/>';
48 */
49
50 ?>
51
52 <table>
53 <tr>
54 <td><a href="main.php">home</a></td>
55 <td><a href="view.php">view</a></td>
56 </tr>
57 </table>
1 <?php
2 include 'include.php';
3 ?>
4
5
6
7 <?php
8
9 $questr='';
10 if(strlen($keyinfo)>0)
11 {
12 $questr=sprintf($selectbyinfoformat,'%'.$keyinfo.'%');
13 }
14 else
15 {
16 $questr=sprintf($selectformat,$startip,$endip,$startport,$endport);
17 }
18 $re=$db->query($questr);
19
20 ?>
21 <table border="1">
22 <tr>
23 <th>ip</th>
24 <th>port</th>
25 <th>info</th>
26 <th>update</th>
27 </tr>
28 <?php
29 while($row=$re->fetch())
30 {
31 ?>
32 <tr>
33 <td><?php echo $row['ip'] ?></td>
34 <td><?php echo $row['port'] ?></td>
35 <td><?php echo $row['info'] ?></td>
36 <td><?php echo $row['updated_at'] ?></td>
37 </tr>
38 <?php
39 }
40 ?>
41 </table>
1 <?php
2 include 'include.php';
3
4 ?>
5
6
7
8 <?php
9 //该处需要以root权限执行portscan进程
10 $execstr='./portscan '.$startip.' '.$endip.
11 ' '.$startport.' '.$endport.' '.$scanthreadnum.' '.$keyinfo;
12
13 echo $execstr;
14 exec($execstr,$output,$revar);
15 var_dump($output);
16 echo $revar;
17 //等待执行过程的时间可能过长,可以使用ajax实时反馈扫描信息
18 echo 'scan secc';
19 ?>
这里的查询部分可以通过对端口的描述keyinfo进行查询,比如要找ftp端口,将keyinfo设为ftp即可。
这样我也可以用来扫描小朋友的mc服务器啦。
整个端口扫描系统到此告一段落。人生最后的一个暑期也即将结束,珍惜最后的时间再好好玩玩。
原文链接: https://www.cnblogs.com/wchrt/p/4732045.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/220684
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!