fucking scanners
This commit is contained in:
parent
998b210463
commit
bf24b4ecaa
8 changed files with 8055 additions and 224 deletions
172
Cargo.lock
generated
172
Cargo.lock
generated
|
@ -26,6 +26,12 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.86"
|
||||
|
@ -190,6 +196,26 @@ version = "0.8.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "6.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"hashbrown 0.14.5",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
|
@ -214,6 +240,12 @@ dependencies = [
|
|||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.12"
|
||||
|
@ -230,6 +262,12 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
|
@ -254,12 +292,24 @@ version = "0.3.31"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "3.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.31"
|
||||
|
@ -267,9 +317,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -292,8 +344,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.13.3+wasi-0.2.2",
|
||||
"wasm-bindgen",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
|
@ -303,6 +357,46 @@ version = "0.31.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "governor"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cbe789d04bf14543f03c4b60cd494148aa79438c8440ae7d81a7778147745c3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"dashmap",
|
||||
"futures-sink",
|
||||
"futures-timer",
|
||||
"futures-util",
|
||||
"getrandom 0.3.1",
|
||||
"hashbrown 0.15.3",
|
||||
"nonzero_ext",
|
||||
"parking_lot",
|
||||
"portable-atomic",
|
||||
"quanta",
|
||||
"rand 0.9.0",
|
||||
"smallvec",
|
||||
"spinning_top",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.4.0"
|
||||
|
@ -630,6 +724,12 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nonzero_ext"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
|
@ -740,6 +840,12 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.20"
|
||||
|
@ -758,6 +864,21 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quanta"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"raw-cpuid",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quiclime"
|
||||
version = "0.1.0"
|
||||
|
@ -765,6 +886,7 @@ dependencies = [
|
|||
"axum",
|
||||
"env_logger",
|
||||
"eyre",
|
||||
"governor",
|
||||
"idna",
|
||||
"log",
|
||||
"parking_lot",
|
||||
|
@ -900,6 +1022,15 @@ dependencies = [
|
|||
"zerocopy 0.8.20",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-cpuid"
|
||||
version = "11.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146"
|
||||
dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.9"
|
||||
|
@ -1192,6 +1323,15 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spinning_top"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
|
@ -1502,6 +1642,16 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-time"
|
||||
version = "1.1.0"
|
||||
|
@ -1521,6 +1671,22 @@ dependencies = [
|
|||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
|
@ -1530,6 +1696,12 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
|
|
|
@ -10,6 +10,7 @@ license = "MIT OR Apache-2.0"
|
|||
axum = "0.6.18"
|
||||
env_logger = "0.10.0"
|
||||
eyre = "0.6.12"
|
||||
governor = "0.10.0"
|
||||
idna = "1.0.3"
|
||||
log = "0.4.19"
|
||||
parking_lot = "0.12.3"
|
||||
|
|
3
src/disconnect_response_rate.json
Normal file
3
src/disconnect_response_rate.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"text": "You are trying to connect too fast. Please wait a minute before retrying."
|
||||
}
|
65
src/main.rs
65
src/main.rs
|
@ -9,14 +9,14 @@ use axum::{
|
|||
routing::{get, post},
|
||||
};
|
||||
use eyre::{eyre, Context};
|
||||
use log::{error, info};
|
||||
use log::{error, info, warn};
|
||||
use netty::{Handshake, ReadError};
|
||||
use quinn::{
|
||||
crypto::rustls::QuicServerConfig,
|
||||
rustls::pki_types::{CertificateDer, PrivateKeyDer},
|
||||
ConnectionError, Endpoint, Incoming, ServerConfig, TransportConfig,
|
||||
};
|
||||
use routing::RoutingTable;
|
||||
use routing::{RoutingError, RoutingTable};
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
net::TcpStream,
|
||||
|
@ -233,9 +233,17 @@ async fn try_handle_minecraft(
|
|||
let Some(address) = handshake.normalized_address() else {
|
||||
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;
|
||||
};
|
||||
let (mut send_host, mut recv_host) =
|
||||
match routing_table.route_limited(&address, peer.ip()).await {
|
||||
Ok(val) => val,
|
||||
Err(RoutingError::InvalidDomain) => {
|
||||
return politely_disconnect(connection, handshake).await;
|
||||
}
|
||||
Err(RoutingError::RateLimited) => {
|
||||
warn!("Connection from {} has been rate limited!", peer);
|
||||
return impolitely_disconnect(connection, handshake).await;
|
||||
}
|
||||
};
|
||||
handshake.send(&mut send_host).await?;
|
||||
let (mut recv_client, mut send_client) = connection.split();
|
||||
tokio::select! {
|
||||
|
@ -294,6 +302,53 @@ async fn politely_disconnect(mut connection: TcpStream, handshake: Handshake) ->
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn impolitely_disconnect(
|
||||
mut connection: TcpStream,
|
||||
handshake: Handshake,
|
||||
) -> eyre::Result<()> {
|
||||
match handshake.next_state {
|
||||
netty::HandshakeType::Status => {
|
||||
let packet = netty::read_packet(&mut connection, 1).await?;
|
||||
let mut packet = packet.as_slice();
|
||||
let id = packet.read_varint()?;
|
||||
if id != 0 {
|
||||
return Err(eyre!(
|
||||
"Packet isn't a Status Request(0x00), but {:#04x}",
|
||||
id
|
||||
));
|
||||
}
|
||||
let mut buf = vec![];
|
||||
buf.write_varint(0).await?;
|
||||
buf.write_string(include_str!("./serverlistping_response_rate.json"))
|
||||
.await?;
|
||||
connection.write_varint(buf.len() as i32).await?;
|
||||
connection.write_all(&buf).await?;
|
||||
let packet = netty::read_packet(&mut connection, 9).await?;
|
||||
let mut packet = packet.as_slice();
|
||||
let id = packet.read_varint()?;
|
||||
if id != 1 {
|
||||
return Err(eyre!("Packet isn't a Ping Request(0x01), but {:#04x}", id));
|
||||
}
|
||||
let payload = packet.read_long()?;
|
||||
let mut buf = Vec::with_capacity(1 + 8);
|
||||
buf.write_varint(1).await?;
|
||||
buf.write_u64(payload).await?;
|
||||
connection.write_varint(buf.len() as i32).await?;
|
||||
connection.write_all(&buf).await?;
|
||||
}
|
||||
netty::HandshakeType::Login => {
|
||||
let _ = netty::read_packet(&mut connection, 128).await?;
|
||||
let mut buf = vec![];
|
||||
buf.write_varint(0).await?;
|
||||
buf.write_string(include_str!("./disconnect_response_rate.json"))
|
||||
.await?;
|
||||
connection.write_varint(buf.len() as i32).await?;
|
||||
connection.write_all(&buf).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_minecraft(connection: TcpStream, routing_table: &'static RoutingTable) {
|
||||
if let Err(e) = try_handle_minecraft(connection, routing_table).await {
|
||||
error!("Error handling Minecraft connection: {:#}", e);
|
||||
|
|
|
@ -87,7 +87,10 @@ pub trait ReadExt: Read {
|
|||
// }
|
||||
}
|
||||
|
||||
pub async fn read_packet(mut reader: impl AsyncReadExt + Unpin, max_size: usize) -> Result<Vec<u8>, ReadError> {
|
||||
pub async fn read_packet(
|
||||
mut reader: impl AsyncReadExt + Unpin,
|
||||
max_size: usize,
|
||||
) -> Result<Vec<u8>, ReadError> {
|
||||
let len = read_varint(&mut reader).await?;
|
||||
if len < 0 || (len as usize) > max_size {
|
||||
return Err(if len == 254 {
|
||||
|
@ -101,7 +104,7 @@ pub async fn read_packet(mut reader: impl AsyncReadExt + Unpin, max_size: usize)
|
|||
}
|
||||
} else {
|
||||
ReadError::PacketTooLarge
|
||||
})
|
||||
});
|
||||
}
|
||||
let mut buf = vec![0u8; len as usize];
|
||||
if len == 254 {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use governor::DefaultKeyedRateLimiter;
|
||||
use governor::Quota;
|
||||
use log::info;
|
||||
use log::warn;
|
||||
use parking_lot::RwLock;
|
||||
|
@ -5,6 +7,7 @@ use quinn::RecvStream;
|
|||
use quinn::SendStream;
|
||||
use rand::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
use std::net::IpAddr;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
|
@ -18,10 +21,15 @@ 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>>,
|
||||
base_domain: String,
|
||||
limiter: DefaultKeyedRateLimiter<IpAddr>,
|
||||
}
|
||||
|
||||
pub enum RoutingError {
|
||||
InvalidDomain,
|
||||
RateLimited,
|
||||
}
|
||||
|
||||
impl RoutingTable {
|
||||
|
@ -29,6 +37,7 @@ impl RoutingTable {
|
|||
RoutingTable {
|
||||
table: RwLock::default(),
|
||||
base_domain,
|
||||
limiter: DefaultKeyedRateLimiter::dashmap(Quota::per_minute(30.try_into().unwrap())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,14 +53,24 @@ impl RoutingTable {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn route(&self, domain: &str) -> Option<(SendStream, RecvStream)> {
|
||||
pub async fn route_limited(
|
||||
&self,
|
||||
domain: &str,
|
||||
ip: IpAddr,
|
||||
) -> Result<(SendStream, RecvStream), RoutingError> {
|
||||
if self.limiter.check_key(&ip).is_err() {
|
||||
return Err(RoutingError::RateLimited);
|
||||
}
|
||||
self.limiter.retain_recent();
|
||||
let (send, recv) = oneshot::channel();
|
||||
self.table
|
||||
.read()
|
||||
.get(domain)?
|
||||
.get(domain)
|
||||
.ok_or(RoutingError::InvalidDomain)?
|
||||
.send(RouterRequest::RouteRequest(send))
|
||||
.ok()?;
|
||||
recv.await.ok()
|
||||
.ok()
|
||||
.ok_or(RoutingError::InvalidDomain)?;
|
||||
recv.await.ok().ok_or(RoutingError::InvalidDomain)
|
||||
}
|
||||
|
||||
fn random_domain(&self) -> String {
|
||||
|
|
13
src/serverlistping_response_rate.json
Normal file
13
src/serverlistping_response_rate.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"version": {
|
||||
"name": "e4mc",
|
||||
"protocol": -1
|
||||
},
|
||||
"players": {
|
||||
"max": 0,
|
||||
"online": 0
|
||||
},
|
||||
"description": {
|
||||
"text": "You are trying to connect too fast. Please wait a minute before retrying."
|
||||
}
|
||||
}
|
7989
src/wordlist.rs
7989
src/wordlist.rs
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue