Dans cette section, je vais expliquer comment créer un générateur de proxy Tor et implémenter une fonctionnalité d'application web permettant de suivre et de gérer les proxys.
Les sujets abordés dans cette section sont les suivants :
- Générateur de proxy Tor
- Génération automatisée de proxy Tor
- Création de proxys
- Vérification de l'état des proxys
- Suppression de proxys
- Modèles de base de données
- Création du backend
- Création du frontend
- Test
Générateur de proxy Tor
Le dépôt GitHub suivant contient le code d'un générateur de proxy Tor :
https://github.com/0xHamy/tor_proxy_gen
Pour chaque proxy, vous aurez besoin d'un conteneur Docker distinct, du moins c'est ce que je fais. Vous pouvez également acheter des centaines de proxys à bas prix, mais cela ne coûte rien d'apprendre à les configurer vous-même.
Si vous regardez le fichier docker-compose.yaml dans ce référentiel, vous pouvez voir que nous acheminons tout le trafic via le port 9050 à l'intérieur du docker vers le réseau hôte via le port 9050 :
services:
tor:
build:
context: .
dockerfile: Dockerfile
image: tor-proxy
ports:
- "9050:9050"
container_name: tor-proxy
restart: unless-stopped
Si vous souhaitez accéder au proxy via un port différent de celui de votre réseau hôte, vous pouvez modifier les ports comme suit :
3531:9050
Le premier port est celui qui s'ouvre sur votre système hôte et le second est celui qui s'exécute dans Docker.
Le fichier torrc utilise le port 9050 pour le service tor :
SocksPort 0.0.0.0:9050
Log notice stdout
Dockerfile exécute une version réduite du système d'exploitation Debian afin de faire fonctionner le proxy Tor :
# 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"]
Lorsqu'il s'agit de créer une application qui génère plusieurs proxys Tor, nous ne pouvons pas nous fier uniquement au port 9050, car il est très utilisé et nous ne pouvons donc pas l'utiliser s'il est déjà occupé par autre chose. Pour cette raison, nous allons créer un script Python en choisissant un port aléatoire entre 40 000 et 60 000. Il n'y a que 65 535 ports dans un ordinateur, c'est pourquoi nous avons choisi cette plage de ports spécifique, car d'après ce que j'ai pu constater, elle n'est généralement pas utilisée. De plus, elle ne nécessite pas de droits root pour être utilisée, du moins sous Ubuntu.
Génération automatisée de proxys Tor
Comme nous générons des proxys Tor à l'aide de Docker, nous devons implémenter trois fonctionnalités principales :
- Une fonction permettant de créer un conteneur Docker pour exécuter un proxy Tor
- Une fonction permettant de vérifier l'état d'un conteneur Docker afin de vérifier si le proxy est actif
- Une fonction permettant d'arrêter et de supprimer un conteneur Docker
Les fichiers correspondants se trouvent dans app/services/*.py. Les fichiers spécifiques que nous utiliserons sont les suivants :
tor_proxy_gen.py: gère la création de conteneurs Docker pour les proxys Torcontainer_status.py: vérifie l'état des conteneurs Dockerrm_container.py: gère la suppression des conteneurs Docker
Création de proxys
Le script tor_proxy_gen.py automatise la création de conteneurs Docker exécutant des proxys Tor, fournissant un proxy SOCKS5 pour un accès anonyme au réseau. Vous trouverez ci-dessous une explication concise de ses composants et de ses fonctionnalités.
Objectif :
- Crée et démarre un conteneur Docker exécutant un proxy Tor, attribue un port aléatoire, récupère l'adresse IP du conteneur et l'adresse IP du nœud de sortie Tor, puis renvoie les détails sous forme de dictionnaire prêt pour JSON.
Variables globales :
PORT_MIN,PORT_MAX:- Objectif : définir la plage (40001-60001) pour la sélection aléatoire des ports hôtes.
- Détails : garantit l'attribution d'un port unique à chaque conteneur.
SOCKS_PORT_IN_CONTAINER:- Objectif : définit le port SOCKS Tor à l'intérieur du conteneur (9050).
- Détails : port standard pour le proxy SOCKS5 de Tor.
- MAX_PORT_ATTEMPTS :
- Objectif : limite le nombre de tentatives pour trouver un port libre (100).
- Détails : empêche les boucles infinies dans la sélection des ports.
- WAIT_MAX_SECONDS, WAIT_STEP_SECONDS :
- Objectif : contrôle le délai d'expiration (60 s) et l'intervalle d'interrogation (2 s) pour la disponibilité des ports.
- Détails : utilisé lors de l'attente de l'ouverture du port du conteneur.
DOCKERFILE,TORRC,COMPOSE_TEMPLATE:- Objectif : définir les fichiers de configuration Docker sous forme de chaînes.
- Détails :
DOCKERFILEconfigure une image basée sur Debian avec Tor ;TORRCconfigure le port SOCKS de Tor ;COMPOSE_TEMPLATEdéfinit les paramètres Docker Compose pour le conteneur.
Fonctions :
-
die:- Objectif : Enregistre un message d'erreur et quitte le programme.
- Paramètres clés :
msg(message d'erreur),code(code de sortie, par défaut 1). - Retour : Aucun (quitte le programme).
- Détails : Affiche l'erreur sur stderr et l'enregistre via
logging.
-
cmd_exists:- Objectif : vérifie si un exécutable (par exemple,
docker) est disponible dans$PATH. - Paramètres clés :
executable(nom de la commande). - Retourne : booléen (
Truesi trouvé). - Détails : utilise
shutil.whichet consigne le résultat dans le journal.
- Objectif : vérifie si un exécutable (par exemple,
-
docker_compose_available:- Objectif : vérifie si Docker Compose est disponible.
- Paramètres clés : aucun.
- Retourne : booléen (
Truesidocker compose versionréussit). - Détails : exécute une commande pour vérifier la présence de Docker Compose et consigne les résultats ou les erreurs.
-
is_port_free:- Objectif : vérifie si un port TCP sur
127.0.0.1est inutilisé. - Paramètres clés :
port(numéro de port). - Retourne : booléen (
Truesi le port est libre). - Détails : tente de se connecter au port à l'aide d'un socket avec un délai d'expiration de 0,5 seconde.
- Objectif : vérifie si un port TCP sur
-
random_free_port:- Objectif : trouve un port aléatoire inutilisé dans la plage définie.
- Paramètres clés : Aucun.
- Retourne : entier (numéro du port libre).
- Détails : tente jusqu'à
MAX_PORT_ATTEMPTSports aléatoires ; appellediesi aucun n'est libre.
-
random_container_name:- Objectif : génère un nom de conteneur unique.
- Paramètres clés : aucun.
- Retourne : chaîne (par exemple,
torproxy_abcdef). - Détails : combine
torproxy_avec six lettres minuscules aléatoires.
-
wait_for_port:- Objectif : attend qu'un port sur un hôte soit ouvert ou que le délai expire.
- Paramètres clés :
host(IP),port(numéro de port),timeout(secondes). - Retourne : Aucun (lève une exception
RuntimeErroren cas de dépassement du délai). - Détails : Interroge toutes les
WAIT_STEP_SECONDSjusqu'à ce que le port soit utilisé ou que le délai expire.
-
fetch_tor_exit_ip:- Objectif : Récupère l'adresse IP du nœud de sortie Tor via des services externes.
- Paramètres clés :
host_port(port proxy),timeout(délai d'expiration de la requête, par défaut 15 s). - Retourne : Chaîne (adresse IP du nœud de sortie).
- Détails : interroge les services IP-echo (par exemple,
checkip.amazonaws.com) via un proxy SOCKS5 ; lève une exceptionRuntimeErrorsi toutes les requêtes échouent.
-
create_and_start_proxy:- Objectif : crée et démarre un conteneur proxy Tor, puis renvoie ses détails.
- Paramètres clés : Aucun.
- Retourne : Dictionnaire contenant
container_name,container_ip(avec port),tor_exit_nodeettimestamp. - Détails :
- Vérifie la disponibilité de Docker et Compose ; quitte si ils sont manquants.
- Génère un nom de conteneur et un port aléatoires.
- Crée un répertoire temporaire avec
Dockerfile,torrcetcompose.yaml. - Exécute
docker compose up --build -dpour démarrer le conteneur. - Attend que le port s'ouvre, récupère l'adresse IP du conteneur via
docker inspectet récupère l'adresse IP de sortie Tor. - Nettoie le conteneur en cas d'échec à l'aide de
docker rm -f.
Sur ma machine, Docker nécessite sudo pour les permissions root. L'exécution de tor_proxy_gen.py avec sudo python3 tor_proxy_gen.py utilise l'interpréteur Python du système, qui contourne l'environnement virtuel contenant les dépendances du projet tornet_scraper.
À la place, exécutez le script comme suit pour utiliser l'interpréteur Python de l'environnement virtuel :
-> % 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
}
Cela garantit que le script utilise l'interpréteur Python de l'environnement virtuel tornet_scraper avec toutes les dépendances requises installées.
Vérification de l'état du proxy
Le script container_status.py fournit des fonctions utilitaires pour vérifier l'état des conteneurs Docker. Vous trouverez ci-dessous une explication concise de ses fonctions.
-
cmd_exists:- Objectif : vérifie si un exécutable spécifié est disponible dans le
$PATHdu système. - Paramètres clés :
executable: nom de la commande sous forme de chaîne (par exemple,docker).
- Retourne : booléen (
Truesi l'exécutable est trouvé,Falsesinon). - Détails : utilise
shutil.whichpour vérifier si l'exécutable existe et est accessible dans le$PATHdu système.
- Objectif : vérifie si un exécutable spécifié est disponible dans le
-
container_running:- Objectif : détermine si un conteneur Docker est en cours d'exécution.
- Paramètres clés :
name: nom sous forme de chaîne du conteneur Docker.
- Renvoie : booléen (
Truesi le conteneur existe et est en cours d'exécution,Falsesinon). - Détails : exécute
sudo docker inspect -f {{.State.Running}} <name>pour vérifier l'état d'exécution du conteneur. RenvoieTruesi la sortie est« true »,Falsesi la commande échoue (par exemple, le conteneur n'existe pas) ou si l'état n'est pas en cours d'exécution. Supprime stderr avecDEVNULLpour éviter les sorties d'erreur.
Suppression de proxys
Le script rm_container.py fournit une fonction permettant de supprimer de force un conteneur Docker. Vous trouverez ci-dessous une explication concise de sa seule fonction.
-
delete_container:- Objectif : supprime un conteneur Docker spécifié à l'aide de
sudo docker rm -f. - Paramètres clés :
name: nom sous forme de chaîne du conteneur Docker à supprimer.
- Retourne : booléen (
Truesi la suppression réussit,Falsesi elle échoue). - Détails : exécute
sudo docker rm -f <name>pour supprimer de force le conteneur, en supprimant à la fois stdout et stderr avecDEVNULL. RenvoieTruesi la commande réussit, ouFalsesi une erreurCalledProcessErrorse produit (par exemple, le conteneur n'existe pas ou il y a un problème d'autorisation).
- Objectif : supprime un conteneur Docker spécifié à l'aide de
Modèles de base de données
Voici à quoi ressemblent vos modèles de base de données :
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)
Pour certains d'entre vous, datetime.utcnow peut sembler obsolète, mais vous n'avez pas à vous en soucier.
Création du backend
Les modules de services font tout le gros du travail, mais nous avons toujours besoin d'un routeur backend pour appeler ces fonctions et gérer les requêtes provenant du frontend. Votre backend pour la génération de proxys se trouve dans app/routes/proxy_gen.py.
Le script proxy_gen.py définit les routes FastAPI pour créer, supprimer et lister les conteneurs de proxy Tor, interagir avec la base de données et les services externes. Vous trouverez ci-dessous une explication concise de ses composants et fonctions.
Variables globales
logger:- Objectif : configure la journalisation pour le débogage et le suivi des erreurs.
- Détails : Utilise le module
loggingavec le niveauINFOpour consigner les opérations et les erreurs.
proxy_gen_router:- Objectif : Routeur FastAPI pour les points de terminaison liés aux proxys.
- Détails : Configuré avec le préfixe
/api/proxy-genet les balises[« API », « Proxy Generator »]pour l'organisation.
Fonctions
-
create_proxy:- Objectif : Crée un nouveau conteneur proxy Tor et stocke ses détails dans la base de données.
- Paramètres clés :
request: Objet FastAPIRequestpour la gestion des sessions.db: SQLAlchemySessionpour les opérations de base de données (viaDepends(get_db)).
- Retourne :
JSONResponseavec le statut de réussite, le message et les détails du proxy (nom du conteneur, IP, nœud de sortie Tor, horodatage, statut d'exécution). - Détails : Appelle
create_and_start_proxy(à partir detor_proxy_gen.py) pour démarrer un conteneur, crée une instance du modèleProxy, l'enregistre dans la base de données et renvoie une réponse JSON. Lève une exceptionHTTPException(500) en cas d'erreur et consigne le problème dans le journal.
-
delete_proxy:- Objectif : supprime un conteneur proxy Tor spécifié et son enregistrement dans la base de données.
- Paramètres clés :
container_name: nom sous forme de chaîne du conteneur à supprimer.request: objet FastAPIRequestpour les messages flash basés sur la session.db: SQLAlchemySessionpour les opérations de base de données.
- Renvoie :
JSONResponseavec le statut de réussite et un message en cas de suppression réussie. - Détails : interroge la table
Proxypour le conteneur ; s'il est trouvé, appelledelete_container(à partir derm_container.py) pour le supprimer. Supprime l'enregistrement de la base de données en cas de succès et ajoute un message flash de réussite à la session. Lève une exceptionHTTPException(404 si introuvable, 500 en cas d'erreur) et ajoute des messages flash d'erreur.
-
list_proxies:- Objectif : récupère une liste de tous les proxys avec leur état d'exécution mis à jour.
- Paramètres clés :
db: SQLAlchemySessionpour les opérations de base de données.
- Retourne :
JSONResponseavec une liste de proxys, chacun contenant le nom du conteneur, l'IP, le nœud de sortie Tor, l'horodatage et l'état d'exécution. - Détails : interroge tous les enregistrements
Proxy, vérifie l'état d'exécution de chaque conteneur à l'aide decontainer_running(à partir decontainer_status.py), met à jour le champrunningdans la base de données si nécessaire et renvoie la liste au format JSON. Génère une exceptionHTTPException(500) en cas d'erreur et consigne le problème dans le journal.
Création de l'interface utilisateur
Votre code de modèle se trouve dans app/templates/proxy_gen.html.
Le modèle proxy_gen.html étend base.html afin de fournir une interface utilisateur permettant de gérer les conteneurs proxy Tor dans l'application tornet_scraper, en interagissant avec le backend via des appels API. Vous trouverez ci-dessous une explication concise de ses principales fonctionnalités et de leur interaction avec le backend.
-
Héritage du modèle :
- Objectif : exploite la mise en page
base.htmlpour garantir une structure cohérente. - Interaction avec le backend : hérite de la barre de navigation et de la gestion des messages flash de
base.html. Le{% block title %}définit le titre de la page « Proxy Generator » et{% block content %}définit les fonctionnalités spécifiques à la page. Les messages flash provenant du backend (stockés dans la session) sont affichés dans le conteneur hérité.
- Objectif : exploite la mise en page
-
Création d'un proxy :
- Objectif : lance et confirme la création d'un nouveau conteneur de proxy Tor.
- Interaction avec le backend :
- Un bouton « Créer un nouveau proxy » déclenche la fonction JavaScript
createProxy(), ouvrant une fenêtre modale de confirmation. - Le bouton « Continuer » de la fenêtre modale appelle
confirmCreateProxy(), envoyant une requête AJAX POST à/api/proxy-gen/create(gérée parproxy_gen.py::create_proxy). - Le backend crée un conteneur Docker (via
tor_proxy_gen.py), enregistre les détails du proxy (nom du conteneur, IP, nœud de sortie Tor, horodatage, état d'exécution) dans la tableProxyde la base de données et renvoie une réponse JSON. - En cas de succès, la table est mise à jour via
updateProxyTable(). Les erreurs déclenchent des journaux de console et réactivent le bouton.
- Un bouton « Créer un nouveau proxy » déclenche la fonction JavaScript
-
Affichage et mise à jour de la table des proxys :
- Objectif : affiche une liste dynamique de proxys avec des mises à jour en temps réel.
- Interaction avec le backend :
- Au chargement de la page, Jinja2 affiche les données initiales des proxys (
proxiesdemain.py::proxy_gen) dans une table avec des colonnes pour le nom du conteneur, l'adresse IP, le nœud de sortie Tor, l'horodatage et le statut. - La fonction
updateProxyTable()s'exécute toutes les 10 secondes (viasetInterval) et lors de la création/suppression, en envoyant une requête AJAX GET à/api/proxy-gen/list(gérée parproxy_gen.py::list_proxies). - Le backend interroge la table
Proxy, vérifie l'état d'exécution de chaque conteneur (viacontainer_status.py::container_running), met à jour la base de données si nécessaire et renvoie une liste JSON des proxys. - La table est effacée et remplie avec les dernières données, affichant l'état « En cours » ou « Arrêté » avec des badges stylisés.
- Au chargement de la page, Jinja2 affiche les données initiales des proxys (
-
Suppression de proxy :
- Objectif : permet aux utilisateurs de supprimer un conteneur proxy.
- Interaction avec le backend :
- Chaque ligne de la table comporte un bouton « Supprimer » qui appelle
openDeleteModal(containerName)pour ouvrir une fenêtre modale de confirmation avec le nom du conteneur stocké dans un champ de saisie masqué. - Le bouton « Supprimer » de la fenêtre modale déclenche
confirmDeleteProxy(), qui envoie une requête AJAX DELETE à/api/proxy-gen/delete/{container_name}(gérée parproxy_gen.py::delete_proxy). - Le backend vérifie que le proxy existe dans la table
Proxy, supprime le conteneur (viarm_container.py::delete_container), supprime l'enregistrement de la base de données et ajoute un message flash de réussite à la session. - En cas de réussite, un message flash de réussite s'affiche (via
showFlashMessage) et la table est mise à jour. Les erreurs déclenchent un message flash d'erreur.
- Chaque ligne de la table comporte un bouton « Supprimer » qui appelle
Test
Exécutez l'application web :
sudo /home/hamy/tornet_scraper/venv/bin/python3 -m uvicorn app.main:app --reload
Ouvrez l'application web :
http://127.0.0.1:8000/proxy-gen
Créez un proxy :
