Skip to content

Commit

Permalink
Merge pull request #101 from jamesmcm/firewalld
Browse files Browse the repository at this point in the history
Improve NetworkManager, firewalld support
  • Loading branch information
jamesmcm authored Aug 13, 2021
2 parents 66bdbf4 + 4d66fb8 commit 4f78e78
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 26 deletions.
10 changes: 8 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.8.3"
version = "0.8.4"
authors = ["James McMurray <jamesmcm03@gmail.com>"]
edition = "2018"
license = "GPL-3.0-or-later"
Expand Down Expand Up @@ -34,7 +34,7 @@ chrono = "0.4"
compound_duration = "1"
ipnet = {version = "2", features = ["serde"]}
reqwest = {default-features = false, version = "0.11", features = ["blocking", "json", "rustls-tls"]}
sysinfo = "0.19"
sysinfo = "0.20"
base64 = "0.13"
x25519-dalek = "1"
strum = "0.21"
Expand All @@ -49,6 +49,12 @@ config = "0.11"
[package.metadata.rpm]
package = "vopono"

[package.metadata.deb]
maintainer = "James McMurray <jamesmcm03@gmail.com>"
recommends = "wireguard-tools, openvpn"
# Not supported in Github Actions image with cargo-deb yet
# suggests = "shadowsocks-libev, openfortivpn"

[package.metadata.rpm.cargo]
buildflags = ["--release"]

Expand Down
10 changes: 5 additions & 5 deletions src/netns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl NetworkNamespace {
// TODO: Handle if name taken?
let source = format!("{}_s", &self.name[7..self.name.len().min(20)]);
let dest = format!("{}_d", &self.name[7..self.name.len().min(20)]);
self.veth_pair = Some(VethPair::new(source, dest, &self)?);
self.veth_pair = Some(VethPair::new(source, dest, self)?);
Ok(())
}

