diff --git a/src/diplonat.rs b/src/diplonat.rs index a94a6f8..96bac3b 100644 --- a/src/diplonat.rs +++ b/src/diplonat.rs @@ -1,4 +1,5 @@ -use anyhow::Result; +use anyhow::{Context, Result}; +use futures::future::FutureExt; use tokio::try_join; use crate::{ @@ -15,7 +16,7 @@ pub struct Diplonat { impl Diplonat { pub async fn new() -> Result { - let rt_cfg = ConfigOpts::from_env()?; + let rt_cfg = ConfigOpts::from_env().context("Parse configuration")?; println!("{:#?}", rt_cfg); let ca = ConsulActor::new(&rt_cfg.consul, &rt_cfg.consul.node_name); @@ -25,7 +26,8 @@ impl Diplonat { rt_cfg.firewall.refresh_time, &ca.rx_open_ports, ) - .await?; + .await + .context("Setup fireall actor")?; let ia = match rt_cfg.igd { Some(igdc) => Some( @@ -35,7 +37,8 @@ impl Diplonat { igdc.expiration_time, &ca.rx_open_ports, ) - .await?, + .await + .context("Setup IGD actor")?, ), None => None, }; @@ -56,16 +59,18 @@ impl Diplonat { let igd_opt = &mut self.igd; try_join!( - self.consul.listen(), + self.consul.listen().map(|x| x.context("Run consul actor")), async { if let Some(igd) = igd_opt { - igd.listen().await + igd.listen().await.context("Run IGD actor") } else { Ok(()) } }, - self.firewall.listen(), - self.stun.listen(), + self.firewall + .listen() + .map(|x| x.context("Run firewall actor")), + self.stun.listen().map(|x| x.context("Run STUN actor")), )?; Ok(()) diff --git a/src/stun_actor.rs b/src/stun_actor.rs index b112bb0..6740c83 100644 --- a/src/stun_actor.rs +++ b/src/stun_actor.rs @@ -1,4 +1,4 @@ -use std::net::{IpAddr, SocketAddr}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use std::time::{Duration, SystemTime}; use anyhow::{anyhow, bail, Result}; @@ -60,20 +60,23 @@ impl StunActor { } async fn autodiscover_ip(&self, stun_server: SocketAddr) -> Result<()> { - let binding_addr = match stun_server.is_ipv4() { - true => "0.0.0.0:34791".parse().unwrap(), - false => "[::]:34792".parse().unwrap(), + let binding_ip = match stun_server.is_ipv4() { + true => IpAddr::V4(Ipv4Addr::UNSPECIFIED), // 0.0.0.0 + false => IpAddr::V6(Ipv6Addr::UNSPECIFIED), // [::] }; + let binding_addr = SocketAddr::new(binding_ip, 0); - let discovered_addr = get_mapped_addr(stun_server, binding_addr).await?.ip(); + let discovered_addr = get_mapped_addr(stun_server, binding_addr) + .await? + .map(|x| x.ip()); let consul_key = match stun_server.is_ipv4() { true => { - debug!("Autodiscovered IPv4: {}", discovered_addr); + debug!("Autodiscovered IPv4: {:?}", discovered_addr); format!("diplonat/autodiscovery/ipv4/{}", self.node) } false => { - debug!("Autodiscovered IPv6: {}", discovered_addr); + debug!("Autodiscovered IPv6: {:?}", discovered_addr); format!("diplonat/autodiscovery/ipv6/{}", self.node) } }; @@ -83,7 +86,7 @@ impl StunActor { &consul_key, serde_json::to_vec(&AutodiscoverResult { timestamp: timestamp(), - address: Some(discovered_addr), + address: discovered_addr, })?, ) .await?; @@ -108,11 +111,23 @@ impl StunActor { } } -async fn get_mapped_addr(stun_server: SocketAddr, binding_addr: SocketAddr) -> Result { +async fn get_mapped_addr( + stun_server: SocketAddr, + binding_addr: SocketAddr, +) -> Result> { use stun_client::*; - let mut client = Client::new(binding_addr, None).await.unwrap(); - let res = client.binding_request(stun_server, None).await.unwrap(); + let mut client = Client::new(binding_addr, None).await?; + let res = match client.binding_request(stun_server, None).await { + Err(e) => { + info!( + "STUN binding request to {} failed, assuming no address (error: {})", + binding_addr, e + ); + return Ok(None); + } + Ok(r) => r, + }; if res.get_class() != Class::SuccessResponse { bail!("STUN server did not responde with a success response"); @@ -120,7 +135,8 @@ async fn get_mapped_addr(stun_server: SocketAddr, binding_addr: SocketAddr) -> R let xor_mapped_addr = Attribute::get_xor_mapped_address(&res) .ok_or(anyhow!("no XorMappedAddress found in STUN response"))?; - Ok(xor_mapped_addr) + + Ok(Some(xor_mapped_addr)) } fn timestamp() -> u64 {