Skip to content

Commit

Permalink
Merge pull request #168 from jamesmcm/libcode
Browse files Browse the repository at this point in the history
First pass at separating library code from CLI
  • Loading branch information
jamesmcm authored Jul 2, 2022
2 parents d38b68c + 90cd5d4 commit b20fa67
Show file tree
Hide file tree
Showing 61 changed files with 233 additions and 198 deletions.
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Clone the repo and build with `cargo build`.

Note the minimum supported Rust version is 1.43.
Note the minimum supported Rust version is 1.56.

### Clippy

Expand All @@ -19,7 +19,7 @@ $ cargo clippy --all-features --all-targets
## Adding a new VPN provider

Adding support for a new VPN provider is as simple as adding the
relevant files to `src/providers/` defining Structs which implement the
relevant files to `vopono_core/config/src/providers/` defining Structs which implement the
base `Provider` trait and at least one of the `OpenVpnProvider` or
`WireguardProvider` traits.

Expand All @@ -37,7 +37,7 @@ provide an enum of choices to the user (i.e. selecting between different
configurations- TCP vs. UDP, etc.).

The new provider must also be added to the `VpnProvider` enum in
`src/providers/mod.rs` to be able to convert from the StructOpt provider
`vopono_core/src/config/providers/mod.rs` to be able to convert from the StructOpt provider
argument to the structs implementing the traits above.

Note that for OpenVPN it is also necessary to create any additional
Expand Down
39 changes: 11 additions & 28 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,51 +1,34 @@
[package]
name = "vopono"
description = "Launch applications via VPN tunnels using temporary network namespaces"
version = "0.9.2"
version = "0.10.0"
authors = ["James McMurray <jamesmcm03@gmail.com>"]
edition = "2021"
license = "GPL-3.0-or-later"
repository = "https://github.com/jamesmcm/vopono"
homepage = "https://github.com/jamesmcm/vopono"
readme = "README.md"
keywords = ["vopono", "vpn", "wireguard", "openvpn", "netns"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[workspace]

[dependencies]
vopono_core = { path = "vopono_core" }
anyhow = "1"
directories-next = "2"
log = "0.4"
pretty_env_logger = "0.4"
clap = {version = "3", features = ["derive"]}
clap = { version = "3", features = ["derive"] }
which = "4"
users = "0.11"
nix = "0.24"
serde = {version = "1", features = ["derive", "std"]}
csv = "1"
dialoguer ="0.10"
regex = "1"
ron = "0.7"
walkdir = "2"
# Must use rand 0.7 for compatibility with x25519-dalek for now
rand = "0.7"
toml = "0.5"
chrono = "0.4"
dialoguer = "0.10"
compound_duration = "1"
ipnet = {version = "2", features = ["serde"]}
reqwest = {default-features = false, version = "0.11", features = ["blocking", "json", "rustls-tls"]}
sysinfo = "0.24"
base64 = "0.13"
x25519-dalek = "1"
strum = "0.24"
strum_macros = "0.24"
zip = "0.6"
maplit = "1"
webbrowser = "0.7"
basic_tcp_proxy = "0.3"
signal-hook = "0.3"
config = "0.13"
serde_json = "1"
walkdir = "2"
chrono = "0.4"
bs58 = "0.4"
nix = "0.24"
config = "0.13"
basic_tcp_proxy = "0.3"

[package.metadata.rpm]
package = "vopono"
Expand Down
7 changes: 6 additions & 1 deletion USERGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,12 @@ Network settings > Settings, then deselect `Enable DNS over HTTPS`.
You may also wish to disable WebRTC - see
[Mullvad's guide](https://mullvad.net/en/help/webrtc/) for more details.

Similar issues apply to Chromium and Google Chrome.
Similar issues apply to Chromium and Google Chrome, where you must provide a
different `user-data-dir` in order to force it to use a separate process:

```bash
$ chromium --user-data-dir=/tmp/profile-2
```

### Daemons and servers

Expand Down
8 changes: 4 additions & 4 deletions src/args.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use super::firewall::Firewall;
use super::network_interface::NetworkInterface;
use super::providers::VpnProvider;
use super::vpn::Protocol;
use clap::Parser;
use std::net::IpAddr;
use std::path::PathBuf;
use vopono_core::config::providers::VpnProvider;
use vopono_core::config::vpn::Protocol;
use vopono_core::network::firewall::Firewall;
use vopono_core::network::network_interface::NetworkInterface;

#[derive(Parser)]
#[clap(
Expand Down
26 changes: 13 additions & 13 deletions src/exec.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
use super::application_wrapper::ApplicationWrapper;
use super::args::ExecCommand;
use super::firewall::Firewall;
use super::netns::NetworkNamespace;
use super::network_interface::{get_active_interfaces, NetworkInterface};
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};
use anyhow::{anyhow, bail};
use log::{debug, error, info, warn};
use signal_hook::{consts::SIGINT, iterator::Signals};
Expand All @@ -20,6 +9,17 @@ use std::{
fs::create_dir_all,
io::{self, Write},
};
use vopono_core::config::providers::VpnProvider;
use vopono_core::config::vpn::{verify_auth, Protocol};
use vopono_core::network::application_wrapper::ApplicationWrapper;
use vopono_core::network::firewall::Firewall;
use vopono_core::network::netns::NetworkNamespace;
use vopono_core::network::network_interface::{get_active_interfaces, NetworkInterface};
use vopono_core::network::shadowsocks::uses_shadowsocks;
use vopono_core::network::sysctl::SysCtl;
use vopono_core::util::vopono_dir;
use vopono_core::util::{get_config_file_protocol, get_config_from_alias};
use vopono_core::util::{get_existing_namespaces, get_target_subnet};

pub fn exec(command: ExecCommand) -> anyhow::Result<()> {
// this captures all sigint signals
Expand Down Expand Up @@ -59,7 +59,7 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> {
anyhow!("Failed to read config file")
})
})
.or_else(|_x| crate::util::get_firewall())?;
.or_else(|_x| vopono_core::util::get_firewall())?;

