Re-work crate management
This commit is contained in:
@ -44,20 +44,35 @@ members = [
|
|||||||
unstable = []
|
unstable = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rocket = { git = "https://github.com/rwf2/Rocket/", rev = "3bf9ef02d6e803fe9f753777f5a829dda6d2453d"}
|
|
||||||
rocket_ws = { git = "https://github.com/rwf2/Rocket/", rev = "3bf9ef02d6e803fe9f753777f5a829dda6d2453d"}
|
|
||||||
rocket_db_pools = { git = "https://github.com/rwf2/Rocket/", rev = "3bf9ef02d6e803fe9f753777f5a829dda6d2453d", default-features = false, features = ["diesel_mysql"] }
|
rocket_db_pools = { git = "https://github.com/rwf2/Rocket/", rev = "3bf9ef02d6e803fe9f753777f5a829dda6d2453d", default-features = false, features = ["diesel_mysql"] }
|
||||||
|
snow-scanner-worker = {path = "./src/worker"}
|
||||||
|
diesel.workspace = true
|
||||||
|
dns-ptr-resolver.workspace = true
|
||||||
|
hickory-resolver.workspace = true
|
||||||
|
uuid.workspace = true
|
||||||
|
rocket.workspace = true
|
||||||
|
rocket_ws.workspace = true
|
||||||
|
ws.workspace = true
|
||||||
|
chrono.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
cidr.workspace = true
|
||||||
|
weighted-rs.workspace = true
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
# mariadb-dev on Alpine
|
# mariadb-dev on Alpine
|
||||||
# "mysqlclient-src" "mysql_backend"
|
# "mysqlclient-src" "mysql_backend"
|
||||||
diesel = { version = "^2", default-features = false, features = ["mysql", "chrono", "uuid"] }
|
diesel = { version = "^2", default-features = false, features = ["mysql", "chrono", "uuid"] }
|
||||||
|
|
||||||
ws = { package = "rocket_ws", version = "0.1.1" }
|
ws = { package = "rocket_ws", version = "0.1.1" }
|
||||||
|
|
||||||
dns-ptr-resolver = {git = "https://github.com/wdes/dns-ptr-resolver.git"}
|
dns-ptr-resolver = {git = "https://github.com/wdes/dns-ptr-resolver.git"}
|
||||||
hickory-resolver = { version = "0.24.1", default-features = false, features = ["tokio-runtime", "dns-over-h3", "dns-over-https", "dns-over-quic"]}
|
hickory-resolver = { version = "0.24.1", default-features = false, features = ["tokio-runtime", "dns-over-h3", "dns-over-https", "dns-over-quic"]}
|
||||||
|
|
||||||
|
rocket = { git = "https://github.com/rwf2/Rocket/", rev = "3bf9ef02d6e803fe9f753777f5a829dda6d2453d"}
|
||||||
|
rocket_ws = { git = "https://github.com/rwf2/Rocket/", rev = "3bf9ef02d6e803fe9f753777f5a829dda6d2453d"}
|
||||||
chrono = "0.4.38"
|
chrono = "0.4.38"
|
||||||
uuid = { version = "1.10.0", default-features = false, features = ["v7", "serde", "std"] }
|
uuid = { version = "1.10.0", default-features = false, features = ["v7", "serde", "std"] }
|
||||||
cidr = "0.3.0"
|
cidr = "0.3.0"
|
||||||
serde = { version = "1.0.210", features = ["derive"] }
|
serde = { version = "1.0.210", features = ["derive"] }
|
||||||
serde_json = "1.0.128"
|
serde_json = "1.0.128"
|
||||||
|
weighted-rs = "0.1.3"
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
use std::{net::IpAddr, str::FromStr};
|
use std::{net::IpAddr, str::FromStr};
|
||||||
|
|
||||||
use crate::{
|
use crate::{DbConnection, SnowDb};
|
||||||
worker::detection::{detect_scanner_from_name, validate_ip},
|
|
||||||
DbConnection, SnowDb,
|
|
||||||
};
|
|
||||||
use hickory_resolver::Name;
|
use hickory_resolver::Name;
|
||||||
use rocket::futures::channel::mpsc as rocket_mpsc;
|
use rocket::futures::channel::mpsc as rocket_mpsc;
|
||||||
use rocket::futures::StreamExt;
|
use rocket::futures::StreamExt;
|
||||||
use rocket::tokio;
|
use rocket::tokio;
|
||||||
|
use snow_scanner_worker::detection::{detect_scanner_from_name, validate_ip};
|
||||||
|
|
||||||
use crate::Scanner;
|
use crate::Scanner;
|
||||||
|
|
||||||
|
@ -27,29 +27,30 @@ use rocket_db_pools::{
|
|||||||
Connection, Pool,
|
Connection, Pool,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::worker::modules::{Network, WorkerMessages};
|
|
||||||
|
|
||||||
use rocket_db_pools::diesel::mysql::{Mysql, MysqlValue};
|
|
||||||
use rocket_db_pools::diesel::serialize::IsNull;
|
|
||||||
use rocket_db_pools::diesel::sql_types::Text;
|
|
||||||
use rocket_db_pools::diesel::MysqlPool;
|
use rocket_db_pools::diesel::MysqlPool;
|
||||||
use rocket_db_pools::diesel::{deserialize, serialize};
|
|
||||||
use rocket_db_pools::Database;
|
use rocket_db_pools::Database;
|
||||||
|
|
||||||
use rocket_ws::WebSocket;
|
use rocket_ws::WebSocket;
|
||||||
use server::Server;
|
use server::Server;
|
||||||
use worker::detection::{detect_scanner, get_dns_client, validate_ip, Scanners};
|
use weighted_rs::Weight;
|
||||||
|
|
||||||
|
use snow_scanner_worker::detection::{
|
||||||
|
detect_scanner, get_dns_client, get_dns_server_config, validate_ip,
|
||||||
|
};
|
||||||
|
use snow_scanner_worker::modules::{Network, WorkerMessages};
|
||||||
|
use snow_scanner_worker::scanners::IsStatic;
|
||||||
|
use snow_scanner_worker::scanners::Scanners;
|
||||||
|
use snow_scanner_worker::utils::get_dns_rr;
|
||||||
|
|
||||||
|
use std::net::SocketAddr;
|
||||||
use std::{
|
use std::{
|
||||||
env, fmt,
|
env,
|
||||||
net::IpAddr,
|
net::IpAddr,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
use std::{io::Write, net::SocketAddr};
|
|
||||||
use std::{path::PathBuf, str::FromStr};
|
use std::{path::PathBuf, str::FromStr};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use dns_ptr_resolver::{get_ptr, ResolvedResult};
|
use dns_ptr_resolver::{get_ptr, ResolvedResult};
|
||||||
|
|
||||||
@ -57,7 +58,6 @@ pub mod event_bus;
|
|||||||
pub mod models;
|
pub mod models;
|
||||||
pub mod schema;
|
pub mod schema;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod worker;
|
|
||||||
|
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
|
|
||||||
@ -99,20 +99,6 @@ impl<D: Database> DerefMut for DbConnection<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait IsStatic {
|
|
||||||
fn is_static(self: &Self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IsStatic for Scanners {
|
|
||||||
fn is_static(self: &Self) -> bool {
|
|
||||||
match self {
|
|
||||||
Scanners::Censys => true,
|
|
||||||
Scanners::InternetMeasurement => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(serde::Deserialize, Clone)]
|
#[derive(serde::Deserialize, Clone)]
|
||||||
struct SafeIpAddr {
|
struct SafeIpAddr {
|
||||||
pub addr: IpAddr,
|
pub addr: IpAddr,
|
||||||
@ -137,109 +123,12 @@ impl FromFormField<'_> for SafeIpAddr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromParam<'_> for Scanners {
|
|
||||||
type Error = String;
|
|
||||||
|
|
||||||
fn from_param(param: &'_ str) -> Result<Self, Self::Error> {
|
|
||||||
match param {
|
|
||||||
"stretchoid" => Ok(Scanners::Stretchoid),
|
|
||||||
"binaryedge" => Ok(Scanners::Binaryedge),
|
|
||||||
"shadowserver" => Ok(Scanners::Shadowserver),
|
|
||||||
"stretchoid.txt" => Ok(Scanners::Stretchoid),
|
|
||||||
"binaryedge.txt" => Ok(Scanners::Binaryedge),
|
|
||||||
"shadowserver.txt" => Ok(Scanners::Shadowserver),
|
|
||||||
"censys.txt" => Ok(Scanners::Censys),
|
|
||||||
"internet-measurement.com.txt" => Ok(Scanners::InternetMeasurement),
|
|
||||||
v => Err(format!("Unknown value: {v}")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Scanners {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let s = <Vec<String>>::deserialize(deserializer)?;
|
|
||||||
let k: &str = s[0].as_str();
|
|
||||||
match k {
|
|
||||||
"stretchoid" => Ok(Scanners::Stretchoid),
|
|
||||||
"binaryedge" => Ok(Scanners::Binaryedge),
|
|
||||||
"shadowserver" => Ok(Scanners::Shadowserver),
|
|
||||||
"stretchoid.txt" => Ok(Scanners::Stretchoid),
|
|
||||||
"binaryedge.txt" => Ok(Scanners::Binaryedge),
|
|
||||||
"shadowserver.txt" => Ok(Scanners::Shadowserver),
|
|
||||||
"censys.txt" => Ok(Scanners::Censys),
|
|
||||||
"internet-measurement.com.txt" => Ok(Scanners::InternetMeasurement),
|
|
||||||
v => Err(serde::de::Error::custom(format!(
|
|
||||||
"Unknown value: {}",
|
|
||||||
v.to_string()
|
|
||||||
))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Scanners {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{}",
|
|
||||||
match self {
|
|
||||||
Self::Stretchoid => "stretchoid",
|
|
||||||
Self::Binaryedge => "binaryedge",
|
|
||||||
Self::Censys => "censys",
|
|
||||||
Self::InternetMeasurement => "internet-measurement.com",
|
|
||||||
Self::Shadowserver => "shadowserver",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl serialize::ToSql<Text, Mysql> for Scanners {
|
|
||||||
fn to_sql(&self, out: &mut serialize::Output<Mysql>) -> serialize::Result {
|
|
||||||
match *self {
|
|
||||||
Self::Stretchoid => out.write_all(b"stretchoid")?,
|
|
||||||
Self::Binaryedge => out.write_all(b"binaryedge")?,
|
|
||||||
Self::Censys => out.write_all(b"censys")?,
|
|
||||||
Self::InternetMeasurement => out.write_all(b"internet-measurement.com")?,
|
|
||||||
Self::Shadowserver => out.write_all(b"shadowserver")?,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(IsNull::No)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl deserialize::FromSql<Text, Mysql> for Scanners {
|
|
||||||
fn from_sql(bytes: MysqlValue) -> deserialize::Result<Self> {
|
|
||||||
let value = <String as deserialize::FromSql<Text, Mysql>>::from_sql(bytes)?;
|
|
||||||
let value = &value as &str;
|
|
||||||
let value: Result<Scanners, String> = value.try_into();
|
|
||||||
match value {
|
|
||||||
Ok(d) => Ok(d),
|
|
||||||
Err(err) => Err(err.into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryInto<Scanners> for &str {
|
|
||||||
type Error = String;
|
|
||||||
|
|
||||||
fn try_into(self) -> Result<Scanners, Self::Error> {
|
|
||||||
match self {
|
|
||||||
"stretchoid" => Ok(Scanners::Stretchoid),
|
|
||||||
"binaryedge" => Ok(Scanners::Binaryedge),
|
|
||||||
"internet-measurement.com" => Ok(Scanners::InternetMeasurement),
|
|
||||||
"shadowserver" => Ok(Scanners::Shadowserver),
|
|
||||||
value => Err(format!("Invalid value: {value}")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_ip(
|
async fn handle_ip(
|
||||||
query_address: IpAddr,
|
query_address: IpAddr,
|
||||||
) -> Result<(IpAddr, Option<Scanners>, ResolvedResult), ()> {
|
) -> Result<(IpAddr, Option<Scanners>, ResolvedResult), ()> {
|
||||||
let ptr_result: Result<ResolvedResult, ()> = std::thread::spawn(move || {
|
let ptr_result: Result<ResolvedResult, ()> = std::thread::spawn(move || {
|
||||||
let client = get_dns_client();
|
let mut rr_dns_servers = get_dns_rr();
|
||||||
|
let client = get_dns_client(&get_dns_server_config(&rr_dns_servers.next().unwrap()));
|
||||||
let ptr_result: ResolvedResult = if let Ok(res) = get_ptr(query_address, client) {
|
let ptr_result: ResolvedResult = if let Ok(res) = get_ptr(query_address, client) {
|
||||||
res
|
res
|
||||||
} else {
|
} else {
|
||||||
|
@ -2,11 +2,9 @@ use rocket::futures::{stream::Next, SinkExt, StreamExt};
|
|||||||
use rocket_ws::{frame::CloseFrame, Message};
|
use rocket_ws::{frame::CloseFrame, Message};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use crate::{
|
use crate::event_bus::{EventBusEvent, EventBusWriter, EventBusWriterEvent};
|
||||||
event_bus::{EventBusEvent, EventBusWriter, EventBusWriterEvent},
|
|
||||||
worker::modules::WorkerMessages,
|
|
||||||
};
|
|
||||||
use rocket::futures::channel::mpsc as rocket_mpsc;
|
use rocket::futures::channel::mpsc as rocket_mpsc;
|
||||||
|
use snow_scanner_worker::modules::WorkerMessages;
|
||||||
|
|
||||||
pub struct Server {}
|
pub struct Server {}
|
||||||
|
|
||||||
|
@ -10,17 +10,25 @@ description = "The CLI to run a snow-scanner worker"
|
|||||||
name = "snow-scanner-worker"
|
name = "snow-scanner-worker"
|
||||||
path = "worker.rs"
|
path = "worker.rs"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "snow_scanner_worker"
|
||||||
|
path = "mod.rs"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tungstenite = { version = "0.24.0", default-features = true, features = ["native-tls"] }
|
tungstenite = { version = "0.24.0", default-features = true, features = ["native-tls"] }
|
||||||
rocket_ws = { git = "https://github.com/rwf2/Rocket/", rev = "3bf9ef02d6e803fe9f753777f5a829dda6d2453d", default-features = true}
|
rocket.workspace = true
|
||||||
|
rocket_ws.workspace = true
|
||||||
log2 = "0.1.11"
|
log2 = "0.1.11"
|
||||||
diesel = { version = "2", default-features = false, features = [] }
|
diesel.workspace = true
|
||||||
dns-ptr-resolver = {git = "https://github.com/wdes/dns-ptr-resolver.git"}
|
dns-ptr-resolver.workspace = true
|
||||||
hickory-resolver = { version = "0.24.1", default-features = false, features = ["tokio-runtime", "dns-over-h3", "dns-over-https", "dns-over-quic"]}
|
hickory-resolver.workspace = true
|
||||||
chrono = "0.4.38"
|
chrono.workspace = true
|
||||||
uuid = { version = "1.10.0", default-features = false, features = ["v7", "serde", "std"] }
|
uuid.workspace = true
|
||||||
cidr = "0.2.2"
|
cidr.workspace = true
|
||||||
serde = "1.0.210"
|
serde.workspace = true
|
||||||
serde_json = "1.0.128"
|
serde_json.workspace = true
|
||||||
|
weighted-rs.workspace = true
|
||||||
|
rayon = "1.10.0"
|
||||||
|
rand = "0.8.5"
|
||||||
|
@ -2,7 +2,7 @@ use std::net::IpAddr;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use diesel::deserialize::FromSqlRow;
|
use crate::scanners::Scanners;
|
||||||
use dns_ptr_resolver::ResolvedResult;
|
use dns_ptr_resolver::ResolvedResult;
|
||||||
|
|
||||||
use hickory_resolver::config::{NameServerConfigGroup, ResolverConfig, ResolverOpts};
|
use hickory_resolver::config::{NameServerConfigGroup, ResolverConfig, ResolverOpts};
|
||||||
@ -10,25 +10,15 @@ use hickory_resolver::{Name, Resolver};
|
|||||||
|
|
||||||
use crate::ip_addr::is_global_hardcoded;
|
use crate::ip_addr::is_global_hardcoded;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, FromSqlRow, PartialEq)]
|
pub fn get_dns_server_config(server_ips: &Vec<IpAddr>) -> NameServerConfigGroup {
|
||||||
pub enum Scanners {
|
NameServerConfigGroup::from_ips_clear(
|
||||||
Stretchoid,
|
server_ips, 53, // Port 53
|
||||||
Binaryedge,
|
true,
|
||||||
Shadowserver,
|
)
|
||||||
Censys,
|
|
||||||
InternetMeasurement,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_dns_client() -> Resolver {
|
pub fn get_dns_client(server: &NameServerConfigGroup) -> Resolver {
|
||||||
let server_ip = "1.1.1.1";
|
let config = ResolverConfig::from_parts(None, vec![], server.clone());
|
||||||
|
|
||||||
let server = NameServerConfigGroup::from_ips_clear(
|
|
||||||
&[IpAddr::from_str(server_ip).unwrap()],
|
|
||||||
53, // Port 53
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
let config = ResolverConfig::from_parts(None, vec![], server);
|
|
||||||
let mut options = ResolverOpts::default();
|
let mut options = ResolverOpts::default();
|
||||||
options.timeout = Duration::from_secs(5);
|
options.timeout = Duration::from_secs(5);
|
||||||
options.attempts = 1; // One try
|
options.attempts = 1; // One try
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
pub mod detection;
|
pub mod detection;
|
||||||
pub mod ip_addr;
|
pub mod ip_addr;
|
||||||
pub mod modules;
|
pub mod modules;
|
||||||
|
pub mod scanners;
|
||||||
|
pub mod utils;
|
||||||
|
133
snow-scanner/src/worker/scanners.rs
Normal file
133
snow-scanner/src/worker/scanners.rs
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
use diesel::deserialize;
|
||||||
|
use diesel::deserialize::FromSqlRow;
|
||||||
|
use diesel::mysql::Mysql;
|
||||||
|
use diesel::mysql::MysqlValue;
|
||||||
|
use diesel::serialize;
|
||||||
|
use diesel::serialize::IsNull;
|
||||||
|
use diesel::sql_types::Text;
|
||||||
|
use rocket::request::FromParam;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
use std::fmt;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, FromSqlRow, PartialEq)]
|
||||||
|
pub enum Scanners {
|
||||||
|
Stretchoid,
|
||||||
|
Binaryedge,
|
||||||
|
Shadowserver,
|
||||||
|
Censys,
|
||||||
|
InternetMeasurement,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IsStatic {
|
||||||
|
fn is_static(self: &Self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IsStatic for Scanners {
|
||||||
|
fn is_static(self: &Self) -> bool {
|
||||||
|
match self {
|
||||||
|
Scanners::Censys => true,
|
||||||
|
Scanners::InternetMeasurement => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromParam<'_> for Scanners {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn from_param(param: &'_ str) -> Result<Self, Self::Error> {
|
||||||
|
match param {
|
||||||
|
"stretchoid" => Ok(Scanners::Stretchoid),
|
||||||
|
"binaryedge" => Ok(Scanners::Binaryedge),
|
||||||
|
"shadowserver" => Ok(Scanners::Shadowserver),
|
||||||
|
"stretchoid.txt" => Ok(Scanners::Stretchoid),
|
||||||
|
"binaryedge.txt" => Ok(Scanners::Binaryedge),
|
||||||
|
"shadowserver.txt" => Ok(Scanners::Shadowserver),
|
||||||
|
"censys.txt" => Ok(Scanners::Censys),
|
||||||
|
"internet-measurement.com.txt" => Ok(Scanners::InternetMeasurement),
|
||||||
|
v => Err(format!("Unknown value: {v}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Scanners {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let s = <Vec<String>>::deserialize(deserializer)?;
|
||||||
|
let k: &str = s[0].as_str();
|
||||||
|
match k {
|
||||||
|
"stretchoid" => Ok(Scanners::Stretchoid),
|
||||||
|
"binaryedge" => Ok(Scanners::Binaryedge),
|
||||||
|
"shadowserver" => Ok(Scanners::Shadowserver),
|
||||||
|
"stretchoid.txt" => Ok(Scanners::Stretchoid),
|
||||||
|
"binaryedge.txt" => Ok(Scanners::Binaryedge),
|
||||||
|
"shadowserver.txt" => Ok(Scanners::Shadowserver),
|
||||||
|
"censys.txt" => Ok(Scanners::Censys),
|
||||||
|
"internet-measurement.com.txt" => Ok(Scanners::InternetMeasurement),
|
||||||
|
v => Err(serde::de::Error::custom(format!(
|
||||||
|
"Unknown value: {}",
|
||||||
|
v.to_string()
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Scanners {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
Self::Stretchoid => "stretchoid",
|
||||||
|
Self::Binaryedge => "binaryedge",
|
||||||
|
Self::Censys => "censys",
|
||||||
|
Self::InternetMeasurement => "internet-measurement.com",
|
||||||
|
Self::Shadowserver => "shadowserver",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serialize::ToSql<Text, Mysql> for Scanners {
|
||||||
|
fn to_sql(&self, out: &mut serialize::Output<Mysql>) -> serialize::Result {
|
||||||
|
match *self {
|
||||||
|
Self::Stretchoid => out.write_all(b"stretchoid")?,
|
||||||
|
Self::Binaryedge => out.write_all(b"binaryedge")?,
|
||||||
|
Self::Censys => out.write_all(b"censys")?,
|
||||||
|
Self::InternetMeasurement => out.write_all(b"internet-measurement.com")?,
|
||||||
|
Self::Shadowserver => out.write_all(b"shadowserver")?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(IsNull::No)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl deserialize::FromSql<Text, Mysql> for Scanners {
|
||||||
|
fn from_sql(bytes: MysqlValue) -> deserialize::Result<Self> {
|
||||||
|
let value = <String as deserialize::FromSql<Text, Mysql>>::from_sql(bytes)?;
|
||||||
|
let value = &value as &str;
|
||||||
|
let value: Result<Scanners, String> = value.try_into();
|
||||||
|
match value {
|
||||||
|
Ok(d) => Ok(d),
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryInto<Scanners> for &str {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_into(self) -> Result<Scanners, Self::Error> {
|
||||||
|
match self {
|
||||||
|
"stretchoid" => Ok(Scanners::Stretchoid),
|
||||||
|
"binaryedge" => Ok(Scanners::Binaryedge),
|
||||||
|
"internet-measurement.com" => Ok(Scanners::InternetMeasurement),
|
||||||
|
"shadowserver" => Ok(Scanners::Shadowserver),
|
||||||
|
value => Err(format!("Invalid value: {value}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
snow-scanner/src/worker/utils.rs
Normal file
35
snow-scanner/src/worker/utils.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use rand::seq::SliceRandom;
|
||||||
|
use rand::thread_rng;
|
||||||
|
use std::net::IpAddr;
|
||||||
|
use weighted_rs::{RoundrobinWeight, Weight};
|
||||||
|
|
||||||
|
pub fn get_dns_rr() -> RoundrobinWeight<Vec<IpAddr>> {
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
// https://gist.github.com/mutin-sa/5dcbd35ee436eb629db7872581093bc5
|
||||||
|
let dns_servers: Vec<IpAddr> = vec![
|
||||||
|
IpAddr::from_str("1.1.1.1").unwrap(),
|
||||||
|
IpAddr::from_str("1.0.0.1").unwrap(),
|
||||||
|
IpAddr::from_str("8.8.8.8").unwrap(),
|
||||||
|
IpAddr::from_str("8.8.4.4").unwrap(),
|
||||||
|
IpAddr::from_str("9.9.9.9").unwrap(),
|
||||||
|
IpAddr::from_str("9.9.9.10").unwrap(),
|
||||||
|
IpAddr::from_str("208.67.222.222").unwrap(), // OpenDNS Cisco
|
||||||
|
IpAddr::from_str("208.67.220.220").unwrap(), // OpenDNS Cisco
|
||||||
|
IpAddr::from_str("208.67.222.220").unwrap(), // OpenDNS Cisco
|
||||||
|
IpAddr::from_str("208.67.220.222").unwrap(), // OpenDNS Cisco
|
||||||
|
IpAddr::from_str("193.110.81.0").unwrap(), // dns0.eu AS50902
|
||||||
|
IpAddr::from_str("185.253.5.0").unwrap(), // dns0.eu AS50902
|
||||||
|
IpAddr::from_str("74.82.42.42").unwrap(), // Hurricane Electric [AS6939]
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut rr: RoundrobinWeight<Vec<IpAddr>> = RoundrobinWeight::new();
|
||||||
|
// For each entry in the list we create a lot of two DNS servers to use
|
||||||
|
for _ in &dns_servers {
|
||||||
|
let mut client_servers = dns_servers.clone();
|
||||||
|
client_servers.shuffle(&mut thread_rng());
|
||||||
|
client_servers.truncate(2);
|
||||||
|
rr.add(client_servers, 1);
|
||||||
|
}
|
||||||
|
rr
|
||||||
|
}
|
@ -1,18 +1,24 @@
|
|||||||
use std::{env, net::IpAddr};
|
use std::{env, net::IpAddr};
|
||||||
|
|
||||||
use chrono::{Duration, NaiveDateTime, Utc};
|
use chrono::{Duration, NaiveDateTime, Utc};
|
||||||
|
use cidr::IpCidr;
|
||||||
use detection::detect_scanner;
|
use detection::detect_scanner;
|
||||||
use dns_ptr_resolver::get_ptr;
|
use dns_ptr_resolver::{get_ptr, ResolvedResult};
|
||||||
use log2::*;
|
use log2::*;
|
||||||
|
use scanners::Scanners;
|
||||||
use tungstenite::stream::MaybeTlsStream;
|
use tungstenite::stream::MaybeTlsStream;
|
||||||
use tungstenite::{connect, Error, Message, WebSocket};
|
use tungstenite::{connect, Error, Message, WebSocket};
|
||||||
|
use weighted_rs::Weight;
|
||||||
|
|
||||||
pub mod detection;
|
pub mod detection;
|
||||||
pub mod ip_addr;
|
pub mod ip_addr;
|
||||||
pub mod modules;
|
pub mod modules;
|
||||||
|
pub mod scanners;
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
use crate::detection::get_dns_client;
|
use crate::detection::{get_dns_client, get_dns_server_config};
|
||||||
use crate::modules::WorkerMessages;
|
use crate::modules::WorkerMessages;
|
||||||
|
use crate::utils::get_dns_rr;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct IpToResolve {
|
pub struct IpToResolve {
|
||||||
@ -143,32 +149,20 @@ impl Worker {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn receive_request(&mut self, server_request: WorkerMessages) -> &Worker {
|
fn work_on_cidr(&mut self, cidr: IpCidr) {
|
||||||
match server_request {
|
|
||||||
WorkerMessages::DoWorkRequest { neworks } => {
|
|
||||||
info!("Should work on: {:?}", neworks);
|
|
||||||
for cidr in neworks {
|
|
||||||
let cidr = cidr.0;
|
|
||||||
info!("Picking up: {cidr}");
|
info!("Picking up: {cidr}");
|
||||||
info!("Range, from {} to {}", cidr.first(), cidr.last());
|
info!("Range, from {} to {}", cidr.first(), cidr.last());
|
||||||
let addresses = cidr.iter().addresses();
|
let addresses = cidr.iter().addresses();
|
||||||
let count = addresses.count();
|
let count = addresses.count();
|
||||||
let mut current = 0;
|
let mut current = 0;
|
||||||
|
let mut rr_dns_servers = get_dns_rr();
|
||||||
|
|
||||||
for addr in addresses {
|
for addr in addresses {
|
||||||
let client = get_dns_client();
|
let client = get_dns_client(&get_dns_server_config(&rr_dns_servers.next().unwrap()));
|
||||||
match get_ptr(addr, client) {
|
match get_ptr(addr, client) {
|
||||||
Ok(result) => match detect_scanner(&result) {
|
Ok(result) => match detect_scanner(&result) {
|
||||||
Ok(Some(scanner_name)) => {
|
Ok(Some(scanner_name)) => {
|
||||||
info!("Detected {:?} for {addr}", scanner_name);
|
self.report_detection(scanner_name, addr, result);
|
||||||
let request = WorkerMessages::ScannerFoundResponse {
|
|
||||||
name: result.result.unwrap().to_string(),
|
|
||||||
address: addr,
|
|
||||||
};
|
|
||||||
let msg_string: String = request.to_string();
|
|
||||||
match self.ws.send(Message::Text(msg_string)) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(err) => error!("Unable to send scanner result: {err}"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(None) => {}
|
Ok(None) => {}
|
||||||
|
|
||||||
@ -180,9 +174,34 @@ impl Worker {
|
|||||||
};
|
};
|
||||||
|
|
||||||
current += 1;
|
current += 1;
|
||||||
|
if current % 10 == 0 {
|
||||||
|
info!("Progress: {count}/{current}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_detection(&mut self, scanner_name: Scanners, addr: IpAddr, result: ResolvedResult) {
|
||||||
|
info!("Detected {:?} for {addr}", scanner_name);
|
||||||
|
let request = WorkerMessages::ScannerFoundResponse {
|
||||||
|
name: result.result.unwrap().to_string(),
|
||||||
|
address: addr,
|
||||||
|
};
|
||||||
|
let msg_string: String = request.to_string();
|
||||||
|
match self.ws.send(Message::Text(msg_string)) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => error!("Unable to send scanner result: {err}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn receive_request(&mut self, server_request: WorkerMessages) -> &Worker {
|
||||||
|
match server_request {
|
||||||
|
WorkerMessages::DoWorkRequest { neworks } => {
|
||||||
|
info!("Work request received for neworks: {:?}", neworks);
|
||||||
|
for cidr in neworks {
|
||||||
|
let cidr = cidr.0;
|
||||||
|
self.work_on_cidr(cidr);
|
||||||
|
}
|
||||||
|
}
|
||||||
WorkerMessages::AuthenticateRequest { .. }
|
WorkerMessages::AuthenticateRequest { .. }
|
||||||
| WorkerMessages::ScannerFoundResponse { .. }
|
| WorkerMessages::ScannerFoundResponse { .. }
|
||||||
| WorkerMessages::GetWorkRequest {}
|
| WorkerMessages::GetWorkRequest {}
|
||||||
@ -194,6 +213,68 @@ impl Worker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*fn resolve_file(addresses: InetAddressIterator<IpAddr>, dns_servers: Vec<&str>) {
|
||||||
|
|
||||||
|
|
||||||
|
let mut ips = vec![];
|
||||||
|
for address in addresses {
|
||||||
|
match IpAddr::from_str(address) {
|
||||||
|
Ok(addr) => ips.push(IpToResolve {
|
||||||
|
address: addr,
|
||||||
|
server: rr.next().unwrap(),
|
||||||
|
}),
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!(
|
||||||
|
"Something went wrong while parsing the IP ({}): {}",
|
||||||
|
address, err
|
||||||
|
);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match rayon::ThreadPoolBuilder::new()
|
||||||
|
.num_threads(30)
|
||||||
|
.build_global()
|
||||||
|
{
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!(
|
||||||
|
"Something went wrong while building the thread pool: {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ips.into_par_iter()
|
||||||
|
.enumerate()
|
||||||
|
.for_each(|(_i, to_resolve)| {
|
||||||
|
let server = NameServerConfigGroup::from_ips_clear(
|
||||||
|
&[to_resolve.server.ip()],
|
||||||
|
to_resolve.server.port(),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
let ptr_result = get_ptr(to_resolve.address, resolver);
|
||||||
|
match ptr_result {
|
||||||
|
Ok(ptr) => match ptr.result {
|
||||||
|
Some(res) => println!("{} # {}", to_resolve.address, res),
|
||||||
|
None => println!("{}", to_resolve.address),
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
let two_hundred_millis = Duration::from_millis(400);
|
||||||
|
thread::sleep(two_hundred_millis);
|
||||||
|
|
||||||
|
eprintln!(
|
||||||
|
"[{}] Error for {} -> {}",
|
||||||
|
to_resolve.server, to_resolve.address, err.message
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}*/
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let _log2 = log2::stdout()
|
let _log2 = log2::stdout()
|
||||||
.module(true)
|
.module(true)
|
||||||
|
Reference in New Issue
Block a user