diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 1f2ad445d..2f55d64d0 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1791,8 +1791,10 @@ dependencies = [ "libc", "netlink-packet-core", "netlink-packet-route", + "nix 0.28.0", "ring", "rtnetlink", + "socket-factory", "tokio", "tracing", "tracing-log", diff --git a/rust/bin-shared/Cargo.toml b/rust/bin-shared/Cargo.toml index b477648f0..f608d1f62 100644 --- a/rust/bin-shared/Cargo.toml +++ b/rust/bin-shared/Cargo.toml @@ -25,7 +25,9 @@ tokio = { workspace = true, features = ["macros"] } libc = "0.2" netlink-packet-core = { version = "0.7", default-features = false } netlink-packet-route = { version = "0.19", default-features = false } +nix = { version = "0.28.0", features = ["socket"] } rtnetlink = { workspace = true } +socket-factory = { workspace = true } zbus = "4.4" # Can't use `zbus`'s `tokio` feature here, or it will break toast popups all the way over in `gui-client`. [target.'cfg(windows)'.dependencies] diff --git a/rust/bin-shared/src/linux.rs b/rust/bin-shared/src/linux.rs index d15e54fd9..46894206c 100644 --- a/rust/bin-shared/src/linux.rs +++ b/rust/bin-shared/src/linux.rs @@ -1,3 +1,9 @@ +use std::{io, net::SocketAddr}; + +use crate::FIREZONE_MARK; +use nix::sys::socket::{setsockopt, sockopt}; +use socket_factory::{TcpSocket, UdpSocket}; + const FIREZONE_DNS_CONTROL: &str = "FIREZONE_DNS_CONTROL"; #[derive(Clone, Copy, Debug)] @@ -29,3 +35,15 @@ impl DnsControlMethod { } } } + +pub fn tcp_socket_factory(socket_addr: &SocketAddr) -> io::Result { + let socket = socket_factory::tcp(socket_addr)?; + setsockopt(&socket, sockopt::Mark, &FIREZONE_MARK)?; + Ok(socket) +} + +pub fn udp_socket_factory(socket_addr: &SocketAddr) -> io::Result { + let socket = socket_factory::udp(socket_addr)?; + setsockopt(&socket, sockopt::Mark, &FIREZONE_MARK)?; + Ok(socket) +} diff --git a/rust/connlib/tunnel/src/lib.rs b/rust/connlib/tunnel/src/lib.rs index bade48966..379012b19 100644 --- a/rust/connlib/tunnel/src/lib.rs +++ b/rust/connlib/tunnel/src/lib.rs @@ -180,9 +180,13 @@ impl ClientTunnel { } impl GatewayTunnel { - pub fn new(private_key: StaticSecret) -> std::io::Result { + pub fn new( + private_key: StaticSecret, + tcp_socket_factory: Arc>, + udp_socket_factory: Arc>, + ) -> std::io::Result { Ok(Self { - io: Io::new(Arc::new(socket_factory::tcp), Arc::new(socket_factory::udp))?, + io: Io::new(tcp_socket_factory, udp_socket_factory)?, role_state: GatewayState::new(private_key, rand::random()), write_buf: Box::new([0u8; DEFAULT_MTU + 20 + 16]), ip4_read_buf: Box::new([0u8; MAX_UDP_SIZE]), diff --git a/rust/gateway/src/main.rs b/rust/gateway/src/main.rs index 467529640..9e99cde4d 100644 --- a/rust/gateway/src/main.rs +++ b/rust/gateway/src/main.rs @@ -3,7 +3,10 @@ use anyhow::{Context, Result}; use backoff::ExponentialBackoffBuilder; use clap::Parser; use connlib_shared::{get_user_agent, keypair, messages::Interface, LoginUrl, StaticSecret}; -use firezone_bin_shared::{setup_global_subscriber, TunDeviceManager}; +use firezone_bin_shared::{ + linux::{tcp_socket_factory, udp_socket_factory}, + setup_global_subscriber, TunDeviceManager, +}; use firezone_tunnel::{GatewayTunnel, IPV4_PEERS, IPV6_PEERS}; use futures::channel::mpsc; @@ -98,7 +101,11 @@ async fn get_firezone_id(env_id: Option) -> Result { } async fn run(login: LoginUrl, private_key: StaticSecret) -> Result { - let mut tunnel = GatewayTunnel::new(private_key)?; + let mut tunnel = GatewayTunnel::new( + private_key, + Arc::new(tcp_socket_factory), + Arc::new(udp_socket_factory), + )?; let portal = PhoenixChannel::connect( Secret::new(login), get_user_agent(None, env!("CARGO_PKG_VERSION")), @@ -107,7 +114,7 @@ async fn run(login: LoginUrl, private_key: StaticSecret) -> Result { ExponentialBackoffBuilder::default() .with_max_elapsed_time(None) .build(), - Arc::new(socket_factory::tcp), + Arc::new(tcp_socket_factory), )?; let (sender, receiver) = mpsc::channel::(10); diff --git a/rust/headless-client/src/linux.rs b/rust/headless-client/src/linux.rs index 390b94c82..5f7b778c0 100644 --- a/rust/headless-client/src/linux.rs +++ b/rust/headless-client/src/linux.rs @@ -2,36 +2,20 @@ use super::TOKEN_ENV_KEY; use anyhow::{bail, Result}; -use firezone_bin_shared::{BUNDLE_ID, FIREZONE_MARK}; -use nix::sys::socket::{setsockopt, sockopt}; -use socket_factory::{TcpSocket, UdpSocket}; -use std::{ - io, - net::SocketAddr, - path::{Path, PathBuf}, -}; +use firezone_bin_shared::BUNDLE_ID; +use std::path::{Path, PathBuf}; // The Client currently must run as root to control DNS // Root group and user are used to check file ownership on the token const ROOT_GROUP: u32 = 0; const ROOT_USER: u32 = 0; -pub(crate) fn tcp_socket_factory(socket_addr: &SocketAddr) -> io::Result { - let socket = socket_factory::tcp(socket_addr)?; - setsockopt(&socket, sockopt::Mark, &FIREZONE_MARK)?; - Ok(socket) -} - -pub(crate) fn udp_socket_factory(socket_addr: &SocketAddr) -> io::Result { - let socket = socket_factory::udp(socket_addr)?; - setsockopt(&socket, sockopt::Mark, &FIREZONE_MARK)?; - Ok(socket) -} - pub(crate) fn default_token_path() -> PathBuf { PathBuf::from("/etc").join(BUNDLE_ID).join("token") } +pub use firezone_bin_shared::linux::{tcp_socket_factory, udp_socket_factory}; + pub(crate) fn check_token_permissions(path: &Path) -> Result<()> { let Ok(stat) = nix::sys::stat::fstatat(None, path, nix::fcntl::AtFlags::empty()) else { // File doesn't exist or can't be read