refactor!: rebrand wraith to alknet

Rename all crates, CLI commands, constants, type names, doc comments,
and documentation from wraith to alknet. Includes wire-protocol changes:
ALPN wraith-ssh -> alknet-ssh, reserved destination prefix wraith- ->
alknet-, SSH auth username wraith -> alknet.
This commit is contained in:
2026-06-05 10:04:32 +00:00
parent af7f4d0006
commit 596c89ce24
101 changed files with 552 additions and 552 deletions

View File

@@ -23,7 +23,7 @@ Supports three outbound proxy modes per server.md: Direct, SOCKS5 proxy, HTTP CO
## Acceptance Criteria
- [ ] `crates/wraith-core/src/server/channel_proxy.rs` exports channel proxy functions
- [ ] `crates/alknet-core/src/server/channel_proxy.rs` exports channel proxy functions
- [ ] `ProxyConfig` enum: `Direct`, `Socks5 { addr: SocketAddr }`, `HttpConnect { addr: SocketAddr }`
- [ ] `connect_outbound(target: SocketAddr, proxy: &ProxyConfig) -> Result<TcpStream>` — connects to target directly or via proxy
- [ ] Direct mode: `TcpStream::connect(target)`

View File

@@ -1,6 +1,6 @@
---
id: server/control-channel
name: Implement wraith-control reserved channel for pubsub event bus bridging (ADR-018)
name: Implement alknet-control reserved channel for pubsub event bus bridging (ADR-018)
status: pending
depends_on:
- server/handler
@@ -13,26 +13,26 @@ level: implementation
## Description
Implement the control channel routing per ADR-018. When the server receives a `channel_open_direct_tcpip` request for `wraith-control:0`:
Implement the control channel routing per ADR-018. When the server receives a `channel_open_direct_tcpip` request for `alknet-control:0`:
1. The handler detects the reserved `wraith-` prefix destination
1. The handler detects the reserved `alknet-` prefix destination
2. Instead of making a TCP connection, it bridges the SSH channel to an internal event bus handle
3. `EventEnvelope` JSON flows bidirectionally over the SSH channel
The entire `wraith-` prefix is reserved — no TCP connections should be attempted for `wraith-*` destinations. The control channel is optional; servers without pubsub configured should accept the channel and provide a configurable behavior (reject or provide a loopback pipe).
The entire `alknet-` prefix is reserved — no TCP connections should be attempted for `alknet-*` destinations. The control channel is optional; servers without pubsub configured should accept the channel and provide a configurable behavior (reject or provide a loopback pipe).
At this stage, implement the routing logic and a `ControlChannel` trait that consumers can implement. The actual pubsub bridge implementation would be in a separate crate or behind a feature flag.
## Acceptance Criteria
- [ ] `crates/wraith-core/src/server/control_channel.rs` exports `ControlChannelHandler` trait and routing logic
- [ ] `WRAITH_CONTROL_DESTINATION` constant defined as `"wraith-control"` (ADR-018)
- [ ] `WRAITH_PREFIX` constant defined as `"wraith-"` for namespace reservation
- [ ] `crates/alknet-core/src/server/control_channel.rs` exports `ControlChannelHandler` trait and routing logic
- [ ] `ALKNET_CONTROL_DESTINATION` constant defined as `"alknet-control"` (ADR-018)
- [ ] `ALKNET_PREFIX` constant defined as `"alknet-"` for namespace reservation
- [ ] `ControlChannelHandler` trait: `async fn handle_channel(stream: Box<dyn AsyncRead + AsyncWrite + Unpin + Send>)`
- [ ] Server handler detects `wraith-*` prefix and routes to `ControlChannelHandler` instead of TCP proxy
- [ ] Server handler detects `alknet-*` prefix and routes to `ControlChannelHandler` instead of TCP proxy
- [ ] If no `ControlChannelHandler` configured, reject the channel open request (SSH channel open failure)
- [ ] Non-reserved destinations continue through normal TCP proxy path
- [ ] Server constraint enforced: no TCP connections to `wraith-*` destinations
- [ ] Server constraint enforced: no TCP connections to `alknet-*` destinations
- [ ] Unit tests: reserved destination detected, non-reserved passes through, prefix matching works
## References

View File