Expand Down Expand Up @@ -230,7 +230,7 @@ impl NetworkNamespace {
disable_ipv6: bool,
) -> anyhow::Result<()> {
self.openvpn = Some(OpenVpn::run(
&self,
self,
config_file,
auth_file,
dns,
Expand All @@ -252,7 +252,7 @@ impl NetworkNamespace {
server: &str,
) -> anyhow::Result<()> {
self.openconnect = Some(OpenConnect::run(
&self,
self,
config_file,
open_ports,
forward_ports,
Expand Down Expand Up @@ -288,7 +288,7 @@ impl NetworkNamespace {
encrypt_method: &str,
) -> anyhow::Result<()> {
self.shadowsocks = Some(Shadowsocks::run(
&self,
self,
config_file,
ss_host,
listen_port,
Expand Down Expand Up @@ -425,7 +425,7 @@ impl Drop for NetworkNamespace {
std::env::set_var("VOPONO_NS", &self.name);
if self.predown_user.is_some() {
std::process::Command::new("sudo")
.args(&["-Eu", self.predown_user.as_ref().unwrap(), &pdcmd])
.args(&["-Eu", self.predown_user.as_ref().unwrap(), pdcmd])
.spawn()
.ok();
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/openconnect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ impl OpenConnect {

// 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)?;
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)?;
super::util::open_ports(netns, forwards.as_slice(), firewall)?;
}

Ok(Self { pid: id })
Expand Down
4 changes: 2 additions & 2 deletions src/openfortivpn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@ impl OpenFortiVpn {
netns.dns_config(dns_ip.as_slice(), suffixes.as_slice())?;
// 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)?;
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)?;
super::util::open_ports(netns, forwards.as_slice(), firewall)?;
}

Ok(Self { pid: id })
Expand Down
4 changes: 2 additions & 2 deletions src/openvpn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,12 @@ impl OpenVpn {

// 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)?;
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)?;
super::util::open_ports(netns, forwards.as_slice(), firewall)?;
}

if use_killswitch {
Expand Down
2 changes: 1 addition & 1 deletion src/providers/ivpn/wireguard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ fn request_port() -> anyhow::Result<u16> {
let port = Input::<u16>::new()
.with_prompt("Enter port number:")
.validate_with(|x: &u16| -> Result<(), &str> {
if [2049,2050,53,30587,41893,48574,58237].contains(&x) {
if [2049,2050,53,30587,41893,48574,58237].contains(x) {
Ok(())
} else {
Err("Port must be one of: 2049,2050,53,30587,41893,48574,58237 (see https://www.ivpn.net/setup/gnu-linux-wireguard.html for ports reference)")
Expand Down
2 changes: 1 addition & 1 deletion src/providers/mozilla/wireguard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl MozillaVPN {
.with_prompt(
"The following devices exist on your account, which would you like to use (you will need the private key)",
)
.items(&devices)
.items(devices)
.item("Create a new device (keypair)")
.default(0)
.interact()?;
Expand Down
2 changes: 1 addition & 1 deletion src/providers/mullvad/wireguard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ fn prompt_for_wg_key(
return Err(anyhow!("Cannot add more Wireguard keypairs to this account. Try to delete existing keypairs."));
}
let keypair = generate_keypair()?;
Mullvad::upload_wg_key(&client, auth_token, &keypair)?;
Mullvad::upload_wg_key(client, auth_token, &keypair)?;
Ok(keypair)
} else {
let private_key = Input::<String>::new()
Expand Down
2 changes: 1 addition & 1 deletion src/providers/nordvpn/openvpn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl OpenVpnProvider for NordVPN {
let server_name = fname.to_lowercase().replace(' ', "_");
let server_name = server_name.split('.').next().unwrap();

if let Some(cap) = server_regex.captures(&server_name) {
if let Some(cap) = server_regex.captures(server_name) {
// check whether the server is a special config type
// or not, and discard ones not in line with user's
// selection
Expand Down
61 changes: 56 additions & 5 deletions src/veth_pair.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::util::sudo_command;
use super::NetworkNamespace;
use anyhow::Context;
use log::debug;
use log::{debug, warn};
use serde::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::Write;
Expand All @@ -26,11 +26,29 @@ impl VethPair {
assert!(source.len() <= 15, "ifname must be <= 15 chars: {}", source);
assert!(dest.len() <= 15, "ifname must be <= 15 chars: {}", dest);

// NetworkManager device management
// If NetworkManager used, add destination veth to unmanaged devices
// Avoids NM overriding our IP assignment
// TODO: Check with systemd?
// TODO: Check with systemd instead of nmcli directly?
let nm_path = PathBuf::from_str("/etc/NetworkManager")?;
let nm_unmanaged = if nm_path.exists() && which::which("nmcli").is_ok() {
let nm_running = if which::which("nmcli").is_ok() {
std::process::Command::new("nmcli")
.arg("general")
.arg("status")
.status()
.map(|x| x.success())
.unwrap_or(false)
} else {
false
};

if nm_running {
debug!("Detected NetworkManager running");
} else {
debug!("NetworkManager not detected running");
}

let nm_unmanaged = if nm_path.exists() && nm_running {
debug!(
"NetworkManager detected, adding {} to unmanaged devices",
&dest
Expand Down Expand Up @@ -72,13 +90,46 @@ impl VethPair {
)?;
}

sudo_command(&["nmcli", "connection", "reload"])
.context("Failed to reload NetworkManager configuration")?;
if let Err(e) = sudo_command(&["nmcli", "connection", "reload"])
.context("Failed to reload NetworkManager configuration")
{
warn!("Tried but failed to reload NetworkManager configuration - is NetworkManager running? : {}", e);
}
Some(NetworkManagerUnmanaged { backup_file })
} else {
None
};

// systemd firewalld device management
let firewalld_running = std::process::Command::new("systemctl")
.arg("is-active")
.arg("firewalld")
.output()
.map(|x| String::from_utf8(x.stdout).ok().unwrap().trim() == "active")
.unwrap_or(false);

if firewalld_running {
debug!("Detected firewalld running");
} else {
debug!("firewalld not detected running");
}

if firewalld_running && which::which("firewall-cmd").is_ok() {
debug!(
"Detected firewalld running, adding {} veth device to trusted zone",
dest
);
// Permit new interface
match std::process::Command::new("firewall-cmd")
.arg("--zone=trusted")
.arg(format!("--add-interface={}", dest).as_str())
.status().map(|x| x.success()) {
Err(e) => warn!("Failed to add veth device {} to firewalld trusted zone, error: {}", dest, e),
Ok(false) => warn!("Possibly failed to add veth device {} to firewalld trusted zone (non-zero exit code)", dest),
_ => {}
}
}

sudo_command(&[
"ip",
"link",
Expand Down
8 changes: 4 additions & 4 deletions src/wireguard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ impl Wireguard {

let dns = dns.unwrap_or(&config.interface.dns);
// TODO: DNS suffixes?
namespace.dns_config(&dns, &[])?;
namespace.dns_config(dns, &[])?;
let fwmark = "51820";
namespace.exec(&["wg", "set", &if_name, "fwmark", fwmark])?;

Expand Down Expand Up @@ -321,12 +321,12 @@ impl Wireguard {

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

// Allow input to and output from forwarded ports
if let Some(forwards) = forward_ports {
super::util::open_ports(&namespace, forwards.as_slice(), firewall)?;
super::util::open_ports(namespace, forwards.as_slice(), firewall)?;
}

if use_killswitch {
Expand Down Expand Up @@ -443,7 +443,7 @@ impl Drop for Wireguard {
"ip",
"link",
"del",
&if_name,
if_name,
]) {
Ok(_) => {}
Err(e) => warn!("Failed to delete ip link {}: {:?}", &self.ns_name, e),
Expand Down

0 comments on commit 4f78e78

Please sign in to comment.