zoukankan      html  css  js  c++  java
  • 端口扫描 多方式协同实现

      最后一个暑假,因为已经有一个项目在手,不想把自己整得太累,但又不能太闲,于是选择了一个可以拖拖踏踏做的简单事情,做一套端口扫描。这种平时集中精力几天就可以做完的事情,结果真是拖拖踏踏了很久才做完。

      进入正题。端口扫描,即是通过一些扫描的手段来探知某些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: %s
    ",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: %s
    ",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 %d
    ",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 
    ");
     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)
    ",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)
    ",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 error
    ");
     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:%s
    ",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:%s
    ",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 %d
    ",ip.c_str(),port);
                }
                else
                {
                    printf("..
    ");
                }
            }
        }
    
    
        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:%d
    ",
                           info->destip.c_str(),info->destport,
                           info->flag.issyn,
                           info->flag.isack,
                           info->flag.isrst);
                }
            }
            else
            {
                printf("send syn error  ip:%s port:%d
    ",
                     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:%s
    ",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:%s
    ",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("..
    ");
     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)
    ",num);
     80         for(int i=0;i<num;i++)
     81         {
     82             printf("%d %s %d %d
    ",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 %d
    ",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服务器啦。

      整个端口扫描系统到此告一段落。人生最后的一个暑期也即将结束,珍惜最后的时间再好好玩玩。

  • 相关阅读:
    Minimum Cost POJ
    SPFA费用流模板
    ISAP模板
    822D My pretty girl Noora
    822C Hacker, pack your bags!
    Dinic模板
    extjs最普通的grid
    springmvc配置首页的方式
    JSTL select和checkbox的用法
    请教<context:component-scan/>和<mvc:annotation-driven/>的区别20
  • 原文地址:https://www.cnblogs.com/wchrt/p/4732045.html
Copyright © 2011-2022 走看看