Aller au contenu
OmniRoute source

MITM TPROXY Transparent Decrypt (Français)

Les quatre autres modes de capture présentent chacun une limitation :

Mode Méthode de redirection du trafic Limitation
AgentBridge Usurpation DNS via /etc/hosts d’un ensemble fixe d’hôtes uniquement les hôtes d’agents IDE enregistrés
Hôtes personnalisés Usurpation DNS via /etc/hosts pour chaque hôte une entrée par hôte ; sudo pour modifier le fichier hosts
HTTP_PROXY Variables d’environnement HTTP_PROXY/HTTPS_PROXY uniquement les applications qui respectent la variable d’environnement
Proxy système Paramètres de proxy du système d’exploitation modifie l’état global ; nécessite une restauration

Le déchiffrement transparent TPROXY redirige plutôt le trafic au niveau du noyau. Il marque les nouvelles connexions TCP locales sortantes vers un port cible (443 par défaut) dans la chaîne mangle OUTPUT ; une règle ip rule redirige les paquets marqués vers une livraison locale et, lors de leur réentrée, la cible TPROXY de mangle PREROUTING les transmet à un listener IP_TRANSPARENT, qui termine ensuite TLS et capture le texte en clair.

Utilisez-le lorsque vous souhaitez capturer et déchiffrer le trafic d’un processus qui :

  • communique avec un hôte non enregistré par AgentBridge ;
  • ne respecte pas HTTP_PROXY ;
  • et que vous ne souhaitez pas perturber en modifiant le proxy à l’échelle du système.

Comme l’interception s’effectue dans le noyau, le processus d’origine ne nécessite aucune modification de configuration — mais il doit faire confiance à l’autorité de certification dynamique installée par OmniRoute (voir §4).


Exigence Détail
Système d’exploitation Linux uniquement — IP_TRANSPARENT est une option de socket propre à Linux. Le chargeur renvoie « indisponible » sur toutes les autres plateformes.
Privilèges La capacité CAP_NET_ADMIN pour créer le socket transparent et appliquer les règles iptables/ip — en pratique, exécutez en tant que root.
Addon natif Un petit addon N-API (src/mitm/tproxy/native/transparent.c) doit être compilé ou fourni sous forme de binaire précompilé. Voir §3.
Modules du noyau iptables avec la prise en charge de la cible TPROXY, de la table mangle et de la correspondance mark (validé avec le noyau 6.8.0).

Dégradation progressive : si une exigence n’est pas satisfaite (système autre que Linux, absence de chaîne d’outils, addon non compilé), le chargeur d’addon (src/mitm/tproxy/transparentSocket.ts::loadTransparentAddon) renvoie null au lieu de lever une exception. L’état du mode de capture indique alors available: false, le bouton d’activation du tableau de bord est désactivé avec l’infobulle « Le déchiffrement TPROXY nécessite Linux + root + l’addon natif », et le reste d’OmniRoute continue de fonctionner.


Le module net de Node ne peut pas appeler setsockopt(IP_TRANSPARENT) avant bind(), ce qu’exige TPROXY (sinon, le noyau abandonne les paquets redirigés). L’addon (src/mitm/tproxy/native/transparent.c, compilé via binding.gyp) est un petit module N-API qui expose trois fonctions, utilisées via transparentSocket.ts :

Fonction de l’addon Opérations sur le socket Utilisation
createTransparentListener(ip, port) socket() + SO_REUSEADDR + IP_TRANSPARENT + bind() + listen(), renvoie le fd brut l’écouteur de capture transparent (Node adopte le fd via server.listen({ fd }))
setSocketMark(fd, mark) setsockopt SO_MARK sur un fd existant prévention des boucles (marquage des propres sockets du proxy)
connectMarked(ip, port, mark) socket() + SO_MARK avant un connect() non bloquant, renvoie le fd le transfert réchiffré vers l’amont (le SYN porte la marque)

La destination d’origine est lue depuis socket.localAddress/localPort — TPROXY la préserve ; aucune recherche SO_ORIGINAL_DST/NAT n’est donc nécessaire.

