Closes the v3.1 unlinkability gap and resists volume/timing correlation:
1) Per-hop client cert (identity-unlinkable hops). [[client.circuit.hops]]
now accepts {addr, cert_path, key_path, [server_name]} per hop — each
hop sees a different CN, so a relay and an exit cannot correlate the
same client by certificate. Old flat `hops = ["ip:port"]` form still
parses (serde untagged enum) and falls back to [pki] cert/key.
`aura provision-client --circuit-hops N` mints N fresh UUIDv4 certs.
2) Cell padding. CellPaddingConn wrapper pads every outgoing packet to a
fixed size (default 1280 bytes; `cell_size = N` configurable) before
it hits the inner AEAD. Format: u16_be(real_len) || pkt || zero_pad.
On-wire sizes become constant -> defeats volume/timing fingerprints.
Opt-in via [client.circuit] cell_padding = true and the mirror
[server] cell_padding_for_circuit_clients = true.
3) 3-hop support. dial_circuit now accepts N >= 2 hops; iterative
ExtendBridge nests N-1 forwarders and N handshakes. Client owns the
full chain via CircuitConnection (forwarders abort on drop).
New integration test multihop_v3_2_three_hops_end_to_end runs three
in-process actors (A relay -> B relay -> C exit) on loopback and
verifies peer_id == C's CN.
4) CIDR whitelist. [server.relay] allow_extend_to entries accept
"10.0.0.0/24" (subnet, any port), "10.0.0.0/24:443" (subnet + port),
"[2001:db8::/32]:443" (IPv6 with port), as well as exact IP:port.
Empty list keeps the v3.1 open-relay (warn).
19 new tests; workspace 276 passed (+19), clippy -D warnings clean, fmt clean.
257 baseline tests untouched; all v2 / v3.1 / LE configs work as before.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Reduces manual setup steps and trims user-identifying data exposed by the
server/client, in the spirit of the deployment story: an operator on the
wire sees less, and the admin types fewer commands.
New CLI subcommands:
- `aura server-init`: one shot — pki init + issue-server + writes a ready
server.toml with auto-detected egress iface; flags --enable-knock,
--enable-cover-traffic, --no-nat, --run-as toggle the new transport
defenses and privilege drop.
- `aura provision-client`: issues a client cert and assembles the full
bundle (ca.crt + client.crt + client.key + client.toml in one directory)
ready to hand over to the client device. --id is optional (defaults to
a fresh UUIDv4, so client identities don't have to encode anything real).
Identity / log minimization:
- `aura pki issue-client --id` is now optional — UUIDv4 by default.
- `[server]/[client] no_logs = true` filters peer_id, client_ip,
source_addr, client_id, local_ip, user, id, assigned_ip, peer field
values through a custom tracing FormatFields layer (events still fire
but the identifying fields are redacted before being written).
- `[client] bridges = [...]`: secondary server addresses; build_dial_targets
shuffles them after the primary, so blocking one IP doesn't kill the
client.
- Auto-detect egress iface in [server.nat] (via detect_default_egress_iface);
egress_iface in config becomes optional with graceful fallback.
Config examples updated; backward-compatible (all new sections optional with
serde defaults). Workspace: 207 tests passed (+22), clippy -D warnings clean,
fmt clean. No new workspace deps.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>