[Add] Ip tracking
All checks were successful
CI / checks (push) Successful in 5m27s

This commit is contained in:
Alex Emmet 2026-07-20 01:39:27 +02:00
commit 04760fd88d
15 changed files with 136 additions and 20 deletions

View file

@ -11,8 +11,14 @@ Native clients and hosts share the same connection shape after the opening hands
| `client_id` | Confirmed or assigned ID with `crypto` | Authenticated or guest client ID with `crypto` | Authenticated or guest client ID with `crypto` |
| `auth_state` | Authentication result with `crypto` | Authentication result with `crypto` | Authentication result with `crypto` |
| `request_path` | — | — | WebTransport CONNECT path (e.g. `/mtp`) |
| `remote_addr` | Server `SocketAddr` when available | Peer `SocketAddr` | Peer `SocketAddr` |
`WebMTPConnection`, returned by `MTPWebServer::accept()`, exposes the same members as the native host connection plus `request_path`, which contains the HTTP/3 path used for the WebTransport extended CONNECT request.
Server-side MTP connections expose `remote_addr`, the peer address observed by
QUIC. HTTP/3 route handlers receive the same address as `Http3Request::remote_addr`.
It is transport metadata and should not be treated as an authenticated identity;
behind a proxy, use the proxy's trusted forwarding mechanism separately.
The host connection also exposes a version-scoped `codec` and, for an authenticated client, its `client_public_key`. The native client connection also exposes these methods:
| Method | Behavior |

View file

@ -66,7 +66,7 @@ not match the route. Query strings remain available through
## HTTP/3 Requests and Responses
`Http3Request` contains `method`, `uri`, `headers`, and an optional buffered `body` represented by `bytes::Bytes`. `Http3Response::status`, `header`, and `body` build a buffered response. `try_header` returns an error for invalid header names or values. `stream` takes a `tokio::sync::mpsc::Receiver<Bytes>` for incremental response chunks.
`Http3Request` contains `method`, `uri`, `headers`, the connecting `remote_addr`, and an optional buffered `body` represented by `bytes::Bytes`. `Http3Response::status`, `header`, and `body` build a buffered response. `try_header` returns an error for invalid header names or values. `stream` takes a `tokio::sync::mpsc::Receiver<Bytes>` for incremental response chunks.
```rust
use bytes::Bytes;
@ -78,6 +78,10 @@ async fn health(_request: Http3Request, response: Http3Response) -> Http3Respons
response.status(StatusCode::OK).body("ok")
}
async fn whoami(request: Http3Request, response: Http3Response) -> Http3Response {
response.body(format!("client: {}", request.remote_addr))
}
async fn stream_numbers(_request: Http3Request, response: Http3Response) -> Http3Response {
let (tx, rx) = mpsc::channel::<Bytes>(10);
tokio::spawn(async move {
@ -95,6 +99,7 @@ async fn stream_numbers(_request: Http3Request, response: Http3Response) -> Http
let web = WebServerConfig::new()
.route("/health", health)?
.route("/whoami", whoami)?
.route_method(Method::GET, "/numbers", stream_numbers)?
.fallback(|_request, response| async move {
response.status(StatusCode::NOT_FOUND).body("not found")
@ -124,7 +129,7 @@ while let Some(connection) = server.accept().await? {
```
> `MTPWebServer::new` consumes a `HostConfig` (not an `MTPHost` instance). It creates its own QUIC endpoint and does not share a port with a running `MTPHost`.
`server.accept()` returns `Option<WebMTPConnection>` for each WebTransport session. HTTP/3 routes do not surface through `accept()` because the server dispatches them internally. `WebMTPConnection` retains the negotiated version, codec, request path, description, sender, and receiver used by native MTP connections.
`server.accept()` returns `Option<WebMTPConnection>` for each WebTransport session. HTTP/3 routes do not surface through `accept()` because the server dispatches them internally. `WebMTPConnection` retains the negotiated version, codec, request path, remote address, description, sender, and receiver used by native MTP connections.
### Authentication

View file

@ -78,6 +78,8 @@ while let Some(conn) = host.accept().await? {
`accept()` returns the shared connection shape in [MTP Connections](CONNECTIONS.md)
after version negotiation and authentication, when enabled. The host-specific `codec` is scoped to the negotiated version, and `client_public_key` is set for authenticated clients.
The connection's `remote_addr` is the peer `SocketAddr` observed by QUIC. It is
network metadata, not an authenticated client identity.
## Version Negotiation