chore: lintathon
This commit is contained in:
parent
d6470c2827
commit
3d381e017f
5 changed files with 70 additions and 96 deletions
52
Cargo.lock
generated
52
Cargo.lock
generated
|
@ -556,7 +556,7 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"quinn",
|
||||
"rand",
|
||||
"rustls 0.22.2",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -575,7 +575,7 @@ dependencies = [
|
|||
"quinn-proto",
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls 0.21.10",
|
||||
"rustls",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
|
@ -591,7 +591,7 @@ dependencies = [
|
|||
"rand",
|
||||
"ring 0.16.20",
|
||||
"rustc-hash",
|
||||
"rustls 0.21.10",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"slab",
|
||||
"thiserror",
|
||||
|
@ -748,24 +748,11 @@ name = "rustls"
|
|||
version = "0.21.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
|
||||
dependencies = [
|
||||
"ring 0.17.7",
|
||||
"rustls-webpki 0.101.7",
|
||||
"sct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring 0.17.7",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki 0.102.2",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
"rustls-webpki",
|
||||
"sct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -789,12 +776,6 @@ dependencies = [
|
|||
"base64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.101.7"
|
||||
|
@ -805,17 +786,6 @@ dependencies = [
|
|||
"untrusted 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.102.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610"
|
||||
dependencies = [
|
||||
"ring 0.17.7",
|
||||
"rustls-pki-types",
|
||||
"untrusted 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.14"
|
||||
|
@ -966,12 +936,6 @@ version = "0.9.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.48"
|
||||
|
@ -1401,9 +1365,3 @@ name = "windows_x86_64_msvc"
|
|||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
||||
|
|
|
@ -16,7 +16,7 @@ log = "0.4.19"
|
|||
parking_lot = "0.12.1"
|
||||
quinn = "0.10.1"
|
||||
rand = "0.8.5"
|
||||
rustls = "*"
|
||||
rustls = "0.21.9"
|
||||
rustls-pemfile = "1.0.2"
|
||||
serde = { version = "1.0.164", features = ["derive"] }
|
||||
serde_json = "1.0.97"
|
||||
|
|
64
src/main.rs
64
src/main.rs
|
@ -1,12 +1,16 @@
|
|||
use std::{net::SocketAddr, sync::Arc, time::Duration, convert::Infallible};
|
||||
#![warn(clippy::pedantic)]
|
||||
#![allow(clippy::cast_possible_truncation)]
|
||||
#![allow(clippy::cast_possible_wrap)]
|
||||
|
||||
use anyhow::{Context, anyhow};
|
||||
use std::{convert::Infallible, net::SocketAddr, sync::Arc, time::Duration};
|
||||
|
||||
use anyhow::{anyhow, Context};
|
||||
use axum::{
|
||||
http::StatusCode,
|
||||
routing::{get, post},
|
||||
};
|
||||
use log::{error, info};
|
||||
use netty::{Handshake, NettyReadError};
|
||||
use netty::{Handshake, ReadError};
|
||||
use quinn::{Connecting, ConnectionError, Endpoint, ServerConfig, TransportConfig};
|
||||
use routing::RoutingTable;
|
||||
use rustls::{Certificate, PrivateKey};
|
||||
|
@ -16,7 +20,7 @@ use tokio::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
netty::{WriteExtNetty, ReadExtNetty},
|
||||
netty::{ReadExt, WriteExt},
|
||||
proto::{ClientboundControlMessage, ServerboundControlMessage},
|
||||
};
|
||||
|
||||
|
@ -32,9 +36,11 @@ fn any_private_keys(rd: &mut dyn std::io::BufRead) -> Result<Vec<Vec<u8>>, std::
|
|||
loop {
|
||||
match rustls_pemfile::read_one(rd)? {
|
||||
None => return Ok(keys),
|
||||
Some(rustls_pemfile::Item::ECKey(key)) => keys.push(key),
|
||||
Some(rustls_pemfile::Item::PKCS8Key(key)) => keys.push(key),
|
||||
Some(rustls_pemfile::Item::RSAKey(key)) => keys.push(key),
|
||||
Some(
|
||||
rustls_pemfile::Item::RSAKey(key)
|
||||
| rustls_pemfile::Item::PKCS8Key(key)
|
||||
| rustls_pemfile::Item::ECKey(key),
|
||||
) => keys.push(key),
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
@ -117,7 +123,7 @@ async fn try_handle_quic(
|
|||
if let Ok(parsed) = serde_json::from_slice(&buf) {
|
||||
match parsed {
|
||||
ServerboundControlMessage::RequestDomainAssignment => {
|
||||
let handle = routing_table.register().await;
|
||||
let handle = routing_table.register();
|
||||
info!(
|
||||
"Domain assigned to {}: {}",
|
||||
connection.remote_address(),
|
||||
|
@ -132,19 +138,19 @@ async fn try_handle_quic(
|
|||
break handle;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
let response = serde_json::to_vec(&ClientboundControlMessage::UnknownMessage)?;
|
||||
send_control.write_all(&[response.len() as u8]).await?;
|
||||
send_control.write_all(&response).await?;
|
||||
}
|
||||
};
|
||||
|
||||
tokio::select! {
|
||||
e = connection.closed() => {
|
||||
match e {
|
||||
ConnectionError::ConnectionClosed(_) => Ok(()),
|
||||
ConnectionError::ApplicationClosed(_) => Ok(()),
|
||||
ConnectionError::LocallyClosed => Ok(()),
|
||||
e => Err(e.into())
|
||||
ConnectionError::ConnectionClosed(_)
|
||||
| ConnectionError::ApplicationClosed(_)
|
||||
| ConnectionError::LocallyClosed => Ok(()),
|
||||
e => Err(e.into()),
|
||||
}
|
||||
},
|
||||
r = async {
|
||||
|
@ -208,7 +214,7 @@ async fn listen_control(
|
|||
endpoint.set_server_config(Some(config));
|
||||
(StatusCode::OK, "Success".to_string())
|
||||
}
|
||||
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", e)),
|
||||
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, format!("{e}")),
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
@ -239,20 +245,18 @@ async fn try_handle_minecraft(
|
|||
let peer = connection.peer_addr()?;
|
||||
info!("Minecraft client connected from: {}", peer);
|
||||
let handshake = netty::read_packet(&mut connection).await;
|
||||
if let Err(NettyReadError::LegacyServerListPing) = handshake {
|
||||
if let Err(ReadError::LegacyServerListPing) = handshake {
|
||||
connection
|
||||
.write_all(include_bytes!("legacy_serverlistping_response.bin"))
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
let handshake = Handshake::new(&handshake?)?;
|
||||
let address = match handshake.normalized_address() {
|
||||
Some(addr) => addr,
|
||||
None => return politely_disconnect(connection, handshake).await,
|
||||
let Some(address) = handshake.normalized_address() else {
|
||||
return politely_disconnect(connection, handshake).await;
|
||||
};
|
||||
let (mut send_host, mut recv_host) = match routing_table.route(&address).await {
|
||||
Some(pair) => pair,
|
||||
None => return politely_disconnect(connection, handshake).await,
|
||||
let Some((mut send_host, mut recv_host)) = routing_table.route(&address).await else {
|
||||
return politely_disconnect(connection, handshake).await;
|
||||
};
|
||||
handshake.send(&mut send_host).await?;
|
||||
let (mut recv_client, mut send_client) = connection.split();
|
||||
|
@ -277,7 +281,10 @@ async fn politely_disconnect(
|
|||
let mut packet = packet.as_slice();
|
||||
let id = packet.read_varint()?;
|
||||
if id != 0 {
|
||||
return Err(anyhow!("Packet isn't a Status Request(0x00), but {:#04x}", id));
|
||||
return Err(anyhow!(
|
||||
"Packet isn't a Status Request(0x00), but {:#04x}",
|
||||
id
|
||||
));
|
||||
}
|
||||
let mut buf = vec![];
|
||||
buf.write_varint(0).await?;
|
||||
|
@ -289,7 +296,10 @@ async fn politely_disconnect(
|
|||
let mut packet = packet.as_slice();
|
||||
let id = packet.read_varint()?;
|
||||
if id != 1 {
|
||||
return Err(anyhow!("Packet isn't a Ping Request(0x01), but {:#04x}", id));
|
||||
return Err(anyhow!(
|
||||
"Packet isn't a Ping Request(0x01), but {:#04x}",
|
||||
id
|
||||
));
|
||||
}
|
||||
let payload = packet.read_long()?;
|
||||
let mut buf = Vec::with_capacity(1 + 8);
|
||||
|
@ -326,10 +336,12 @@ async fn listen_minecraft(routing_table: &'static RoutingTable) -> anyhow::Resul
|
|||
.await?;
|
||||
loop {
|
||||
match server.accept().await {
|
||||
Ok((connection, _)) => { tokio::spawn(handle_minecraft(connection, routing_table)); },
|
||||
Ok((connection, _)) => {
|
||||
tokio::spawn(handle_minecraft(connection, routing_table));
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Error accepting minecraft connection: {}", e);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
38
src/netty.rs
38
src/netty.rs
|
@ -1,3 +1,5 @@
|
|||
#![allow(clippy::cast_sign_loss)]
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
@ -7,56 +9,56 @@ use log::error;
|
|||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum NettyReadError {
|
||||
pub enum ReadError {
|
||||
#[error("{0}")]
|
||||
IoError(std::io::Error),
|
||||
#[error("Was not a netty packet, but a Legacy ServerListPing")]
|
||||
LegacyServerListPing,
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for NettyReadError {
|
||||
impl From<std::io::Error> for ReadError {
|
||||
fn from(value: std::io::Error) -> Self {
|
||||
Self::IoError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::ErrorKind> for NettyReadError {
|
||||
impl From<std::io::ErrorKind> for ReadError {
|
||||
fn from(value: std::io::ErrorKind) -> Self {
|
||||
Self::IoError(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ReadExtNetty: Read {
|
||||
fn read_u8(&mut self) -> Result<u8, NettyReadError> {
|
||||
pub trait ReadExt: Read {
|
||||
fn read_u8(&mut self) -> Result<u8, ReadError> {
|
||||
let mut buf = [0u8];
|
||||
self.read_exact(&mut buf)?;
|
||||
Ok(buf[0])
|
||||
}
|
||||
|
||||
fn read_u16(&mut self) -> Result<u16, NettyReadError> {
|
||||
fn read_u16(&mut self) -> Result<u16, ReadError> {
|
||||
let mut buf = [0u8; 2];
|
||||
self.read_exact(&mut buf)?;
|
||||
Ok(u16::from_be_bytes(buf))
|
||||
}
|
||||
|
||||
fn read_long(&mut self) -> Result<u64, NettyReadError> {
|
||||
fn read_long(&mut self) -> Result<u64, ReadError> {
|
||||
let mut buf = [0u8; 8];
|
||||
self.read_exact(&mut buf)?;
|
||||
Ok(u64::from_be_bytes(buf))
|
||||
}
|
||||
|
||||
fn read_string(&mut self) -> Result<String, NettyReadError> {
|
||||
fn read_string(&mut self) -> Result<String, ReadError> {
|
||||
let len = self.read_varint()?;
|
||||
let mut buf = vec![0u8; len as usize];
|
||||
self.read_exact(&mut buf)?;
|
||||
String::from_utf8(buf).map_err(|_| std::io::ErrorKind::InvalidData.into())
|
||||
}
|
||||
|
||||
fn read_varint(&mut self) -> Result<i32, NettyReadError> {
|
||||
fn read_varint(&mut self) -> Result<i32, ReadError> {
|
||||
let mut res = 0i32;
|
||||
for i in 0..5 {
|
||||
let part = self.read_u8()?;
|
||||
res |= (part as i32 & 0x7F) << (7 * i);
|
||||
res |= (i32::from(part) & 0x7F) << (7 * i);
|
||||
if part & 0x80 == 0 {
|
||||
return Ok(res);
|
||||
}
|
||||
|
@ -84,7 +86,7 @@ pub trait ReadExtNetty: Read {
|
|||
// }
|
||||
}
|
||||
|
||||
pub async fn read_packet(mut reader: impl AsyncReadExt + Unpin) -> Result<Vec<u8>, NettyReadError> {
|
||||
pub async fn read_packet(mut reader: impl AsyncReadExt + Unpin) -> Result<Vec<u8>, ReadError> {
|
||||
let len = read_varint(&mut reader).await?;
|
||||
let mut buf = vec![0u8; len as usize];
|
||||
if len == 254 {
|
||||
|
@ -92,7 +94,7 @@ pub async fn read_packet(mut reader: impl AsyncReadExt + Unpin) -> Result<Vec<u8
|
|||
reader.read_exact(&mut temp).await?;
|
||||
if temp[0] == 0xFA {
|
||||
// FE 01 FA: Legacy ServerListPing
|
||||
return Err(NettyReadError::LegacyServerListPing);
|
||||
return Err(ReadError::LegacyServerListPing);
|
||||
}
|
||||
buf[0] = temp[0];
|
||||
reader.read_exact(&mut buf[1..]).await?;
|
||||
|
@ -102,11 +104,11 @@ pub async fn read_packet(mut reader: impl AsyncReadExt + Unpin) -> Result<Vec<u8
|
|||
Ok(buf)
|
||||
}
|
||||
|
||||
async fn read_varint(mut reader: impl AsyncReadExt + Unpin) -> Result<i32, NettyReadError> {
|
||||
async fn read_varint(mut reader: impl AsyncReadExt + Unpin) -> Result<i32, ReadError> {
|
||||
let mut res = 0i32;
|
||||
for i in 0..5 {
|
||||
let part = reader.read_u8().await?;
|
||||
res |= (part as i32 & 0x7F) << (7 * i);
|
||||
res |= (i32::from(part) & 0x7F) << (7 * i);
|
||||
if part & 0x80 == 0 {
|
||||
return Ok(res);
|
||||
}
|
||||
|
@ -115,10 +117,10 @@ async fn read_varint(mut reader: impl AsyncReadExt + Unpin) -> Result<i32, Netty
|
|||
Err(std::io::ErrorKind::InvalidData.into())
|
||||
}
|
||||
|
||||
impl<T: Read> ReadExtNetty for T {}
|
||||
impl<T: Read> ReadExt for T {}
|
||||
|
||||
#[async_trait]
|
||||
pub trait WriteExtNetty: AsyncWriteExt + Unpin {
|
||||
pub trait WriteExt: AsyncWriteExt + Unpin {
|
||||
async fn write_varint(&mut self, mut val: i32) -> std::io::Result<()> {
|
||||
for _ in 0..5 {
|
||||
if val & !0x7F == 0 {
|
||||
|
@ -161,7 +163,7 @@ impl Handshake {
|
|||
} else {
|
||||
let protocol_version = packet.read_varint()?;
|
||||
let server_address = packet.read_string()?;
|
||||
let server_port = ReadExtNetty::read_u16(&mut packet)?;
|
||||
let server_port = ReadExt::read_u16(&mut packet)?;
|
||||
let next_state = match packet.read_varint()? {
|
||||
1 => HandshakeType::Status,
|
||||
2 => HandshakeType::Login,
|
||||
|
@ -207,4 +209,4 @@ impl Handshake {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: AsyncWriteExt + Unpin> WriteExtNetty for T {}
|
||||
impl<T: AsyncWriteExt + Unpin> WriteExt for T {}
|
||||
|
|
|
@ -17,6 +17,7 @@ pub enum RouterRequest {
|
|||
type RouterCallback = oneshot::Sender<(SendStream, RecvStream)>;
|
||||
type RouteRequestReceiver = mpsc::UnboundedSender<RouterRequest>;
|
||||
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
#[derive(Default)]
|
||||
pub struct RoutingTable {
|
||||
table: RwLock<HashMap<String, RouteRequestReceiver>>,
|
||||
|
@ -26,7 +27,7 @@ pub struct RoutingTable {
|
|||
impl RoutingTable {
|
||||
pub fn new(base_domain: String) -> Self {
|
||||
RoutingTable {
|
||||
table: Default::default(),
|
||||
table: RwLock::default(),
|
||||
base_domain,
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +54,7 @@ impl RoutingTable {
|
|||
recv.await.ok()
|
||||
}
|
||||
|
||||
pub async fn register(&self) -> RoutingHandle {
|
||||
pub fn register(&self) -> RoutingHandle {
|
||||
let mut lock = self.table.write();
|
||||
let mut domain = format!(
|
||||
"{}-{}.{}",
|
||||
|
@ -93,6 +94,7 @@ impl RoutingTable {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
pub struct RoutingHandle<'a> {
|
||||
recv: mpsc::UnboundedReceiver<RouterRequest>,
|
||||
domain: String,
|
||||
|
|
Loading…
Reference in a new issue