initial
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
1091
Cargo.lock
generated
Normal file
1091
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "spamlist_monitor"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
ipnet = "2.11.0"
|
||||
thiserror = "2.0.17"
|
||||
trust-dns-resolver = "0.23.2"
|
||||
123
src/main.rs
Normal file
123
src/main.rs
Normal file
@@ -0,0 +1,123 @@
|
||||
use ipnet::{Ipv6Net, PrefixLenError};
|
||||
use std::net::{AddrParseError, IpAddr};
|
||||
use thiserror::Error;
|
||||
use trust_dns_resolver::{
|
||||
Resolver,
|
||||
config::{ResolverConfig, ResolverOpts},
|
||||
error::ResolveError,
|
||||
};
|
||||
|
||||
static BLACKLISTS_IPV4: &[&str] = &[
|
||||
"zen.spamhaus.org",
|
||||
"bl.spamcop.net",
|
||||
"b.barracudacentral.org",
|
||||
"dnsbl.sorbs.net",
|
||||
];
|
||||
|
||||
static BLACKLISTS_IPV6: &[&str] = &["zen.spamhaus.org", "dnsbl.sorbs.net", "psbl.surriel.com"];
|
||||
|
||||
fn reverse_ipv4(ip: &str) -> String {
|
||||
ip.split('.').rev().collect::<Vec<_>>().join(".")
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
enum ReverseIpv6Error {
|
||||
#[error("failed to parse ip address")]
|
||||
FailedToParse(#[from] AddrParseError),
|
||||
#[error("ip address is not v6")]
|
||||
NotIpv6(IpAddr),
|
||||
#[error("ip address failed to expand to prefix len")]
|
||||
FailedExpansion(#[from] PrefixLenError),
|
||||
}
|
||||
|
||||
fn reverse_ipv6(ip: &str) -> Result<String, ReverseIpv6Error> {
|
||||
let addr: IpAddr = ip.parse().map_err(ReverseIpv6Error::FailedToParse)?;
|
||||
let IpAddr::V6(v6) = addr else {
|
||||
return Err(ReverseIpv6Error::NotIpv6(addr));
|
||||
};
|
||||
|
||||
let expanded = Ipv6Net::new(v6, 128)
|
||||
.map_err(ReverseIpv6Error::FailedExpansion)?
|
||||
.addr()
|
||||
.to_string()
|
||||
.replace(":", "");
|
||||
|
||||
Ok(expanded
|
||||
.chars()
|
||||
.rev()
|
||||
.map(|c| format!("{}.{}", c, ""))
|
||||
.collect::<String>()
|
||||
.trim_end_matches('.')
|
||||
.to_string())
|
||||
}
|
||||
|
||||
fn check_blacklists(domain: &str) -> Result<Vec<(String, bool, String)>, ResolveError> {
|
||||
let resolver = Resolver::new(ResolverConfig::default(), ResolverOpts::default())?;
|
||||
|
||||
let v4s: Vec<String> = resolver
|
||||
.ipv4_lookup(domain)
|
||||
.map(|ips| ips.iter().map(|ip| ip.to_string()).collect())?;
|
||||
|
||||
let v6s: Vec<String> = resolver
|
||||
.ipv6_lookup(domain)
|
||||
.map(|ips| ips.iter().map(|ip| ip.to_string()).collect())?;
|
||||
|
||||
Ok(BLACKLISTS_IPV4
|
||||
.iter()
|
||||
.map(|bl| {
|
||||
v4s.iter().map(|v4| {
|
||||
let query = format!("{}.{}", reverse_ipv4(v4), *bl);
|
||||
let result = resolver.lookup_ip(query);
|
||||
(bl.to_string(), result.is_ok(), v4.clone())
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
.chain(
|
||||
BLACKLISTS_IPV6
|
||||
.iter()
|
||||
.map(|bl| {
|
||||
v6s.iter().map(|v6| match reverse_ipv6(v6) {
|
||||
Ok(rv6) => {
|
||||
let query = format!("{}.{}", rv6, *bl);
|
||||
let result = resolver.lookup_ip(query);
|
||||
(bl.to_string(), result.is_ok(), v6.clone())
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("ERROR: Failed to reverse ipv6 {e}");
|
||||
(String::new(), false, String::new())
|
||||
}
|
||||
})
|
||||
})
|
||||
.flatten(),
|
||||
)
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let email_servers = ["microbel.pvv.ntnu.no"];
|
||||
for domain in email_servers {
|
||||
println!("Checking {domain}:");
|
||||
match check_blacklists(domain) {
|
||||
Ok(spamlist) => {
|
||||
for (bl, listed, email_ip) in spamlist {
|
||||
println!(
|
||||
"email server ip: {email_ip}\t{:24} {}",
|
||||
bl,
|
||||
if listed { "LISTED" } else { "OK" }
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("ERROR: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn reverse_ipv4() {
|
||||
assert_eq!(super::reverse_ipv4("110.70.54.107"), "107.54.70.110");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user