A
AngelDelivery
Guest
-------------------------------------------------------------
Vorwort
-------------------------------------------------------------
Hallo Habo,
anlässlich der Startseitenplatzierung des Tutorials-Bereichs, schmeisse ich mich mal in die Bresche und schreibe ein Tutorial. Leider waren 20.000 Zeichen nicht genug, deswegen oft der Verweis auf die Anhänge.
Ich habe euch einen socks5 proxyserver in c# geschrieben und möchte zeigen, wie es mit den Mitteln des frameworks, unter Anwendung der bestehenden Wekzeuge zu machen ist.
angeprochene (eher angekratzte) Themen diesen Artikels sind
- allgemeines Vorgehen zur Protokollimplementierung
- Das socks Protokoll an sich
- Verständnis von tcp connections
- Netzwerkfunktionen und thread-pooling mit c#
Voraussetzungen:
Kenntnis der Basistypen von c#, oder einfach Interesse.
Ich habe mich für die socks Implementierung (anstatt eines anderen Protokolls) entschieden, da sie mit wenig Aufwand tolle Ergebnisse liefert, außerdem ist socks im Zeitalter der Internetanonymisierung ein interessantes Thema für einige hier, wie ich denke.
Dieses how2 ist unabhängig von Betriebssystem und Entwicklungsumgebung (feel free to choose):
-linux + mono runtime
-windows + .net framework 2.0 oder höher
-visual studio, sharpdevelop oder mono develop
-------------------------------------------------------------
Was ist socks ?
-------------------------------------------------------------
Socks wurde entwickelt, um verschiedene Netzwerkprotokolle auf Transportschicht in socks zu tunneln. Dabei wird der Netzwerkdatenverkehr über einen socksproxy gebündelt,ja zentralisiert.
Wir bechränken uns in diesem Beispiel auf das tcp Protokoll.
normaler Lebenszyklus einer tcp Verbindung:
- ein tcp client initiiert eine tcp Verbindung zu einem tcp server, definiert durch die Zieladresse und den Zielport des servers.
- der tcp server nimmt die Verbindung an und indentifiziert diese Verbindung über die client ip-Adresse und den verwendeten client port. Der client port wird i.d.R. dynamisch vor dem Verbindungsaufbau, auf clientseite vergeben
- Der Datenverkehr eines Applicationlayer Protokolls, z.B. http, wird nun über diese Verbindung abgewickelt.
tcp Verbindung mit socks
Der socks proxy nimmt eine "man-in-the-middle Position" wenn man so will, zwischen dem tcp client und dem tcp server, ein.
- der client, fortan socksClient genannt, baut eine tcp-Verbindung (s.o.) zu einem socks proxy auf.
- der socksClient übermittelt nun die Informationen an den socksproxy, die dieser für einen Verbindungsaufbau zum eigentlichen Verbindungsziel benötigt, zentral Zieladresse und Zielport
- der socksproxy baut nun eine tcp Verbindung mit einem tcp-server, unter Verwendung der gerade erhaltenen Daten auf, und ist somit nun auch ein client, fortan serverClient genannt.
- Es bestehen nun zwei Verbindungen aus Sicht des socks Proxies, die Verbindung mit dem socksClient und die Verbindung mit dem tcp server über den serverClient. Der Datenverkehr eines höheren Protokolles findet nun zwischen dem socksClient und dem socks proxy statt und wird weitergeleitet über den serverClient an den tcp Server und vice versa.
Für den tcp-Server ist nun nur der serverClient des proxies sichtbar, den eigentlichen Verbindungsinitiator kennt nur der socksproxy, die Potentiale zur Anonymisierung liegen auf der Hand und finden verbreitet Anwendung, siehe tor, widecap/freecap, etc.
Weiterhin kann socks zu einer übersichtlichen Firewallregeldefinition nützlich sein. Hinter einer Firewall reicht es dem socksclient, eine Verbindung auf einen außenstehenden socksproxy eingehen zu dürfen, um die eigentlichen Verbindungen zum Endpunkt, durch den socksproxy außerhalb der Firewallrestriktionszone durchführen zu lassen.
-------------------------------------------------------------
Restriktionen dieses Beispiels
-------------------------------------------------------------
Es würde zu weit führen alle socks5 Optionen zu implementieren, vielleicht hat ja jemand Lust das Bsp. zu erweitern.
- wir bahandeln nur tcp Verbindungen
- wir setzten nur ausgehende Verbindungen um, socks5 erlaubt auch die Weiterleitung eingehender Verbindungen
- wir sind nicht kompatibel zu socks4
- wir unterstützen nur Verbindungen ohne Authentifizierung
- wir unterstützen keine ipv6 Anforderungen
-------------------------------------------------------------
Interpretieren der rfc Protokolldefinition
-------------------------------------------------------------
Um einen socksproxy zu programmieren benötigen wir zunächst die Informationen, wie wir die header zur Verbindungsweiterleitung interpretieren müssen.
Eine vollständige Beschreibung dessen findet sich immer im rfc, hier unter z.B.
Bitte vollständig lesen und auswändiglernen...
http://www.faqs.org/rfcs/rfc1928.html
..oder
Zusammenfassung (eigene Nummerierung):
Zitat rfc: The SOCKS service is conventionally located on TCP port 1080
rfc0: Der proxy lauscht auf port 1080
rfc1 - Authentifizierungsselektion
Der socks client sendet eine Struktur:
rfc1.1: Version (1 byte) - immer gleich 5
rfc1.2: Numbermethods (1 byte) - Die Anzahl der durch den socksClient unterstützten Authentifizierungsmethoden
rfc1.3: Methoden (jeweils 1 byte)
der server Antwortet:
rfc1.4: Version (1 byte)
rfc1.5: Selektierte Methode (1 byte) - immer 0, keine Auth. (siehe Restriktionen dieses Beispiels)
rfc2 - request
Der socks client sendet eine Struktur:
rfc2.1: Version (1 byte)
rfc2.2: Command (1 byte) - immer 1 (1 steht für connect, 2 wäre bind und würde eingehende Verbindungen an den socksClient leiten)
rfc2.3: reserved (1 byte)
rfc2.4: Addresstype (1 byte) - (1=ipv4address, 3=domainname, 4=ipv6address) wir unterstützen 1,2
rfc2.5: Destination-Address (variabel) - Bei ipv4-Adressen 4 bytes, bei domänennamen enthält das erste byte des destinationaddress Feldes die Länge des folgenden Domänennamens
rfc2.6: destination port (2 byte) - unsigned integer
rfc3 - reply
Der socksproxy sendet dem socksClient nach erfolgreichem Verbindungsaufbau eine Struktur:
rfc3.1: Version (1 byte)
rfc3.2: Replytype (1 byte) - wir unterstützen 1=success und 2=failure
rfc3.3: reserved (1 byte)
rfc3.4: addresstype (1 byte) - siehe rfc2.4
rfc3.5: server bound address (variable) - siehe rfc2.5
rfc3.6: server vound port (2 byte) - siehe rfc.2.6
-------------------------------------------------------------
Multithreading tcp server in c#
-------------------------------------------------------------
Unser socks5proxy soll beliebig viele Verbindungen von socks Clients entgegennehmen können. Der socks connect sowie das folgende tcp forwarding soll für alle Verbindungen parallel abgearbeitet werden, also multithreading.
Was wir dafür benötigen sind typen aus den namespaces System.Net.Sockets sowie System.Threading. Die namespaces sollten dem Programm als using Direktive im Kopf von program.cs (bzw. der Klassendatei, in der der Einstiegspunkt void main in das Programm deklariert ist ) hinzugefügt werden.
In der methode main deklarieren wir zunächst ein Objekt vom Typ TcpListener. Ein TcpListener abstrahiert die Funktionen eines typs socket um die Möglichkeit, tcp serversockets schlank abzubilden, sowie die erforderlichen Funktionen zum akzeptieren und entgegenehmen ankommender tcp-connection-requests, in userem Fall die Verbindungsanforderungen der socksClients, zu gewährleisten.
Im constructor des neuen Tcplistener kann der port, auf dem auf neue Verbindungen gelauscht werden soll, direkt mitgegeben werden. Wie rfc0 empfiehlt, wählen wir 1080.
Nach Aufruf der Methode Start, ist der TcpListener bereit um connections entgegenzunehmen. Die Methode AcceptTcpClient gibt ein objekt vom Typ TcpClient zurück, welches fortan an als lokale Repräsentation eines verbundenen clients zu verstehen ist.
Bereits in diesem Zutand können wir den tcp accept testen, indem Du Deinen Bowser auf die Nutzung dieses Programms einstellst.
Leider akzeptiert der Server jetzt beliebige clients, lässt durch die wiederholte Benutzung des Bezeichners client in der Endlosschleife aber alte connections immer wieder dem garbage-collector zum Opfer fallen.
Wir wollen für jeden angeschlossenen client eine eigene Socks5Session starten, die parallel zum Hauptprogramm, nun auf eigene Faust mit seinem jeweils angeschlossenen client weiterarbeitet.
Und was soll: 'client.Client.RemoteEndPoint.ToString()' ?
Naja der 'zweite' client ist das untergeordnete objekt vom Typ socket und ist auch client benannt. Weiterhin hat jeder socket einen member vom typ ipendpoint; dieser gilt als lokale Repräsentation des 'tcp-Gegenübers' und lässt sichtbare Daten des Gegenübers einsehen.
Wir implementieren den Rumpf unserer Klasse Socks5Session in einer weiteren code-Datei:
... und erweitern die main methode um die Nutzung dieser Klasse für jede eingehende Verbindung.
Ein Thread erwartet einen ThreadStart Parameter im Konstruktor, der widerum einen "Funktionszeiger" ein sog. delegate auf eine void Methode erwartet. Nach Aufruf der Methode Thread.Start wird die Funktion, auf die das delegate zeigt gestartet und läuft ab jetzt parallel zum Hauptprogramm.
Die socks4session, die nun läuft, hat alles was Sie dafür wissen muss, also den angeschlossenen client über seinen Konstruktor zu wissen bekommen.
Der multithreading tcp server ist nun fertig. Jetzt müssen wir das socks5 Protokoll in der Worker methode work der socks5session implementieren.
-------------------------------------------------------------
Interpretieren der Authentifizierungs- und Requestfelder
-------------------------------------------------------------
Wie man oben sieht, habe ich unserere Restriktionen aus der rfc Interpretation schonmal als member der Klasse untergebracht, deren Verwendung folgt später.
Interessanter ist die Verwendung des Typs NetworkStream. Wir ziehen einen aus dem tcpclient der sockssession heraus. Dieser kann verwendet werden um Daten in bestehende tcp Verbindung zu schreiben oder daraus zu lesen.
Die socks5session erwartet nun die Übergabe möglicher Authentifizierungsmehtoden des clients, die über den NetworkStream eingelesen werden.
Die methode read eines NetworkStream liest Daten aus einer connection und erwartet ein byte-array, worin die ankommenden Daten gespeichert werden, den offset (die Stelle) an der die Daten in dem array beginnend abgelegt zu werden, und die Länge der erwarteten Daten in bytes. Achtung, die methode read wartet solange, bis die gewünschte Anzahl bytes im Buffer unerer Netzwerkkarte angekommen ist, falls nicht ein Lesetimeout für das NetworkStream objekt festgelegt wurde.
Wir gehen davon aus, dass wir einen gültigen socksclient haben und verlassen uns mal drauf, dass genau diese Daten kommen.
Wir antworten nun unter Benutzung der methode write, die genauso wie read zu verwenden ist und teilen dem client mit, dass wir nur ohne Auth. arbeiten wollen.
Jetzt wirds interessant, der socksClient soll dem Sockproxy nun endlich sagen wohin er denn nun verbunden werden möchte.
Es wurde ja gesagt, ipv4 und dns-Namen werden unterstützt. Die string variable connection_target enthält nun das target, wenn es aus der Menge unterstützter Typen selektiert wurde, ansonsten enthält connection_target einen 'Leerstring'.
Neu ist die Zeile
IPAddress ip = new IPAddress(target_data);
Im namespace System.Net verbirgt sich der Typ ipaddress welcher eine Repräsentation einer ip Adresse ist, und entsprechende Eigenschaften und Konvertierungsmöglichkeiten von und in verschiedenste Darstellungsformen bietet. In o.g. Zeile wird eine ip-Adresse aus einem 4-stelligen Bytearray gelesen.
In der Protokollimplementierung ist immer wieder wichtig, wie Texte (hier dnsName), in einem binären Strom interpretiert werden sollen, also in welchem encoding sie stehen bzw. wie sie als string interpretiert werden sollen.
connection_target = Encoding.Default.GetString(target_data);
Die Klasse encoding aus der .net Klassenbibliothek bietet beliebige Möglichkeiten hierzu.
Jetzt muss noch der Zielport aus dem Datenstrom gelesen werden können. Danach weiß der proxy alles, um seinen, nun als member hinzugefügten TcpClient serverClient mit dem entgültige tcp server zu verbinden.
Was passiert da mit 'tmp_byteorder[0] = bintargetport[1]; ....'? Die Reihenfolge der bytes für numerische typen, wie hier usigned integer 16, in einem Netzwerkdatenstrom, sind oft in umgekehrter Reihenfolge abgelegt, als Sie, wie bekannt aus der Ablageform im Speicher vorliegen, erwaret werden. Deswegen habe ich Sie hier einmal manuell 'umgedreht', um den Zahlwert dann mit der Klasse Bitconverter standardmäßig aus einem byte array zu erstellen. Bei der Umkehrung der Reihenfolge spricht man oft von 'network octet order'.
-------------------------------------------------------------
Der reply part
-------------------------------------------------------------
Im folgenden part wird nach dem erfolgreichen connect, die 10 byte starke Antwort an den socks client gegeben. Ich habe hier jedes byte einzeln gesetzt, um es Zeile für Zeile übersichtlich darzustellen, und nochmal die Konvertierungsmöglichkeiten des typs ipaddress darzustellen. Also bitte nich als schlechten Stil fehlinterpretieren.
Schlussendlich kommt der relativ einfache Teil des Programm, der eigentliche tcp redirect. Solange beide clients, der socksClient und der serverClient verbunden sind, und auch kein unerwarteter Übertragungsfehler auftaucht, wird abwechselnd versucht aus dem einen und dem anderen Networkstream zu lesen und die Daten in den jeweils anderen Stream zu schreiben.
Mit der methode 'System.Threading.Thread.Sleep(100);' schenken wir anderen Applikationen Rechenzeit, damit Sie nicht durch die sockets des Proxies 'geblockt werden'.
die methode:
int count_read = socksClientStream.Read(readbuffer, 0, 10000);
liest max, 10000 bytes jedoch sonst nur soviel wie im Buffer ist, und gibt die Anzahl gelesener bytes zurück zurück. Man könnte sich bei der Auswahl rel. gut an die mtu seiner Datenpakete halten.
FAZIT:
Funktioniert das ganze eigentlich jetzt wirklich ? Ich denk ja, denn ich schreibe diesen Artikel auf habo über diesen socksproxy. Falls ihn jemand mal testet, gebt mir doch mal ne Rückmeldung. Ansonsten hoffe ich, es hat euch Spass gemacht und eure Kreativität angeregt.
ciao bin raus.
Vorwort
-------------------------------------------------------------
Hallo Habo,
anlässlich der Startseitenplatzierung des Tutorials-Bereichs, schmeisse ich mich mal in die Bresche und schreibe ein Tutorial. Leider waren 20.000 Zeichen nicht genug, deswegen oft der Verweis auf die Anhänge.
Ich habe euch einen socks5 proxyserver in c# geschrieben und möchte zeigen, wie es mit den Mitteln des frameworks, unter Anwendung der bestehenden Wekzeuge zu machen ist.
angeprochene (eher angekratzte) Themen diesen Artikels sind
- allgemeines Vorgehen zur Protokollimplementierung
- Das socks Protokoll an sich
- Verständnis von tcp connections
- Netzwerkfunktionen und thread-pooling mit c#
Voraussetzungen:
Kenntnis der Basistypen von c#, oder einfach Interesse.
Ich habe mich für die socks Implementierung (anstatt eines anderen Protokolls) entschieden, da sie mit wenig Aufwand tolle Ergebnisse liefert, außerdem ist socks im Zeitalter der Internetanonymisierung ein interessantes Thema für einige hier, wie ich denke.
Dieses how2 ist unabhängig von Betriebssystem und Entwicklungsumgebung (feel free to choose):
-linux + mono runtime
-windows + .net framework 2.0 oder höher
-visual studio, sharpdevelop oder mono develop
-------------------------------------------------------------
Was ist socks ?
-------------------------------------------------------------
Socks wurde entwickelt, um verschiedene Netzwerkprotokolle auf Transportschicht in socks zu tunneln. Dabei wird der Netzwerkdatenverkehr über einen socksproxy gebündelt,ja zentralisiert.
Wir bechränken uns in diesem Beispiel auf das tcp Protokoll.
normaler Lebenszyklus einer tcp Verbindung:
- ein tcp client initiiert eine tcp Verbindung zu einem tcp server, definiert durch die Zieladresse und den Zielport des servers.
- der tcp server nimmt die Verbindung an und indentifiziert diese Verbindung über die client ip-Adresse und den verwendeten client port. Der client port wird i.d.R. dynamisch vor dem Verbindungsaufbau, auf clientseite vergeben
- Der Datenverkehr eines Applicationlayer Protokolls, z.B. http, wird nun über diese Verbindung abgewickelt.
tcp Verbindung mit socks
Der socks proxy nimmt eine "man-in-the-middle Position" wenn man so will, zwischen dem tcp client und dem tcp server, ein.
- der client, fortan socksClient genannt, baut eine tcp-Verbindung (s.o.) zu einem socks proxy auf.
- der socksClient übermittelt nun die Informationen an den socksproxy, die dieser für einen Verbindungsaufbau zum eigentlichen Verbindungsziel benötigt, zentral Zieladresse und Zielport
- der socksproxy baut nun eine tcp Verbindung mit einem tcp-server, unter Verwendung der gerade erhaltenen Daten auf, und ist somit nun auch ein client, fortan serverClient genannt.
- Es bestehen nun zwei Verbindungen aus Sicht des socks Proxies, die Verbindung mit dem socksClient und die Verbindung mit dem tcp server über den serverClient. Der Datenverkehr eines höheren Protokolles findet nun zwischen dem socksClient und dem socks proxy statt und wird weitergeleitet über den serverClient an den tcp Server und vice versa.
Für den tcp-Server ist nun nur der serverClient des proxies sichtbar, den eigentlichen Verbindungsinitiator kennt nur der socksproxy, die Potentiale zur Anonymisierung liegen auf der Hand und finden verbreitet Anwendung, siehe tor, widecap/freecap, etc.
Weiterhin kann socks zu einer übersichtlichen Firewallregeldefinition nützlich sein. Hinter einer Firewall reicht es dem socksclient, eine Verbindung auf einen außenstehenden socksproxy eingehen zu dürfen, um die eigentlichen Verbindungen zum Endpunkt, durch den socksproxy außerhalb der Firewallrestriktionszone durchführen zu lassen.
-------------------------------------------------------------
Restriktionen dieses Beispiels
-------------------------------------------------------------
Es würde zu weit führen alle socks5 Optionen zu implementieren, vielleicht hat ja jemand Lust das Bsp. zu erweitern.
- wir bahandeln nur tcp Verbindungen
- wir setzten nur ausgehende Verbindungen um, socks5 erlaubt auch die Weiterleitung eingehender Verbindungen
- wir sind nicht kompatibel zu socks4
- wir unterstützen nur Verbindungen ohne Authentifizierung
- wir unterstützen keine ipv6 Anforderungen
-------------------------------------------------------------
Interpretieren der rfc Protokolldefinition
-------------------------------------------------------------
Um einen socksproxy zu programmieren benötigen wir zunächst die Informationen, wie wir die header zur Verbindungsweiterleitung interpretieren müssen.
Eine vollständige Beschreibung dessen findet sich immer im rfc, hier unter z.B.
Bitte vollständig lesen und auswändiglernen...
http://www.faqs.org/rfcs/rfc1928.html
..oder
Zusammenfassung (eigene Nummerierung):
Zitat rfc: The SOCKS service is conventionally located on TCP port 1080
rfc0: Der proxy lauscht auf port 1080
rfc1 - Authentifizierungsselektion
Der socks client sendet eine Struktur:
rfc1.1: Version (1 byte) - immer gleich 5
rfc1.2: Numbermethods (1 byte) - Die Anzahl der durch den socksClient unterstützten Authentifizierungsmethoden
rfc1.3: Methoden (jeweils 1 byte)
der server Antwortet:
rfc1.4: Version (1 byte)
rfc1.5: Selektierte Methode (1 byte) - immer 0, keine Auth. (siehe Restriktionen dieses Beispiels)
rfc2 - request
Der socks client sendet eine Struktur:
rfc2.1: Version (1 byte)
rfc2.2: Command (1 byte) - immer 1 (1 steht für connect, 2 wäre bind und würde eingehende Verbindungen an den socksClient leiten)
rfc2.3: reserved (1 byte)
rfc2.4: Addresstype (1 byte) - (1=ipv4address, 3=domainname, 4=ipv6address) wir unterstützen 1,2
rfc2.5: Destination-Address (variabel) - Bei ipv4-Adressen 4 bytes, bei domänennamen enthält das erste byte des destinationaddress Feldes die Länge des folgenden Domänennamens
rfc2.6: destination port (2 byte) - unsigned integer
rfc3 - reply
Der socksproxy sendet dem socksClient nach erfolgreichem Verbindungsaufbau eine Struktur:
rfc3.1: Version (1 byte)
rfc3.2: Replytype (1 byte) - wir unterstützen 1=success und 2=failure
rfc3.3: reserved (1 byte)
rfc3.4: addresstype (1 byte) - siehe rfc2.4
rfc3.5: server bound address (variable) - siehe rfc2.5
rfc3.6: server vound port (2 byte) - siehe rfc.2.6
-------------------------------------------------------------
Multithreading tcp server in c#
-------------------------------------------------------------
Unser socks5proxy soll beliebig viele Verbindungen von socks Clients entgegennehmen können. Der socks connect sowie das folgende tcp forwarding soll für alle Verbindungen parallel abgearbeitet werden, also multithreading.
Was wir dafür benötigen sind typen aus den namespaces System.Net.Sockets sowie System.Threading. Die namespaces sollten dem Programm als using Direktive im Kopf von program.cs (bzw. der Klassendatei, in der der Einstiegspunkt void main in das Programm deklariert ist ) hinzugefügt werden.
Code:
using System.Net.Sockets;
using System.Threading;
Im constructor des neuen Tcplistener kann der port, auf dem auf neue Verbindungen gelauscht werden soll, direkt mitgegeben werden. Wie rfc0 empfiehlt, wählen wir 1080.
Nach Aufruf der Methode Start, ist der TcpListener bereit um connections entgegenzunehmen. Die Methode AcceptTcpClient gibt ein objekt vom Typ TcpClient zurück, welches fortan an als lokale Repräsentation eines verbundenen clients zu verstehen ist.
Code:
TcpListener server = new TcpListener(1080);
server.Start();
while (true)
{
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("accepted new socks client at " +
client.Client.RemoteEndPoint.ToString());
}
Leider akzeptiert der Server jetzt beliebige clients, lässt durch die wiederholte Benutzung des Bezeichners client in der Endlosschleife aber alte connections immer wieder dem garbage-collector zum Opfer fallen.
Wir wollen für jeden angeschlossenen client eine eigene Socks5Session starten, die parallel zum Hauptprogramm, nun auf eigene Faust mit seinem jeweils angeschlossenen client weiterarbeitet.
Und was soll: 'client.Client.RemoteEndPoint.ToString()' ?
Naja der 'zweite' client ist das untergeordnete objekt vom Typ socket und ist auch client benannt. Weiterhin hat jeder socket einen member vom typ ipendpoint; dieser gilt als lokale Repräsentation des 'tcp-Gegenübers' und lässt sichtbare Daten des Gegenübers einsehen.
Wir implementieren den Rumpf unserer Klasse Socks5Session in einer weiteren code-Datei:
Code:
/* ***********************************************************************************************
* experimental sock5proxy implementation
* 2009 by AngelDelivery for www.hackerboard.de
*
* license: feel free to use this code free of charge,
* but do not publish this article without any reference to www.hackerboard.de and the author.
* warranty: this code comes without any warranty. It's your own risc.
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace Socks5Proxy
{
public class Socks5Session
{
TcpClient socksClient;
public Socks5Session(TcpClient client)
{
socksClient = client;
}
public void Work()
{
}
}
}
Code:
TcpListener server = new TcpListener(1080);
server.Start();
while (true)
{
TcpClient client = server.AcceptTcpClient();
Socks5Session S = new Socks5Session(client);
Thread T = new Thread(new ThreadStart(S.Work));
T.Start();
Console.WriteLine("accepted new socks client at " + client.Client.RemoteEndPoint.ToString());
}
Die socks4session, die nun läuft, hat alles was Sie dafür wissen muss, also den angeschlossenen client über seinen Konstruktor zu wissen bekommen.
Der multithreading tcp server ist nun fertig. Jetzt müssen wir das socks5 Protokoll in der Worker methode work der socks5session implementieren.
-------------------------------------------------------------
Interpretieren der Authentifizierungs- und Requestfelder
-------------------------------------------------------------
Code:
public class Socks5Session
{
TcpClient socksClient;
TcpClient serverClient;
byte SOCKS_VERSION = 5;
byte SOCKS_NOAUTH = 0;
byte SOCKS_REPLYSUCCESS = 0;
byte SOCKS_IPV4ADDR = 1;
byte SOCKS_DNSNAME =3;
public Socks5Session(TcpClient client)
{
socksClient = client;
}
public void Work()
{
Console.WriteLine(
"new client connected: " +
socksClient.Client.RemoteEndPoint.ToString());
NetworkStream socksClientStream = socksClient.GetStream();
..........
Interessanter ist die Verwendung des Typs NetworkStream. Wir ziehen einen aus dem tcpclient der sockssession heraus. Dieser kann verwendet werden um Daten in bestehende tcp Verbindung zu schreiben oder daraus zu lesen.
Die socks5session erwartet nun die Übergabe möglicher Authentifizierungsmehtoden des clients, die über den NetworkStream eingelesen werden.
Code:
/* *****************************************************
* supported methods part
* ***************************************************** */
code im Anhang
Wir gehen davon aus, dass wir einen gültigen socksclient haben und verlassen uns mal drauf, dass genau diese Daten kommen.
Wir antworten nun unter Benutzung der methode write, die genauso wie read zu verwenden ist und teilen dem client mit, dass wir nur ohne Auth. arbeiten wollen.
Code:
/* *****************************************************
* method selection part
* ***************************************************** */
code im Anhang
Code:
/* *****************************************************
* request part
* ***************************************************** */
code im Anhang
Neu ist die Zeile
IPAddress ip = new IPAddress(target_data);
Im namespace System.Net verbirgt sich der Typ ipaddress welcher eine Repräsentation einer ip Adresse ist, und entsprechende Eigenschaften und Konvertierungsmöglichkeiten von und in verschiedenste Darstellungsformen bietet. In o.g. Zeile wird eine ip-Adresse aus einem 4-stelligen Bytearray gelesen.
In der Protokollimplementierung ist immer wieder wichtig, wie Texte (hier dnsName), in einem binären Strom interpretiert werden sollen, also in welchem encoding sie stehen bzw. wie sie als string interpretiert werden sollen.
connection_target = Encoding.Default.GetString(target_data);
Die Klasse encoding aus der .net Klassenbibliothek bietet beliebige Möglichkeiten hierzu.
Jetzt muss noch der Zielport aus dem Datenstrom gelesen werden können. Danach weiß der proxy alles, um seinen, nun als member hinzugefügten TcpClient serverClient mit dem entgültige tcp server zu verbinden.
Code:
*****************************************************
* server client connection part
* ***************************************************** */
code im Anhang
-------------------------------------------------------------
Der reply part
-------------------------------------------------------------
Im folgenden part wird nach dem erfolgreichen connect, die 10 byte starke Antwort an den socks client gegeben. Ich habe hier jedes byte einzeln gesetzt, um es Zeile für Zeile übersichtlich darzustellen, und nochmal die Konvertierungsmöglichkeiten des typs ipaddress darzustellen. Also bitte nich als schlechten Stil fehlinterpretieren.
Code:
/* *****************************************************
* reply part
* ***************************************************** */
code im Anhang
Schlussendlich kommt der relativ einfache Teil des Programm, der eigentliche tcp redirect. Solange beide clients, der socksClient und der serverClient verbunden sind, und auch kein unerwarteter Übertragungsfehler auftaucht, wird abwechselnd versucht aus dem einen und dem anderen Networkstream zu lesen und die Daten in den jeweils anderen Stream zu schreiben.
Mit der methode 'System.Threading.Thread.Sleep(100);' schenken wir anderen Applikationen Rechenzeit, damit Sie nicht durch die sockets des Proxies 'geblockt werden'.
Code:
tcp redirection
code im Anhang
die methode:
int count_read = socksClientStream.Read(readbuffer, 0, 10000);
liest max, 10000 bytes jedoch sonst nur soviel wie im Buffer ist, und gibt die Anzahl gelesener bytes zurück zurück. Man könnte sich bei der Auswahl rel. gut an die mtu seiner Datenpakete halten.
FAZIT:
Funktioniert das ganze eigentlich jetzt wirklich ? Ich denk ja, denn ich schreibe diesen Artikel auf habo über diesen socksproxy. Falls ihn jemand mal testet, gebt mir doch mal ne Rückmeldung. Ansonsten hoffe ich, es hat euch Spass gemacht und eure Kreativität angeregt.
ciao bin raus.
Zuletzt bearbeitet: