2016-05-22 10 views
2

Ich versuche, eine einfache port scanner in C zu machen, und bin endlich in der Endstufe. Ich schrieb eine einfache Funktion, um eine Verbindung zu einem Server an einem Port herzustellen, und sollte Timeout sein, wenn der Port geschlossen ist. Ich habe folgenden Testfall:Mit select() zum Zeitablauf einer Steckdose

#define _GNU_SOURCE 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <strings.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <netdb.h> 
#include <sys/time.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 

int main(int argc, char **argv) { 
    if(argc != 3) { 
     fprintf(stderr, "idiot.\n"); 
    } 

    int sock = socket(AF_INET, SOCK_STREAM, 0); 
    int flags = fcntl(sock, F_GETFL, 0); 

    flags |= O_NONBLOCK; 
    fcntl(sock, F_SETFL, flags); 

    if(sock < 0) { 
     perror("socket()"); 
    } 

    struct hostent *server = gethostbyname(argv[1]); 

    if (server == NULL) { 
     perror("gethostbyname()"); 
    } 

    struct sockaddr_in server_addr; 
    bzero((char*)&server_addr, sizeof(server_addr)); 
    server_addr.sin_family = AF_INET; 
    bcopy(server->h_addr, (char*)&server_addr.sin_addr.s_addr, server->h_length); 
    server_addr.sin_port = htons(atoi(argv[2])); 

    if(connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { 
     perror("connecting()"); 
    } 

    fd_set rfds; 
    struct timeval tv; 
    int retval; 

    FD_ZERO(&rfds); 
    FD_SET(sock, &rfds); 

    tv.tv_sec = 3; 
    tv.tv_usec = 0; 
    retval = select(sock+1, &rfds, NULL, NULL, &tv); 

    if (retval == -1) 
     perror("select()"); 
    else if (retval) 
     printf("port is open.\n"); 
    else 
     printf("port is closed.\n"); 
    return 0; 
} 

Das Problem ist, jeder Port, den ich es erteile, wird als offen gemeldet. Zum Beispiel:

[[email protected]:~/SpinCloud/Chevron] [devel]$ ./testcase localhost 22 # sshd actually runs on this machine, so its correct 
connecting(): Operation now in progress 
port is open. 
[[email protected]:~/SpinCloud/Chevron] [devel]$ telnet localhost 22 
Trying 127.0.0.1... 
Connected to localhost. 
Escape character is '^]'. 
SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.6 
^] 

telnet> quit 
Connection closed. 
[[email protected]:~/SpinCloud/Chevron] [devel]$ ./testcase localhost 80 # but no webserver 
connecting(): Operation now in progress 
port is open. 
[[email protected]:~/SpinCloud/Chevron] [devel]$ telnet localhost 80 
Trying 127.0.0.1... 
telnet: Unable to connect to remote host: Connection refused 
[[email protected]:~/SpinCloud/Chevron] [devel]$ 

Antwort

4

Die Tatsache, dass select Berichte etwas als „lesbar“ oder „beschreibbaren“ bedeutet nur, dass ein Versuch, read/write nicht blockieren. Es deutet nichts darauf hin, was das Ergebnis von diesem read/write sein wird.

Hinweis: Außerdem müssen Sie den Fall unterscheiden, wenn connectEINPROGRESS (und Abfrage für Schreibbarkeit in diesem Fall) von anderen Fehlern zurückgibt. (Obwohl vielleicht haben Sie TCP_KEEPCNT oder TCP_USER_TIMEOUT stattdessen verwenden könnte? Aber das würde nicht funktionieren, wenn Sie verwendet getaddrinfo wie Sie sind angeblich und versuchte alle der Adressen auf einmal potenziell, aber mit einer Verzögerung zwischen jedem)

Außerdem sollten Sie ernsthaft in Betracht ziehen, eine der neueren Alternativen zu verwenden, zumindest poll (das ist POSIX), wenn nicht etwas Systemspezifisches wie epoll oder kqueue ist.

2

Sie öffnen eine nicht blockierende Anfrage. Wenn Sie eine Verbindung() aufrufen, gibt es EINPROGRESS oder "Operation im Gange ist", wie in der manpage for connect() beschrieben:

  The socket is nonblocking and the connection cannot be 
      completed immediately. It is possible to select(2) or poll(2) 
      for completion by selecting the socket for writing. After 
      select(2) indicates writability, use getsockopt(2) to read the 
      SO_ERROR option at level SOL_SOCKET to determine whether 
      connect() completed successfully (SO_ERROR is zero) or 
      unsuccessfully (SO_ERROR is one of the usual error codes 
      listed here, explaining the reason for the failure). 

Sie sollten den errno Wert auf connect werden überprüft(). Eine nicht negative select Rückgabe bedeutet außerdem nicht, dass der Port auf dem Server, den Sie testen, geöffnet ist.

Nebenbei ist der Code, den Sie geschrieben haben, im Allgemeinen Fehler nicht gut behandeln. Von der ersten if(argc != 3) { werden Sie nicht zurückgeben, sondern nur eine Nachricht drucken. Wenn Sie Ihren Code ohne drei Eingaben ausführen würden, würde dies den Fehler anzeigen, aber dann die Ausführung fortsetzen (was wahrscheinlich zu einem Seg-Fehler führen würde).

Ich würde Sie ermutigen, mehr Zeit für die Untersuchung von synchronen vs asynchronen I/O und tatsächlich verbinden mit Ports bevor sie offen sind.

+0

notiert. Haben Sie empfohlene Literaturquellen? – DTSCode

+0

@DTSCode Das Lesen aller Manpages ist ein guter Anfang, da gibt es eine Menge. – o11c

Verwandte Themen