Skip to content

feat(mitm): TPROXY IP_TRANSPARENT native addon + conditional loader (Epic A) - #4148

Merged
diegosouzapw merged 1 commit into
release/v3.8.29from
feat/mitm-tproxy-native
Jun 18, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.29from
feat/mitm-tproxy-native

Conversation

@diegosouzapw

Copy link
Copy Markdown
Collaborator

Summary

Resolves the architectural blocker for Fase 3 / Epic A (TPROXY transparent capture mode): Node's net cannot setsockopt(IP_TRANSPARENT) before bind(), which TPROXY requires (the kernel drops the redirected packets otherwise). This PR adds a tiny N-API addon that creates the transparent socket, plus a conditional loader so it never breaks a JS-only install.

  • src/mitm/tproxy/native/transparent.c — socket()+SO_REUSEADDR+IP_TRANSPARENT+bind()+listen(), returns the raw fd. Node adopts it via server.listen({ fd }) and reads the original destination from socket.localAddress/localPort (TPROXY preserves it — no SO_ORIGINAL_DST/NAT).
  • src/mitm/tproxy/transparentSocket.ts — loads the prebuilt addon conditionally (Linux-only, optional build). isTransparentSocketAvailable() gates the TPROXY mode; createTransparentListenerFd() throws a clear, actionable error when unavailable. Injected require/platform make the load logic unit-testable.
  • Build is opt-in (npm run build:native:tproxy); build/+prebuilds/ are git-ignored, so the addon is not committed and CI exercises the graceful-unavailable path.

Viability proven on the VPS (Hard Rule #18)

Validated on root@192.168.0.15 (kernel 6.8.0-124-generic):

- compiled the .node locally (Node v24.16), copied to the VPS (Node v24.14) → loaded fine (N-API is ABI-stable)
- as root: createTransparentListener("0.0.0.0", 18443) → fd=21 (IP_TRANSPARENT set OK)
- net.createServer().listen({ fd }) → "LISTENING on adopted transparent fd — Node owns it"
- as non-root: setsockopt(IP_TRANSPARENT) → EPERM (expected; needs CAP_NET_ADMIN)

Together with the iptables/ip-rule apply+revert already validated on the same kernel (#4139), both Epic A blockers — the TPROXY rules and the transparent socket — are now proven on a real kernel.

Not in this PR (gated follow-ups)

  • The TPROXY listener that adopts the fd, terminates TLS, and feeds the capture buffer (reusing the MITM path).
  • repairMitm() calling revertTproxy() (feat(mitm): TPROXY setup layer — transactional apply/revert (Epic A) #4144) so a crash flushes the mangle rules.
  • Capture-mode route + Traffic Inspector UI tab.
  • Per-platform prebuild distribution (prebuildify, linux-x64/arm64 only — IP_TRANSPARENT is Linux-only).
  • A live end-to-end intercept in a dedicated test environment (needs a routing scenario; risky on a production proxy).

Test Plan

  • node --test tproxy-transparent-socket.test.ts — 6/6 (non-Linux skip, absent-addon graceful, well-shaped load, bad-shape reject, unavailable-throws)
  • npm run build:native:tproxy compiles the addon cleanly (node-gyp)
  • typecheck:core — 0 errors · eslint — 0
  • VPS: real IP_TRANSPARENT socket created + adopted by Node (evidence above)

🤖 Generated with Claude Code

…Epic A)

Node's net module cannot setsockopt(IP_TRANSPARENT) before bind(), which TPROXY
requires. src/mitm/tproxy/native/transparent.c is a tiny N-API addon that does
socket()+SO_REUSEADDR+IP_TRANSPARENT+bind()+listen() and returns the raw fd for
Node to adopt via server.listen({ fd }); the original destination is then read
from socket.localAddress/localPort (TPROXY preserves it — no SO_ORIGINAL_DST).

transparentSocket.ts loads the addon CONDITIONALLY (Linux-only, optional build)
so a JS-only install keeps working — TPROXY mode is gated on availability.
Injected require/platform make the load logic unit-testable; the addon is not
committed (build/ is git-ignored), so CI exercises the graceful-unavailable path.

Viability proven on the VPS (kernel 6.8.0-124): the prebuilt .node compiled here
loaded under a different Node version (N-API ABI-stable) and, as root, created
the IP_TRANSPARENT socket which Node adopted. Build is opt-in
(npm run build:native:tproxy). Listener wiring, route, UI, prebuild
distribution, and a live intercept stay gated as follow-ups. 6/6 tests.
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@diegosouzapw
diegosouzapw merged commit 97173b1 into release/v3.8.29 Jun 18, 2026
4 checks passed
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…Epic A) (cheaper-inference#4148)

TPROXY IP_TRANSPARENT native addon + conditional loader (Epic A). Opt-in (não compila no npm install; loader degrada gracioso non-Linux/sem-toolchain). Groundwork — listener/captura/UI = follow-ups gated. Integrado em release/v3.8.29.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant