C# TcpClient Problem bei Portscanner

Hallo Community. Bin neu hier und hab auch direkt mal ne Frage.
Vorab:

Hab die Suchfunktion benutzt und nichts gefunden. Bei Google habe ich auf das Problem nur unzureichende Lösungen gefunden. Denkte das geht besser:wink:

Jetzt zu meinem Problem. Für eine Hausaufgabe im Fach Kommunikationstechnik bin ich dabei einen TCP Portscanner in C# zu schreiben. IDE: VS2015 OS: Win10

Der Portscanner soll von einer IPv4 Startadresse ausgehend alle online Hosts bis zur Endadresse mittels Ping ausfindig machen und bei allen online Hosts einen Portscan ausführen. Später soll die CScanner Klasse auch in größere Programme eingebaut werden können um Scans automatisch ausführen zu können.

Jetzt zum Problem:
Aus irgendeinem Grund dauern die Portscans immer ewig. Bei offenen Ports ist es kein Problem aber bei geschlossenen Ports hängt sich das Programm immer für einige Sekunden auf bis es auf den nächsten springt.

ich habe schon:

tcpClient.NoDelay = true;
tcpClient.ReceiveTimeout = 50;
tcpClient.SendTimeout = 50;

Google hat mich nur auf Threading verwiesen. Finde ich allerdings ne unelegante Lösung. Vielleicht habe ich irgendwas übersehen oder es gibt eine simple Lösung die mir bisher nicht aufgefallen ist? Wäre dankbar für Hilfe:):):):)

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.NetworkInformation;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace teststt
{
    class CScanner
    {
        private const int MAX = 255;                //Höchste, mit einem Byte darstellbare Zahl
        private byte[] _sIP, _eIP;                  //Byte-Arrays für Start und End IP-Adresse
        bool[] status;                              //Status Array um verschachtelten Schleifenablauf lückenlos zu garantieren
        private string[] _result;                   //String Array für die Resultate der Verbindungstests
        private TcpClient tcpClient;                //TCPClient
        private Ping ping;                          //Ping
        private PingReply pingReply;                //PingReply
        private int vStartPort, vEndPort;           //Erster und letzter zu scannender Port. 
        private bool trigger;                       //Schleifentrigger
        private int counter;                        //Zeilencounter
        private string vCurrentIP;                  //Schleifengenerierte IP Adresse

        public CScanner(IPAddress startIP, IPAddress endIP, int startPort, int endPort)
        {
            _sIP = startIP.GetAddressBytes();
            _eIP = endIP.GetAddressBytes();
            vStartPort = startPort;
            vEndPort = endPort;
            _result = new string[1000];
            counter = 0;
            trigger = false;
            status = new bool[3] { true, true, true };
        }

        public void Scan()
        {
            for (int i = _sIP[0]; trigger != true; i++)
            {
                for (int j = 0; trigger != true && j <= MAX; j++)
                {
                    if (status[0]) j = _sIP[1];
                    //Schleife auf 3. unterster Ebene durchlaufen => Zähler bei 0 anfangen
                    status[0] = false;

                    for (int k = 0; trigger != true && j <= MAX; k++)
                    {
                        if (status[1]) k = _sIP[2];
                        //Schleife auf 2. unterster Ebene durchlaufen => Zähler bei 0 anfangen
                        status[1] = false;

                        for (int l = 0; trigger != true && j <= MAX; l++)
                        {
                            if (status[2]) l = _sIP[3];
                            //Schleife auf unterster Ebene durchlaufen => Zähler bei 0 anfangen
                            status[2] = false;

                            vCurrentIP = Convert.ToString(i) + "." + Convert.ToString(j) + "." + Convert.ToString(k) + "." + Convert.ToString(l);
                            ping = new Ping();

                            try
                            {
                                pingReply = ping.Send(vCurrentIP);
                                if (pingReply.Status == IPStatus.Success)
                                {
                                    Console.WriteLine( vCurrentIP + ": online");
                                    _result[counter] = "[*] " + vCurrentIP + " | Status: online";
                                    counter++;

                                    for (int vCurrentPort = vStartPort; vCurrentPort <= vEndPort; vCurrentPort++)
                                    {
                                        tcpClient = new TcpClient();tcpClient.NoDelay = true;
                                        tcpClient.ReceiveTimeout = 50;
                                        tcpClient.SendTimeout = 50;
                                        try
                                        {
                                            tcpClient.Connect(vCurrentIP, vCurrentPort);
                                            tcpClient.Close();
                                            Console.WriteLine("Port: " + vCurrentIP + ": open");
                                            _result[counter] = "[*] Port " + vCurrentPort + " Status: open";
                                            counter++;
                                        }
                                        
                                        catch
                                        {
                                            tcpClient.Close();
                                            Console.WriteLine("Port: " + vCurrentPort + ": closed");
                                            _result[counter] = "[*] Port " + vCurrentPort + " Status: closed";
                                            counter++;
                                        }
                                    }
                                }
                                else
                                {
                                    Console.WriteLine(vCurrentIP + ": offline");
                                    _result[counter] = vCurrentIP + " Status: offline";
                                    counter++;
                                }
                            }

                            catch
                            {
                                Console.WriteLine(vCurrentIP + ": offline");
                                _result[counter] = vCurrentIP + " Status: offline";
                                counter++;
                            }

                            //End IP Adresse erreicht. Schleife beenden
                            if (i == _eIP[0] && j == _eIP[1] && k == _eIP[2] && l == _eIP[3]) trigger = true;
                        }
                    }
                }
            }

            File.WriteAllLines(@"C:\result.txt", _result);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            string startIP = "192.168.2.105";
            string endIP = "192.168.2.112";

            IPAddress sIP = IPAddress.Parse(startIP);
            IPAddress eIP = IPAddress.Parse(endIP);

            CScanner s = new CScanner(sIP, eIP, 75, 85);
            s.Scan();
        }
    }
}
 