Fenêtre de terminal
npm run build:native:tproxy # accède à src/mitm/tproxy/native et exécute node-gyp rebuild
# -> native/build/Release/transparent.node
  • Pendant npm run build, scripts/build/build-tproxy-native.mjs exécute node-gyp rebuild. Cette étape est réservée à Linux et non bloquante — l’absence de chaîne d’outils rend simplement le mode de capture indisponible.
  • assembleStandalone.mjs copie build/Release/transparent.node dans le paquet autonome ; transparentSocket.ts le recherche à la fois relativement au module et relativement au cwd (<cwd>/src/mitm/tproxy/native/...).
  • build/ et prebuilds/ sont ignorés par git — le binaire est compilé, jamais validé dans le dépôt.

Le chargeur recherche, par ordre de priorité : native/build/Release/transparent.node, puis native/prebuilds/transparent.node (à la fois relativement au module et sous <cwd>/src/mitm/tproxy/).


§4 L’AC dynamique par SNI et le programme d’installation du magasin de confiance

Section intitulée « §4 L’AC dynamique par SNI et le programme d’installation du magasin de confiance »

Mise à jour #6684 : le serveur statique AgentBridge (src/mitm/server.cjs) partage désormais cette même architecture d’AC et de certificats feuilles au lieu d’utiliser un unique certificat feuille autosigné statique. Il utilise une instance d’AC distincte (src/mitm/cert/rootCa.ts, persistée dans <DATA_DIR>/mitm/ca.key/ca.crt) et l’installe dans l’emplacement préexistant omniroute-mitm.crt du magasin de confiance (remplaçant l’ancien certificat feuille unique à cet emplacement — aucun nettoyage lié à une double approbation n’est nécessaire), qui reste entièrement séparé de l’emplacement omniroute-tproxy-ca.crt propre à TPROXY décrit ci-dessous. Les nouvelles installations d’AgentBridge bénéficient automatiquement du modèle d’AC ; une installation qui faisait déjà confiance à l’ancien certificat feuille statique continue de l’utiliser jusqu’à ce que l’opérateur choisisse d’activer MITM_ROOT_CA_ENABLED=true (voir src/mitm/cert/migration.ts) — une AC MITM approuvée capable de signer un certificat feuille pour n’importe quel hôte est considérablement plus puissante que l’ancien certificat feuille aux SAN fixes ; la transition n’est donc jamais silencieuse pour une installation qui lui fait déjà confiance.

Historiquement, le certificat MITM statique d’AgentBridge ne fonctionnait que parce qu’AgentBridge usurpe les DNS d’un ensemble d’hôtes fixe (désormais unifié avec le modèle ci-dessous). TPROXY intercepte des hôtes arbitraires ; son écouteur doit donc présenter un certificat feuille valide pour tout SNI demandé par le client — la même exigence qu’AgentBridge doit désormais respecter pour l’ensemble complet MITM_TOOL_HOSTS (9 entrées d’outils), au lieu des seuls 4 hôtes antigravity.

DynamicCertStore exécute une AC locale (basée sur la dépendance selfsigned) qui :

  • Génère une AC à longue durée de vie via generateMitmCa() (CN "OmniRoute MITM CA", validité de 10 ans, basicConstraints CA=true + keyUsage keyCertSign,cRLSign, RSA 2048 bits / SHA-256).
  • Émet à la demande un certificat feuille par nom d’hôte SNI via issueLeafCert() (validité de 1 an, subjectAltName = l’hôte SNI) et met en cache un tls.SecureContext par nom d’hôte.
  • Expose createSNICallback() pour le serveur qui termine la connexion TLS (voir §5).
  • Peut être construit avec une existingCa afin de maintenir l’AC stable entre les redémarrages (ainsi, il n’est pas nécessaire de la réinstaller dans le magasin de confiance).

La clé privée de l’AC ne quitte jamais la machine.

Programme d’installation du magasin de confiance (src/mitm/tproxy/caTrust.ts)

Section intitulée « Programme d’installation du magasin de confiance (src/mitm/tproxy/caTrust.ts) »

