/*
Simply Win Port-Scanner v0.3 
Autore:         __GiReX__
Linguaggio: 	C++
Descrizione: 	Windows Port-Scanner with timeout parameter

Changelog:      Aggiunta la possibilità di risolvere l'host
                E' quindi possibile passare al programma un DNS per lo scan!
*/

#include <iostream>
#include <winsock.h>
#include <cstdlib>
#include <cstring>
#include <ctime>
using namespace std;

bool scan(SOCKET *sock, sockaddr_in *sock_addr, u_int port, u_long *enabled, timeval *time);
int check_host(char *host, sockaddr_in *sock_addr);
int check_port(u_int start, u_int end);
void usage(char *prog);

int main(int argc, char *argv[])
{
 u_int start_port, end_port;   
  
 SOCKET sock;  
 WSADATA info;
 SOCKADDR_IN sock_addr;

 u_long enabled = 1;
 timeval timeout;
 
 bool noth = true;

 if(argc < 4) {
        usage(argv[0]);
        return 1;  
  }
  
    if(argc!=5) {
          timeout.tv_sec = 0;
          timeout.tv_usec = 500000;                             // 500 millisceondi di default
    } else {
          timeout.tv_sec = 0;
          timeout.tv_usec = atoi(argv[4])*1000;                 // Timeout da riga di comando
}
        
  cout << "Simply Win Port-Scanner v0.3 by __GiReX__\n\n"
       << "Opened ports list:\n\n";
    
   start_port = atoi(argv[2]);                                  // Range di porte
   end_port = atoi(argv[3]);                                    // da riga di comando
    
    if(check_port(start_port, end_port)) return 1;              // Controllo se il range di porte è valido
   
   
    WSAStartup(MAKEWORD(2, 2), &info);                          // Inizializzo la procedura per i socket
      sock_addr.sin_family = AF_INET;                           // Struttura sockaddr_in : Protocollo   
       if(check_host(argv[1], &sock_addr)) return 1;            // Controllo se l'input dell'host è regolare
      
     
    for(int i = start_port; i <= end_port; i++)
    {
      cout << "Scanning: " << i << "\r";
        sock = socket(AF_INET, SOCK_STREAM, 0); 
           if(scan(&sock, &sock_addr, i, &enabled, &timeout)) { // Se scan ritorna true la porta è aperta
               cout << "Scanning: " << i << "\t opened\n";
               noth = false;
        }
  }
     
      if(noth) cout << "No port seems is open\n";
      
     cout << "Scanning: //\tfinished\n\nElapsed time: " << clock() / CLOCKS_PER_SEC  << " s\n"; 
    
   closesocket(sock);                                           // Chiudo socket
  WSACleanup();                                                 // Pulisco e termino procedura socket
 return 0;
}

bool scan(SOCKET *sock, sockaddr_in *sock_addr, u_int port, u_long *enabled, timeval *timeout)
{
 FD_SET fds;
   
   sock_addr->sin_port = htons(port);                           // Setto la porta
     ioctlsocket(*sock, FIONBIO, enabled);                      // Abilito le socket non-blocking
     
     FD_ZERO(&fds);                                             // Pulisco il set                
     FD_SET(*sock, &fds);                                       // Aggiungo il socket al SET della select
     
     connect(*sock,(struct sockaddr*)sock_addr,sizeof(struct sockaddr)); // Ritorna sempre errore
            
   if(select(*sock, 0, &fds, 0, timeout)>0)  return true;       // Individuo il socket con la select
                                                                // Se ritorna 1 valore > 0 la porta è aperta
 return false;
} 

int check_host(char *chost, sockaddr_in *sock_addr) 
{
 u_long host;
 LPHOSTENT site;
    
    if(!strstr(chost, "www")) {                                 // Se non trovo www allora viene specificato un IP
         host = inet_addr(chost);                               
         
          if(host == INADDR_NONE) {                             // Se ritorna INADDR_NONE l'IP non è valido
              cout << "Invalid IP format! Unable to resolve the host!\n";
          return 1; 
     
      } else 
           sock_addr->sin_addr.s_addr = host;                   // Se invece trovo www si tratta di un DNS
           
   }  else {
           site = gethostbyname(chost);                         // Risolvo il DNS..
           
            if(!site)  {
                cout << "Invalid www address! Unable to resolve the host!\n";
            return 1;
    } else 
          sock_addr->sin_addr = *((LPIN_ADDR)*site->h_addr_list); }
          
 return 0;
}

int check_port(u_int start, u_int end)
{
    
    if(start > 65535 || start < 0 || end > 65535 || end < 0 || start > end) {
             cout << "Invalid port range! Re-insert it!\n";
             return 1;
     } 
  return 0; 

}       

void usage(char *prog)
{
     cout << "\nUsage: " << prog << " <ip/host> <porta_iniziale> <porta_finale> [time-out]\n\n"
             << "Example: scan.exe   www.google.com   1   100\n"
             << "         scan.exe   127.0.0.1        1   500 80\n\n"
             << "[time-out] is optional and must be expressed in milliseconds\n"
             << "default is 500 milliseconds, more is lower more the scan faster!\n";
}
