Skip to content

Commit 20ccb31

Browse files
authored
Merge pull request #158 from jamesmcm/vopono091
vopono 0.9.1
2 parents b1e1e8b + 304f4ee commit 20ccb31

File tree

4 files changed

+73
-26
lines changed

4 files changed

+73
-26
lines changed

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "vopono"
33
description = "Launch applications via VPN tunnels using temporary network namespaces"
4-
version = "0.9.0"
4+
version = "0.9.1"
55
authors = ["James McMurray <[email protected]>"]
66
edition = "2021"
77
license = "GPL-3.0-or-later"
@@ -19,7 +19,7 @@ pretty_env_logger = "0.4"
1919
clap = {version = "3", features = ["derive"]}
2020
which = "4"
2121
users = "0.11"
22-
nix = "0.23"
22+
nix = "0.24"
2323
serde = {version = "1", features = ["derive", "std"]}
2424
csv = "1"
2525
dialoguer ="0.10"
@@ -40,7 +40,7 @@ strum = "0.24"
4040
strum_macros = "0.24"
4141
zip = "0.6"
4242
maplit = "1"
43-
webbrowser = "0.6"
43+
webbrowser = "0.7"
4444
basic_tcp_proxy = "0.3"
4545
signal-hook = "0.3"
4646
config = "0.13"

USERGUIDE.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,8 @@ Note for same daemons you may need to use the `-k` keep-alive option in
300300
case the process ID changes (you will then need to manually kill the
301301
daemon after finishing).
302302

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

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

323+
#### Jackett
324+
325+
The same approach also works for [Jackett](https://github.com/Jackett/Jackett), e.g. with the setup from
326+
the [AUR PKGBUILD](https://aur.archlinux.org/packages/jackett-bin) (a separate `jackett` user and hosting on port `9117`):
327+
328+
```bash
329+
$ vopono -v exec -u jackett "/usr/lib/jackett/jackett --NoRestart --NoUpdates --DataFolder /var/lib/jackett" -f 9117
330+
```
331+
332+
You can then access the web UI on the host machine at `http://127.0.0.1:9117/UI/Dashboard`, but all of Jackett's connections will go via the VPN.
333+
334+
#### Proxy to host
335+
321336
By default, vopono runs a small TCP proxy to proxy the ports on your
322337
host machine to the ports on the network namespace - if you do not want
323338
this to run use the `--no-proxy` flag.

src/dns_config.rs

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
55
use std::io::BufRead;
66
use std::io::Write;
77
use std::net::IpAddr;
8+
use std::os::unix::fs::PermissionsExt;
89

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

24-
let mut resolv = std::fs::File::create(format!("/etc/netns/{}/resolv.conf", ns_name))
25-
.with_context(|| {
26-
format!(
27-
"Failed to open resolv.conf: /etc/netns/{}/resolv.conf",
28-
ns_name
29-
)
30-
})?;
28+
let resolv_conf_path = format!("/etc/netns/{}/resolv.conf", ns_name);
29+
let mut resolv = std::fs::File::create(&resolv_conf_path)
30+
.with_context(|| format!("Failed to open resolv.conf: {}", &resolv_conf_path))?;
31+
std::fs::set_permissions(&resolv_conf_path, PermissionsExt::from_mode(0o644))
32+
.with_context(|| format!("Failed to set file permissions for {}", resolv_conf_path))?;
3133

3234
debug!(
3335
"Setting namespace {} DNS server to {}",
@@ -59,8 +61,11 @@ impl DnsConfig {
5961
}
6062

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

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

76-
let mut nsswitch =
77-
std::fs::File::create(format!("/etc/netns/{}/nsswitch.conf", ns_name))
78-
.with_context(|| {
79-
format!(
80-
"Failed to open nsswitch.conf: /etc/netns/{}/nsswitch.conf",
81-
ns_name
82-
)
83-
})?;
81+
let nsswitch_path = format!("/etc/netns/{}/nsswitch.conf", ns_name);
82+
let mut nsswitch = std::fs::File::create(&nsswitch_path)
83+
.with_context(|| format!("Failed to open nsswitch.conf: {}", nsswitch_path))?;
84+
std::fs::set_permissions(&nsswitch_path, PermissionsExt::from_mode(0o644))
85+
.with_context(|| {
86+
format!("Failed to set file permissions for {}", &nsswitch_path)
87+
})?;
8488

8589
for line in std::io::BufReader::new(nsswitch_src).lines() {
8690
writeln!(

src/exec.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use anyhow::{anyhow, bail};
1515
use log::{debug, error, info, warn};
1616
use signal_hook::{consts::SIGINT, iterator::Signals};
1717
use std::net::{IpAddr, Ipv4Addr};
18+
use std::str::FromStr;
1819
use std::{
1920
fs::create_dir_all,
2021
io::{self, Write},
@@ -203,14 +204,41 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> {
203204

204205
let mut ns;
205206
let _sysctl;
206-
let interface: NetworkInterface = match command.interface {
207+
208+
// Assign network interface from args or vopono config file
209+
let interface = command.interface.clone().or_else(|| {
210+
vopono_config_settings
211+
.get_string("interface")
212+
.map_err(|e| {
213+
debug!("vopono config.toml: {:?}", e);
214+
anyhow!("Failed to read config file")
215+
})
216+
.map(|x| {
217+
NetworkInterface::from_str(&x)
218+
.map_err(|e| {
219+
debug!("vopono config.toml: {:?}", e);
220+
anyhow!("Failed to parse network interface in config file")
221+
})
222+
.ok()
223+
})
224+
.ok()
225+
.flatten()
226+
});
227+
let interface: NetworkInterface = match interface {
207228
Some(x) => anyhow::Result::<NetworkInterface>::Ok(x),
208-
None => Ok(NetworkInterface::new(
209-
get_active_interfaces()?
229+
None => {
230+
let active_interfaces = get_active_interfaces()?;
231+
if active_interfaces.len() > 1 {
232+
warn!("Multiple network interfaces are active: {:#?}, consider specifying the interface with the -i argument. Using {}", &active_interfaces, &active_interfaces[0]);
233+
}
234+
Ok(
235+
NetworkInterface::new(
236+
active_interfaces
210237
.into_iter()
211238
.next()
212239
.ok_or_else(|| anyhow!("No active network interface - consider overriding network interface selection with -i argument"))?,
213-
)?),
240+
)?)
241+
}
214242
}?;
215243
debug!("Interface: {}", &interface.name);
216244

0 commit comments

Comments
 (0)