diff options
Diffstat (limited to 'src/manager/builder.rs')
-rw-r--r-- | src/manager/builder.rs | 119 |
1 files changed, 79 insertions, 40 deletions
diff --git a/src/manager/builder.rs b/src/manager/builder.rs index 3f3e227..e5fe2da 100644 --- a/src/manager/builder.rs +++ b/src/manager/builder.rs @@ -2,50 +2,56 @@ // // See COPYING. +use super::Source; use crate::{config, model, proto}; use std::collections::hash_map; use std::{error, fmt}; #[derive(Debug)] -pub struct ConfigError { - pub url: String, +pub struct Error { + pub src: String, pub peer: model::Key, - pub important: bool, + important: bool, err: &'static str, } -impl ConfigError { - fn new(err: &'static str, s: &config::Source, p: &proto::Peer, important: bool) -> Self { +impl Error { + fn new(err: &'static str, src: &Source, p: &proto::Peer, important: bool) -> Self { Self { - url: s.url.clone(), - peer: p.public_key.clone(), + src: src.name.clone(), + peer: p.public_key, important, err, } } + + #[inline] + pub fn important(&self) -> bool { + self.important + } } -impl error::Error for ConfigError {} -impl fmt::Display for ConfigError { +impl error::Error for Error {} +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "{} [{}] from [{}]: {}", + "{} [{}]/[{}]: {}", if self.important { "Invalid peer" } else { "Misconfigured peer" }, + self.src, self.peer, - self.url, self.err ) } } -pub struct ConfigBuilder<'a> { +pub(super) struct ConfigBuilder<'a> { c: model::Config, - err: Vec<ConfigError>, + err: Vec<Error>, public_key: model::Key, gc: &'a config::GlobalConfig, } @@ -54,7 +60,7 @@ impl<'a> ConfigBuilder<'a> { #[inline] pub fn new(public_key: model::Key, gc: &'a config::GlobalConfig) -> Self { Self { - c: model::Config::default(), + c: model::Config::empty(), err: vec![], public_key, gc, @@ -62,32 +68,48 @@ impl<'a> ConfigBuilder<'a> { } #[inline] - pub fn build(self) -> (model::Config, Vec<ConfigError>) { + pub fn build(self) -> (model::Config, Vec<Error>) { (self.c, self.err) } #[inline] - pub fn add_server(&mut self, s: &config::Source, p: &proto::Server) { + pub fn add_server(&mut self, src: &Source, p: &proto::Server) { + let gc = self.gc; + + let psk = match find_psk(gc, src, &p.peer) { + Ok(v) => v, + Err(e) => { + self.err.push(e); + return; + } + }; + if p.peer.public_key == self.public_key { return; } - let gc = self.gc; - let ent = insert_peer(&mut self.c, &mut self.err, s, &p.peer, |ent| { - ent.psk = s.psk.clone(); - ent.endpoint = Some(p.endpoint.clone()); + let ent = insert_peer(&mut self.c, &mut self.err, src, &p.peer, psk, |ent| { + ent.endpoint = Some(p.endpoint); ent.keepalive = gc.fix_keepalive(p.keepalive); }); - add_peer(&mut self.err, ent, s, &p.peer) + add_peer(&mut self.err, ent, src, &p.peer) } #[inline] - pub fn add_road_warrior(&mut self, s: &config::Source, p: &proto::RoadWarrior) { + pub fn add_road_warrior(&mut self, src: &Source, p: &proto::RoadWarrior) { + let psk = match find_psk(&self.gc, src, &p.peer) { + Ok(v) => v, + Err(e) => { + self.err.push(e); + return; + } + }; + if p.peer.public_key == self.public_key { - self.err.push(ConfigError::new( + self.err.push(Error::new( "The local peer cannot be a road warrior", - s, + src, &p.peer, true, )); @@ -95,35 +117,36 @@ impl<'a> ConfigBuilder<'a> { } let ent = if p.base == self.public_key { - insert_peer(&mut self.c, &mut self.err, s, &p.peer, |_| {}) + insert_peer(&mut self.c, &mut self.err, src, &p.peer, psk, |_| {}) } else if let Some(ent) = self.c.peers.get_mut(&p.base) { ent } else { self.err - .push(ConfigError::new("Unknown base peer", s, &p.peer, true)); + .push(Error::new("Unknown base peer", src, &p.peer, true)); return; }; - add_peer(&mut self.err, ent, s, &p.peer) + add_peer(&mut self.err, ent, src, &p.peer) } } #[inline] fn insert_peer<'b>( c: &'b mut model::Config, - err: &mut Vec<ConfigError>, - s: &config::Source, + err: &mut Vec<Error>, + src: &Source, p: &proto::Peer, + psk: Option<&model::Key>, update: impl for<'c> FnOnce(&'c mut model::Peer) -> (), ) -> &'b mut model::Peer { - match c.peers.entry(p.public_key.clone()) { + match c.peers.entry(p.public_key) { hash_map::Entry::Occupied(ent) => { - err.push(ConfigError::new("Duplicate public key", s, p, true)); + err.push(Error::new("Duplicate public key", src, p, true)); ent.into_mut() } hash_map::Entry::Vacant(ent) => { let ent = ent.insert(model::Peer { endpoint: None, - psk: None, + psk: psk.cloned(), keepalive: 0, ipv4: vec![], ipv6: vec![], @@ -134,17 +157,33 @@ fn insert_peer<'b>( } } -fn add_peer( - err: &mut Vec<ConfigError>, - ent: &mut model::Peer, - s: &config::Source, +fn find_psk<'a>( + gc: &'a config::GlobalConfig, + src: &'a Source, p: &proto::Peer, -) { +) -> Result<Option<&'a model::Key>, Error> { + let want = gc.peers.get(&p.public_key); + let want = if let Some(v) = want { + v + } else { + return Ok(None); + }; + + if let Some(ref want_src) = &want.source { + if *want_src != src.name { + return Err(Error::new("Peer source not allowed", src, p, true)); + } + } + + Ok(want.psk.as_ref().or_else(|| src.config.psk.as_ref())) +} + +fn add_peer(err: &mut Vec<Error>, ent: &mut model::Peer, src: &Source, p: &proto::Peer) { let mut added = false; let mut removed = false; for i in &p.ipv4 { - if s.ipv4.contains(i) { + if src.config.ipv4.contains(i) { ent.ipv4.push(*i); added = true; } else { @@ -152,7 +191,7 @@ fn add_peer( } } for i in &p.ipv6 { - if s.ipv6.contains(i) { + if src.config.ipv6.contains(i) { ent.ipv6.push(*i); added = true; } else { @@ -166,6 +205,6 @@ fn add_peer( } else { "All IPs removed" }; - err.push(ConfigError::new(msg, s, p, !added)); + err.push(Error::new(msg, src, p, !added)); } } |