public IP address autodiscovery #20

Merged
lx merged 10 commits from stun into main 2023-04-21 09:56:22 +00:00
2 changed files with 41 additions and 20 deletions
Showing only changes of commit 48da5b61ac - Show all commits

View file

@ -1,4 +1,5 @@
use anyhow::Result; use anyhow::{Context, Result};
use futures::future::FutureExt;
use tokio::try_join; use tokio::try_join;
use crate::{ use crate::{
@ -15,7 +16,7 @@ pub struct Diplonat {
impl Diplonat { impl Diplonat {
pub async fn new() -> Result<Self> { pub async fn new() -> Result<Self> {
let rt_cfg = ConfigOpts::from_env()?; let rt_cfg = ConfigOpts::from_env().context("Parse configuration")?;
println!("{:#?}", rt_cfg); println!("{:#?}", rt_cfg);
let ca = ConsulActor::new(&rt_cfg.consul, &rt_cfg.consul.node_name); let ca = ConsulActor::new(&rt_cfg.consul, &rt_cfg.consul.node_name);
@ -25,7 +26,8 @@ impl Diplonat {
rt_cfg.firewall.refresh_time, rt_cfg.firewall.refresh_time,
&ca.rx_open_ports, &ca.rx_open_ports,
) )
.await?; .await
.context("Setup fireall actor")?;
let ia = match rt_cfg.igd { let ia = match rt_cfg.igd {
Some(igdc) => Some( Some(igdc) => Some(
@ -35,7 +37,8 @@ impl Diplonat {
igdc.expiration_time, igdc.expiration_time,
&ca.rx_open_ports, &ca.rx_open_ports,
) )
.await?, .await
.context("Setup IGD actor")?,
), ),
None => None, None => None,
}; };
@ -56,16 +59,18 @@ impl Diplonat {
let igd_opt = &mut self.igd; let igd_opt = &mut self.igd;
try_join!( try_join!(
self.consul.listen(), self.consul.listen().map(|x| x.context("Run consul actor")),
async { async {
if let Some(igd) = igd_opt { if let Some(igd) = igd_opt {
igd.listen().await igd.listen().await.context("Run IGD actor")
} else { } else {
Ok(()) Ok(())
} }
}, },
self.firewall.listen(), self.firewall
self.stun.listen(), .listen()
.map(|x| x.context("Run firewall actor")),
self.stun.listen().map(|x| x.context("Run STUN actor")),
)?; )?;
Ok(()) Ok(())

View file

@ -1,4 +1,4 @@
use std::net::{IpAddr, SocketAddr}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use anyhow::{anyhow, bail, Result}; use anyhow::{anyhow, bail, Result};
@ -60,20 +60,23 @@ impl StunActor {
} }
async fn autodiscover_ip(&self, stun_server: SocketAddr) -> Result<()> { async fn autodiscover_ip(&self, stun_server: SocketAddr) -> Result<()> {
let binding_addr = match stun_server.is_ipv4() { let binding_ip = match stun_server.is_ipv4() {
true => "0.0.0.0:34791".parse().unwrap(), true => IpAddr::V4(Ipv4Addr::UNSPECIFIED), // 0.0.0.0
false => "[::]:34792".parse().unwrap(), 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() { let consul_key = match stun_server.is_ipv4() {
true => { true => {
debug!("Autodiscovered IPv4: {}", discovered_addr); debug!("Autodiscovered IPv4: {:?}", discovered_addr);
format!("diplonat/autodiscovery/ipv4/{}", self.node) format!("diplonat/autodiscovery/ipv4/{}", self.node)
} }
false => { false => {
debug!("Autodiscovered IPv6: {}", discovered_addr); debug!("Autodiscovered IPv6: {:?}", discovered_addr);
format!("diplonat/autodiscovery/ipv6/{}", self.node) format!("diplonat/autodiscovery/ipv6/{}", self.node)
} }
}; };
@ -83,7 +86,7 @@ impl StunActor {
&consul_key, &consul_key,
serde_json::to_vec(&AutodiscoverResult { serde_json::to_vec(&AutodiscoverResult {
timestamp: timestamp(), timestamp: timestamp(),
address: Some(discovered_addr), address: discovered_addr,
})?, })?,
) )
.await?; .await?;
@ -108,11 +111,23 @@ impl StunActor {
} }
} }
async fn get_mapped_addr(stun_server: SocketAddr, binding_addr: SocketAddr) -> Result<SocketAddr> { async fn get_mapped_addr(
stun_server: SocketAddr,
binding_addr: SocketAddr,
) -> Result<Option<SocketAddr>> {
use stun_client::*; use stun_client::*;
let mut client = Client::new(binding_addr, None).await.unwrap(); let mut client = Client::new(binding_addr, None).await?;
let res = client.binding_request(stun_server, None).await.unwrap(); 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 { if res.get_class() != Class::SuccessResponse {
bail!("STUN server did not responde with a success response"); 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) let xor_mapped_addr = Attribute::get_xor_mapped_address(&res)
.ok_or(anyhow!("no XorMappedAddress found in STUN response"))?; .ok_or(anyhow!("no XorMappedAddress found in STUN response"))?;
Ok(xor_mapped_addr)
Ok(Some(xor_mapped_addr))
} }
fn timestamp() -> u64 { fn timestamp() -> u64 {