#![deny(warnings)] #![allow(dead_code)] //! [TSM.ID].[11031972] -- Platform X Ecosystem //! xcu-relay -- NAT Traversal Relay Server (STUN/TURN) pub mod turn; #[derive(Debug)] pub enum RelayError { AllocationFailed(String), PeerNotFound(String), QuotaExceeded(String) } impl std::fmt::Display for RelayError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::AllocationFailed(e) => write!(f, "Alloc: {e}"), Self::PeerNotFound(e) => write!(f, "Peer: {e}"), Self::QuotaExceeded(e) => write!(f, "Quota: {e}") } } } impl std::error::Error for RelayError {} use std::collections::HashMap; use std::net::IpAddr; #[derive(Debug, Clone, Copy)] pub struct SocketAddr { pub ip: IpAddr, pub port: u16 } impl SocketAddr { pub fn new(ip: IpAddr, port: u16) -> Self { Self { ip, port } } } /// STUN binding response: reflexive address (your public IP:port) #[derive(Debug, Clone)] pub struct StunResponse { pub mapped_addr: SocketAddr, pub transaction_id: [u8; 12] } /// TURN allocation #[derive(Debug, Clone)] pub struct TurnAllocation { pub client_addr: SocketAddr, pub relay_addr: SocketAddr, pub lifetime_secs: u32, pub created_at: u64, pub bytes_relayed: u64, pub permissions: Vec, } pub struct RelayServer { allocations: HashMap, next_port: u16, relay_ip: IpAddr, max_allocations: usize, max_bytes_per_alloc: u64, } impl RelayServer { pub fn new(relay_ip: IpAddr, start_port: u16, max_alloc: usize) -> Self { Self { allocations: HashMap::new(), next_port: start_port, relay_ip, max_allocations: max_alloc, max_bytes_per_alloc: 100 * 1024 * 1024 } } /// STUN binding request → returns reflexive address pub fn handle_stun_binding(&self, source: SocketAddr, transaction_id: [u8; 12]) -> StunResponse { StunResponse { mapped_addr: source, transaction_id } } /// TURN allocate request pub fn allocate(&mut self, client: SocketAddr, lifetime: u32, now: u64) -> Result { if self.allocations.len() >= self.max_allocations { return Err(RelayError::AllocationFailed("Max allocations reached".into())); } let key = format!("{}:{}", client.ip, client.port); let relay_port = self.next_port; self.next_port += 1; let alloc = TurnAllocation { client_addr: client, relay_addr: SocketAddr::new(self.relay_ip, relay_port), lifetime_secs: lifetime.min(3600), created_at: now, bytes_relayed: 0, permissions: Vec::new(), }; self.allocations.insert(key, alloc.clone()); Ok(alloc) } /// Add permission for peer pub fn create_permission(&mut self, client_key: &str, peer_ip: IpAddr) -> Result<(), RelayError> { let alloc = self.allocations.get_mut(client_key).ok_or_else(|| RelayError::PeerNotFound(client_key.into()))?; if !alloc.permissions.contains(&peer_ip) { alloc.permissions.push(peer_ip); } Ok(()) } /// Relay data from client to peer (if permitted) pub fn relay_data(&mut self, client_key: &str, peer_ip: IpAddr, data_len: u64) -> Result<(), RelayError> { let alloc = self.allocations.get_mut(client_key).ok_or_else(|| RelayError::PeerNotFound(client_key.into()))?; if !alloc.permissions.contains(&peer_ip) { return Err(RelayError::PeerNotFound(format!("{peer_ip} not permitted"))); } alloc.bytes_relayed += data_len; if alloc.bytes_relayed > self.max_bytes_per_alloc { return Err(RelayError::QuotaExceeded(format!("{}B > {}B", alloc.bytes_relayed, self.max_bytes_per_alloc))); } Ok(()) } /// Cleanup expired allocations pub fn cleanup(&mut self, now: u64) -> usize { let before = self.allocations.len(); self.allocations.retain(|_, a| now - a.created_at < a.lifetime_secs as u64); before - self.allocations.len() } pub fn active_allocations(&self) -> usize { self.allocations.len() } } #[cfg(test)] mod tests { use super::*; use std::net::Ipv4Addr; #[test] fn test_stun() { let s = RelayServer::new(IpAddr::V4(Ipv4Addr::new(1,2,3,4)), 50000, 100); let client = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10,0,0,1)), 12345); let resp = s.handle_stun_binding(client, [0u8; 12]); assert_eq!(resp.mapped_addr.port, 12345); } #[test] fn test_turn() { let mut s = RelayServer::new(IpAddr::V4(Ipv4Addr::new(1,2,3,4)), 50000, 100); let client = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10,0,0,1)), 12345); let alloc = s.allocate(client, 600, 1000).unwrap(); assert_eq!(alloc.relay_addr.port, 50000); let key = "10.0.0.1:12345"; let peer = IpAddr::V4(Ipv4Addr::new(10,0,0,2)); s.create_permission(key, peer).unwrap(); s.relay_data(key, peer, 1000).unwrap(); } }