feat(proto,cli): v3.1 multi-hop scaffold — control kinds + config sections
Foundation for v3.1 onion routing (client → entry-relay → exit-server).
The relay/circuit runtime is implemented in a follow-up commit; this
scaffold lands the wire-level control extensions and the config schema:
- aura-proto: ControlKind gains ExtendBridge (client→relay), CircuitReady
(relay→client), CircuitFailed (relay→client, with utf-8 reason); helpers
encode_extend_bridge / decode_extend_bridge (1-byte family + 4/16 addr
bytes + u16 port). Integration test in tests/control_extend.rs covers
IPv4/IPv6 roundtrip + full magic-envelope wrap.
- aura-cli config: [server.relay] {enabled, allow_extend_to} +
[client.circuit] {enabled, hops} sections; relay_whitelist() helper
parses IP:port literals. All new fields serde-default, back-compat.
- crl_push.rs touched only to leave the new ControlKinds passing through
the existing magic-envelope dispatcher unchanged.
Workspace: 247 tests passed (+12), clippy/fmt clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
//! Integration test for v3.1 multi-hop control envelope payloads (`ExtendBridge`).
|
||||
//!
|
||||
//! Mirrors `frame.rs`'s in-crate unit coverage but at the integration level so an external
|
||||
//! consumer of `aura-proto` (the CLI's `circuit` module) sees the same wire layout.
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use aura_proto::{
|
||||
decode_control_envelope, decode_extend_bridge, encode_control_envelope, encode_extend_bridge,
|
||||
ControlKind,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn extend_bridge_payload_roundtrips_ipv4() {
|
||||
let addr: SocketAddr = "203.0.113.42:443".parse().unwrap();
|
||||
let payload = encode_extend_bridge(addr);
|
||||
assert_eq!(payload.len(), 1 + 4 + 2);
|
||||
let got = decode_extend_bridge(&payload).expect("decode v4");
|
||||
assert_eq!(got, addr);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extend_bridge_payload_roundtrips_ipv6() {
|
||||
let addr: SocketAddr = "[2001:db8::dead:beef]:1234".parse().unwrap();
|
||||
let payload = encode_extend_bridge(addr);
|
||||
assert_eq!(payload.len(), 1 + 16 + 2);
|
||||
let got = decode_extend_bridge(&payload).expect("decode v6");
|
||||
assert_eq!(got, addr);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extend_bridge_via_full_envelope() {
|
||||
// Build the bytes the client actually sends over the wire: the envelope wraps the payload.
|
||||
let addr: SocketAddr = "10.0.0.5:443".parse().unwrap();
|
||||
let payload = encode_extend_bridge(addr);
|
||||
let envelope = encode_control_envelope(ControlKind::ExtendBridge, &payload);
|
||||
let (kind, decoded_payload) = decode_control_envelope(&envelope).unwrap().unwrap();
|
||||
assert_eq!(kind, ControlKind::ExtendBridge);
|
||||
let got_addr = decode_extend_bridge(&decoded_payload).expect("decode addr from envelope");
|
||||
assert_eq!(got_addr, addr);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extend_bridge_rejects_malformed_payload() {
|
||||
assert!(decode_extend_bridge(&[]).is_err());
|
||||
assert!(decode_extend_bridge(&[4u8]).is_err()); // family but truncated
|
||||
assert!(decode_extend_bridge(&[4u8, 1, 2, 3, 4]).is_err()); // missing port bytes
|
||||
assert!(decode_extend_bridge(&[4u8, 1, 2, 3, 4, 0, 0, 99]).is_err()); // extra byte
|
||||
assert!(decode_extend_bridge(&[6u8, 0, 0]).is_err()); // v6 truncated
|
||||
assert!(decode_extend_bridge(&[7u8, 0, 0, 0, 0, 0, 0]).is_err()); // unknown family
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn circuit_ready_envelope_has_empty_payload() {
|
||||
let envelope = encode_control_envelope(ControlKind::CircuitReady, &[]);
|
||||
let (kind, payload) = decode_control_envelope(&envelope).unwrap().unwrap();
|
||||
assert_eq!(kind, ControlKind::CircuitReady);
|
||||
assert!(payload.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn circuit_failed_carries_utf8_reason() {
|
||||
let envelope = encode_control_envelope(ControlKind::CircuitFailed, b"not in allow_extend_to");
|
||||
let (kind, payload) = decode_control_envelope(&envelope).unwrap().unwrap();
|
||||
assert_eq!(kind, ControlKind::CircuitFailed);
|
||||
assert_eq!(
|
||||
std::str::from_utf8(&payload).unwrap(),
|
||||
"not in allow_extend_to"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user