Le client intercepté doit faire confiance à l’AC dynamique ; le démarrage du mode de capture installe donc le certificat de l’AC dans le magasin de confiance du système d’exploitation, dans un emplacement dédié — omniroute-tproxy-ca.crt (constante TPROXY_CA_CERT_NAME) — maintenu séparément de l’emplacement du certificat MITM statique (omniroute-mitm.crt), afin que les deux ne s’écrasent jamais mutuellement.

installTproxyCa(caPem, sudoPassword?) détecte le répertoire d’ancres de la distribution (dans l’ordre suivant : style Debian en premier) et exécute la commande d’actualisation correspondante :

Répertoire d’ancres Commande d’actualisation
/usr/local/share/ca-certificates update-ca-certificates
/etc/ca-certificates/trust-source/anchors update-ca-trust
/etc/pki/ca-trust/source/anchors update-ca-trust
/etc/pki/trust/anchors update-ca-certificates

L’installation place d’abord le PEM dans un fichier temporaire, puis exécute (avec des privilèges) mkdir -p sur le répertoire d’ancres, utilise cp pour y copier le fichier temporaire et exécute la commande d’actualisation. uninstallTproxyCa() supprime uniquement l’emplacement dédié (sans toucher au certificat MITM statique), puis actualise le magasin — sans effet sur les systèmes autres que Linux.

Toutes les commandes privilégiées sont exécutées via execFileWithPassword (src/mitm/systemCommands.ts) — spawn avec des tableaux d’arguments, sans shell ni interpolation de chaînes (règle absolue nº 13). Lorsque le processus s’exécute en tant que root (par exemple sur le VPS), la cible est exécutée directement et aucun mot de passe n’est nécessaire ; sur un poste de travail non-root, sudoPassword est transmis via sudo -S sur stdin.

Le sudoPassword du poste de travail est fourni dans le corps de la requête POST afin d’autoriser l’installation dans le magasin de confiance ; il est entièrement ignoré lorsque le processus s’exécute en tant que root.


§5 Fonctionnement du déchiffrement et de la capture

Section intitulée « §5 Fonctionnement du déchiffrement et de la capture »

Le pipeline (entièrement sous src/mitm/tproxy/) :

application locale ──TCP/443──▶ mangle OUTPUT marque la connexion (fwmark)
ip rule → table de routage locale → lo
mangle PREROUTING TPROXY → écouteur IP_TRANSPARENT (port 8443)
│ captureMode.ts : lit la destination d’origine depuis socket.localAddress
▼
tlsCapture.ts :
1. termine TLS côté CLIENT avec un certificat feuille propre à chaque SNI (dynamicCert)
2. un http.Server interne analyse le texte en clair déchiffré
3. capture → globalTrafficBuffer.push() avec source: "tproxy"
(sanitizeHeaders + maskSecret appliqués)
4. transfère les données RECHIFFRÉES vers la destination d’origine
via un socket marqué pour le contournement (connectMarked, anti-boucle)
│
▼
serveur amont d’origine (api.example.com)
  • Terminaison TLS (createTlsCaptureServer) : encapsule le socket brut intercepté dans un tls.TLSSocket côté serveur à l’aide du callback SNI de l’autorité de certification dynamique, puis transmet le flux déchiffré à un http.Server interne (la technique standard de terminaison MITM). La durée de vie des sockets est limitée par MITM_IDLE_TIMEOUT_MS afin qu’un tunnel bloqué ne puisse pas épuiser les descripteurs de fichiers.
  • Capture (handleDecryptedRequest) : ajoute un InterceptedRequest avec source: "tproxy", un statut initial "in-flight", les en-têtes traités par sanitizeHeaders() et les corps par maskSecret() avant leur entrée dans le tampon. L’entrée est ensuite mise à jour avec la réponse, les tailles et la latence.
  • Transfert rechiffré (createForward / realForward) : rechiffre les données vers la destination d’origine. rejectUnauthorized vaut true par défaut (sécurisé par défaut) — le certificat du serveur amont est vérifié par rapport au SNI/Host demandé par le client, de sorte que le proxy rejette exactement ce que le client d’origine aurait rejeté.

