2017-08-15 5 views
0

J'ai donc développé un scanner de port pour C sur windows mais j'ai remarqué sur certaines IP qu'il fonctionne très lentement. Voici mon code pour elle:Speedup Windows C Port Scanner

DWORD WINAPI connectPortW(LPVOID lpParam) 
{ 
    HANDLE hStdout; 
    PMYDATA pDataArray; 

    WSADATA firstsock; 
    SOCKET s; 
    struct sockaddr_in sa; 
    int err; 

    char * openPorts = (char *)malloc(sizeof(char)*256); 
    memset(&openPorts[0], 0, strlen(openPorts)); 

    hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
    if(hStdout == INVALID_HANDLE_VALUE) 
    { 
     return 1; 
    } 

    pDataArray = (PMYDATA)lpParam; 

    strncpy((char *)&sa,"",sizeof sa); 
    sa.sin_family = AF_INET; 

    if (WSAStartup(MAKEWORD(2,0),&firstsock) != 0) 
    { 
     fprintf(stderr,"WSAStartup() failed"); 
     exit(1); 
    } 

    sa.sin_addr.s_addr = inet_addr(pDataArray->ip); 

    s = socket(AF_INET, SOCK_STREAM, 0); //make net a valid socket handle 
    if(s < 0) 
    { 
     perror("\nSocket creation failed"); // perror function prints an error message to stderr 
     exit(1); 
    } 

    sa.sin_port = htons(pDataArray->port); 
    err = connect(s, (struct sockaddr *)&sa, sizeof sa); 

    //connection not accepted 
    if(err == SOCKET_ERROR) 
    { 
     printf("%s %-5d Winsock Error Code : %d\n", pDataArray->ip, pDataArray->port, WSAGetLastError()); 
     strcpy("NULL", openPorts); 
     fflush(stdout); 
    } 
    //connection accepted 
    else 
    { 
     printf("%s %-5d accepted   \n", pDataArray->ip, pDataArray->port); 
     sprintf(openPorts, "%i,", pDataArray->port); 
     if(shutdown(s, SD_BOTH) == SOCKET_ERROR) 
     { 
      perror("\nshutdown"); 
      exit(1); 
     } 
    } 
    closesocket(s); 

    fflush(stdout); 

    strcpy(pDataArray->openPorts, openPorts); 

    free(openPorts); 

    return 0; 
} 

Gardez à l'esprit que je l'utilise déjà des fils et chaque thread appelle cette fonction pour un autre port (0-1024) sur la même adresse IP.

Alors, comment puis-je accélérer cela? Je continue de voir des gens parler de non-blocage, est-ce que cela accélérerait le processus et si oui, comment puis-je l'appliquer? Merci!

Edit: Il prend 614 secondes (10 minutes) pour numériser 0-1024 sur l'un des mentionné ci-dessus « lent »

de ip

Edit 2: Je commencé à essayer d'utiliser non bloquante ... Suis-je est-ce que c'est bien?

ioctlsocket(s, FIONBIO, &on); 
connect(s, (struct sockaddr *)&sa, sizeof sa); 
FD_ZERO(&fds); 
FD_SET(s, &fds); 

err = select(s, &fds, &fds, &fds, &tv); 

if (err != SOCKET_ERROR && err != 0) 
{ 
    sprintf(openPorts + strlen(openPorts),"%i,", pDataArray->port); 
} 
closesocket(s); 

Édition 3: Il semble que cette nouvelle méthode me donne des résultats inexacts mais beaucoup plus rapidement. J'ai l'impression d'avoir des ports plus ouverts que les résultats de l'exécution de nmap sur la même adresse IP.

+3

Savez-vous ce que vos goulots d'étranglement sont? L'avez-vous profilé? –

+0

Non, je n'ai aucune idée de ce qui goute, comment pourrais-je essayer de comprendre ce qui goute? –

+0

en utilisant asynchrone io vous ne pouvez pas accélérer la réponse de certaines IP spécifiques. cela ne dépend pas du tout de votre code. mais en utilisant io asynchrone - vous pouvez rendre votre code beaucoup plus efficace et moins d'utilisation des ressources. 1024 discussions c'est un cauchemar. avec io asynchrone vous utilisez uniquement pool de threads avec nombre fixe de threads (habituel un thread par cœur) – RbMm

Répondre

1

Je vois beaucoup de problèmes avec votre code de fil:

  • il fuit la mémoire si une panne se produit.

  • Vous utilisez abusivement strlen() lorsque vous appelez memset() sur votre variable openports. Supprimez simplement le memset() et utilisez calloc() ou LocalAlloc(LMEM_ZEROINIT) au lieu d'attribuer openports. Ou, utilisez simplement la pile d'appel à la place, puisque la variable est petite: char openPorts[256] = {0}; Ou mieux, n'utilisez même pas une variable locale openports, écrivez simplement à pDataArray->openPorts directement quand vous avez un résultat disponible. Vous ne devriez pas utiliser exit() Utilisez return à la place.

  • il est techniquement illégal d'appeler WSAStartup()/WSACleanup() plusieurs fois, car WinSock est compté référence, mais il est préférable de les appeler qu'une seule fois au démarrage du programme/sortie, et non par fil. Mais, puisque vous appelez WSAStartup(), vous devez appeler WSACleanup() pour garder le nombre de références WinSock équilibré.

  • Qu'essayez-vous de faire avec strcpy("NULL", openPorts);? Vous écrivez en mémoire en lecture seule. Je pense que vous voulez dire strcpy(openPorts, "NULL"); à la place.

  • écrit à pDataArray->openPorts est pas thread-safe si plusieurs threads partagent un seul tampon (utilisation de , dans votre chaîne sprintf() implique peut-être le cas). Vous devez synchroniser l'accès au tampon lorsque vous écrivez sur plusieurs threads. vous pouvez utiliser une section critique ou un mutex à cette fin.