Hi, im Zweifel einfach mal Wireshark anschmeißen und gucken was passiert. Dabei hilft es etwas Ahnung vom Aufbau des TCP-Protokolls zu haben, insbesondere was den Verbindungsaufbau angeht.
Wikipedia hat gesagt.:
Der Server (siehe Skizze) empfängt das Paket. Ist der Port geschlossen, antwortet er mit einem TCP-RST, um zu signalisieren, dass keine Verbindung aufgebaut werden kann. Ist der Port geöffnet, bestätigt er den Erhalt des ersten SYN-Pakets und stimmt dem Verbindungsaufbau zu, indem er ein SYN/ACK-Paket zurückschickt (ACK von engl. acknowledgement ‚Bestätigung‘).

Interessant für dich könnte auch PCap sein, damit kannst du den Netzwerkkram auf einer tieferen Ebene angehen:
Pcap.Net * GitHub
Pcap.Net - Home
c# - Creating a valid TCP connection in Pcap.NET - Stack Overflow
Grüße
 
Nicht jeder Server sendet bei einem geschlossenen Port auch ein REJECT (TCP-RST). Um Portscans zu erschweren, werden bei geschlossenen Ports die Pakete zumeist einfach verworfen (DROP). Dein Scanner wartet daher bis zu seinem definierten Timeout auf die Antwort des Servers bevor er zum nächsten Port weiter geht. Entweder definierst du also ein kürzeres Timeout oder du parallelisierst die Scans der einzelnen Ports indem du sie in Threads auslagerst. Die Ergebnisse der einzelnen Threads sammelst du dann zentral ein und wertest sie aus.
 
tcpClient.ReceiveTimeout = 50;

Dieser Timeout bezieht sich auf einen Timeout BEIM empfangen.
D.h. dieser Client Wert wird automatisch relevant, wenn der Client bereits etwas empfangen hat. Das ist hilfreich, da du sonst bei einem fehlenden RST bis in alle Ewigkeit warten müsstest. Diese Option tut nicht das, was du erwartest.

Das was du willst wird idR. vom Stack selbst gehandhabt und ist eher ein Connection Timeout (und lässt sich selten konfigurieren). Für c# gibt es da die "BeginConnect" Methode, der du Zeit mitgeben kannst.

In deinem Fall solltest du so vorgehen: Wenn du eine Portrange scannen willst, benutze Threads und scanne die Range "gleichzeitig". Lege in in jedem Thread einn "counter" fest, den du abgreifst (ka wie genau man das in C# macht, in C wäre das zb SIGNAL). Oder probiere die BeginConnect Methode je Thread. Als Timeout zeit kommst du in einem LAN mit 2 Sekunden hin - in jedem Fall aber < 5 Sekunden.

Sammle alle Werte in einer globalen Struktur und werte sie aus, wenn der Scanvorgang komplett abgeschlossen ist.

PS: Sowas wie "File.WriteAllLines" gehört DA nicht hin ;)
 
Danke für die Antworten!

Werde mich mal an eine Lösung machen und gucken was am besten passt wobei ich denke das mit dem Threading ist warscheinlich das beste bei größeren Ranges...
Wenn ich was zufriedenstellendes hab stell ichs hier rein
Ciao thx ;)
 
Zurück
Oben