aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoradrien <adrien@luxeylab.net>2021-09-10 18:41:39 +0200
committeradrien <adrien@luxeylab.net>2021-09-10 18:41:39 +0200
commit4d76c3d78ade04038593aeef867294c9eee2a4b8 (patch)
tree8fac4937beafb831b7354bb2afa37bb5bea99e00
parent195aec2cfe738f4025ea540d2591f876e1d209b9 (diff)
downloaddiplonat-4d76c3d78ade04038593aeef867294c9eee2a4b8.tar.gz
diplonat-4d76c3d78ade04038593aeef867294c9eee2a4b8.zip
wrote the skeleton of ACME. Involved solving the cosmetic warnings about CamelCase for enums (without changing the API).
-rw-r--r--src/acme_actor.rs70
-rw-r--r--src/config/options.rs2
-rw-r--r--src/config/runtime.rs4
-rw-r--r--src/consul_actor.rs29
-rw-r--r--src/diplonat.rs22
-rw-r--r--src/fw.rs11
-rw-r--r--src/fw_actor.rs3
-rw-r--r--src/main.rs1
-rw-r--r--src/messages.rs6
9 files changed, 126 insertions, 22 deletions
diff --git a/src/acme_actor.rs b/src/acme_actor.rs
new file mode 100644
index 0000000..3b6aa50
--- /dev/null
+++ b/src/acme_actor.rs
@@ -0,0 +1,70 @@
+use anyhow::Result;
+use log::*;
+use tokio::{
+ select,
+ sync::watch,
+ time::{
+ Duration,
+ self,
+}};
+
+use crate::config::RuntimeConfigAcme;
+use crate::messages;
+
+pub struct AcmeActor {
+ email: String,
+ last_ports: messages::PublicExposedPorts,
+ refresh: Duration,
+
+ rx_ports: watch::Receiver<messages::PublicExposedPorts>,
+}
+
+impl AcmeActor {
+ pub async fn new(
+ config: Option<RuntimeConfigAcme>,
+ rxp: &watch::Receiver<messages::PublicExposedPorts>
+ ) -> Result<Option<Self>> {
+
+ if config.is_none() {
+ return Ok(None);
+ }
+ let config = config.unwrap();
+
+ let ctx = Self {
+ email: config.email,
+ last_ports: messages::PublicExposedPorts::new(),
+ refresh: config.refresh_time,
+ rx_ports: rxp.clone(),
+ };
+
+ Ok(Some(ctx))
+ }
+
+ pub async fn listen(&mut self) -> Result<()> {
+ let mut interval = time::interval(self.refresh);
+ loop {
+ // 1. Wait for an event
+ let new_ports = select! {
+ Some(ports) = self.rx_ports.recv() => Some(ports),
+ _ = interval.tick() => None,
+ else => return Ok(()) // Sender dropped, terminate loop.
+ };
+
+ // 2. Update last ports if needed
+ if let Some(p) = new_ports { self.last_ports = p; }
+
+ // 3. Flush IGD requests
+ match self.do_acme().await {
+ Ok(()) => debug!("Successfully updated ACME"),
+ Err(e) => error!("An error occured while updating ACME. {}", e),
+ }
+ }
+ }
+
+ pub async fn do_acme(&self) -> Result<()> {
+ debug!("Doing ACME!!!");
+ debug!("{:#?}", self.last_ports);
+
+ Ok(())
+ }
+} \ No newline at end of file
diff --git a/src/config/options.rs b/src/config/options.rs
index b3a63b0..54e948d 100644
--- a/src/config/options.rs
+++ b/src/config/options.rs
@@ -34,6 +34,8 @@ pub struct ConfigOptsAcme {
/// The default domain holder's e-mail [default: None]
pub email: Option<String>,
+ /// Refresh time for firewall rules [default: 300]
+ pub refresh_time: Option<u16>,
}
/// Firewall configuration options
diff --git a/src/config/runtime.rs b/src/config/runtime.rs
index f83a6b5..ee7f682 100644
--- a/src/config/runtime.rs
+++ b/src/config/runtime.rs
@@ -20,6 +20,7 @@ pub struct RuntimeConfigConsul {
#[derive(Debug)]
pub struct RuntimeConfigAcme {
pub email: String,
+ pub refresh_time: Duration,
}
#[derive(Debug)]
@@ -79,9 +80,12 @@ impl RuntimeConfigAcme {
let email = opts.email.expect(
"'DIPLONAT_ACME_EMAIL' is required if ACME is enabled");
+ let refresh_time = Duration::from_secs(
+ opts.refresh_time.unwrap_or(super::REFRESH_TIME).into());
Ok(Some(Self {
email,
+ refresh_time,
}))
}
}
diff --git a/src/consul_actor.rs b/src/consul_actor.rs
index dcbd79e..fd4d05f 100644
--- a/src/consul_actor.rs
+++ b/src/consul_actor.rs
@@ -14,9 +14,11 @@ use crate::consul;
use crate::messages;
#[derive(Serialize, Deserialize, Debug)]
+#[serde(rename_all = "snake_case")]
pub enum DiplonatParameter {
- tcp_port(HashSet<u16>),
- udp_port(HashSet<u16>)
+ TcpPort(HashSet<u16>),
+ UdpPort(HashSet<u16>),
+ Acme(HashSet<String>)
}
#[derive(Serialize, Deserialize, Debug)]
@@ -57,17 +59,19 @@ fn to_parameters(catalog: &consul::CatalogNode) -> Vec<DiplonatConsul> {
}
fn to_open_ports(params: &Vec<DiplonatConsul>) -> messages::PublicExposedPorts {
- let mut op = messages::PublicExposedPorts {
- tcp_ports: HashSet::new(),
- udp_ports: HashSet::new()
- };
+ // let mut op = messages::PublicExposedPorts {
+ // tcp_ports: HashSet::new(),
+ // udp_ports: HashSet::new()
+ // };
+ let mut op = messages::PublicExposedPorts::new();
for conf in params {
let DiplonatConsul::diplonat(c) = conf;
for parameter in c {
match parameter {
- DiplonatParameter::tcp_port(p) => op.tcp_ports.extend(p),
- DiplonatParameter::udp_port(p) => op.udp_ports.extend(p),
+ DiplonatParameter::TcpPort(p) => op.tcp_ports.extend(p),
+ DiplonatParameter::UdpPort(p) => op.udp_ports.extend(p),
+ DiplonatParameter::Acme(urls) => op.acme.extend(urls.clone()),
};
}
}
@@ -77,10 +81,11 @@ fn to_open_ports(params: &Vec<DiplonatConsul>) -> messages::PublicExposedPorts {
impl ConsulActor {
pub fn new(config: RuntimeConfigConsul) -> Self {
- let (tx, rx) = watch::channel(messages::PublicExposedPorts{
- tcp_ports: HashSet::new(),
- udp_ports: HashSet::new()
- });
+ let (tx, rx) = watch::channel(messages::PublicExposedPorts::new());
+ // let (tx, rx) = watch::channel(messages::PublicExposedPorts{
+ // tcp_ports: HashSet::new(),
+ // udp_ports: HashSet::new()
+ // });
return Self {
consul: consul::Consul::new(&config.url),
diff --git a/src/diplonat.rs b/src/diplonat.rs
index 6334e5b..b2310f9 100644
--- a/src/diplonat.rs
+++ b/src/diplonat.rs
@@ -1,14 +1,17 @@
use anyhow::{Result, anyhow};
+use log::debug;
use tokio::try_join;
use crate::config::ConfigOpts;
use crate::consul_actor::ConsulActor;
+use crate::acme_actor::AcmeActor;
use crate::fw_actor::FirewallActor;
use crate::igd_actor::IgdActor;
pub struct Diplonat {
consul: ConsulActor,
+ acme: Option<AcmeActor>,
firewall: Option<FirewallActor>,
igd: Option<IgdActor>,
}
@@ -16,10 +19,15 @@ pub struct Diplonat {
impl Diplonat {
pub async fn new() -> Result<Self> {
let config = ConfigOpts::from_env()?;
- println!("{:#?}", config);
+ debug!("{:#?}", config);
let consul_actor = ConsulActor::new(config.consul);
+ let acme_actor = AcmeActor::new(
+ config.acme,
+ &consul_actor.rx_open_ports
+ ).await?;
+
let firewall_actor = FirewallActor::new(
config.firewall,
&consul_actor.rx_open_ports
@@ -30,13 +38,16 @@ impl Diplonat {
&consul_actor.rx_open_ports
).await?;
- if firewall_actor.is_none() && igd_actor.is_none() {
+ if acme_actor.is_none() &&
+ firewall_actor.is_none() &&
+ igd_actor.is_none() {
return Err(anyhow!(
"At least enable *one* module, otherwise it's boring!"));
}
let ctx = Self {
consul: consul_actor,
+ acme: acme_actor,
firewall: firewall_actor,
igd: igd_actor,
};
@@ -45,12 +56,19 @@ impl Diplonat {
}
pub async fn listen(&mut self) -> Result<()> {
+ let acme = &mut self.acme;
let firewall = &mut self.firewall;
let igd = &mut self.igd;
try_join!(
self.consul.listen(),
async {
+ match acme {
+ Some(x) => x.listen().await,
+ None => Ok(())
+ }
+ },
+ async {
match firewall {
Some(x) => x.listen().await,
None => Ok(())
diff --git a/src/fw.rs b/src/fw.rs
index a71dd1c..355e928 100644
--- a/src/fw.rs
+++ b/src/fw.rs
@@ -1,4 +1,4 @@
-use std::collections::HashSet;
+// use std::collections::HashSet;
use anyhow::{Result,Context};
use iptables;
@@ -31,10 +31,11 @@ pub fn open_ports(ipt: &iptables::IPTables, ports: messages::PublicExposedPorts)
}
pub fn get_opened_ports(ipt: &iptables::IPTables) -> Result<messages::PublicExposedPorts> {
- let mut ports = messages::PublicExposedPorts {
- tcp_ports: HashSet::new(),
- udp_ports: HashSet::new()
- };
+ let mut ports = messages::PublicExposedPorts::new();
+ // let mut ports = messages::PublicExposedPorts {
+ // tcp_ports: HashSet::new(),
+ // udp_ports: HashSet::new()
+ // };
let list = ipt.list("filter", "DIPLONAT")?;
let re = Regex::new(r"\-A.*? \-p (\w+).*\-\-dport (\d+).*?\-j ACCEPT").context("Regex matching open ports encountered an unexpected rule")?;
diff --git a/src/fw_actor.rs b/src/fw_actor.rs
index 29e6473..9000048 100644
--- a/src/fw_actor.rs
+++ b/src/fw_actor.rs
@@ -73,7 +73,8 @@ impl FirewallActor {
let ports_to_open = messages::PublicExposedPorts {
tcp_ports: diff_tcp,
- udp_ports: diff_udp
+ udp_ports: diff_udp,
+ acme: HashSet::new()
};
fw::open_ports(&self.ipt, ports_to_open)?;
diff --git a/src/main.rs b/src/main.rs
index 720edf8..48467d6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,4 @@
+mod acme_actor;
mod config;
mod consul;
mod consul_actor;
diff --git a/src/messages.rs b/src/messages.rs
index 09a7c14..86ba1b2 100644
--- a/src/messages.rs
+++ b/src/messages.rs
@@ -3,14 +3,16 @@ use std::collections::HashSet;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PublicExposedPorts {
pub tcp_ports: HashSet<u16>,
- pub udp_ports: HashSet<u16>
+ pub udp_ports: HashSet<u16>,
+ pub acme: HashSet<String>
}
impl PublicExposedPorts {
pub fn new() -> Self {
return Self {
tcp_ports: HashSet::new(),
- udp_ports: HashSet::new()
+ udp_ports: HashSet::new(),
+ acme: HashSet::new()
}
}
}