Ein paar Socks5 Experimente (Fortsetzung)
Bevor es an einen weiteren Artikel der MW2 Serie geht, möchte ich zunächst etwas weiter auf Socks5 eingehen. Das finale Ziel wird es sein, ein Reverse Socks5 Programm zu schreiben, wie in Teil 1 der Socks5-Serie beschrieben.
An dieser Stelle ein herzliches Dankeschön an den User Krusty, welcher mir in diversen Nachrichten immer mit Rat und Denkanstößen zur Seite stand Von ihm kam auch der Verweis auf die weiter unten besprochene Socks5 Klasse.
Das Programm in Teil 1 bestand aus nicht mehr als der Socks5 Anmeldefunktion und einem Datenaustausch (Eine Seite laden -> Eine Seite zurückliefern). So mochte der Proxy-Check von Proxifier das zwar das als Socks5 ansehen, doch mehr auch nicht. So hat das Programm Multithreading und eine hilfreiche UI bekommen:
Doch bevor ich weiter auf das Programm eingehe, werde ich erst ein “Negativbeispiel” aufzeigen, welches (o Wunder) so ziemlich alle Socks5 Szene-Programme verwenden. Es geht um dieses Tutorial. Aus diesem Source sind alle der Socks5-Klassen entstanden, zu finden unter Free-Hack, VB-Community oder in dem VicSocksMaker von Cardmarket. Doch ich würde nicht von einem Negativbeispiel reden, wenn es nicht ein paar Sachen dabei zu bemängeln gäbe Dabei geht es mir vor allem um diesen Codeabschnitt:
while (serverClient.Connected && socksClient.Connected && !ioError ) { System.Threading.Thread.Sleep(100); try { if (socksClientStream.DataAvailable) { byte[] readbuffer = new byte[10000]; int count_read = socksClientStream.Read(readbuffer, 0, 10000); byte[] read_data = new byte[count_read]; Array.Copy(readbuffer, read_data, count_read); serverClientStream.Write(read_data, 0, read_data.Length); Console.WriteLine("writing " + read_data.Length.ToString() + " to target"); } if (serverClientStream.DataAvailable) { byte[] receivebuffer = new byte[10000]; int count_receive = serverClientStream.Read(receivebuffer, 0, 10000); byte[] receive_data = new byte[count_receive]; Array.Copy(receivebuffer, receive_data, count_receive); socksClientStream.Write(receive_data, 0, receive_data.Length); Console.WriteLine("writing " + receive_data.Length.ToString() + " to socks initiator"); } } catch { ioError = true; } } |
- Es wird Threading.Sleep(100) verwendet. Der Autor schreibt dazu: “Mit der methode ‘System.Threading.Thread.Sleep(100);’ schenken wir anderen Applikationen Rechenzeit, damit Sie nicht durch die sockets des Proxies ‘geblockt werden‘.”, was also (glaube ich
) bedeuten sollte, dass das Netzwerk nicht durch die Schleife überlastet und somit blockiert wird. Effektiv ist das nicht! Dazu habe ich mir ein kleines Rechenbeispiel einfallen lassen: Ein Youtubevideo hat ca. 40 Megabyte, was 41943040 Bytes entspricht. Der Buffer ist 10000 Byte groß, also brauchen wir 4194 (im optimalen Fall) Schleifendurchläufe bis das Video geladen ist. Das sind 4194 * 0.1 Sekunden = 419,4 Sekunden zusätzliche Ladezeit des Videos. Also relativ ineffektiv
- Es wird für jeden Client einen neuen Thread erstellt. Wenn man bei Sites wie Facebook mit 4 verschiedenen IPs kommuniziert, so wird die Threadanzahl ziemlich hoch mit der Zeit. Diese Threads werden zudem die ganze Zeit aufrecht erhalten. In meiner Version werden zwar auch Threads verwendet, welche aber nur dann aktiv werden wenn sie gebraucht werden (Asynchrone Events).
Na klar kann man sagen dass das “Kleinigkeiten” sind, aber will man es nicht immer ein bisschen besser machen als all die anderen?
Mit diesem Ziel bin ich also an das Projekt gegangen. Am Aufbau hat sich nichts verändert, es gibt einen TCPListener welcher einfach einen neuen Thread mit der Handlefunktion startet. Sobald der Handshake abgeschlossen ist, wird der Hauptthread beendet und folgender Code spielt sich ab:
private void HandleIncommingData() { SetupSocketIn(); SetupSocketOut(); } |
Wie man sieht werden nur 2 Funktionen aufgerufen. Und diese Funktionen regeln ab jetzt die ganze Weiterleitungsgeschichte:
private void SetupSocketIn() { SocketsData SocketsDataIn = new SocketsData(); SocketsDataIn.InSocket = this.InSocket; SocketsDataIn.OutSocket = this.ForwardSocket; // Wir sagen dem InSocket: // Höre auf Data und springe die Funktion OnRecievedDataIn wenn was da ist. // Und fülle dabei die übergebne Struktur SocketsDataIn InSocket.BeginReceive(SocketsDataIn.BufRecvInSocket, 0, SocketsData.BufferSize, SocketFlags.None, OnRecievedDataIn, SocketsDataIn); } private void SetupSocketOut() { SocketsData SocketsDataOut = new SocketsData(); SocketsDataOut.InSocket = this.InSocket; SocketsDataOut.OutSocket = this.ForwardSocket; ForwardSocket.BeginReceive(SocketsDataOut.BufRecvOutSocket, 0, SocketsData.BufferSize, SocketFlags.None, OnRecievedDataOut, SocketsDataOut); } |
Zwei mal ziemlich das selbe. Wir erstellen erst eine Instanz einer SocketsData Klasse, in welcher u.a. zwei Sockets (In und Out) und ein Byte-Buffer enthalten sind. Diese Inztanz wird an die asynchrone Funktion “BeginRecieve” übergeben, welche OnRecieveX aufruft wenn Daten ankommen. Und genau da wird sofort am Quellcode weitergemacht:
private void OnRecievedDataIn(IAsyncResult ar) { try { // Die SocketsData wieder zurückcasten // Sie ist nun gefüllt mit Werten, die empfangen wurden! SocketsData SocketStruct = (SocketsData)ar.AsyncState; // Wir lesen die Bytes aus die empfangen wurden int nBytesRec = SocketStruct.InSocket.EndReceive(ar); if (nBytesRec < 0) { // Wenn Daten dasind, so werden diese asynchron versendet. // Dabei wird der Buffer mit den Daten (BufRecvInSocket) // und die Anzahl übergeben SocketStruct.OutSocket.BeginSend(SocketStruct.BufRecvInSocket, 0, nBytesRec, SocketFlags.None, OnSendDataOut, SocketStruct); // Für die UI Ausgabe this.iTotalBytesIn += nBytesRec; ServerManager.ParseIncommingSock5Struct(new Socks5InfoStruct(this.FinalIP, this.sHostname, this.iTotalBytesIn, this.iTotalBytesOut, false)); // Wieder die asynchrone Funktion zurücksetzen SetupSocketIn(); } else { Console.WriteLine("Client X, disconnected"); this.CloseSocketHandle(); } } catch { this.CloseSocketHandle(); } } |
Das selbe geschieht natürlich noch mit OnRecievedDataOut. So wird also jetzt jedesmal wenn etwas empfangen wird, dieses sofort in den anderen Socket geschrieben. So können auch mehrere Datenpakete gesendet werden, ohne dass erst auf ein Send bzw Recieve gewartet werden muss. Und Schleifen entfallen dadurch natürlich auch.
Den Source dieses Socks5-Servers stelle ich natürlich komplett zur Verfügung, mit dem Wissen dass er auch “missbraucht” werden kann um neue Ultra 1337 VicToSocks Programme zu schreiben, vorallem da die Klassenstruktur ja relativ Objektorientiert gehalten ist. Aber es gibt genügend andere Module die dieses besser leisten und auch ganze Programme, die ihren Job wesentlich stabiler verrichten sollten. Und da keine Authentifizierung in dem Protokoll implementiert wurde, werden C&P eh keinen Spass daran haben.
Download:Socks5 Server UI.zip
Grüße Easysurfer
Hallo Easy,
Nettes Tutorial. Schöne infos hast du da auf deinem Block. Werde das ganze versuchen in C++ nach zu coden.
Weiter so
MfG NEO_2.0
Hi,
dein VB-Community Link passt nicht mehr
die Domain vb-c.de gibt es nicht mehr
Gruß
Ice
Danke, habs gefixxed =)