diff --git a/CHANGELOG.md b/CHANGELOG.md index 726623b..85db2c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project follows [semantic versioning](http://semver.org). - [added] Automatically set optimal MTU on interface - [added] Warning for disabled or loose rp_filter setting - [added] Add --fix-rp-filter to fix rp filter settings +- [added] Offer to migrate old configs - [changed] **Complete change of network protocol** - [changed] Negotiate crypto method per peer, select best method - [changed] Make encryption the default, no encryption must be stated explicitly diff --git a/Cargo.lock b/Cargo.lock index ce3662c..737c615 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,9 +319,9 @@ dependencies = [ [[package]] name = "proc-macro-hack" -version = "0.5.18" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" diff --git a/src/config.rs b/src/config.rs index c0bdbcd..843bad5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -454,7 +454,11 @@ pub struct Args { /// Print logs also to this file #[structopt(long)] - pub log_file: Option + pub log_file: Option, + + /// Migrate an old config file + #[structopt(long, alias = "migrate", requires = "config")] + pub migrate_config: bool } #[derive(Serialize, Deserialize, Debug, PartialEq, Default)] diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index 1f426e0..32745b6 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -277,16 +277,16 @@ impl PeerCrypto

{ if let Some(ref core) = self.core { let algo = core.algorithm(); if algo == &aead::CHACHA20_POLY1305 { - "chacha20" + "CHACHA20" } else if algo == &aead::AES_128_GCM { - "aes128" + "AES128" } else if algo == &aead::AES_256_GCM { - "aes256" + "AES256" } else { unreachable!() } } else { - "plain" + "PLAIN" } } diff --git a/src/main.rs b/src/main.rs index a822fd6..ccf61d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ pub mod device; pub mod error; pub mod messages; pub mod net; +pub mod oldconfig; pub mod payload; pub mod poll; pub mod port_forwarding; @@ -49,8 +50,9 @@ use crate::{ config::{Args, Config}, crypto::Crypto, device::{Device, TunTapDevice, Type}, - port_forwarding::PortForwarding, + oldconfig::OldConfigFile, payload::Protocol, + port_forwarding::PortForwarding, util::SystemTimeSource }; @@ -242,11 +244,39 @@ fn main() { } else { log::LevelFilter::Info }); + if args.migrate_config { + let file = args.config.unwrap(); + info!("Trying to convert from old config format"); + let f = try_fail!(File::open(&file), "Failed to open config file: {:?}"); + let config_file_old: OldConfigFile = + try_fail!(serde_yaml::from_reader(f), "Config file not valid for version 1: {:?}"); + let new_config = config_file_old.convert(); + info!("Successfully converted from old format"); + info!("Renaming original file to {}.orig", file); + try_fail!(fs::rename(&file, format!("{}.orig", file)), "Failed to rename original file: {:?}"); + info!("Writing new config back into {}", file); + let f = try_fail!(File::create(&file), "Failed to open config file: {:?}"); + try_fail!(fs::set_permissions(&file, fs::Permissions::from_mode(0o600)), "Failed to set permissions on file: {:?}"); + try_fail!(serde_yaml::to_writer(f, &new_config), "Failed to write converted config: {:?}"); + return + } let mut config = Config::default(); if let Some(ref file) = args.config { info!("Reading config file '{}'", file); let f = try_fail!(File::open(file), "Failed to open config file: {:?}"); - let config_file = try_fail!(serde_yaml::from_reader(f), "Failed to load config file: {:?}"); + let config_file = match serde_yaml::from_reader(f) { + Ok(config) => config, + Err(err) => { + error!("Failed to read config file: {}", err); + info!("Trying to convert from old config format"); + let f = try_fail!(File::open(file), "Failed to open config file: {:?}"); + let config_file_old: OldConfigFile = + try_fail!(serde_yaml::from_reader(f), "Config file is neither version 2 nor version 1: {:?}"); + let new_config = config_file_old.convert(); + info!("Successfully converted from old format, please migrate your config using migrate-config"); + new_config + } + }; config.merge_file(config_file) } config.merge_args(args); diff --git a/src/oldconfig.rs b/src/oldconfig.rs new file mode 100644 index 0000000..0a717a0 --- /dev/null +++ b/src/oldconfig.rs @@ -0,0 +1,123 @@ +use super::{device::Type, types::Mode, util::Duration}; +use crate::config::{ConfigFile, ConfigFileBeacon, ConfigFileDevice, ConfigFileStatsd, CryptoConfig}; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)] +pub enum OldCryptoMethod { + #[serde(rename = "chacha20")] + ChaCha20, + #[serde(rename = "aes256")] + AES256, + #[serde(rename = "aes128")] + AES128 +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Default)] +pub struct OldConfigFile { + #[serde(alias = "device-type")] + pub device_type: Option, + #[serde(alias = "device-name")] + pub device_name: Option, + #[serde(alias = "device-path")] + pub device_path: Option, + pub ifup: Option, + pub ifdown: Option, + pub crypto: Option, + #[serde(alias = "shared-key")] + pub shared_key: Option, + pub magic: Option, + pub port: Option, + pub listen: Option, + pub peers: Option>, + #[serde(alias = "peer-timeout")] + pub peer_timeout: Option, + pub keepalive: Option, + #[serde(alias = "beacon-store")] + pub beacon_store: Option, + #[serde(alias = "beacon-load")] + pub beacon_load: Option, + #[serde(alias = "beacon-interval")] + pub beacon_interval: Option, + pub mode: Option, + #[serde(alias = "dst-timeout")] + pub dst_timeout: Option, + pub subnets: Option>, + #[serde(alias = "port-forwarding")] + pub port_forwarding: Option, + #[serde(alias = "pid-file")] + pub pid_file: Option, + #[serde(alias = "stats-file")] + pub stats_file: Option, + #[serde(alias = "statsd-server")] + pub statsd_server: Option, + #[serde(alias = "statsd-prefix")] + pub statsd_prefix: Option, + pub user: Option, + pub group: Option +} + +impl OldConfigFile { + #[allow(clippy::or_fun_call)] + pub fn convert(self) -> ConfigFile { + if self.device_type.is_none() { + warn!("The default device type changed from TAP to TUN") + } + if self.ifup.is_some() { + info!("There is a new option --ip that can handle most use cases of --ifup") + } + info!("The converted config enables all available encryption algorithms"); + if self.shared_key.is_none() { + warn!("Operation without a password is no longer supported, password set to 'none'"); + } + if self.magic.is_some() { + warn!("The magic header functionality is no longer supported") + } + if self.listen.is_some() && self.port.is_some() { + warn!("The port option is no longer available, using listen instead") + } + if self.peer_timeout.is_none() { + info!("The default peer timeout changed from 10 minutes to 5 minutes") + } + warn!("Even with a converted config file version 2 nodes can not communicate with version 1 nodes"); + ConfigFile { + auto_claim: None, + beacon: Some(ConfigFileBeacon { + interval: self.beacon_interval, + load: self.beacon_load, + store: self.beacon_store, + password: self.shared_key.clone() + }), + claims: self.subnets, + crypto: CryptoConfig { + algorithms: vec![], + password: Some(self.shared_key.unwrap_or_else(|| "none".to_string())), + private_key: None, + public_key: None, + trusted_keys: vec![] + }, + device: Some(ConfigFileDevice { + fix_rp_filter: None, + name: self.device_name, + path: self.device_path, + type_: self.device_type + }), + group: self.group, + ifdown: self.ifdown, + ifup: self.ifup, + ip: None, + keepalive: self.keepalive, + listen: self.listen.or(self.port.map(|p| format!("{}", p))), + mode: self.mode, + peer_timeout: self.peer_timeout, + peers: self.peers, + pid_file: self.pid_file, + port_forwarding: self.port_forwarding, + stats_file: self.stats_file, + statsd: Some(ConfigFileStatsd { + prefix: self.statsd_prefix, + server: self.statsd_server + }), + switch_timeout: self.dst_timeout, + user: self.user + } + } +} \ No newline at end of file