public IP address autodiscovery #20
2 changed files with 41 additions and 20 deletions
|
@ -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(())
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue