0

特定のIPで開いているすべてのポートをスキャンし、開いているポートとその上で実行されているサービスの名前のみを返すTCPポートスキャナーがあります。これを行うには、ソケットを作成し、非ブロッキング モードに設定します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()は、「3 つのセットのいずれかで最も大きい番号のファイル記述子に 1 を加えた値」です ( man ページを参照)。

また、次のように括弧で囲む必要があります。

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

>演算子の結果をser変数に代入しているため、これはおそらく期待したものではありません。

于 2013-01-15T10:44:09.230 に答える
0

Before using the I/O descriptor set, working_set, you need to make sure that you clear it:

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