MITM TPROXY Transparent Decrypt (中文 (繁體))
§1 功能與使用時機
Section titled “§1 功能與使用時機”其他四種擷取模式各有一項限制:
| 模式 | 流量導向方式 | 限制 |
|---|---|---|
| AgentBridge | 透過 /etc/hosts 對固定主機集合進行 DNS 偽造 |
僅限已註冊的 IDE 代理程式主機 |
| 自訂主機 | 透過 /etc/hosts 對每個主機進行 DNS 偽造 |
每個主機需要一筆項目;編輯 hosts 需要 sudo |
| HTTP_PROXY | HTTP_PROXY/HTTPS_PROXY 環境變數 |
僅適用於遵循環境變數的應用程式 |
| 全系統代理 | 作業系統代理設定 | 變更全域狀態;需要還原 |
TPROXY 透明解密改為在核心層導向流量。它會在
mangle OUTPUT 鏈中標記前往目標連接埠(預設為 443)的新本機對外 TCP 連線,再由 ip rule 將已標記的封包重新路由至本機遞送;封包重新進入後,mangle PREROUTING 的 TPROXY 目標會將其交給
IP_TRANSPARENT 接聽程式——該程式接著終止 TLS 並擷取明文。
若您想擷取並解密來自符合以下條件之程序的流量,請使用此模式:
- 連線至 AgentBridge 未註冊的主機,且
- 不遵循
HTTP_PROXY,且 - 您不希望透過變更全系統代理設定來干擾該程序。
由於攔截發生在核心中,來源程序不需要變更任何設定——但該程序必須信任 OmniRoute 安裝的動態 CA(請參閱§4)。
§2 系統需求
Section titled “§2 系統需求”| 需求 | 詳細資訊 |
|---|---|
| 作業系統 | 僅限 Linux — IP_TRANSPARENT 是 Linux 專用的 socket 選項。在其他所有平台上,載入器都會回傳「不可用」。 |
| 權限 | 需要 CAP_NET_ADMIN capability,才能建立透明 socket 並套用 iptables/ip 規則 — 實務上應以 root 身分執行。 |
| 原生 addon | 必須建置或以預先建置版本提供一個小型 N-API addon(src/mitm/tproxy/native/transparent.c)。請參閱 §3。 |
| 核心模組 | iptables 須支援 TPROXY、mangle 與 mark 比對功能(已針對 kernel 6.8.0 驗證)。 |
優雅降級:若缺少任何需求(非 Linux、無工具鏈、
addon 未建置),addon 載入器(src/mitm/tproxy/transparentSocket.ts::loadTransparentAddon)
會回傳 null,而不是擲出例外。接著,擷取模式狀態會回報
available: false,儀表板切換開關會被停用,並顯示工具提示
「TPROXY 解密需要 Linux + root + 原生 addon」,而 OmniRoute 的其餘部分
仍會繼續運作。
§3 原生 IP_TRANSPARENT addon
Section titled “§3 原生 IP_TRANSPARENT addon”Node 的 net 模組無法在 bind() 之前 呼叫 setsockopt(IP_TRANSPARENT),而這是
TPROXY 的必要條件(否則核心會丟棄重新導向的封包)。此 addon
(src/mitm/tproxy/native/transparent.c,透過 binding.gyp 建置)是一個小型 N-API
模組,公開三個函式,並透過 transparentSocket.ts 使用:
| Addon 函式 | Socket 操作 | 用途 |
|---|---|---|
createTransparentListener(ip, port) |
socket() + SO_REUSEADDR + IP_TRANSPARENT + bind() + listen(),回傳原始 fd |
透明擷取監聽器(Node 透過 server.listen({ fd }) 接管 fd) |
setSocketMark(fd, mark) |
對現有 fd 執行 setsockopt SO_MARK |
防止迴圈(標記 proxy 自身的 socket) |
connectMarked(ip, port, mark) |
socket() + 在非阻塞 connect() 之前設定 SO_MARK,回傳 fd |
重新加密後的上游轉送(SYN 會攜帶該標記) |
原始目的地會從 socket.localAddress/localPort 讀取 — TPROXY
會保留該資訊,因此不需要查詢 SO_ORIGINAL_DST/NAT。
建置 addon
Section titled “建置 addon”npm run build:native:tproxy # cd src/mitm/tproxy/native && node-gyp rebuild # -> native/build/Release/transparent.node- 執行
npm run build時,scripts/build/build-tproxy-native.mjs會執行node-gyp rebuild。此操作僅限 Linux,且失敗不會中止流程 — 缺少工具鏈只會導致 擷取模式無法使用。 assembleStandalone.mjs會將build/Release/transparent.node複製至 獨立套件中;transparentSocket.ts會分別以模組相對路徑與 cwd 相對路徑(<cwd>/src/mitm/tproxy/native/...)解析該檔案。build/與prebuilds/已由 git 忽略 — 二進位檔會建置,但絕不 提交。
載入器會依優先順序探測:
native/build/Release/transparent.node,接著是 native/prebuilds/transparent.node
(兩者皆會從模組相對路徑及 <cwd>/src/mitm/tproxy/ 下探測)。
§4 各 SNI 的動態 CA 與信任存放區安裝程式
Section titled “§4 各 SNI 的動態 CA 與信任存放區安裝程式”#6684 更新:AgentBridge 靜態伺服器(
src/mitm/server.cjs)現在 也採用相同的 CA/葉憑證架構模式,而不再使用單一靜態 自簽葉憑證。它使用一個獨立的 CA 執行個體 (src/mitm/cert/rootCa.ts,持久化於<DATA_DIR>/mitm/ca.key/ca.crt) 並安裝至既有的omniroute-mitm.crt信任存放區位置 (取代該位置舊有的單一葉憑證——無須進行雙重信任清理), 與下方 TPROXY 自己的omniroute-tproxy-ca.crt位置完全分開。 全新安裝的 AgentBridge 會自動採用 CA 模型;已經信任舊靜態葉憑證的 現有安裝則會繼續使用該憑證,直到操作者透過MITM_ROOT_CA_ENABLED=true主動選擇啟用為止(請參閱src/mitm/cert/migration.ts)——能夠為任何主機簽署葉憑證的受信任 MITM CA,其權限實質上遠高於舊有的固定 SAN 葉憑證,因此對於已信任 舊憑證的安裝,此切換絕不會在未告知的情況下進行。
過去,靜態 AgentBridge MITM 憑證之所以能運作,只是因為 AgentBridge
僅對一組固定的主機進行 DNS 欺騙(現在已與下方模型統一)。TPROXY
會攔截任意主機,因此其監聽器必須針對用戶端請求的任何 SNI
提供有效的葉憑證——這也是 AgentBridge 現在針對完整
MITM_TOOL_HOSTS 集合(9 個工具項目)所具有的相同需求,而不再只限於
4 個 antigravity 主機。
動態 CA(src/mitm/tproxy/dynamicCert.ts)
Section titled “動態 CA(src/mitm/tproxy/dynamicCert.ts)”DynamicCertStore 會執行本機 CA(以 selfsigned 相依套件建構),其功能包括:
- 透過
generateMitmCa()產生長效 CA(CN"OmniRoute MITM CA"、 有效期 10 年、basicConstraints CA=true+keyUsage keyCertSign,cRLSign、 2048 位元 RSA/SHA-256)。 - 透過
issueLeafCert()按需為每個 SNI 主機名稱簽發一張葉憑證(有效期 1 年,subjectAltName= SNI 主機),並為每個主機名稱快取一個tls.SecureContext。 - 為終止 TLS 的伺服器公開
createSNICallback()(請參閱 §5)。 - 建構時可傳入
existingCa,使 CA 在重新啟動後仍保持不變 (因此無須重新安裝至信任存放區)。
CA 私密金鑰永遠不會離開該機器。
信任存放區安裝程式(src/mitm/tproxy/caTrust.ts)
Section titled “信任存放區安裝程式(src/mitm/tproxy/caTrust.ts)”遭攔截的用戶端必須信任動態 CA,因此啟動擷取模式時,
會將 CA 憑證安裝至作業系統信任存放區中的專用位置——
omniroute-tproxy-ca.crt(常數 TPROXY_CA_CERT_NAME)——並與
靜態 MITM 憑證的位置(omniroute-mitm.crt)分開,確保兩者絕不會
互相覆寫。
installTproxyCa(caPem, sudoPassword?) 會偵測發行版的錨點目錄
(依序偵測,優先採用 Debian 樣式),並執行對應的重新整理命令:
| 錨點目錄 | 重新整理命令 |
|---|---|
/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 |
安裝時會先將 PEM 暫存至臨時檔案,接著以高權限執行 mkdir -p
建立錨點目錄、使用 cp 將暫存檔案複製至其中,然後執行重新整理命令。
uninstallTproxyCa() 僅會移除專用位置(不影響靜態 MITM 憑證)
並重新整理;在非 Linux 系統上則不執行任何操作。
所有高權限命令都會透過 execFileWithPassword(src/mitm/systemCommands.ts)
執行——使用帶有引數陣列、不經 shell、不進行字串插值的 spawn
(強制規則 #13)。當處理程序以 root 身分執行時(例如在 VPS 上),
目標命令會直接執行,且不需要密碼;在非 root 的桌面環境中,
sudoPassword 會透過 stdin 傳遞給 sudo -S。
桌面環境的
sudoPassword會在 POST 主體中提供,用於授權安裝 信任存放區;當處理程序以 root 身分執行時,則會完全忽略該值。
§5 解密與擷取的運作方式
Section titled “§5 解密與擷取的運作方式”處理管線(全部位於 src/mitm/tproxy/ 下):
本機應用程式 ──TCP/443──▶ mangle OUTPUT 標記連線(fwmark) ip rule → 本機路由表 → lo mangle PREROUTING TPROXY → IP_TRANSPARENT 接聽器(連接埠 8443) │ captureMode.ts:從 socket.localAddress 讀取原始目的地 ▼ tlsCapture.ts: 1. 使用依 SNI 產生的分支憑證終止用戶端的 TLS(dynamicCert) 2. 內部 http.Server 解析解密後的明文 3. 擷取 → globalTrafficBuffer.push(),source: "tproxy" (套用 sanitizeHeaders + maskSecret) 4. 透過帶有繞過標記的 socket,重新加密並轉送至原始目的地 (connectMarked,防迴圈) │ ▼ 原始上游(api.example.com)- TLS 終止(
createTlsCaptureServer):使用動態 CA 的 SNI 回呼,將攔截到的原始 socket 包裝於伺服器端tls.TLSSocket中,接著把解密後的串流交給內部http.Server(標準的 MITM 終止技巧)。Socket 的存續時間受MITM_IDLE_TIMEOUT_MS限制,因此掛起的隧道無法耗盡檔案描述符。 - 擷取(
handleDecryptedRequest):推送一個InterceptedRequest,其中source: "tproxy"、狀態起始為"in-flight";標頭會先經過sanitizeHeaders(),本文則會先經過maskSecret(),之後才進入緩衝區。 接著會以回應、大小與延遲資訊更新該項目。 - 重新加密轉送(
createForward/realForward):重新加密後轉送至原始 目的地。rejectUnauthorized預設為true(預設安全)——上游憑證會依據 用戶端所要求的 SNI/Host 進行驗證,因此原始用戶端會拒絕的情況,代理伺服器也會拒絕。
防迴圈(SO_MARK)
Section titled “防迴圈(SO_MARK)”由於規則會標記新的本機對外連線,因此代理伺服器本身經重新加密的轉送通常也會被再次攔截, 從而形成無限迴圈。轉送路徑使用繞過 socket 標記(SO_MARK)來防止此問題:
realForward透過connectMarked(ip, port, DEFAULT_BYPASS_MARK)開啟其上游 socket ——DEFAULT_BYPASS_MARK = 0x539——此函式會在connect()之前設定 SO_MARK,因此轉送連線的 SYN 會帶有繞過標記。mangle OUTPUT規則會排除已帶有繞過標記的連線 (-m mark ! --mark <bypassMark>),因此代理伺服器的轉送連線不會被重新標記, 也不會再次進入 TPROXY。
實作注意事項:帶有繞過標記的 socket 必須安裝於 agent 的
createConnection上(當存在 agent 時,https.request({ createConnection })會被無提示地忽略),否則轉送會開啟未標記的 socket,導致迴圈再次出現。 這是經端對端驗證的防迴圈修正。
§6 安全性
Section titled “§6 安全性”| 控制措施 | 詳細資訊 |
|---|---|
| 僅限迴路位址的 API | /api/tools/agent-bridge/tproxy 涵蓋於 LOCAL_ONLY_API_PREFIXES(src/server/authz/routeGuard.ts)中的 /api/tools/agent-bridge/ 前綴。迴路位址限制會在驗證之前執行(硬性規則 #15 + #17)——透過通道洩漏的 JWT 無法啟動 TPROXY 擷取;此功能會套用 iptables 規則,並透過子行程安裝信任存放區 CA。 |
| 專用 CA 插槽 | 動態 CA 會安裝至 omniroute-tproxy-ca.crt,絕不覆寫靜態 MITM 憑證。 |
| CA 金鑰絕不離開主機 | DynamicCertStore 將 CA 金鑰保留在記憶體中;不會將其匯出。 |
| 機密資訊遮罩 | 在執行 globalTrafficBuffer.push() 之前,會對請求/回應主體執行 maskSecret(),並對標頭執行 sanitizeHeaders()。 |
| 無 shell 插值 | 所有 iptables/ip/信任存放區命令皆透過 execFile/execFileWithPassword 搭配引數陣列執行(硬性規則 #13)。 |
| 上游憑證驗證 | 重新加密的轉送預設會驗證上游憑證(rejectUnauthorized: true)。 |
| 錯誤清理 | 此路由的錯誤回應會經過 sanitizeErrorMessage() 處理(硬性規則 #12)。 |
MITM CA 是一項功能強大的能力。 受作業系統信任且能為任何 主機簽署憑證的 CA,意味著 OmniRoute 攔截的任何內容都能被解密。此功能僅能透過 明確啟用且僅限本機的 TPROXY 擷取模式使用,預設為關閉,且當您停止此模式時, 信任存放區項目也會被移除。
§7 交易式防火牆套用 / 還原
Section titled “§7 交易式防火牆套用 / 還原”當程式崩潰時,絕不能遺留 mangle 規則或過時的路由。命令建構器
(src/mitm/tproxy/commands.ts)與執行器(src/mitm/tproxy/setup.ts)保證
還原操作會以相反順序,精確反轉套用操作。
applyTproxy(cfg) 會依序執行套用命令;若發生任何失敗,它會以盡力而為的方式執行完整的
revertTproxy(cfg),然後重新擲出錯誤——因此防火牆不是完全套用,
就是完全還原,絕不會處於僅套用一部分的狀態。revertTproxy(cfg) 會以相反順序執行
反向命令並忽略失敗(具冪等性——可安全地無條件呼叫,
例如從 AgentBridge 的 repairMitm() 清理流程中呼叫)。
validateTproxyConfig(cfg) 會在任何命令之前執行:連接埠必須介於 1–65535,
mark/routeTable/bypassMark 必須是正整數,且 bypassMark 必須
與 mark 不同(防止迴圈)。
套用命令(依序)
Section titled “套用命令(依序)”ip rule add fwmark <mark> lookup <routeTable>ip route add local 0.0.0.0/0 dev lo table <routeTable>iptables -t mangle -A OUTPUT -p tcp --dport <dport> -m mark ! --mark <bypassMark> -j MARK --set-mark <mark>iptables -t mangle -A PREROUTING -p tcp --dport <dport> -m mark --mark <mark> -j TPROXY --on-port <onPort> --tproxy-mark <mark>還原會以相反順序刪除它們:PREROUTING -D、OUTPUT -D、ip route del、ip rule del。
此配置方式以 OUTPUT 為基礎,因為 MITM 使用案例是_本機_對外 流量(同一主機上的應用程式),而僅位於
PREROUTING中的 TPROXY 無法看見這些流量——PREROUTING只能看見轉送流量。OUTPUT鏈會標記新的 本機連線,ip rule會將它們重新路由至本機傳遞(lo),接著PREROUTING會將它們指派給透明監聽器。
啟動請求(POST /api/tools/agent-bridge/tproxy)接受以下
欄位,並由 StartTproxyBodySchema(tproxy/route.ts)驗證。所有欄位皆為選填,
未提供時會使用其預設值:
| 欄位 | 類型 | 預設值 | 說明 |
|---|---|---|---|
| dport | int (1–65535) | 443 |
要透明攔截的目的 TCP 連接埠 |
| mark | int (≥1) | 0x2333 |
在 OUTPUT 上設定的防火牆標記,由 ip rule + PREROUTING 比對 |
| onPort | int (1–65535) | 8443 |
透明(IP_TRANSPARENT)監聽器繫結的連接埠 |
| routeTable | int (≥1) | 233 |
保存 local 0.0.0.0/0 路由的策略路由表 ID |
| bypassMark | int (≥1, ≠ mark) |
0x539 |
Proxy 為其自身上游連線設定的略過通訊端標記(SO_MARK);在 OUTPUT 中予以排除(防止迴圈) |
| sudoPassword | string | — | 僅適用於非 root 桌面環境:授權安裝信任儲存區;以 root 身分執行時會忽略 |
TPROXY 沒有任何環境變數——所有組態皆透過 POST 主體或上述預設值提供。
§9 從流量檢查器啟用
Section titled “§9 從流量檢查器啟用”- 開啟 流量檢查器(
/dashboard/tools/traffic-inspector)。 - 在擷取模式工具列中,找到 「TPROXY 解密」 ⚠ 按鈕
(
src/app/(dashboard)/dashboard/tools/traffic-inspector/components/CaptureModesToolbar.tsx)。 - 按一下該按鈕。它會透過
startTproxyCaptureMode()(src/lib/inspector/tproxyCaptureApi.ts)呼叫POST /api/tools/agent-bridge/tproxy,其會: 建置動態 CA、開啟透明監聽器、套用防火牆規則, 並將 CA 安裝至作業系統的信任存放區。 - 執行時,切換按鈕會變為琥珀色,並顯示即時攔截計數
(
· <interceptCount>)。遭攔截的請求會出現在請求清單中,並帶有source: "tproxy"。 - 再按一下即可停止——透過
stopTproxyCaptureMode()呼叫DELETE /api/tools/agent-bridge/tproxy,這會關閉監聽器、解除安裝 CA, 並還原防火牆規則。
擷取模式狀態(執行中/可用性/攔截計數/監聽器連接埠)來自
GET /api/tools/agent-bridge/tproxy(位於
src/mitm/tproxy/captureManager.ts 的 getCaptureStatus())。一次只能執行一個 TPROXY 工作階段——
嘗試啟動第二個工作階段時,會遭到拒絕並顯示「TPROXY capture mode is already running」。
§10 疑難排解
Section titled “§10 疑難排解”切換按鈕已停用
Section titled “切換按鈕已停用”原生附加元件無法載入。請確認:您使用的是 Linux、已建置附加元件
(npm run build:native:tproxy),且程序能夠載入 transparent.node。
isTransparentSocketAvailable() 會控制切換按鈕;缺少附加元件時,GET /api/tools/agent-bridge/tproxy
會傳回 available: false。
未擷取到任何內容
Section titled “未擷取到任何內容”- 確認遭攔截的程序確實連線至已設定的
dport(預設為443)。 - 確認該程序信任動態 CA。CA 會以
omniroute-tproxy-ca.crt的名稱安裝;使用自身信任存放區的應用程式(Firefox/Chrome NSS) 可能也需要將憑證加入該存放區。 - 執行 AgentBridge 的 Diagnose 自我測試(請參閱
AGENTBRIDGE.md),以進行憑證信任/伺服器 健康狀態檢查。
當機後殘留的防火牆規則
Section titled “當機後殘留的防火牆規則”revertTproxy() 與套用操作完全相反,且具有冪等性。停止該模式會還原規則;
如果 OmniRoute 在工作階段進行期間遭到終止,請使用 AgentBridge 的
Repair 動作(POST /api/tools/agent-bridge/repair)復原遺留的系統
狀態(DNS 欺騙、根 CA、系統代理伺服器)。TPROXY mangle 規則和路由也會在
重新開機時自動清除。
無限迴圈/代理伺服器攔截自身的轉送
Section titled “無限迴圈/代理伺服器攔截自身的轉送”這是防迴圈情況。請確認 bypassMark 與 mark 不同(驗證會
強制執行此條件),且轉送使用 connectMarked(realForward 中確實如此)。
請參閱 §5 防迴圈。
§11 原始碼對照表
Section titled “§11 原始碼對照表”| 檔案 | 職責 |
|---|---|
src/mitm/tproxy/commands.ts |
純 iptables/ip 套用與還原命令建構器;validateTproxyConfig |
src/mitm/tproxy/setup.ts |
交易式 applyTproxy / revertTproxy 執行器(失敗時回復) |
src/mitm/tproxy/transparentSocket.ts |
原生附加元件載入器(loadTransparentAddon)、createTransparentListenerFd、connectMarked、setSocketMark、isTransparentSocketAvailable |
src/mitm/tproxy/native/transparent.c |
N-API 附加元件:createTransparentListener(IP_TRANSPARENT)、setSocketMark、connectMarked |
src/mitm/tproxy/native/binding.gyp |
node-gyp 建置資訊清單 |
src/mitm/tproxy/dynamicCert.ts |
DynamicCertStore——個別 SNI 的動態 CA 與分葉憑證快取 |
src/mitm/tproxy/caTrust.ts |
作業系統信任存放區的安裝/解除安裝(installTproxyCa / uninstallTproxyCa,專用槽位) |
src/mitm/tproxy/tlsCapture.ts |
TLS 終止解密引擎與重新加密的防迴圈轉送 |
src/mitm/tproxy/captureMode.ts |
透明監聽器協調管理;從 socket.localAddress 讀取原始目的地 |
src/mitm/tproxy/captureManager.ts |
單例生命週期:startCaptureMode / stopCaptureMode / getCaptureStatus |
src/app/api/tools/agent-bridge/tproxy/route.ts |
GET / POST / DELETE 路由(LOCAL_ONLY) |
src/lib/inspector/tproxyCaptureApi.ts |
用戶端擷取輔助函式(fetchTproxyStatus / startTproxyCaptureMode / stopTproxyCaptureMode) |
HagiCode
HagiCode 是智慧代理程式開發工作台,結合結構化工作流程、多代理程式執行與 Hero Dungeon 介面,將想法化為交付成果。
以更聰明、更快速且更有趣的智慧代理程式工作流程,打造實用的軟體。

- Smart結構化流程將意圖轉化為從構想到交付的可執行步驟。
- Efficient多代理程式工作流程讓研究、實作與審查並行進行。
- FunHero Dungeon 讓長時間的程式協作更直覺、更有參與感。