Offer to migrate old configs

This commit is contained in:
Dennis Schwerdel 2020-10-29 22:12:33 +01:00
parent 16da58b8df
commit ca0e5e9791
6 changed files with 167 additions and 9 deletions

View File

@ -10,6 +10,7 @@ This project follows [semantic versioning](http://semver.org).
- [added] Automatically set optimal MTU on interface - [added] Automatically set optimal MTU on interface
- [added] Warning for disabled or loose rp_filter setting - [added] Warning for disabled or loose rp_filter setting
- [added] Add --fix-rp-filter to fix rp filter settings - [added] Add --fix-rp-filter to fix rp filter settings
- [added] Offer to migrate old configs
- [changed] **Complete change of network protocol** - [changed] **Complete change of network protocol**
- [changed] Negotiate crypto method per peer, select best method - [changed] Negotiate crypto method per peer, select best method
- [changed] Make encryption the default, no encryption must be stated explicitly - [changed] Make encryption the default, no encryption must be stated explicitly

4
Cargo.lock generated
View File

@ -319,9 +319,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro-hack" name = "proc-macro-hack"
version = "0.5.18" version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"

View File

@ -454,7 +454,11 @@ pub struct Args {
/// Print logs also to this file /// Print logs also to this file
#[structopt(long)] #[structopt(long)]
pub log_file: Option<String> pub log_file: Option<String>,
/// Migrate an old config file
#[structopt(long, alias = "migrate", requires = "config")]
pub migrate_config: bool
} }
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)] #[derive(Serialize, Deserialize, Debug, PartialEq, Default)]

View File

@ -277,16 +277,16 @@ impl<P: Payload> PeerCrypto<P> {
if let Some(ref core) = self.core { if let Some(ref core) = self.core {
let algo = core.algorithm(); let algo = core.algorithm();
if algo == &aead::CHACHA20_POLY1305 { if algo == &aead::CHACHA20_POLY1305 {
"chacha20" "CHACHA20"
} else if algo == &aead::AES_128_GCM { } else if algo == &aead::AES_128_GCM {
"aes128" "AES128"
} else if algo == &aead::AES_256_GCM { } else if algo == &aead::AES_256_GCM {
"aes256" "AES256"
} else { } else {
unreachable!() unreachable!()
} }
} else { } else {
"plain" "PLAIN"
} }
} }

View File

@ -23,6 +23,7 @@ pub mod device;
pub mod error; pub mod error;
pub mod messages; pub mod messages;
pub mod net; pub mod net;
pub mod oldconfig;
pub mod payload; pub mod payload;
pub mod poll; pub mod poll;
pub mod port_forwarding; pub mod port_forwarding;
@ -49,8 +50,9 @@ use crate::{
config::{Args, Config}, config::{Args, Config},
crypto::Crypto, crypto::Crypto,
device::{Device, TunTapDevice, Type}, device::{Device, TunTapDevice, Type},
port_forwarding::PortForwarding, oldconfig::OldConfigFile,
payload::Protocol, payload::Protocol,
port_forwarding::PortForwarding,
util::SystemTimeSource util::SystemTimeSource
}; };
@ -242,11 +244,39 @@ fn main() {
} else { } else {
log::LevelFilter::Info 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(); let mut config = Config::default();
if let Some(ref file) = args.config { if let Some(ref file) = args.config {
info!("Reading config file '{}'", file); info!("Reading config file '{}'", file);
let f = try_fail!(File::open(file), "Failed to open config 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_file(config_file)
} }
config.merge_args(args); config.merge_args(args);

123
src/oldconfig.rs Normal file
View File

@ -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<Type>,
#[serde(alias = "device-name")]
pub device_name: Option<String>,
#[serde(alias = "device-path")]
pub device_path: Option<String>,
pub ifup: Option<String>,
pub ifdown: Option<String>,
pub crypto: Option<OldCryptoMethod>,
#[serde(alias = "shared-key")]
pub shared_key: Option<String>,
pub magic: Option<String>,
pub port: Option<u16>,
pub listen: Option<String>,
pub peers: Option<Vec<String>>,
#[serde(alias = "peer-timeout")]
pub peer_timeout: Option<Duration>,
pub keepalive: Option<Duration>,
#[serde(alias = "beacon-store")]
pub beacon_store: Option<String>,
#[serde(alias = "beacon-load")]
pub beacon_load: Option<String>,
#[serde(alias = "beacon-interval")]
pub beacon_interval: Option<Duration>,
pub mode: Option<Mode>,
#[serde(alias = "dst-timeout")]
pub dst_timeout: Option<Duration>,
pub subnets: Option<Vec<String>>,
#[serde(alias = "port-forwarding")]
pub port_forwarding: Option<bool>,
#[serde(alias = "pid-file")]
pub pid_file: Option<String>,
#[serde(alias = "stats-file")]
pub stats_file: Option<String>,
#[serde(alias = "statsd-server")]
pub statsd_server: Option<String>,
#[serde(alias = "statsd-prefix")]
pub statsd_prefix: Option<String>,
pub user: Option<String>,
pub group: Option<String>
}
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
}
}
}