mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 18:18:55 +00:00
refactor(connlib): move TunDeviceManager into firezone-bin-shared (#5843)
The `TunDeviceManager` is a component that the leaf-nodes of our dependency tree need: the binaries. Thus, it is misplaced in the `connlib-shared` crate which is at the very bottom of the dependency tree. This is necessary to allow the `TunDeviceManager` to actually construct a `Tun` (which currently lives in `firezone-tunnel`). Related: #5839. --------- Signed-off-by: Thomas Eizinger <thomas@eizinger.io> Co-authored-by: Reactor Scram <ReactorScram@users.noreply.github.com>
This commit is contained in:
22
rust/Cargo.lock
generated
22
rust/Cargo.lock
generated
@@ -1136,15 +1136,12 @@ dependencies = [
|
||||
"known-folders",
|
||||
"libc",
|
||||
"log",
|
||||
"netlink-packet-core",
|
||||
"netlink-packet-route",
|
||||
"os_info",
|
||||
"phoenix-channel",
|
||||
"proptest",
|
||||
"rand 0.8.5",
|
||||
"rand_core 0.6.4",
|
||||
"ring",
|
||||
"rtnetlink",
|
||||
"secrecy",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -1831,14 +1828,23 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "firezone-cli-utils"
|
||||
name = "firezone-bin-shared"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"connlib-shared",
|
||||
"futures",
|
||||
"ip_network",
|
||||
"netlink-packet-core",
|
||||
"netlink-packet-route",
|
||||
"rtnetlink",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-log",
|
||||
"tracing-subscriber",
|
||||
"url",
|
||||
"windows 0.57.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1855,7 +1861,7 @@ dependencies = [
|
||||
"dns-lookup",
|
||||
"domain",
|
||||
"either",
|
||||
"firezone-cli-utils",
|
||||
"firezone-bin-shared",
|
||||
"firezone-tunnel",
|
||||
"futures",
|
||||
"futures-bounded",
|
||||
@@ -1939,7 +1945,7 @@ dependencies = [
|
||||
"connlib-client-shared",
|
||||
"connlib-shared",
|
||||
"dirs",
|
||||
"firezone-cli-utils",
|
||||
"firezone-bin-shared",
|
||||
"futures",
|
||||
"git-version",
|
||||
"humantime",
|
||||
@@ -2024,6 +2030,7 @@ dependencies = [
|
||||
"connlib-shared",
|
||||
"derivative",
|
||||
"domain",
|
||||
"firezone-bin-shared",
|
||||
"firezone-relay",
|
||||
"futures",
|
||||
"futures-bounded",
|
||||
@@ -2037,8 +2044,6 @@ dependencies = [
|
||||
"itertools 0.13.0",
|
||||
"libc",
|
||||
"log",
|
||||
"netlink-packet-core",
|
||||
"netlink-packet-route",
|
||||
"pretty_assertions",
|
||||
"proptest",
|
||||
"proptest-state-machine",
|
||||
@@ -2046,7 +2051,6 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"rand_core 0.6.4",
|
||||
"rangemap",
|
||||
"rtnetlink",
|
||||
"secrecy",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@@ -7,7 +7,7 @@ members = [
|
||||
"connlib/tunnel",
|
||||
"connlib/snownet",
|
||||
"gateway",
|
||||
"firezone-cli-utils",
|
||||
"bin-shared",
|
||||
"gui-smoke-test",
|
||||
"headless-client",
|
||||
"snownet-tests",
|
||||
@@ -45,7 +45,7 @@ connlib-client-shared = { path = "connlib/clients/shared"}
|
||||
firezone-gateway = { path = "gateway"}
|
||||
firezone-headless-client = { path = "headless-client"}
|
||||
firezone-gui-client = { path = "gui-client/src-tauri"}
|
||||
firezone-cli-utils = { path = "firezone-cli-utils"}
|
||||
firezone-bin-shared = { path = "bin-shared"}
|
||||
snownet = { path = "connlib/snownet"}
|
||||
firezone-relay = { path = "relay"}
|
||||
connlib-shared = { path = "connlib/shared"}
|
||||
|
||||
33
rust/bin-shared/Cargo.toml
Normal file
33
rust/bin-shared/Cargo.toml
Normal file
@@ -0,0 +1,33 @@
|
||||
[package]
|
||||
name = "firezone-bin-shared"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "Firezone-specific modules shared between binaries."
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.82"
|
||||
clap = { version = "4.5", features = ["derive", "env"] }
|
||||
connlib-shared = { workspace = true }
|
||||
futures = "0.3"
|
||||
ip_network = { version = "0.4", default-features = false, features = ["serde"] }
|
||||
tokio = { workspace = true, features = ["rt"] }
|
||||
tracing = { workspace = true }
|
||||
tracing-log = "0.2"
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||
url = { version = "2.3.1", default-features = false }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
netlink-packet-core = { version = "0.7", default-features = false }
|
||||
netlink-packet-route = { version = "0.19", default-features = false }
|
||||
rtnetlink = { workspace = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.57.0"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -1,3 +1,5 @@
|
||||
mod tun_device_manager;
|
||||
|
||||
use clap::Args;
|
||||
use tracing_log::LogTracer;
|
||||
use tracing_subscriber::{
|
||||
@@ -5,6 +7,9 @@ use tracing_subscriber::{
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
pub use tun_device_manager::TunDeviceManager;
|
||||
|
||||
pub fn setup_global_subscriber<L>(additional_layer: L)
|
||||
where
|
||||
L: Layer<Registry> + Send + Sync,
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Virtual network interface
|
||||
|
||||
use crate::DEFAULT_MTU;
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use connlib_shared::DEFAULT_MTU;
|
||||
use futures::TryStreamExt;
|
||||
use ip_network::{IpNetwork, Ipv4Network, Ipv6Network};
|
||||
use netlink_packet_route::route::{RouteProtocol, RouteScope};
|
||||
@@ -12,8 +12,7 @@ use std::{
|
||||
net::{Ipv4Addr, Ipv6Addr},
|
||||
};
|
||||
|
||||
pub const FIREZONE_MARK: u32 = 0xfd002021;
|
||||
pub const IFACE_NAME: &str = "tun-firezone";
|
||||
const FIREZONE_MARK: u32 = 0xfd002021; // Keep this synced with `Sockets` until #5797.
|
||||
const FILE_ALREADY_EXISTS: i32 = -17;
|
||||
const FIREZONE_TABLE: u32 = 0x2021_fd00;
|
||||
|
||||
@@ -35,6 +34,8 @@ impl Drop for TunDeviceManager {
|
||||
}
|
||||
|
||||
impl TunDeviceManager {
|
||||
pub const IFACE_NAME: &'static str = "tun-firezone"; // Keep this synced with `Tun` until we fix the module dependencies (i.e. move `Tun` out of `firezone-tunnel`).
|
||||
|
||||
/// Creates a new managed tunnel device.
|
||||
///
|
||||
/// Panics if called without a Tokio runtime.
|
||||
@@ -51,15 +52,17 @@ impl TunDeviceManager {
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
pub async fn set_ips(&mut self, ipv4: Ipv4Addr, ipv6: Ipv6Addr) -> Result<()> {
|
||||
let name = Self::IFACE_NAME;
|
||||
|
||||
let handle = &self.connection.handle;
|
||||
let index = handle
|
||||
.link()
|
||||
.get()
|
||||
.match_name(IFACE_NAME.to_string())
|
||||
.match_name(name.to_string())
|
||||
.execute()
|
||||
.try_next()
|
||||
.await?
|
||||
.ok_or_else(|| anyhow!("Interface '{IFACE_NAME}' does not exist"))?
|
||||
.ok_or_else(|| anyhow!("Interface '{name}' does not exist"))?
|
||||
.header
|
||||
.index;
|
||||
|
||||
@@ -139,6 +142,7 @@ impl TunDeviceManager {
|
||||
.map(IpNetwork::from)
|
||||
.chain(ipv6.into_iter().map(IpNetwork::from))
|
||||
.collect();
|
||||
|
||||
if new_routes == self.routes {
|
||||
tracing::debug!("Routes are unchanged");
|
||||
|
||||
@@ -152,7 +156,7 @@ impl TunDeviceManager {
|
||||
let index = handle
|
||||
.link()
|
||||
.get()
|
||||
.match_name(IFACE_NAME.to_string())
|
||||
.match_name(Self::IFACE_NAME.to_string())
|
||||
.execute()
|
||||
.try_next()
|
||||
.await?
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::windows::{CREATE_NO_WINDOW, TUNNEL_NAME};
|
||||
use anyhow::Result;
|
||||
use connlib_shared::windows::{CREATE_NO_WINDOW, TUNNEL_NAME};
|
||||
use ip_network::{Ipv4Network, Ipv6Network};
|
||||
use std::{
|
||||
net::{Ipv4Addr, Ipv6Addr},
|
||||
@@ -44,11 +44,6 @@ tokio = { version = "1.38", features = ["macros", "rt"] }
|
||||
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies]
|
||||
swift-bridge = { workspace = true }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
netlink-packet-route = { version = "0.19", default-features = false }
|
||||
netlink-packet-core = { version = "0.7", default-features = false }
|
||||
rtnetlink = { workspace = true }
|
||||
|
||||
# Windows tunnel dependencies
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
wintun = "0.4.0"
|
||||
|
||||
@@ -27,14 +27,6 @@ pub enum ConnlibError {
|
||||
/// Glob for errors without a type.
|
||||
#[error("Other error: {0}")]
|
||||
Other(&'static str),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[error(transparent)]
|
||||
NetlinkError(rtnetlink::Error),
|
||||
/// Io translation of netlink error
|
||||
/// The IO version is easier to interpret
|
||||
/// We maintain a different variant from the standard IO for this to keep more context
|
||||
#[error("IO netlink error: {0}")]
|
||||
NetlinkErrorIo(std::io::Error),
|
||||
/// No iface found
|
||||
#[error("No iface found")]
|
||||
NoIface,
|
||||
@@ -89,14 +81,3 @@ pub enum ConnlibError {
|
||||
#[error("connection to the portal failed: {0}")]
|
||||
PortalConnectionFailed(phoenix_channel::Error),
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl From<rtnetlink::Error> for ConnlibError {
|
||||
fn from(err: rtnetlink::Error) -> Self {
|
||||
#[allow(clippy::wildcard_enum_match_arm)]
|
||||
match err {
|
||||
rtnetlink::Error::NetlinkError(err) => Self::NetlinkErrorIo(err.to_io()),
|
||||
err => Self::NetlinkError(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
pub mod callbacks;
|
||||
pub mod error;
|
||||
pub mod messages;
|
||||
pub mod tun_device_manager;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub mod windows;
|
||||
|
||||
@@ -50,6 +50,9 @@ hickory-proto = { workspace = true }
|
||||
derivative = "2.2.0"
|
||||
ip-packet = { workspace = true, features = ["proptest"] }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dev-dependencies]
|
||||
firezone-bin-shared = { workspace = true } # Required for benchmark.
|
||||
|
||||
[[bench]]
|
||||
name = "tunnel"
|
||||
harness = false
|
||||
@@ -57,12 +60,6 @@ harness = false
|
||||
[features]
|
||||
proptest = ["dep:proptest", "connlib-shared/proptest"]
|
||||
|
||||
# Linux tunnel dependencies
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
netlink-packet-route = { version = "0.19", default-features = false }
|
||||
netlink-packet-core = { version = "0.7", default-features = false }
|
||||
rtnetlink = { workspace = true }
|
||||
|
||||
# Windows tunnel dependencies
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
tokio = { workspace = true, features = ["sync"] }
|
||||
|
||||
@@ -26,6 +26,7 @@ mod platform {
|
||||
#[cfg(target_os = "windows")]
|
||||
mod platform {
|
||||
use anyhow::Result;
|
||||
use firezone_bin_shared::TunDeviceManager;
|
||||
use firezone_tunnel::Tun;
|
||||
use ip_packet::{IpPacket, Packet as _};
|
||||
use std::{
|
||||
@@ -59,8 +60,7 @@ mod platform {
|
||||
|
||||
let ipv4 = Ipv4Addr::from([100, 90, 215, 97]);
|
||||
let ipv6 = Ipv6Addr::from([0xfd00, 0x2021, 0x1111, 0x0, 0x0, 0x0, 0x0016, 0x588f]);
|
||||
let mut device_manager =
|
||||
connlib_shared::tun_device_manager::platform::TunDeviceManager::new()?;
|
||||
let mut device_manager = TunDeviceManager::new()?;
|
||||
device_manager.set_ips(ipv4, ipv6).await?;
|
||||
tun.add_route(ipv4.into())?;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::utils;
|
||||
use crate::device_channel::ioctl;
|
||||
use connlib_shared::{tun_device_manager::platform::IFACE_NAME, Callbacks, Error, Result};
|
||||
use connlib_shared::{Callbacks, Error, Result};
|
||||
use ip_network::IpNetwork;
|
||||
use libc::{
|
||||
close, fcntl, makedev, mknod, open, F_GETFL, F_SETFL, IFF_NO_PI, IFF_TUN, O_NONBLOCK, O_RDWR,
|
||||
@@ -22,6 +22,7 @@ use tokio::io::unix::AsyncFd;
|
||||
const TUNSETIFF: libc::c_ulong = 0x4004_54ca;
|
||||
const TUN_DEV_MAJOR: u32 = 10;
|
||||
const TUN_DEV_MINOR: u32 = 200;
|
||||
const IFACE_NAME: &str = "tun-firezone"; // Keep this synced with `TunDeviceManager` until we fix the module dependencies (i.e. move `Tun` out of `firezone-tunnel`).
|
||||
|
||||
// Safety: We know that this is a valid C string.
|
||||
const TUN_FILE: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"/dev/net/tun\0") };
|
||||
|
||||
@@ -339,7 +339,9 @@ fn make_socket(addr: impl Into<SocketAddr>) -> Result<std::net::UdpSocket> {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
socket.set_mark(connlib_shared::tun_device_manager::platform::FIREZONE_MARK)?;
|
||||
const FIREZONE_MARK: u32 = 0xfd002021; // Keep this synced with `TunDeviceManager` until #5797.
|
||||
|
||||
socket.set_mark(FIREZONE_MARK)?;
|
||||
}
|
||||
|
||||
// Note: for AF_INET sockets IPV6_V6ONLY is not a valid flag
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
[package]
|
||||
name = "firezone-cli-utils"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
url = { version = "2.3.1", default-features = false }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||
tracing = { workspace = true }
|
||||
tracing-log = "0.2"
|
||||
clap = { version = "4.5", features = ["derive", "env"] }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -17,7 +17,7 @@ connlib-shared = { workspace = true }
|
||||
firezone-tunnel = { workspace = true }
|
||||
futures = "0.3.29"
|
||||
futures-bounded = { workspace = true }
|
||||
firezone-cli-utils = { workspace = true }
|
||||
firezone-bin-shared = { workspace = true }
|
||||
phoenix-channel = { workspace = true }
|
||||
secrecy = { workspace = true }
|
||||
serde = { version = "1.0", default-features = false, features = ["std", "derive"] }
|
||||
|
||||
@@ -2,10 +2,10 @@ use crate::eventloop::{Eventloop, PHOENIX_TOPIC};
|
||||
use anyhow::{Context, Result};
|
||||
use backoff::ExponentialBackoffBuilder;
|
||||
use clap::Parser;
|
||||
use connlib_shared::messages::Interface;
|
||||
use connlib_shared::tun_device_manager::TunDeviceManager;
|
||||
use connlib_shared::{get_user_agent, keypair, Callbacks, LoginUrl, StaticSecret};
|
||||
use firezone_cli_utils::{setup_global_subscriber, CommonArgs};
|
||||
use connlib_shared::{
|
||||
get_user_agent, keypair, messages::Interface, Callbacks, LoginUrl, StaticSecret,
|
||||
};
|
||||
use firezone_bin_shared::{setup_global_subscriber, CommonArgs, TunDeviceManager};
|
||||
use firezone_tunnel::{GatewayTunnel, Sockets};
|
||||
use futures::channel::mpsc;
|
||||
use futures::{future, StreamExt, TryFutureExt};
|
||||
|
||||
@@ -13,7 +13,7 @@ atomicwrites = "0.4.3" # Needed to safely backup `/etc/resolv.conf` and write th
|
||||
clap = { version = "4.5", features = ["derive", "env", "string"] }
|
||||
connlib-client-shared = { workspace = true }
|
||||
connlib-shared = { workspace = true }
|
||||
firezone-cli-utils = { workspace = true }
|
||||
firezone-bin-shared = { workspace = true }
|
||||
futures = "0.3.30"
|
||||
git-version = "0.3.9"
|
||||
humantime = "2.1"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use anyhow::{bail, Context as _, Result};
|
||||
use connlib_shared::tun_device_manager::linux::IFACE_NAME;
|
||||
use firezone_bin_shared::TunDeviceManager;
|
||||
use std::{net::IpAddr, process::Command, str::FromStr};
|
||||
|
||||
mod etc_resolv_conf;
|
||||
@@ -95,7 +95,7 @@ fn configure_network_manager(_dns_config: &[IpAddr]) -> Result<()> {
|
||||
async fn configure_systemd_resolved(dns_config: &[IpAddr]) -> Result<()> {
|
||||
let status = tokio::process::Command::new("resolvectl")
|
||||
.arg("dns")
|
||||
.arg(IFACE_NAME)
|
||||
.arg(TunDeviceManager::IFACE_NAME)
|
||||
.args(dns_config.iter().map(ToString::to_string))
|
||||
.status()
|
||||
.await
|
||||
@@ -106,7 +106,7 @@ async fn configure_systemd_resolved(dns_config: &[IpAddr]) -> Result<()> {
|
||||
|
||||
let status = tokio::process::Command::new("resolvectl")
|
||||
.arg("domain")
|
||||
.arg(IFACE_NAME)
|
||||
.arg(TunDeviceManager::IFACE_NAME)
|
||||
.arg("~.")
|
||||
.status()
|
||||
.await
|
||||
|
||||
@@ -7,7 +7,6 @@ use crate::{
|
||||
use anyhow::{Context as _, Result};
|
||||
use clap::Parser;
|
||||
use connlib_client_shared::{file_logger, keypair, ConnectArgs, LoginUrl, Session, Sockets};
|
||||
use connlib_shared::tun_device_manager;
|
||||
use futures::{future, SinkExt as _, StreamExt as _};
|
||||
use std::{net::IpAddr, path::PathBuf, pin::pin, time::Duration};
|
||||
use tokio::{sync::mpsc, time::Instant};
|
||||
@@ -16,6 +15,7 @@ use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Layer, Registry};
|
||||
use url::Url;
|
||||
|
||||
pub mod ipc;
|
||||
use firezone_bin_shared::TunDeviceManager;
|
||||
use ipc::{Server as IpcServer, ServiceId};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
@@ -162,7 +162,7 @@ struct Handler {
|
||||
ipc_rx: ipc::ServerRead,
|
||||
ipc_tx: ipc::ServerWrite,
|
||||
last_connlib_start_instant: Option<Instant>,
|
||||
tun_device: tun_device_manager::TunDeviceManager,
|
||||
tun_device: TunDeviceManager,
|
||||
}
|
||||
|
||||
enum Event {
|
||||
@@ -178,7 +178,7 @@ impl Handler {
|
||||
.await
|
||||
.context("Failed to wait for incoming IPC connection from a GUI")?;
|
||||
let (cb_tx, cb_rx) = mpsc::channel(10);
|
||||
let tun_device = tun_device_manager::TunDeviceManager::new()?;
|
||||
let tun_device = TunDeviceManager::new()?;
|
||||
|
||||
Ok(Self {
|
||||
callback_handler: CallbackHandler { cb_tx },
|
||||
|
||||
@@ -7,8 +7,7 @@ use crate::{
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use clap::Parser;
|
||||
use connlib_client_shared::{file_logger, keypair, ConnectArgs, LoginUrl, Session, Sockets};
|
||||
use connlib_shared::tun_device_manager;
|
||||
use firezone_cli_utils::setup_global_subscriber;
|
||||
use firezone_bin_shared::{setup_global_subscriber, TunDeviceManager};
|
||||
use futures::{FutureExt as _, StreamExt as _};
|
||||
use secrecy::SecretString;
|
||||
use std::{
|
||||
@@ -175,7 +174,7 @@ pub fn run_only_headless_client() -> Result<()> {
|
||||
let mut terminate = pin!(terminate.recv().fuse());
|
||||
let mut hangup = pin!(hangup.recv().fuse());
|
||||
let mut dns_controller = DnsController::default();
|
||||
let mut tun_device = tun_device_manager::TunDeviceManager::new()?;
|
||||
let mut tun_device = TunDeviceManager::new()?;
|
||||
let mut cb_rx = ReceiverStream::new(cb_rx).fuse();
|
||||
|
||||
loop {
|
||||
|
||||
Reference in New Issue
Block a user