Kürzlich haben Telegrammentwickler den Quellcode eines Proxyservers veröffentlicht, der auf dem MTProto-Protokoll ausgeführt wird. Die Artikel über die
Merkmale seiner Montage und das
Umpacken des Docker-Containers wurden auf dem
Hub veröffentlicht . Der offizielle Proxy-Server, geschrieben in C, überrascht mit der Menge an Code - ungefähr 23.000 Zeilen. Zur gleichen Zeit und manchmal etwas früher kamen mehrere alternative Implementierungen heraus, aber keine von ihnen unterstützte die Möglichkeit, ihren Kanal zu bewerben.
In diesem Artikel möchte ich zum einen über wenig bekannte Funktionen des Protokolls für die Kommunikation eines Proxyservers mit externen Servern sprechen und zum anderen über unsere eigene Entwicklung - die Implementierung eines Proxyservers in Python, der gerade veröffentlicht wurde und allen unter verfügbar ist Kostenlose MIT-Lizenz.
Merkmale der Interaktion des Proxyservers mit externen Servern
- Der offizielle Proxyserver interagiert nicht direkt mit Telegrammservern, sondern verwendet hierfür mindestens eine weitere Proxy-Schicht. Wir werden sie als Middle-Proxy bezeichnen . Ihre Liste finden Sie unter core.telegram.org/getProxyConfig und core.telegram.org/getProxyConfigV6 . Die IPv6-Verbindung wird vom offiziellen Proxyserver noch nicht unterstützt.
- Zum Verschlüsseln von Daten zwischen dem Proxyserver und dem mittleren Proxy wird ein Schlüssel verwendet, der aus den IP-Adressen beider Knoten abgerufen wird. Daher muss der Proxyserver für die Verbindung zum mittleren Proxy seine externe IP-Adresse kennen, da sonst die Verschlüsselungsschlüssel auf der einen und der anderen Seite unterschiedlich sind. Darüber hinaus sind die Portnummern beider Knoten und das unter core.telegram.org/getProxySecret verfügbare gemeinsame Geheimnis an der Bildung des Schlüssels beteiligt. Telegrammentwickler empfehlen, dieses Geheimnis einmal täglich zu aktualisieren.
- Wenn Sie einen Proxyserver mit einem mittleren Proxy verbinden, überträgt der erste seine Zeit. Wenn sich die Zeit um mehr als einige Minuten unterscheidet, schließt die zweite Seite die Verbindung.
- Beim Senden einer Nachricht vom Client an den mittleren Proxy wird die Nachricht in einen RPC-Aufruf an das MTProto-Protokoll eingeschlossen. Bei jedem solchen RPC-Aufruf fügt der Proxy mehrere Argumente hinzu: IP und Port beider Knoten, eine zufällige Verbindungskennung sowie das Proxy-Server-Tag, mit dem der Werbekanal in der Anwendung angezeigt wird. Diese zusätzlichen Argumente belegen ungefähr 96 Bytes. Aufgrund dieser Funktion ist es nicht möglich, Werbekanäle anzuzeigen, wenn Sie direkt arbeiten, nicht über den mittleren Proxy.
- Telegrammserver "glauben" den Informationen über den IP-Client, die vom Proxyserver empfangen wurden. Diese Adressen sind in den Sitzungsinformationen zu sehen (das Rechteck wird gezeichnet):

