public IP address autodiscovery #20
5 changed files with 25 additions and 24 deletions
|
@ -26,7 +26,7 @@ fn all_valid_options() -> HashMap<String, String> {
|
|||
);
|
||||
opts.insert(
|
||||
"DIPLONAT_PRIVATE_IP".to_string(),
|
||||
"172.123.43.555".to_string(),
|
||||
"172.123.43.55".to_string(),
|
||||
);
|
||||
opts.insert("DIPLONAT_REFRESH_TIME".to_string(), "10".to_string());
|
||||
opts.insert(
|
||||
|
@ -118,7 +118,7 @@ fn ok_from_iter_all_valid_options() {
|
|||
);
|
||||
assert_eq!(rt_config.firewall.refresh_time, refresh_time);
|
||||
assert_eq!(
|
||||
&rt_config.igd.private_ip.unwrap(),
|
||||
&rt_config.igd.private_ip.unwrap().to_string(),
|
||||
opts.get(&"DIPLONAT_PRIVATE_IP".to_string()).unwrap()
|
||||
);
|
||||
assert_eq!(rt_config.igd.expiration_time, expiration_time);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs};
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
|
||||
use crate::config::{ConfigOpts, ConfigOptsAcme, ConfigOptsBase, ConfigOptsConsul};
|
||||
|
||||
|
@ -31,7 +31,7 @@ pub struct RuntimeConfigFirewall {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct RuntimeConfigIgd {
|
||||
pub private_ip: Option<String>,
|
||||
pub private_ip: Option<Ipv4Addr>,
|
||||
pub expiration_time: Duration,
|
||||
pub refresh_time: Duration,
|
||||
}
|
||||
|
@ -137,7 +137,12 @@ impl RuntimeConfigFirewall {
|
|||
|
||||
impl RuntimeConfigIgd {
|
||||
pub(super) fn new(opts: &ConfigOptsBase) -> Result<Self> {
|
||||
let private_ip = opts.private_ip.clone();
|
||||
let private_ip = opts
|
||||
.private_ip
|
||||
.as_ref()
|
||||
.map(|x| x.parse())
|
||||
.transpose()
|
||||
.context("parse private_ip")?;
|
||||
let expiration_time = Duration::from_secs(
|
||||
opts.expiration_time
|
||||
.unwrap_or(super::EXPIRATION_TIME)
|
||||
|
|
|
@ -23,7 +23,7 @@ impl Diplonat {
|
|||
let fw = FirewallActor::new(rt_cfg.firewall.refresh_time, &ca.rx_open_ports).await?;
|
||||
|
||||
let ia = IgdActor::new(
|
||||
rt_cfg.igd.private_ip.as_ref().map(String::as_str),
|
||||
rt_cfg.igd.private_ip,
|
||||
rt_cfg.igd.refresh_time,
|
||||
rt_cfg.igd.expiration_time,
|
||||
&ca.rx_open_ports,
|
||||
|
|
|
@ -11,7 +11,7 @@ pub fn setup(ipt: &iptables::IPTables) -> Result<()> {
|
|||
// ensure we start from a clean state without any rule already set
|
||||
cleanup(ipt)?;
|
||||
|
||||
info!("{}: creating DIPLONAT chain using", ipt.cmd);
|
||||
info!("{}: creating DIPLONAT chain", ipt.cmd);
|
||||
ipt.new_chain("filter", "DIPLONAT")
|
||||
.context("Failed to create new chain")?;
|
||||
ipt.insert_unique("filter", "INPUT", "-j DIPLONAT", 1)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::net::SocketAddrV4;
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use igd::{aio::*, PortMappingProtocol};
|
||||
|
@ -17,12 +17,12 @@ pub struct IgdActor {
|
|||
gateway: Gateway,
|
||||
refresh: Duration,
|
||||
expire: Duration,
|
||||
private_ip: String,
|
||||
private_ip: Ipv4Addr,
|
||||
}
|
||||
|
||||
impl IgdActor {
|
||||
pub async fn new(
|
||||
priv_ip: Option<&str>,
|
||||
priv_ip: Option<Ipv4Addr>,
|
||||
refresh: Duration,
|
||||
expire: Duration,
|
||||
rxp: &watch::Receiver<messages::PublicExposedPorts>,
|
||||
|
@ -34,7 +34,7 @@ impl IgdActor {
|
|||
|
||||
let private_ip = if let Some(ip) = priv_ip {
|
||||
info!("Using private IP from config: {}", ip);
|
||||
ip.to_string()
|
||||
ip
|
||||
} else {
|
||||
info!("Trying to automatically detect private IP");
|
||||
let gwa = gw.addr.ip().octets();
|
||||
|
@ -47,18 +47,17 @@ impl IgdActor {
|
|||
),
|
||||
};
|
||||
#[allow(unused_parens)]
|
||||
let public_ip = get_if_addrs::get_if_addrs()?
|
||||
let private_ip = get_if_addrs::get_if_addrs()?
|
||||
.into_iter()
|
||||
.map(|i| i.addr.ip())
|
||||
.filter(|a| match a {
|
||||
std::net::IpAddr::V4(a4) => (a4.octets()[..cmplen] == gwa[..cmplen]),
|
||||
_ => false,
|
||||
.filter_map(|a| match a {
|
||||
std::net::IpAddr::V4(a4) if a4.octets()[..cmplen] == gwa[..cmplen] => Some(a4),
|
||||
_ => None,
|
||||
})
|
||||
.next()
|
||||
.expect("No interface has an IP on same subnet as gateway")
|
||||
.to_string();
|
||||
info!("Found private IP: {}", public_ip);
|
||||
public_ip
|
||||
.expect("No interface has an IP on same subnet as gateway");
|
||||
info!("Autodetected private IP: {}", private_ip);
|
||||
private_ip
|
||||
};
|
||||
|
||||
let ctx = Self {
|
||||
|
@ -104,10 +103,7 @@ impl IgdActor {
|
|||
|
||||
for (proto, list) in actions.iter() {
|
||||
for port in *list {
|
||||
let service_str = format!("{}:{}", self.private_ip, port);
|
||||
let service = service_str
|
||||
.parse::<SocketAddrV4>()
|
||||
.context("Invalid socket address")?;
|
||||
let service = SocketAddrV4::new(self.private_ip, *port);
|
||||
self.gateway
|
||||
.add_port(
|
||||
*proto,
|
||||
|
|
Loading…
Reference in a new issue