From 8219292672bc84ba5facb9286bf75b923fdccbd6 Mon Sep 17 00:00:00 2001 From: funtimes909 <68979259+Funtimes909@users.noreply.github.com> Date: Sun, 5 Apr 2026 18:06:00 +1200 Subject: [PATCH] Improvements to scanning code --- src/database/mod.rs | 2 +- src/scanning/discovery.rs | 77 +++++++++++++++++---------------------- src/scanning/mod.rs | 23 ++++++++++++ 3 files changed, 58 insertions(+), 44 deletions(-) diff --git a/src/database/mod.rs b/src/database/mod.rs index 5fb1a07..037e909 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -241,7 +241,7 @@ impl ServerUpdateOperation { } /// Insert a servers icon into the favicons table - pub async fn update_or_insert_favicon(&self, hash: [u8; 32]) -> anyhow::Result<()> { + async fn update_or_insert_favicon(&self, hash: [u8; 32]) -> anyhow::Result<()> { sqlx::query("INSERT INTO favicons VALUES ($1, $2, $3) ON CONFLICT (hash) DO UPDATE set last_seen = EXCLUDED.last_seen") .bind(hash.as_slice()) .bind(&self.server.favicon) diff --git a/src/scanning/discovery.rs b/src/scanning/discovery.rs index 66bcecd..dd3a17d 100644 --- a/src/scanning/discovery.rs +++ b/src/scanning/discovery.rs @@ -1,21 +1,15 @@ -use chrono::Timelike; +use chrono::Utc; use sqlx::types::ipnet::{IpNet, Ipv4Net}; -use std::{ - net::{Ipv4Addr, SocketAddrV4}, - str::FromStr, -}; +use std::{net::Ipv4Addr, str::FromStr}; use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::process::Command; +use tracing::debug; -use crate::{ - config::Config, - database::{Database, ServerUpdateOperation}, - protocol::{minecraft::simple_ping, response::MinecraftServer}, -}; +use crate::CONFIG; +use crate::database::ServerUpdateOperation; +use crate::database::Database; pub struct DiscoveryScanner { - pub is_active: bool, - config: Config, database: Database, } @@ -23,7 +17,7 @@ impl DiscoveryScanner { async fn scan(&self) { // Spawn masscan let mut command = Command::new("sudo") - .args(["masscan", "-c", &self.config.masscan.config_file]) + .args(["masscan", "-c", &CONFIG.masscan.config_file]) .stdout(std::process::Stdio::piped()) .spawn() .expect("error while executing masscan"); @@ -40,54 +34,51 @@ impl DiscoveryScanner { while let Ok(Some(line)) = reader.next_line().await { let mut line = line.split_whitespace(); - // .nth() consumes all preceding elements so address will be the 2nd + // Address let address = match line.nth(1).and_then(|a| Ipv4Addr::from_str(a).ok()) { Some(address) => address, _ => continue, }; - // Get port + // Port let port = match line .nth(3) // Split on port/tcp .and_then(|p| p.split('/').nth(0)) // Parse as u16 - .and_then(|s| s.parse::().ok()) + .and_then(|s| s.parse().ok()) { Some(port) => port, None => continue, }; - let database_clone = self.database.clone(); + // Immediately ping any returned servers + let completed_server = super::run(address, port).await; - // Spawn a pinging task for each server found - tokio::spawn(async move { - let socket = SocketAddrV4::new(address, port); - let mut stream = tokio::net::TcpStream::connect(socket).await.unwrap(); + if let Ok(Ok(server)) = completed_server { + let insertion_operation = ServerUpdateOperation { + server, + address: IpNet::from(Ipv4Net::from(address)), + port: port as i32, + timestamp: Utc::now().naive_local(), + database: self.database.clone(), + }; - if let Ok(response) = simple_ping(&mut stream).await - && let Ok(server) = serde_json::from_str::(&response) - { - let address = IpNet::from(Ipv4Net::from(address)); - - if server.has_opted_out() { - println!("Deleting server!"); - database_clone.delete_server(address).await.unwrap(); - } - - let update_operation = ServerUpdateOperation { - server, - address, - port: port as i32, - timestamp: chrono::Utc::now().naive_utc().with_nanosecond(0).unwrap(), - database: database_clone, - }; - - update_operation.update_or_insert_server().await.unwrap(); - update_operation.update_or_insert_players().await.unwrap(); - update_operation.update_or_insert_mods().await.unwrap(); + // Update server + if let Err(e) = insertion_operation.update_or_insert_server().await { + debug!("Error while updating server ({address}:{port}) in database: {e}") } - }); + + // Update players + if let Err(e) = insertion_operation.update_or_insert_players().await { + debug!("Error while updating players ({address}:{port}) in database: {e}") + } + + // Update mods + if let Err(e) = insertion_operation.update_or_insert_mods().await { + debug!("Error while updating mods ({address}:{port}) in database: {e}") + } + } } } } diff --git a/src/scanning/mod.rs b/src/scanning/mod.rs index 53d74e9..a7a781c 100644 --- a/src/scanning/mod.rs +++ b/src/scanning/mod.rs @@ -1,2 +1,25 @@ +use std::net::{Ipv4Addr, SocketAddrV4}; +use anyhow::bail; +use tokio::{net::TcpStream, task::JoinHandle}; + +use crate::protocol::{minecraft, response::MinecraftServer}; + pub mod discovery; pub mod rescanner; + +pub fn run(address: Ipv4Addr, port: u16) -> JoinHandle> { + tokio::spawn(async move { + let socket = SocketAddrV4::new(address, port); + let mut stream = TcpStream::connect(socket).await.unwrap(); + + return match minecraft::simple_ping(&mut stream).await { + Ok(s) => { + match serde_json::from_str::(&s) { + Ok(server) => Ok(server), + Err(e) => bail!("{e}"), + } + } + Err(e) => bail!("{e}") + } + }) +} \ No newline at end of file