vpncloud/src/config.rs

871 lines
28 KiB
Rust
Raw Normal View History

2017-07-22 14:49:53 +00:00
// VpnCloud - Peer-to-Peer VPN
2021-02-08 09:11:20 +00:00
// Copyright (C) 2015-2021 Dennis Schwerdel
2017-07-22 14:49:53 +00:00
// This software is licensed under GPL-3 or newer (see LICENSE.md)
2021-04-06 10:28:31 +00:00
use super::{device::Type, types::Mode, util::run_cmd, util::Duration};
2020-09-24 17:48:13 +00:00
pub use crate::crypto::Config as CryptoConfig;
2021-04-06 10:28:31 +00:00
use std::{cmp::max, collections::HashMap, ffi::OsStr, process, thread};
2021-01-24 18:24:40 +00:00
use structopt::{clap::Shell, StructOpt};
2020-09-24 17:48:13 +00:00
pub const DEFAULT_PEER_TIMEOUT: u16 = 300;
2020-06-24 13:28:16 +00:00
pub const DEFAULT_PORT: u16 = 3210;
2019-02-15 21:42:13 +00:00
2019-01-10 18:36:50 +00:00
#[derive(Deserialize, Debug, PartialEq, Clone)]
pub struct Config {
pub device_type: Type,
pub device_name: String,
2019-02-12 18:30:38 +00:00
pub device_path: Option<String>,
2020-09-24 17:48:13 +00:00
pub fix_rp_filter: bool,
pub ip: Option<String>,
pub advertise_addresses: Vec<String>,
pub ifup: Option<String>,
pub ifdown: Option<String>,
2020-09-24 17:48:13 +00:00
pub crypto: CryptoConfig,
2020-12-20 00:40:32 +00:00
pub listen: String,
pub peers: Vec<String>,
pub peer_timeout: Duration,
2019-01-10 18:36:50 +00:00
pub keepalive: Option<Duration>,
2019-02-19 21:04:21 +00:00
pub beacon_store: Option<String>,
pub beacon_load: Option<String>,
pub beacon_interval: Duration,
2020-09-24 17:48:13 +00:00
pub beacon_password: Option<String>,
pub mode: Mode,
2020-09-24 17:48:13 +00:00
pub switch_timeout: Duration,
pub claims: Vec<String>,
pub auto_claim: bool,
pub port_forwarding: bool,
2016-11-23 14:21:22 +00:00
pub daemonize: bool,
pub pid_file: Option<String>,
2019-01-09 16:45:12 +00:00
pub stats_file: Option<String>,
2020-05-29 09:51:04 +00:00
pub statsd_server: Option<String>,
2020-05-30 14:12:54 +00:00
pub statsd_prefix: Option<String>,
2016-11-23 14:21:22 +00:00
pub user: Option<String>,
2020-12-20 00:40:32 +00:00
pub group: Option<String>,
2021-01-24 18:24:40 +00:00
pub hook: Option<String>,
2021-04-06 10:28:31 +00:00
pub hooks: HashMap<String, String>,
}
impl Default for Config {
fn default() -> Self {
Config {
2020-09-24 17:48:13 +00:00
device_type: Type::Tun,
2019-12-04 08:32:35 +00:00
device_name: "vpncloud%d".to_string(),
device_path: None,
2020-09-24 17:48:13 +00:00
fix_rp_filter: false,
ip: None,
advertise_addresses: vec![],
2019-12-04 08:32:35 +00:00
ifup: None,
ifdown: None,
2020-09-24 17:48:13 +00:00
crypto: CryptoConfig::default(),
2021-02-03 21:44:31 +00:00
listen: "3210".to_string(),
2019-12-04 08:32:35 +00:00
peers: vec![],
peer_timeout: DEFAULT_PEER_TIMEOUT as Duration,
2019-12-04 08:32:35 +00:00
keepalive: None,
beacon_store: None,
beacon_load: None,
beacon_interval: 3600,
2020-09-24 17:48:13 +00:00
beacon_password: None,
2019-12-04 08:32:35 +00:00
mode: Mode::Normal,
2020-09-24 17:48:13 +00:00
switch_timeout: 300,
claims: vec![],
auto_claim: true,
2016-11-23 14:21:22 +00:00
port_forwarding: true,
daemonize: false,
pid_file: None,
2019-01-09 16:45:12 +00:00
stats_file: None,
2020-05-29 09:51:04 +00:00
statsd_server: None,
2020-05-30 14:12:54 +00:00
statsd_prefix: None,
2016-11-23 14:21:22 +00:00
user: None,
2020-12-20 00:40:32 +00:00
group: None,
2021-01-24 18:24:40 +00:00
hook: None,
2021-04-06 10:28:31 +00:00
hooks: HashMap::new(),
}
}
}
impl Config {
#[allow(clippy::cognitive_complexity)]
2020-09-24 17:48:13 +00:00
pub fn merge_file(&mut self, mut file: ConfigFile) {
2020-09-24 22:45:58 +00:00
if let Some(device) = file.device {
if let Some(val) = device.type_ {
self.device_type = val;
}
if let Some(val) = device.name {
self.device_name = val;
}
if let Some(val) = device.path {
self.device_path = Some(val);
}
if let Some(val) = device.fix_rp_filter {
self.fix_rp_filter = val;
}
2020-09-24 17:48:13 +00:00
}
if let Some(val) = file.ip {
self.ip = Some(val);
}
if let Some(mut val) = file.advertise_addresses {
self.advertise_addresses.append(&mut val);
}
if let Some(val) = file.ifup {
self.ifup = Some(val);
}
if let Some(val) = file.ifdown {
self.ifdown = Some(val);
}
if let Some(val) = file.listen {
2020-12-20 00:40:32 +00:00
self.listen = val;
}
if let Some(mut val) = file.peers {
self.peers.append(&mut val);
}
if let Some(val) = file.peer_timeout {
self.peer_timeout = val;
}
2019-01-10 18:36:50 +00:00
if let Some(val) = file.keepalive {
self.keepalive = Some(val);
}
2020-09-24 22:45:58 +00:00
if let Some(beacon) = file.beacon {
if let Some(val) = beacon.store {
self.beacon_store = Some(val);
}
if let Some(val) = beacon.load {
self.beacon_load = Some(val);
}
if let Some(val) = beacon.interval {
self.beacon_interval = val;
}
if let Some(val) = beacon.password {
self.beacon_password = Some(val);
}
2020-09-24 17:48:13 +00:00
}
if let Some(val) = file.mode {
self.mode = val;
}
2020-09-24 17:48:13 +00:00
if let Some(val) = file.switch_timeout {
self.switch_timeout = val;
}
if let Some(mut val) = file.claims {
self.claims.append(&mut val);
}
2020-09-24 17:48:13 +00:00
if let Some(val) = file.auto_claim {
self.auto_claim = val;
}
if let Some(val) = file.port_forwarding {
self.port_forwarding = val;
}
2016-11-23 14:21:22 +00:00
if let Some(val) = file.pid_file {
self.pid_file = Some(val);
}
2019-01-09 16:45:12 +00:00
if let Some(val) = file.stats_file {
self.stats_file = Some(val);
}
2020-09-24 22:45:58 +00:00
if let Some(statsd) = file.statsd {
if let Some(val) = statsd.server {
self.statsd_server = Some(val);
}
if let Some(val) = statsd.prefix {
self.statsd_prefix = Some(val);
}
2020-05-30 14:12:54 +00:00
}
2016-11-23 14:21:22 +00:00
if let Some(val) = file.user {
self.user = Some(val);
}
if let Some(val) = file.group {
self.group = Some(val);
}
2020-09-24 17:48:13 +00:00
if let Some(val) = file.crypto.password {
self.crypto.password = Some(val)
}
if let Some(val) = file.crypto.public_key {
self.crypto.public_key = Some(val)
}
if let Some(val) = file.crypto.private_key {
self.crypto.private_key = Some(val)
}
self.crypto.trusted_keys.append(&mut file.crypto.trusted_keys);
if !file.crypto.algorithms.is_empty() {
self.crypto.algorithms = file.crypto.algorithms.clone();
}
2021-01-24 18:24:40 +00:00
if let Some(val) = file.hook {
self.hook = Some(val)
2021-01-23 19:29:15 +00:00
}
2021-01-24 18:24:40 +00:00
for (k, v) in file.hooks {
self.hooks.insert(k, v);
2021-01-23 19:29:15 +00:00
}
}
pub fn merge_args(&mut self, mut args: Args) {
2020-05-29 06:37:29 +00:00
if let Some(val) = args.type_ {
self.device_type = val;
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.device {
self.device_name = val;
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.device_path {
2019-02-12 18:30:38 +00:00
self.device_path = Some(val);
}
2020-09-24 17:48:13 +00:00
if args.fix_rp_filter {
self.fix_rp_filter = true;
}
if let Some(val) = args.ip {
self.ip = Some(val);
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.ifup {
self.ifup = Some(val);
}
self.advertise_addresses.append(&mut args.advertise_addresses);
2020-05-29 06:37:29 +00:00
if let Some(val) = args.ifdown {
self.ifdown = Some(val);
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.listen {
2020-12-20 00:40:32 +00:00
self.listen = val;
}
2020-09-24 17:48:13 +00:00
self.peers.append(&mut args.peers);
2020-05-29 06:37:29 +00:00
if let Some(val) = args.peer_timeout {
self.peer_timeout = val;
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.keepalive {
2019-01-10 18:36:50 +00:00
self.keepalive = Some(val);
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.beacon_store {
2019-02-19 21:04:21 +00:00
self.beacon_store = Some(val);
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.beacon_load {
2019-02-19 21:04:21 +00:00
self.beacon_load = Some(val);
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.beacon_interval {
2019-02-19 21:04:21 +00:00
self.beacon_interval = val;
}
2020-09-24 17:48:13 +00:00
if let Some(val) = args.beacon_password {
self.beacon_password = Some(val);
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.mode {
self.mode = val;
}
2020-09-24 17:48:13 +00:00
if let Some(val) = args.switch_timeout {
self.switch_timeout = val;
}
self.claims.append(&mut args.claims);
if args.no_auto_claim {
self.auto_claim = false;
}
2020-05-29 06:37:29 +00:00
if args.no_port_forwarding {
self.port_forwarding = false;
}
2020-05-29 06:37:29 +00:00
if args.daemon {
2016-11-23 14:21:22 +00:00
self.daemonize = true;
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.pid_file {
2016-11-23 14:21:22 +00:00
self.pid_file = Some(val);
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.stats_file {
2019-01-09 16:45:12 +00:00
self.stats_file = Some(val);
}
2020-05-29 09:51:04 +00:00
if let Some(val) = args.statsd_server {
self.statsd_server = Some(val);
}
2020-05-30 14:12:54 +00:00
if let Some(val) = args.statsd_prefix {
self.statsd_prefix = Some(val);
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.user {
2016-11-23 14:21:22 +00:00
self.user = Some(val);
}
2020-05-29 06:37:29 +00:00
if let Some(val) = args.group {
2016-11-23 14:21:22 +00:00
self.group = Some(val);
}
2020-09-24 17:48:13 +00:00
if let Some(val) = args.password {
self.crypto.password = Some(val)
}
if let Some(val) = args.public_key {
self.crypto.public_key = Some(val)
}
if let Some(val) = args.private_key {
self.crypto.private_key = Some(val)
}
self.crypto.trusted_keys.append(&mut args.trusted_keys);
if !args.algorithms.is_empty() {
self.crypto.algorithms = args.algorithms.clone();
}
2021-01-24 18:24:40 +00:00
for s in args.hook {
if s.contains(':') {
let pos = s.find(':').unwrap();
let name = &s[..pos];
2021-04-06 10:28:31 +00:00
let hook = &s[pos + 1..];
2021-01-24 18:24:40 +00:00
self.hooks.insert(name.to_string(), hook.to_string());
} else {
self.hook = Some(s);
}
2021-01-23 19:29:15 +00:00
}
}
2019-01-10 18:36:50 +00:00
2021-02-13 23:09:11 +00:00
pub fn into_config_file(self) -> ConfigFile {
ConfigFile {
auto_claim: Some(self.auto_claim),
claims: Some(self.claims),
beacon: Some(ConfigFileBeacon {
store: self.beacon_store,
load: self.beacon_load,
interval: Some(self.beacon_interval),
2021-04-06 10:28:31 +00:00
password: self.beacon_password,
2021-02-13 23:09:11 +00:00
}),
device: Some(ConfigFileDevice {
name: Some(self.device_name),
path: self.device_path,
type_: Some(self.device_type),
2021-04-06 10:28:31 +00:00
fix_rp_filter: Some(self.fix_rp_filter),
2021-02-13 23:09:11 +00:00
}),
crypto: self.crypto,
group: self.group,
user: self.user,
ifup: self.ifup,
ifdown: self.ifdown,
ip: self.ip,
advertise_addresses: Some(self.advertise_addresses),
2021-02-13 23:09:11 +00:00
keepalive: self.keepalive,
listen: Some(self.listen),
mode: Some(self.mode),
peer_timeout: Some(self.peer_timeout),
peers: Some(self.peers),
pid_file: self.pid_file,
port_forwarding: Some(self.port_forwarding),
stats_file: self.stats_file,
2021-04-06 10:28:31 +00:00
statsd: Some(ConfigFileStatsd { server: self.statsd_server, prefix: self.statsd_prefix }),
2021-02-13 23:09:11 +00:00
switch_timeout: Some(self.switch_timeout),
hook: self.hook,
2021-04-06 10:28:31 +00:00
hooks: self.hooks,
2021-02-13 23:09:11 +00:00
}
}
2019-01-10 18:36:50 +00:00
pub fn get_keepalive(&self) -> Duration {
match self.keepalive {
Some(dur) => dur,
2020-12-20 00:40:32 +00:00
None => max(self.peer_timeout / 2 - 60, 1),
2019-01-10 18:36:50 +00:00
}
}
2021-01-24 18:24:40 +00:00
pub fn call_hook(
2021-04-06 10:28:31 +00:00
&self, event: &'static str, envs: impl IntoIterator<Item = (&'static str, impl AsRef<OsStr>)>, detach: bool,
2021-01-23 19:29:15 +00:00
) {
let mut script = None;
2021-01-24 18:24:40 +00:00
if let Some(ref s) = self.hook {
2021-01-23 19:29:15 +00:00
script = Some(s);
}
2021-12-19 12:54:09 +00:00
if let Some(s) = self.hooks.get(event) {
2021-01-23 19:29:15 +00:00
script = Some(s);
}
if script.is_none() {
2021-04-06 10:28:31 +00:00
return;
2021-01-23 19:29:15 +00:00
}
let script = script.unwrap();
2021-02-03 21:44:31 +00:00
let mut cmd = process::Command::new("sh");
2021-01-23 19:29:15 +00:00
cmd.arg("-c").arg(script).envs(envs).env("EVENT", event);
debug!("Running event script: {:?}", cmd);
if detach {
thread::spawn(move || run_cmd(cmd));
} else {
run_cmd(cmd)
}
}
}
2020-09-24 17:48:13 +00:00
#[derive(StructOpt, Debug, Default)]
pub struct Args {
/// Read configuration options from the specified file.
#[structopt(long)]
pub config: Option<String>,
/// Set the type of network
#[structopt(name = "type", short, long, possible_values=&["tun", "tap"])]
pub type_: Option<Type>,
/// Set the path of the base device
#[structopt(long)]
pub device_path: Option<String>,
/// Fix the rp_filter settings on the host
#[structopt(long)]
pub fix_rp_filter: bool,
/// The mode of the VPN
#[structopt(short, long, possible_values=&["normal", "router", "switch", "hub"])]
pub mode: Option<Mode>,
/// The shared password to encrypt all traffic
2021-02-04 22:38:08 +00:00
#[structopt(short, long, env)]
2020-09-24 17:48:13 +00:00
pub password: Option<String>,
/// The private key to use
#[structopt(long, alias = "key", conflicts_with = "password", env)]
pub private_key: Option<String>,
/// The public key to use
#[structopt(long)]
pub public_key: Option<String>,
/// Other public keys to trust
2020-09-24 22:45:58 +00:00
#[structopt(long = "trusted-key", alias = "trust", use_delimiter = true)]
2020-09-24 17:48:13 +00:00
pub trusted_keys: Vec<String>,
/// Algorithms to allow
2020-09-24 22:45:58 +00:00
#[structopt(long = "algorithm", alias = "algo", use_delimiter=true, case_insensitive = true, possible_values=&["plain", "aes128", "aes256", "chacha20"])]
2020-09-24 17:48:13 +00:00
pub algorithms: Vec<String>,
/// The local subnets to claim (IP or IP/prefix)
2020-09-24 22:45:58 +00:00
#[structopt(long = "claim", use_delimiter = true)]
2020-09-24 17:48:13 +00:00
pub claims: Vec<String>,
/// Do not automatically claim the device ip
#[structopt(long)]
pub no_auto_claim: bool,
/// Name of the virtual device
#[structopt(short, long)]
pub device: Option<String>,
/// The port number (or ip:port) on which to listen for data
#[structopt(short, long)]
pub listen: Option<String>,
/// Address of a peer to connect to
2020-09-24 22:45:58 +00:00
#[structopt(short = "c", long = "peer", alias = "connect")]
2020-09-24 17:48:13 +00:00
pub peers: Vec<String>,
/// Peer timeout in seconds
#[structopt(long)]
pub peer_timeout: Option<Duration>,
2020-09-24 22:45:58 +00:00
/// Periodically send message to keep connections alive
2020-09-24 17:48:13 +00:00
#[structopt(long)]
pub keepalive: Option<Duration>,
/// Switch table entry timeout in seconds
#[structopt(long)]
pub switch_timeout: Option<Duration>,
/// The file path or |command to store the beacon
#[structopt(long)]
pub beacon_store: Option<String>,
/// The file path or |command to load the beacon
#[structopt(long)]
pub beacon_load: Option<String>,
/// Beacon store/load interval in seconds
#[structopt(long)]
pub beacon_interval: Option<Duration>,
/// Password to encrypt the beacon with
#[structopt(long)]
pub beacon_password: Option<String>,
/// Print debug information
#[structopt(short, long, conflicts_with = "quiet")]
pub verbose: bool,
/// Only print errors and warnings
#[structopt(short, long)]
pub quiet: bool,
/// An IP address (plus optional prefix length) for the interface
#[structopt(long)]
pub ip: Option<String>,
/// A list of IP Addresses to advertise as our external address(s)
#[structopt(long = "advertise_addresses", use_delimiter = true)]
pub advertise_addresses: Vec<String>,
2020-09-24 17:48:13 +00:00
/// A command to setup the network interface
#[structopt(long)]
pub ifup: Option<String>,
/// A command to bring down the network interface
#[structopt(long)]
pub ifdown: Option<String>,
/// Print the version and exit
#[structopt(long)]
pub version: bool,
/// Disable automatic port forwarding
#[structopt(long)]
pub no_port_forwarding: bool,
/// Run the process in the background
#[structopt(long)]
pub daemon: bool,
/// Store the process id in this file when daemonizing
#[structopt(long)]
pub pid_file: Option<String>,
/// Print statistics to this file
#[structopt(long)]
pub stats_file: Option<String>,
/// Send statistics to this statsd server
#[structopt(long)]
pub statsd_server: Option<String>,
/// Use the given prefix for statsd records
#[structopt(long, requires = "statsd-server")]
pub statsd_prefix: Option<String>,
/// Run as other user
#[structopt(long)]
pub user: Option<String>,
/// Run as other group
#[structopt(long)]
pub group: Option<String>,
/// Print logs also to this file
#[structopt(long)]
2020-10-29 21:12:33 +00:00
pub log_file: Option<String>,
2021-02-03 21:44:31 +00:00
/// Call script on event
#[structopt(long)]
pub hook: Vec<String>,
2020-12-20 00:40:32 +00:00
#[structopt(subcommand)]
pub cmd: Option<Command>,
}
#[derive(StructOpt, Debug)]
pub enum Command {
/// Generate and print a key-pair and exit
#[structopt(name = "genkey", alias = "gen-key")]
2021-02-05 17:27:48 +00:00
GenKey {
/// The shared password to encrypt all traffic
#[structopt(short, long, env)]
password: Option<String>,
},
2020-12-20 00:40:32 +00:00
2021-02-04 20:19:05 +00:00
/// Run a websocket proxy
2021-02-04 20:42:38 +00:00
#[cfg(feature = "websocket")]
2021-02-04 20:19:05 +00:00
#[structopt(alias = "wsproxy")]
WsProxy {
/// Websocket listen address IP:PORT
2021-04-06 10:28:31 +00:00
#[structopt(long, short, default_value = "3210")]
listen: String,
2021-02-04 20:19:05 +00:00
},
2020-12-20 00:40:32 +00:00
2020-10-29 21:12:33 +00:00
/// Migrate an old config file
2020-12-20 00:40:32 +00:00
#[structopt(alias = "migrate")]
MigrateConfig {
/// Config file
#[structopt(long)]
config_file: String,
},
2021-01-16 22:44:43 +00:00
/// Generate shell completions
2021-02-03 21:44:31 +00:00
Completion {
/// Shell to create completions for
2021-04-06 10:28:31 +00:00
#[structopt(long, default_value = "bash")]
shell: Shell,
2021-02-13 23:09:11 +00:00
},
/// Edit the config of a network
#[cfg(feature = "wizard")]
Config {
/// Name of the network
#[structopt(short, long)]
2021-04-06 10:28:31 +00:00
name: Option<String>,
},
/// Install required utility files
#[cfg(feature = "installer")]
Install {
/// Remove installed files again
#[structopt(long)]
2021-04-06 10:28:31 +00:00
uninstall: bool,
},
2020-09-24 17:48:13 +00:00
}
2020-09-24 22:45:58 +00:00
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
#[serde(rename_all = "kebab-case", deny_unknown_fields, default)]
pub struct ConfigFileDevice {
#[serde(rename = "type")]
pub type_: Option<Type>,
pub name: Option<String>,
pub path: Option<String>,
2020-12-20 00:40:32 +00:00
pub fix_rp_filter: Option<bool>,
2020-09-24 22:45:58 +00:00
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
#[serde(rename_all = "kebab-case", deny_unknown_fields, default)]
pub struct ConfigFileBeacon {
pub store: Option<String>,
pub load: Option<String>,
pub interval: Option<Duration>,
2020-12-20 00:40:32 +00:00
pub password: Option<String>,
2020-09-24 22:45:58 +00:00
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
#[serde(rename_all = "kebab-case", deny_unknown_fields, default)]
pub struct ConfigFileStatsd {
pub server: Option<String>,
2020-12-20 00:40:32 +00:00
pub prefix: Option<String>,
2020-09-24 22:45:58 +00:00
}
2020-09-24 17:48:13 +00:00
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
2020-09-24 17:48:13 +00:00
#[serde(rename_all = "kebab-case", deny_unknown_fields, default)]
pub struct ConfigFile {
2020-09-24 22:45:58 +00:00
pub device: Option<ConfigFileDevice>,
2020-09-24 17:48:13 +00:00
pub ip: Option<String>,
pub advertise_addresses: Option<Vec<String>>,
pub ifup: Option<String>,
pub ifdown: Option<String>,
2020-09-24 17:48:13 +00:00
pub crypto: CryptoConfig,
pub listen: Option<String>,
pub peers: Option<Vec<String>>,
pub peer_timeout: Option<Duration>,
2019-01-10 18:36:50 +00:00
pub keepalive: Option<Duration>,
2020-09-24 22:45:58 +00:00
pub beacon: Option<ConfigFileBeacon>,
pub mode: Option<Mode>,
2020-09-24 17:48:13 +00:00
pub switch_timeout: Option<Duration>,
pub claims: Option<Vec<String>>,
pub auto_claim: Option<bool>,
2016-11-23 14:21:22 +00:00
pub port_forwarding: Option<bool>,
pub pid_file: Option<String>,
2019-01-09 16:45:12 +00:00
pub stats_file: Option<String>,
2020-09-24 22:45:58 +00:00
pub statsd: Option<ConfigFileStatsd>,
2016-11-23 14:21:22 +00:00
pub user: Option<String>,
2020-12-20 00:40:32 +00:00
pub group: Option<String>,
2021-01-24 18:24:40 +00:00
pub hook: Option<String>,
2021-04-06 10:28:31 +00:00
pub hooks: HashMap<String, String>,
}
2019-02-19 17:42:50 +00:00
#[test]
fn config_file() {
let config_file = "
2020-09-25 20:11:28 +00:00
device:
type: tun
name: vpncloud%d
path: /dev/net/tun
2020-09-24 17:48:13 +00:00
ip: 10.0.1.1/16
advertise-addresses:
- 192.168.0.1
- 192.168.1.1
2019-02-19 17:42:50 +00:00
ifup: ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up
ifdown: 'true'
peers:
- remote.machine.foo:3210
- remote.machine.bar:3210
2020-09-24 17:48:13 +00:00
peer-timeout: 600
2019-02-19 17:42:50 +00:00
keepalive: 840
2020-09-24 17:48:13 +00:00
switch-timeout: 300
2020-09-25 20:11:28 +00:00
beacon:
store: /run/vpncloud.beacon.out
load: /run/vpncloud.beacon.in
interval: 3600
password: test123
2019-02-19 17:42:50 +00:00
mode: normal
2020-09-24 17:48:13 +00:00
claims:
2019-02-19 17:42:50 +00:00
- 10.0.1.0/24
2020-09-24 17:48:13 +00:00
port-forwarding: true
2019-02-19 17:42:50 +00:00
user: nobody
group: nogroup
2020-09-24 17:48:13 +00:00
pid-file: /run/vpncloud.run
stats-file: /var/log/vpncloud.stats
2020-09-25 20:11:28 +00:00
statsd:
server: example.com:1234
prefix: prefix
2019-02-19 17:42:50 +00:00
";
2020-12-20 00:40:32 +00:00
assert_eq!(
serde_yaml::from_str::<ConfigFile>(config_file).unwrap(),
ConfigFile {
device: Some(ConfigFileDevice {
type_: Some(Type::Tun),
name: Some("vpncloud%d".to_string()),
path: Some("/dev/net/tun".to_string()),
fix_rp_filter: None
}),
ip: Some("10.0.1.1/16".to_string()),
advertise_addresses: Some(vec!["192.168.0.1".to_string(), "192.168.1.1".to_string()]),
2020-12-20 00:40:32 +00:00
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
ifdown: Some("true".to_string()),
crypto: CryptoConfig::default(),
listen: None,
peers: Some(vec!["remote.machine.foo:3210".to_string(), "remote.machine.bar:3210".to_string()]),
peer_timeout: Some(600),
keepalive: Some(840),
beacon: Some(ConfigFileBeacon {
store: Some("/run/vpncloud.beacon.out".to_string()),
load: Some("/run/vpncloud.beacon.in".to_string()),
interval: Some(3600),
password: Some("test123".to_string())
}),
mode: Some(Mode::Normal),
switch_timeout: Some(300),
claims: Some(vec!["10.0.1.0/24".to_string()]),
auto_claim: None,
port_forwarding: Some(true),
user: Some("nobody".to_string()),
group: Some("nogroup".to_string()),
pid_file: Some("/run/vpncloud.run".to_string()),
stats_file: Some("/var/log/vpncloud.stats".to_string()),
statsd: Some(ConfigFileStatsd {
server: Some("example.com:1234".to_string()),
prefix: Some("prefix".to_string())
2021-02-03 21:44:31 +00:00
}),
hook: None,
hooks: HashMap::new()
2020-12-20 00:40:32 +00:00
}
)
2019-02-19 17:42:50 +00:00
}
2020-10-26 22:00:36 +00:00
#[test]
2021-02-08 09:11:35 +00:00
fn parse_example_config() {
serde_yaml::from_str::<ConfigFile>(include_str!("../assets/example.net.disabled")).unwrap();
2020-10-26 22:00:36 +00:00
}
2019-02-19 17:42:50 +00:00
#[test]
fn config_merge() {
let mut config = Config::default();
2019-12-04 08:32:35 +00:00
config.merge_file(ConfigFile {
2020-09-24 22:45:58 +00:00
device: Some(ConfigFileDevice {
type_: Some(Type::Tun),
name: Some("vpncloud%d".to_string()),
path: None,
2020-12-20 00:40:32 +00:00
fix_rp_filter: None,
2020-09-24 22:45:58 +00:00
}),
2020-09-24 17:48:13 +00:00
ip: None,
advertise_addresses: Some(vec![]),
2019-02-19 17:42:50 +00:00
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
ifdown: Some("true".to_string()),
2020-09-24 17:48:13 +00:00
crypto: CryptoConfig::default(),
listen: None,
2019-02-19 17:42:50 +00:00
peers: Some(vec!["remote.machine.foo:3210".to_string(), "remote.machine.bar:3210".to_string()]),
peer_timeout: Some(600),
2019-02-19 17:42:50 +00:00
keepalive: Some(840),
2020-09-24 22:45:58 +00:00
beacon: Some(ConfigFileBeacon {
store: Some("/run/vpncloud.beacon.out".to_string()),
load: Some("/run/vpncloud.beacon.in".to_string()),
interval: Some(7200),
2020-12-20 00:40:32 +00:00
password: Some("test123".to_string()),
2020-09-24 22:45:58 +00:00
}),
2019-02-19 17:42:50 +00:00
mode: Some(Mode::Normal),
2020-09-24 17:48:13 +00:00
switch_timeout: Some(300),
claims: Some(vec!["10.0.1.0/24".to_string()]),
auto_claim: Some(true),
2019-02-19 17:42:50 +00:00
port_forwarding: Some(true),
user: Some("nobody".to_string()),
group: Some("nogroup".to_string()),
pid_file: Some("/run/vpncloud.run".to_string()),
2020-05-29 09:51:04 +00:00
stats_file: Some("/var/log/vpncloud.stats".to_string()),
2020-09-24 22:45:58 +00:00
statsd: Some(ConfigFileStatsd {
server: Some("example.com:1234".to_string()),
2020-12-20 00:40:32 +00:00
prefix: Some("prefix".to_string()),
}),
2021-01-24 18:24:40 +00:00
hook: None,
2021-04-06 10:28:31 +00:00
hooks: HashMap::new(),
2019-02-19 17:42:50 +00:00
});
2021-04-06 10:28:31 +00:00
assert_eq!(
config,
Config {
device_type: Type::Tun,
device_name: "vpncloud%d".to_string(),
device_path: None,
ip: None,
advertise_addresses: vec![],
2021-04-06 10:28:31 +00:00
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
ifdown: Some("true".to_string()),
listen: "3210".to_string(),
peers: vec!["remote.machine.foo:3210".to_string(), "remote.machine.bar:3210".to_string()],
peer_timeout: 600,
keepalive: Some(840),
switch_timeout: 300,
beacon_store: Some("/run/vpncloud.beacon.out".to_string()),
beacon_load: Some("/run/vpncloud.beacon.in".to_string()),
beacon_interval: 7200,
beacon_password: Some("test123".to_string()),
mode: Mode::Normal,
port_forwarding: true,
claims: vec!["10.0.1.0/24".to_string()],
user: Some("nobody".to_string()),
group: Some("nogroup".to_string()),
pid_file: Some("/run/vpncloud.run".to_string()),
stats_file: Some("/var/log/vpncloud.stats".to_string()),
statsd_server: Some("example.com:1234".to_string()),
statsd_prefix: Some("prefix".to_string()),
..Default::default()
}
);
2019-12-04 08:32:35 +00:00
config.merge_args(Args {
2020-05-29 06:37:29 +00:00
type_: Some(Type::Tap),
device: Some("vpncloud0".to_string()),
device_path: Some("/dev/null".to_string()),
ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()),
ifdown: Some("ifconfig $IFNAME down".to_string()),
2020-09-24 17:48:13 +00:00
password: Some("anothersecret".to_string()),
2021-02-03 21:44:31 +00:00
listen: Some("[::]:3211".to_string()),
2020-05-29 06:37:29 +00:00
peer_timeout: Some(1801),
keepalive: Some(850),
2020-09-24 17:48:13 +00:00
switch_timeout: Some(301),
2020-05-29 06:37:29 +00:00
beacon_store: Some("/run/vpncloud.beacon.out2".to_string()),
beacon_load: Some("/run/vpncloud.beacon.in2".to_string()),
beacon_interval: Some(3600),
2020-09-24 17:48:13 +00:00
beacon_password: Some("test1234".to_string()),
2020-05-29 06:37:29 +00:00
mode: Some(Mode::Switch),
2020-09-24 17:48:13 +00:00
claims: vec![],
peers: vec!["another:3210".to_string()],
2020-05-29 06:37:29 +00:00
no_port_forwarding: true,
daemon: true,
pid_file: Some("/run/vpncloud-mynet.run".to_string()),
stats_file: Some("/var/log/vpncloud-mynet.stats".to_string()),
2020-05-29 09:51:04 +00:00
statsd_server: Some("example.com:2345".to_string()),
2020-05-30 14:12:54 +00:00
statsd_prefix: Some("prefix2".to_string()),
2020-05-29 06:37:29 +00:00
user: Some("root".to_string()),
group: Some("root".to_string()),
2019-02-19 17:42:50 +00:00
..Default::default()
});
2021-04-06 10:28:31 +00:00
assert_eq!(
config,
Config {
device_type: Type::Tap,
device_name: "vpncloud0".to_string(),
device_path: Some("/dev/null".to_string()),
fix_rp_filter: false,
ip: None,
advertise_addresses: vec![],
2021-04-06 10:28:31 +00:00
ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()),
ifdown: Some("ifconfig $IFNAME down".to_string()),
crypto: CryptoConfig { password: Some("anothersecret".to_string()), ..CryptoConfig::default() },
listen: "[::]:3211".to_string(),
peers: vec![
"remote.machine.foo:3210".to_string(),
"remote.machine.bar:3210".to_string(),
"another:3210".to_string()
],
peer_timeout: 1801,
keepalive: Some(850),
switch_timeout: 301,
beacon_store: Some("/run/vpncloud.beacon.out2".to_string()),
beacon_load: Some("/run/vpncloud.beacon.in2".to_string()),
beacon_interval: 3600,
beacon_password: Some("test1234".to_string()),
mode: Mode::Switch,
port_forwarding: false,
claims: vec!["10.0.1.0/24".to_string()],
auto_claim: true,
user: Some("root".to_string()),
group: Some("root".to_string()),
pid_file: Some("/run/vpncloud-mynet.run".to_string()),
stats_file: Some("/var/log/vpncloud-mynet.stats".to_string()),
statsd_server: Some("example.com:2345".to_string()),
statsd_prefix: Some("prefix2".to_string()),
daemonize: true,
hook: None,
hooks: HashMap::new()
}
);
2019-02-19 17:42:50 +00:00
}