- Eine TCP-Verbindung zwischen dem Proxyserver und dem mittleren Proxy sendet Nachrichten von verschiedenen Benutzern. In Anfragen und Antworten gibt es ein Argument "zufällige Verbindungskennung", das erforderlich ist, damit die Daten den richtigen Client erreichen.
- Ein Proxyserver kann keine Clientdaten entschlüsseln, aber er kann reguläre Nachrichten von übertragenen Dateien unterscheiden. Außerdem kennt er die Größe jeder Nachricht.
Fuf, ich hoffe nicht müde von den technischen Details. Jetzt sollte klar sein, warum es in vielen alternativen Proxys keine Werbeunterstützung gibt - sie senden Nachrichten direkt an die Telegrammserver, wobei der mittlere Proxy umgangen wird. Es stellt sich viel einfacher heraus. Der zweite Teil des Artikels beschreibt die erste inoffizielle Implementierung eines Proxyservers, der über Middle-Proxy funktioniert. Im Moment finden Sie im öffentlichen Bereich drei solcher Implementierungen: offiziell, auf Erlang und diese.
Python-Proxy-Implementierung
Ursprünglich wurde der Proxyserver geschrieben, um die Funktionen des Protokolls zu verstehen, und es wurde ein anderes Projekt entwickelt - ein asynchroner Socken-Proxy, der wiederum geschrieben wurde, um asynchrones / Warten in Python zu "berühren".
Allmählich begann das Projekt, Benutzer zu haben, die mit Fragen, Fehlerberichten und Funktionsanfragen überschwemmt waren. Nach Verbesserungen trat das Projekt in die Beta-Test- und Stabilisierungsphase ein, die etwa eine Woche dauerte und fünf Server mit unterschiedlichen Konfigurationen umfasste.
Bevor ich über Funktionen spreche, die der offizielle Proxyserver noch nicht hat, aber der alternative Proxy (und über die Funktionen, die der offizielle Proxy bei der Alternative nicht hat) schweigt, werde ich über die Dinge sprechen, an die viele Leute zuerst denken, wenn sie das Wort Python erwähnen .
Leistung
Für Leistungstests wurde eine virtuelle Maschine in einer Cloud mit minimaler Konfiguration verwendet: 1 CPU, 1024 MB RAM.
Bei synthetischen Tests konnte der Proxyserver etwa 240 Megabit / s oder 3000 Nachrichten / s übertragen. Bei Verwendung einer alternativen Implementierung der Ereignisschleife in C, die als uvloop bezeichnet wird, und auch bei Verwendung des PyPy-Interpreters sind die Leistungsdaten unterschiedlich (alle Messungen erfolgen pro Sekunde):

Beim Testen an realen Benutzern stellte sich heraus, dass ein solcher Server ausreichte, um 4.000 Benutzer oder 8.000 Benutzer bei Verwendung von PyPy bequem zu bedienen. Eine große Überraschung war, dass immer noch 89% der Benutzer aus dem Iran stammten, unabhängig davon, wie der Testserver in russischsprachigen Kanälen beworben wurde (Vielleicht unterscheidet sich für andere Länder die Anzahl der gleichzeitig bedienten Benutzer). Es sieht so aus:

Ich habe mehrere Administratoren anderer Server gefragt - ihre Situation ist dieselbe. Vielleicht liegt das daran, dass das Telegramm in Russland ohne Proxyserver gut funktioniert. Im Iran wurden Testserver einige Stunden nach ihrer Erstellung für die Öffentlichkeit gesperrt.