Comme les règles marquent les nouvelles connexions sortantes locales, le transfert rechiffré du proxy lui-même serait normalement intercepté à nouveau, créant ainsi une boucle infinie. Le chemin de transfert empêche cela grâce à une marque de contournement sur le socket (SO_MARK) :

  • realForward ouvre son socket vers le serveur amont via connectMarked(ip, port, DEFAULT_BYPASS_MARK) — DEFAULT_BYPASS_MARK = 0x539 — qui définit SO_MARK avant connect(), de sorte que le SYN du transfert porte la marque de contournement.
  • La règle mangle OUTPUT exclut les connexions portant déjà la marque de contournement (-m mark ! --mark &lt;bypassMark&gt;), de sorte que le transfert du proxy n’est pas marqué de nouveau et ne repasse pas par TPROXY.

Remarque d’implémentation : le socket portant la marque de contournement doit être installé sur createConnection de l’agent (https.request({ createConnection }) est silencieusement ignoré lorsqu’un agent est présent), sans quoi le transfert ouvrirait un socket non marqué et la boucle réapparaîtrait. Ce correctif anti-boucle a été validé par des tests e2e.


Contrôle Détail
API limitée à l’interface de bouclage /api/tools/agent-bridge/tproxy est couvert par le préfixe /api/tools/agent-bridge/ dans LOCAL_ONLY_API_PREFIXES (src/server/authz/routeGuard.ts). Le contrôle de l’interface de bouclage s’exécute avant l’authentification (règles strictes nº 15 et nº 17) — un JWT divulgué via un tunnel ne peut pas démarrer la capture TPROXY, qui applique des règles iptables et installe une AC dans le magasin de confiance au moyen de processus enfants.
Emplacement dédié pour l’AC L’AC dynamique est installée sous omniroute-tproxy-ca.crt, sans jamais écraser le certificat MITM statique.
La clé de l’AC ne quitte jamais l’hôte DynamicCertStore conserve la clé de l’AC en mémoire ; elle n’est pas exportée.
Masquage des secrets maskSecret() sur les corps des requêtes/réponses et sanitizeHeaders() sur les en-têtes sont exécutés avant globalTrafficBuffer.push().
Aucune interpolation de shell Toutes les commandes iptables/ip/du magasin de confiance sont exécutées via execFile/execFileWithPassword avec des tableaux d’arguments (règle stricte nº 13).
Vérification du certificat en amont Le transfert rechiffré vérifie par défaut le certificat en amont (rejectUnauthorized: true).
Assainissement des erreurs Les réponses d’erreur de la route passent par sanitizeErrorMessage() (règle stricte nº 12).

L’AC MITM constitue une capacité puissante. Une AC approuvée par le système d’exploitation et capable de signer pour n’importe quel hôte permet de déchiffrer tout ce qu’OmniRoute intercepte. Elle est protégée par le mode de capture TPROXY explicite, limité à l’accès local et désactivé par défaut, et l’entrée du magasin de confiance est supprimée lorsque vous arrêtez ce mode.


§7 Application / annulation transactionnelle du pare-feu

Section intitulée « §7 Application / annulation transactionnelle du pare-feu »

Un plantage ne doit jamais laisser derrière lui une règle mangle ou une route obsolète. Le générateur de commandes (src/mitm/tproxy/commands.ts) et l’exécuteur (src/mitm/tproxy/setup.ts) garantissent que l’annulation est l’inverse exact de l’application, dans l’ordre inverse.

applyTproxy(cfg) exécute les commandes d’application dans l’ordre ; en cas de n’importe quel échec, cette fonction exécute une opération revertTproxy(cfg) complète au mieux, puis relance l’exception — le pare-feu est donc soit entièrement appliqué, soit entièrement annulé, mais jamais partiellement appliqué. revertTproxy(cfg) exécute les commandes inverses dans l’ordre inverse et ignore les échecs (opération idempotente — elle peut être appelée sans condition, par exemple depuis le nettoyage repairMitm() d’AgentBridge).

validateTproxyConfig(cfg) s’exécute avant toute commande : les ports doivent être compris entre 1–65535, mark/routeTable/bypassMark doivent être des entiers positifs, et bypassMark doit être différent de mark (anti-boucle).

