Skip to content

Commit d28845d

Browse files
authored
Merge pull request #242 from jamesmcm/create_netns_only
Add create-netns-only argument for debugging + firejail usage
2 parents 688cbe3 + 18ea6c2 commit d28845d

File tree

5 files changed

+72
-33
lines changed

5 files changed

+72
-33
lines changed

USERGUIDE.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,22 @@ entire shell sessions inside vopono.
2121
Note that the order of command-line arguments matters, as the `--dns`
2222
argument can take a list of DNS servers for example.
2323

24+
### Creating only Network Namespace
25+
26+
You can run vopono to create only the network namespace using the
27+
`--create-netns-only` argument, the application related arguments are
28+
then ignored (pass anything as the application name). This can be useful
29+
for debugging connection issues.
30+
31+
This can also be used to launch an application without sudo via firejail
32+
- e.g. (where `none` is passed as the dummy application):
33+
34+
```bash
35+
$ vopono -v exec --provider protonvpn --server japan --protocol openvpn --create-netns-only none
36+
2023-11-26T11:17:52.623Z INFO vopono::exec > Created netns vo_pr_japan - will leave network namespace alive until ctrl+C received
37+
$ firejail --netns=vo_pr_japan firefox-developer-edition
38+
```
39+
2440
### Configuration file
2541
2642
You can save default configuration options in the config file

src/args.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@ pub struct ExecCommand {
216216
/// Enable port forwarding for ProtonVPN connections
217217
#[clap(long = "protonvpn-port-forwarding")]
218218
pub protonvpn_port_forwarding: bool,
219+
220+
/// Only create network namespace (does not run application)
221+
#[clap(long = "create-netns-only")]
222+
pub create_netns_only: bool,
219223
}
220224

221225
#[derive(Parser)]

src/exec.rs

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,17 @@ pub fn exec(command: ExecCommand, uiclient: &dyn UiClient) -> anyhow::Result<()>
150150
command.protonvpn_port_forwarding
151151
};
152152

153+
// Create netns only
154+
let create_netns_only = if !command.create_netns_only {
155+
vopono_config_settings
156+
.get("create-netns-only")
157+
.map_err(|_e| anyhow!("Failed to read config file"))
158+
.ok()
159+
.unwrap_or(false)
160+
} else {
161+
command.create_netns_only
162+
};
163+
153164
// Assign DNS server from args or vopono config file
154165
let base_dns = command.dns.clone().or_else(|| {
155166
vopono_config_settings
@@ -551,15 +562,6 @@ pub fn exec(command: ExecCommand, uiclient: &dyn UiClient) -> anyhow::Result<()>
551562
vopono_core::util::open_ports(&ns, &[pmpc.local_port], firewall)?;
552563
}
553564

554-
let application = ApplicationWrapper::new(
555-
&ns,
556-
&command.application,
557-
user,
558-
group,
559-
working_directory.map(PathBuf::from),
560-
natpmpc,
561-
)?;
562-
563565
// Launch TCP proxy server on other threads if forwarding ports
564566
// TODO: Fix when running as root
565567
let mut proxy = Vec::new();
@@ -580,27 +582,46 @@ pub fn exec(command: ExecCommand, uiclient: &dyn UiClient) -> anyhow::Result<()>
580582
}
581583
}
582584

583-
let pid = application.handle.id();
584-
info!(
585-
"Application {} launched in network namespace {} with pid {}",
586-
&command.application, &ns.name, pid
587-
);
585+
if !create_netns_only {
586+
let application = ApplicationWrapper::new(
587+
&ns,
588+
&command.application,
589+
user,
590+
group,
591+
working_directory.map(PathBuf::from),
592+
natpmpc,
593+
)?;
588594

589-
if let Some(pmpc) = application.protonvpn_port_forwarding.as_ref() {
590-
info!("ProtonVPN Port Forwarding on port {}", pmpc.local_port)
591-
}
592-
let output = application.wait_with_output()?;
593-
io::stdout().write_all(output.stdout.as_slice())?;
595+
let pid = application.handle.id();
596+
info!(
597+
"Application {} launched in network namespace {} with pid {}",
598+
&command.application, &ns.name, pid
599+
);
594600

595-
// Allow daemons to leave namespace open
596-
if vopono_core::util::check_process_running(pid) {
601+
if let Some(pmpc) = application.protonvpn_port_forwarding.as_ref() {
602+
info!("ProtonVPN Port Forwarding on port {}", pmpc.local_port)
603+
}
604+
let output = application.wait_with_output()?;
605+
io::stdout().write_all(output.stdout.as_slice())?;
606+
607+
// Allow daemons to leave namespace open
608+
if vopono_core::util::check_process_running(pid) {
609+
info!(
610+
"Process {} still running, assumed to be daemon - will leave network namespace {} alive until ctrl+C received",
611+
pid, &ns.name
612+
);
613+
stay_alive(Some(pid), signals);
614+
} else if command.keep_alive {
615+
info!(
616+
"Keep-alive flag active - will leave network namespace {} alive until ctrl+C received", &ns.name
617+
);
618+
stay_alive(None, signals);
619+
}
620+
} else {
597621
info!(
598-
"Process {} still running, assumed to be daemon - will leave network namespace alive until ctrl+C received",
599-
pid
622+
"Created netns {} - will leave network namespace alive until ctrl+C received",
623+
&ns.name
600624
);
601-
stay_alive(Some(pid), signals);
602-
} else if command.keep_alive {
603-
info!("Keep-alive flag active - will leave network namespace alive until ctrl+C received");
604625
stay_alive(None, signals);
605626
}
606627

vopono_core/src/network/shadowsocks.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use log::{debug, error};
1616
use rand::seq::SliceRandom;
1717
use regex::Regex;
1818
use serde::{Deserialize, Serialize};
19-
use std::convert::TryFrom;
2019
use std::fs::read_to_string;
2120
use std::net::{IpAddr, Ipv4Addr};
2221
use std::path::Path;
@@ -95,9 +94,9 @@ pub fn uses_shadowsocks(openvpn_config: &Path) -> anyhow::Result<Option<(IpAddr,
9594
}
9695
debug!("socks-proxy detected, will launch Shadowsocks server");
9796
Ok(Some((
98-
IpAddr::try_from(Ipv4Addr::from_str(
97+
IpAddr::from(Ipv4Addr::from_str(
9998
cap.as_ref().unwrap().get(1).unwrap().as_str(),
100-
)?)?,
99+
)?),
101100
cap.unwrap().get(2).unwrap().as_str().parse::<u16>()?,
102101
)))
103102
}
@@ -113,9 +112,9 @@ pub fn get_routes_from_config(path: &Path) -> anyhow::Result<Vec<IpAddr>> {
113112
let caps = re.captures_iter(&file_string);
114113

115114
for cap in caps {
116-
output_vec.push(IpAddr::try_from(Ipv4Addr::from_str(
115+
output_vec.push(IpAddr::from(Ipv4Addr::from_str(
117116
cap.get(1).unwrap().as_str(),
118-
)?)?);
117+
)?));
119118
}
120119

121120
if output_vec.is_empty() {

vopono_core/src/util/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,7 @@ pub fn elevate_privileges(askpass: bool) -> anyhow::Result<()> {
353353
.status()
354354
.context(format!("Executing sudo {} {:?}", sudo_flags, &args))?;
355355

356-
// Deprecated - do we need to handle flag here?
357-
// cleanup::cleanup_signal(SIGINT)?;
356+
// TODO: Could handle executing with non-sudo firejail here
358357

359358
if terminated.load(Ordering::SeqCst) {
360359
// we received a sigint,

0 commit comments

Comments
 (0)