// Assign custom_config from args or vopono config file
let custom_config = command.custom_config.clone().or_else(|| {
Expand Down Expand Up @@ -474,7 +474,7 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> {
io::stdout().write_all(output.stdout.as_slice())?;

// Allow daemons to leave namespace open
if crate::util::check_process_running(pid) {
if vopono_core::util::check_process_running(pid) {
info!(
"Process {} still running, assumed to be daemon - will leave network namespace alive until ctrl+C received",
pid
Expand Down
31 changes: 1 addition & 30 deletions src/list.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
use super::args::ListCommand;
use super::netns::Lockfile;
use super::util::config_dir;
use chrono::prelude::*;
use std::collections::HashMap;
use std::fs::File;
use walkdir::WalkDir;

// TODO: Implement read-only namespace struct without Drop?
use vopono_core::util::get_lock_namespaces;

pub fn output_list(listcmd: ListCommand) -> anyhow::Result<()> {
match listcmd.list_type.as_deref() {
Expand Down Expand Up @@ -47,7 +41,6 @@ pub fn print_applications() -> anyhow::Result<()> {
Ok(())
}

// TODO: DRY
pub fn print_namespaces() -> anyhow::Result<()> {
let namespaces = get_lock_namespaces()?;

Expand Down Expand Up @@ -84,25 +77,3 @@ pub fn print_namespaces() -> anyhow::Result<()> {
std::mem::forget(namespaces);
Ok(())
}

pub fn get_lock_namespaces() -> anyhow::Result<HashMap<String, Vec<Lockfile>>> {
let mut dir = config_dir()?;
dir.push("vopono");
dir.push("locks");

let mut namespaces: HashMap<String, Vec<Lockfile>> = HashMap::new();
WalkDir::new(dir)
.into_iter()
.filter(|x| x.is_ok() && x.as_ref().unwrap().path().is_file())
.map(|x| x.unwrap())
.try_for_each(|x| -> anyhow::Result<()> {
let lockfile = File::open(x.path())?;
let lock: Lockfile = ron::de::from_reader(lockfile)?;
namespaces
.entry(lock.ns.name.clone())
.or_insert_with(Vec::new)
.push(lock);
Ok(())
})?;
Ok(namespaces)
}
6 changes: 3 additions & 3 deletions src/list_configs.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use super::args::ServersCommand;
use crate::providers::VpnProvider;
use crate::util::get_configs_from_alias;
use crate::vpn::Protocol;
use anyhow::bail;
use vopono_core::config::providers::VpnProvider;
use vopono_core::config::vpn::Protocol;
use vopono_core::util::get_configs_from_alias;

pub fn print_configs(cmd: ServersCommand) -> anyhow::Result<()> {
let provider = cmd.vpn_provider;
Expand Down
29 changes: 4 additions & 25 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,22 @@
#![allow(clippy::large_enum_variant)]
#![allow(dead_code)]

mod application_wrapper;
mod args;
mod dns_config;
mod exec;
mod firewall;
mod host_masquerade;
mod list;
mod list_configs;
mod netns;
mod network_interface;
mod openconnect;
mod openfortivpn;
mod openvpn;
mod providers;
mod pulseaudio;
mod shadowsocks;
mod sync;
mod sysctl;
mod util;
mod veth_pair;
mod vpn;
mod wireguard;

use clap::Parser;
use list::output_list;
use list_configs::print_configs;
use log::{debug, warn, LevelFilter};
use netns::NetworkNamespace;
use sync::{sync_menu, synch};
use util::clean_dead_locks;
use util::clean_dead_namespaces;
use util::elevate_privileges;
use vopono_core::util::clean_dead_locks;
use vopono_core::util::clean_dead_namespaces;
use vopono_core::util::elevate_privileges;
use which::which;

// TODO:
// - Allow for not saving OpenVPN creds to config

fn main() -> anyhow::Result<()> {
// Get struct of args using structopt
let app = args::App::parse();
Expand All @@ -57,7 +36,7 @@ fn main() -> anyhow::Result<()> {
args::Command::Exec(cmd) => {
clean_dead_locks()?;
if which("pactl").is_ok() {
let pa = pulseaudio::get_pulseaudio_server();
let pa = vopono_core::util::pulseaudio::get_pulseaudio_server();
if let Ok(pa) = pa {
std::env::set_var("PULSE_SERVER", pa);
} else {
Expand Down
6 changes: 3 additions & 3 deletions src/sync.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use super::providers::VpnProvider;
use super::util::set_config_permissions;
use super::vpn::Protocol;
use anyhow::bail;
use clap::ArgEnum;
use dialoguer::MultiSelect;
use log::{error, info};
use vopono_core::config::providers::VpnProvider;
use vopono_core::config::vpn::Protocol;
use vopono_core::util::set_config_permissions;

pub fn sync_menu() -> anyhow::Result<()> {
let variants = VpnProvider::value_variants()
Expand Down
45 changes: 45 additions & 0 deletions vopono_core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[package]
name = "vopono_core"
description = "Library code for running VPN connections in network namespaces"
version = "0.1.0"
edition = "2021"
authors = ["James McMurray <jamesmcm03@gmail.com>"]
license = "GPL-3.0-or-later"
repository = "https://github.com/jamesmcm/vopono"
homepage = "https://github.com/jamesmcm/vopono"
readme = "README.md"
keywords = ["vopono", "vpn", "wireguard", "openvpn", "netns"]

[dependencies]
anyhow = "1"
directories-next = "2"
log = "0.4"
which = "4"
users = "0.11"
nix = "0.24"
serde = { version = "1", features = ["derive", "std"] }
csv = "1"
dialoguer = "0.10" # TODO: Remove me
clap = { version = "3", features = ["derive"] } # TODO: Remove me
regex = "1"
ron = "0.7"
walkdir = "2"
# Must use rand 0.7 for compatibility with x25519-dalek for now
rand = "0.7"
toml = "0.5"
ipnet = { version = "2", features = ["serde"] }
reqwest = { default-features = false, version = "0.11", features = [
"blocking",
"json",
"rustls-tls",
] } # TODO: Can we remove Tokio dependency?
sysinfo = "0.24"
base64 = "0.13"
x25519-dalek = "1"
strum = "0.24"
strum_macros = "0.24"
zip = "0.6"
maplit = "1"
webbrowser = "0.7"
serde_json = "1"
signal-hook = "0.3"
10 changes: 10 additions & 0 deletions vopono_core/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# vopono_core

This crate contains the library code used in [vopono](https://github.com/jamesmcm/vopono).

The separation of library code is still in development and the public
API is not stable.

VPN provider specific code is in `src/config/providers/`


2 changes: 2 additions & 0 deletions vopono_core/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod providers;
pub mod vpn;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod openvpn;

use super::{ConfigurationChoice, OpenVpnProvider, Provider};
use crate::vpn::Protocol;
use crate::config::vpn::Protocol;

pub struct AirVPN {}

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ mod openvpn;
mod wireguard;

use super::{ConfigurationChoice, OpenVpnProvider, Provider, WireguardProvider};
use crate::vpn::Protocol;
use crate::wireguard::{de_socketaddr, de_vec_ipaddr, de_vec_ipnet};
use crate::config::vpn::Protocol;
use crate::network::wireguard::{de_socketaddr, de_vec_ipaddr, de_vec_ipnet};
use dialoguer::{Input, Password};
use ipnet::IpNet;
use serde::Deserialize;
Expand All @@ -30,6 +30,7 @@ impl Provider for AzireVPN {
}
}

#[allow(dead_code)]
#[derive(Deserialize, Debug, Clone)]
struct ConnectResponse {
status: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::AzireVPN;
use super::{ConfigurationChoice, OpenVpnProvider};
use crate::config::vpn::OpenVpnProtocol;
use crate::util::delete_all_files_in_dir;
use crate::vpn::OpenVpnProtocol;
use log::{debug, info};
use std::fs::create_dir_all;
use std::fs::File;
Expand Down
Loading

0 comments on commit b20fa67

Please sign in to comment.