Lernprojekt - Nonblocking TCP Portscanner

Dieses Thema im Forum "C/C++" wurde erstellt von Greenleon, 07.03.2010.

  1. #1 Greenleon, 07.03.2010
    Greenleon

    Greenleon Tripel-As

    Dabei seit:
    08.01.2007
    Beiträge:
    184
    Zustimmungen:
    0
    Hallo,

    ich moechte meine C-Kenntnisse etwas vertiefen. Dazu moechte ich einen Portscanner schreiben, der versucht eine TCP-Verbindung zu einem Bestimmten Port einer Liste von Hosts aufzubauen und meldet ob der Port auf dem Rechner offen ist.

    In meiner Recherche bin ich ueber 3 Ansaetze gestolpert:
    1. Verbindung aufbauen; timeout || sucess; naechste Verbindung, etc.
    Das dauert natuerlich sehr lange, da 0 Parallelisierung

    2. Threads: Wie 1., nur dass das ganze in mehreren Threads parallelisiert wird.
    Machen wohl die meisten so. Ist aber mit ziemlich viel Ressourcen verbunden und soll auch nicht so effektiv sein.

    3. Die NMAP-Methode: Das ganze wird mit nichtblockenden Ports gemacht, die mit Select ueberwacht werden. Diese Methode moechte ich auch implementieren.

    Leider bin ich nicht auf wirklich brauchbaren Quelltext gestossen, an dem ich mich orientieren koennte, deswegen hab ich ein paar grundsaetzliche Fragen.

    Was ich bereits verstanden hab (glaube ich):
    - Ich gehe in einer Schleife die Liste der Zielrechner durch, erstelle jeweils einen socket(), connect()e diesen Socket im nonblocking Modus zum Zielrechner und fuege ihn dann in das fd_set fuer select() ein.

    Ist das soweit richtig?
    Was muss ich jetzt mit select anstellen?

    Gruss
    Leon
     
  2. Anzeige

    Schau dir mal diese Kategorie an. Dort findest du bestimmt etwas.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  3. #2 bytepool, 07.03.2010
    bytepool

    bytepool Code Monkey

    Dabei seit:
    12.07.2003
    Beiträge:
    791
    Zustimmungen:
    0
    Ort:
    /home/sweden/göteborg
    Hi,

    ich will dich nicht ueberzeugen was anderes zu machen, aber solltest du dir Variante 2 nochmal angucken wollen, dann schau dir mal OpenMP an (nicht zu verwechseln mit OpenMPI ;)). Ich war letztens hin und weg wie einfach sich damit Sachen parallelisieren lassen, ohne dass du deinen Code grossartig aendern musst. Natuerlich muss man einiges beachten, aber im grossen und ganzen ist der Aufwand wirklich minimal.

    Von wegen select, hattest du diesen Thread hier schon gesehen?
    http://www.unixboard.de/vb3/showthread.php?t=44172
    Vielleicht gibt das schon Anregungen?

    Was ist mit nmap selbst? Zu komplex? (Ich hab da selbst nie reingeguckt.)

    mfg,
    bytepool
     
  4. #3 Greenleon, 07.03.2010
    Zuletzt bearbeitet: 07.03.2010
    Greenleon

    Greenleon Tripel-As

    Dabei seit:
    08.01.2007
    Beiträge:
    184
    Zustimmungen:
    0
    Der nmap Code. Naja, bis ich da die passende Stelle gefunden hab, bin ich 50. Den Thread kannte ich noch nicht. Ich werds mir mal zu Gemuete fuehren.

    Nee Variante 2 wir hier stark kritisiert http://groups.google.de/group/de.or...&oe=UTF-8&q=dingler+portscanning&btnG=Google+.
    Ist auch nachvollziehbar die Kritik. Und sooo schwer kann das mit select() nicht sein.

    Hier mal, was ich heute geschafft hab:
    Code:
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <stdlib.h>
    #include <sys/select.h>
    
    #define DEBUG 1
    
    // error number
    extern int errno;
    
    const int MAX_SESSIONS = 255;
    unsigned long ip_list[MAX_SESSIONS];
    short ipc = 0;
    
    int main(int argc, char** argv)
    {
      return 1;
    }
    
    void scan()
    {
      const unsigned short scanp = 337;
      bool open_list[MAX_SESSIONS];
    
      // fds
      fd_set master;
      fd_set read_fds;
    
      int fdmax = 0;
    
      // address information
      struct sockaddr_in tsin;
    
      // timeout
      struct timeval to;
      int i, s;
    
      // clear fd sets
      FD_ZERO(&master);
    
      i = 0;
      do{
         // fill in connection information
         memset(&tsin,0,sizeof(struct sockaddr_in));
         tsin.sin_family = AF_INET;
         tsin.sin_port = htons(scanp);
         tsin.sin_addr.s_addr = ip_list[i]; // take an ip from the list
    
         // open a new socket
         if(s = socket(AF_INET,SOCK_STREAM,0)==-1)
    	fprintf(stderr,"Unable to open socket()! Errno: %i\n",errno);
    
         // set the socket to nonblocking-mode
         if(fcntl(s, F_SETFL, O_NONBLOCK)==-1)
            fprintf(stderr,"Unable to set socket to O_NONBLOCK! Errno: %i\n",errno);
    
         // TODO: set fdmax
    
         // connect
         if(connect(s,(struct sockaddr *) &tsin,sizeof(&tsin))==-1)
         {
            /*connect() returned with an error*/
    	if(errno == EINPROGRESS || errno == EALREADY)
    	   /*the errno indicates this socket can be monitored with select()*/
               FD_SET(s,master);
            else
    	   /*something went wrong*/
    	   fprintf(sterr,"Unable to connect()! Errno: %i\n",errno);
         }
         else
         {
    	/*connect() succeeded; remember and close() socket*/
    	open_list[i] = true;
    	if(close(s) == -1)
    	   fprintf(stderr,"Unable to close() socket! Errno: %i\n",errno);
         }
    
      }while(++i <= ipc)
    
      //TODO: select the list
    
    
      //TODO: print results
    }
    
    
    /* add an IP-address of the type "ccc.ccc.ccc.ccc" to the list */
    int addip(char* ip)
    {
       if(ipc >= MAX_SESSIONS)
          return 1;
    
       ip_list[ipc++] = inet_addr(ip);
       return 0;
    }
    
     
  5. #4 Greenleon, 27.05.2010
    Greenleon

    Greenleon Tripel-As

    Dabei seit:
    08.01.2007
    Beiträge:
    184
    Zustimmungen:
    0
    Soo eine erste Version laeuft :-).

    Code:
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <stdlib.h>
    #include <sys/select.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <string.h>
    
    #define DEBUG 1
    
    // error number
    extern int errno;
    
    #define MAX_SESSIONS 255
    unsigned long int ip_list[MAX_SESSIONS];
    int open_list[MAX_SESSIONS] = {0};
    int fd_list[MAX_SESSIONS] = {-1};
    
    short ipc = 0;
    
    char * ntoa(unsigned long);
    int add_ip(char*);
    void scan(const int, const unsigned long*, int*);
    
    int main(int argc, char** argv)
    {
     
      char * tip = malloc(16);
      int i;
    
      for(i=0;i<255;i++)
      {
         sprintf(tip,"192.168.0.%i",i);
         add_ip(tip);
      }
    
    
      scan(MAX_SESSIONS, ip_list, open_list);
    
      return 0;
    }
    
    void scan(const int num, const unsigned long* ip_list, int* open_list)
    {
      const unsigned short scanp = 337;
    
      // fds
      fd_set master;
      fd_set tfds;
      int fds[num];
    
      int fdmax = -1;
    
      // address information
      struct sockaddr_in tsin;
    
      // timeout
      struct timeval to;
    
      int i, sockfd, sret, scount;
    
      // clear fd sets
      FD_ZERO(&master);
    
      scount = 0;
    
      i = 0;
      do{
         // fill in connection information
         memset(&tsin,0,sizeof(tsin));
         tsin.sin_family = AF_INET;
         tsin.sin_port = htons(scanp);
         tsin.sin_addr.s_addr = ip_list[i]; // take an ip from the list
    
         // open a new socket
         if((sockfd = socket(AF_INET,SOCK_STREAM,0))==-1)
    	perror("Unable to open socket()!");
    
         // set the socket to nonblocking-mode
         if(fcntl(sockfd, F_SETFL, O_NONBLOCK)==-1)
            perror("Unable to set socket to O_NONBLOCK!");
    
         // connect
         if(connect(sockfd, (struct sockaddr *) &tsin, sizeof(tsin)) == -1)
         {
            /*connect() returned with an error*/
    	if(errno == EINPROGRESS || errno == EALREADY)
    	{
    
               #ifdef DEBUG
                  printf("DEBUG: Adding to select-list: socket %i\n",sockfd);
               #endif
    
    	   /*the errno indicates this socket can be monitored with select()*/
               FD_SET(sockfd,&master); // select the socket
               
               // set fdmax
               fdmax = (fdmax>sockfd ? fdmax : sockfd);
    	   scount++;
    	   fd_list[i] = sockfd;
            }
            else
    	   /*something went wrong*/
    	   perror("Unable to connect()!");
         }
         else
         {
    	/*connect() succeeded; remember and close() socket*/
    	open_list[i] = 1;
            printf("Port %i on host %s is open.\n",scanp,ip_list[i]);
    
    	if(close(sockfd) == -1)
    	   perror("Unable to close() socket!");
         }
    
      }while(++i < ipc);
    
      /* only select() if master contains at least one fd */
      if(fdmax >=0)
      /* the select() loop */
      while(scount>0)
      {
    
        #ifdef DEBUG
           printf("DEBUG: Setting timeout\n");
        #endif
    
        // set timeout. reset after every select, because select() may alter it
        to.tv_sec = 2;
        to.tv_usec = 0;
     
        // copy the fd_list
        tfds = master;
     
        #ifdef DEBUG
           printf("DEBUG: Selecting. fdmax %i; ipc %i\n",fdmax,ipc);
        #endif
    
        // select the list
        sret = select(fdmax+1,&tfds,NULL,NULL,&to);
        
    
        if(sret == -1)
        {
          perror("Unable to select()!");
          return;
        }else if(sret == 0)
        {
          // timed out... the remaining hosts are probably down
           #ifdef DEBUG
              printf("DEBUG: Select timed out. Finishing...\n",fdmax);
           #endif
          break;
        }else
        {
          // something changed
          #ifdef DEBUG
              printf("DEBUG: Select returned %i.\n",sret);
          #endif
    
          for(i=0;i<ipc;i++)
          {
            if(fd_list[i] > 0 && FD_ISSET(fd_list[i],&tfds))
            {
               /* got an answer. remove it from master and close socket. */
    
               printf("%s:%i is open.\n",ntoa(ip_list[i]),scanp);
               FD_CLR(fd_list[i],&master);
               scount--;
    
    	   if(close(fd_list[i]) == -1)
    	      perror("Unable to close() socket!");
            }
          }
        }
      }
    }
    
    
    
    /* add an IP-address of the type "ccc.ccc.ccc.ccc" to the list */
    int add_ip(char* ip)
    {
       if(ipc >= MAX_SESSIONS)
          return 1;
    
       ip_list[ipc++] = inet_addr(ip);
       return 0;
    }
    
    char * ntoa(unsigned long in)
    {
       struct sockaddr_in addr;
       memset(&addr,0,sizeof(addr));
       addr.sin_addr.s_addr = in;
       return inet_ntoa(addr.sin_addr);
    }
    
    Es wird ueberprueft, welche Hosts im Bereich 192.168.0.0-254 einen offenen Port 254 haben.

    Was sehr seltsam ist: Wenn ich das Timeout fuer Select auf >= 3 Sekunden setze werden alle Hosts gelistet, als ob alle einen offenen Port 337 haetten. Fuer to < 3s funktioniert alles korrekt. Hat jemand ne Idee, woran das liegen koennte?
     
  6. #5 faxe410, 27.05.2010
    faxe410

    faxe410 Grünschnabel

    Dabei seit:
    27.05.2010
    Beiträge:
    5
    Zustimmungen:
    0
    Wenn du das select timeout grösser als 3 Sekunden einstellst, dann ist es anscheinend größer als das connect timeout. In diesem Fall wird also das connect mit einem timeout abgeschlossen und das select meldet dir, dass der Filedescriptor nun wieder zum lesen (für schreiben und exception verwendest du ja NULL) verwendet werden kann. Der select lässt sich nicht darüber aus, ob der connect erfolgreich war.
    Das kannst du am einfachsten mit einem write von 0 bytes oder mit einem Aufruf von getpeername nach dem return von select feststellen. Ist der write von 0 bytes oder der Aufruf von getpeername erfolgreich, so hast du dich erfolgreich zu dem entsprechenden Port verbunden. Ansonsten war der connect nicht erfolgreich.

    LG,
    Faxe
     
  7. #6 Greenleon, 27.05.2010
    Greenleon

    Greenleon Tripel-As

    Dabei seit:
    08.01.2007
    Beiträge:
    184
    Zustimmungen:
    0
    Ah, danke! Klingt plausibel.
    Sollte aber nicht noetig sein. Nach 1 Sekunde muessten doch alle Verbindungen stehen, selbst bei hoher Latenz. Was meinst du?
     
  8. Anzeige

    Vielleicht findest du HIER Antworten.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  9. #7 faxe410, 27.05.2010
    faxe410

    faxe410 Grünschnabel

    Dabei seit:
    27.05.2010
    Beiträge:
    5
    Zustimmungen:
    0
    Für ein lokales Netzwerk sollte eine Sekunde ausreichen.
    Aber wie gesagt, eigentlich kann (bzw. darf?) man vom return von select nicht automatisch daraus schliessen, ob der connect erfolgreich war oder nicht (vielleicht gibt es andere Scenarios, in denen der connect nicht in ein timeout läuft sondern schon vorher darauf kommt, dass keine Verbindung möglich ist).

    LG,
    Faxe
     
  10. #8 Greenleon, 27.05.2010
    Greenleon

    Greenleon Tripel-As

    Dabei seit:
    08.01.2007
    Beiträge:
    184
    Zustimmungen:
    0
    So hier ist eine erste funktionierende Version. qt-GUI folgt ;)

    Code:
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <stdlib.h>
    #include <sys/select.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <string.h>
    
    #undef DEBUG 
    
    const int MAX_SESSIONS = 255;
    
    
    unsigned long int * ip_list;
    int * open_list;
    int * fd_list;
    const unsigned short scanp = 445;
    short ipc = 0;
    
    char * ntoa(unsigned long);
    int add_ip(char*);
    void scan(const int, const unsigned long*, int*);
    
    int main(int argc, char** argv)
    {
    
      ip_list = malloc(MAX_SESSIONS * sizeof(unsigned long int));
      open_list = malloc(MAX_SESSIONS * sizeof(int));
      fd_list = malloc(MAX_SESSIONS * sizeof(int));
    
      memset(open_list,0,MAX_SESSIONS * sizeof(int));
      memset(fd_list,-1,MAX_SESSIONS * sizeof(int));
    
      char * tip = malloc(16);
      int i;
    
      for(i=1;i<10;i++)
      {
         sprintf(tip,"192.168.0.%i",i);
         add_ip(tip);
      }
    
      scan(MAX_SESSIONS, ip_list, open_list);
    
      printf("scanned port %i on %i hosts\n",scanp,ipc);
      printf("%-15s\t%-10s\n","host","status");
      printf("----------------------\n");
      for(i=0;i<ipc;i++)
         printf("%-15s\t%-10s\n",ntoa(ip_list[i]), (open_list[i] ? "open" : "closed" ));
      
    
      return 0;
    }
    
    void scan(const int num, const unsigned long* ip_list, int* open_list)
    {
      char * buffer = "test";
      // fds
      fd_set master;
      fd_set tfds;
      int fds[num];
    
      int fdmax = -1;
    
      // address information
      struct sockaddr_in tsin;
    
      // timeout
      struct timeval to;
    
      int i, sockfd, sret, scount;
    
      // clear fd sets
      FD_ZERO(&master);
    
      scount = 0;
    
      i = 0;
      do{
         // fill in connection information
         memset(&tsin,0,sizeof(tsin));
         tsin.sin_family = AF_INET;
         tsin.sin_port = htons(scanp);
         tsin.sin_addr.s_addr = ip_list[i]; // take an ip from the list
    
         // open a new socket
         if((sockfd = socket(AF_INET,SOCK_STREAM,0))==-1)
         {
    	perror("Unable to open socket()!");
            continue;
         }
    
         // set the socket to nonblocking-mode
         if(fcntl(sockfd, F_SETFL, O_NONBLOCK)==-1)
         {
            perror("Unable to set socket to O_NONBLOCK!");
            continue;
         }
    
         // connect
         if(connect(sockfd, (struct sockaddr *) &tsin, sizeof(tsin)) == -1)
         {
            /*connect() returned with an error*/
    	if(errno == EINPROGRESS || errno == EALREADY)
    	{
    
               #ifdef DEBUG
                  printf("DEBUG: Adding to select-list: socket %i\n",sockfd);
               #endif
    
    	   /*the errno indicates this socket can be monitored with select()*/
               FD_SET(sockfd,&master); // select the socket
               
               // set fdmax
               fdmax = (fdmax>sockfd ? fdmax : sockfd);
    	   scount++;
    	   fd_list[i] = sockfd;
            }
            else
            {
               #ifdef DEBUG
                  printf("DEBUG: fd: %i ",sockfd);
               #endif
    
    	   /*something went wrong - close socket*/
    	   perror("Unable to connect()!");
    	
               if(close(sockfd) == -1)
    	      perror("Unable to close() socket!");
            }
         }
         else
         {
    	/*connect() succeeded; remember and close() socket*/
    	open_list[i] = 1;
    
    	if(close(sockfd) == -1)
    	   perror("Unable to close() socket!");
         }
    
      }while(++i < ipc);
    
      /* only select() if master contains at least one fd */
      /* the select() loop */
      while(scount>0)
      {
    
        #ifdef DEBUG
           printf("DEBUG: Setting timeout\n");
        #endif
    
        // set timeout. reset after every select, because select() may alter it
        to.tv_sec = 1;
        to.tv_usec = 0;
     
        // copy the fd_list
        tfds = master;
     
        #ifdef DEBUG
           printf("DEBUG: Selecting %i fds\n",scount);
        #endif
    
        // select the list
        sret = select(fdmax+1,NULL,&tfds,NULL,&to);
        
    
        if(sret == -1)
        {
          perror("Unable to select()!");
          return;
        }else if(sret == 0)
        {
          // timed out... the remaining hosts are probably down
           #ifdef DEBUG
              printf("DEBUG: Select timed out. Finishing...\n",fdmax);
           #endif
          break;
        }else
        {
          // something changed
          #ifdef DEBUG
              printf("DEBUG: Select returned %i.\n",sret);
          #endif
    
          for(i=0;i<ipc;i++)
          {
            if(fd_list[i] > 0 && FD_ISSET(fd_list[i],&tfds))
            {
               /* the state of this fd changed. Try to write 0 bytes now */
               if(write(fd_list[i],buffer,0) >= 0)
                  open_list[i] = 1;
               #ifdef DEBUG
               else
               {
                  printf("DEBUG: %s:%i is closed.\n",ntoa(ip_list[i]),scanp);
                  perror("DEBUG: Unable to write()");
               }
               #endif
               
               // remove fd from the masterlist dec scount and close sock
               FD_CLR(fd_list[i],&master);
               scount--;
    	   if(close(fd_list[i]) == -1)
    	      perror("Unable to close() socket!");
            }
          }
        }
      }
    }
    
    
    
    /* add an IP-address of the type "ccc.ccc.ccc.ccc" to the list */
    int add_ip(char* ip)
    {
       if(ipc >= MAX_SESSIONS)
          return 1;
    
       ip_list[ipc++] = inet_addr(ip);
       return 0;
    }
    
    char * ntoa(unsigned long in)
    {
       struct sockaddr_in addr;
       memset(&addr,0,sizeof(addr));
       addr.sin_addr.s_addr = in;
       return inet_ntoa(addr.sin_addr);
    }
    
     
Thema:

Lernprojekt - Nonblocking TCP Portscanner

Die Seite wird geladen...

Lernprojekt - Nonblocking TCP Portscanner - Ähnliche Themen

  1. Libre Music Production als Lernprojekt aufgelegt

    Libre Music Production als Lernprojekt aufgelegt: Das neue Projekt Libre Music Production und die dazugehörige Webseite möchten Musikproduktion mit freier Software in allen Facetten verständlich...
  2. Lernprojekt Gnome University startet

    Lernprojekt Gnome University startet: Gnome University ist ein Projekt, um die Menschen, die zu Gnome beitragen und solche, die sich zukünftig gerne einbringen möchten, zu schulen....