Fenêtre de terminal
ip rule add fwmark &lt;mark&gt; lookup &lt;routeTable&gt;
ip route add local 0.0.0.0/0 dev lo table &lt;routeTable&gt;
iptables -t mangle -A OUTPUT -p tcp --dport &lt;dport&gt; -m mark ! --mark &lt;bypassMark&gt; -j MARK --set-mark &lt;mark&gt;
iptables -t mangle -A PREROUTING -p tcp --dport &lt;dport&gt; -m mark --mark &lt;mark&gt; -j TPROXY --on-port &lt;onPort&gt; --tproxy-mark &lt;mark&gt;

L’annulation les supprime dans l’ordre inverse : PREROUTING -D, OUTPUT -D, ip route del, ip rule del.

Cette procédure est basée sur OUTPUT, car le cas d’utilisation MITM concerne le trafic sortant local (les applications sur le même hôte), que TPROXY dans PREROUTING seul ne voit pas — PREROUTING ne voit que le trafic transféré. La chaîne OUTPUT marque les nouvelles connexions locales, la règle ip rule les redirige vers la remise locale (lo), puis PREROUTING les affecte au point d’écoute transparent.


La requête de démarrage (POST /api/tools/agent-bridge/tproxy) accepte les champs suivants, validés par StartTproxyBodySchema (tproxy/route.ts). Ils sont tous facultatifs et utilisent leurs valeurs par défaut lorsqu’ils sont omis :

Champ Type Valeur par défaut Remarques
dport int (1–65535) 443 Port TCP de destination à intercepter de manière transparente
mark int (≥1) 0x2333 Marque de pare-feu définie dans OUTPUT, utilisée par la règle ip rule et par PREROUTING
onPort int (1–65535) 8443 Port auquel se lie le point d’écoute transparent (IP_TRANSPARENT)
routeTable int (≥1) 233 Identifiant de la table de routage par stratégies contenant la route local 0.0.0.0/0
bypassMark int (≥1, ≠ mark) 0x539 Marque de socket de contournement (SO_MARK) définie par le proxy sur ses propres connexions en amont ; exclue dans OUTPUT (anti-boucle)
sudoPassword string — Uniquement pour les environnements de bureau non-root : autorise l’installation dans le magasin de confiance ; ignoré en tant que root

Il n’existe aucune variable d’environnement pour TPROXY — toute la configuration s’effectue via le corps de la requête POST ou les valeurs par défaut ci-dessus.


  1. Ouvrez l’Inspecteur de trafic (/dashboard/tools/traffic-inspector).
  2. Dans la barre d’outils des modes de capture, recherchez le bouton « Déchiffrement TPROXY » ⚠ (src/app/(dashboard)/dashboard/tools/traffic-inspector/components/CaptureModesToolbar.tsx).
    • S’il est désactivé avec l’infobulle « Le déchiffrement TPROXY nécessite Linux + les droits root + l’extension native », l’extension native n’est pas disponible sur cet hôte (système autre que Linux, absence de chaîne d’outils ou extension non compilée). Consultez les §2 et §3.
  3. Cliquez sur le bouton. Il appelle POST /api/tools/agent-bridge/tproxy via startTproxyCaptureMode() (src/lib/inspector/tproxyCaptureApi.ts), qui : génère l’AC dynamique, ouvre l’écouteur transparent, applique les règles du pare-feu et installe l’AC dans le magasin de certificats de confiance du système d’exploitation.
  4. Lorsqu’il est actif, le bouton devient orange et affiche le nombre d’interceptions en temps réel (· &lt;interceptCount&gt;). Les requêtes interceptées apparaissent dans la liste des requêtes avec source: "tproxy".
  5. Cliquez à nouveau pour l’arrêter — DELETE /api/tools/agent-bridge/tproxy via stopTproxyCaptureMode() ferme l’écouteur, désinstalle l’AC et annule les règles du pare-feu.

L’état du mode de capture (actif / disponible / nombre d’interceptions / port d’écoute) provient de GET /api/tools/agent-bridge/tproxy (getCaptureStatus() dans src/mitm/tproxy/captureManager.ts). Une seule session TPROXY peut être active à la fois — toute tentative d’en démarrer une seconde est rejetée avec le message « Le mode de capture TPROXY est déjà actif ».


