diff --git a/src/fw.rs b/src/fw.rs index a320fa2..a3e6dec 100644 --- a/src/fw.rs +++ b/src/fw.rs @@ -1,5 +1,4 @@ use std::collections::HashSet; -use std::sync::Arc; use anyhow::{Context, Result}; use iptables; diff --git a/src/stun_actor.rs b/src/stun_actor.rs index 3182662..4cca4f1 100644 --- a/src/stun_actor.rs +++ b/src/stun_actor.rs @@ -8,6 +8,11 @@ use serde::{Deserialize, Serialize}; use crate::config::{RuntimeConfigConsul, RuntimeConfigStun}; use crate::consul; +/// If autodiscovery returns None but an address was obtained less than +/// this number of seconds ago (here 15 minutes), we keep that address +/// in the Consul db instead of insterting a None. +const PERSIST_SOME_RESULT_DURATION_SECS: u64 = 900; + pub struct StunActor { consul: consul::Consul, refresh_time: Duration, @@ -78,7 +83,7 @@ impl StunActor { } impl StunAutodiscovery { - async fn do_iteration(&self, consul: &consul::Consul) -> Result<()> { + async fn do_iteration(&mut self, consul: &consul::Consul) -> Result<()> { let binding_ip = match self.is_ipv4 { true => IpAddr::V4(Ipv4Addr::UNSPECIFIED), // 0.0.0.0 false => IpAddr::V6(Ipv6Addr::UNSPECIFIED), // [::] @@ -96,16 +101,31 @@ impl StunAutodiscovery { None => None, }; + let now = timestamp(); + + if discovered_addr.is_none() { + if let Some(last_result) = &self.last_result { + if last_result.address.is_some() + && now - last_result.timestamp <= PERSIST_SOME_RESULT_DURATION_SECS + { + // Keep non-None result that was obtained before by not + // writing/taking into account None result. + return Ok(()); + } + } + } + + let current_result = AutodiscoverResult { + timestamp: now, + address: discovered_addr, + }; + consul - .kv_put( - &self.consul_key, - serde_json::to_vec(&AutodiscoverResult { - timestamp: timestamp(), - address: discovered_addr, - })?, - ) + .kv_put(&self.consul_key, serde_json::to_vec(¤t_result)?) .await?; + self.last_result = Some(current_result); + Ok(()) } }