fix DDoS when no data received from remote, better logging

This commit is contained in:
ari melody 2026-04-17 15:58:03 +01:00
parent fc34b1e328
commit 9426d23913
Signed by: ari
GPG key ID: CF99829C92678188
2 changed files with 48 additions and 29 deletions

View file

@ -136,7 +136,10 @@ env!("CARGO_PKG_VERSION"));
let address = addrs_iter.next().unwrap(); let address = addrs_iter.next().unwrap();
match MinecraftStatus::fetch(address) { match MinecraftStatus::fetch(address) {
Err(_) => { Err(e) => {
println!(
"Failed to connect to {} ({}): {}",
query_address, address, e);
response.status(StatusCode::InternalServerError); response.status(StatusCode::InternalServerError);
query_response = format!( query_response = format!(
"<hr/> "<hr/>

View file

@ -1,5 +1,6 @@
use std::io::{Error, ErrorKind, Read, Write, Result}; use std::io::{Error, ErrorKind, Read, Write, Result};
use std::net::{SocketAddr, TcpStream}; use std::net::{SocketAddr, TcpStream};
use std::time::Duration;
use crate::leb128::{read_leb128, write_leb128}; use crate::leb128::{read_leb128, write_leb128};
@ -56,26 +57,34 @@ pub struct MinecraftStatus {
impl MinecraftStatus { impl MinecraftStatus {
pub fn fetch(address: SocketAddr) -> Result<MinecraftStatus> { pub fn fetch(address: SocketAddr) -> Result<MinecraftStatus> {
// println!("Connecting to {address}..."); //println!("Connecting to {address}...");
let stream = TcpStream::connect(address.to_string()); let stream = TcpStream::connect_timeout(&address, Duration::new(5, 0));
if stream.is_err() { return Err(stream.unwrap_err()); } if stream.is_err() { return Err(stream.unwrap_err()); }
// println!("Connected!");
//println!("Connected!");
let mut stream = stream.unwrap(); let mut stream = stream.unwrap();
let mut send_buffer: Vec<u8> = Vec::new(); let mut send_buffer: Vec<u8> = Vec::new();
// println!("Sending payload..."); //println!("Sending payload...");
send_buffer.push(0x00);
write_leb128(&mut send_buffer, 769); // 1.21.4 send_buffer.push(0x00); // packet ID
write_leb128(&mut send_buffer, address.ip().to_string().len().try_into().unwrap()); write_leb128(&mut send_buffer, 769); // "i am 1.21.4"
send_buffer.extend_from_slice(address.ip().to_string().as_bytes()); write_leb128(&mut send_buffer, // upcoming address length
send_buffer.extend_from_slice(&address.port().to_be_bytes()); address.ip().to_string().len().try_into().unwrap());
write_leb128(&mut send_buffer, 1); send_buffer.extend_from_slice( // the address
address.ip().to_string().as_bytes());
send_buffer.extend_from_slice( // the port
&address.port().to_be_bytes());
write_leb128(&mut send_buffer, 1); // give me status please <3
send_packet(&mut stream, &send_buffer).unwrap(); send_packet(&mut stream, &send_buffer).unwrap();
send_packet(&mut stream, &[0x00]).unwrap(); send_packet(&mut stream, &[0x00]).unwrap();
//println!("Payload sent, receiving...\n");
let mut data: Vec<u8> = Vec::new(); let mut data: Vec<u8> = Vec::new();
let mut len: usize = 0; let mut len: usize = 0;
let mut msg_len: usize = 0; let mut msg_len: usize = 0;
@ -84,28 +93,35 @@ impl MinecraftStatus {
loop { loop {
let mut recv_buffer: [u8; 10240] = [0; 10240]; let mut recv_buffer: [u8; 10240] = [0; 10240];
len += stream.read(&mut recv_buffer)?; match stream.read(&mut recv_buffer) {
Ok(_len) => len += _len,
Err(e) => return Err(e)
};
if len > 0 { if len == 0 {
if msg_len == 0 { return Err(Error::new(ErrorKind::HostUnreachable, format!("No data received from remote")));
let mut val: u32; }
(val, offset) = read_leb128(&recv_buffer);
msg_len = val as usize;
if recv_buffer[offset] != 0x00 { //println!("< {} bytes\n", len);
return Err(Error::new(ErrorKind::InvalidData, format!("Expected packet type 0x00, but got 0x{:02x?}!", recv_buffer[offset])));
}
offset += 1; // skip message type bit
let offset2: usize; if msg_len == 0 {
(val, offset2) = read_leb128(&recv_buffer[offset..]); let mut val: u32;
object_len = val as usize; (val, offset) = read_leb128(&recv_buffer);
offset += offset2; msg_len = val as usize;
}
data.extend_from_slice(&recv_buffer); if recv_buffer[offset] != 0x00 {
if len >= offset + object_len { return Err(Error::new(ErrorKind::InvalidData, format!("Expected packet type 0x00, but got 0x{:02x?}!", recv_buffer[offset])));
break;
} }
offset += 1; // skip message type bit
let offset2: usize;
(val, offset2) = read_leb128(&recv_buffer[offset..]);
object_len = val as usize;
offset += offset2;
}
data.extend_from_slice(&recv_buffer);
if len >= offset + object_len {
break;
} }
} }
let msg = std::str::from_utf8(&data[offset..]).unwrap().trim(); let msg = std::str::from_utf8(&data[offset..]).unwrap().trim();