L’extension native ne peut pas être chargée. Vérifiez que vous utilisez Linux, que vous avez compilé l’extension (npm run build:native:tproxy) et que le processus peut charger transparent.node. isTransparentSocketAvailable() contrôle l’activation du bouton ; GET /api/tools/agent-bridge/tproxy renvoie available: false lorsque l’extension est absente.

  • Vérifiez que le processus intercepté se connecte effectivement au dport configuré (valeur par défaut : 443).
  • Vérifiez que le processus fait confiance à l’AC dynamique. L’AC est installée sous le nom omniroute-tproxy-ca.crt ; les applications disposant de leur propre magasin de certificats de confiance (NSS de Firefox/Chrome) peuvent nécessiter que le certificat y soit également ajouté.
  • Exécutez l’autotest Diagnose d’AgentBridge (consultez AGENTBRIDGE.md) pour vérifier que le certificat est approuvé et que le serveur fonctionne correctement.

revertTproxy() est l’inverse exact de l’application et est idempotente. L’arrêt du mode annule les règles ; si OmniRoute a été interrompu pendant une session, utilisez l’action Repair d’AgentBridge (POST /api/tools/agent-bridge/repair) pour annuler l’état système orphelin (usurpation DNS, AC racine, proxy système). Les règles TPROXY mangle et la route sont également automatiquement supprimées au redémarrage.

Boucle infinie / le proxy intercepte son propre transfert

Section intitulée « Boucle infinie / le proxy intercepte son propre transfert »

Il s’agit du cas traité par la protection anti-boucle. Vérifiez que bypassMark diffère de mark (la validation l’impose) et que le transfert utilise connectMarked (c’est le cas dans realForward). Consultez §5 Protection anti-boucle.


Fichier Responsabilité
src/mitm/tproxy/commands.ts Générateur pur de commandes iptables/ip d’application et d’annulation ; validateTproxyConfig
src/mitm/tproxy/setup.ts Exécuteur transactionnel applyTproxy / revertTproxy (annulation en cas d’échec)
src/mitm/tproxy/transparentSocket.ts Chargeur de l’extension native (loadTransparentAddon), createTransparentListenerFd, connectMarked, setSocketMark, isTransparentSocketAvailable
src/mitm/tproxy/native/transparent.c Extension N-API : createTransparentListener (IP_TRANSPARENT), setSocketMark, connectMarked
src/mitm/tproxy/native/binding.gyp Manifeste de compilation node-gyp
src/mitm/tproxy/dynamicCert.ts DynamicCertStore — AC dynamique par SNI + cache des certificats terminaux
src/mitm/tproxy/caTrust.ts Installation/désinstallation dans le magasin de certificats de confiance du système (installTproxyCa / uninstallTproxyCa, emplacement dédié)
src/mitm/tproxy/tlsCapture.ts Moteur de déchiffrement avec terminaison TLS + transfert rechiffré protégé contre les boucles
src/mitm/tproxy/captureMode.ts Orchestration de l’écouteur transparent ; lit la destination d’origine depuis socket.localAddress
src/mitm/tproxy/captureManager.ts Cycle de vie du singleton : startCaptureMode / stopCaptureMode / getCaptureStatus
src/app/api/tools/agent-bridge/tproxy/route.ts Route GET / POST / DELETE (LOCAL_ONLY)
src/lib/inspector/tproxyCaptureApi.ts Fonctions clientes de récupération (fetchTproxyStatus / startTproxyCaptureMode / stopTproxyCaptureMode)

Code source d’OmniRoute (a58000c7685f)

HagiCode

HagiCode est un espace de développement agentique qui associe workflows structurés, exécution multi-agent et vues Hero Dungeon.

Transformez vos idées en logiciels utiles grâce à un workflow agentique plus intelligent, rapide et agréable.

Interface principale de HagiCode en thème clair
  • SmartDes workflows structurés transforment une intention en parcours exécutable, de l’idée à la livraison.
  • EfficientLes workflows multi-agents font avancer recherche, réalisation et revue en parallèle.
  • FunHero Dungeon rend les longues sessions de code plus visuelles et collaboratives.
Visiter HagiCode