mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-09 06:47:59 -06:00
fcb3b2be17
- Write PROTOCOL.md with full wire format spec and 8 real-world scenario
analyses (reconnect, multi-operator, large files, AV evasion, router crash,
malformed packets, future pivoting)
- Rewrite workspace structure:
- unshell lib: protocol types (PacketHeader, TreeRequest/Response,
HandshakeMessage/Ack), Transport trait, TcpTransport, Tree routing
- ush-router: router binary with per-node threads, NodeRegistry with
longest-prefix path matching, packet relay
- ush-payload: implant binary with reconnect loop, module tree, InfoModule
- ush-cli: operator REPL with rustyline, session management, command parser
- Protocol design: two-part rkyv frame [header][payload]; router reads only
header for routing, payload bytes forwarded opaque
- All code documented with doc comments and examples
- Zero warnings, zero errors across entire workspace
- 32 tests pass (unit tests for tree routing, TCP transport, framing,
command parsing, node registry)
50 lines
1.4 KiB
Rust
50 lines
1.4 KiB
Rust
//! # Router Core
|
|
//!
|
|
//! The main accept loop. Binds a TCP listener and spawns a node thread for
|
|
//! each incoming connection.
|
|
|
|
use std::net::TcpListener;
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use crate::registry::NodeRegistry;
|
|
use crate::node::spawn_node;
|
|
|
|
/// Start the router, binding to `bind_addr` and accepting connections forever.
|
|
///
|
|
/// This function blocks until an unrecoverable error occurs.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// Returns an error if the bind fails (e.g., port already in use).
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust,no_run
|
|
/// ush_router::router::run("0.0.0.0:9000").expect("router failed");
|
|
/// ```
|
|
pub fn run(bind_addr: &str) -> Result<(), Box<dyn std::error::Error>> {
|
|
let listener = TcpListener::bind(bind_addr)?;
|
|
eprintln!("[router] listening on {bind_addr}");
|
|
|
|
let registry = Arc::new(Mutex::new(NodeRegistry::new()));
|
|
|
|
for stream in listener.incoming() {
|
|
match stream {
|
|
Ok(stream) => {
|
|
let addr = stream
|
|
.peer_addr()
|
|
.map(|a| a.to_string())
|
|
.unwrap_or_else(|_| "unknown".into());
|
|
eprintln!("[router] new connection from {addr}");
|
|
spawn_node(stream, Arc::clone(®istry));
|
|
}
|
|
Err(e) => {
|
|
eprintln!("[router] accept error: {e}");
|
|
// Non-fatal; keep accepting.
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|