@@ -16,17 +16,17 @@ level: implementation
Implement the core `ServerHandler` that implements `russh::server::Handler`. This is the heart of the server. Per server.md, it has two primary responsibilities:
1. **`auth_publickey()`**: Delegated to `ServerAuthConfig` — checks key against authorized set or validates cert-authority
2. **`channel_open_direct_tcpip()`**: Routes the channel — either to a TCP target (directly or via proxy) or internally for reserved `wraith-*` destinations (ADR-018)
2. **`channel_open_direct_tcpip()`**: Routes the channel — either to a TCP target (directly or via proxy) or internally for reserved `alknet-*` destinations (ADR-018)
At this stage, implement the handler struct, auth delegation, and the channel dispatch skeleton (actual TCP connection and proxy logic in dependent tasks).
## Acceptance Criteria
- [ ] `crates/wraith-core/src/server/handler.rs` exports `ServerHandler`
- [ ] `crates/alknet-core/src/server/handler.rs` exports `ServerHandler`
- [ ] `ServerHandler` implements `russh::server::Handler`
- [ ] `ServerHandler` holds: `Arc<ServerAuthConfig>`, `outbound_proxy: Option<ProxyConfig>`, `remote_addr: Option<SocketAddr>`
- [ ] `auth_publickey()` delegates to `ServerAuthConfig` and returns `Accept` or `Reject`
- [ ] `channel_open_direct_tcpip()` dispatches: if `host.starts_with("wraith-")`, route to internal handler (stub for control channel); otherwise, spawn TCP proxy task (stub that logs and returns error for now)
- [ ] `channel_open_direct_tcpip()` dispatches: if `host.starts_with("alknet-")`, route to internal handler (stub for control channel); otherwise, spawn TCP proxy task (stub that logs and returns error for now)
- [ ] One `ServerHandler` instance per connection; state is not shared between connections (unless explicitly Arc'd)
- [ ] Structured auth logging via `tracing::info!` with `remote_addr`, `key_fingerprint`, `result` (ADR-013)
- [ ] Unit tests: auth delegation works, reserved destination routing logic, unknown channel types rejected
@@ -34,7 +34,7 @@ At this stage, implement the handler struct, auth delegation, and the channel di
## References
- docs/architecture/server.md — Server Handler Behavior section, channel handling
- docs/architecture/decisions/018-control-channel-for-pubsub.md — reserved `wraith-*` destinations
- docs/architecture/decisions/018-control-channel-for-pubsub.md — reserved `alknet-*` destinations
- docs/architecture/decisions/013-fail2ban-friendly-logging.md — structured auth logging
## Notes

View File

@@ -21,7 +21,7 @@ No logging of tunnel destinations, DNS resolutions, or bytes transferred (ADR-00
## Acceptance Criteria
- [ ] `crates/wraith-core/src/server/rate_limit.rs` exports connection rate limiter
- [ ] `crates/alknet-core/src/server/rate_limit.rs` exports connection rate limiter
- [ ] `ConnectionRateLimiter` tracks active connections per IP using `HashMap<IpAddr, usize>`
- [ ] `ConnectionRateLimiter::check(ip) -> bool` — returns `true` if connection allowed, `false` if over limit
- [ ] `ConnectionRateLimiter::on_connect(ip)` — increment counter

View File

@@ -26,7 +26,7 @@ Implement the server's main accept loop and configuration. This ties together th
## Acceptance Criteria
- [x] `crates/wraith-core/src/server/mod.rs` re-exports all server components
- [x] `crates/alknet-core/src/server/mod.rs` re-exports all server components
- [x] `ServeOptions` struct with fields matching server.md CLI interface: `key`, `authorized_keys`, `cert_authority`, `transport_mode`, `listen_addr`, `tls_cert`, `tls_key`, `acme_domain`, `stealth`, `proxy`, `iroh_relay`, `max_connections_per_ip`, `max_auth_attempts`
- [x] `Server::new(opts: ServeOptions) -> Result<Server>` — creates server with bound acceptor, auth config, rate limiter
- [x] `Server::run()` — enters accept loop, for each connection: check rate limit → create handler → `run_stream()`
@@ -56,7 +56,7 @@ Key design decisions:
## Summary
Implemented server accept loop and configuration in `crates/wraith-core/src/server/serve.rs`:
Implemented server accept loop and configuration in `crates/alknet-core/src/server/serve.rs`:
- `ServeOptions` struct with all CLI interface fields, builder pattern, KeySource support
- `Server::new()` creates server with russh config, auth config, rate limiter
- `Server::run(acceptor, endpoint_info)` enters accept loop with rate limiting, stealth detection, russh::server::run_stream()

View File

@@ -25,7 +25,7 @@ Stealth mode requires TLS transport. The CLI should reject or warn if `--stealth
## Acceptance Criteria
- [ ] `crates/wraith-core/src/server/stealth.rs` exports stealth mode protocol detection
- [ ] `crates/alknet-core/src/server/stealth.rs` exports stealth mode protocol detection
- [ ] `detect_protocol(stream: TlsStream) -> ProtocolDetection` — peeks at first bytes to determine SSH vs HTTP
- [ ] `ProtocolDetection` enum: `Ssh`, `Http` (or `Unknown`)
- [ ] If SSH detected: pass stream to `russh::server::run_stream()`