Skip to content

Commit

Permalink
Merge pull request #92 from jamesmcm/natfix
Browse files Browse the repository at this point in the history
Fix case where NAT rules undone prematurely
  • Loading branch information
jamesmcm authored Jun 5, 2021
2 parents 46775dd + cf19aa3 commit 5ae5210
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 61 deletions.
6 changes: 3 additions & 3 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.1"
version = "0.8.2"
authors = ["James McMurray <jamesmcm03@gmail.com>"]
edition = "2018"
license = "GPL-3.0-or-later"
Expand Down Expand Up @@ -37,8 +37,8 @@ reqwest = {default-features = false, version = "0.11", features = ["blocking", "
sysinfo = "0.18"
base64 = "0.13"
x25519-dalek = "1"
strum = "0.20"
strum_macros = "0.20"
strum = "0.21"
strum_macros = "0.21"
zip = "0.5"
maplit = "1"
webbrowser = "0.5"
Expand Down
2 changes: 1 addition & 1 deletion src/dns_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use std::io::Write;
use std::net::IpAddr;

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct DnsConfig {
ns_name: String,
}
Expand Down
83 changes: 47 additions & 36 deletions src/host_masquerade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use super::firewall::Firewall;
use super::network_interface::NetworkInterface;
use super::util::sudo_command;
use anyhow::Context;
use log::debug;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Clone)]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct HostMasquerade {
ip_mask: String,
interface: NetworkInterface,
Expand Down Expand Up @@ -80,43 +81,48 @@ impl HostMasquerade {

impl Drop for HostMasquerade {
fn drop(&mut self) {
match self.firewall {
Firewall::IpTables => {
sudo_command(&[
"iptables",
"-t",
"nat",
"-D",
"POSTROUTING",
"-s",
&self.ip_mask,
"-o",
&self.interface.name,
"-j",
"MASQUERADE",
])
.unwrap_or_else(|_| {
panic!(
"Failed to delete iptables masquerade rule, ip_mask: {}, interface: {}",
&self.ip_mask, &self.interface.name
)
});
}
Firewall::NfTables => {
sudo_command(&["nft", "delete", "table", "inet", "vopono_nat"]).unwrap_or_else(
|_| {
// Only drop these settings if there are no other active namespaces
let namespaces = crate::list::get_lock_namespaces();
debug!("Remaining namespaces: {:?}", namespaces);
if namespaces.is_ok() && namespaces.unwrap().is_empty() {
match self.firewall {
Firewall::IpTables => {
sudo_command(&[
"iptables",
"-t",
"nat",
"-D",
"POSTROUTING",
"-s",
&self.ip_mask,
"-o",
&self.interface.name,
"-j",
"MASQUERADE",
])
.unwrap_or_else(|_| {
panic!(
"Failed to delete iptables masquerade rule, ip_mask: {}, interface: {}",
&self.ip_mask, &self.interface.name
)
});
}
Firewall::NfTables => {
sudo_command(&["nft", "delete", "table", "inet", "vopono_nat"]).unwrap_or_else(
|_| {
panic!(
"Failed to delete nftables masquerade rule, ip_mask: {}, interface: {}",
&self.ip_mask, &self.interface.name
)
},
);
},
);
}
}
}
}
}

#[derive(Serialize, Deserialize, Clone)]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct FirewallException {
host_interface: NetworkInterface,
ns_interface: NetworkInterface,
Expand Down Expand Up @@ -231,9 +237,13 @@ impl FirewallException {

impl Drop for FirewallException {
fn drop(&mut self) {
match self.firewall {
Firewall::IpTables => {
sudo_command(&[
// Only drop these settings if there are no other active namespaces
let namespaces = crate::list::get_lock_namespaces();
debug!("Remaining namespaces: {:?}", namespaces);
if namespaces.is_ok() && namespaces.unwrap().is_empty() {
match self.firewall {
Firewall::IpTables => {
sudo_command(&[
"iptables",
"-D",
"FORWARD",
Expand All @@ -251,7 +261,7 @@ impl Drop for FirewallException {
)
});

sudo_command(&[
sudo_command(&[
"iptables",
"-D",
"FORWARD",
Expand All @@ -268,16 +278,17 @@ impl Drop for FirewallException {
&self.host_interface.name, &self.ns_interface.name
)
});
}
Firewall::NfTables => {
sudo_command(&["nft", "delete", "table", "inet", "vopono_bridge"]).unwrap_or_else(
}
Firewall::NfTables => {
sudo_command(&["nft", "delete", "table", "inet", "vopono_bridge"]).unwrap_or_else(
|_| {
panic!(
"Failed to delete nftables namespace bridge firewall rule, host interface: {}, namespace interface: {}",
&self.host_interface.name, &self.ns_interface.name
)
},
);
}
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions src/netns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct NetworkNamespace {
pub name: String,
pub veth_pair: Option<VethPair>,
Expand Down Expand Up @@ -444,6 +444,10 @@ impl Drop for NetworkNamespace {
.unwrap_or_else(|_| panic!("Failed to delete network namespace: {}", &self.name));
} else {
debug!("Skipping destructors since other vopono instance using this namespace!");
debug!(
"Existing lockfiles using this namespace: {:?}",
lockfile_path.read_dir().unwrap().collect::<Vec<_>>()
);
std::mem::forget(self.openvpn.take());
std::mem::forget(self.veth_pair.take());
std::mem::forget(self.dns_config.take());
Expand All @@ -455,7 +459,7 @@ impl Drop for NetworkNamespace {
}
}

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct Lockfile {
pub ns: NetworkNamespace,
pub start: u64,
Expand Down
2 changes: 1 addition & 1 deletion src/network_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use std::process::Command;
use std::str::FromStr;

#[derive(Clone, Serialize, Deserialize)]
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct NetworkInterface {
pub name: String,
}
Expand Down
2 changes: 1 addition & 1 deletion src/openconnect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use log::{debug, error, info};
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct OpenConnect {
pid: u32,
}
Expand Down
2 changes: 1 addition & 1 deletion src/openfortivpn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::net::{IpAddr, Ipv4Addr};
use std::path::{Path, PathBuf};
use std::str::FromStr;

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct OpenFortiVpn {
pid: u32,
}
Expand Down
2 changes: 1 addition & 1 deletion src/openvpn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::net::IpAddr;
use std::path::{Path, PathBuf};
use std::str::FromStr;

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct OpenVpn {
pid: u32,
pub openvpn_dns: Option<IpAddr>,
Expand Down
2 changes: 1 addition & 1 deletion src/shadowsocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use std::net::{IpAddr, Ipv4Addr};
use std::path::Path;
use std::str::FromStr;

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct Shadowsocks {
pid: u32,
}
Expand Down
31 changes: 18 additions & 13 deletions src/veth_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ use std::io::Write;
use std::path::PathBuf;
use std::str::FromStr;

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct VethPair {
pub source: String,
pub dest: String,
pub nm_unmanaged: Option<NetworkManagerUnmanaged>,
}

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct NetworkManagerUnmanaged {
pub backup_file: Option<PathBuf>,
}
Expand Down Expand Up @@ -123,17 +123,22 @@ impl Drop for VethPair {

impl Drop for NetworkManagerUnmanaged {
fn drop(&mut self) {
let nm_path = PathBuf::from_str("/etc/NetworkManager/conf.d/unmanaged.conf")
.expect("Failed to build path");
if self.backup_file.is_some() {
std::fs::copy(self.backup_file.as_ref().unwrap(), &nm_path)
.expect("Failed to restore backup of NetworkManager unmanaged.conf");
std::fs::remove_file(self.backup_file.as_ref().unwrap())
.expect("Failed to delete backup of NetworkManager unmanaged.conf");
} else {
std::fs::remove_file(&nm_path).expect("Failed to delete NetworkManager unmanaged.conf");
// Only restore settings if there are no other active namespaces
let namespaces = crate::list::get_lock_namespaces();
if namespaces.is_ok() && namespaces.unwrap().is_empty() {
let nm_path = PathBuf::from_str("/etc/NetworkManager/conf.d/unmanaged.conf")
.expect("Failed to build path");
if self.backup_file.is_some() {
std::fs::copy(self.backup_file.as_ref().unwrap(), &nm_path)
.expect("Failed to restore backup of NetworkManager unmanaged.conf");
std::fs::remove_file(self.backup_file.as_ref().unwrap())
.expect("Failed to delete backup of NetworkManager unmanaged.conf");
} else {
std::fs::remove_file(&nm_path)
.expect("Failed to delete NetworkManager unmanaged.conf");
}
sudo_command(&["nmcli", "connection", "reload"])
.expect("Failed to reload NetworkManager configuration");
}
sudo_command(&["nmcli", "connection", "reload"])
.expect("Failed to reload NetworkManager configuration");
}
}
2 changes: 1 addition & 1 deletion src/wireguard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::path::PathBuf;

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct Wireguard {
ns_name: String,
config_file: PathBuf,
Expand Down

0 comments on commit 5ae5210

Please sign in to comment.