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]
|
[package]
|
||||||
name = "check_ip"
|
name = "check_ip"
|
||||||
version = "1.0.0"
|
version = "2.0.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -14,3 +14,4 @@ serde = { version = "1.0", features = ["derive"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
simplelog = "^0.10.0"
|
simplelog = "^0.10.0"
|
||||||
clokwerk = "0.3"
|
clokwerk = "0.3"
|
||||||
|
trust-dns-resolver = {version = "0.20", features = ["serde-config"] }
|
||||||
|
|
5
TODO.md
5
TODO.md
|
@ -1,4 +1,5 @@
|
||||||
# TODO
|
# TODO
|
||||||
* [ ] Examples de fichiers de config
|
* [ ] Examples de fichiers de config (config + systemd)
|
||||||
* [ ] Test à partir de l’adresse IP récupéré par DNS (https://crates.io/crates/trust-dns-resolver)
|
* [ ] N’envoyer qu’un seul mail par test =>_test_domains renvoie Option<String>
|
||||||
* [ ] Test de l’IPv6 (https://crates.io/crates/query_external_ip)
|
* [ ] Test de l’IPv6 (https://crates.io/crates/query_external_ip)
|
||||||
|
* [ ] Rustfmt
|
126
src/main.rs
126
src/main.rs
|
@ -8,6 +8,7 @@ extern crate native_tls;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate simplelog;
|
extern crate simplelog;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
|
extern crate trust_dns_resolver;
|
||||||
|
|
||||||
use self::native_tls::{Protocol, TlsConnector};
|
use self::native_tls::{Protocol, TlsConnector};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
@ -20,8 +21,8 @@ use serde::Deserialize;
|
||||||
use simplelog::{ConfigBuilder, LevelFilter, WriteLogger};
|
use simplelog::{ConfigBuilder, LevelFilter, WriteLogger};
|
||||||
use std::fs::{self, OpenOptions};
|
use std::fs::{self, OpenOptions};
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use std::path::Path;
|
|
||||||
use std::{thread, time::Duration};
|
use std::{thread, time::Duration};
|
||||||
|
use trust_dns_resolver::{config::*, Name, Resolver};
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
// Init log
|
// Init log
|
||||||
|
@ -40,21 +41,32 @@ fn main() -> Result<()> {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Init scheduler
|
// Init tester
|
||||||
let mut scheduler = Scheduler::new();
|
info!("Init tester");
|
||||||
info!("Init");
|
let tester = match Tester::new() {
|
||||||
scheduler.every(1.day()).at("06:00").run(|| {
|
Err(e) => {
|
||||||
if let Err(e) = check() {
|
|
||||||
error!("Error {}", e);
|
error!("Error {}", e);
|
||||||
|
bail!("Cannot init tester");
|
||||||
}
|
}
|
||||||
});
|
Ok(tester) => tester,
|
||||||
|
};
|
||||||
|
|
||||||
// Initial check
|
// Initial check
|
||||||
if let Err(e) = check() {
|
if let Err(e) = tester.check() {
|
||||||
error!("Error {}", e);
|
error!("Error {}", e);
|
||||||
bail!("Cannot get initial IP");
|
bail!("Cannot get initial IP");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// Run
|
||||||
loop {
|
loop {
|
||||||
scheduler.run_pending();
|
scheduler.run_pending();
|
||||||
|
@ -62,26 +74,38 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check() -> Result<()> {
|
Ok(())
|
||||||
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) => {
|
Err(err) => {
|
||||||
let msg = format!("Cannot get IP ({})", err);
|
let msg = format!("Cannot get IP ({})", err);
|
||||||
error!("{}", msg);
|
error!("{}", msg);
|
||||||
send_mail("Error on getting IP".to_owned(), msg)?;
|
self.send_mail("Error on getting IP".to_owned(), msg)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get() -> Result<(IpAddr, IpAddr)> {
|
fn get_ip(&self) -> Result<IpAddr> {
|
||||||
// Get new IP
|
// Get new IP
|
||||||
let new_ip = match my_internet_ip::get() {
|
let new_ip = match my_internet_ip::get() {
|
||||||
Ok(ip) => ip,
|
Ok(ip) => ip,
|
||||||
|
@ -89,54 +113,76 @@ fn get() -> Result<(IpAddr, IpAddr)> {
|
||||||
};
|
};
|
||||||
info!("Current IP is {}", new_ip);
|
info!("Current IP is {}", new_ip);
|
||||||
|
|
||||||
// Get old IP
|
Ok(new_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);
|
|
||||||
|
|
||||||
// Write new IP
|
|
||||||
fs::write(path, format!("{}", new_ip))?;
|
|
||||||
|
|
||||||
Ok((old_ip, new_ip))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_mail(subject: String, body: String) -> Result<()> {
|
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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_mail(&self, subject: String, body: String) -> Result<()> {
|
||||||
info!("Send mail {}", subject);
|
info!("Send mail {}", subject);
|
||||||
|
|
||||||
let config: Config = toml::from_str(&fs::read_to_string("config.toml")?)?;
|
if let Some(false) = self.config.test {
|
||||||
|
|
||||||
let email = EmailBuilder::new()
|
let email = EmailBuilder::new()
|
||||||
.to(config.mail.from)
|
.to(self.config.mail.from.clone())
|
||||||
.from(config.mail.to)
|
.from(self.config.mail.to.clone())
|
||||||
.subject(subject)
|
.subject(subject)
|
||||||
.text(body)
|
.text(body)
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
// Create transport
|
// Create transport
|
||||||
let creds = Credentials::new(config.mail.username, config.mail.password);
|
let creds = Credentials::new(
|
||||||
|
self.config.mail.username.clone(),
|
||||||
|
self.config.mail.password.clone(),
|
||||||
|
);
|
||||||
let mut tls_builder = TlsConnector::builder();
|
let mut tls_builder = TlsConnector::builder();
|
||||||
tls_builder.min_protocol_version(Some(Protocol::Sslv3));
|
tls_builder.min_protocol_version(Some(Protocol::Sslv3));
|
||||||
let tls_parameters =
|
let tls_parameters = ClientTlsParameters::new(
|
||||||
ClientTlsParameters::new(config.mail.server.clone(), tls_builder.build().unwrap());
|
self.config.mail.server.clone(),
|
||||||
|
tls_builder.build().unwrap(),
|
||||||
|
);
|
||||||
let mut mailer = SmtpClient::new(
|
let mut mailer = SmtpClient::new(
|
||||||
(config.mail.server, config.mail.port),
|
(self.config.mail.server.clone(), self.config.mail.port),
|
||||||
ClientSecurity::Required(tls_parameters),
|
ClientSecurity::Required(tls_parameters),
|
||||||
)?
|
)?
|
||||||
.credentials(creds)
|
.credentials(creds)
|
||||||
.transport();
|
.transport();
|
||||||
|
|
||||||
mailer.send(email.into())?;
|
mailer.send(email.into())?;
|
||||||
|
} else {
|
||||||
|
println!("subject: {} - body: {}", subject, body);
|
||||||
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct Config {
|
struct Config {
|
||||||
mail: MailConfig,
|
mail: MailConfig,
|
||||||
|
server: ServerConfig,
|
||||||
|
test: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct ServerConfig {
|
||||||
|
domains: Vec<Name>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
|
Loading…
Reference in a new issue