0

我有一个 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()
    }
}
4

2 回答 2

5

这是相当多的代码。我没有运行它。然而,这:

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

是错的。的第一个参数select()是“三个集合中任何一个中编号最高的文件描述符,加 1”(参见手册页)。

此外,您应该像这样用括号括起来:

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

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

于 2013-01-15T10:44:09.230 回答
0

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

FD_ZERO(&working_set);
于 2013-01-22T22:46:05.397 回答