Unix TCP端口扫描程序

时间:2013-01-15 10:39:38

标签: c unix tcp port-scanning

我有一个TCP端口扫描程序,它扫描给定IP上的所有开放端口,并仅返回打开的端口以及符号上的服务名称。为此,我创建一个套接字,将其设置为非阻塞模式,并在端口上select(),如果超时则表示端口已关闭,否则打开。问题是我的select()总是超时,即使我尝试扫描开放端口。我希望有人指出我的错误,我的逻辑是不是很糟糕?

#include <stdlib.h>
#include <iostream>
#include <cstdio>
#include <string.h>
#include <netdb.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/time.h>
#include <errno.h>

using namespace std;
fd_set    working_set;
hostent *he;
char* protoc [2] = { "tcp","udpn" };
int port;
struct sockaddr_in servaddr;
int sendfd;
servent *srvport;
void set_nonblock(int socket) {
    int flags;
    flags = fcntl(socket,F_GETFL,0);
    assert(flags != -1);
    fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
void set_block(int socket) {
    int flags;
    flags = fcntl(socket,F_GETFL,0);
    assert(flags != -1);
    fcntl(socket, F_SETFL, flags | ~O_NONBLOCK);
}

int main( int argc, char* argv[] )
{

    struct timeval  timeout;
    timeout.tv_sec  = 1;
    timeout.tv_usec = 0;
    char* host = argv[1];
    char* pro = argv[2];
    int portlow  = atoi(argv[3]);
    int porthigh = atoi(argv[4]);

    fprintf(stderr, "n Scanning host=%s, protocol=%s, ports: %d -> %d   \n",
            host, pro, portlow, porthigh);

    if(strcmp(pro, protoc[0])==0)
        pro = protoc[0];
    else if (strcmp(pro, protoc[1])==0)
        pro = protoc[1];
    else
    {
        herror("n specify valid protocol - tcp or udpn");
        exit(-1);
    }


    if((he = gethostbyname(argv[1])) == NULL)
    {
        herror("n *** gethostbyname() failed ***n");
        exit(-1);
    }
    /*In case TCP protocol is selected for scan, app opens streaming socket

for every port to be scanned, tries to connect to it, and if successful

it displays information about service using struct servent.
*/

    if(strcmp(pro, protoc[0])==0) // tcp scan
    {
        for(port = portlow; port <= porthigh; port++)
        {
            // open stream socket
            if((sendfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
            {
                perror("*** socket(,SOCK_STREAM,) failed ***n");
                exit(-1);
            }
            set_nonblock(sendfd);
            bzero(&servaddr, sizeof(servaddr));

            servaddr.sin_family = AF_INET;
            servaddr.sin_port = htons(port);
            servaddr.sin_addr = *((struct in_addr *)he->h_addr);
            int res = connect(sendfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
int ser;
            if (res < 0) {
                 if (errno == EINPROGRESS) {
                    timeout.tv_sec = 0;
                    timeout.tv_usec = 10;
                    FD_SET(sendfd, &working_set);

                    if ((ser=select(sendfd+1, NULL, &working_set, NULL, &timeout)) > 0) {
                          srvport = getservbyport(htons(port), protoc[0]);

                    }
                    else {
                       fprintf(stderr, "Timeout or error() %d\n",ser);
                       perror("select(): ");

                    }
                 }
                 else {
                    fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
                 }
                 if(srvport != NULL)
                     printf("tport %d: %sn   \n ", port, srvport->s_name);
                 else if (ser=0)
                   close(sendfd);
                 fflush(stdout);
              }

            //set_block(sendfd);
        }//end of for()
    }
}

2 个答案:

答案 0 :(得分:5)

这是很多代码。我没有运行它。但是,这个:

if (ser=(select(sendfd, NULL, &working_set, NULL, &timeout)) > 0) {

错了。 select()的第一个参数是“三个集合中任意一个中编号最大的文件描述符加1”(参见man page)。

另外,你应该像这样括号:

if ((ser = select(...)) > 0) {

因为现在您要将>运算符的结果分配给ser变量,这可能不是您所期望的。

答案 1 :(得分:0)

在使用I / O描述符set_set之前,您需要确保清除它:

FD_ZERO(&working_set);