mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-03 19:13:43 +02:00
Bring service back to simple working state to end-to-end test.
This commit is contained in:
parent
0552d587a0
commit
2017dcf746
9 changed files with 164 additions and 59 deletions
|
@ -227,9 +227,23 @@ mod tests {
|
|||
type TypeMap = HashMap<String, Type>;
|
||||
|
||||
use super::{Dictionary, BOOL_TRUTH};
|
||||
use crate::util::testutil::randstring;
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn randstring(len: u8) -> String {
|
||||
(0..len)
|
||||
.map(|_| (rand::random::<u8>() % 26) + 'a' as u8)
|
||||
.map(|c| {
|
||||
if rand::random::<bool>() {
|
||||
(c as char).to_ascii_uppercase()
|
||||
} else {
|
||||
c as char
|
||||
}
|
||||
})
|
||||
.map(|c| c.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("")
|
||||
}
|
||||
|
||||
fn make_dictionary() -> (Dictionary, TypeMap) {
|
||||
let mut d = Dictionary::new();
|
||||
let mut tm = TypeMap::new();
|
||||
|
|
|
@ -8,9 +8,6 @@ pub mod marshalable;
|
|||
/// A value for ticks that indicates that something never happened, and is thus very long before zero ticks.
|
||||
pub(crate) const NEVER_HAPPENED_TICKS: i64 = -2147483648;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod testutil;
|
||||
|
||||
#[cfg(feature = "debug_events")]
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! debug_event {
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
// from zeronsd
|
||||
pub fn randstring(len: u8) -> String {
|
||||
(0..len)
|
||||
.map(|_| (rand::random::<u8>() % 26) + 'a' as u8)
|
||||
.map(|c| {
|
||||
if rand::random::<bool>() {
|
||||
(c as char).to_ascii_uppercase()
|
||||
} else {
|
||||
c as char
|
||||
}
|
||||
})
|
||||
.map(|c| c.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("")
|
||||
}
|
|
@ -459,6 +459,21 @@ mod tests {
|
|||
},
|
||||
};
|
||||
|
||||
fn randstring(len: u8) -> String {
|
||||
(0..len)
|
||||
.map(|_| (rand::random::<u8>() % 26) + 'a' as u8)
|
||||
.map(|c| {
|
||||
if rand::random::<bool>() {
|
||||
(c as char).to_ascii_uppercase()
|
||||
} else {
|
||||
c as char
|
||||
}
|
||||
})
|
||||
.map(|c| c.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn endpoint_default() {
|
||||
let e: Endpoint = Default::default();
|
||||
|
@ -611,7 +626,6 @@ mod tests {
|
|||
#[test]
|
||||
fn endpoint_marshal_http() {
|
||||
use crate::util::buffer::Buffer;
|
||||
use crate::util::testutil::randstring;
|
||||
|
||||
for _ in 0..1000 {
|
||||
let http = Endpoint::Http(randstring(30));
|
||||
|
@ -650,7 +664,6 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn endpoint_to_from_string() {
|
||||
use crate::util::testutil::randstring;
|
||||
use std::str::FromStr;
|
||||
|
||||
for _ in 0..1000 {
|
||||
|
|
|
@ -24,7 +24,7 @@ pub use event::Event;
|
|||
pub use identity::Identity;
|
||||
pub use inetaddress::InetAddress;
|
||||
pub use mac::MAC;
|
||||
pub use node::{HostSystem, InnerProtocol, Node, PathFilter, Storage};
|
||||
pub use node::{DummyInnerProtocol, DummyPathFilter, HostSystem, InnerProtocol, Node, PathFilter, Storage};
|
||||
pub use path::Path;
|
||||
pub use peer::Peer;
|
||||
pub use rootset::{Root, RootSet};
|
||||
|
|
|
@ -97,9 +97,9 @@ pub trait Storage: Sync + Send + 'static {
|
|||
|
||||
/// Trait to be implemented to provide path hints and a filter to approve physical paths
|
||||
#[async_trait]
|
||||
pub trait PathFilter<HostSystemImpl: HostSystem>: Sync + Send + 'static {
|
||||
pub trait PathFilter: Sync + Send + 'static {
|
||||
/// Called to check and see if a physical address should be used for ZeroTier traffic to a node.
|
||||
async fn check_path(
|
||||
async fn check_path<HostSystemImpl: HostSystem>(
|
||||
&self,
|
||||
id: &Identity,
|
||||
endpoint: &Endpoint,
|
||||
|
@ -108,7 +108,7 @@ pub trait PathFilter<HostSystemImpl: HostSystem>: Sync + Send + 'static {
|
|||
) -> bool;
|
||||
|
||||
/// Called to look up any statically defined or memorized paths to known nodes.
|
||||
async fn get_path_hints(
|
||||
async fn get_path_hints<HostSystemImpl: HostSystem>(
|
||||
&self,
|
||||
id: &Identity,
|
||||
) -> Option<
|
||||
|
@ -849,3 +849,79 @@ impl<HostSystemImpl: HostSystem> Node<HostSystemImpl> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Dummy no-op inner protocol for debugging and testing.
|
||||
#[derive(Default)]
|
||||
pub struct DummyInnerProtocol;
|
||||
|
||||
#[async_trait]
|
||||
impl InnerProtocol for DummyInnerProtocol {
|
||||
async fn handle_packet<HostSystemImpl: HostSystem>(
|
||||
&self,
|
||||
_source: &Peer<HostSystemImpl>,
|
||||
_source_path: &Path<HostSystemImpl>,
|
||||
_verb: u8,
|
||||
_payload: &PacketBuffer,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
async fn handle_error<HostSystemImpl: HostSystem>(
|
||||
&self,
|
||||
_source: &Peer<HostSystemImpl>,
|
||||
_source_path: &Path<HostSystemImpl>,
|
||||
_in_re_verb: u8,
|
||||
_in_re_message_id: u64,
|
||||
_error_code: u8,
|
||||
_payload: &PacketBuffer,
|
||||
_cursor: &mut usize,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
async fn handle_ok<HostSystemImpl: HostSystem>(
|
||||
&self,
|
||||
_source: &Peer<HostSystemImpl>,
|
||||
_source_path: &Path<HostSystemImpl>,
|
||||
_in_re_verb: u8,
|
||||
_in_re_message_id: u64,
|
||||
_payload: &PacketBuffer,
|
||||
_cursor: &mut usize,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn should_communicate_with(&self, _id: &Identity) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Dummy no-op path filter for debugging and testing.
|
||||
#[derive(Default)]
|
||||
pub struct DummyPathFilter;
|
||||
|
||||
#[async_trait]
|
||||
impl PathFilter for DummyPathFilter {
|
||||
async fn check_path<HostSystemImpl: HostSystem>(
|
||||
&self,
|
||||
_id: &Identity,
|
||||
_endpoint: &Endpoint,
|
||||
_local_socket: Option<&<HostSystemImpl as HostSystem>::LocalSocket>,
|
||||
_local_interface: Option<&<HostSystemImpl as HostSystem>::LocalInterface>,
|
||||
) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
async fn get_path_hints<HostSystemImpl: HostSystem>(
|
||||
&self,
|
||||
_id: &Identity,
|
||||
) -> Option<
|
||||
Vec<(
|
||||
Endpoint,
|
||||
Option<<HostSystemImpl as HostSystem>::LocalSocket>,
|
||||
Option<<HostSystemImpl as HostSystem>::LocalInterface>,
|
||||
)>,
|
||||
> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,12 @@ use std::sync::Arc;
|
|||
use crate::localconfig::Config;
|
||||
use crate::utils::{read_limit, DEFAULT_FILE_IO_READ_LIMIT};
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
|
||||
use zerotier_crypto::random::next_u32_secure;
|
||||
use zerotier_network_hypervisor::vl1::Identity;
|
||||
use zerotier_network_hypervisor::vl1::{Identity, Storage};
|
||||
|
||||
const AUTH_TOKEN_DEFAULT_LENGTH: usize = 48;
|
||||
const AUTH_TOKEN_POSSIBLE_CHARS: &'static str = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
@ -26,6 +28,32 @@ pub struct DataDir {
|
|||
authtoken: Mutex<String>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Storage for DataDir {
|
||||
async fn load_node_identity(&self) -> Option<Identity> {
|
||||
let id_data = read_limit(self.base_path.join(IDENTITY_SECRET_FILENAME), 4096).await;
|
||||
if id_data.is_err() {
|
||||
return None;
|
||||
}
|
||||
let id_data = Identity::from_str(String::from_utf8_lossy(id_data.unwrap().as_slice()).as_ref());
|
||||
if id_data.is_err() {
|
||||
return None;
|
||||
}
|
||||
Some(id_data.unwrap())
|
||||
}
|
||||
|
||||
async fn save_node_identity(&self, id: &Identity) {
|
||||
assert!(id.secret.is_some());
|
||||
let id_secret_str = id.to_secret_string();
|
||||
let id_public_str = id.to_string();
|
||||
let secret_path = self.base_path.join(IDENTITY_SECRET_FILENAME);
|
||||
// TODO: handle errors
|
||||
let _ = tokio::fs::write(&secret_path, id_secret_str.as_bytes()).await;
|
||||
assert!(crate::utils::fs_restrict_permissions(&secret_path));
|
||||
let _ = tokio::fs::write(self.base_path.join(IDENTITY_PUBLIC_FILENAME), id_public_str.as_bytes()).await;
|
||||
}
|
||||
}
|
||||
|
||||
impl DataDir {
|
||||
pub async fn open<P: AsRef<Path>>(path: P) -> std::io::Result<Self> {
|
||||
let base_path = path.as_ref().to_path_buf();
|
||||
|
@ -58,28 +86,6 @@ impl DataDir {
|
|||
return Ok(Self { base_path, config, authtoken: Mutex::new(String::new()) });
|
||||
}
|
||||
|
||||
/// Load identity.secret from data directory.
|
||||
pub async fn load_identity(&self) -> std::io::Result<Identity> {
|
||||
let id_data = Identity::from_str(
|
||||
String::from_utf8_lossy(read_limit(self.base_path.join(IDENTITY_SECRET_FILENAME), 4096).await?.as_slice()).as_ref(),
|
||||
);
|
||||
if id_data.is_err() {
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, id_data.err().unwrap()));
|
||||
}
|
||||
Ok(id_data.unwrap())
|
||||
}
|
||||
|
||||
/// Save identity.secret and identity.public to data directory.
|
||||
pub async fn save_identity(&self, id: &Identity) -> std::io::Result<()> {
|
||||
assert!(id.secret.is_some());
|
||||
let id_secret_str = id.to_secret_string();
|
||||
let id_public_str = id.to_string();
|
||||
let secret_path = self.base_path.join(IDENTITY_SECRET_FILENAME);
|
||||
tokio::fs::write(&secret_path, id_secret_str.as_bytes()).await?;
|
||||
assert!(crate::utils::fs_restrict_permissions(&secret_path));
|
||||
tokio::fs::write(self.base_path.join(IDENTITY_PUBLIC_FILENAME), id_public_str.as_bytes()).await
|
||||
}
|
||||
|
||||
/// Get authorization token for local API, creating and saving if it does not exist.
|
||||
pub async fn authtoken(&self) -> std::io::Result<String> {
|
||||
let authtoken = self.authtoken.lock().clone();
|
||||
|
|
|
@ -10,12 +10,15 @@ pub mod utils;
|
|||
pub mod vnic;
|
||||
|
||||
use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
|
||||
use clap::error::{ContextKind, ContextValue};
|
||||
use clap::{Arg, ArgMatches, Command};
|
||||
|
||||
use zerotier_network_hypervisor::vl2::Switch;
|
||||
use zerotier_network_hypervisor::{VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION};
|
||||
use zerotier_vl1_service::VL1Service;
|
||||
|
||||
use crate::datadir::DataDir;
|
||||
|
||||
pub fn print_help() {
|
||||
let h = crate::cmdline_help::make_cmdline_help();
|
||||
|
@ -39,6 +42,19 @@ pub struct Flags {
|
|||
pub auth_token_override: Option<String>,
|
||||
}
|
||||
|
||||
async fn open_datadir(flags: &Flags) -> Arc<DataDir> {
|
||||
let datadir = DataDir::open(flags.base_path.as_str()).await;
|
||||
if datadir.is_ok() {
|
||||
return Arc::new(datadir.unwrap());
|
||||
}
|
||||
eprintln!(
|
||||
"FATAL: unable to open data directory {}: {}",
|
||||
flags.base_path,
|
||||
datadir.err().unwrap().to_string()
|
||||
);
|
||||
std::process::exit(exitcode::ERR_IOERR);
|
||||
}
|
||||
|
||||
async fn async_main(flags: Flags, global_args: Box<ArgMatches>) -> i32 {
|
||||
#[allow(unused)]
|
||||
match global_args.subcommand() {
|
||||
|
@ -59,8 +75,10 @@ async fn async_main(flags: Flags, global_args: Box<ArgMatches>) -> i32 {
|
|||
Some(("service", _)) => {
|
||||
drop(global_args); // free unnecessary heap before starting service as we're done with CLI args
|
||||
|
||||
/*
|
||||
let svc = service::Service::new(tokio::runtime::Handle::current(), &flags.base_path, true).await;
|
||||
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).await;
|
||||
let svc = VL1Service::new(datadir, test_inner, test_path_filter, zerotier_vl1_service::Settings::default()).await;
|
||||
if svc.is_ok() {
|
||||
let _ = tokio::signal::ctrl_c().await;
|
||||
println!("Terminate signal received, shutting down...");
|
||||
|
@ -69,8 +87,6 @@ async fn async_main(flags: Flags, global_args: Box<ArgMatches>) -> i32 {
|
|||
println!("FATAL: error launching service: {}", svc.err().unwrap().to_string());
|
||||
exitcode::ERR_IOERR
|
||||
}
|
||||
*/
|
||||
todo!()
|
||||
}
|
||||
Some(("identity", cmd_args)) => todo!(),
|
||||
Some(("rootset", cmd_args)) => cli::rootset::cmd(flags, cmd_args).await,
|
||||
|
|
|
@ -24,7 +24,7 @@ use tokio::time::Duration;
|
|||
/// talks to the physical network, manages the vl1 node, and presents a templated interface for
|
||||
/// whatever inner protocol implementation is using it. This would typically be VL2 but could be
|
||||
/// a test harness or just the controller for a controller that runs stand-alone.
|
||||
pub struct VL1Service<StorageImpl: Storage, PathFilterImpl: PathFilter<Self>, InnerProtocolImpl: InnerProtocol> {
|
||||
pub struct VL1Service<StorageImpl: Storage, PathFilterImpl: PathFilter, InnerProtocolImpl: InnerProtocol> {
|
||||
state: tokio::sync::RwLock<VL1ServiceMutableState>,
|
||||
storage: Arc<StorageImpl>,
|
||||
inner: Arc<InnerProtocolImpl>,
|
||||
|
@ -38,7 +38,7 @@ struct VL1ServiceMutableState {
|
|||
settings: Settings,
|
||||
}
|
||||
|
||||
impl<StorageImpl: Storage, PathFilterImpl: PathFilter<Self>, InnerProtocolImpl: InnerProtocol>
|
||||
impl<StorageImpl: Storage, PathFilterImpl: PathFilter, InnerProtocolImpl: InnerProtocol>
|
||||
VL1Service<StorageImpl, PathFilterImpl, InnerProtocolImpl>
|
||||
{
|
||||
pub async fn new(
|
||||
|
@ -199,7 +199,7 @@ impl<StorageImpl: Storage, PathFilterImpl: PathFilter<Self>, InnerProtocolImpl:
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<StorageImpl: Storage, PathFilterImpl: PathFilter<Self>, InnerProtocolImpl: InnerProtocol> HostSystem
|
||||
impl<StorageImpl: Storage, PathFilterImpl: PathFilter, InnerProtocolImpl: InnerProtocol> HostSystem
|
||||
for VL1Service<StorageImpl, PathFilterImpl, InnerProtocolImpl>
|
||||
{
|
||||
type LocalSocket = crate::LocalSocket;
|
||||
|
@ -297,7 +297,7 @@ impl<StorageImpl: Storage, PathFilterImpl: PathFilter<Self>, InnerProtocolImpl:
|
|||
}
|
||||
}
|
||||
|
||||
impl<StorageImpl: Storage, PathFilterImpl: PathFilter<Self>, InnerProtocolImpl: InnerProtocol> Drop
|
||||
impl<StorageImpl: Storage, PathFilterImpl: PathFilter, InnerProtocolImpl: InnerProtocol> Drop
|
||||
for VL1Service<StorageImpl, PathFilterImpl, InnerProtocolImpl>
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
|
|
Loading…
Add table
Reference in a new issue