Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vopono 0.9.1 #158

Merged
merged 1 commit into from
May 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.9.0"
version = "0.9.1"
authors = ["James McMurray <[email protected]>"]
edition = "2021"
license = "GPL-3.0-or-later"
Expand All @@ -19,7 +19,7 @@ pretty_env_logger = "0.4"
clap = {version = "3", features = ["derive"]}
which = "4"
users = "0.11"
nix = "0.23"
nix = "0.24"
serde = {version = "1", features = ["derive", "std"]}
csv = "1"
dialoguer ="0.10"
Expand All @@ -40,7 +40,7 @@ strum = "0.24"
strum_macros = "0.24"
zip = "0.6"
maplit = "1"
webbrowser = "0.6"
webbrowser = "0.7"
basic_tcp_proxy = "0.3"
signal-hook = "0.3"
config = "0.13"
Expand Down
15 changes: 15 additions & 0 deletions USERGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ Note for same daemons you may need to use the `-k` keep-alive option in
case the process ID changes (you will then need to manually kill the
daemon after finishing).

#### transmission-daemon

For example, to launch `transmission-daemon` that is externally
accessible at `127.0.0.1:9091` (with outward connections via AzireVPN with Wireguard and a VPN server in Norway):

Expand All @@ -318,6 +320,19 @@ the network namespace runs on.
When finished with vopono, you must manually kill the
`transmission-daemon` since the PID changes (i.e. use `killall`).

#### Jackett

The same approach also works for [Jackett](https://github.com/Jackett/Jackett), e.g. with the setup from
the [AUR PKGBUILD](https://aur.archlinux.org/packages/jackett-bin) (a separate `jackett` user and hosting on port `9117`):

```bash
$ vopono -v exec -u jackett "/usr/lib/jackett/jackett --NoRestart --NoUpdates --DataFolder /var/lib/jackett" -f 9117
```

You can then access the web UI on the host machine at `https://127.0.0.1:9117/UI/Dashboard`, but all of Jackett's connections will go via the VPN.

#### Proxy to host

By default, vopono runs a small TCP proxy to proxy the ports on your
host machine to the ports on the network namespace - if you do not want
this to run use the `--no-proxy` flag.
Expand Down
42 changes: 23 additions & 19 deletions src/dns_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
use std::io::BufRead;
use std::io::Write;
use std::net::IpAddr;
use std::os::unix::fs::PermissionsExt;

#[derive(Serialize, Deserialize, Debug)]
pub struct DnsConfig {
Expand All @@ -18,16 +19,17 @@ impl DnsConfig {
suffixes: &[&str],
hosts_entries: Option<&Vec<String>>,
) -> anyhow::Result<Self> {
std::fs::create_dir_all(format!("/etc/netns/{}", ns_name))
.with_context(|| format!("Failed to create directory: /etc/netns/{}", ns_name))?;
let dir_path = format!("/etc/netns/{}", ns_name);
std::fs::create_dir_all(&dir_path)
.with_context(|| format!("Failed to create directory: {}", &dir_path))?;
std::fs::set_permissions(&dir_path, PermissionsExt::from_mode(0o644))
.with_context(|| format!("Failed to set directory permissions for {}", dir_path))?;

let mut resolv = std::fs::File::create(format!("/etc/netns/{}/resolv.conf", ns_name))
.with_context(|| {
format!(
"Failed to open resolv.conf: /etc/netns/{}/resolv.conf",
ns_name
)
})?;
let resolv_conf_path = format!("/etc/netns/{}/resolv.conf", ns_name);
let mut resolv = std::fs::File::create(&resolv_conf_path)
.with_context(|| format!("Failed to open resolv.conf: {}", &resolv_conf_path))?;
std::fs::set_permissions(&resolv_conf_path, PermissionsExt::from_mode(0o644))
.with_context(|| format!("Failed to set file permissions for {}", resolv_conf_path))?;

debug!(
"Setting namespace {} DNS server to {}",
Expand Down Expand Up @@ -59,8 +61,11 @@ impl DnsConfig {
}

if let Some(my_hosts_entries) = hosts_entries {
let mut hosts = std::fs::File::create(format!("/etc/netns/{}/hosts", ns_name))
.with_context(|| format!("Failed to open hosts: /etc/netns/{}/hosts", ns_name))?;
let hosts_path = format!("/etc/netns/{}/hosts", ns_name);
let mut hosts = std::fs::File::create(&hosts_path)
.with_context(|| format!("Failed to open hosts: {}", &hosts_path))?;
std::fs::set_permissions(&hosts_path, PermissionsExt::from_mode(0o644))
.with_context(|| format!("Failed to set file permissions for {}", &hosts_path))?;

for hosts_enty in my_hosts_entries {
writeln!(hosts, "{}", hosts_enty).with_context(|| {
Expand All @@ -73,14 +78,13 @@ impl DnsConfig {
let nsswitch_src = std::fs::File::open("/etc/nsswitch.conf")
.with_context(|| "Failed to open nsswitch.conf: /etc/nsswitch.conf")?;

let mut nsswitch =
std::fs::File::create(format!("/etc/netns/{}/nsswitch.conf", ns_name))
.with_context(|| {
format!(
"Failed to open nsswitch.conf: /etc/netns/{}/nsswitch.conf",
ns_name
)
})?;
let nsswitch_path = format!("/etc/netns/{}/nsswitch.conf", ns_name);
let mut nsswitch = std::fs::File::create(&nsswitch_path)
.with_context(|| format!("Failed to open nsswitch.conf: {}", nsswitch_path))?;
std::fs::set_permissions(&nsswitch_path, PermissionsExt::from_mode(0o644))
.with_context(|| {
format!("Failed to set file permissions for {}", &nsswitch_path)
})?;

for line in std::io::BufReader::new(nsswitch_src).lines() {
writeln!(
Expand Down
36 changes: 32 additions & 4 deletions src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use anyhow::{anyhow, bail};
use log::{debug, error, info, warn};
use signal_hook::{consts::SIGINT, iterator::Signals};
use std::net::{IpAddr, Ipv4Addr};
use std::str::FromStr;
use std::{
fs::create_dir_all,
io::{self, Write},
Expand Down Expand Up @@ -203,14 +204,41 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> {

let mut ns;
let _sysctl;
let interface: NetworkInterface = match command.interface {

// Assign network interface from args or vopono config file
let interface = command.interface.clone().or_else(|| {
vopono_config_settings
.get_string("interface")
.map_err(|e| {
debug!("vopono config.toml: {:?}", e);
anyhow!("Failed to read config file")
})
.map(|x| {
NetworkInterface::from_str(&x)
.map_err(|e| {
debug!("vopono config.toml: {:?}", e);
anyhow!("Failed to parse network interface in config file")
})
.ok()
})
.ok()
.flatten()
});
let interface: NetworkInterface = match interface {
Some(x) => anyhow::Result::<NetworkInterface>::Ok(x),
None => Ok(NetworkInterface::new(
get_active_interfaces()?
None => {
let active_interfaces = get_active_interfaces()?;
if active_interfaces.len() > 1 {
warn!("Multiple network interfaces are active: {:#?}, consider specifying the interface with the -i argument. Using {}", &active_interfaces, &active_interfaces[0]);
}
Ok(
NetworkInterface::new(
active_interfaces
.into_iter()
.next()
.ok_or_else(|| anyhow!("No active network interface - consider overriding network interface selection with -i argument"))?,
)?),
)?)
}
}?;
debug!("Interface: {}", &interface.name);

Expand Down