Add test through DNS
This commit is contained in:
parent
7659338106
commit
94050d4af4
3 changed files with 122 additions and 74 deletions
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "check_ip"
|
||||
version = "1.0.0"
|
||||
version = "2.0.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
|
@ -14,3 +14,4 @@ serde = { version = "1.0", features = ["derive"] }
|
|||
log = "0.4"
|
||||
simplelog = "^0.10.0"
|
||||
clokwerk = "0.3"
|
||||
trust-dns-resolver = {version = "0.20", features = ["serde-config"] }
|
||||
|
|
5
TODO.md
5
TODO.md
|
@ -1,4 +1,5 @@
|
|||
# TODO
|
||||
* [ ] Examples de fichiers de config
|
||||
* [ ] Test à partir de l’adresse IP récupéré par DNS (https://crates.io/crates/trust-dns-resolver)
|
||||
* [ ] Examples de fichiers de config (config + systemd)
|
||||
* [ ] N’envoyer qu’un seul mail par test =>_test_domains renvoie Option<String>
|
||||
* [ ] Test de l’IPv6 (https://crates.io/crates/query_external_ip)
|
||||
* [ ] Rustfmt
|
188
src/main.rs
188
src/main.rs
|
@ -8,6 +8,7 @@ extern crate native_tls;
|
|||
extern crate serde;
|
||||
extern crate simplelog;
|
||||
extern crate toml;
|
||||
extern crate trust_dns_resolver;
|
||||
|
||||
use self::native_tls::{Protocol, TlsConnector};
|
||||
use anyhow::{bail, Result};
|
||||
|
@ -20,8 +21,8 @@ use serde::Deserialize;
|
|||
use simplelog::{ConfigBuilder, LevelFilter, WriteLogger};
|
||||
use std::fs::{self, OpenOptions};
|
||||
use std::net::IpAddr;
|
||||
use std::path::Path;
|
||||
use std::{thread, time::Duration};
|
||||
use trust_dns_resolver::{config::*, Name, Resolver};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// Init log
|
||||
|
@ -40,103 +41,148 @@ fn main() -> Result<()> {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
// Init scheduler
|
||||
let mut scheduler = Scheduler::new();
|
||||
info!("Init");
|
||||
scheduler.every(1.day()).at("06:00").run(|| {
|
||||
if let Err(e) = check() {
|
||||
// Init tester
|
||||
info!("Init tester");
|
||||
let tester = match Tester::new() {
|
||||
Err(e) => {
|
||||
error!("Error {}", e);
|
||||
bail!("Cannot init tester");
|
||||
}
|
||||
});
|
||||
Ok(tester) => tester,
|
||||
};
|
||||
|
||||
// Initial check
|
||||
if let Err(e) = check() {
|
||||
if let Err(e) = tester.check() {
|
||||
error!("Error {}", e);
|
||||
bail!("Cannot get initial IP");
|
||||
}
|
||||
|
||||
// Run
|
||||
loop {
|
||||
scheduler.run_pending();
|
||||
thread::sleep(Duration::from_secs(60));
|
||||
if let Some(false) = tester.config.test {
|
||||
// Init scheduler
|
||||
info!("Init scheduler");
|
||||
let mut scheduler = Scheduler::new();
|
||||
scheduler.every(1.day()).at("06:00").run(move || {
|
||||
if let Err(e) = tester.check() {
|
||||
error!("Error {}", e);
|
||||
}
|
||||
});
|
||||
|
||||
// Run
|
||||
loop {
|
||||
scheduler.run_pending();
|
||||
thread::sleep(Duration::from_secs(60));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check() -> Result<()> {
|
||||
info!("Check");
|
||||
match get() {
|
||||
Ok((old_ip, new_ip)) => {
|
||||
if old_ip != new_ip {
|
||||
let msg = format!("IP changed from {} to {}", old_ip, new_ip);
|
||||
info!("{}", msg);
|
||||
send_mail("New IP".to_owned(), msg)?;
|
||||
struct Tester {
|
||||
config: Config,
|
||||
dns_resolver: Resolver,
|
||||
}
|
||||
|
||||
impl Tester {
|
||||
fn new() -> Result<Tester> {
|
||||
Ok(Tester {
|
||||
config: toml::from_str(&fs::read_to_string("config.toml")?)?,
|
||||
dns_resolver: Resolver::new(ResolverConfig::default(), ResolverOpts::default())?,
|
||||
})
|
||||
}
|
||||
|
||||
fn check(&self) -> Result<()> {
|
||||
info!("Check");
|
||||
match self.get_ip() {
|
||||
Ok(ipv4) => {
|
||||
self.test_domains(ipv4)?;
|
||||
}
|
||||
Err(err) => {
|
||||
let msg = format!("Cannot get IP ({})", err);
|
||||
error!("{}", msg);
|
||||
self.send_mail("Error on getting IP".to_owned(), msg)?;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
let msg = format!("Cannot get IP ({})", err);
|
||||
error!("{}", msg);
|
||||
send_mail("Error on getting IP".to_owned(), msg)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get() -> Result<(IpAddr, IpAddr)> {
|
||||
// Get new IP
|
||||
let new_ip = match my_internet_ip::get() {
|
||||
Ok(ip) => ip,
|
||||
Err(e) => bail!("Could not get IP: {:?}", e),
|
||||
};
|
||||
info!("Current IP is {}", new_ip);
|
||||
fn get_ip(&self) -> Result<IpAddr> {
|
||||
// Get new IP
|
||||
let new_ip = match my_internet_ip::get() {
|
||||
Ok(ip) => ip,
|
||||
Err(e) => bail!("Could not get IP: {:?}", e),
|
||||
};
|
||||
info!("Current IP is {}", new_ip);
|
||||
|
||||
// Get old IP
|
||||
let path = Path::new("./old_ip.txt");
|
||||
let old_ip = if path.exists() {
|
||||
fs::read_to_string(path)?.parse()?
|
||||
} else {
|
||||
new_ip.clone()
|
||||
};
|
||||
info!("Old IP is {}", old_ip);
|
||||
Ok(new_ip)
|
||||
}
|
||||
|
||||
// Write new IP
|
||||
fs::write(path, format!("{}", new_ip))?;
|
||||
fn test_domains(&self, ipv4: IpAddr) -> Result<()> {
|
||||
for domain in self.config.server.domains.iter() {
|
||||
let address = self.dns_resolver.lookup_ip(domain.clone())?;
|
||||
for dns_ip in address.iter() {
|
||||
if dns_ip.is_ipv4() {
|
||||
if dns_ip != ipv4 {
|
||||
let msg = format!(
|
||||
"Wrong IPV4 for {} (DNS: {}, current: {})",
|
||||
domain, dns_ip, ipv4
|
||||
);
|
||||
info!("{}", msg);
|
||||
self.send_mail("Wrong IP".to_owned(), msg)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok((old_ip, new_ip))
|
||||
}
|
||||
fn send_mail(&self, subject: String, body: String) -> Result<()> {
|
||||
info!("Send mail {}", subject);
|
||||
|
||||
fn send_mail(subject: String, body: String) -> Result<()> {
|
||||
info!("Send mail {}", subject);
|
||||
if let Some(false) = self.config.test {
|
||||
let email = EmailBuilder::new()
|
||||
.to(self.config.mail.from.clone())
|
||||
.from(self.config.mail.to.clone())
|
||||
.subject(subject)
|
||||
.text(body)
|
||||
.build()?;
|
||||
|
||||
let config: Config = toml::from_str(&fs::read_to_string("config.toml")?)?;
|
||||
// Create transport
|
||||
let creds = Credentials::new(
|
||||
self.config.mail.username.clone(),
|
||||
self.config.mail.password.clone(),
|
||||
);
|
||||
let mut tls_builder = TlsConnector::builder();
|
||||
tls_builder.min_protocol_version(Some(Protocol::Sslv3));
|
||||
let tls_parameters = ClientTlsParameters::new(
|
||||
self.config.mail.server.clone(),
|
||||
tls_builder.build().unwrap(),
|
||||
);
|
||||
let mut mailer = SmtpClient::new(
|
||||
(self.config.mail.server.clone(), self.config.mail.port),
|
||||
ClientSecurity::Required(tls_parameters),
|
||||
)?
|
||||
.credentials(creds)
|
||||
.transport();
|
||||
|
||||
let email = EmailBuilder::new()
|
||||
.to(config.mail.from)
|
||||
.from(config.mail.to)
|
||||
.subject(subject)
|
||||
.text(body)
|
||||
.build()?;
|
||||
mailer.send(email.into())?;
|
||||
} else {
|
||||
println!("subject: {} - body: {}", subject, body);
|
||||
};
|
||||
|
||||
// Create transport
|
||||
let creds = Credentials::new(config.mail.username, config.mail.password);
|
||||
let mut tls_builder = TlsConnector::builder();
|
||||
tls_builder.min_protocol_version(Some(Protocol::Sslv3));
|
||||
let tls_parameters =
|
||||
ClientTlsParameters::new(config.mail.server.clone(), tls_builder.build().unwrap());
|
||||
let mut mailer = SmtpClient::new(
|
||||
(config.mail.server, config.mail.port),
|
||||
ClientSecurity::Required(tls_parameters),
|
||||
)?
|
||||
.credentials(creds)
|
||||
.transport();
|
||||
|
||||
mailer.send(email.into())?;
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Config {
|
||||
mail: MailConfig,
|
||||
server: ServerConfig,
|
||||
test: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ServerConfig {
|
||||
domains: Vec<Name>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
|
Loading…
Reference in a new issue