Diskussion: socks5-Proxyserver in c# im Forum Programmierung, in der Kategorie Tutorials; ------------------------------------------------------------- Vorwort ------------------------------------------------------------- Hallo Habo, anlässlich der Startseitenplatzierung des Tutorials-Bereichs, schmeisse ich mich mal in die Bresche und schreibe ein ...
![]() |
|
|
#1 (permalink) |
|
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. 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
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 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. Geändert von AngelDelivery (20.01.10 um 20:38 Uhr) |
|
|
|
#2 (permalink) |
|
Registriert seit: 18.01.10
![]() |
Sehr sehr sehr nices ding muss ich sagen!
Habs gestern schon ein bisschen getestet mit Proxyfier. Klappt echt gut. Nur ich bekomme damit keine verbindungen hergestellt. Also mit proxifier kann man ja socks5 testen. Bei einem Test verbindet er zu google.de:80. Das schlägt leider fehl. Könnte es vielleicht auch daran liegen dass ich den socks auf meinem pc aufgesetzt habe bzw hinter einem router sitze (und der port vllt nicht freigegeben ist)? Aber echt spitzen ding was du da gemacht hast! |
|
|
|
|
|
#3 (permalink) | |
|
Guest
|
Hi Heidi12
Dafür, dass es bei Dir nicht funktioniert, ganz schön viel Lob ![]() Danke, freut mich dass Du Dich damit bechäftigst Zitat:
Du hast 127.0.0.1:1080 bei proxyfier als Proxy hinterlegt ? und Du hat keine weiteren proxyfication Regeln hinterlegt ? Wenn Du diese 3 Fragen mit JA beantwortest, ist Folgendes passiert: - Der Browser verbindet sich mit google. - wird nun durch proxifier aber auf 127.0.0.1:1080 gezwungen - die Verbindung von 127.0.0.1 auf google wird auf 127.0.0.1:1080 gezwungen - dann: die Verbindung auf 127.0.0.1:1080 wird auf 127.0.0.1:1080 gezwungen ... Das ist eine Klasse Endlosschleife ![]() Ist das so? ansonsten: leite doch mal bitte den stdout meines proxies in eine Datei um und poste Sie mal. Vielen lieben Dank für diesen Fall. Es funktioniert nähmlich bei mir mit proxifier wunderbar. Du solltest proxyfication mal so einstellen: siehe Anhang Geändert von AngelDelivery (20.01.10 um 20:14 Uhr) |
|
|
|
|
#4 (permalink) |
|
Registriert seit: 18.01.10
![]() |
Hey!
Danke für deine Tips! Hab proxification genauso eingestellt wie du mirs gezeigt hast, jedoch kommt immer noch der selbe Fehler. Als erstes bekomme ich den folgenden fehler: accepted new socks client at 127.0.0.1:49713 new client connected: 127.0.0.1:49713 authFields: version 5 methods 1 socks client supports 1 methods socksclient requests address type 3 unsupported addresstype 3 terminating connection Den habe ich bypassed indem ich "byte SOCKS_IPV4ADDR = 1;" Auf "byte SOCKS_IPV4ADDR = 3;" gesetzt habe. Nur dann kommt accepted new socks client at 127.0.0.1:49715 new client connected: 127.0.0.1:49715 authFields: version 5 methods 1 socks client supports 1 methods socksclient requests address type 3 requesting 14.119.119.119:11879 Und im Visual Studio wird mir der Fehler angezeigt: Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat 14.119.119.119:11879 Sonst passiert nichts mehr. |
|
|
|
|
|
#5 (permalink) |
|
Guest
|
wow sorry,
es ist mein Fehler. habe den Dateianhang schon ausgetauscht. Das Problem ist tatsächlich der addresstype dns. Ich habe fälschlicher Weise 2 erwartet. Es ist aber 3. Code:
byte SOCKS_DNSNAME =3; |
|
|
|
#6 (permalink) |
|
Registriert seit: 18.01.10
![]() |
Klappt jetzt ohne Probleme!
Echt genial. Danke! Sehr gute arbeit muss ich sagen!!!! EDIT: Kann ich den Server eingeltich auf einem Windows VPS installieren und ihn dann als Socks5 nutzen? Muss mir vorher nur son teil besorgen ;-) Deswegen frag ich dich da du bestimmt mehr ahnung davon hast als ich! Geändert von Heidi12 (20.01.10 um 20:51 Uhr) |
|
|
|
|
|
#7 (permalink) |
|
Guest
|
Klar warum nicht als vps, vielleicht muss man den proxy dann auf einem anderen port starten wenn der provider es nicht zulässt auf 1080.
Allerdings beachte bitte, dass Du mit Deinem privaten vps nicht wirklich anonym bist , falls dieser in DE steht.
|
|
|
|
#8 (permalink) |
|
Registriert seit: 04.03.10
![]() |
Sehr schönes Tutorial...
Aber hab ne weile gebraucht, bis ich gerafft hab, dass ich dem FF als Client auch tatsächlich einen SOCKS Proxy einhämmern muss, bevor das klapp.... Geändert von Mappel (04.03.10 um 23:04 Uhr) |
|
|
|
|
|
#9 (permalink) |
|
Registriert seit: 08.03.10
![]() |
Schöne Sourcen, einfacher als erwartet, funktioniert einwandfrei. Besten Dank!
|
|
|
|
|
|
#10 (permalink) | ||
|
Guest
|
Zitat:
Zitat:
|
||
|
![]() |
| Themen-Optionen | |
| Ansicht | |
|
|