Skip to content

Commit

Permalink
rustfmt and update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesmcm committed Jan 20, 2024
1 parent 9820ef8 commit 8d103bc
Show file tree
Hide file tree
Showing 12 changed files with 193 additions and 135 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ lynx all running through different VPN connections:
| AirVPN |||
| Cloudflare Warp\*\*\*\* |||

\* Port forwarding is not currently supported for PrivateInternetAccess. PRs welcome.
\* Port forwarding supported with the `--port-forwarding` option and `--port-forwarding-callback` to run a command when the port is refreshed.

\*\* See the [User Guide](USERGUIDE.md) for authentication instructions for generating the OpenVPN config files via `vopono sync`. You must copy the authentication header of the form `AUTH-xxx=yyy` where `yyy` is the value of the `x-pm-uid` header in the same request when logged in, in your web browser.

\*\*\* For ProtonVPN you can generate and download specific Wireguard config
files, and use them as a custom provider config. See the [User Guide](USERGUIDE.md)
for details. [Port Forwarding](https://protonvpn.com/support/port-forwarding-manual-setup/) is supported with the `--protonvpn-port-forwarding` argument for both OpenVPN and Wireguard (with `--provider custom --custom xxx.conf --protocol wireguard` ). `natpmpc` must be installed. Note for OpenVPN you must generate the OpenVPN config files appending `+pmp` to your OpenVPN username, and you must choose servers which support this feature (e.g. at the time of writing, the Romania servers do). The assigned port is then printed to the terminal where vopono was launched - this should then be set in any applications that require it.
for details. [Port Forwarding](https://protonvpn.com/support/port-forwarding-manual-setup/) is supported with the `--port-forwarding` argument for both OpenVPN and Wireguard (with `--provider custom --custom xxx.conf --protocol wireguard` ). `natpmpc` must be installed. Note for OpenVPN you must generate the OpenVPN config files appending `+pmp` to your OpenVPN username, and you must choose servers which support this feature (e.g. at the time of writing, the Romania servers do). The assigned port is then printed to the terminal where vopono was launched - this should then be set in any applications that require it.


\*\*\*\* Cloudflare Warp uses its own protocol. Set both the provider and
Expand Down
20 changes: 12 additions & 8 deletions USERGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,12 +488,12 @@ Due to the way Wireguard configuration generation is handled, this should be
generated online and then used as a custom configuration, e.g.:
```bash
$ vopono -v exec --provider custom --custom testwg-UK-17.conf --protocol wireguard --protonvpn-port-forwarding firefox-developer-edition
$ vopono -v exec --provider custom --custom testwg-UK-17.conf --protocol wireguard --port-forwarding firefox-developer-edition
```
#### Port Forwarding
Port forwarding can be enabled with the `--protonvpn-port-forwarding` argument, but requires using a server that supports port forwarding.
Port forwarding can be enabled with the `--port-forwarding` argument, but requires using a server that supports port forwarding.
`natpmpc` must be installed e.g. via the `libnatpmp` package on Arch Linux.
Expand All @@ -508,6 +508,10 @@ The port you are allocated will then be printed to the console like:
And that is the port you would then set up in applications that require it.
### PrivateInternetAccess
Port forwaring supported with the `--port-forwarding` option, use the `--port-forwarding-callback` option to specify a command to run when the port is refreshed.
### Cloudflare Warp
Cloudflare Warp users must first register with Warp via the CLI client:
Expand All @@ -525,31 +529,31 @@ You can then kill `warp-svc` and run it via vopono:
$ vopono -v exec --no-killswitch --provider warp --protocol warp firefox-developer-edition
```
### VPN Provider limitations
## VPN Provider limitations
#### PrivateInternetAccess
### PrivateInternetAccess
Wireguard support for PrivateInternetAccess (PIA) requires the use of a
user token to get the latest servers at time of use. See [issue 9](https://github.com/jamesmcm/vopono/issues/9) for details,
and PIA's [official script for Wireguard access](https://github.com/pia-foss/manual-connections/blob/master/connect_to_wireguard_with_token.sh).
So if you encounter connection issues, first try re-running `vopono sync`.
#### MozillaVPN
### MozillaVPN
There is no easy way to delete MozillaVPN devices (Wireguard keypairs),
unlike Mullvad this _cannot_ be done on the webpage.
I recommend using [MozWire](https://github.com/NilsIrl/MozWire) to manage this.
#### iVPN
### iVPN
iVPN Wireguard keypairs must be uploaded manually, as the Client Area is
behind a captcha login.
#### NordVPN
### NordVPN
Starting 27 June 2023, the required user credentials are no longer your NordVPN login details but need to be generated in the user control panel, under Services → NordVPN. Scroll down and locate the Manual Setup tab, then click on Set up NordVPN manually and follow instructions. Copy your service credentials and re-sync NordVPN configuration inside Vopono.
### Tunnel Port Forwarding
## Tunnel Port Forwarding
Some providers allow port forwarding inside the tunnel, so you can open
some ports inside the network namespace which can be accessed via the
Expand Down
2 changes: 1 addition & 1 deletion src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ pub struct ExecCommand {
/// Enable port forwarding for if supported
#[clap(long = "port-forwarding")]
pub port_forwarding: bool,

/// Path or alias to executable script or binary to be called with the port as an argumnet
/// when the port forwarding is refreshed (PIA only)
#[clap(long = "port-forwarding-callback")]
Expand Down
47 changes: 27 additions & 20 deletions src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ 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::natpmpc::Natpmpc;
use vopono_core::network::piapf::Piapf;
use vopono_core::network::Forwarder;
use vopono_core::network::netns::NetworkNamespace;
use vopono_core::network::network_interface::{get_active_interfaces, NetworkInterface};
use vopono_core::network::piapf::Piapf;
use vopono_core::network::shadowsocks::uses_shadowsocks;
use vopono_core::network::sysctl::SysCtl;
use vopono_core::network::Forwarder;
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};
Expand Down Expand Up @@ -484,7 +484,9 @@ pub fn exec(command: ExecCommand, uiclient: &dyn UiClient) -> anyhow::Result<()>
// TODO: DNS suffixes?
ns.dns_config(&dns, &[], command.hosts_entries.as_ref())?;
ns.run_openconnect(
config_file.clone().expect("No OpenConnect config file provided"),
config_file
.clone()
.expect("No OpenConnect config file provided"),
command.open_ports.as_ref(),
command.forward_ports.as_ref(),
firewall,
Expand All @@ -495,7 +497,9 @@ pub fn exec(command: ExecCommand, uiclient: &dyn UiClient) -> anyhow::Result<()>
Protocol::OpenFortiVpn => {
// TODO: DNS handled by OpenFortiVpn directly?
ns.run_openfortivpn(
config_file.clone().expect("No OpenFortiVPN config file provided"),
config_file
.clone()
.expect("No OpenFortiVPN config file provided"),
command.open_ports.as_ref(),
command.forward_ports.as_ref(),
command.hosts_entries.as_ref(),
Expand Down Expand Up @@ -553,33 +557,36 @@ pub fn exec(command: ExecCommand, uiclient: &dyn UiClient) -> anyhow::Result<()>
let ns = ns.write_lockfile(&command.application)?;

let forwarder: Option<Box<dyn Forwarder>> = if port_forwarding {

let callback = command
.port_forwarding_callback
.or_else(|| {
vopono_config_settings
.get("port_forwarding_callback")
.map_err(|_e| anyhow!("Failed to read config file"))
.ok()
});
let callback = command.port_forwarding_callback.or_else(|| {
vopono_config_settings
.get("port_forwarding_callback")
.map_err(|_e| anyhow!("Failed to read config file"))
.ok()
});
match provider {
VpnProvider::PrivateInternetAccess => {
let conf_path = config_file
.expect("No PIA config file provided");
let conf_path = config_file.expect("No PIA config file provided");
let conf_name = conf_path
.file_name().unwrap()
.to_str().expect("No filename for PIA config file")
.file_name()
.unwrap()
.to_str()
.expect("No filename for PIA config file")
.to_string();
Some(Box::new(Piapf::new(&ns, &conf_name, &protocol, callback.as_ref())?))
},
Some(Box::new(Piapf::new(
&ns,
&conf_name,
&protocol,
callback.as_ref(),
)?))
}
VpnProvider::ProtonVPN => {
vopono_core::util::open_hosts(
&ns,
vec![vopono_core::network::natpmpc::PROTONVPN_GATEWAY],
firewall,
)?;
Some(Box::new(Natpmpc::new(&ns)?))
},
}
_ => {
anyhow::bail!("Port forwarding not supported for the selected provider");
}
Expand Down
7 changes: 3 additions & 4 deletions vopono_core/src/config/providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ use crate::util::vopono_dir;
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
use std::{
net::IpAddr,
path::{Path, PathBuf},
fs::File,
io::{BufReader, BufRead},
io::{BufRead, BufReader},
net::IpAddr,
path::{Path, PathBuf},
};
use strum_macros::{Display, EnumIter};
// TODO: Consider removing this re-export
Expand Down Expand Up @@ -141,7 +141,6 @@ pub trait OpenVpnProvider: Provider {
fn prompt_for_auth(&self, uiclient: &dyn UiClient) -> anyhow::Result<(String, String)>;
fn auth_file_path(&self) -> anyhow::Result<Option<PathBuf>>;


fn load_openvpn_auth(&self) -> anyhow::Result<(String, String)> {
let auth_file = self.auth_file_path()?;
if let Some(auth_file) = auth_file {
Expand Down
50 changes: 25 additions & 25 deletions vopono_core/src/config/providers/pia/openvpn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ use super::PrivateInternetAccess;
use super::{ConfigurationChoice, OpenVpnProvider};
use crate::config::providers::UiClient;
use crate::util::delete_all_files_in_dir;
use log::debug;
use anyhow::Context;
use log::info;
use log::{debug, warn};
use regex::Regex;
use reqwest::Url;
use serde::Deserialize;
use serde::Serialize;
use std::collections::HashMap;
use std::fmt::Display;
use std::fs::create_dir_all;
use std::fs::File;
Expand All @@ -13,37 +19,31 @@ use std::path::PathBuf;
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
use zip::ZipArchive;
use serde::Deserialize;
use serde::Serialize;
use std::collections::HashMap;
use log::info;
use regex::Regex;
use anyhow::Context;

#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
pub hostname_lookup: HashMap<String, String>,
}

impl PrivateInternetAccess {

fn openvpn_config_file_path(&self) -> anyhow::Result<PathBuf> {
Ok(self.openvpn_dir()?.join("config.txt"))
}

//This only works if openvpn was sync'd
pub fn hostname_for_openvpn_conf(&self, config_file: &String) -> anyhow::Result<String> {
pub fn hostname_for_openvpn_conf(&self, config_file: &String) -> anyhow::Result<String> {
let pia_config_file = File::open(self.openvpn_config_file_path()?)?;
let pia_config: Config = serde_json::from_reader(pia_config_file)?;

let hostname = pia_config
.hostname_lookup
.get(config_file)
.with_context(|| format!("Could not find matching hostname for openvpn conf {config_file}"))?;

.with_context(|| {
format!("Could not find matching hostname for openvpn conf {config_file}")
})?;

Ok(hostname.to_string())
}

}

impl OpenVpnProvider for PrivateInternetAccess {
Expand Down Expand Up @@ -72,11 +72,11 @@ impl OpenVpnProvider for PrivateInternetAccess {
let country_map = crate::util::country_map::country_to_code_map();
create_dir_all(&openvpn_dir)?;
delete_all_files_in_dir(&openvpn_dir)?;

let mut config = Config {
hostname_lookup: HashMap::new(),
};

for i in 0..zip.len() {
// For each file, detect if ovpn, crl or crt
// Modify auth line for config
Expand Down Expand Up @@ -111,19 +111,20 @@ impl OpenVpnProvider for PrivateInternetAccess {
} else {
file.name().to_string()
};

let re = Regex::new(r"\n *remote +([^ ]+) +\d+ *\n").expect("Failed to compile hostname regex");

let re = Regex::new(r"\n *remote +([^ ]+) +\d+ *\n")
.expect("Failed to compile hostname regex");
if let Some(capture) = re.captures(&String::from_utf8_lossy(&file_contents)) {
let hostname = capture
.get(1)
.expect("No matching hostname group in openvpn config")
.as_str()
.to_string();

info!("Associating {filename} with hostname {hostname}");
config.hostname_lookup.insert(filename.clone(), hostname);
} else {
info!("Configuration {filename} did not have a parseable hostname - port forwarding will not work!");
warn!("Configuration {filename} did not have a parseable hostname - port forwarding will not work!");
}

debug!("Reading file: {}", file.name());
Expand All @@ -139,17 +140,16 @@ impl OpenVpnProvider for PrivateInternetAccess {
let mut outfile = File::create(auth_file)?;
write!(outfile, "{user}\n{pass}")?;
}

// Write PrivateInternetAccess openvpn config file
let pia_config_file = File::create(self.openvpn_config_file_path()?)?;
serde_json::to_writer(pia_config_file, &config)?;
// Write PIA certificate

// Write PIA certificate
self.write_pia_cert()?;

Ok(())
}

}

#[derive(EnumIter, PartialEq)]
Expand Down
Loading

0 comments on commit 8d103bc

Please sign in to comment.