diff --git a/src/main.rs b/src/main.rs index 2d870b0..887c139 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,7 @@ use quinn::{ rustls::pki_types::{CertificateDer, PrivateKeyDer}, ConnectionError, Endpoint, Incoming, ServerConfig, TransportConfig, }; -use routing::{RoutingError, RoutingTable}; +use routing::RoutingTable; use serde::Serialize; use time::OffsetDateTime; use tokio::{ @@ -81,6 +81,7 @@ struct Connection { client: Ipv6Addr, intent: &'static str, successful: bool, + target: String, } #[tokio::main] @@ -201,7 +202,7 @@ async fn try_handle_quic(connection: Incoming, routing_table: &RoutingTable) -> async fn handle_quic(connection: Incoming, routing_table: &RoutingTable) { if let Err(e) = try_handle_quic(connection, routing_table).await { error!("Error handling QUIClime connection: {:#}", e); - }; + } info!("Finished handling QUIClime connection"); } @@ -261,6 +262,7 @@ async fn try_handle_minecraft( routing_table: &'static RoutingTable, inserter: Arc>>, ) -> eyre::Result<()> { + let established = OffsetDateTime::now_utc(); let peer = connection.peer_addr()?; info!("Minecraft client connected from: {}", peer); let handshake = netty::read_packet(&mut connection, 512).await; @@ -274,37 +276,14 @@ async fn try_handle_minecraft( let Some(address) = handshake.normalized_address() else { return politely_disconnect(connection, handshake).await; }; - let (mut send_host, mut recv_host) = - match routing_table.route_limited(&address, peer.ip()).await { - Ok(val) => val, - Err(RoutingError::InvalidDomain) => { - tokio::task::spawn(async move { - if let Err(e) = inserter.lock().await.write(&Connection { - established: OffsetDateTime::now_utc(), - region: routing_table.base_domain(), - client: match peer.ip() { - std::net::IpAddr::V4(ipv4_addr) => ipv4_addr.to_ipv6_mapped(), - std::net::IpAddr::V6(ipv6_addr) => ipv6_addr, - }, - intent: match handshake.next_state { - netty::HandshakeType::Status => "status", - netty::HandshakeType::Login => "login", - }, - successful: false, - }) { - error!("Failed to send telemetry: {e:?}"); - } - }); - return politely_disconnect(connection, handshake).await; - } - Err(RoutingError::RateLimited) => { - warn!("Connection from {} has been rate limited!", peer); - return impolitely_disconnect(connection, handshake).await; - } - }; + if routing_table.ratelimit(peer.ip()) { + return impolitely_disconnect(connection, handshake).await; + } + let routing_result = routing_table.route(&address).await; + let routing_ok = routing_result.is_some(); tokio::task::spawn(async move { if let Err(e) = inserter.lock().await.write(&Connection { - established: OffsetDateTime::now_utc(), + established, region: routing_table.base_domain(), client: match peer.ip() { std::net::IpAddr::V4(ipv4_addr) => ipv4_addr.to_ipv6_mapped(), @@ -314,11 +293,15 @@ async fn try_handle_minecraft( netty::HandshakeType::Status => "status", netty::HandshakeType::Login => "login", }, - successful: true, + successful: routing_ok, + target: address }) { error!("Failed to send telemetry: {e:?}"); } }); + let Some((mut send_host, mut recv_host)) = routing_result else { + return politely_disconnect(connection, handshake).await; + }; handshake.send(&mut send_host).await?; let (mut recv_client, mut send_client) = connection.split(); tokio::select! { @@ -431,7 +414,7 @@ async fn handle_minecraft( ) { if let Err(e) = try_handle_minecraft(connection, routing_table, inserter).await { error!("Error handling Minecraft connection: {:#}", e); - }; + } } async fn listen_minecraft( diff --git a/src/routing.rs b/src/routing.rs index 542e11a..8a8f7e1 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -27,11 +27,6 @@ pub struct RoutingTable { limiter: DefaultKeyedRateLimiter, } -pub enum RoutingError { - InvalidDomain, - RateLimited, -} - impl RoutingTable { pub fn new(base_domain: String) -> Self { RoutingTable { @@ -53,24 +48,22 @@ impl RoutingTable { } } - pub async fn route_limited( - &self, - domain: &str, - ip: IpAddr, - ) -> Result<(SendStream, RecvStream), RoutingError> { + pub fn ratelimit(&self, ip: IpAddr) -> bool { if self.limiter.check_key(&ip).is_err() { - return Err(RoutingError::RateLimited); + return true; } self.limiter.retain_recent(); + false + } + + pub async fn route(&self, domain: &str) -> Option<(SendStream, RecvStream)> { let (send, recv) = oneshot::channel(); self.table .read() - .get(domain) - .ok_or(RoutingError::InvalidDomain)? + .get(domain)? .send(RouterRequest::RouteRequest(send)) - .ok() - .ok_or(RoutingError::InvalidDomain)?; - recv.await.ok().ok_or(RoutingError::InvalidDomain) + .ok()?; + recv.await.ok() } fn random_domain(&self) -> String {