{"id":35101183,"url":"https://github.com/metastable-void/tinspect","last_synced_at":"2026-05-18T12:32:33.762Z","repository":{"id":327367065,"uuid":"1108890326","full_name":"metastable-void/tinspect","owner":"metastable-void","description":"a transparent HTTP/HTTPS/WebSocket inspector and MITM proxy written in Rust","archived":false,"fork":false,"pushed_at":"2025-12-05T07:02:19.000Z","size":149,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-05T09:43:16.316Z","etag":null,"topics":["mitm","tproxy"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/metastable-void.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-03T03:54:14.000Z","updated_at":"2025-12-05T07:02:22.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/metastable-void/tinspect","commit_stats":null,"previous_names":["metastable-void/tinspect"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/metastable-void/tinspect","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metastable-void%2Ftinspect","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metastable-void%2Ftinspect/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metastable-void%2Ftinspect/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metastable-void%2Ftinspect/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/metastable-void","download_url":"https://codeload.github.com/metastable-void/tinspect/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metastable-void%2Ftinspect/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33178136,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-18T09:27:30.708Z","status":"ssl_error","status_checked_at":"2026-05-18T09:27:28.300Z","response_time":71,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mitm","tproxy"],"created_at":"2025-12-27T16:57:13.176Z","updated_at":"2026-05-18T12:32:33.756Z","avatar_url":"https://github.com/metastable-void.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tinspect\n\n**tinspect** is a transparent HTTP/HTTPS/WebSocket inspector and MITM proxy written in Rust.\n\nIt is designed to sit behind a **TPROXY** rule on Linux and receive redirected traffic destined for arbitrary remote hosts, terminate application-layer protocols, optionally inspect or transform them, and then forward traffic to the intended upstream server.\n\nThe project already supports **HTTP/1.1**, **HTTPS MITM**, **WebSocket (`ws://` and `wss://`)**, and transparent forwarding.\nThe only major missing protocol is **HTTP/2**.\n\nThis crate is not yet production ready, but the core pipeline works end-to-end.\n\n---\n\n## Features\n\n### Transparent interception (TPROXY)\n\n* Receives TCP connections redirected using `TPROXY`.\n* Recovers the **original destination address and port**.\n* Opens a new outbound connection to the correct origin server.\n* Forwards bytes bidirectionally.\n\n### HTTP/1.1 proxying (implemented)\n\n* Uses Hyper 1.x to parse HTTP/1 requests and responses.\n* Logging example shows full request/response forwarding.\n* Supports body buffering (100MiB max).\n* Enables inspection and transformation at many points.\n\n### HTTPS MITM (implemented)\n\n* Terminates TLS using **rustls**.\n* Extracts SNI from the client handshake.\n* Dynamically generates per-hostname leaf certificates using **rcgen**.\n* Signs those certificates with a **company CA** loaded from PEM.\n* Caches generated certificates in an **LRU** cache for fast lookup.\n* Creates a second TLS client session to the upstream server.\n\nEffectively: full HTTPS MITM is already working.\n\n### WebSocket support (implemented)\n\n* Detects HTTP Upgrade requests (`Connection: upgrade`, `Upgrade: websocket`).\n* Responds with `101 Switching Protocols` via Hyper.\n* Uses `hyper::upgrade::on(req)` to obtain the raw TCP stream.\n* Wraps the stream in `tokio-tungstenite::WebSocketStream`.\n* For `wss://`, this happens *after* TLS MITM → you receive decrypted frames.\n* Handles Ping/Pong automatically (tungstenite handles this internally).\n\n### Missing / in progress\n\n* **HTTP/2 (h2) support**\n  ALPN + rustls + Hyper integration for h2 still needs to be implemented.\n* **HTTP/3 / QUIC** (out of scope for now)\n* **Raw TCP forwarding fallback** (not planned)\n* **Advanced inspection plugins**\n* **Policy engine \u0026 configuration layer**\n\n---\n\n## Intended use-cases\n\n* Corporate / lab networks that want **central HTTPS/WSS inspection** using a private CA.\n* Diagnostic and debugging tools to observe and modify HTTP/TLS/WebSocket flows.\n* A programmable, embeddable Rust-native MITM engine.\n* Research environments needing deterministic control over traffic.\n\nThis crate is **not intended for covert MITM**.\nIt assumes a network where clients trust your internal CA.\n\n---\n\n## Repository structure\n\n* `src/` – core library\n\n  * TPROXY listener\n  * HTTP/1 handling (client and upstream)\n  * TLS MITM (rustls + rcgen)\n  * WebSocket upgrade + framing (tokio-tungstenite)\n  * Forwarding utilities\n* `examples/` – runnable binaries demonstrating usage\n\n  * Logging-only example (currently provided): forwards traffic unmodified and logs metadata\n\n---\n\n## Building and running\n\nClone and build:\n\n```\ngit clone https://github.com/metastable-void/tinspect\ncd tinspect\ncargo build\n```\n\nRun the logging example (check actual example names):\n\n```\ncargo run --example tinspect-logging-proxy\n```\n\n---\n\n## Minimal TPROXY setup (IPv4 sketch)\n\nThis is only a starting point.\nAdapt to your network (interfaces, marks, routing tables) and test on a safe machine:\n\n```\n# send TCP/80 + TCP/443 traffic from lan0 to our transparent proxy\niptables -t mangle -A PREROUTING -i lan0 -p tcp --dport 80  -j TPROXY --on-port 80  --tproxy-mark 0x1/0x1\niptables -t mangle -A PREROUTING -i lan0 -p tcp --dport 443 -j TPROXY --on-port 443 --tproxy-mark 0x1/0x1\n\n# route marked packets back to the local machine so the proxy can accept them\nip rule add fwmark 0x1 lookup 100\nip route add local 0.0.0.0/0 dev lo table 100\n```\n\n### IPv6 translation\n\n```\nip6tables -t mangle -A PREROUTING -i lan0 -p tcp --dport 80  -j TPROXY --on-port 80  --tproxy-mark 0x1/0x1\nip6tables -t mangle -A PREROUTING -i lan0 -p tcp --dport 443 -j TPROXY --on-port 443 --tproxy-mark 0x1/0x1\n\nip -6 rule add fwmark 0x1 lookup 100\nip -6 route add local ::/0 dev lo table 100\n```\n\nThe listeners bind to `[::]:80` and `[::]:443` with `IPV6_V6ONLY` disabled, so a single socket handles both IPv4 and IPv6 once the NAT rules feed the traffic back to the host.\n\n### Making the rules persistent\n\n* **systemd service** – create a oneshot unit (e.g. `/etc/systemd/system/tinspect-tproxy.service`) that runs the iptables/ip rule commands in `ExecStart`, and add matching `ExecStop` lines that delete them. `WantedBy=multi-user.target` keeps them applied during normal boots.\n* **systemd-networkd** – if your host uses `systemd-networkd`, you can keep everything in declarative files:\n\n  * `*.network` – apply the fwmark routing when the interface comes up:\n\n    ```\n    [Match]\n    Name=lan0\n\n    [RoutingPolicyRule]\n    Priority=100\n    FwMark=0x1\n    Table=100\n\n    [Route]\n    Table=100\n    Gateway=0.0.0.0\n    PreferredSource=0.0.0.0\n    Type=local\n    ```\n\n    Add a second `[RoutingPolicyRule]/[Route]` block for IPv6 (`Table=100`, `Type=local`, `Gateway=::`).\n\n  * `*.netdev` – attach a `tc` qdisc or IP rule helper if you prefer invoking `iptables` via `ExecStart=`; otherwise use a companion `*.service` with `WantedBy=sys-subsystem-net-devices-lan0.device` so the firewall rules track the interface state.\n\n* **iptables-persistent** – store the mangle table in `/etc/iptables/rules.v4` and `/etc/iptables/rules.v6` (`iptables-save \u003e /etc/iptables/rules.v4`). The routing policy entries can be added from `systemd-networkd` as above or via `/etc/network/if-pre-up.d/` scripts.\n* Always pair persistence with a rollback plan (console access or a watchdog timer) so you do not lock yourself out of the machine.\n\n---\n\n## HTTPS MITM: how it works\n\n* At startup you provide:\n\n  * a CA **private key** PEM\n  * a CA **certificate** PEM\n* These are loaded into a `rcgen::Issuer`.\n* When a client starts TLS:\n\n  1. rustls extracts SNI\n  2. the proxy looks up that hostname in a `DashMap`\n  3. if missing, it generates a leaf keypair + certificate for that host\n  4. signs it with your CA\n  5. hands it to rustls as the server certificate\n* From that point onward, the proxy can inspect decrypted data.\n\nThis matches what corporate TLS inspection gateways typically do.\n\n---\n\n## WebSocket MITM: how it works\n\n* All WebSockets start as HTTP/1.1 requests.\n* The proxy:\n\n  * parses the request via Hyper,\n  * detects Upgrade,\n  * builds a 101 response,\n  * calls `hyper::upgrade::on(req)`,\n  * wraps the resulting stream with `tokio_tungstenite`.\n* Because tungstenite automatically responds to pings, the proxy only needs to read/write frames or forward them upstream.\n\nWorks for:\n\n* `ws://host/path`\n* `wss://host/path` (after TLS termination)\n\n---\n\n## Security considerations\n\n* Clients **must** trust your internal CA.\n* Certificate pinning may break for some applications (expected).\n* QUIC and HTTP/3 cannot be MITM’d with this architecture.\n* Use only in networks where MITM is authorized.\n\n---\n\n## Roadmap\n\n* HTTP/2 parsing \u0026 forwarding\n* Extensible inspection rule engine\n* Streaming body inspection\n* Performance tuning (zero-copy, buffer pools)\n* Configuration loader (TOML/YAML)\n* Better metrics and tracing\n\n---\n\n## License\n\nDual-licensed:\n\n* Apache License 2.0\n* Mozilla Public License 2.0\n\nSee the `LICENSE.APACHE` and `LICENSE.MPL` files for details.\n\n---\n\n## Contributions\n\nPRs, issues, and discussion are very welcome — especially around:\n\n* correct and efficient TPROXY usage,\n* rustls MITM details,\n* Hyper 1.x integration,\n* HTTP/2 handling strategies,\n* WebSocket inspection examples.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetastable-void%2Ftinspect","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetastable-void%2Ftinspect","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetastable-void%2Ftinspect/lists"}