Cela étant dit, vous utilisez une prise de blocage, donc connect() va bloquer le fil jusqu'à ce que les temps WinSock en interne, ce qui peut prendre un certain temps sur les réseaux lents.Pour accélérer, changer la prise en mode non-bloquant à l'aide ioctrlsocket(FIONBIO), puis utilisez select() pour mettre en œuvre votre propre délai d'attente pour connect(), par exemple:

DWORD WINAPI connectPortW(LPVOID lpParam) 
{ 
    PMYDATA pDataArray = (PMYDATA) lpParam; 

    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
    if (hStdout == INVALID_HANDLE_VALUE) 
     return 1; 

    WSADATA wsa; 
    int err = WSAStartup(MAKEWORD(2,0), &wsa); 
    if (err != 0) 
    { 
     fprintf(stderr, "%s %d WSAStartup() failed, Error Code : %d\n", pDataArray->ip, pDataArray->port, err); 
     return 1; 
    } 

    SOCKET s = socket(AF_INET, SOCK_STREAM, 0); //make net a valid socket handle 
    if (s == INVALID_SOCKET) 
    { 
     fprintf(stderr, "%s %d Socket creation failed, Error Code : %d\n", pDataArray->ip, pDataArray->port, WSAGetLastError()); 
     WSACleanup(); 
     return 1; 
    } 

    u_long enabled = 1; 
    if (ioctlsocket(s, FIONBIO, &enabled) == SOCKET_ERROR) 
    { 
     fprintf(stderr, "%s %d Socket non-blocking mode failed, Error Code : %d\n", pDataArray->ip, pDataArray->port, WSAGetLastError()); 
     closesocket(s); 
     WSACleanup(); 
     return 1; 
    } 

    struct sockaddr_in sa = {0}; 
    sa.sin_family = AF_INET; 
    sa.sin_addr.s_addr = inet_addr(pDataArray->ip); 
    sa.sin_port = htons(pDataArray->port); 

    if (connect(s, (struct sockaddr *)&sa, sizeof sa) == SOCKET_ERROR) 
    { 
     err = WSAGetLastError(); 
     if (err != WSAEWOULDBLOCK) 
     { 
      fprintf(stderr, "%s %d Socket connect failed, Error Code : %d\n", pDataArray->ip, pDataArray->port, err); 
      closesocket(s); 
      WSACleanup(); 
      return 1; 
     } 

     fd_set wfd, efd; 

     FD_ZERO(s, &wfd); 
     FD_SET(s, &wfd); 

     FD_ZERO(s, &efd); 
     FD_SET(s, &efd)' 

     timeval timeout; 
     timeout.tv_sec = 5; 
     timeout.tv_usec = 0; 

     err = select(0, NULL, &wfd, &efd, &timeout); 
     if (err == SOCKET_ERROR) 
     { 
      fprintf(stderr, "%s %d Socket select failed, Error Code : %d\n", pDataArray->ip, pDataArray->port, WSAGetLastError()); 
      closesocket(s); 
      WSACleanup(); 
      return 1; 
     } 

     if (err == 0) 
     { 
      // connect timeout 
      closesocket(s); 
      WSACleanup(); 
      return 0; 
     } 

     if (FD_ISSET(s, &efd)) 
     { 
      err = 0; 
      getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&err, sizeof err); 
      closesocket(s); 
      WSACleanup(); 

      switch (err) 
      { 
       case WSAETIMEDOUT: // connect timeout 
       case WSAECONNREFUSED: // port closed 
        return 0; 
      } 

      fprintf(stderr, "%s %d Socket connect failed, Error Code : %d\n", pDataArray->ip, pDataArray->port, err); 
      return 1; 
     } 
    } 

    // connected! 
    printf("%s %d accepted\n", pDataArray->ip, pDataArray->port); 

    // note, this is not thread-safe! Need to sync access to openPorts... 
    sprintf(pDataArray->openPorts + strlen(pDataArray->openPorts), "%d,", pDataArray->port); 

    closesocket(s); 
    WSACleanup(); 
    return 0; 
} 
+0

Merci beaucoup! Votre exemple a aidé une tonne. Maintenant, si je veux raccourcir le délai, est-ce que je change timeout.tv_sec = 5 en quelque chose de moins comme 3 ou 2? –

+0

@JustinBraham: oui. [Lire la documentation] (https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms740560.aspx). –