Serverlast mit 2.000 Benutzern. Der Moment der Sperrung des Servers für iranische Bürger ist deutlich sichtbar.
Daher ist die CPU-Leistung kein Engpass auf dem Testknoten. Bei 10.000 Clients ist der Speicher wahrscheinlich knapp.
Die gleichzeitige Verwendung mehrerer CPU-Kerne ist nicht implementiert (Hallo, GIL).
Funktionen, die der offizielle Proxyserver noch nicht hat
Arbeiten Sie am IPv6-Protokoll.Ein Proxyserver ohne zusätzliche Konfiguration kann IPv6 für ausgehende Verbindungen verwenden. IPv6-Verbindungen sind in Russland (vorerst) nicht blockiert.
Betriebsart ohne Middle-ProxyWenn keine Kanalwerbung benötigt wird, stellt der Proxy automatisch eine direkte Verbindung zu den Telegrammservern her und umgeht den mittleren Proxy. Es ist schneller und zuverlässiger.
Der optionale "
Schnellmodus " wird auch implementiert, wenn Nachrichten vom Telegrammserver an den Proxy und vom Proxy an den Client mit demselben Schlüssel verschlüsselt werden. Daher muss der Proxy Nachrichten nicht neu verschlüsseln - er sendet sie so wie sie sind. Dies sollte die Sicherheit nicht beeinträchtigen. In jedem Fall hat der Proxy-Administrator keinen Zugriff auf Benutzernachrichten.
Mittlere Proxy-Liste und Geheimnis einmal täglich automatisch aktualisieren.Der offizielle Proxyserver zum Aktualisieren der Middle-Proxy-Liste empfiehlt, den Docker-Container einmal täglich neu zu starten, wodurch alle Verbindungen zurückgesetzt werden. Neue Verbindungen können möglicherweise nicht hergestellt werden, wenn beispielsweise ein Server im Land blockiert ist. Die Python-Version besucht die Site regelmäßig und aktualisiert die Liste.
Multi-PlattformAlle Plattformen, auf denen Python ausgeführt wird, werden unterstützt. Es stellte sich heraus, dass es sogar auf dem iPad ausgeführt werden konnte. Die externen eingehenden Verbindungen wurden jedoch vom Gerät blockiert. Windows wird separat unterstützt, es war eine Überraschung für mich, wie viele Leute Proxys unter diesem Betriebssystem starten. Obwohl Sie unter Windows den offiziellen Client ausführen können, wenn Sie Virtualisierungstechnologien oder Docker verwenden.
Die Fähigkeit, einfach ohne Docker zu laufen.Wenn es (plötzlich) diejenigen gibt, die Docker nicht mögen, kann ein Proxy ohne Docker gestartet werden. Sie müssen mindestens zwei Parameter in der Konfigurationsdatei angeben: port und secret. Sie können auch das optionale Werbetag festlegen und dann den folgenden Befehl ausführen: python3 mtprotoproxy.py. In diesem Fall müssen Sie jedoch über Autorun im Betriebssystem nachdenken, z. B. Unit-Datei für systemd schreiben. Sie müssen auch pycrypto oder pycryptodome installieren, ohne es wird es funktionieren, aber sehr langsam.
Im Fall von Docker kann der Container mit dem Befehl docker-compose up --build neu erstellt werden.
Für die nächste Version geplante Funktionen
Begrenzung der Geschwindigkeit beim Herunterladen großer Dateien.Wenn Sie große Dateien herunterladen, können Sie auf TCP-Ebene den mittleren Proxy oder den Telegrammserver bitten, Daten langsamer zu senden. Dies erfolgt nun durch Festlegen eines kleinen Werts des Empfangspuffers, wodurch zusätzlich Serverspeicher gespart wird.
Streaming von Nachrichten.Jetzt lesen alle bekannten Proxy-Server, die mit Middle-Proxy arbeiten, zuerst die Nachricht vom Client und senden sie erst dann. Die Größe einer Nachricht kann 1 MB erreichen. Ein Speicher wird für seine Speicherung benötigt und die Übertragungsverzögerung wird geringfügig erhöht. Sie können Daten-Streaming übertragen. Dies kompliziert den Code, reduziert jedoch im schlimmsten Fall den Speicherverbrauch.
Ändern Sie die Länge der Pakete, um den Filter entlang der Länge des Pakets zu umgehen .
Ich habe es nicht geschafft, in die Veröffentlichung zu kommen.
Installation und Start
- Git-Klon -b stabil github.com/alexbers/mtprotoproxy.git; cd mtprotoproxy
- (optional, empfohlen) Geben Sie PORT , USERS und AD_TAG in config.py an
- docker-compose up --build -d (oder python3 mtprotoproxy.py, also ohne Docker)
- (Optional, zeigt einen Link der Form tg: // an) Docker-Compose-Protokolle
Andere Implementierungen von MTProto-Proxy mit Unterstützung für Kanalwerbung:Danksagungseriyps - für Hilfe beim Testen an echten Benutzern
shifttstas - für Docker-Tipps
forst (github) - für die Idee und Umsetzung der Arbeit an IPv6
p1ratrulezzz (github) - für Tipps und einen Artikel über das Projekt
freekzy (github) - für einen Bug Patch mit Griffleck
UPD: Repository, das verschiedene Implementierungen des MTProto-Proxys kompiliert:
github.com/mtProtoProxy