Skip to content

Commit

Permalink
Merge pull request #72 from jamesmcm/configfile
Browse files Browse the repository at this point in the history
Add vopono config file support
  • Loading branch information
jamesmcm authored Apr 4, 2021
2 parents c4869bf + 558733b commit bb13a12
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 5 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "vopono"
description = "Launch applications via VPN tunnels using temporary network namespaces"
version = "0.6.9"
version = "0.6.10"
authors = ["James McMurray <jamesmcm03@gmail.com>"]
edition = "2018"
license = "GPL-3.0-or-later"
Expand All @@ -23,7 +23,7 @@ users = "0.11"
nix = "0.20"
serde = {version = "1", features = ["derive", "std"]}
csv = "1"
dialoguer ="0.7"
dialoguer ="0.8"
regex = "1"
ron = "0.6"
walkdir = "2"
Expand All @@ -44,6 +44,7 @@ maplit = "1"
webbrowser = "0.5"
basic_tcp_proxy = "0.3"
signal-hook = "0.3"
config = "0.11"

[package.metadata.rpm]
package = "vopono"
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ connections - if your VPN provider allows it). Commands launched with
the same server prefix and VPN provider will share the same network
namespace.

Default configuration options can be saved in the `~/.config/vopono/config.toml`
file, for example:

```toml
firewall = "NfTables"
provider = "Mullvad"
protocol = "Wireguard"
server = "usa-us22"
```

Note that the values are case-sensitive.

See the [vopono User Guide](USERGUIDE.md) for much more detailed usage instructions
(including handling daemons and servers).

Expand Down
20 changes: 20 additions & 0 deletions USERGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,26 @@ Note that child processes of the application will also be spawned inside
the network namespace and so use the same VPN connection, so you can run
entire shell sessions inside vopono.

### Configuration file

You can save default configuration options in the config file
`~/.config/vopono/config.toml` (or in the respective `$XDG_CONFIG/vopono/`
directory).

Here is an example:

```toml
firewall = "NfTables"
provider = "Mullvad"
protocol = "Wireguard"
server = "usa-us22"
# custom_config = "/home/user/vpn/mycustomconfig.ovpn"
```

Note that the values are case-sensitive. If you use a custom config file
then you should not set the provider or server (setting the protocol is
also optional).

### Wireguard

Install vopono and use `vopono sync` to
Expand Down
74 changes: 71 additions & 3 deletions src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use super::providers::VpnProvider;
use super::shadowsocks::uses_shadowsocks;
use super::sync::synch;
use super::sysctl::SysCtl;
use super::util::vopono_dir;
use super::util::{get_config_file_protocol, get_config_from_alias};
use super::util::{get_existing_namespaces, get_target_subnet};
use super::vpn::{verify_auth, Protocol};
Expand All @@ -25,12 +26,43 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> {
let server_name: String;
let protocol: Protocol;

// Create empty config file if does not exist
let config_path = vopono_dir()?.join("config.toml");
{
std::fs::OpenOptions::new()
.write(true)
.create(true)
.read(true)
.open(&config_path)?;
}
let mut vopono_config_settings = config::Config::default();
vopono_config_settings.merge(config::File::from(config_path))?;

// Assign firewall from args or vopono config file
let firewall: Firewall = command
.firewall
.ok_or_else(|| anyhow!(""))
.or_else(|_| {
vopono_config_settings.get("firewall").map_err(|e| {
debug!("vopono config.toml: {:?}", e);
anyhow!("Failed to read config file")
})
})
.or_else(|_x| crate::util::get_firewall())?;

if let Some(path) = &command.custom_config {
// Assign custom_config from args or vopono config file
let custom_config = command.custom_config.clone().or_else(|| {
vopono_config_settings
.get("custom_config")
.map_err(|e| {
debug!("vopono config.toml: {:?}", e);
anyhow!("Failed to read config file")
})
.ok()
});

// Assign protocol and server from args or vopono config file or custom config if used
if let Some(path) = &custom_config {
protocol = command
.protocol
.unwrap_or_else(|| get_config_file_protocol(path));
Expand All @@ -50,17 +82,53 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> {
} else {
// Get server and provider
// TODO: Handle default case and remove expect()
provider = command.vpn_provider.expect("Enter a VPN provider");
provider = command
.vpn_provider
.or_else(|| {
vopono_config_settings
.get("provider")
.map_err(|e| {
debug!("vopono config.toml: {:?}", e);
anyhow!("Failed to read config file")
})
.ok()
})
.expect(
"Enter a VPN provider as a command-line argument or in the vopono config.toml file",
);
if provider == VpnProvider::Custom {
bail!("Must provide config file if using custom VPN Provider");
}
server_name = command.server.expect("Enter a VPN server prefix");
server_name = command
.server
.or_else(|| {
vopono_config_settings
.get("server")
.map_err(|e| {
debug!("vopono config.toml: {:?}", e);
anyhow!("Failed to read config file")
})
.ok()
})
.expect(
"Enter a VPN server prefix as a command-line argument or in the vopono config.toml file",
);

// Check protocol is valid for provider
protocol = command
.protocol
.or_else(|| {
vopono_config_settings
.get("protocol")
.map_err(|e| {
debug!("vopono config.toml: {:?}", e);
anyhow!("Failed to read config file")
})
.ok()
})
.unwrap_or_else(|| provider.get_dyn_provider().default_protocol());
}
// TODO: PostUp and PreDown scripts

if provider != VpnProvider::Custom {
// Check config files exist for provider
Expand Down
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::upper_case_acronyms)]

mod application_wrapper;
mod args;
mod dns_config;
Expand Down

0 comments on commit bb13a12

Please sign in to comment.