In diesem Abschnitt werde ich erklären, wie man einen Tor-Proxy-Generator erstellt und eine Webanwendungsfunktion implementiert, um Proxys zu verfolgen und zu verwalten.

Die Themen dieses Abschnitts umfassen Folgendes:

  1. Tor-Proxy-Generator
  2. Automatisierte Tor-Proxy-Generierung
    1. Proxys erstellen
    2. Proxy-Status überprüfen
    3. Proxys löschen
  3. Datenbankmodelle
  4. Backend erstellen
  5. Frontend erstellen
  6. Test

Tor-Proxy-Generator

Das folgende GitHub-Repository enthält Code für einen Tor-Proxy-Generator:

https://github.com/0xHamy/tor_proxy_gen

Für jeden Proxy benötigen Sie einen separaten Docker-Container, zumindest mache ich das so. Sie können auch Hunderte von Proxys günstig kaufen, aber es schadet nicht, die Einrichtung selbst zu lernen.

Wenn Sie sich die Datei „docker-compose.yaml” in diesem Repository ansehen, sehen Sie, dass wir den gesamten Datenverkehr über Port 9050 innerhalb des Docker an das Host-Netzwerk über Port 9050 weiterleiten:

services:
  tor:
    build:
      context: .
      dockerfile: Dockerfile
    image: tor-proxy
    ports:
      - "9050:9050"
    container_name: tor-proxy
    restart: unless-stopped

Wenn Sie über einen anderen Port als den Ihres Host-Netzwerks auf den Proxy zugreifen möchten, können Sie die Ports wie folgt ändern:

3531:9050

Der erste Port ist der Port, der auf Ihrem Host-System geöffnet wird, und der zweite Port ist der Port, der in Docker ausgeführt wird.

Die Datei torrc verwendet Port 9050 für den Tor-Dienst:

SocksPort 0.0.0.0:9050
Log notice stdout

Dockerfile führt eine kleine Version des Debian-Betriebssystems aus, um den Tor-Proxy auszuführen:

# Use a lightweight Debian-based image
FROM debian:bullseye-slim

