Skip to content

Commit

Permalink
iVPN Wireguard working, confirmed OpenVPN port forwarding
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesmcm committed Nov 7, 2020
1 parent d550100 commit 9859737
Show file tree
Hide file tree
Showing 15 changed files with 293 additions and 74 deletions.
2 changes: 1 addition & 1 deletion 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.5.2"
version = "0.5.3"
authors = ["James McMurray <[email protected]>"]
edition = "2018"
license = "GPL-3.0-or-later"
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ as normal.

vopono includes built-in killswitches for both Wireguard and OpenVPN.

Currently Mullvad, AzireVPN, MozillaVPN, TigerVPN, ProtonVPN and
Currently Mullvad, AzireVPN, MozillaVPN, TigerVPN, ProtonVPN, iVPN and
PrivateInternetAccess are supported directly, with custom configuration files
also supported with the `--custom` argument.

Expand All @@ -18,16 +18,13 @@ lynx all running through different VPN connections:

![Screenshot](screenshot.png)

### asciinema example

[![asciicast](https://asciinema.org/a/369367.png)](https://asciinema.org/a/369367)

## Supported Providers

| Provider | OpenVPN support | Wireguard support |
|-----------------------|-----------------|-------------------|
| Mullvad |||
| AzireVPN |||
| iVPN |||
| PrivateInternetAccess |||
| TigerVPN |||
| ProtonVPN |||
Expand Down Expand Up @@ -137,11 +134,15 @@ $ rustc --version

## Known issues

* When launching a new application in an existing vopono namespace, any
modifications to the firewall rules (i.e. forwarding and opening
ports) will not be applied.
* Connections to the host's PulseAudio and D-bus servers will likely
fail since the connection from the network namespace will not appear as a localhost
connection. See [issue #38](https://github.com/jamesmcm/vopono/issues/38) for work on solving this.
* OpenVPN credentials are always stored in plaintext in configuration - may add
option to not store credentials, but it seems OpenVPN needs them
provided in plaintext.
* ProtonVPN DNS servers do not reliably connect, so Google's DNS is used
for now (you can override this with the `--dns` argument.
* 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.

Expand Down
36 changes: 34 additions & 2 deletions USERGUIDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# vopono User Guide

## asciinema example

[![asciicast](https://asciinema.org/a/369367.png)](https://asciinema.org/a/369367)

## Usage

Applications will be run as the current user by default (you can use
Expand Down Expand Up @@ -259,8 +263,36 @@ for the same (note the instructions on disabling WebRTC). I noticed that
when using IPv6 with OpenVPN it incorrectly states you are not connected
via AzireVPN though (Wireguard works correctly).

Mullvad port forwarding works for both Wireguard and OpenVPN. You will
need to enable the ports in your [Mullvad account](https://mullvad.net/en/account/#/ports).

### VPN Provider limitations

#### 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 Wireguard keypairs must be uploaded manually, as the Client Area is
behind a captcha login.

### 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
Wireguard/OpenVPN tunnel (this can be important for BitTorrent
connectivity, etc.).

Mullvad tunnel port forwarding works for both Wireguard and OpenVPN. You will
need to enable the ports in your [Mullvad account](https://mullvad.net/en/account/#/ports).
Remember to open the port with the `-o PORTNUMBER` argument to
`vopono exec` if you have the killswitch enabled!

For iVPN port forwarding also works the same way, however it is __only
supported for OpenVPN__ on iVPN's side. So remember to pass
`--protocol openvpn -o PORTNUMBER` when trying it! Enable port
forwarding in the [Port Forwarding page in the iVPN client area](https://www.ivpn.net/clientarea/vpn/273887).

## Dependencies

Expand Down
9 changes: 7 additions & 2 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ pub struct ExecCommand {
#[structopt(long = "keep-alive", short = "k")]
pub keep_alive: bool,

/// List of ports to forward from network namespace - usefuel for running servers and daemons
/// List of ports to open on network namespace (to allow port forwarding through the tunnel,
/// e.g. for BitTorrent, etc.)
#[structopt(long = "open-ports", short = "o")]
pub open_ports: Option<Vec<u16>>,

/// List of ports to forward from network namespace to host - useful for running servers and daemons
#[structopt(long = "forward", short = "f")]
pub forward_ports: Option<Vec<u16>>,

Expand All @@ -115,7 +120,7 @@ pub struct ExecCommand {

#[derive(StructOpt)]
pub struct ListCommand {
/// VPN Provider (if not given will use default)
/// VPN Provider
#[structopt(possible_values = &["namespaces", "applications"])]
pub list_type: Option<String>,
}
Expand Down
3 changes: 3 additions & 0 deletions src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> {
auth_file,
&dns,
!command.no_killswitch,
command.open_ports.as_ref(),
command.forward_ports.as_ref(),
firewall,
command.disable_ipv6,
Expand Down Expand Up @@ -209,6 +210,7 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> {
ns.run_wireguard(
config_file.expect("No config file provided"),
!command.no_killswitch,
command.open_ports.as_ref(),
command.forward_ports.as_ref(),
firewall,
command.disable_ipv6,
Expand All @@ -221,6 +223,7 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> {
ns.dns_config(&dns)?;
ns.run_openconnect(
config_file,
command.open_ports.as_ref(),
command.forward_ports.as_ref(),
firewall,
&server_name,
Expand Down
6 changes: 6 additions & 0 deletions src/netns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ impl NetworkNamespace {
auth_file: Option<PathBuf>,
dns: &[IpAddr],
use_killswitch: bool,
open_ports: Option<&Vec<u16>>,
forward_ports: Option<&Vec<u16>>,
firewall: Firewall,
disable_ipv6: bool,
Expand All @@ -217,6 +218,7 @@ impl NetworkNamespace {
auth_file,
dns,
use_killswitch,
open_ports,
forward_ports,
firewall,
disable_ipv6,
Expand All @@ -227,13 +229,15 @@ impl NetworkNamespace {
pub fn run_openconnect(
&mut self,
config_file: Option<PathBuf>,
open_ports: Option<&Vec<u16>>,
forward_ports: Option<&Vec<u16>>,
firewall: Firewall,
server: &str,
) -> anyhow::Result<()> {
self.openconnect = Some(OpenConnect::run(
&self,
config_file,
open_ports,
forward_ports,
firewall,
server,
Expand Down Expand Up @@ -264,6 +268,7 @@ impl NetworkNamespace {
&mut self,
config_file: PathBuf,
use_killswitch: bool,
open_ports: Option<&Vec<u16>>,
forward_ports: Option<&Vec<u16>>,
firewall: Firewall,
disable_ipv6: bool,
Expand All @@ -272,6 +277,7 @@ impl NetworkNamespace {
self,
config_file,
use_killswitch,
open_ports,
forward_ports,
firewall,
disable_ipv6,
Expand Down
6 changes: 6 additions & 0 deletions src/openconnect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ impl OpenConnect {
pub fn run(
netns: &NetworkNamespace,
config_file: Option<PathBuf>,
open_ports: Option<&Vec<u16>>,
forward_ports: Option<&Vec<u16>>,
firewall: Firewall,
server: &str,
Expand Down Expand Up @@ -49,6 +50,11 @@ impl OpenConnect {
.context("Failed to launch OpenConnect - is openconnect installed?")?;
let id = handle.id();

// Allow input to and output from open ports (for port forwarding in tunnel)
if let Some(opens) = open_ports {
super::util::open_ports(&netns, opens.as_slice(), firewall)?;
}

// Allow input to and output from forwarded ports
if let Some(forwards) = forward_ports {
super::util::open_ports(&netns, forwards.as_slice(), firewall)?;
Expand Down
12 changes: 8 additions & 4 deletions src/openvpn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ impl OpenVpn {
auth_file: Option<PathBuf>,
dns: &[IpAddr],
use_killswitch: bool,
open_ports: Option<&Vec<u16>>,
forward_ports: Option<&Vec<u16>>,
firewall: Firewall,
disable_ipv6: bool,
Expand Down Expand Up @@ -78,9 +79,7 @@ impl OpenVpn {
let mut logfile = BufReader::with_capacity(64, File::open(log_file_str)?);
let mut pos: usize = 0;

// TODO: Override DNS with DNS response if present
// PUSH: Received control message: \'PUSH_REPLY,redirect-gateway def1,explicit-exit-notify 3,comp-lzo no,route-gateway 10.73.40.1,topology subnet,ping 10,ping-restart 60,dhcp-option DNS 10.73.40.1

// Parse DNS header from OpenVPN response
let dns_regex = Regex::new(r"dhcp-option DNS ([0-9.]+)").unwrap();
let mut openvpn_dns: Option<IpAddr> = None;
// Tail OpenVPN log file
Expand Down Expand Up @@ -133,7 +132,12 @@ impl OpenVpn {
return Err(anyhow!("OpenVPN options error, use -v for full log output"));
}

// Allow input to and output from forwarded ports
// Allow input to and output from open ports (for port forwarding in tunnel)
if let Some(opens) = open_ports {
super::util::open_ports(&netns, opens.as_slice(), firewall)?;
}

// Allow input to and output from forwarded ports (will be proxied to host)
if let Some(forwards) = forward_ports {
super::util::open_ports(&netns, forwards.as_slice(), firewall)?;
}
Expand Down
10 changes: 5 additions & 5 deletions src/providers/ivpn/ivpn_wg_hosts.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
country,hostname,ip,key
country,hostname,ip,pubkey
at-vienna,at1.wg.ivpn.net,185.244.212.69,83LUBnP97SFpnS0y1MpEAFcg8MIiQJgW1FRv/8Mc40g=
au-sydney,au-nsw1.wg.ivpn.net,46.102.153.246,KmSrG48t5xw9CJCPlYLBG3JnmiY0CnUgyRM5TUEwZhM=
be-brussels,be1.wg.ivpn.net,194.187.251.13,awriP5lpdxEMWKuG+A1DOg+vb1M5jd3WhynIMB61BhU=
Expand All @@ -20,10 +20,10 @@ dk-copenhagen,dk1.wg.ivpn.net,185.245.84.229,jTsV5gOD7lT4egDj9rhKwO2OO2X7bKs2EQP
es-madrid,es1.wg.ivpn.net,84.17.62.98,w7umiArTtlJ4Pk6Ii9WX5VXK5vw/Qu+Z37/icKlIYWo=
fi-helsinki,fi1.wg.ivpn.net,194.34.134.63,mIxEzfjZ2wV6jJVj30w38ECd2LSH4bw/HLMnM2ICHiI=
fr-paris,fr1.wg.ivpn.net,185.93.2.132,g7BuMzj3r/noLiLR4qhQMcvU6GSIY8RGEnaYtdYsFX4=
gb-london,gb1.wg.ivpn.net,81.92.202.114,7+jos+Eg+hMEOQE4Std6OJ+WVnCcmbqS1/EbPwn9w3s=
gb-london,gb2.wg.ivpn.net,185.59.221.225,x0BTRaxsdxAd58ZyU2YMX4bmuj+Eg+8/urT2F3Vs1n8=
gb-london,gb1.wg.ivpn.net,185.59.221.140,yKK5x+D17Jr3Q12T/UBaDjNVmNdZBsqpvTqH6YfsGHg=
gb-manchester,gb-man1.wg.ivpn.net,89.238.141.231,+hf4DYilNEIjTdSOuCNcWdqVyaRoxGzXw7wvNl7f7Rg=
uk-london,gb1.wg.ivpn.net,81.92.202.114,7+jos+Eg+hMEOQE4Std6OJ+WVnCcmbqS1/EbPwn9w3s=
uk-london,gb2.wg.ivpn.net,185.59.221.225,x0BTRaxsdxAd58ZyU2YMX4bmuj+Eg+8/urT2F3Vs1n8=
uk-london,gb1.wg.ivpn.net,185.59.221.140,yKK5x+D17Jr3Q12T/UBaDjNVmNdZBsqpvTqH6YfsGHg=
uk-manchester,gb-man1.wg.ivpn.net,89.238.141.231,+hf4DYilNEIjTdSOuCNcWdqVyaRoxGzXw7wvNl7f7Rg=
hk-hongkong,hk1.wg.ivpn.net,209.58.189.105,MbqqGy6TI2WVxHYdMa7X1LJoIEQNElhYXMGlMqtwtS0=
hu-budapest,hu1.wg.ivpn.net,185.189.114.189,G30fNdXrnlqtqqOLF23QXWzFdLIKDxLW60HoYPvqml8=
il-telaviv,il1.wg.ivpn.net,185.191.207.197,HR9gAjpxXU3YVt6kehBw5n8yVYVE0iIgJdc4HTqOzEE=
Expand Down
6 changes: 4 additions & 2 deletions src/providers/ivpn/scrape_wireguard.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
country = b.contents[4].strip()
country = country.replace(",", "-").replace(" ", "")
country = country.lower()
# Fix GB -> UK country code
country = country.replace("gb-", "uk-")
b = b.find_next("div", {"class": "col-xs-6 col-md-3"})
hostname = b.contents[2].strip()
b = b.find_next("div", {"class": "col-xs-6 col-md-2"})
Expand All @@ -26,13 +28,13 @@
key = b.text.strip()
print(f"{country}|{hostname}|{ip}|{key}")
hosts.append(
{"country": country, "hostname": hostname, "ip": ip, "key": key}
{"country": country, "hostname": hostname, "ip": ip, "pubkey": key}
)
else:
break

with open("ivpn_wg_hosts.csv", "w") as csvfile:
fieldnames = ["country", "hostname", "ip", "key"]
fieldnames = ["country", "hostname", "ip", "pubkey"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for host in hosts:
Expand Down
Loading

0 comments on commit 9859737

Please sign in to comment.