diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 610b37be3..8ebf40845 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -2118,6 +2118,9 @@ dependencies = [ "resolv-conf", "ring", "rtnetlink", + "serde", + "serde_json", + "smbios-lib", "socket-factory", "tempfile", "thiserror 1.0.69", @@ -2275,7 +2278,6 @@ dependencies = [ "serde", "serde_json", "serde_variant", - "smbios-lib", "strum", "tempfile", "thiserror 1.0.69", diff --git a/rust/bin-shared/Cargo.toml b/rust/bin-shared/Cargo.toml index 2907adf5a..6fe40e898 100644 --- a/rust/bin-shared/Cargo.toml +++ b/rust/bin-shared/Cargo.toml @@ -8,6 +8,7 @@ license = { workspace = true } [dependencies] anyhow = { workspace = true } +atomicwrites = { workspace = true } axum = { workspace = true, features = ["http1", "tokio"] } clap = { workspace = true, features = ["derive", "env"] } dns-types = { workspace = true } @@ -17,11 +18,15 @@ gat-lending-iterator = { workspace = true } hex-literal = { workspace = true } ip-packet = { workspace = true } ip_network = { workspace = true, features = ["serde"] } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +smbios-lib = { workspace = true } socket-factory = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = ["io-util", "net", "rt", "sync", "process"] } tracing = { workspace = true } tun = { workspace = true } +uuid = { workspace = true } [dev-dependencies] bufferpool = { workspace = true } diff --git a/rust/headless-client/src/device_id.rs b/rust/bin-shared/src/device_id.rs similarity index 83% rename from rust/headless-client/src/device_id.rs rename to rust/bin-shared/src/device_id.rs index 31d732b3e..c76e5de4a 100644 --- a/rust/headless-client/src/device_id.rs +++ b/rust/bin-shared/src/device_id.rs @@ -1,3 +1,5 @@ +//! Generate a persistent device ID, stores it to disk, and reads it back. + use anyhow::{Context as _, Result}; use atomicwrites::{AtomicFile, OverwriteBehavior}; use std::{ @@ -15,43 +17,12 @@ pub struct DeviceId { /// e.g. `C:\ProgramData\dev.firezone.client/firezone-id.json` or /// `/var/lib/dev.firezone.client/config/firezone-id.json`. pub(crate) fn path() -> Result { - let path = firezone_bin_shared::known_dirs::ipc_service_config() + let path = crate::known_dirs::ipc_service_config() .context("Failed to compute path for firezone-id file")? .join("firezone-id.json"); Ok(path) } -fn device_serial() -> Option { - const DEFAULT_SERIAL: &str = "123456789"; - let data = smbioslib::table_load_from_device().ok()?; - - let serial = data.find_map(|sys_info: smbioslib::SMBiosSystemInformation| { - sys_info.serial_number().to_utf8_lossy() - })?; - - if serial == DEFAULT_SERIAL { - return None; - } - - Some(serial) -} - -fn device_uuid() -> Option { - let data = smbioslib::table_load_from_device().ok()?; - - let uuid = data.find_map(|sys_info: smbioslib::SMBiosSystemInformation| sys_info.uuid()); - - uuid?.to_string().into() -} - -pub fn device_info() -> phoenix_channel::DeviceInfo { - phoenix_channel::DeviceInfo { - device_serial: device_serial(), - device_uuid: device_uuid(), - ..Default::default() - } -} - /// Returns the device ID without generating it pub fn get() -> Result { let path = path()?; diff --git a/rust/bin-shared/src/device_info.rs b/rust/bin-shared/src/device_info.rs new file mode 100644 index 000000000..b766fba51 --- /dev/null +++ b/rust/bin-shared/src/device_info.rs @@ -0,0 +1,22 @@ +pub fn serial() -> Option { + const DEFAULT_SERIAL: &str = "123456789"; + let data = smbioslib::table_load_from_device().ok()?; + + let serial = data.find_map(|sys_info: smbioslib::SMBiosSystemInformation| { + sys_info.serial_number().to_utf8_lossy() + })?; + + if serial == DEFAULT_SERIAL { + return None; + } + + Some(serial) +} + +pub fn uuid() -> Option { + let data = smbioslib::table_load_from_device().ok()?; + + let uuid = data.find_map(|sys_info: smbioslib::SMBiosSystemInformation| sys_info.uuid()); + + uuid?.to_string().into() +} diff --git a/rust/bin-shared/src/lib.rs b/rust/bin-shared/src/lib.rs index a63d0b385..0caac00e1 100644 --- a/rust/bin-shared/src/lib.rs +++ b/rust/bin-shared/src/lib.rs @@ -6,8 +6,6 @@ mod dns_control; mod network_changes; mod tun_device_manager; -pub mod signals; - #[cfg(target_os = "linux")] pub mod linux; @@ -26,7 +24,10 @@ pub mod macos; #[cfg(target_os = "macos")] pub use macos as platform; +pub mod device_id; +pub mod device_info; pub mod known_dirs; +pub mod signals; pub mod uptime; pub const TOKEN_ENV_KEY: &str = "FIREZONE_TOKEN"; diff --git a/rust/gui-client/src-tauri/src/main.rs b/rust/gui-client/src-tauri/src/main.rs index fa694d83e..832f3727a 100644 --- a/rust/gui-client/src-tauri/src/main.rs +++ b/rust/gui-client/src-tauri/src/main.rs @@ -114,7 +114,7 @@ fn run_gui(cli: Cli) -> Result<()> { ); // Get the device ID before starting Tokio, so that all the worker threads will inherit the correct scope. // Technically this means we can fail to get the device ID on a newly-installed system, since the IPC service may not have fully started up when the GUI process reaches this point, but in practice it's unlikely. - if let Ok(id) = firezone_headless_client::device_id::get() { + if let Ok(id) = firezone_bin_shared::device_id::get() { Telemetry::set_firezone_id(id.id); } fix_log_filter(&mut settings)?; diff --git a/rust/headless-client/Cargo.toml b/rust/headless-client/Cargo.toml index 0b8c429e7..d0350073c 100644 --- a/rust/headless-client/Cargo.toml +++ b/rust/headless-client/Cargo.toml @@ -9,7 +9,7 @@ license = { workspace = true } [dependencies] anyhow = { workspace = true } -atomicwrites = { workspace = true } # Needed to safely backup `/etc/resolv.conf` and write the device ID on behalf of `gui-client` +atomicwrites = { workspace = true } # Needed to safely backup `/etc/resolv.conf` backoff = { workspace = true } clap = { workspace = true, features = ["derive", "env", "string"] } connlib-client-shared = { workspace = true } @@ -31,7 +31,6 @@ secrecy = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } serde_variant = { workspace = true } -smbios-lib = { workspace = true } strum = { workspace = true } thiserror = { workspace = true } # This actually relies on many other features in Tokio, so this will probably diff --git a/rust/headless-client/src/ipc_service.rs b/rust/headless-client/src/ipc_service.rs index d61b43880..919b0458d 100644 --- a/rust/headless-client/src/ipc_service.rs +++ b/rust/headless-client/src/ipc_service.rs @@ -1,10 +1,11 @@ -use crate::{CallbackHandler, CliCommon, ConnlibMsg, device_id}; +use crate::{CallbackHandler, CliCommon, ConnlibMsg}; use anyhow::{Context as _, Result, bail}; use atomicwrites::{AtomicFile, OverwriteBehavior}; use clap::Parser; use connlib_model::ResourceView; use firezone_bin_shared::{ - DnsControlMethod, DnsController, TOKEN_ENV_KEY, TunDeviceManager, known_dirs, + DnsControlMethod, DnsController, TOKEN_ENV_KEY, TunDeviceManager, device_id, device_info, + known_dirs, platform::{tcp_socket_factory, udp_socket_factory}, signals, }; @@ -15,7 +16,7 @@ use futures::{ future::poll_fn, task::{Context, Poll}, }; -use phoenix_channel::LoginUrl; +use phoenix_channel::{DeviceInfo, LoginUrl}; use secrecy::SecretString; use serde::{Deserialize, Serialize}; use std::{ @@ -566,7 +567,11 @@ impl<'a> Handler<'a> { &token, device_id.id, None, - device_id::device_info(), + DeviceInfo { + device_serial: device_info::serial(), + device_uuid: device_info::uuid(), + ..Default::default() + }, ) .context("Failed to create `LoginUrl`")?; diff --git a/rust/headless-client/src/lib.rs b/rust/headless-client/src/lib.rs index ed9c1c2f4..5913f8fb9 100644 --- a/rust/headless-client/src/lib.rs +++ b/rust/headless-client/src/lib.rs @@ -24,8 +24,6 @@ use tokio::sync::mpsc; use tracing_subscriber::{EnvFilter, Layer as _, Registry, fmt, layer::SubscriberExt as _}; mod clear_logs; -/// Generate a persistent device ID, stores it to disk, and reads it back. -pub mod device_id; mod ipc_service; pub use clear_logs::clear_logs; diff --git a/rust/headless-client/src/main.rs b/rust/headless-client/src/main.rs index 30dfaf50b..50bada880 100644 --- a/rust/headless-client/src/main.rs +++ b/rust/headless-client/src/main.rs @@ -7,19 +7,20 @@ use backoff::ExponentialBackoffBuilder; use clap::Parser; use connlib_client_shared::Session; use firezone_bin_shared::{ - DnsController, TOKEN_ENV_KEY, TunDeviceManager, new_dns_notifier, new_network_notifier, + DnsController, TOKEN_ENV_KEY, TunDeviceManager, device_id, device_info, new_dns_notifier, + new_network_notifier, platform::{tcp_socket_factory, udp_socket_factory}, signals, }; -use firezone_headless_client::{CallbackHandler, CliCommon, ConnlibMsg, device_id}; +use firezone_headless_client::{CallbackHandler, CliCommon, ConnlibMsg}; use firezone_logging::telemetry_span; use firezone_telemetry::Telemetry; use firezone_telemetry::otel; use futures::StreamExt as _; use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider}; -use phoenix_channel::LoginUrl; use phoenix_channel::PhoenixChannel; use phoenix_channel::get_user_agent; +use phoenix_channel::{DeviceInfo, LoginUrl}; use secrecy::{Secret, SecretString}; use std::{ path::{Path, PathBuf}, @@ -194,7 +195,11 @@ fn main() -> Result<()> { &token, firezone_id.clone(), cli.firezone_name, - device_id::device_info(), + DeviceInfo { + device_serial: device_info::serial(), + device_uuid: device_info::uuid(), + ..Default::default() + }, )?; if cli.check {