Files
firezone/rust/connlib/shared/src/lib.rs
Reactor Scram deefabd8f8 refactor(firezone-tunnel): move routes and DNS control out of connlib and up to the Client (#5111)
Refs #3636 (This pays down some of the technical debt from Linux DNS)
Refs #4473 (This partially fulfills it)
Refs #5068 (This is needed to make `FIREZONE_DNS_CONTROL` mandatory)

As of dd6421:

- On both Linux and Windows, DNS control and IP setting (i.e.
`on_set_interface_config`) both move to the Client
- On Windows, route setting stays in `tun_windows.rs`. Route setting in
Windows requires us to know the interface index, which we don't know in
the Client code. If we could pass opaque platform-specific data between
the tunnel and the Client it would be easy.
- On Linux, route setting moves to the Client and Gateway, which
completely removes the `worker` task in `tun_linux.rs`
- Notifying systemd that we're ready moves up to the headless Client /
IPC service

```[tasklist]
### Before merging / notes
- [x] Does DNS roaming work on Linux on `main`? I don't see where it hooks up. I think I only set up DNS in `Tun::new` (Yes, the `Tun` gets recreated every time we reconfigure the device)
- [x] Fix Windows Clients
- [x] Fix Gateway
- [x] Make sure connlib doesn't get the DNS control method from the env var (will be fixed in #5068)
- [x] De-dupe consts
- [ ] ~~Add DNS control test~~ (failed)
- [ ] Smoke test Linux
- [ ] Smoke test Windows
```
2024-06-03 14:32:08 +00:00

131 lines
4.1 KiB
Rust

//! This crates contains shared types and behavior between all the other libraries.
//!
//! This includes types provided by external crates, i.e. [boringtun] to make sure that
//! we are using the same version across our own crates.
pub mod callbacks;
pub mod error;
pub mod messages;
pub mod tun_device_manager;
#[cfg(target_os = "windows")]
pub mod windows;
#[cfg(feature = "proptest")]
pub mod proptest;
pub use boringtun::x25519::PublicKey;
pub use boringtun::x25519::StaticSecret;
pub use callbacks::{Callbacks, Cidrv4, Cidrv6};
pub use error::ConnlibError as Error;
pub use error::Result;
pub use phoenix_channel::{LoginUrl, LoginUrlError};
use rand_core::OsRng;
pub type DomainName = domain::base::Name<Vec<u8>>;
/// Bundle ID / App ID that the client uses to distinguish itself from other programs on the system
///
/// e.g. In ProgramData and AppData we use this to name our subdirectories for configs and data,
/// and Windows may use it to track things like the MSI installer, notification titles,
/// deep link registration, etc.
///
/// This should be identical to the `tauri.bundle.identifier` over in `tauri.conf.json`,
/// but sometimes I need to use this before Tauri has booted up, or in a place where
/// getting the Tauri app handle would be awkward.
///
/// Luckily this is also the AppUserModelId that Windows uses to label notifications,
/// so if your dev system has Firezone installed by MSI, the notifications will look right.
/// <https://learn.microsoft.com/en-us/windows/configuration/find-the-application-user-model-id-of-an-installed-app>
pub const BUNDLE_ID: &str = "dev.firezone.client";
pub const DEFAULT_MTU: u32 = 1280;
const VERSION: &str = env!("CARGO_PKG_VERSION");
const LIB_NAME: &str = "connlib";
pub fn keypair() -> (StaticSecret, PublicKey) {
let private_key = StaticSecret::random_from_rng(OsRng);
let public_key = PublicKey::from(&private_key);
(private_key, public_key)
}
pub fn get_user_agent(os_version_override: Option<String>) -> String {
// Note: we could switch to sys-info and get the hostname
// but we lose the arch
// and neither of the libraries provide the kernel version.
// so I rather keep os_info which seems like the most popular
// and keep implementing things that we are missing on top
let info = os_info::get();
// iOS returns "Unknown", but we already know we're on iOS here
#[cfg(target_os = "ios")]
let os_type = "iOS";
#[cfg(not(target_os = "ios"))]
let os_type = info.os_type();
let os_version = os_version_override.unwrap_or(info.version().to_string());
let additional_info = additional_info();
let lib_version = VERSION;
let lib_name = LIB_NAME;
format!("{os_type}/{os_version}{additional_info}{lib_name}/{lib_version}")
}
fn additional_info() -> String {
let info = os_info::get();
match (info.architecture(), kernel_version()) {
(None, None) => " ".to_string(),
(None, Some(k)) => format!(" {k} "),
(Some(a), None) => format!(" {a} "),
(Some(a), Some(k)) => format!(" ({a};{k};) "),
}
}
#[cfg(not(target_family = "unix"))]
fn kernel_version() -> Option<String> {
None
}
#[cfg(target_family = "unix")]
fn kernel_version() -> Option<String> {
#[cfg(any(target_os = "android", target_os = "linux"))]
let mut utsname = libc::utsname {
sysname: [0; 65],
nodename: [0; 65],
release: [0; 65],
version: [0; 65],
machine: [0; 65],
domainname: [0; 65],
};
#[cfg(any(target_os = "macos", target_os = "ios"))]
let mut utsname = libc::utsname {
sysname: [0; 256],
nodename: [0; 256],
release: [0; 256],
version: [0; 256],
machine: [0; 256],
};
// SAFETY: we just allocated the pointer
if unsafe { libc::uname(&mut utsname as *mut _) } != 0 {
return None;
}
#[cfg_attr(
all(target_os = "linux", target_arch = "aarch64"),
allow(clippy::unnecessary_cast)
)]
let version: Vec<u8> = utsname
.release
.split(|c| *c == 0)
.next()?
.iter()
.map(|x| *x as u8)
.collect();
String::from_utf8(version).ok()
}