Papers please.

This commit is contained in:
Skye 2025-05-26 17:39:02 +09:00
parent 70bdcef3e7
commit 23ce1f80a5
Signed by: me
GPG key ID: 0104BC05F41B77B8
2 changed files with 25 additions and 49 deletions

View file

@ -22,7 +22,7 @@ use quinn::{
rustls::pki_types::{CertificateDer, PrivateKeyDer}, rustls::pki_types::{CertificateDer, PrivateKeyDer},
ConnectionError, Endpoint, Incoming, ServerConfig, TransportConfig, ConnectionError, Endpoint, Incoming, ServerConfig, TransportConfig,
}; };
use routing::{RoutingError, RoutingTable}; use routing::RoutingTable;
use serde::Serialize; use serde::Serialize;
use time::OffsetDateTime; use time::OffsetDateTime;
use tokio::{ use tokio::{
@ -81,6 +81,7 @@ struct Connection {
client: Ipv6Addr, client: Ipv6Addr,
intent: &'static str, intent: &'static str,
successful: bool, successful: bool,
target: String,
} }
#[tokio::main] #[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) { async fn handle_quic(connection: Incoming, routing_table: &RoutingTable) {
if let Err(e) = try_handle_quic(connection, routing_table).await { if let Err(e) = try_handle_quic(connection, routing_table).await {
error!("Error handling QUIClime connection: {:#}", e); error!("Error handling QUIClime connection: {:#}", e);
}; }
info!("Finished handling QUIClime connection"); info!("Finished handling QUIClime connection");
} }
@ -261,6 +262,7 @@ async fn try_handle_minecraft(
routing_table: &'static RoutingTable, routing_table: &'static RoutingTable,
inserter: Arc<Mutex<Inserter<Connection>>>, inserter: Arc<Mutex<Inserter<Connection>>>,
) -> eyre::Result<()> { ) -> eyre::Result<()> {
let established = OffsetDateTime::now_utc();
let peer = connection.peer_addr()?; let peer = connection.peer_addr()?;
info!("Minecraft client connected from: {}", peer); info!("Minecraft client connected from: {}", peer);
let handshake = netty::read_packet(&mut connection, 512).await; 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 { let Some(address) = handshake.normalized_address() else {
return politely_disconnect(connection, handshake).await; return politely_disconnect(connection, handshake).await;
}; };
let (mut send_host, mut recv_host) = if routing_table.ratelimit(peer.ip()) {
match routing_table.route_limited(&address, peer.ip()).await { return impolitely_disconnect(connection, handshake).await;
Ok(val) => val, }
Err(RoutingError::InvalidDomain) => { let routing_result = routing_table.route(&address).await;
tokio::task::spawn(async move { let routing_ok = routing_result.is_some();
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;
}
};
tokio::task::spawn(async move { tokio::task::spawn(async move {
if let Err(e) = inserter.lock().await.write(&Connection { if let Err(e) = inserter.lock().await.write(&Connection {
established: OffsetDateTime::now_utc(), established,
region: routing_table.base_domain(), region: routing_table.base_domain(),
client: match peer.ip() { client: match peer.ip() {
std::net::IpAddr::V4(ipv4_addr) => ipv4_addr.to_ipv6_mapped(), 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::Status => "status",
netty::HandshakeType::Login => "login", netty::HandshakeType::Login => "login",
}, },
successful: true, successful: routing_ok,
target: address
}) { }) {
error!("Failed to send telemetry: {e:?}"); 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?; handshake.send(&mut send_host).await?;
let (mut recv_client, mut send_client) = connection.split(); let (mut recv_client, mut send_client) = connection.split();
tokio::select! { tokio::select! {
@ -431,7 +414,7 @@ async fn handle_minecraft(
) { ) {
if let Err(e) = try_handle_minecraft(connection, routing_table, inserter).await { if let Err(e) = try_handle_minecraft(connection, routing_table, inserter).await {
error!("Error handling Minecraft connection: {:#}", e); error!("Error handling Minecraft connection: {:#}", e);
}; }
} }
async fn listen_minecraft( async fn listen_minecraft(

View file

@ -27,11 +27,6 @@ pub struct RoutingTable {
limiter: DefaultKeyedRateLimiter<IpAddr>, limiter: DefaultKeyedRateLimiter<IpAddr>,
} }
pub enum RoutingError {
InvalidDomain,
RateLimited,
}
impl RoutingTable { impl RoutingTable {
pub fn new(base_domain: String) -> Self { pub fn new(base_domain: String) -> Self {
RoutingTable { RoutingTable {
@ -53,24 +48,22 @@ impl RoutingTable {
} }
} }
pub async fn route_limited( pub fn ratelimit(&self, ip: IpAddr) -> bool {
&self,
domain: &str,
ip: IpAddr,
) -> Result<(SendStream, RecvStream), RoutingError> {
if self.limiter.check_key(&ip).is_err() { if self.limiter.check_key(&ip).is_err() {
return Err(RoutingError::RateLimited); return true;
} }
self.limiter.retain_recent(); self.limiter.retain_recent();
false
}
pub async fn route(&self, domain: &str) -> Option<(SendStream, RecvStream)> {
let (send, recv) = oneshot::channel(); let (send, recv) = oneshot::channel();
self.table self.table
.read() .read()
.get(domain) .get(domain)?
.ok_or(RoutingError::InvalidDomain)?
.send(RouterRequest::RouteRequest(send)) .send(RouterRequest::RouteRequest(send))
.ok() .ok()?;
.ok_or(RoutingError::InvalidDomain)?; recv.await.ok()
recv.await.ok().ok_or(RoutingError::InvalidDomain)
} }
fn random_domain(&self) -> String { fn random_domain(&self) -> String {