/*
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!

Site: 		www.girex.altervista.org
*/

#include <iostream>
#include <winsock.h>
#include <cstdlib>
#include <cstring>
#include <ctime>
using namespace std;

void banner()
{
   cout << "Simply Win Port-Scanner v0.3 by __GiReX__\n\n";
   cout << "Opened ports list:\n\n";
}

void exit_clean(SOCKET *sock)
{
    closesocket(*sock);
    WSACleanup();
    exit(1);
}

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 come parametro
   }
        
  banner();  
  
  start_port = atoi(argv[2]);                                  // Range di porte
  end_port = atoi(argv[3]);                                    // come parametro
    
  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")) 
     {                         
         host = inet_addr(chost);                               
         
         if(host == INADDR_NONE) {                            
             cout << "Invalid IP format! Unable to resolve the host!\n";
             return 1; 
         } 
         
         else sock_addr->sin_addr.s_addr = host;                  
           
   }  else 
    {
         site = gethostbyname(chost);                       
           
         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";
}
