Restrict namespace arguments to Linux

This commit is contained in:
B. Blechschmidt 2024-04-07 21:12:20 +02:00
parent af6a8a3cb0
commit e8469f0aee
3 changed files with 39 additions and 29 deletions

View file

@ -1,9 +1,10 @@
use crate::{Error, Result}; use crate::{Error, Result};
use socks5_impl::protocol::UserKey; use socks5_impl::protocol::UserKey;
use std::{
ffi::OsString, #[cfg(target_os = "linux")]
net::{IpAddr, SocketAddr, ToSocketAddrs}, use std::ffi::OsString;
};
use std::net::{IpAddr, SocketAddr, ToSocketAddrs};
#[derive(Debug, Clone, clap::Parser)] #[derive(Debug, Clone, clap::Parser)]
#[command(author, version, about = "Tunnel interface to proxy.", long_about = None)] #[command(author, version, about = "Tunnel interface to proxy.", long_about = None)]
@ -25,17 +26,21 @@ pub struct Args {
/// Create a tun interface in a newly created unprivileged namespace /// Create a tun interface in a newly created unprivileged namespace
/// while maintaining proxy connectivity via the global network namespace. /// while maintaining proxy connectivity via the global network namespace.
#[cfg(target_os = "linux")]
#[arg(long)] #[arg(long)]
pub unshare: bool, pub unshare: bool,
/// File descriptor for UNIX datagram socket meant to transfer /// File descriptor for UNIX datagram socket meant to transfer
/// network sockets from global namespace to the new one. /// network sockets from global namespace to the new one.
/// See `unshare(1)`, `namespaces(7)`, `sendmsg(2)`, `unix(7)`. /// See `unshare(1)`, `namespaces(7)`, `sendmsg(2)`, `unix(7)`.
#[arg(long, value_name = "fd")] #[cfg(target_os = "linux")]
#[arg(long, value_name = "fd", hide(true))]
pub socket_transfer_fd: Option<i32>, pub socket_transfer_fd: Option<i32>,
/// Specify a command to run with root-like capabilities in the new namespace. /// Specify a command to run with root-like capabilities in the new namespace
/// when using `--unshare`.
/// This could be useful to start additional daemons, e.g. `openvpn` instance. /// This could be useful to start additional daemons, e.g. `openvpn` instance.
#[cfg(target_os = "linux")]
#[arg(requires = "unshare")] #[arg(requires = "unshare")]
pub admin_command: Vec<OsString>, pub admin_command: Vec<OsString>,
@ -91,8 +96,11 @@ impl Default for Args {
proxy: ArgProxy::default(), proxy: ArgProxy::default(),
tun: None, tun: None,
tun_fd: None, tun_fd: None,
#[cfg(target_os = "linux")]
unshare: false, unshare: false,
#[cfg(target_os = "linux")]
socket_transfer_fd: None, socket_transfer_fd: None,
#[cfg(target_os = "linux")]
admin_command: Vec::new(), admin_command: Vec::new(),
ipv6_enabled: false, ipv6_enabled: false,
setup, setup,

View file

@ -13,14 +13,15 @@ async fn main() -> Result<(), BoxError> {
let join_handle = tokio::spawn({ let join_handle = tokio::spawn({
let shutdown_token = shutdown_token.clone(); let shutdown_token = shutdown_token.clone();
async move { async move {
if args.unshare && args.socket_transfer_fd.is_none() {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
if args.unshare && args.socket_transfer_fd.is_none() {
if let Err(err) = namespace_proxy_main(args, shutdown_token).await { if let Err(err) = namespace_proxy_main(args, shutdown_token).await {
log::error!("namespace proxy error: {}", err); log::error!("namespace proxy error: {}", err);
} }
#[cfg(not(target_os = "linux"))] return;
log::error!("Your platform doesn't support unprivileged namespaces"); }
} else if let Err(err) = tun2proxy::desktop_run_async(args, shutdown_token).await {
if let Err(err) = tun2proxy::desktop_run_async(args, shutdown_token).await {
log::error!("main loop error: {}", err); log::error!("main loop error: {}", err);
} }
} }

View file

@ -149,6 +149,7 @@ pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::Can
run_ip_util(format!("-6 route delete 80::/1 dev {}", tproxy_args.tun_name)); run_ip_util(format!("-6 route delete 80::/1 dev {}", tproxy_args.tun_name));
} }
#[cfg(target_os = "linux")]
if setup && args.unshare { if setup && args.unshare {
// New namespace doesn't have any other routing device by default // New namespace doesn't have any other routing device by default
// So our `tun` device should act as such to make space for other proxies. // So our `tun` device should act as such to make space for other proxies.
@ -164,7 +165,6 @@ pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::Can
run_ip_util(format!("-6 route add ::/0 dev {}", tproxy_args.tun_name)); run_ip_util(format!("-6 route add ::/0 dev {}", tproxy_args.tun_name));
} }
} }
}
let mut admin_command_args = args.admin_command.iter(); let mut admin_command_args = args.admin_command.iter();
if let Some(command) = admin_command_args.next() { if let Some(command) = admin_command_args.next() {
@ -186,6 +186,7 @@ pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::Can
} }
}; };
} }
}
let join_handle = tokio::spawn(crate::run(device, MTU, args, shutdown_token)); let join_handle = tokio::spawn(crate::run(device, MTU, args, shutdown_token));
join_handle.await.map_err(std::io::Error::from)??; join_handle.await.map_err(std::io::Error::from)??;