1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//! Byte-accurate network accounting for an arbitrary child process.
//!
//! [`proxy::Proxy`] runs an ephemeral proxy on loopback that speaks three protocols on one
//! port — HTTP, HTTP `CONNECT`, and SOCKS5 — so a child process configured through the
//! standard `HTTP_PROXY`/`HTTPS_PROXY`/`ALL_PROXY` variables has every byte it sends and
//! receives counted per remote endpoint.
//!
//! This measures *cooperative* clients only. A proxy is not an interception layer: those
//! environment variables are advisory configuration, and a client that declines to consult them
//! sends its bytes straight out of the machine where nothing here can observe them. Accounting
//! is exact for traffic that does come through, and blind to the rest.
//!
//! Tunnelled traffic is never decrypted or even parsed: `CONNECT` and SOCKS5 both become raw
//! TCP splices, so the totals are exact wire counts for any TCP protocol the client chooses to
//! tunnel, and there is no certificate to install. A client that asks for SOCKS5 UDP relay gets
//! one, counted the same way ([`udp::Relay`]) — but UDP sent straight to a destination, which is
//! what QUIC and HTTP/3 normally do, never reaches the proxy and cannot be seen at all.
//!
//! ```no_run
//! use wiretally::{proxy::Proxy, stats::Registry};
//! use std::sync::Arc;
//!
//! # async fn run() -> anyhow::Result<()> {
//! let registry = Arc::new(Registry::new());
//! let proxy = Proxy::bind(Arc::clone(®istry), false).await?;
//! // Point a child process at `proxy.local_addr()`, then read `registry.snapshot()`.
//! # Ok(())
//! # }
//! ```