Merge branch 'main' into dev
This commit is contained in:
commit
ec4d6035e8
4 changed files with 79 additions and 49 deletions
|
|
@ -7,7 +7,7 @@ const RECURSION_DESIRED: u16 = 1 << 8;
|
||||||
const RECORD_TYPE_SRV: u16 = 33;
|
const RECORD_TYPE_SRV: u16 = 33;
|
||||||
const RECORD_CLASS_IN: u16 = 1;
|
const RECORD_CLASS_IN: u16 = 1;
|
||||||
|
|
||||||
pub fn create_dns_query(qname: &String, qtype: u16, qclass: u16) -> Result<Vec<u8>> {
|
pub fn create_dns_query(qname: &str, qtype: u16, qclass: u16) -> Result<Vec<u8>> {
|
||||||
let qname = match qname.is_ascii() {
|
let qname = match qname.is_ascii() {
|
||||||
true => qname,
|
true => qname,
|
||||||
false => return Err(Error::new(ErrorKind::InvalidInput, "domain is not valid ASCII")),
|
false => return Err(Error::new(ErrorKind::InvalidInput, "domain is not valid ASCII")),
|
||||||
|
|
@ -110,7 +110,7 @@ pub fn parse_srv_response(mut ptr: usize, recv: &[u8]) -> Option<DnsSrvResponse>
|
||||||
|
|
||||||
pub fn resolve_srv_port(domain: &str) -> Option<u16> {
|
pub fn resolve_srv_port(domain: &str) -> Option<u16> {
|
||||||
let request = create_dns_query(
|
let request = create_dns_query(
|
||||||
&("_minecraft._tcp.".to_string() + domain),
|
&format!("_minecraft._tcp.{}", domain),
|
||||||
RECORD_TYPE_SRV,
|
RECORD_TYPE_SRV,
|
||||||
RECORD_CLASS_IN).unwrap();
|
RECORD_CLASS_IN).unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
23
src/http.rs
23
src/http.rs
|
|
@ -41,7 +41,7 @@ impl StatusCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type HttpHandlerFunc = fn(&Request, Response) -> Result<StatusCode>;
|
type HttpHandlerFunc = fn(&Request, Response, bool) -> Result<StatusCode>;
|
||||||
|
|
||||||
pub struct Request<'a> {
|
pub struct Request<'a> {
|
||||||
stream: &'a TcpStream,
|
stream: &'a TcpStream,
|
||||||
|
|
@ -213,20 +213,21 @@ impl<'a> Response<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HttpServer {
|
pub struct HttpServer<'a> {
|
||||||
address: String,
|
address: &'a str,
|
||||||
port: u16,
|
port: u16,
|
||||||
trusted_proxies: Arc<Vec<IpAddr>>,
|
trusted_proxies: Arc<Vec<IpAddr>>,
|
||||||
max_connections: usize,
|
max_connections: usize,
|
||||||
|
verbose: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpServer {
|
impl HttpServer <'_> {
|
||||||
pub fn new(address: String, max_connections: usize, trusted_proxies: Vec<IpAddr>) -> HttpServer {
|
pub fn new(address: &'_ str, max_connections: usize, trusted_proxies: Vec<IpAddr>, verbose: bool) -> HttpServer<'_> {
|
||||||
let mut _address = address.clone();
|
let mut _address = address;
|
||||||
let mut _port: u16 = 8080;
|
let mut _port: u16 = 8080;
|
||||||
match address.split_once(":") {
|
match address.split_once(":") {
|
||||||
Some((ip, port)) => {
|
Some((ip, port)) => {
|
||||||
_address = ip.to_string();
|
_address = ip;
|
||||||
_port = port.parse::<u16>().expect(format!("Invalid port {}", port).as_str());
|
_port = port.parse::<u16>().expect(format!("Invalid port {}", port).as_str());
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
|
|
@ -236,12 +237,14 @@ impl HttpServer {
|
||||||
port: _port,
|
port: _port,
|
||||||
trusted_proxies: Arc::new(trusted_proxies),
|
trusted_proxies: Arc::new(trusted_proxies),
|
||||||
max_connections,
|
max_connections,
|
||||||
|
verbose,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&self, handler: HttpHandlerFunc) -> Result<()> {
|
pub fn start(&self, handler: HttpHandlerFunc) -> Result<()> {
|
||||||
let pool = ThreadPool::new(self.max_connections);
|
let pool = ThreadPool::new(self.max_connections);
|
||||||
let listener = TcpListener::bind(format!("{}:{}", self.address, self.port)).expect("Failed to bind to port");
|
let listener = TcpListener::bind(format!("{}:{}", self.address, self.port)).expect("Failed to bind to port");
|
||||||
|
let verbose = self.verbose;
|
||||||
|
|
||||||
println!("Now listening on {}:{}", self.address, self.port);
|
println!("Now listening on {}:{}", self.address, self.port);
|
||||||
|
|
||||||
|
|
@ -250,7 +253,7 @@ impl HttpServer {
|
||||||
Ok(stream) => {
|
Ok(stream) => {
|
||||||
let trusted_proxies = self.trusted_proxies.clone();
|
let trusted_proxies = self.trusted_proxies.clone();
|
||||||
pool.execute(move || {
|
pool.execute(move || {
|
||||||
HttpServer::handle_client(&stream, handler, trusted_proxies);
|
HttpServer::handle_client(&stream, handler, trusted_proxies, verbose);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -262,7 +265,7 @@ impl HttpServer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_client(stream: &TcpStream, handler: HttpHandlerFunc, trusted_proxies: Arc<Vec<IpAddr>>) {
|
fn handle_client(stream: &TcpStream, handler: HttpHandlerFunc, trusted_proxies: Arc<Vec<IpAddr>>, verbose: bool) {
|
||||||
let buf_reader = BufReader::new(stream);
|
let buf_reader = BufReader::new(stream);
|
||||||
let http_request: Vec<String> = buf_reader
|
let http_request: Vec<String> = buf_reader
|
||||||
.lines()
|
.lines()
|
||||||
|
|
@ -280,7 +283,7 @@ impl HttpServer {
|
||||||
let response = Response::new(stream);
|
let response = Response::new(stream);
|
||||||
|
|
||||||
let start_date = Local::now();
|
let start_date = Local::now();
|
||||||
match handler(&request, response) {
|
match handler(&request, response, verbose) {
|
||||||
Ok(status) => {
|
Ok(status) => {
|
||||||
let end_date = Local::now();
|
let end_date = Local::now();
|
||||||
|
|
||||||
|
|
|
||||||
54
src/main.rs
54
src/main.rs
|
|
@ -53,7 +53,7 @@ fn parse_address(address: &str) -> Result<SocketAddr> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_html_request(request: &Request, response: &mut Response) -> Result<StatusCode> {
|
fn handle_html_request(request: &Request, response: &mut Response, verbose: bool) -> Result<StatusCode> {
|
||||||
let content = include_str!("views/index.html");
|
let content = include_str!("views/index.html");
|
||||||
response.set_header("Content-Type", "text/html".to_string());
|
response.set_header("Content-Type", "text/html".to_string());
|
||||||
response.status(StatusCode::OK);
|
response.status(StatusCode::OK);
|
||||||
|
|
@ -72,7 +72,7 @@ fn handle_html_request(request: &Request, response: &mut Response) -> Result<Sta
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
Ok(address) => {
|
Ok(address) => {
|
||||||
match MinecraftStatus::fetch(&address) {
|
match MinecraftStatus::fetch(&address, verbose) {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!(
|
println!(
|
||||||
"Failed to connect to {} ({}): {}",
|
"Failed to connect to {} ({}): {}",
|
||||||
|
|
@ -136,7 +136,7 @@ fn handle_html_request(request: &Request, response: &mut Response) -> Result<Sta
|
||||||
return response.send();
|
return response.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_json_request(request: &Request, response: &mut Response) -> Result<StatusCode> {
|
fn handle_json_request(request: &Request, response: &mut Response, verbose: bool) -> Result<StatusCode> {
|
||||||
response.set_header("Content-Type", "text/plain".to_string());
|
response.set_header("Content-Type", "text/plain".to_string());
|
||||||
response.status(StatusCode::OK);
|
response.status(StatusCode::OK);
|
||||||
|
|
||||||
|
|
@ -149,7 +149,7 @@ fn handle_json_request(request: &Request, response: &mut Response) -> Result<Sta
|
||||||
response.body("Invalid server address.\n".to_string());
|
response.body("Invalid server address.\n".to_string());
|
||||||
}
|
}
|
||||||
Ok(address) => {
|
Ok(address) => {
|
||||||
match MinecraftStatus::fetch(&address) {
|
match MinecraftStatus::fetch(&address, verbose) {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!(
|
println!(
|
||||||
"Failed to connect to {} ({}): {}",
|
"Failed to connect to {} ({}): {}",
|
||||||
|
|
@ -194,9 +194,7 @@ fn handle_json_request(request: &Request, response: &mut Response) -> Result<Sta
|
||||||
return response.send();
|
return response.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn print_help() {
|
||||||
let args: Vec<String> = env::args().collect();
|
|
||||||
if args.len() < 2 {
|
|
||||||
println!(
|
println!(
|
||||||
r#"Crafty McStatusFace, v{} - made with <3 by ari melody
|
r#"Crafty McStatusFace, v{} - made with <3 by ari melody
|
||||||
|
|
||||||
|
|
@ -206,13 +204,29 @@ $ mcstatusface serve [address[:port]]
|
||||||
Query a server:
|
Query a server:
|
||||||
$ mcstatusface <address[:port]>"#,
|
$ mcstatusface <address[:port]>"#,
|
||||||
env!("CARGO_PKG_VERSION"));
|
env!("CARGO_PKG_VERSION"));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
if args.len() < 2 {
|
||||||
|
print_help();
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if args[1] != "serve" {
|
let verbose = args.contains(&String::from("-v"));
|
||||||
let address = parse_address(&args[1]).expect("Failed to parse address");
|
|
||||||
let status = MinecraftStatus::fetch(&address).unwrap();
|
|
||||||
|
|
||||||
|
if !args[1..].contains(&String::from("serve")) {
|
||||||
|
let address_arg = match args[1..].iter().find(|arg| !arg.starts_with("-")) {
|
||||||
|
Some(arg) => arg,
|
||||||
|
None => {
|
||||||
|
print_help();
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let address = parse_address(&address_arg).expect("Failed to parse address");
|
||||||
|
|
||||||
|
match MinecraftStatus::fetch(&address, verbose) {
|
||||||
|
Ok(status) => {
|
||||||
println!("Version: {} ({})", status.version.name, status.version.protocol);
|
println!("Version: {} ({})", status.version.name, status.version.protocol);
|
||||||
println!("Players: {}/{}", status.players.online, status.players.max);
|
println!("Players: {}/{}", status.players.online, status.players.max);
|
||||||
println!(
|
println!(
|
||||||
|
|
@ -223,10 +237,20 @@ env!("CARGO_PKG_VERSION"));
|
||||||
println!("{}", status.parse_description());
|
println!("{}", status.parse_description());
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
},
|
||||||
|
Err (e) => {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::Other,
|
||||||
|
format!("Failed to fetch status: {}", e)));
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut address = "0.0.0.0:8080".to_string();
|
let mut address = "0.0.0.0:8080";
|
||||||
if args.len() > 2 { address = args[2].to_string() }
|
let address_args = args[1..].iter()
|
||||||
|
.filter(|arg| *arg != "-v" && *arg != "serve")
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
if !address_args.is_empty() { address = address_args[0] }
|
||||||
let trusted_proxies: Vec<IpAddr> =
|
let trusted_proxies: Vec<IpAddr> =
|
||||||
match env::var("MCSTATUSFACE_TRUSTED_PROXIES") {
|
match env::var("MCSTATUSFACE_TRUSTED_PROXIES") {
|
||||||
Err(_) => { vec![] }
|
Err(_) => { vec![] }
|
||||||
|
|
@ -242,7 +266,7 @@ env!("CARGO_PKG_VERSION"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
HttpServer::new(address, 16, trusted_proxies).start(|request, mut response| {
|
HttpServer::new(address, 16, trusted_proxies, verbose).start(|request, mut response, verbose| {
|
||||||
response.status(StatusCode::OK);
|
response.status(StatusCode::OK);
|
||||||
response.set_header("Content-Type", "text/plain".to_string());
|
response.set_header("Content-Type", "text/plain".to_string());
|
||||||
response.set_header("x-powered-by", "GIRL FUEL".to_string());
|
response.set_header("x-powered-by", "GIRL FUEL".to_string());
|
||||||
|
|
@ -264,11 +288,11 @@ env!("CARGO_PKG_VERSION"));
|
||||||
if request.headers().get("accept").is_some_and(
|
if request.headers().get("accept").is_some_and(
|
||||||
|accept| accept.contains("text/html")
|
|accept| accept.contains("text/html")
|
||||||
) {
|
) {
|
||||||
return handle_html_request(request, &mut response);
|
return handle_html_request(request, &mut response, verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON response
|
// JSON response
|
||||||
return handle_json_request(request, &mut response);
|
return handle_json_request(request, &mut response, verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
response.status(StatusCode::NotFound);
|
response.status(StatusCode::NotFound);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ use std::time::Duration;
|
||||||
|
|
||||||
use crate::leb128::{read_leb128, write_leb128};
|
use crate::leb128::{read_leb128, write_leb128};
|
||||||
|
|
||||||
|
const TIMEOUT_SECS: u64 = 5;
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
pub struct MinecraftVersion {
|
pub struct MinecraftVersion {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
@ -56,20 +58,21 @@ pub struct MinecraftStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MinecraftStatus {
|
impl MinecraftStatus {
|
||||||
pub fn fetch(address: &SocketAddr) -> Result<MinecraftStatus> {
|
pub fn fetch(address: &SocketAddr, verbose: bool) -> Result<MinecraftStatus> {
|
||||||
//println!("Connecting to {address}...");
|
if verbose { println!("Connecting to {address}..."); }
|
||||||
|
|
||||||
let stream = TcpStream::connect_timeout(address, Duration::new(5, 0));
|
let mut stream = match TcpStream::connect_timeout(
|
||||||
if stream.is_err() { return Err(stream.unwrap_err()); }
|
address, Duration::from_secs(TIMEOUT_SECS)) {
|
||||||
|
Ok(stream) => stream,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if verbose { println!("Connected!"); }
|
||||||
|
|
||||||
//println!("Connected!");
|
if verbose { println!("Sending payload..."); }
|
||||||
|
|
||||||
let mut stream = stream.unwrap();
|
|
||||||
|
|
||||||
let mut send_buffer: Vec<u8> = Vec::new();
|
let mut send_buffer: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
//println!("Sending payload...");
|
|
||||||
|
|
||||||
send_buffer.push(0x00); // packet ID
|
send_buffer.push(0x00); // packet ID
|
||||||
write_leb128(&mut send_buffer, 769); // "i am 1.21.4"
|
write_leb128(&mut send_buffer, 769); // "i am 1.21.4"
|
||||||
write_leb128(&mut send_buffer, // upcoming address length
|
write_leb128(&mut send_buffer, // upcoming address length
|
||||||
|
|
@ -83,7 +86,7 @@ impl MinecraftStatus {
|
||||||
|
|
||||||
send_packet(&mut stream, &[0x00]).unwrap();
|
send_packet(&mut stream, &[0x00]).unwrap();
|
||||||
|
|
||||||
//println!("Payload sent, receiving...\n");
|
if verbose { println!("Awaiting response..."); }
|
||||||
|
|
||||||
let mut data: Vec<u8> = Vec::new();
|
let mut data: Vec<u8> = Vec::new();
|
||||||
let mut len: usize = 0;
|
let mut len: usize = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue