diff --git a/Cargo.toml b/Cargo.toml index 351c083..59eacd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "vopono" description = "Launch applications via VPN tunnels using temporary network namespaces" -version = "0.7.0" +version = "0.7.1" authors = ["James McMurray "] edition = "2018" license = "GPL-3.0-or-later" @@ -34,7 +34,7 @@ chrono = "0.4" compound_duration = "1" ipnet = {version = "2", features = ["serde"]} reqwest = {default-features = false, version = "0.11", features = ["blocking", "json", "rustls-tls"]} -sysinfo = "0.16" +sysinfo = "0.17" base64 = "0.13" x25519-dalek = "1" strum = "0.20" diff --git a/USERGUIDE.md b/USERGUIDE.md index 7016529..ea6fc03 100644 --- a/USERGUIDE.md +++ b/USERGUIDE.md @@ -18,6 +18,9 @@ Note that child processes of the application will also be spawned inside the network namespace and so use the same VPN connection, so you can run entire shell sessions inside vopono. +Note that the order of command-line arguments matters, as the `--dns` +argument can take a list of DNS servers for example. + ### Configuration file You can save default configuration options in the config file @@ -34,6 +37,7 @@ server = "usa-us22" postup = "/home/archie/postup.sh" predown = "/home/archie/predown.sh" user = "archie" +dns = "8.8.8.8" # custom_config = "/home/user/vpn/mycustomconfig.ovpn" ``` @@ -41,6 +45,10 @@ Note that the values are case-sensitive. If you use a custom config file then you should not set the provider or server (setting the protocol is also optional). +The current network namespace name is provided to the PostUp and PreDown +scripts in the environment variable `$VOPONO_NS`. It is temporarily set +when running these scripts only. + ### Host scripts Host scripts to run just after a network namespace is created and just before it is destroyed, diff --git a/src/exec.rs b/src/exec.rs index 820d25c..63c895c 100644 --- a/src/exec.rs +++ b/src/exec.rs @@ -98,6 +98,17 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> { command.user }; + // Assign DNS server from args or vopono config file + let base_dns = command.dns.clone().or_else(|| { + vopono_config_settings + .get("dns") + .map_err(|e| { + debug!("vopono config.toml: {:?}", e); + anyhow!("Failed to read config file") + }) + .ok() + }); + // Assign protocol and server from args or vopono config file or custom config if used if let Some(path) = &custom_config { protocol = command @@ -254,8 +265,7 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> { None }; - let dns = command - .dns + let dns = base_dns .clone() .or_else(|| { provider @@ -266,7 +276,6 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> { }) .unwrap_or_else(|| vec![IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))]); - // TODO: Don't rely on Google DNS here - could copy local one? ns.dns_config(&dns)?; // Check if using Shadowsocks if let Some((ss_host, ss_lport)) = @@ -313,7 +322,7 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> { } // Set DNS with OpenVPN server response if present - if command.dns.is_none() { + if base_dns.is_none() { if let Some(newdns) = ns.openvpn.as_ref().unwrap().openvpn_dns { let old_dns = ns.dns_config.take(); std::mem::forget(old_dns); @@ -329,13 +338,11 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> { command.forward_ports.as_ref(), firewall, command.disable_ipv6, - command.dns.as_ref(), + base_dns.as_ref(), )?; } Protocol::OpenConnect => { - let dns = command - .dns - .unwrap_or_else(|| vec![IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))]); + let dns = base_dns.unwrap_or_else(|| vec![IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))]); ns.dns_config(&dns)?; ns.run_openconnect( config_file, @@ -348,7 +355,9 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> { } // Run PostUp script (if any) + // Temporarily set env var referring to this network namespace name if let Some(pucmd) = postup { + std::env::set_var("VOPONO_NS", &ns.name); if user.is_some() { std::process::Command::new("sudo") .args(&["-Eu", user.as_ref().unwrap(), &pucmd]) @@ -356,6 +365,7 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> { } else { std::process::Command::new(&pucmd).spawn()?; } + std::env::remove_var("VOPONO_NS"); } } diff --git a/src/netns.rs b/src/netns.rs index 30e8a4f..2d08aea 100644 --- a/src/netns.rs +++ b/src/netns.rs @@ -396,6 +396,7 @@ impl Drop for NetworkNamespace { info!("Shutting down vopono namespace - as there are no processes left running inside"); // Run PreDown script (if any) if let Some(pdcmd) = self.predown.as_ref() { + std::env::set_var("VOPONO_NS", &self.name); if self.predown_user.is_some() { std::process::Command::new("sudo") .args(&["-Eu", self.predown_user.as_ref().unwrap(), &pdcmd]) @@ -404,6 +405,7 @@ impl Drop for NetworkNamespace { } else { std::process::Command::new(&pdcmd).spawn().ok(); } + std::env::remove_var("VOPONO_NS"); } self.openvpn = None;