// Copyright 2019 Hristo Venev // // See COPYING. use crate::{config, model, proto}; use std::collections::hash_map; use std::{error, fmt}; #[derive(Debug)] pub struct ConfigError { pub url: String, pub peer: model::Key, pub important: bool, err: &'static str, } impl ConfigError { fn new(err: &'static str, s: &config::Source, p: &proto::Peer, important: bool) -> Self { ConfigError { url: s.url.clone(), peer: p.public_key.clone(), important, err, } } } impl error::Error for ConfigError {} impl fmt::Display for ConfigError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "{} [{}] from [{}]: {}", if self.important { "Invalid peer" } else { "Misconfigured peer" }, self.peer, self.url, self.err ) } } pub struct ConfigBuilder<'a> { c: model::Config, err: Vec, public_key: model::Key, pc: &'a config::PeerConfig, } impl<'a> ConfigBuilder<'a> { #[inline] pub fn new(public_key: model::Key, pc: &'a config::PeerConfig) -> Self { ConfigBuilder { c: model::Config::default(), err: vec![], public_key, pc, } } #[inline] pub fn build(self) -> (model::Config, Vec) { (self.c, self.err) } #[inline] pub fn add_server(&mut self, s: &config::Source, p: &proto::Server) { if p.peer.public_key == self.public_key { return; } let pc = self.pc; 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()); ent.keepalive = pc.fix_keepalive(p.keepalive); }); add_peer(&mut self.err, ent, s, &p.peer) } #[inline] pub fn add_road_warrior(&mut self, s: &config::Source, p: &proto::RoadWarrior) { if p.peer.public_key == self.public_key { self.err.push(ConfigError::new( "The local peer cannot be a road warrior", s, &p.peer, true, )); return; } let ent = if p.base == self.public_key { insert_peer(&mut self.c, &mut self.err, s, &p.peer, |_| {}) } else { match self.c.peers.get_mut(&p.base) { Some(ent) => ent, None => { self.err .push(ConfigError::new("Unknown base peer", s, &p.peer, true)); return; } } }; add_peer(&mut self.err, ent, s, &p.peer) } } #[inline] fn insert_peer<'b>( c: &'b mut model::Config, err: &mut Vec, s: &config::Source, p: &proto::Peer, update: impl for<'c> FnOnce(&'c mut model::Peer) -> (), ) -> &'b mut model::Peer { match c.peers.entry(p.public_key.clone()) { hash_map::Entry::Occupied(ent) => { err.push(ConfigError::new("Duplicate public key", s, p, true)); ent.into_mut() } hash_map::Entry::Vacant(ent) => { let ent = ent.insert(model::Peer { endpoint: None, psk: None, keepalive: 0, ipv4: vec![], ipv6: vec![], }); update(ent); ent } } } fn add_peer( err: &mut Vec, ent: &mut model::Peer, s: &config::Source, p: &proto::Peer, ) { let mut added = false; let mut removed = false; for i in p.ipv4.iter() { if s.ipv4.contains(i) { ent.ipv4.push(*i); added = true; } else { removed = true; } } for i in p.ipv6.iter() { if s.ipv6.contains(i) { ent.ipv6.push(*i); added = true; } else { removed = true; } } if removed { let msg = if added { "Some IPs removed" } else { "All IPs removed" }; err.push(ConfigError::new(msg, s, p, !added)); } }