# Install Tor
RUN apt-get update && \
    apt-get install -y tor && \
    rm -rf /var/lib/apt/lists/*

# Copy custom Tor configuration
COPY torrc /etc/tor/torrc

# Expose the Tor SOCKS5 proxy port
EXPOSE 9050

# Run Tor as the main process
CMD ["tor", "-f", "/etc/tor/torrc"]

Wenn es darum geht, eine App zu erstellen, die mehrere Tor-Proxys generiert, können wir uns nicht nur auf Port 9050 verlassen, da dieser bereits belegt ist und wir ihn daher nicht verwenden können, wenn er bereits von etwas anderem genutzt wird. Aus diesem Grund erstellen wir ein Python-Skript, das einen zufälligen Port zwischen 40.000 und 60.000 auswählt. Da es in jedem Computer nur 65.535 Ports gibt, haben wir diesen bestimmten Portbereich gewählt, da er meiner Erfahrung nach normalerweise nicht verwendet wird und zumindest unter Ubuntu keine Root-Rechte erfordert.


Automatisierte Tor-Proxy-Generierung

Da wir Tor-Proxys mit Docker generieren, müssen wir drei Kernfunktionen implementieren:

  1. Eine Funktion zum Erstellen eines Docker-Containers für die Ausführung eines Tor-Proxys
  2. Eine Funktion zum Überprüfen des Status eines Docker-Containers, um zu überprüfen, ob der Proxy aktiv ist
  3. Eine Funktion zum Herunterfahren und Entfernen eines Docker-Containers

Die entsprechenden Dateien befinden sich in app/services/*.py. Die spezifischen Dateien, die wir verwenden werden, sind:

  1. tor_proxy_gen.py: Erstellt Docker-Container für Tor-Proxys
  2. container_status.py: Überprüft den Status von Docker-Containern
  3. rm_container.py: Verwaltet das Löschen von Docker-Containern

Proxys erstellen

Das Skript tor_proxy_gen.py automatisiert die Erstellung von Docker-Containern, auf denen Tor-Proxys ausgeführt werden, und stellt einen SOCKS5-Proxy für den anonymen Netzwerkzugriff bereit. Nachfolgend finden Sie eine kurze Erläuterung der Komponenten und Funktionen.

Zweck:

  • Erstellt und startet einen Docker-Container, auf dem ein Tor-Proxy ausgeführt wird, weist einen zufälligen Port zu, ruft die IP-Adresse des Containers und die IP-Adresse des Tor-Ausgangsknotens ab und gibt die Details als JSON-fähiges Wörterbuch zurück.

Global Variables:

  • PORT_MIN, PORT_MAX:
    • Zweck: Definiert den Bereich (40001–60001) für die Auswahl zufälliger Host-Ports.
    • Details: Stellt die eindeutige Portzuweisung für jeden Container sicher.
  • SOCKS_PORT_IN_CONTAINER:
    • Zweck: Legt den Tor-SOCKS-Port innerhalb des Containers fest (9050).
    • Details: Standardport für den SOCKS5-Proxy von Tor.
    • MAX_PORT_ATTEMPTS:
      • Zweck: Begrenzt die Anzahl der Versuche, einen freien Port zu finden (100).
      • Details: Verhindert Endlosschleifen bei der Port-Auswahl.
    • WAIT_MAX_SECONDS, WAIT_STEP_SECONDS:
      • Zweck: Steuert das Zeitlimit (60 s) und das Abfrageintervall (2 s) für die Portbereitschaft.
      • Details: Wird verwendet, wenn auf die Öffnung des Containerports gewartet wird.
  • DOCKERFILE, TORRC, COMPOSE_TEMPLATE:
    • Zweck: Definiert Docker-Konfigurationsdateien als Zeichenfolgen.
    • Details: DOCKERFILE richtet ein Debian-basiertes Image mit Tor ein; TORRC konfiguriert den SOCKS-Port von Tor; COMPOSE_TEMPLATE definiert die Docker Compose-Einstellungen für den Container.

Funktionen:

  • die:

    • Zweck: Protokolliert eine Fehlermeldung und beendet das Programm.
    • Wichtige Parameter: msg (Fehlermeldung), code (Exit-Code, Standardwert 1).
    • Rückgabewerte: Keine (beendet das Programm).
    • Details: Gibt den Fehler an stderr aus und protokolliert ihn über logging.
  • cmd_exists:

    • Zweck: Prüft, ob eine ausführbare Datei (z. B. docker) in $PATH verfügbar ist.
    • Wichtige Parameter: executable (Befehlsname).
    • Rückgabewerte: Boolesch (True, wenn gefunden).
    • Details: Verwendet shutil.which und protokolliert das Ergebnis.
  • docker_compose_available:

    • Zweck: Überprüft, ob Docker Compose verfügbar ist.
    • Wichtige Parameter: Keine.
    • Rückgabewert: Boolescher Wert (True, wenn docker compose version erfolgreich ist).
    • Details: Führt einen Befehl aus, um nach Docker Compose zu suchen, und protokolliert die Ausgabe oder Fehler.
  • is_port_free:

    • Zweck: Überprüft, ob ein TCP-Port auf 127.0.0.1 unbenutzt ist.
    • Wichtige Parameter: port (Portnummer).
    • Rückgabewert: Boolescher Wert (True, wenn der Port frei ist).
    • Details: Versucht, mit einem Socket und einer Zeitüberschreitung von 0,5 Sekunden eine Verbindung zum Port herzustellen.
  • random_free_port:

    • Zweck: Sucht einen zufälligen, ungenutzten Port im definierten Bereich.
    • Wichtige Parameter: Keine.
    • Rückgabewert: Ganzzahl (freie Portnummer).
    • Details: Versucht bis zu MAX_PORT_ATTEMPTS zufällige Ports; ruft die auf, wenn keiner frei ist.
  • random_container_name:

    • Zweck: Generiert einen eindeutigen Containernamen.
    • Wichtige Parameter: Keine.
    • Rückgabewert: Zeichenfolge (z. B. torproxy_abcdef).
    • Details: Kombiniert torproxy_ mit sechs zufälligen Kleinbuchstaben.
  • wait_for_port:

    • Zweck: Wartet, bis ein Port auf einem Host geöffnet ist oder die Zeit abgelaufen ist.
    • Wichtige Parameter: host (IP), port (Portnummer), timeout (Sekunden).
    • Rückgabewert: Keine (löst bei Zeitüberschreitung einen RuntimeError aus).
    • Details: Fragt alle WAIT_STEP_SECONDS ab, bis der Port verwendet wird oder timeout abläuft.
  • fetch_tor_exit_ip:

    • Zweck: Ruft die IP-Adresse des Tor-Ausgangsknotens über externe Dienste ab.
    • Wichtige Parameter: host_port (Proxy-Port), timeout (Zeitüberschreitung für die Anfrage, standardmäßig 15 Sekunden).
    • Rückgabewert: Zeichenfolge (IP-Adresse des Ausgangsknotens).
    • Details: Fragt IP-Echo-Dienste (z. B. checkip.amazonaws.com) über einen SOCKS5-Proxy ab; löst RuntimeError aus, wenn alle fehlschlagen.
  • create_and_start_proxy:

    • Zweck: Erstellt einen Tor-Proxy-Container, startet ihn und gibt seine Details zurück.
    • Wichtige Parameter: Keine.
    • Rückgabewerte: Wörterbuch mit container_name, container_ip (mit Port), tor_exit_node und timestamp.
    • Details:
      • Überprüft die Verfügbarkeit von Docker und Compose; bricht ab, wenn diese fehlen.
      • Generiert einen zufälligen Containernamen und Port.
      • Erstellt ein temporäres Verzeichnis mit Dockerfile, torrc und compose.yaml.
      • Führt docker compose up --build -d aus, um den Container zu starten.
      • Wartet, bis der Port geöffnet ist, ruft die IP-Adresse des Containers über docker inspect ab und ruft die Tor-Ausgangs-IP ab.
      • Bereinigt den Container bei einem Fehler mit „docker rm -f“.

Auf meinem Rechner benötigt Docker „sudo“ für Root-Rechte. Wenn Sie „tor_proxy_gen.py“ mit „sudo python3 tor_proxy_gen.py“ ausführen, wird der systemweite Python-Interpreter verwendet, der die virtuelle Umgebung mit den Abhängigkeiten des Projekts „tornet_scraper“ umgeht.

Führen Sie stattdessen das Skript wie folgt aus, um den Python-Interpreter der virtuellen Umgebung zu verwenden:

-> % sudo /home/hamy/tornet_scraper/venv/bin/python3 app/services/tor_proxy_gen.py                      
[sudo] password for hamy: 
{
  "container_name": "torproxy_tucgye",
  "proxy_ip_docker": "192.168.128.2:45364",
  "proxy_ip_exit_node": "185.193.52.180",
  "timestamp": 1752431067
}

Dadurch wird sichergestellt, dass das Skript den Python-Interpreter der virtuellen Umgebung „tornet_scraper” mit allen erforderlichen Abhängigkeiten verwendet.

Überprüfen des Proxy-Status

Das Skript „container_status.py” enthält Hilfsfunktionen zum Überprüfen des Status von Docker-Containern. Nachfolgend finden Sie eine kurze Erläuterung der Funktionen.

  1. cmd_exists:

    • Zweck: Überprüft, ob eine bestimmte ausführbare Datei im $PATH des Systems verfügbar ist.
    • Wichtige Parameter:
      • executable: String-Name des Befehls (z. B. docker).
    • Rückgabewert: Boolescher Wert (True, wenn die ausführbare Datei gefunden wurde, andernfalls False).
    • Details: Verwendet shutil.which, um zu überprüfen, ob die ausführbare Datei vorhanden und im $PATH des Systems zugänglich ist.
  2. container_running:

    • Zweck: Stellt fest, ob ein Docker-Container ausgeführt wird.
    • Wichtige Parameter:
      • name: String-Name des Docker-Containers.
    • Rückgabewert: Boolescher Wert (True, wenn der Container vorhanden ist und ausgeführt wird, andernfalls False).
    • Details: Führt „sudo docker inspect -f {{.State.Running}} “ aus, um den Ausführungsstatus des Containers zu überprüfen. Gibt „True“ zurück, wenn die Ausgabe „true“ lautet, „False“, wenn der Befehl fehlschlägt (z. B. wenn der Container nicht existiert) oder der Status nicht „running“ ist. Unterdrückt stderr mit „DEVNULL“, um Fehlerausgaben zu vermeiden.

Proxys löschen

Das Skript „rm_container.py“ bietet eine Funktion zum zwangsweisen Entfernen eines Docker-Containers. Nachfolgend finden Sie eine kurze Erläuterung der einzigen Funktion.

  1. „delete_container“:

    • Zweck: Löscht einen angegebenen Docker-Container mit „sudo docker rm -f“.
    • Wichtige Parameter:
      • name: String-Name des zu löschenden Docker-Containers.
    • Rückgabewerte: Boolesche Werte (True, wenn das Löschen erfolgreich war, False, wenn es fehlgeschlagen ist).
    • Details: Führt sudo docker rm -f <name> aus, um den Container zwangsweise zu entfernen, wobei sowohl stdout als auch stderr mit DEVNULL unterdrückt werden. Gibt True zurück, wenn der Befehl erfolgreich war, oder False, wenn ein CalledProcessError auftritt (z. B. wenn der Container nicht existiert oder Berechtigungsprobleme vorliegen).

Datenbankmodelle

So sehen Ihre Datenbankmodelle aus:

class Proxy(Base):
    __tablename__ = "proxies"

    id = Column(Integer, primary_key=True, index=True)
    container_name = Column(String, unique=True, index=True)
    container_ip = Column(String)
    tor_exit_node = Column(String)
    timestamp = Column(DateTime, default=datetime.utcnow)
    running = Column(Boolean, default=True)

Einigen von Ihnen erscheint datetime.utcnow möglicherweise als veraltet, aber darüber müssen Sie sich keine Gedanken machen.


Backend erstellen

Die Services-Module übernehmen die ganze Arbeit, aber wir benötigen noch einen Backend-Router, um diese Funktionen aufzurufen und Anfragen vom Frontend zu bearbeiten. Ihr Backend für die Proxy-Generierung befindet sich in app/routes/proxy_gen.py.

Das Skript proxy_gen.py definiert FastAPI-Routen zum Erstellen, Löschen und Auflisten von Tor-Proxy-Containern sowie zur Interaktion mit der Datenbank und externen Diensten. Nachfolgend finden Sie eine kurze Erläuterung der Komponenten und Funktionen.

Globale Variablen

  1. logger:
    • Zweck: Konfiguriert die Protokollierung für die Fehlerbehebung und Fehlerverfolgung.
    • Details: Verwendet das Modul logging mit der Stufe INFO, um Vorgänge und Fehler zu protokollieren.
  2. proxy_gen_router:
    • Zweck: FastAPI-Router für proxybezogene Endpunkte.
    • Details: Konfiguriert mit dem Präfix /api/proxy-gen und den Tags [„API“, „Proxy Generator“] zur Organisation.

Funktionen

  1. create_proxy:

    • Zweck: Erstellt einen neuen Tor-Proxy-Container und speichert dessen Details in der Datenbank.
    • Wichtige Parameter:
      • request: FastAPI-Request-Objekt für die Sitzungsverwaltung.
      • db: SQLAlchemy-Session für Datenbankoperationen (über Depends(get_db)).
    • Rückgabewerte: JSONResponse mit Erfolgsstatus, Meldung und Proxy-Details (Containername, IP, Tor-Ausgangsknoten, Zeitstempel, Ausführungsstatus).
    • Details: Ruft create_and_start_proxy (aus tor_proxy_gen.py) auf, um einen Container zu starten, erstellt eine Proxy-Modellinstanz, speichert sie in der Datenbank und gibt eine JSON-Antwort zurück. Löst bei Fehlern HTTPException (500) aus und protokolliert das Problem.
  2. delete_proxy:

    • Zweck: Löscht einen angegebenen Tor-Proxy-Container und seinen Datenbankeintrag.
    • Wichtige Parameter:
      • container_name: String-Name des zu löschenden Containers.
      • request: FastAPI-Objekt Request für sitzungsbasierte Flash-Meldungen.
      • db: SQLAlchemy-Objekt Session für Datenbankoperationen.
    • Rückgabewert: JSONResponse mit Status und Meldung bei erfolgreicher Löschung.
    • Details: Fragt die Tabelle Proxy nach dem Container ab; wenn er gefunden wird, ruft er delete_container (aus rm_container.py) auf, um ihn zu entfernen. Löscht bei Erfolg den Datenbankeintrag und fügt eine erfolgreiche Flash-Meldung zur Sitzung hinzu. Löst HTTPException aus (404, wenn nicht gefunden, 500 bei Fehlern) und fügt Fehler-Flash-Meldungen hinzu.
  3. list_proxies:

    • Zweck: Ruft eine Liste aller Proxys mit aktualisiertem Ausführungsstatus ab.
    • Wichtige Parameter:
      • db: SQLAlchemy Session für Datenbankoperationen.
    • Rückgabewerte: JSONResponse mit einer Liste von Proxys, die jeweils den Containernamen, die IP-Adresse, den Tor-Ausgangsknoten, den Zeitstempel und den Ausführungsstatus enthalten.
    • Details: Fragt alle Proxy-Datensätze ab, überprüft den Ausführungsstatus jedes Containers mit container_running (aus container_status.py), aktualisiert bei Bedarf das Feld running in der Datenbank und gibt die Liste als JSON zurück. Bei Fehlern wird eine HTTPException (500) ausgelöst und das Problem protokolliert.

Frontend erstellen

Ihr Vorlagencode befindet sich in app/templates/proxy_gen.html.

Die Vorlage proxy_gen.html erweitert base.html um eine Benutzeroberfläche zur Verwaltung von Tor-Proxy-Containern in der Anwendung tornet_scraper, die über API-Aufrufe mit dem Backend interagiert. Im Folgenden finden Sie eine kurze Erläuterung der wichtigsten Funktionen und ihrer Interaktion mit dem Backend.

  1. Vorlagenvererbung:

    • Zweck: Nutzt das Layout von base.html für eine einheitliche Struktur.
    • Backend-Interaktion: Erbt die Navigationleiste und die Verarbeitung von Flash-Meldungen aus base.html. Der {% block title %} setzt den Seitentitel auf „Proxy Generator“ und {% block content %} definiert die seitenbezogenen Funktionen. Flash-Meldungen aus dem Backend (die in der Sitzung gespeichert sind) werden im geerbten Container angezeigt.
  2. Proxy-Erstellung:

    • Zweck: Initiiert und bestätigt die Erstellung eines neuen Tor-Proxy-Containers.
    • Backend-Interaktion:
      • Eine Schaltfläche „Neuen Proxy erstellen“ löst die JavaScript-Funktion createProxy() aus und öffnet ein Bestätigungsmodal.
      • Die Schaltfläche „Weiter“ des Modals ruft confirmCreateProxy() auf und sendet eine AJAX-POST-Anfrage an /api/proxy-gen/create (verarbeitet von proxy_gen.py::create_proxy).
      • Das Backend erstellt einen Docker-Container (über tor_proxy_gen.py), speichert die Proxy-Details (Containername, IP, Tor-Ausgangsknoten, Zeitstempel, Ausführungsstatus) in der Tabelle Proxy in der Datenbank und gibt eine JSON-Antwort zurück.
      • Bei Erfolg wird die Tabelle über updateProxyTable() aktualisiert. Fehler lösen Konsolenprotokolle aus und aktivieren die Schaltfläche erneut.
  3. Anzeige und Aktualisierung der Proxy-Tabelle:

    • Zweck: Zeigt eine dynamische Liste von Proxys mit Statusaktualisierungen in Echtzeit an.
    • Backend-Interaktion:
      • Beim Laden der Seite rendert Jinja2 die anfänglichen Proxy-Daten (proxies aus main.py::proxy_gen) in eine Tabelle mit Spalten für Containername, IP, Tor-Ausgangsknoten, Zeitstempel und Status.
      • Die Funktion updateProxyTable() wird alle 10 Sekunden (über setInterval) und bei Erstellung/Löschung ausgeführt und sendet eine AJAX-GET-Anfrage an /api/proxy-gen/list (verarbeitet von proxy_gen.py::list_proxies).
      • Das Backend fragt die Tabelle „Proxy“ ab, überprüft den Ausführungsstatus jedes Containers (über „container_status.py::container_running“), aktualisiert bei Bedarf die Datenbank und gibt eine JSON-Liste der Proxys zurück.
      • Die Tabelle wird gelöscht und mit den neuesten Daten neu gefüllt, wobei der Status mit farbigen Badges als „Running“ (Ausgeführt) oder „Not Running“ (Nicht ausgeführt) angezeigt wird.
  4. Proxy löschen:

    • Zweck: Ermöglicht Benutzern das Löschen eines Proxy-Containers.
    • Backend-Interaktion:
      • Jede Tabellenzeile verfügt über eine Schaltfläche „Löschen“, die openDeleteModal(containerName) aufruft, um ein Bestätigungsmodal mit dem in einem versteckten Eingabefeld gespeicherten Containernamen zu öffnen.
      • Die Schaltfläche „Löschen“ des Modals löst confirmDeleteProxy() aus, wodurch eine AJAX-DELETE-Anfrage an /api/proxy-gen/delete/{container_name} gesendet wird (verarbeitet durch proxy_gen.py::delete_proxy).
      • Das Backend überprüft, ob der Proxy in der Tabelle „Proxy“ vorhanden ist, löscht den Container (über „rm_container.py::delete_container“), entfernt den Datenbankeintrag und fügt eine Erfolgsmeldung zur Sitzung hinzu.
      • Bei Erfolg wird eine Erfolgsmeldung angezeigt (über „showFlashMessage“) und die Tabelle wird aktualisiert. Fehler lösen eine Fehlermeldung aus.

Testen

Führen Sie die Web-App aus:

sudo /home/hamy/tornet_scraper/venv/bin/python3 -m uvicorn app.main:app --reload

Öffnen Sie die Web-App:

http://127.0.0.1:8000/proxy-gen

Erstellen Sie einen Proxy:

Tornet Scraper Proxy Page