mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-25 16:36:54 +02:00
Move datadir and make it generic.
This commit is contained in:
parent
433c6058d2
commit
a6f09dbec4
9 changed files with 108 additions and 49 deletions
|
@ -17,3 +17,7 @@ parking_lot = { version = "^0", features = [], default-features = false }
|
|||
serde = { version = "^1", features = ["derive"], default-features = false }
|
||||
serde_json = { version = "^1", features = ["std"], default-features = false }
|
||||
clap = { version = "^3", features = ["std", "suggestions"], default-features = false }
|
||||
|
||||
[target."cfg(not(windows))".dependencies]
|
||||
signal-hook = "^0"
|
||||
libc = "^0"
|
||||
|
|
|
@ -1,3 +1,45 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
fn main() {}
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use zerotier_utils::exitcode;
|
||||
use zerotier_vl1_service::VL1Service;
|
||||
|
||||
fn main() {
|
||||
std::process::exit(
|
||||
if let Ok(_tokio_runtime) = zerotier_utils::tokio::runtime::Builder::new_multi_thread().enable_all().build() {
|
||||
let test_inner = Arc::new(zerotier_network_hypervisor::vl1::DummyInnerProtocol::default());
|
||||
let test_path_filter = Arc::new(zerotier_network_hypervisor::vl1::DummyPathFilter::default());
|
||||
let datadir = open_datadir(&flags);
|
||||
let svc = VL1Service::new(datadir, test_inner, test_path_filter, zerotier_vl1_service::VL1Settings::default());
|
||||
if svc.is_ok() {
|
||||
let svc = svc.unwrap();
|
||||
svc.node().init_default_roots();
|
||||
|
||||
// Wait for kill signal on Unix-like platforms.
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let term = Arc::new(AtomicBool::new(false));
|
||||
let _ = signal_hook::flag::register(libc::SIGINT, term.clone());
|
||||
let _ = signal_hook::flag::register(libc::SIGTERM, term.clone());
|
||||
let _ = signal_hook::flag::register(libc::SIGQUIT, term.clone());
|
||||
while !term.load(Ordering::Relaxed) {
|
||||
std::thread::sleep(Duration::from_secs(1));
|
||||
}
|
||||
}
|
||||
|
||||
println!("Terminate signal received, shutting down...");
|
||||
exitcode::OK
|
||||
} else {
|
||||
eprintln!("FATAL: error launching service: {}", svc.err().unwrap().to_string());
|
||||
exitcode::ERR_IOERR
|
||||
}
|
||||
} else {
|
||||
eprintln!("FATAL: error launching service: can't start async runtime");
|
||||
exitcode::ERR_IOERR
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
pub mod cli;
|
||||
pub mod cmdline_help;
|
||||
pub mod datadir;
|
||||
pub mod localconfig;
|
||||
pub mod utils;
|
||||
pub mod vnic;
|
||||
|
@ -18,9 +17,10 @@ use clap::{Arg, ArgMatches, Command};
|
|||
|
||||
use zerotier_network_hypervisor::{VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION};
|
||||
use zerotier_utils::exitcode;
|
||||
use zerotier_vl1_service::datadir::DataDir;
|
||||
use zerotier_vl1_service::VL1Service;
|
||||
|
||||
use crate::datadir::DataDir;
|
||||
use crate::localconfig::Config;
|
||||
|
||||
pub fn print_help() {
|
||||
let h = crate::cmdline_help::make_cmdline_help();
|
||||
|
@ -44,7 +44,7 @@ pub struct Flags {
|
|||
pub auth_token_override: Option<String>,
|
||||
}
|
||||
|
||||
fn open_datadir(flags: &Flags) -> Arc<DataDir> {
|
||||
fn open_datadir(flags: &Flags) -> Arc<DataDir<Config>> {
|
||||
let datadir = DataDir::open(flags.base_path.as_str());
|
||||
if datadir.is_ok() {
|
||||
return Arc::new(datadir.unwrap());
|
||||
|
|
|
@ -1,42 +1,10 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
|
||||
use zerotier_network_hypervisor::vl1::Identity;
|
||||
|
||||
/// Default sanity limit parameter for read_limit() used throughout the service.
|
||||
pub const DEFAULT_FILE_IO_READ_LIMIT: usize = 1048576;
|
||||
|
||||
/// Convenience function to read up to limit bytes from a file.
|
||||
///
|
||||
/// If the file is larger than limit, the excess is not read.
|
||||
pub fn read_limit<P: AsRef<Path>>(path: P, limit: usize) -> std::io::Result<Vec<u8>> {
|
||||
let mut f = File::open(path)?;
|
||||
let bytes = f.metadata()?.len().min(limit as u64) as usize;
|
||||
let mut v: Vec<u8> = Vec::with_capacity(bytes);
|
||||
v.resize(bytes, 0);
|
||||
f.read_exact(v.as_mut_slice())?;
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
/// Set permissions on a file or directory to be most restrictive (visible only to the service's user).
|
||||
#[cfg(unix)]
|
||||
pub fn fs_restrict_permissions<P: AsRef<Path>>(path: P) -> bool {
|
||||
unsafe {
|
||||
let c_path = std::ffi::CString::new(path.as_ref().to_str().unwrap()).unwrap();
|
||||
libc::chmod(
|
||||
c_path.as_ptr(),
|
||||
if path.as_ref().is_dir() {
|
||||
0o700
|
||||
} else {
|
||||
0o600
|
||||
},
|
||||
) == 0
|
||||
}
|
||||
}
|
||||
use zerotier_utils::io::read_limit;
|
||||
|
||||
/// Returns true if the string starts with [yY1tT] or false for [nN0fF].
|
||||
pub fn parse_bool(v: &str) -> Result<bool, String> {
|
||||
|
|
|
@ -14,3 +14,9 @@ parking_lot = { version = "^0", features = [], default-features = false }
|
|||
serde = { version = "^1", features = ["derive"], default-features = false }
|
||||
serde_json = { version = "^1", features = ["std"], default-features = false }
|
||||
tokio = { version = "^1", default-features = false, features = ["fs", "io-util", "io-std", "net", "parking_lot", "process", "rt", "rt-multi-thread", "signal", "sync", "time"], optional = true }
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
winapi = { version = "^0", features = ["handleapi", "ws2ipdef", "ws2tcpip"] }
|
||||
|
||||
[target."cfg(not(windows))".dependencies]
|
||||
libc = "^0"
|
||||
|
|
36
utils/src/io.rs
Normal file
36
utils/src/io.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
|
||||
/// Default sanity limit parameter for read_limit() used throughout the service.
|
||||
pub const DEFAULT_FILE_IO_READ_LIMIT: usize = 1048576;
|
||||
|
||||
/// Convenience function to read up to limit bytes from a file.
|
||||
///
|
||||
/// If the file is larger than limit, the excess is not read.
|
||||
pub fn read_limit<P: AsRef<Path>>(path: P, limit: usize) -> std::io::Result<Vec<u8>> {
|
||||
let mut f = File::open(path)?;
|
||||
let bytes = f.metadata()?.len().min(limit as u64) as usize;
|
||||
let mut v: Vec<u8> = Vec::with_capacity(bytes);
|
||||
v.resize(bytes, 0);
|
||||
f.read_exact(v.as_mut_slice())?;
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
/// Set permissions on a file or directory to be most restrictive (visible only to the service's user).
|
||||
#[cfg(unix)]
|
||||
pub fn fs_restrict_permissions<P: AsRef<Path>>(path: P) -> bool {
|
||||
unsafe {
|
||||
let c_path = std::ffi::CString::new(path.as_ref().to_str().unwrap()).unwrap();
|
||||
libc::chmod(
|
||||
c_path.as_ptr(),
|
||||
if path.as_ref().is_dir() {
|
||||
0o700
|
||||
} else {
|
||||
0o600
|
||||
},
|
||||
) == 0
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ pub mod exitcode;
|
|||
pub mod gate;
|
||||
pub mod gatherarray;
|
||||
pub mod hex;
|
||||
pub mod io;
|
||||
pub mod json;
|
||||
pub mod marshalable;
|
||||
pub mod memory;
|
||||
|
|
|
@ -1,32 +1,33 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
use crate::localconfig::Config;
|
||||
use crate::utils::{read_limit, DEFAULT_FILE_IO_READ_LIMIT};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
|
||||
use zerotier_crypto::random::next_u32_secure;
|
||||
use zerotier_network_hypervisor::vl1::{Identity, NodeStorage};
|
||||
use zerotier_utils::io::{fs_restrict_permissions, read_limit, DEFAULT_FILE_IO_READ_LIMIT};
|
||||
use zerotier_utils::json::to_json_pretty;
|
||||
|
||||
pub const AUTH_TOKEN_FILENAME: &'static str = "authtoken.secret";
|
||||
pub const IDENTITY_PUBLIC_FILENAME: &'static str = "identity.public";
|
||||
pub const IDENTITY_SECRET_FILENAME: &'static str = "identity.secret";
|
||||
pub const CONFIG_FILENAME: &'static str = "local.conf";
|
||||
|
||||
const AUTH_TOKEN_DEFAULT_LENGTH: usize = 48;
|
||||
const AUTH_TOKEN_POSSIBLE_CHARS: &'static str = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
const AUTH_TOKEN_FILENAME: &'static str = "authtoken.secret";
|
||||
const IDENTITY_PUBLIC_FILENAME: &'static str = "identity.public";
|
||||
const IDENTITY_SECRET_FILENAME: &'static str = "identity.secret";
|
||||
const CONFIG_FILENAME: &'static str = "local.conf";
|
||||
|
||||
/// Abstraction around ZeroTier's home data directory.
|
||||
pub struct DataDir {
|
||||
pub struct DataDir<Config: PartialEq + Eq + Clone + Send + Sync + Default + Serialize + DeserializeOwned + 'static> {
|
||||
pub base_path: PathBuf,
|
||||
config: RwLock<Arc<Config>>,
|
||||
authtoken: Mutex<String>,
|
||||
}
|
||||
|
||||
impl NodeStorage for DataDir {
|
||||
impl<Config: PartialEq + Eq + Clone + Send + Sync + Default + Serialize + DeserializeOwned + 'static> NodeStorage for DataDir<Config> {
|
||||
fn load_node_identity(&self) -> Option<Identity> {
|
||||
let id_data = read_limit(self.base_path.join(IDENTITY_SECRET_FILENAME), 4096);
|
||||
if id_data.is_err() {
|
||||
|
@ -46,12 +47,12 @@ impl NodeStorage for DataDir {
|
|||
let secret_path = self.base_path.join(IDENTITY_SECRET_FILENAME);
|
||||
// TODO: handle errors
|
||||
let _ = std::fs::write(&secret_path, id_secret_str.as_bytes());
|
||||
assert!(crate::utils::fs_restrict_permissions(&secret_path));
|
||||
assert!(fs_restrict_permissions(&secret_path));
|
||||
let _ = std::fs::write(self.base_path.join(IDENTITY_PUBLIC_FILENAME), id_public_str.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
impl DataDir {
|
||||
impl<Config: PartialEq + Eq + Clone + Send + Sync + Default + Serialize + DeserializeOwned + 'static> DataDir<Config> {
|
||||
pub fn open<P: AsRef<Path>>(path: P) -> std::io::Result<Self> {
|
||||
let base_path = path.as_ref().to_path_buf();
|
||||
if !base_path.is_dir() {
|
||||
|
@ -95,7 +96,7 @@ impl DataDir {
|
|||
tmp.push(AUTH_TOKEN_POSSIBLE_CHARS.as_bytes()[(next_u32_secure() as usize) % AUTH_TOKEN_POSSIBLE_CHARS.len()] as char);
|
||||
}
|
||||
std::fs::write(&authtoken_path, tmp.as_bytes())?;
|
||||
assert!(crate::utils::fs_restrict_permissions(&authtoken_path));
|
||||
assert!(fs_restrict_permissions(&authtoken_path));
|
||||
*self.authtoken.lock() = tmp;
|
||||
} else {
|
||||
*self.authtoken.lock() = String::from_utf8_lossy(authtoken_bytes.unwrap().as_slice()).into();
|
|
@ -6,6 +6,7 @@ mod settings;
|
|||
mod vl1service;
|
||||
|
||||
pub mod constants;
|
||||
pub mod datadir;
|
||||
pub mod sys;
|
||||
|
||||
pub use localinterface::LocalInterface;
|
||||
|
|
Loading…
Add table
Reference in a new issue