Skip to content

Commit

Permalink
Merge pull request #178 from jamesmcm/vopono101
Browse files Browse the repository at this point in the history
vopono 0.10.1
  • Loading branch information
jamesmcm authored Jul 24, 2022
2 parents c5b37eb + 36e6b6d commit dfa5af3
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 29 deletions.
56 changes: 55 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,20 @@ jobs:
with:
name: armv5-deb
path: ./target/armv5te-unknown-linux-musleabi/debian/*
aarch64deb:
needs: [build]
runs-on: ubuntu-latest
name: Aarch64Deb
steps:
- uses: actions/checkout@v2
- name: BuildDeb
id: debbuild
uses: jamesmcm/cargo-deb-aarch64-debian@master
- name: Upload Deb Artifact
uses: actions/upload-artifact@v2
with:
name: aarch64-deb
path: ./target/aarch64-unknown-linux-musl/debian/*
amd64binaries:
needs: [build, quickcheck]
runs-on: ubuntu-latest
Expand Down Expand Up @@ -168,8 +182,28 @@ jobs:
with:
name: armv5
path: ./target/armv5te-unknown-linux-musleabi/release/vopono
aarch64binaries:
needs: [build, quickcheck]
runs-on: ubuntu-latest
name: Aarch64StaticBinaries
steps:
- uses: actions/checkout@v2
- id: cargoversion
run: cargo --version
- id: rustcversion
run: rustc --version
- name: StaticBinaryBuild
id: aarch64staticbuild
uses: jamesmcm/cargo-deb-aarch64-debian@master
with:
cmd: cargo build --release --target=aarch64-unknown-linux-musl
- name: Upload Vopono Artifact
uses: actions/upload-artifact@v2
with:
name: aarch64
path: ./target/aarch64-unknown-linux-musl/release/vopono
update_release_draft:
needs: [quickcheck, build, arm7binaries, arm5binaries, amd64binaries, raspbianbuild, armv5deb, debbuild, opensuseleaprpmbuild, fedorarpmbuild]
needs: [quickcheck, build, arm7binaries, arm5binaries, aarch64binaries, amd64binaries, raspbianbuild, armv5deb, aarch64deb, debbuild, opensuseleaprpmbuild, fedorarpmbuild]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand All @@ -193,6 +227,8 @@ jobs:
- run: ls -lha armv7
- run: ls -lha armv5-deb
- run: ls -lha armv5
- run: ls -lha aarch64-deb
- run: ls -lha aarch64
- run: ls -lha fedorarpm
- run: ls -lha opensuserpm
- name: Upload amd64 deb Release Asset
Expand Down Expand Up @@ -222,6 +258,15 @@ jobs:
asset_path: ./armv5-deb/vopono_${{needs.quickcheck.outputs.version}}_armel.deb
asset_name: 'vopono_${{needs.quickcheck.outputs.version}}_armel.deb'
asset_content_type: application/vnd.debian.binary-package
- name: Upload aarch64 deb Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./aarch64-deb/vopono_${{needs.quickcheck.outputs.version}}_aarch64.deb
asset_name: 'vopono_${{needs.quickcheck.outputs.version}}_aarch64.deb'
asset_content_type: application/vnd.debian.binary-package
- name: Upload amd64 rpm fedora Release Asset
uses: actions/upload-release-asset@v1
env:
Expand Down Expand Up @@ -258,6 +303,15 @@ jobs:
asset_path: ./armv5/vopono
asset_name: 'vopono_${{needs.quickcheck.outputs.version}}_linux_armv5'
asset_content_type: application/octet-stream
- name: Upload Aarch64 Static Binary
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./aarch64/vopono
asset_name: 'vopono_${{needs.quickcheck.outputs.version}}_linux_aarch64'
asset_content_type: application/octet-stream
- name: Upload Amd64 Static Binary
uses: actions/upload-release-asset@v1
env:
Expand Down
9 changes: 9 additions & 0 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,15 @@ pub struct ExecCommand {
/// Default: ~/.config/vopono/config.toml
#[clap(long = "vopono-config")]
pub vopono_config: Option<PathBuf>,

/// Custom name for the generated network namespace
/// Will use this network namespace directly if it exists
#[clap(long = "custom-netns-name")]
pub custom_netns_name: Option<String>,
/// Allow access to host from network namespace
/// Useful for accessing services on the host locally
#[clap(long = "allow-host-access")]
pub allow_host_access: bool,
}

#[derive(Parser)]
Expand Down
57 changes: 53 additions & 4 deletions src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub fn exec(command: ExecCommand, uiclient: &dyn UiClient) -> anyhow::Result<()>
let server_name: String;
let protocol: Protocol;

// TODO: Refactor this part - DRY
// TODO: Refactor this part - DRY - macro_rules ?
// Check if we have config file path passed on command line
// Create empty config file if does not exist
create_dir_all(vopono_dir()?)?;
Expand Down Expand Up @@ -73,6 +73,36 @@ pub fn exec(command: ExecCommand, uiclient: &dyn UiClient) -> anyhow::Result<()>
.ok()
});

// Assign custom_config from args or vopono config file
let custom_netns_name = command.custom_netns_name.clone().or_else(|| {
vopono_config_settings
.get("custom_netns_name")
.map_err(|e| {
debug!("vopono config.toml: {:?}", e);
anyhow!("Failed to read config file")
})
.ok()
});

// Assign open_hosts from args or vopono config file
let mut open_hosts = command.open_hosts.clone().or_else(|| {
vopono_config_settings
.get("open_hosts")
.map_err(|e| {
debug!("vopono config.toml: {:?}", e);
anyhow!("Failed to read config file")
})
.ok()
});
let allow_host_access = command.allow_host_access
|| vopono_config_settings
.get("allow_host_access")
.map_err(|e| {
debug!("vopono config.toml: {:?}", e);
anyhow!("Failed to read config file")
})
.unwrap_or(false);

// Assign postup script from args or vopono config file
let postup = command.postup.clone().or_else(|| {
vopono_config_settings
Expand Down Expand Up @@ -224,7 +254,11 @@ pub fn exec(command: ExecCommand, uiclient: &dyn UiClient) -> anyhow::Result<()>
_ => provider.get_dyn_provider().alias(),
};

let ns_name = format!("vopono_{}_{}", alias, server_name);
let ns_name = if let Some(c_ns_name) = custom_netns_name {
c_ns_name
} else {
format!("vopono_{}_{}", alias, server_name)
};

let mut ns;
let _sysctl;
Expand Down Expand Up @@ -298,7 +332,22 @@ pub fn exec(command: ExecCommand, uiclient: &dyn UiClient) -> anyhow::Result<()>
let target_subnet = get_target_subnet()?;
ns.add_loopback()?;
ns.add_veth_pair()?;
ns.add_routing(target_subnet, command.open_hosts.as_ref())?;
ns.add_routing(target_subnet, open_hosts.as_ref(), allow_host_access)?;

// Add local host to open hosts if allow_host_access enabled
if allow_host_access {
let host_ip = ns.veth_pair_ips.as_ref().unwrap().host_ip;
warn!(
"Allowing host access from network namespace, host IP address is: {}",
host_ip
);
if let Some(oh) = open_hosts.iter_mut().next() {
oh.push(host_ip);
} else {
open_hosts = Some(vec![host_ip]);
}
}

ns.add_host_masquerade(target_subnet, interface.clone(), firewall)?;
ns.add_firewall_exception(
interface,
Expand Down Expand Up @@ -418,7 +467,7 @@ pub fn exec(command: ExecCommand, uiclient: &dyn UiClient) -> anyhow::Result<()>
}
}

if let Some(ref hosts) = command.open_hosts {
if let Some(ref hosts) = open_hosts {
vopono_core::util::open_hosts(&ns, hosts.to_vec(), firewall)?;
}

Expand Down
2 changes: 1 addition & 1 deletion vopono_core/src/network/application_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl ApplicationWrapper {
}

// TODO: Could allow user to set custom working directory here
let handle = netns.exec_no_block(app_vec.as_slice(), user, false, false, None)?;
let handle = netns.exec_no_block(app_vec.as_slice(), user, false, false, false, None)?;
Ok(Self { handle })
}

Expand Down
37 changes: 31 additions & 6 deletions vopono_core/src/network/netns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ impl NetworkNamespace {
user: Option<String>,
silent: bool,
capture_output: bool,
capture_input: bool,
set_dir: Option<PathBuf>,
) -> anyhow::Result<std::process::Child> {
let mut handle = Command::new("ip");
Expand All @@ -126,7 +127,9 @@ impl NetworkNamespace {
handle.stdout(Stdio::piped());
handle.stderr(Stdio::piped());
}
handle.stdin(Stdio::piped());
if capture_input {
handle.stdin(Stdio::piped());
}

debug!(
"ip netns exec {}{} {}",
Expand All @@ -139,7 +142,7 @@ impl NetworkNamespace {
}

pub fn exec(&self, command: &[&str]) -> anyhow::Result<()> {
self.exec_no_block(command, None, false, false, None)?
self.exec_no_block(command, None, false, false, false, None)?
.wait()?;
Ok(())
}
Expand All @@ -154,7 +157,8 @@ impl NetworkNamespace {

pub fn add_veth_pair(&mut self) -> anyhow::Result<()> {
// TODO: Handle if name taken?
let basename = &self.name[(self.name.len() - 13).max(0)..self.name.len()];
// Use bs58 here?
let basename = &self.name[((self.name.len() as i32) - 13).max(0) as usize..self.name.len()];
let source = format!("{}_s", basename);
let dest = format!("{}_d", basename);
self.veth_pair = Some(VethPair::new(source, dest, self)?);
Expand All @@ -165,6 +169,7 @@ impl NetworkNamespace {
&mut self,
target_subnet: u8,
hosts: Option<&Vec<IpAddr>>,
allow_host_access: bool,
) -> anyhow::Result<()> {
// TODO: Handle case where IP address taken in better way i.e. don't just change subnet
let veth_dest = &self
Expand Down Expand Up @@ -213,21 +218,40 @@ impl NetworkNamespace {
"ip",
"route",
"add",
&format!("{}", host),
&host.to_string(),
"via",
&ip_nosub,
"dev",
veth_source,
])
.with_context(|| {
format!(
"Failed to assign hosts route to veth source: {}",
veth_source
"Failed to assign hosts route {} to veth source: {}",
host, veth_source
)
})?;
}
}

if allow_host_access {
self.exec(&[
"ip",
"route",
"add",
&ip_nosub,
"via",
&ip_nosub,
"dev",
veth_source,
])
.with_context(|| {
format!(
"Failed to assign hosts route for local host {} to veth source: {}",
ip_nosub, veth_source
)
})?;
}

info!(
"IP address of namespace as seen from host: {}",
veth_source_ip_nosub
Expand Down Expand Up @@ -446,6 +470,7 @@ impl Drop for NetworkNamespace {
lockfile_path.push(format!("vopono/locks/{}", self.name));

// Drop if lock directory doesn't exist, or it exists but is empty
// TODO: How can we make this check that no _other_ PIDs exist (aside from ones we have spawned)
if !lockfile_path.exists()
|| (lockfile_path.read_dir().is_ok()
&& lockfile_path.read_dir().unwrap().next().is_none())
Expand Down
2 changes: 1 addition & 1 deletion vopono_core/src/network/openconnect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl OpenConnect {
}

let handle = netns
.exec_no_block(&command_vec, None, false, false, None)
.exec_no_block(&command_vec, None, false, false, true, None)
.context("Failed to launch OpenConnect - is openconnect installed?")?;

handle
Expand Down
2 changes: 1 addition & 1 deletion vopono_core/src/network/openfortivpn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl OpenFortiVpn {

// TODO - better handle forwarding output when blocking on password entry (no newline!)
let mut handle = netns
.exec_no_block(&command_vec, None, false, true, None)
.exec_no_block(&command_vec, None, false, true, false, None)
.context("Failed to launch OpenFortiVPN - is openfortivpn installed?")?;
let stdout = handle.stdout.take().unwrap();
let id = handle.id();
Expand Down
22 changes: 19 additions & 3 deletions vopono_core/src/network/openvpn.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::firewall::Firewall;
use super::netns::NetworkNamespace;
use crate::config::vpn::OpenVpnProtocol;
use crate::util::check_process_running;
use crate::util::{check_process_running, vopono_dir};
use anyhow::{anyhow, Context};
use log::{debug, error, info};
use regex::Regex;
Expand All @@ -16,6 +16,7 @@ use std::str::FromStr;
pub struct OpenVpn {
pid: u32,
pub openvpn_dns: Option<IpAddr>,
pub logfile: PathBuf,
}

impl OpenVpn {
Expand All @@ -42,7 +43,9 @@ impl OpenVpn {
));
}

let log_file_str = format!("/etc/netns/{}/openvpn.log", &netns.name);
std::fs::create_dir_all(vopono_dir()?.join("logs"))?;
let log_file_path = vopono_dir()?.join(format!("logs/{}_openvpn.log", &netns.name));
let log_file_str: String = log_file_path.as_os_str().to_string_lossy().to_string();
{
File::create(&log_file_str)?;
}
Expand Down Expand Up @@ -95,7 +98,7 @@ impl OpenVpn {
let working_dir = PathBuf::from(config_file_path.parent().unwrap());

let handle = netns
.exec_no_block(&command_vec, None, true, false, Some(working_dir))
.exec_no_block(&command_vec, None, true, false, false, Some(working_dir))
.context("Failed to launch OpenVPN - is openvpn installed?")?;
let id = handle.id();
let mut buffer = String::with_capacity(16384);
Expand Down Expand Up @@ -173,6 +176,7 @@ impl OpenVpn {
Ok(Self {
pid: id,
openvpn_dns,
logfile: log_file_path,
})
}

Expand All @@ -190,6 +194,18 @@ impl Drop for OpenVpn {
Ok(_) => debug!("Killed OpenVPN (pid: {})", self.pid),
Err(e) => error!("Failed to kill OpenVPN (pid: {}): {:?}", self.pid, e),
}

match std::fs::remove_file(&self.logfile) {
Ok(_) => debug!(
"Deleted OpenVPN logfile: {}",
self.logfile.as_os_str().to_string_lossy()
),
Err(e) => error!(
"Failed to delete OpenVPN logfile: {}: {:?}",
self.logfile.as_os_str().to_string_lossy(),
e
),
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion vopono_core/src/network/shadowsocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl Shadowsocks {
];

let handle = netns
.exec_no_block(&command_vec, None, true, false, None)
.exec_no_block(&command_vec, None, true, false, false, None)
.context("Failed to launch Shadowsocks - is shadowsocks-libev installed?")?;

Ok(Self { pid: handle.id() })
Expand Down
Loading

0 comments on commit dfa5af3

Please sign in to comment.