mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-07 21:13:44 +02:00
(1) Implement typestate Verified for identity, (2) FileDatabase in controller now works.
This commit is contained in:
parent
68021b8a7f
commit
19d973cfd4
33 changed files with 994 additions and 219 deletions
|
@ -35,7 +35,7 @@ pub struct Controller {
|
|||
reaper: Reaper,
|
||||
runtime: tokio::runtime::Handle,
|
||||
database: Arc<dyn Database>,
|
||||
local_identity: Identity,
|
||||
local_identity: Verified<Identity>,
|
||||
|
||||
/// Handler for MULTICAST_LIKE and MULTICAST_GATHER messages.
|
||||
multicast_authority: MulticastAuthority,
|
||||
|
@ -61,7 +61,7 @@ impl Controller {
|
|||
reaper: Reaper::new(&runtime),
|
||||
runtime,
|
||||
database: database.clone(),
|
||||
local_identity,
|
||||
local_identity: local_identity,
|
||||
multicast_authority: MulticastAuthority::new(),
|
||||
daemons: Mutex::new(Vec::with_capacity(2)),
|
||||
recently_authorized: RwLock::new(HashMap::new()),
|
||||
|
@ -76,9 +76,8 @@ impl Controller {
|
|||
/// Set the service and HostSystem implementation for this controller and start daemons.
|
||||
///
|
||||
/// This must be called once the service that uses this handler is up or the controller
|
||||
/// won't actually do anything. The reference the handler holds is weak to prevent
|
||||
/// a circular reference, so if the VL1Service is dropped this must be called again to
|
||||
/// tell the controller handler about a new instance.
|
||||
/// won't actually do anything. The controller holds a weak reference to VL1Service so
|
||||
/// be sure it's not dropped.
|
||||
pub async fn start(&self, service: &Arc<VL1Service<dyn Database, Self, Self>>) {
|
||||
*self.service.write().unwrap() = Arc::downgrade(service);
|
||||
|
||||
|
@ -106,7 +105,7 @@ impl Controller {
|
|||
// Create background task to expire multicast subscriptions and recent authorizations.
|
||||
let self2 = self.self_ref.clone();
|
||||
self.daemons.lock().unwrap().push(self.runtime.spawn(async move {
|
||||
let sleep_duration = Duration::from_millis((protocol::VL2_DEFAULT_MULTICAST_LIKE_EXPIRE / 2).min(5000) as u64);
|
||||
let sleep_duration = Duration::from_millis((protocol::VL2_DEFAULT_MULTICAST_LIKE_EXPIRE / 2).min(2500) as u64);
|
||||
loop {
|
||||
tokio::time::sleep(sleep_duration).await;
|
||||
|
||||
|
@ -234,7 +233,7 @@ impl Controller {
|
|||
/// reason is returned with None or an acceptance reason with a network configuration is returned.
|
||||
async fn get_network_config(
|
||||
self: &Arc<Self>,
|
||||
source_identity: &Identity,
|
||||
source_identity: &Verified<Identity>,
|
||||
network_id: NetworkId,
|
||||
now: i64,
|
||||
) -> Result<(AuthorizationResult, Option<NetworkConfig>, Option<Vec<vl2::v1::Revocation>>), Box<dyn Error + Send + Sync>> {
|
||||
|
@ -287,7 +286,7 @@ impl Controller {
|
|||
if !member_authorized {
|
||||
if member.is_none() {
|
||||
if network.learn_members.unwrap_or(true) {
|
||||
let _ = member.insert(Member::new_with_identity(source_identity.clone(), network_id));
|
||||
let _ = member.insert(Member::new_with_identity(source_identity.as_ref().clone(), network_id));
|
||||
member_changed = true;
|
||||
} else {
|
||||
return Ok((AuthorizationResult::Rejected, None, None));
|
||||
|
@ -407,8 +406,10 @@ impl Controller {
|
|||
} else {
|
||||
return Ok((AuthorizationResult::RejectedDueToError, None, None));
|
||||
}
|
||||
} else {
|
||||
// TODO: create V2 type credential for V2-only networks
|
||||
}
|
||||
|
||||
if source_identity.p384.is_some() {
|
||||
// TODO: create V2 type credential for V2 nodes
|
||||
}
|
||||
|
||||
// Log this member in the recently authorized cache, which is currently just used to filter whether we should
|
||||
|
@ -578,14 +579,14 @@ impl InnerProtocol for Controller {
|
|||
|
||||
impl VL1AuthProvider for Controller {
|
||||
#[inline(always)]
|
||||
fn should_respond_to(&self, _: &Identity) -> bool {
|
||||
fn should_respond_to(&self, _: &Verified<Identity>) -> bool {
|
||||
// Controllers always have to establish sessions to process requests. We don't really know if
|
||||
// a member is relevant until we have looked up both the network and the member, since whether
|
||||
// or not to "learn" unknown members is a network level option.
|
||||
true
|
||||
}
|
||||
|
||||
fn has_trust_relationship(&self, id: &Identity) -> bool {
|
||||
fn has_trust_relationship(&self, id: &Verified<Identity>) -> bool {
|
||||
self.recently_authorized
|
||||
.read()
|
||||
.unwrap()
|
||||
|
|
|
@ -9,7 +9,7 @@ use zerotier_utils::tokio::sync::broadcast::Receiver;
|
|||
use crate::model::*;
|
||||
|
||||
/// Database change relevant to the controller and that was NOT initiated by the controller.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Change {
|
||||
NetworkCreated(Network),
|
||||
NetworkChanged(Network, Network),
|
||||
|
|
|
@ -8,11 +8,9 @@ use async_trait::async_trait;
|
|||
use notify::{RecursiveMode, Watcher};
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
use zerotier_network_hypervisor::vl1::{Address, Identity, NodeStorage};
|
||||
use zerotier_network_hypervisor::vl1::{Address, Identity, NodeStorage, Verified};
|
||||
use zerotier_network_hypervisor::vl2::NetworkId;
|
||||
|
||||
use zerotier_utils::io::{fs_restrict_permissions, read_limit};
|
||||
|
||||
use zerotier_utils::reaper::Reaper;
|
||||
use zerotier_utils::tokio::fs;
|
||||
use zerotier_utils::tokio::runtime::Handle;
|
||||
|
@ -60,11 +58,6 @@ impl FileDatabase {
|
|||
tasks: Reaper::new(&runtime2),
|
||||
cache: Cache::new(),
|
||||
daemon: runtime2.spawn(async move {
|
||||
while db_weak.lock().unwrap().upgrade().is_none() {
|
||||
// Wait for parent to finish constructing and start up, then create watcher.
|
||||
sleep(Duration::from_millis(10)).await;
|
||||
}
|
||||
|
||||
let mut watcher = notify::recommended_watcher(move |event: notify::Result<notify::event::Event>| {
|
||||
if let Ok(event) = event {
|
||||
match event.kind {
|
||||
|
@ -121,7 +114,6 @@ impl FileDatabase {
|
|||
}
|
||||
|
||||
if deleted.is_some() {
|
||||
println!("DELETED: {}", deleted.unwrap().as_os_str().to_string_lossy());
|
||||
match record_type {
|
||||
RecordType::Network => {
|
||||
if let Some((network, mut members)) =
|
||||
|
@ -147,7 +139,6 @@ impl FileDatabase {
|
|||
}
|
||||
|
||||
if let Some(changed) = changed {
|
||||
println!("CHANGED: {}", changed.as_os_str().to_string_lossy());
|
||||
match record_type {
|
||||
RecordType::Network => {
|
||||
if let Ok(Some(new_network)) =
|
||||
|
@ -258,7 +249,7 @@ impl FileDatabase {
|
|||
|
||||
/// Get record type and also the number after it: network number or address.
|
||||
fn record_type_from_path(controller_address: Address, p: &Path) -> Option<(RecordType, NetworkId, Option<Address>)> {
|
||||
let parent = p.parent()?.to_string_lossy();
|
||||
let parent = p.parent()?.file_name()?.to_string_lossy();
|
||||
if parent.len() == 7 && (parent.starts_with("N") || parent.starts_with('n')) {
|
||||
let network_id = NetworkId::from_controller_and_network_no(controller_address, u64::from_str_radix(&parent[1..], 16).ok()?)?;
|
||||
if let Some(file_name) = p.file_name().map(|p| p.to_string_lossy().to_lowercase()) {
|
||||
|
@ -284,7 +275,7 @@ impl Drop for FileDatabase {
|
|||
}
|
||||
|
||||
impl NodeStorage for FileDatabase {
|
||||
fn load_node_identity(&self) -> Option<Identity> {
|
||||
fn load_node_identity(&self) -> Option<Verified<Identity>> {
|
||||
let id_data = read_limit(self.base_path.join(IDENTITY_SECRET_FILENAME), 16384);
|
||||
if id_data.is_err() {
|
||||
return None;
|
||||
|
@ -293,10 +284,10 @@ impl NodeStorage for FileDatabase {
|
|||
if id_data.is_err() {
|
||||
return None;
|
||||
}
|
||||
Some(id_data.unwrap())
|
||||
Some(Verified::assume_verified(id_data.unwrap()))
|
||||
}
|
||||
|
||||
fn save_node_identity(&self, id: &Identity) {
|
||||
fn save_node_identity(&self, id: &Verified<Identity>) {
|
||||
assert!(id.secret.is_some());
|
||||
let id_secret_str = id.to_secret_string();
|
||||
let secret_path = self.base_path.join(IDENTITY_SECRET_FILENAME);
|
||||
|
@ -422,17 +413,35 @@ mod tests {
|
|||
println!("test filedatabase is in: {}", test_dir.as_os_str().to_str().unwrap());
|
||||
|
||||
let _ = std::fs::remove_dir_all(&test_dir);
|
||||
let controller_id = Identity::generate();
|
||||
|
||||
let db = Arc::new(FileDatabase::new(tokio_runtime.handle().clone(), test_dir).await.expect("new db"));
|
||||
db.save_node_identity(&controller_id);
|
||||
assert!(db.load_node_identity().is_some());
|
||||
|
||||
let db2 = db.clone();
|
||||
tokio_runtime.spawn(async move {
|
||||
let mut change_receiver = db2.changes().await.unwrap();
|
||||
loop {
|
||||
if let Ok(change) = change_receiver.recv().await {
|
||||
//println!("[FileDatabase] {:#?}", change);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut test_network = Network::new(network_id);
|
||||
db.save_network(test_network.clone()).await.expect("network save error");
|
||||
|
||||
let db = FileDatabase::new(tokio_runtime.handle().clone(), test_dir).await.expect("new db");
|
||||
let mut test_member = Member::new_without_identity(node_id, network_id);
|
||||
|
||||
for x in 0..3 {
|
||||
test_member.name = x.to_string();
|
||||
db.save_member(test_member.clone()).await.expect("member save ok");
|
||||
db.save_member(test_member.clone()).await.expect("member save error");
|
||||
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
|
||||
let test_member2 = db.get_member(network_id, node_id).await.unwrap().unwrap();
|
||||
//println!("{}", test_member.to_string());
|
||||
//println!("{}", test_member2.to_string());
|
||||
assert!(test_member == test_member2);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ use zerotier_network_hypervisor::vl1::{Address, Identity, InetAddress};
|
|||
use zerotier_network_hypervisor::vl2::NetworkId;
|
||||
use zerotier_utils::blob::Blob;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub struct Member {
|
||||
#[serde(rename = "address")]
|
||||
pub node_id: Address,
|
||||
|
@ -119,9 +119,3 @@ impl Hash for Member {
|
|||
self.network_id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for Member {
|
||||
fn to_string(&self) -> String {
|
||||
zerotier_utils::json::to_json_pretty(self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use zerotier_network_hypervisor::vl2::networkconfig::NetworkConfig;
|
|||
use zerotier_network_hypervisor::vl2::NetworkId;
|
||||
use zerotier_utils::blob::Blob;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum RecordType {
|
||||
Network,
|
||||
Member,
|
||||
|
@ -23,13 +23,13 @@ pub enum RecordType {
|
|||
}
|
||||
|
||||
/// A complete network with all member configuration information for import/export or blob storage.
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct NetworkExport {
|
||||
pub network: Network,
|
||||
pub members: HashMap<Address, Member>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[repr(u8)]
|
||||
pub enum AuthorizationResult {
|
||||
#[serde(rename = "r")]
|
||||
|
@ -87,7 +87,7 @@ impl ToString for AuthorizationResult {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RequestLogItem {
|
||||
#[serde(rename = "nw")]
|
||||
pub network_id: NetworkId,
|
||||
|
|
|
@ -15,12 +15,12 @@ use crate::model::Member;
|
|||
|
||||
pub const CREDENTIAL_WINDOW_SIZE_DEFAULT: u64 = 1000 * 60 * 60;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default, Debug)]
|
||||
pub struct Ipv4AssignMode {
|
||||
pub zt: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default, Debug)]
|
||||
pub struct Ipv6AssignMode {
|
||||
pub zt: bool,
|
||||
pub rfc4193: bool,
|
||||
|
@ -28,7 +28,7 @@ pub struct Ipv6AssignMode {
|
|||
pub _6plane: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Debug)]
|
||||
pub struct IpAssignmentPool {
|
||||
#[serde(rename = "ipRangeStart")]
|
||||
ip_range_start: InetAddress,
|
||||
|
@ -40,7 +40,7 @@ pub struct IpAssignmentPool {
|
|||
///
|
||||
/// This contains only fields of relevance to the controller. Other fields can be tracked by various
|
||||
/// database implementations such as row last modified, creation time, ownership in an admin panel, etc.
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub struct Network {
|
||||
pub id: NetworkId,
|
||||
|
||||
|
@ -134,18 +134,32 @@ impl Hash for Network {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToString for Network {
|
||||
fn to_string(&self) -> String {
|
||||
zerotier_utils::json::to_json_pretty(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn troo() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
impl Network {
|
||||
pub fn new(id: NetworkId) -> Self {
|
||||
Network {
|
||||
id,
|
||||
name: String::new(),
|
||||
multicast_limit: None,
|
||||
enable_broadcast: None,
|
||||
v4_assign_mode: None,
|
||||
v6_assign_mode: None,
|
||||
ip_assignment_pools: HashSet::new(),
|
||||
ip_routes: HashSet::new(),
|
||||
dns: HashMap::new(),
|
||||
rules: Vec::new(),
|
||||
credential_ttl: None,
|
||||
min_supported_version: None,
|
||||
mtu: None,
|
||||
private: true,
|
||||
learn_members: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check member IP assignments and return 'true' if IP assignments were created or modified.
|
||||
pub async fn assign_ip_addresses<DatabaseImpl: Database + ?Sized>(&self, database: &DatabaseImpl, member: &mut Member) -> bool {
|
||||
let mut modified = false;
|
||||
|
|
|
@ -11,7 +11,7 @@ ed25519-dalek = { version = "1.0.1", features = ["std", "u64_backend"], default-
|
|||
foreign-types = "0.3.1"
|
||||
lazy_static = "^1"
|
||||
openssl = { version = "^0", features = [], default-features = false }
|
||||
poly1305 = { version = "0.7.2", features = [], default-features = false }
|
||||
poly1305 = { version = "0.8.0", features = [], default-features = false }
|
||||
pqc_kyber = { path = "../third_party/kyber", features = ["kyber1024", "reference"], default-features = false }
|
||||
#pqc_kyber = { version = "^0", features = ["kyber1024", "reference"], default-features = false }
|
||||
rand_core = "0.5.1"
|
||||
|
@ -19,9 +19,6 @@ rand_core_062 = { package = "rand_core", version = "0.6.2" }
|
|||
subtle = "2.4.1"
|
||||
x25519-dalek = { version = "1.2.0", features = ["std", "u64_backend"], default-features = false }
|
||||
|
||||
[target."cfg(not(any(target_os = \"macos\", target_os = \"ios\")))".dependencies]
|
||||
openssl = "^0"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3"
|
||||
sha2 = "^0"
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
|
||||
Most of this library is just glue to provide a simple safe API around things like OpenSSL or OS-specific crypto APIs.
|
||||
|
||||
It also contains ZSSP, the V2 ZeroTier Secure Session Protocol.
|
||||
It also contains [ZSSP](ZSSP.md), the V2 ZeroTier Secure Session Protocol.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
use poly1305::universal_hash::NewUniversalHash;
|
||||
use poly1305::universal_hash::KeyInit;
|
||||
|
||||
/// The poly1305 message authentication function.
|
||||
pub struct Poly1305(poly1305::Poly1305, [u8; 16], usize);
|
||||
|
@ -12,7 +12,6 @@ pub const POLY1305_MAC_SIZE: usize = 16;
|
|||
pub fn compute(one_time_key: &[u8], message: &[u8]) -> [u8; POLY1305_MAC_SIZE] {
|
||||
poly1305::Poly1305::new(poly1305::Key::from_slice(one_time_key))
|
||||
.compute_unpadded(message)
|
||||
.into_bytes()
|
||||
.into()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,32 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// A zero-overhead wrapper that signals that a credential is verified.
|
||||
/// A zero-overhead typestate indicating that a credential has been verified as valid.
|
||||
///
|
||||
/// This is used when a function expects to receive an object that is already verified to
|
||||
/// make code more self-documenting and make it semantically harder to accidentally use
|
||||
/// an untrusted object.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
/// What this means is obviously specific to the credential.
|
||||
///
|
||||
/// The purpose of this is to make code more self-documenting and make it harder to accidentally
|
||||
/// use an unverified/unvalidated credential (or other security critical object) where a verified
|
||||
/// one is required.
|
||||
#[repr(transparent)]
|
||||
pub struct Verified<T>(pub T);
|
||||
pub struct Verified<T>(T);
|
||||
|
||||
impl<T> AsRef<T> for Verified<T> {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsMut<T> for Verified<T> {
|
||||
#[inline(always)]
|
||||
fn as_mut(&mut self) -> &mut T {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Verified<T> {
|
||||
type Target = T;
|
||||
|
@ -27,9 +44,78 @@ impl<T> DerefMut for Verified<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Verified<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialEq for Verified<T>
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.eq(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Eq for Verified<T> where T: Eq {}
|
||||
|
||||
impl<T> Ord for Verified<T>
|
||||
where
|
||||
T: Ord,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.0.cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialOrd for Verified<T>
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
self.0.partial_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Hash for Verified<T>
|
||||
where
|
||||
T: Hash,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Debug for Verified<T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("Verified").field(&self.0).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Verified<T> {
|
||||
/// Strip the Verified typestate off this object.
|
||||
#[inline(always)]
|
||||
pub fn unwrap(self) -> T {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Set Verified typestate on an object.
|
||||
#[inline(always)]
|
||||
pub fn assume_verified(o: T) -> Self {
|
||||
Self(o)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::num::NonZeroU64;
|
||||
use std::str::FromStr;
|
||||
|
@ -12,7 +13,7 @@ use zerotier_utils::error::InvalidFormatError;
|
|||
use zerotier_utils::hex;
|
||||
|
||||
/// A unique address on the global ZeroTier VL1 network.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[repr(transparent)]
|
||||
pub struct Address(NonZeroU64);
|
||||
|
||||
|
@ -92,6 +93,13 @@ impl Hash for Address {
|
|||
}
|
||||
}
|
||||
|
||||
impl Debug for Address {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Address {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use std::cmp::Ordering;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io::Write;
|
||||
use std::str::FromStr;
|
||||
|
@ -22,6 +23,7 @@ use zerotier_utils::marshalable::{Marshalable, UnmarshalError};
|
|||
|
||||
use crate::protocol::{ADDRESS_SIZE, ADDRESS_SIZE_STRING, IDENTITY_POW_THRESHOLD};
|
||||
use crate::vl1::Address;
|
||||
use crate::vl1::Verified;
|
||||
|
||||
/// Current maximum size for an identity signature.
|
||||
pub const IDENTITY_MAX_SIGNATURE_SIZE: usize = P384_ECDSA_SIGNATURE_SIZE + 1;
|
||||
|
@ -164,7 +166,7 @@ impl Identity {
|
|||
const FLAG_INCLUDES_SECRETS: u8 = 0x80;
|
||||
|
||||
/// Generate a new identity.
|
||||
pub fn generate() -> Self {
|
||||
pub fn generate() -> Verified<Self> {
|
||||
// First generate an identity with just x25519 keys and derive its address.
|
||||
let mut sha = SHA512::new();
|
||||
let ed25519 = Ed25519KeyPair::generate();
|
||||
|
@ -204,7 +206,7 @@ impl Identity {
|
|||
assert!(id.upgrade().is_ok());
|
||||
assert!(id.p384.is_some() && id.secret.as_ref().unwrap().p384.is_some());
|
||||
|
||||
id
|
||||
Verified::assume_verified(id)
|
||||
}
|
||||
|
||||
/// Upgrade older x25519-only identities to hybrid identities with both x25519 and NIST P-384 curves.
|
||||
|
@ -288,7 +290,7 @@ impl Identity {
|
|||
/// Locally check the validity of this identity.
|
||||
///
|
||||
/// This is somewhat time consuming due to the memory-intensive work algorithm.
|
||||
pub fn validate_identity(&self) -> bool {
|
||||
pub fn validate(self) -> Option<Verified<Self>> {
|
||||
if let Some(p384) = self.p384.as_ref() {
|
||||
let mut self_sign_buf: Vec<u8> = Vec::with_capacity(
|
||||
ADDRESS_SIZE + 4 + C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P384_PUBLIC_KEY_SIZE + P384_PUBLIC_KEY_SIZE,
|
||||
|
@ -301,12 +303,12 @@ impl Identity {
|
|||
let _ = self_sign_buf.write_all(p384.ecdsa.as_bytes());
|
||||
|
||||
if !p384.ecdsa.verify(self_sign_buf.as_slice(), &p384.ecdsa_self_signature) {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
|
||||
let _ = self_sign_buf.write_all(&p384.ecdsa_self_signature);
|
||||
if !ed25519_verify(&self.ed25519, &p384.ed25519_self_signature, self_sign_buf.as_slice()) {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,7 +320,11 @@ impl Identity {
|
|||
let mut digest = sha.finish();
|
||||
zt_address_derivation_work_function(&mut digest);
|
||||
|
||||
return digest[0] < IDENTITY_POW_THRESHOLD && Address::from_bytes(&digest[59..64]).map_or(false, |a| a == self.address);
|
||||
return if digest[0] < IDENTITY_POW_THRESHOLD && Address::from_bytes(&digest[59..64]).map_or(false, |a| a == self.address) {
|
||||
Some(Verified::assume_verified(self))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns true if this identity was upgraded from another older version.
|
||||
|
@ -337,7 +343,7 @@ impl Identity {
|
|||
/// For new identities with P-384 keys a hybrid agreement is performed using both X25519 and NIST P-384 ECDH.
|
||||
/// The final key is derived as HMAC(x25519 secret, p-384 secret) to yield a FIPS-compliant key agreement with
|
||||
/// the X25519 secret being used as a "salt" as far as FIPS is concerned.
|
||||
pub fn agree(&self, other: &Identity) -> Option<Secret<64>> {
|
||||
pub fn agree(&self, other: &Verified<Identity>) -> Option<Secret<64>> {
|
||||
if let Some(secret) = self.secret.as_ref() {
|
||||
let c25519_secret: Secret<64> = Secret(SHA512::hash(&secret.x25519.agree(&other.x25519).0));
|
||||
|
||||
|
@ -822,6 +828,13 @@ impl Hash for Identity {
|
|||
}
|
||||
}
|
||||
|
||||
impl Debug for Identity {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Identity {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
|
@ -887,8 +900,7 @@ mod tests {
|
|||
let id = Identity::from_str(
|
||||
"728efdb79d:0:3077ed0084d8d48a3ac628af6b45d9351e823bff34bc4376cddfc77a3d73a966c7d347bdcc1244d0e99e1b9c961ff5e963092e90ca43b47ff58c114d2d699664:2afaefcd1dca336ed59957eb61919b55009850b0b7088af3ee142672b637d1d49cc882b30a006f9eee42f2211ef8fe1cbe99a16a4436737fc158ce2243c15f12",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(id.validate_identity());
|
||||
.unwrap().validate().unwrap();
|
||||
let self_agree = id.agree(&id).unwrap();
|
||||
assert!(self_agree_expected.as_slice().eq(&self_agree.as_bytes()[..48]));
|
||||
|
||||
|
@ -920,7 +932,6 @@ mod tests {
|
|||
fn marshal_unmarshal_sign_verify_agree() {
|
||||
let gen = Identity::generate();
|
||||
assert!(gen.agree(&gen).is_some());
|
||||
assert!(gen.validate_identity());
|
||||
let bytes = gen.to_secret_bytes().unwrap();
|
||||
let string = gen.to_secret_string();
|
||||
assert!(Identity::from_str(string.as_str()).unwrap().eq(&gen));
|
||||
|
@ -938,57 +949,53 @@ mod tests {
|
|||
assert!(Identity::from_str(string.as_str()).unwrap().secret.is_some());
|
||||
|
||||
let gen2 = Identity::generate();
|
||||
assert!(gen2.validate_identity());
|
||||
assert!(gen2.agree(&gen).unwrap().eq(&gen.agree(&gen2).unwrap()));
|
||||
|
||||
for id_str in GOOD_V0_IDENTITIES {
|
||||
let mut id = Identity::from_str(id_str).unwrap();
|
||||
let mut id = Identity::from_str(id_str).unwrap().validate().unwrap();
|
||||
assert_eq!(id.to_secret_string().as_str(), id_str);
|
||||
|
||||
assert!(id.validate_identity());
|
||||
assert!(id.p384.is_none());
|
||||
|
||||
let idb = id.to_secret_bytes().unwrap();
|
||||
let id_unmarshal = Identity::from_bytes(idb.as_bytes()).unwrap();
|
||||
let id_unmarshal = Identity::from_bytes(idb.as_bytes()).unwrap().validate().unwrap();
|
||||
assert!(id == id_unmarshal);
|
||||
assert!(id_unmarshal.secret.is_some());
|
||||
|
||||
let idb2 = id_unmarshal.to_bytes();
|
||||
let id_unmarshal2 = Identity::from_bytes(&idb2).unwrap();
|
||||
let id_unmarshal2 = Identity::from_bytes(&idb2).unwrap().validate().unwrap();
|
||||
assert!(id_unmarshal2 == id_unmarshal);
|
||||
assert!(id_unmarshal2 == id);
|
||||
assert!(id_unmarshal2.secret.is_none());
|
||||
|
||||
let ids = id.to_string();
|
||||
assert!(Identity::from_str(ids.as_str()).unwrap() == id);
|
||||
assert!(Identity::from_str(ids.as_str()).unwrap() == *id);
|
||||
|
||||
assert!(id.upgrade().is_ok());
|
||||
assert!(id.validate_identity());
|
||||
assert!(id.p384.is_some());
|
||||
assert!(id.secret.as_ref().unwrap().p384.is_some());
|
||||
|
||||
let ids = id.to_string();
|
||||
assert!(Identity::from_str(ids.as_str()).unwrap() == id);
|
||||
assert!(Identity::from_str(ids.as_str()).unwrap() == *id);
|
||||
}
|
||||
for id_str in GOOD_V1_IDENTITIES {
|
||||
let id = Identity::from_str(id_str).unwrap();
|
||||
let id = Identity::from_str(id_str).unwrap().validate().unwrap();
|
||||
assert_eq!(id.to_secret_string().as_str(), id_str);
|
||||
|
||||
assert!(id.validate_identity());
|
||||
assert!(id.p384.is_some());
|
||||
assert!(id.secret.as_ref().unwrap().p384.is_some());
|
||||
|
||||
let idb = id.to_secret_bytes().unwrap();
|
||||
let id_unmarshal = Identity::from_bytes(idb.as_bytes()).unwrap();
|
||||
let id_unmarshal = Identity::from_bytes(idb.as_bytes()).unwrap().validate().unwrap();
|
||||
assert!(id == id_unmarshal);
|
||||
|
||||
let idb2 = id_unmarshal.to_bytes();
|
||||
let id_unmarshal2 = Identity::from_bytes(&idb2).unwrap();
|
||||
let id_unmarshal2 = Identity::from_bytes(&idb2).unwrap().validate().unwrap();
|
||||
assert!(id_unmarshal2 == id_unmarshal);
|
||||
assert!(id_unmarshal2 == id);
|
||||
|
||||
let ids = id.to_string();
|
||||
assert!(Identity::from_str(ids.as_str()).unwrap() == id);
|
||||
assert!(Identity::from_str(ids.as_str()).unwrap() == *id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -222,7 +222,7 @@ impl TryInto<SocketAddrV6> for InetAddress {
|
|||
impl TryInto<SocketAddrV6> for &InetAddress {
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn try_into(self) -> Result<SocketAddrV6, Self::Error> {
|
||||
unsafe {
|
||||
match self.sa.sa_family {
|
||||
|
@ -239,7 +239,7 @@ impl TryInto<SocketAddrV6> for &InetAddress {
|
|||
}
|
||||
|
||||
impl From<&IpAddr> for InetAddress {
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn from(ip: &IpAddr) -> Self {
|
||||
match ip {
|
||||
IpAddr::V4(ip4) => Self::from(ip4),
|
||||
|
@ -284,7 +284,7 @@ impl From<Ipv6Addr> for InetAddress {
|
|||
}
|
||||
|
||||
impl From<&SocketAddr> for InetAddress {
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn from(sa: &SocketAddr) -> Self {
|
||||
match sa {
|
||||
SocketAddr::V4(sa4) => Self::from(sa4),
|
||||
|
@ -353,6 +353,7 @@ impl std::fmt::Debug for InetAddress {
|
|||
const TEMP_SERIALIZE_BUFFER_SIZE: usize = 24;
|
||||
|
||||
impl Serialize for InetAddress {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
|
@ -372,10 +373,12 @@ struct InetAddressVisitor;
|
|||
impl<'de> serde::de::Visitor<'de> for InetAddressVisitor {
|
||||
type Value = InetAddress;
|
||||
|
||||
#[inline]
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("an InetAddress")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
|
@ -390,6 +393,7 @@ impl<'de> serde::de::Visitor<'de> for InetAddressVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
|
@ -399,6 +403,7 @@ impl<'de> serde::de::Visitor<'de> for InetAddressVisitor {
|
|||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for InetAddress {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<InetAddress, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
|
@ -420,7 +425,7 @@ impl InetAddress {
|
|||
|
||||
/// Construct from IP and port.
|
||||
/// If the IP is not either 4 or 16 bytes in length, a nil/0 InetAddress is returned.
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
pub fn from_ip_port(ip: &[u8], port: u16) -> InetAddress {
|
||||
unsafe {
|
||||
let mut c = MaybeUninit::<InetAddress>::uninit().assume_init(); // gets zeroed in set()
|
||||
|
@ -570,6 +575,7 @@ impl InetAddress {
|
|||
}
|
||||
|
||||
/// Get the IP port for this InetAddress.
|
||||
#[inline]
|
||||
pub fn port(&self) -> u16 {
|
||||
unsafe {
|
||||
u16::from_be(match self.sa.sa_family as AddressFamilyType {
|
||||
|
|
|
@ -17,12 +17,6 @@ use zerotier_utils::marshalable::{Marshalable, UnmarshalError};
|
|||
#[repr(transparent)]
|
||||
pub struct MAC(NonZeroU64);
|
||||
|
||||
impl Debug for MAC {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl MAC {
|
||||
#[inline(always)]
|
||||
pub fn from_u64(i: u64) -> Option<MAC> {
|
||||
|
@ -122,6 +116,12 @@ impl Hash for MAC {
|
|||
}
|
||||
}
|
||||
|
||||
impl Debug for MAC {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for MAC {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
|
|
|
@ -24,6 +24,8 @@ pub use path::Path;
|
|||
pub use peer::Peer;
|
||||
pub use rootset::{Root, RootSet};
|
||||
|
||||
pub use zerotier_crypto::verified::Verified;
|
||||
|
||||
#[cfg(feature = "debug_events")]
|
||||
#[allow(unused_macros)]
|
||||
#[macro_export]
|
||||
|
|
|
@ -17,9 +17,9 @@ use crate::vl1::identity::Identity;
|
|||
use crate::vl1::path::{Path, PathServiceResult};
|
||||
use crate::vl1::peer::Peer;
|
||||
use crate::vl1::rootset::RootSet;
|
||||
use crate::vl1::Verified;
|
||||
|
||||
use zerotier_crypto::random;
|
||||
use zerotier_crypto::verified::Verified;
|
||||
use zerotier_utils::error::InvalidParameterError;
|
||||
use zerotier_utils::gate::IntervalGate;
|
||||
use zerotier_utils::hex;
|
||||
|
@ -36,14 +36,14 @@ pub trait VL1AuthProvider: Sync + Send {
|
|||
///
|
||||
/// If this returns false, the node simply drops messages on the floor and refuses
|
||||
/// to init V2 sessions.
|
||||
fn should_respond_to(&self, id: &Identity) -> bool;
|
||||
fn should_respond_to(&self, id: &Verified<Identity>) -> bool;
|
||||
|
||||
/// Check if this node has any trust relationship with the provided identity.
|
||||
///
|
||||
/// This should return true if there is any special trust relationship such as mutual
|
||||
/// membership in a network or for controllers the peer's membership in any network
|
||||
/// they control.
|
||||
fn has_trust_relationship(&self, id: &Identity) -> bool;
|
||||
fn has_trust_relationship(&self, id: &Verified<Identity>) -> bool;
|
||||
}
|
||||
|
||||
/// Trait to be implemented by outside code to provide object storage to VL1
|
||||
|
@ -52,10 +52,10 @@ pub trait VL1AuthProvider: Sync + Send {
|
|||
/// implementers of HostSystem to break this out and allow a user to specify it.
|
||||
pub trait NodeStorage: Sync + Send {
|
||||
/// Load this node's identity from the data store.
|
||||
fn load_node_identity(&self) -> Option<Identity>;
|
||||
fn load_node_identity(&self) -> Option<Verified<Identity>>;
|
||||
|
||||
/// Save this node's identity to the data store.
|
||||
fn save_node_identity(&self, id: &Identity);
|
||||
fn save_node_identity(&self, id: &Verified<Identity>);
|
||||
}
|
||||
|
||||
/// Trait implemented by external code to handle events and provide an interface to the system or application.
|
||||
|
@ -112,7 +112,7 @@ pub trait HostSystem: VL1AuthProvider + NodeStorage + 'static {
|
|||
#[allow(unused_variables)]
|
||||
fn should_use_physical_path<HostSystemImpl: HostSystem + ?Sized>(
|
||||
&self,
|
||||
id: &Identity,
|
||||
id: &Verified<Identity>,
|
||||
endpoint: &Endpoint,
|
||||
local_socket: Option<&HostSystemImpl::LocalSocket>,
|
||||
local_interface: Option<&HostSystemImpl::LocalInterface>,
|
||||
|
@ -126,7 +126,7 @@ pub trait HostSystem: VL1AuthProvider + NodeStorage + 'static {
|
|||
#[allow(unused_variables)]
|
||||
fn get_path_hints<HostSystemImpl: HostSystem + ?Sized>(
|
||||
&self,
|
||||
id: &Identity,
|
||||
id: &Verified<Identity>,
|
||||
) -> Option<
|
||||
Vec<(
|
||||
Endpoint,
|
||||
|
@ -272,7 +272,7 @@ pub struct Node {
|
|||
pub instance_id: [u8; 16],
|
||||
|
||||
/// This node's identity and permanent keys.
|
||||
pub identity: Identity,
|
||||
pub identity: Verified<Identity>,
|
||||
|
||||
/// Interval latches for periodic background tasks.
|
||||
intervals: Mutex<BackgroundTaskIntervals>,
|
||||
|
@ -306,7 +306,7 @@ impl Node {
|
|||
return Err(InvalidParameterError("no identity found and auto-generate not enabled"));
|
||||
} else {
|
||||
let id = Identity::generate();
|
||||
host_system.event(Event::IdentityAutoGenerated(id.clone()));
|
||||
host_system.event(Event::IdentityAutoGenerated(id.as_ref().clone()));
|
||||
host_system.storage().save_node_identity(&id);
|
||||
id
|
||||
}
|
||||
|
@ -319,7 +319,7 @@ impl Node {
|
|||
let old = id.clone();
|
||||
if id.upgrade()? {
|
||||
host_system.storage().save_node_identity(&id);
|
||||
host_system.event(Event::IdentityAutoUpgraded(old, id.clone()));
|
||||
host_system.event(Event::IdentityAutoUpgraded(old.unwrap(), id.as_ref().clone()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -477,7 +477,7 @@ impl Node {
|
|||
let (mut old_root_identities, address_collisions, new_roots, bad_identities, my_root_sets) = {
|
||||
let roots = self.roots.read().unwrap();
|
||||
|
||||
let old_root_identities: Vec<Identity> = roots.roots.iter().map(|(p, _)| p.identity.clone()).collect();
|
||||
let old_root_identities: Vec<Identity> = roots.roots.iter().map(|(p, _)| p.identity.as_ref().clone()).collect();
|
||||
let mut new_roots = HashMap::new();
|
||||
let mut bad_identities = Vec::new();
|
||||
let mut my_root_sets: Option<Vec<u8>> = None;
|
||||
|
@ -497,7 +497,7 @@ impl Node {
|
|||
.read()
|
||||
.unwrap()
|
||||
.get(&m.identity.address)
|
||||
.map_or(false, |p| !p.identity.eq(&m.identity))
|
||||
.map_or(false, |p| !p.identity.as_ref().eq(&m.identity))
|
||||
|| address_collision_check
|
||||
.insert(m.identity.address, &m.identity)
|
||||
.map_or(false, |old_id| !old_id.eq(&m.identity))
|
||||
|
@ -522,7 +522,8 @@ impl Node {
|
|||
if let Some(peer) = peers.get(&m.identity.address) {
|
||||
new_roots.insert(peer.clone(), m.endpoints.as_ref().unwrap().iter().cloned().collect());
|
||||
} else {
|
||||
if let Some(peer) = Peer::new(&self.identity, m.identity.clone(), time_ticks) {
|
||||
if let Some(peer) = Peer::new(&self.identity, Verified::assume_verified(m.identity.clone()), time_ticks)
|
||||
{
|
||||
drop(peers);
|
||||
new_roots.insert(
|
||||
self.peers
|
||||
|
@ -557,7 +558,7 @@ impl Node {
|
|||
)));
|
||||
}
|
||||
|
||||
let mut new_root_identities: Vec<Identity> = new_roots.iter().map(|(p, _)| p.identity.clone()).collect();
|
||||
let mut new_root_identities: Vec<Identity> = new_roots.iter().map(|(p, _)| p.identity.as_ref().clone()).collect();
|
||||
old_root_identities.sort_unstable();
|
||||
new_root_identities.sort_unstable();
|
||||
|
||||
|
@ -991,7 +992,7 @@ impl Node {
|
|||
authoritative: bool,
|
||||
) {
|
||||
if authoritative {
|
||||
if received_identity.validate_identity() {
|
||||
if let Some(received_identity) = received_identity.validate() {
|
||||
let mut whois_queue = self.whois_queue.lock().unwrap();
|
||||
if let Some(qi) = whois_queue.get_mut(&received_identity.address) {
|
||||
let address = received_identity.address;
|
||||
|
@ -1124,12 +1125,12 @@ impl InnerProtocol for DummyInnerProtocol {}
|
|||
|
||||
impl VL1AuthProvider for DummyInnerProtocol {
|
||||
#[inline(always)]
|
||||
fn should_respond_to(&self, id: &Identity) -> bool {
|
||||
fn should_respond_to(&self, _: &Verified<Identity>) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn has_trust_relationship(&self, id: &Identity) -> bool {
|
||||
fn has_trust_relationship(&self, _: &Verified<Identity>) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,14 @@ use crate::protocol::*;
|
|||
use crate::vl1::address::Address;
|
||||
use crate::vl1::debug_event;
|
||||
use crate::vl1::node::*;
|
||||
use crate::vl1::Verified;
|
||||
use crate::vl1::{Endpoint, Identity, Path};
|
||||
use crate::{VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION};
|
||||
|
||||
pub(crate) const SERVICE_INTERVAL_MS: i64 = 10000;
|
||||
|
||||
pub struct Peer {
|
||||
pub identity: Identity,
|
||||
pub identity: Verified<Identity>,
|
||||
|
||||
v1_proto_static_secret: v1::SymmetricSecret,
|
||||
paths: Mutex<Vec<PeerPath>>,
|
||||
|
@ -61,7 +62,7 @@ impl Peer {
|
|||
///
|
||||
/// This only returns None if this_node_identity does not have its secrets or if some
|
||||
/// fatal error occurs performing key agreement between the two identities.
|
||||
pub(crate) fn new(this_node_identity: &Identity, id: Identity, time_ticks: i64) -> Option<Self> {
|
||||
pub(crate) fn new(this_node_identity: &Verified<Identity>, id: Verified<Identity>, time_ticks: i64) -> Option<Self> {
|
||||
this_node_identity.agree(&id).map(|static_secret| -> Self {
|
||||
Self {
|
||||
identity: id,
|
||||
|
|
|
@ -119,7 +119,7 @@ impl RootSet {
|
|||
}
|
||||
}
|
||||
|
||||
return Some(Verified(self));
|
||||
return Some(Verified::assume_verified(self));
|
||||
}
|
||||
|
||||
/// Add a member to this definition, replacing any current entry with this address.
|
||||
|
|
|
@ -21,7 +21,6 @@ pub struct MulticastAuthority {
|
|||
}
|
||||
|
||||
impl MulticastAuthority {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self { subscriptions: RwLock::new(HashMap::new()) }
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::str::FromStr;
|
||||
|
||||
|
@ -34,6 +35,20 @@ impl Hash for MulticastGroup {
|
|||
state.write_u32(self.adi);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for MulticastGroup {
|
||||
fn to_string(&self) -> String {
|
||||
format!("{}/{}", self.mac.to_string(), self.adi.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for MulticastGroup {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for MulticastGroup {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
|
|
|
@ -17,7 +17,7 @@ use zerotier_utils::error::InvalidParameterError;
|
|||
use zerotier_utils::marshalable::Marshalable;
|
||||
|
||||
/// Network configuration object sent to nodes by network controllers.
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct NetworkConfig {
|
||||
/// Network ID
|
||||
pub network_id: NetworkId,
|
||||
|
@ -420,7 +420,7 @@ mod proto_v1_field_name {
|
|||
}
|
||||
|
||||
/// SSO authentication configuration object.
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct SSOAuthConfiguration {
|
||||
pub version: u32,
|
||||
pub authentication_url: String,
|
||||
|
@ -435,7 +435,7 @@ pub struct SSOAuthConfiguration {
|
|||
///
|
||||
/// These are also handed out to V2 nodes to use when communicating with V1 nodes on
|
||||
/// networks that support older protocol versions.
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct V1Credentials {
|
||||
pub revision: u64,
|
||||
pub max_delta: u64,
|
||||
|
@ -447,7 +447,7 @@ pub struct V1Credentials {
|
|||
}
|
||||
|
||||
/// Statically pushed L3 IP routes included with a network configuration.
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
pub struct IpRoute {
|
||||
pub target: InetAddress,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::num::NonZeroU64;
|
||||
use std::str::FromStr;
|
||||
|
@ -97,6 +98,13 @@ impl ToString for NetworkId {
|
|||
}
|
||||
}
|
||||
|
||||
impl Debug for NetworkId {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for NetworkId {
|
||||
type Err = InvalidFormatError;
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use std::fmt::Debug;
|
||||
use std::mem::{size_of, zeroed};
|
||||
use std::net::Ipv6Addr;
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
|
@ -159,44 +161,44 @@ union RuleValue {
|
|||
|
||||
/// Trait to implement in order to evaluate rules.
|
||||
pub trait RuleVisitor {
|
||||
fn action_drop(self) -> bool;
|
||||
fn action_accept(self) -> bool;
|
||||
fn action_tee(self, address: Address, flags: u32, length: u16) -> bool;
|
||||
fn action_watch(self, address: Address, flags: u32, length: u16) -> bool;
|
||||
fn action_redirect(self, address: Address, flags: u32, length: u16) -> bool;
|
||||
fn action_break(self) -> bool;
|
||||
fn action_priority(self, qos_bucket: u8) -> bool;
|
||||
fn action_drop(&mut self) -> bool;
|
||||
fn action_accept(&mut self) -> bool;
|
||||
fn action_tee(&mut self, address: Address, flags: u32, length: u16) -> bool;
|
||||
fn action_watch(&mut self, address: Address, flags: u32, length: u16) -> bool;
|
||||
fn action_redirect(&mut self, address: Address, flags: u32, length: u16) -> bool;
|
||||
fn action_break(&mut self) -> bool;
|
||||
fn action_priority(&mut self, qos_bucket: u8) -> bool;
|
||||
|
||||
fn invalid_rule(self) -> bool;
|
||||
fn invalid_rule(&mut self) -> bool;
|
||||
|
||||
fn match_source_zerotier_address(self, not: bool, or: bool, address: Address);
|
||||
fn match_dest_zerotier_address(self, not: bool, or: bool, address: Address);
|
||||
fn match_vlan_id(self, not: bool, or: bool, id: u16);
|
||||
fn match_vlan_pcp(self, not: bool, or: bool, pcp: u8);
|
||||
fn match_vlan_dei(self, not: bool, or: bool, dei: u8);
|
||||
fn match_mac_source(self, not: bool, or: bool, mac: MAC);
|
||||
fn match_mac_dest(self, not: bool, or: bool, mac: MAC);
|
||||
fn match_ipv4_source(self, not: bool, or: bool, ip: &[u8; 4], mask: u8);
|
||||
fn match_ipv4_dest(self, not: bool, or: bool, ip: &[u8; 4], mask: u8);
|
||||
fn match_ipv6_source(self, not: bool, or: bool, ip: &[u8; 16], mask: u8);
|
||||
fn match_ipv6_dest(self, not: bool, or: bool, ip: &[u8; 16], mask: u8);
|
||||
fn match_ip_tos(self, not: bool, or: bool, mask: u8, start: u8, end: u8);
|
||||
fn match_ip_protocol(self, not: bool, or: bool, protocol: u8);
|
||||
fn match_ethertype(self, not: bool, or: bool, ethertype: u16);
|
||||
fn match_icmp(self, not: bool, or: bool, _type: u8, code: u8, flags: u8);
|
||||
fn match_ip_source_port_range(self, not: bool, or: bool, start: u16, end: u16);
|
||||
fn match_ip_dest_port_range(self, not: bool, or: bool, start: u16, end: u16);
|
||||
fn match_characteristics(self, not: bool, or: bool, characteristics: u64);
|
||||
fn match_frame_size_range(self, not: bool, or: bool, start: u16, end: u16);
|
||||
fn match_random(self, not: bool, or: bool, probability: u32);
|
||||
fn match_tags_difference(self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_tags_bitwise_and(self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_tags_bitwise_or(self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_tags_bitwise_xor(self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_tags_equal(self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_tag_sender(self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_tag_receiver(self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_integer_range(self, not: bool, or: bool, start: u64, end: u64, idx: u16, format: u8);
|
||||
fn match_source_zerotier_address(&mut self, not: bool, or: bool, address: Address);
|
||||
fn match_dest_zerotier_address(&mut self, not: bool, or: bool, address: Address);
|
||||
fn match_vlan_id(&mut self, not: bool, or: bool, id: u16);
|
||||
fn match_vlan_pcp(&mut self, not: bool, or: bool, pcp: u8);
|
||||
fn match_vlan_dei(&mut self, not: bool, or: bool, dei: u8);
|
||||
fn match_mac_source(&mut self, not: bool, or: bool, mac: MAC);
|
||||
fn match_mac_dest(&mut self, not: bool, or: bool, mac: MAC);
|
||||
fn match_ipv4_source(&mut self, not: bool, or: bool, ip: &[u8; 4], mask: u8);
|
||||
fn match_ipv4_dest(&mut self, not: bool, or: bool, ip: &[u8; 4], mask: u8);
|
||||
fn match_ipv6_source(&mut self, not: bool, or: bool, ip: &[u8; 16], mask: u8);
|
||||
fn match_ipv6_dest(&mut self, not: bool, or: bool, ip: &[u8; 16], mask: u8);
|
||||
fn match_ip_tos(&mut self, not: bool, or: bool, mask: u8, start: u8, end: u8);
|
||||
fn match_ip_protocol(&mut self, not: bool, or: bool, protocol: u8);
|
||||
fn match_ethertype(&mut self, not: bool, or: bool, ethertype: u16);
|
||||
fn match_icmp(&mut self, not: bool, or: bool, _type: u8, code: u8, flags: u8);
|
||||
fn match_ip_source_port_range(&mut self, not: bool, or: bool, start: u16, end: u16);
|
||||
fn match_ip_dest_port_range(&mut self, not: bool, or: bool, start: u16, end: u16);
|
||||
fn match_characteristics(&mut self, not: bool, or: bool, characteristics: u64);
|
||||
fn match_frame_size_range(&mut self, not: bool, or: bool, start: u16, end: u16);
|
||||
fn match_random(&mut self, not: bool, or: bool, probability: u32);
|
||||
fn match_tags_difference(&mut self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_tags_bitwise_and(&mut self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_tags_bitwise_or(&mut self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_tags_bitwise_xor(&mut self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_tags_equal(&mut self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_tag_sender(&mut self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_tag_receiver(&mut self, not: bool, or: bool, id: u32, value: u32);
|
||||
fn match_integer_range(&mut self, not: bool, or: bool, start: u64, end: u64, idx: u16, format: u8);
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
|
@ -220,8 +222,8 @@ impl Rule {
|
|||
}
|
||||
|
||||
/// Execute the visitor, returning the result of action methods and true for condition methods.
|
||||
#[inline(always)]
|
||||
pub fn visit<V: RuleVisitor>(&self, v: V) -> bool {
|
||||
#[inline]
|
||||
pub fn visit<V: RuleVisitor>(&self, v: &mut V) -> bool {
|
||||
unsafe {
|
||||
let t = self.t;
|
||||
let not = (t & 0x80) != 0;
|
||||
|
@ -576,6 +578,7 @@ impl Marshalable for Rule {
|
|||
}
|
||||
|
||||
impl PartialEq for Rule {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
unsafe { (*(self as *const Self).cast::<[u8; size_of::<Self>()]>()).eq(&*(other as *const Self).cast::<[u8; size_of::<Self>()]>()) }
|
||||
}
|
||||
|
@ -583,6 +586,21 @@ impl PartialEq for Rule {
|
|||
|
||||
impl Eq for Rule {}
|
||||
|
||||
impl ToString for Rule {
|
||||
fn to_string(&self) -> String {
|
||||
let mut s = RuleStringer(String::with_capacity(32));
|
||||
self.visit(&mut s);
|
||||
s.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Rule {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Rule {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
|
@ -675,7 +693,7 @@ static HR_NAME_TO_RULE_TYPE: phf::Map<&'static str, u8> = phf_map! {
|
|||
"MATCH_TAGS_EQUAL" => match_cond::TAGS_EQUAL,
|
||||
"MATCH_TAG_SENDER" => match_cond::TAG_SENDER,
|
||||
"MATCH_TAG_RECEIVER" => match_cond::TAG_RECEIVER,
|
||||
"INTEGER_RANGE" => match_cond::INTEGER_RANGE,
|
||||
"MATCH_INTEGER_RANGE" => match_cond::INTEGER_RANGE,
|
||||
};
|
||||
|
||||
/// A "bag of fields" used to serialize/deserialize rules in human readable form e.g. JSON.
|
||||
|
@ -860,21 +878,22 @@ impl<'a> HumanReadableRule<'a> {
|
|||
|
||||
fn from_rule(r: &Rule) -> Self {
|
||||
let mut hr = HumanReadableRule::default();
|
||||
r.visit(MakeHumanReadable(&mut hr));
|
||||
r.visit(&mut MakeHumanReadable(&mut hr));
|
||||
hr
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
struct MakeHumanReadable<'a>(&'a mut HumanReadableRule<'static>);
|
||||
|
||||
impl<'a> MakeHumanReadable<'a> {
|
||||
fn do_tag(self, t: &'static str, not: bool, or: bool, id: u32, value: u32) {
|
||||
fn do_tag(&mut self, t: &'static str, not: bool, or: bool, id: u32, value: u32) {
|
||||
let _ = self.0.id.insert(id);
|
||||
let _ = self.0.value.insert(value);
|
||||
self.do_cond(t, not, or);
|
||||
}
|
||||
|
||||
fn do_cond(self, t: &'static str, not: bool, or: bool) {
|
||||
fn do_cond(&mut self, t: &'static str, not: bool, or: bool) {
|
||||
self.0._type = t;
|
||||
if not {
|
||||
let _ = self.0.not.insert(not);
|
||||
|
@ -887,19 +906,19 @@ impl<'a> MakeHumanReadable<'a> {
|
|||
|
||||
impl<'a> RuleVisitor for MakeHumanReadable<'a> {
|
||||
#[inline(always)]
|
||||
fn action_drop(self) -> bool {
|
||||
fn action_drop(&mut self) -> bool {
|
||||
self.0._type = "ACTION_DROP";
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn action_accept(self) -> bool {
|
||||
fn action_accept(&mut self) -> bool {
|
||||
self.0._type = "ACTION_ACCEPT";
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn action_tee(self, address: Address, flags: u32, length: u16) -> bool {
|
||||
fn action_tee(&mut self, address: Address, flags: u32, length: u16) -> bool {
|
||||
self.0._type = "ACTION_TEE";
|
||||
let _ = self.0.address.insert(address);
|
||||
let _ = self.0.flags.insert(flags);
|
||||
|
@ -908,7 +927,7 @@ impl<'a> RuleVisitor for MakeHumanReadable<'a> {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn action_watch(self, address: Address, flags: u32, length: u16) -> bool {
|
||||
fn action_watch(&mut self, address: Address, flags: u32, length: u16) -> bool {
|
||||
self.0._type = "ACTION_WATCH";
|
||||
let _ = self.0.address.insert(address);
|
||||
let _ = self.0.flags.insert(flags);
|
||||
|
@ -917,7 +936,7 @@ impl<'a> RuleVisitor for MakeHumanReadable<'a> {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn action_redirect(self, address: Address, flags: u32, length: u16) -> bool {
|
||||
fn action_redirect(&mut self, address: Address, flags: u32, length: u16) -> bool {
|
||||
self.0._type = "ACTION_REDIRECT";
|
||||
let _ = self.0.address.insert(address);
|
||||
let _ = self.0.flags.insert(flags);
|
||||
|
@ -926,91 +945,91 @@ impl<'a> RuleVisitor for MakeHumanReadable<'a> {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn action_break(self) -> bool {
|
||||
fn action_break(&mut self) -> bool {
|
||||
self.0._type = "ACTION_BREAK";
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn action_priority(self, qos_bucket: u8) -> bool {
|
||||
fn action_priority(&mut self, qos_bucket: u8) -> bool {
|
||||
self.0._type = "ACTION_PRIORITY";
|
||||
let _ = self.0.qosBucket.insert(qos_bucket);
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn invalid_rule(self) -> bool {
|
||||
fn invalid_rule(&mut self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_source_zerotier_address(self, not: bool, or: bool, address: Address) {
|
||||
fn match_source_zerotier_address(&mut self, not: bool, or: bool, address: Address) {
|
||||
let _ = self.0.zt.insert(address);
|
||||
self.do_cond("MATCH_SOURCE_ZEROTIER_ADDRESS", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_dest_zerotier_address(self, not: bool, or: bool, address: Address) {
|
||||
fn match_dest_zerotier_address(&mut self, not: bool, or: bool, address: Address) {
|
||||
let _ = self.0.zt.insert(address);
|
||||
self.do_cond("MATCH_DEST_ZEROTIER_ADDRESS", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_vlan_id(self, not: bool, or: bool, id: u16) {
|
||||
fn match_vlan_id(&mut self, not: bool, or: bool, id: u16) {
|
||||
let _ = self.0.vlanId.insert(id);
|
||||
self.do_cond("MATCH_VLAN_ID", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_vlan_pcp(self, not: bool, or: bool, pcp: u8) {
|
||||
fn match_vlan_pcp(&mut self, not: bool, or: bool, pcp: u8) {
|
||||
let _ = self.0.vlanPcp.insert(pcp);
|
||||
self.do_cond("MATCH_VLAN_PCP", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_vlan_dei(self, not: bool, or: bool, dei: u8) {
|
||||
fn match_vlan_dei(&mut self, not: bool, or: bool, dei: u8) {
|
||||
let _ = self.0.vlanDei.insert(dei);
|
||||
self.do_cond("MATCH_VLAN_DEI", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_mac_source(self, not: bool, or: bool, mac: MAC) {
|
||||
fn match_mac_source(&mut self, not: bool, or: bool, mac: MAC) {
|
||||
let _ = self.0.mac.insert(mac);
|
||||
self.do_cond("MATCH_MAC_SOURCE", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_mac_dest(self, not: bool, or: bool, mac: MAC) {
|
||||
fn match_mac_dest(&mut self, not: bool, or: bool, mac: MAC) {
|
||||
let _ = self.0.mac.insert(mac);
|
||||
self.do_cond("MATCH_MAC_DEST", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ipv4_source(self, not: bool, or: bool, ip: &[u8; 4], mask: u8) {
|
||||
fn match_ipv4_source(&mut self, not: bool, or: bool, ip: &[u8; 4], mask: u8) {
|
||||
let _ = self.0.ip.insert(InetAddress::from_ip_port(ip, mask as u16));
|
||||
self.do_cond("MATCH_IPV4_SOURCE", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ipv4_dest(self, not: bool, or: bool, ip: &[u8; 4], mask: u8) {
|
||||
fn match_ipv4_dest(&mut self, not: bool, or: bool, ip: &[u8; 4], mask: u8) {
|
||||
let _ = self.0.ip.insert(InetAddress::from_ip_port(ip, mask as u16));
|
||||
self.do_cond("MATCH_IPV4_DEST", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ipv6_source(self, not: bool, or: bool, ip: &[u8; 16], mask: u8) {
|
||||
fn match_ipv6_source(&mut self, not: bool, or: bool, ip: &[u8; 16], mask: u8) {
|
||||
let _ = self.0.ip.insert(InetAddress::from_ip_port(ip, mask as u16));
|
||||
self.do_cond("MATCH_IPV6_SOURCE", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ipv6_dest(self, not: bool, or: bool, ip: &[u8; 16], mask: u8) {
|
||||
fn match_ipv6_dest(&mut self, not: bool, or: bool, ip: &[u8; 16], mask: u8) {
|
||||
let _ = self.0.ip.insert(InetAddress::from_ip_port(ip, mask as u16));
|
||||
self.do_cond("MATCH_IPV6_DEST", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ip_tos(self, not: bool, or: bool, mask: u8, start: u8, end: u8) {
|
||||
fn match_ip_tos(&mut self, not: bool, or: bool, mask: u8, start: u8, end: u8) {
|
||||
let _ = self.0.mask.insert(mask as u64);
|
||||
let _ = self.0.start.insert(start as u64);
|
||||
let _ = self.0.end.insert(end as u64);
|
||||
|
@ -1018,19 +1037,19 @@ impl<'a> RuleVisitor for MakeHumanReadable<'a> {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ip_protocol(self, not: bool, or: bool, protocol: u8) {
|
||||
fn match_ip_protocol(&mut self, not: bool, or: bool, protocol: u8) {
|
||||
let _ = self.0.ipProtocol.insert(protocol);
|
||||
self.do_cond("MATCH_IP_PROTOCOL", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ethertype(self, not: bool, or: bool, ethertype: u16) {
|
||||
fn match_ethertype(&mut self, not: bool, or: bool, ethertype: u16) {
|
||||
let _ = self.0.etherType.insert(ethertype);
|
||||
self.do_cond("MATCH_ETHERTYPE", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_icmp(self, not: bool, or: bool, _type: u8, code: u8, flags: u8) {
|
||||
fn match_icmp(&mut self, not: bool, or: bool, _type: u8, code: u8, flags: u8) {
|
||||
let _ = self.0.icmpType.insert(_type);
|
||||
if (flags & 0x01) != 0 {
|
||||
let _ = self.0.icmpCode.insert(code);
|
||||
|
@ -1039,80 +1058,662 @@ impl<'a> RuleVisitor for MakeHumanReadable<'a> {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ip_source_port_range(self, not: bool, or: bool, start: u16, end: u16) {
|
||||
fn match_ip_source_port_range(&mut self, not: bool, or: bool, start: u16, end: u16) {
|
||||
let _ = self.0.start.insert(start as u64);
|
||||
let _ = self.0.end.insert(end as u64);
|
||||
self.do_cond("MATCH_IP_SOURCE_PORT_RANGE", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ip_dest_port_range(self, not: bool, or: bool, start: u16, end: u16) {
|
||||
fn match_ip_dest_port_range(&mut self, not: bool, or: bool, start: u16, end: u16) {
|
||||
let _ = self.0.start.insert(start as u64);
|
||||
let _ = self.0.end.insert(end as u64);
|
||||
self.do_cond("MATCH_IP_DEST_PORT_RANGE", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_characteristics(self, not: bool, or: bool, characteristics: u64) {
|
||||
fn match_characteristics(&mut self, not: bool, or: bool, characteristics: u64) {
|
||||
let _ = self.0.mask.insert(characteristics);
|
||||
self.do_cond("MATCH_CHARACTERISTICS", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_frame_size_range(self, not: bool, or: bool, start: u16, end: u16) {
|
||||
fn match_frame_size_range(&mut self, not: bool, or: bool, start: u16, end: u16) {
|
||||
let _ = self.0.start.insert(start as u64);
|
||||
let _ = self.0.end.insert(end as u64);
|
||||
self.do_cond("MATCH_FRAME_SIZE_RANGE", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_random(self, not: bool, or: bool, probability: u32) {
|
||||
fn match_random(&mut self, not: bool, or: bool, probability: u32) {
|
||||
let _ = self.0.probability.insert(probability);
|
||||
self.do_cond("MATCH_RANDOM", not, or);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tags_difference(self, not: bool, or: bool, id: u32, value: u32) {
|
||||
fn match_tags_difference(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.do_tag("MATCH_TAGS_DIFFERENCE", not, or, id, value);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tags_bitwise_and(self, not: bool, or: bool, id: u32, value: u32) {
|
||||
fn match_tags_bitwise_and(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.do_tag("MATCH_TAGS_BITWISE_AND", not, or, id, value);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tags_bitwise_or(self, not: bool, or: bool, id: u32, value: u32) {
|
||||
fn match_tags_bitwise_or(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.do_tag("MATCH_TAGS_BITWISE_OR", not, or, id, value);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tags_bitwise_xor(self, not: bool, or: bool, id: u32, value: u32) {
|
||||
fn match_tags_bitwise_xor(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.do_tag("MATCH_TAGS_BITWISE_XOR", not, or, id, value);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tags_equal(self, not: bool, or: bool, id: u32, value: u32) {
|
||||
fn match_tags_equal(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.do_tag("MATCH_TAGS_EQUAL", not, or, id, value);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tag_sender(self, not: bool, or: bool, id: u32, value: u32) {
|
||||
fn match_tag_sender(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.do_tag("MATCH_TAG_SENDER", not, or, id, value);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tag_receiver(self, not: bool, or: bool, id: u32, value: u32) {
|
||||
fn match_tag_receiver(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.do_tag("MATCH_TAG_RECEIVER", not, or, id, value);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_integer_range(self, not: bool, or: bool, start: u64, end: u64, idx: u16, format: u8) {
|
||||
fn match_integer_range(&mut self, not: bool, or: bool, start: u64, end: u64, idx: u16, format: u8) {
|
||||
let _ = self.0.start.insert(start);
|
||||
let _ = self.0.end.insert(end);
|
||||
let _ = self.0.idx.insert(idx);
|
||||
let _ = self.0.little.insert((format & 0x80) != 0);
|
||||
let _ = self.0.bits.insert((format & 63) + 1);
|
||||
self.do_cond("INTEGER_RANGE", not, or);
|
||||
self.do_cond("MATCH_INTEGER_RANGE", not, or);
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
struct RuleStringer(String);
|
||||
|
||||
impl RuleVisitor for RuleStringer {
|
||||
#[inline(always)]
|
||||
fn action_drop(&mut self) -> bool {
|
||||
self.0.push_str("ACTION_DROP");
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn action_accept(&mut self) -> bool {
|
||||
self.0.push_str("ACTION_ACCEPT");
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn action_tee(&mut self, address: Address, flags: u32, length: u16) -> bool {
|
||||
self.0 = format!("ACTION_TEE({}, {}, {})", address.to_string(), flags, length);
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn action_watch(&mut self, address: Address, flags: u32, length: u16) -> bool {
|
||||
self.0 = format!("ACTION_WATCH({}, {}, {})", address.to_string(), flags, length);
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn action_redirect(&mut self, address: Address, flags: u32, length: u16) -> bool {
|
||||
self.0 = format!("ACTION_REDIRECT({}, {}, {})", address.to_string(), flags, length);
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn action_break(&mut self) -> bool {
|
||||
self.0.push_str("ACTION_BREAK");
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn action_priority(&mut self, qos_bucket: u8) -> bool {
|
||||
self.0 = format!("ACTION_PRIORITY({})", qos_bucket);
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn invalid_rule(&mut self) -> bool {
|
||||
self.0.push_str("(INVALID RULE)");
|
||||
false
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_source_zerotier_address(&mut self, not: bool, or: bool, address: Address) {
|
||||
self.0 = format!(
|
||||
"MATCH_SOURCE_ZEROTIER_ADDRESS({}{}{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
address.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_dest_zerotier_address(&mut self, not: bool, or: bool, address: Address) {
|
||||
self.0 = format!(
|
||||
"MATCH_DEST_ZEROTIER_ADDRESS({}{}{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
address.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_vlan_id(&mut self, not: bool, or: bool, id: u16) {
|
||||
self.0 = format!(
|
||||
"MATCH_VLAN_ID({}{}{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
id
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_vlan_pcp(&mut self, not: bool, or: bool, pcp: u8) {
|
||||
self.0 = format!(
|
||||
"MATCH_VLAN_PCP({}{}{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
pcp
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_vlan_dei(&mut self, not: bool, or: bool, dei: u8) {
|
||||
self.0 = format!(
|
||||
"MATCH_VLAN_DEI({}{}{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
dei
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_mac_source(&mut self, not: bool, or: bool, mac: MAC) {
|
||||
self.0 = format!(
|
||||
"MATCH_MAC_SOURCE({}{}{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
mac.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_mac_dest(&mut self, not: bool, or: bool, mac: MAC) {
|
||||
self.0 = format!(
|
||||
"MATCH_MAC_DEST({}{}{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
mac.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ipv4_source(&mut self, not: bool, or: bool, ip: &[u8; 4], mask: u8) {
|
||||
self.0 = format!(
|
||||
"MATCH_IPV4_SOURCE({}{}{}.{}.{}.{}/{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
ip[0],
|
||||
ip[1],
|
||||
ip[2],
|
||||
ip[3],
|
||||
mask
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ipv4_dest(&mut self, not: bool, or: bool, ip: &[u8; 4], mask: u8) {
|
||||
self.0 = format!(
|
||||
"MATCH_IPV4_DEST({}{}{}.{}.{}.{}/{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
ip[0],
|
||||
ip[1],
|
||||
ip[2],
|
||||
ip[3],
|
||||
mask
|
||||
);
|
||||
}
|
||||
|
||||
fn match_ipv6_source(&mut self, not: bool, or: bool, ip: &[u8; 16], mask: u8) {
|
||||
self.0 = format!(
|
||||
"MATCH_IPV6_SOURCE({}{}{}/{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
Ipv6Addr::from(*ip).to_string(),
|
||||
mask
|
||||
);
|
||||
}
|
||||
|
||||
fn match_ipv6_dest(&mut self, not: bool, or: bool, ip: &[u8; 16], mask: u8) {
|
||||
self.0 = format!(
|
||||
"MATCH_IPV6_DEST({}{}{}/{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
Ipv6Addr::from(*ip).to_string(),
|
||||
mask
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ip_tos(&mut self, not: bool, or: bool, mask: u8, start: u8, end: u8) {
|
||||
self.0 = format!(
|
||||
"MATCH_IP_TOS({}{}{}&{}-{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
mask,
|
||||
start,
|
||||
end
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ip_protocol(&mut self, not: bool, or: bool, protocol: u8) {
|
||||
self.0 = format!(
|
||||
"MATCH_IP_PROTOCOL({}{}{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
protocol
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ethertype(&mut self, not: bool, or: bool, ethertype: u16) {
|
||||
self.0 = format!(
|
||||
"MATCH_ETHERTYPE({}{}{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
ethertype
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_icmp(&mut self, not: bool, or: bool, _type: u8, code: u8, flags: u8) {
|
||||
self.0 = format!(
|
||||
"MATCH_ICMP({}{} {}, {}, {})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
_type,
|
||||
code,
|
||||
flags
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ip_source_port_range(&mut self, not: bool, or: bool, start: u16, end: u16) {
|
||||
self.0 = format!(
|
||||
"MATCH_IP_SOURCE_PORT_RANGE({}{}{}-{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
start,
|
||||
end
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_ip_dest_port_range(&mut self, not: bool, or: bool, start: u16, end: u16) {
|
||||
self.0 = format!(
|
||||
"MATCH_IP_DEST_PORT_RANGE({}{}{}-{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
start,
|
||||
end
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_characteristics(&mut self, not: bool, or: bool, characteristics: u64) {
|
||||
self.0 = format!(
|
||||
"MATCH_IP_CHARACTERISTICS({}{}{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
zerotier_utils::hex::to_string_u64(characteristics, false)
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_frame_size_range(&mut self, not: bool, or: bool, start: u16, end: u16) {
|
||||
self.0 = format!(
|
||||
"MATCH_FRAME_SIZE_RANGE({}{}{}-{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
start,
|
||||
end
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_random(&mut self, not: bool, or: bool, probability: u32) {
|
||||
self.0 = format!(
|
||||
"MATCH_RANDOM({}{}{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
probability
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tags_difference(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.0 = format!(
|
||||
"MATCH_TAGS_DIFFERENCE({}{}{}<>{})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
id,
|
||||
value
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tags_bitwise_and(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.0 = format!(
|
||||
"MATCH_TAGS_BITWISE_AND({}{}{}&{}!=0)",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
id,
|
||||
value
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tags_bitwise_or(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.0 = format!(
|
||||
"MATCH_TAGS_BITWISE_OR({}{}{}|{}!=0)",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
id,
|
||||
value
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tags_bitwise_xor(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.0 = format!(
|
||||
"MATCH_TAGS_BITWISE_XOR({}{}{}^{}!=0)",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
id,
|
||||
value
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tags_equal(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.0 = format!(
|
||||
"MATCH_TAGS_EQUAL({}{}{}=={})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
id,
|
||||
value
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tag_sender(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.0 = format!(
|
||||
"MATCH_TAG_SENDER({}{}{}=={})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
id,
|
||||
value
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_tag_receiver(&mut self, not: bool, or: bool, id: u32, value: u32) {
|
||||
self.0 = format!(
|
||||
"MATCH_TAG_RECEIVER({}{}{}=={})",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
id,
|
||||
value
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn match_integer_range(&mut self, not: bool, or: bool, start: u64, end: u64, idx: u16, format: u8) {
|
||||
self.0 = format!(
|
||||
"MATCH_INTEGER_RANGE({}{}({}, {}, {}, {}))",
|
||||
if or {
|
||||
"|"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if not {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
start,
|
||||
end,
|
||||
idx,
|
||||
format
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ use zerotier_utils::memory;
|
|||
/// This was done to permit some things such as geo-fencing that were never implemented, so it's
|
||||
/// a bit of a case of YAGNI. In V2 this is deprecated in favor of a more standard sort of
|
||||
/// certificate.
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct CertificateOfMembership {
|
||||
pub network_id: NetworkId,
|
||||
pub timestamp: i64,
|
||||
|
@ -173,7 +173,7 @@ impl CertificateOfMembership {
|
|||
pub fn verify(self, issuer: &Identity, expect_issued_to: &Identity) -> Option<Verified<Self>> {
|
||||
if Self::v1_proto_issued_to_fingerprint(expect_issued_to).eq(&self.issued_to_fingerprint.as_bytes()[..32]) {
|
||||
if issuer.verify(&self.v1_proto_get_qualifier_bytes(), self.signature.as_bytes()) {
|
||||
return Some(Verified(self));
|
||||
return Some(Verified::assume_verified(self));
|
||||
}
|
||||
}
|
||||
return None;
|
||||
|
|
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
|||
use zerotier_utils::arrayvec::ArrayVec;
|
||||
use zerotier_utils::error::InvalidParameterError;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
pub enum Thing {
|
||||
Ipv4([u8; 4]),
|
||||
Ipv6([u8; 16]),
|
||||
|
@ -27,7 +27,7 @@ impl Thing {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct CertificateOfOwnership {
|
||||
pub network_id: NetworkId,
|
||||
pub timestamp: i64,
|
||||
|
|
|
@ -3,6 +3,7 @@ mod certificateofownership;
|
|||
mod revocation;
|
||||
mod tag;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
pub enum CredentialType {
|
||||
Null = 0u8,
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::vl1::{Address, Identity};
|
|||
use crate::vl2::v1::CredentialType;
|
||||
use crate::vl2::NetworkId;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Revocation {
|
||||
pub id: u32,
|
||||
pub network_id: NetworkId,
|
||||
|
|
|
@ -10,7 +10,7 @@ use zerotier_utils::arrayvec::ArrayVec;
|
|||
use zerotier_utils::blob::Blob;
|
||||
use zerotier_utils::error::InvalidParameterError;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Tag {
|
||||
pub network_id: NetworkId,
|
||||
pub timestamp: i64,
|
||||
|
|
|
@ -42,8 +42,10 @@ pub fn parse_cli_identity(input: &str, validate: bool) -> Result<Identity, Strin
|
|||
Identity::from_str(s).map_or_else(
|
||||
|e| Err(format!("invalid identity: {}", e.to_string())),
|
||||
|id| {
|
||||
if !validate || id.validate_identity() {
|
||||
if !validate {
|
||||
Ok(id)
|
||||
} else if let Some(id) = id.validate() {
|
||||
Ok(id.unwrap())
|
||||
} else {
|
||||
Err(String::from("invalid identity: local validation failed"))
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::io::Write;
|
||||
use std::mem::{size_of, MaybeUninit};
|
||||
use std::ptr::{slice_from_raw_parts, slice_from_raw_parts_mut};
|
||||
|
@ -77,6 +78,20 @@ impl<T: Clone, const C: usize, const S: usize> From<[T; S]> for ArrayVec<T, C> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<const C: usize> ToString for ArrayVec<u8, C> {
|
||||
#[inline]
|
||||
fn to_string(&self) -> String {
|
||||
crate::hex::to_string(self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const C: usize> Debug for ArrayVec<u8, C> {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const C: usize> Write for ArrayVec<u8, C> {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
use serde::ser::SerializeTuple;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
|
@ -64,6 +66,13 @@ impl<const L: usize> ToString for Blob<L> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<const L: usize> Debug for Blob<L> {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const L: usize> Serialize for Blob<L> {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
|
|
|
@ -8,7 +8,7 @@ use serde::de::DeserializeOwned;
|
|||
use serde::Serialize;
|
||||
|
||||
use zerotier_crypto::random::next_u32_secure;
|
||||
use zerotier_network_hypervisor::vl1::{Identity, NodeStorage};
|
||||
use zerotier_network_hypervisor::vl1::{Identity, NodeStorage, Verified};
|
||||
use zerotier_utils::io::{fs_restrict_permissions, read_limit, DEFAULT_FILE_IO_READ_LIMIT};
|
||||
use zerotier_utils::json::to_json_pretty;
|
||||
|
||||
|
@ -27,7 +27,7 @@ pub struct DataDir<Config: PartialEq + Eq + Clone + Send + Sync + Default + Seri
|
|||
}
|
||||
|
||||
impl<Config: PartialEq + Eq + Clone + Send + Sync + Default + Serialize + DeserializeOwned + 'static> NodeStorage for DataDir<Config> {
|
||||
fn load_node_identity(&self) -> Option<Identity> {
|
||||
fn load_node_identity(&self) -> Option<Verified<Identity>> {
|
||||
let id_data = read_limit(self.base_path.join(IDENTITY_SECRET_FILENAME), 4096);
|
||||
if id_data.is_err() {
|
||||
return None;
|
||||
|
@ -36,10 +36,10 @@ impl<Config: PartialEq + Eq + Clone + Send + Sync + Default + Serialize + Deseri
|
|||
if id_data.is_err() {
|
||||
return None;
|
||||
}
|
||||
Some(id_data.unwrap())
|
||||
Some(Verified::assume_verified(id_data.unwrap()))
|
||||
}
|
||||
|
||||
fn save_node_identity(&self, id: &Identity) {
|
||||
fn save_node_identity(&self, id: &Verified<Identity>) {
|
||||
assert!(id.secret.is_some());
|
||||
let id_secret_str = id.to_secret_string();
|
||||
let id_public_str = id.to_string();
|
||||
|
|
|
@ -328,12 +328,12 @@ impl<
|
|||
> NodeStorage for VL1Service<NodeStorageImpl, VL1AuthProviderImpl, InnerProtocolImpl>
|
||||
{
|
||||
#[inline(always)]
|
||||
fn load_node_identity(&self) -> Option<Identity> {
|
||||
fn load_node_identity(&self) -> Option<Verified<Identity>> {
|
||||
self.storage.load_node_identity()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn save_node_identity(&self, id: &Identity) {
|
||||
fn save_node_identity(&self, id: &Verified<Identity>) {
|
||||
self.storage.save_node_identity(id)
|
||||
}
|
||||
}
|
||||
|
@ -345,12 +345,12 @@ impl<
|
|||
> VL1AuthProvider for VL1Service<NodeStorageImpl, VL1AuthProviderImpl, InnerProtocolImpl>
|
||||
{
|
||||
#[inline(always)]
|
||||
fn should_respond_to(&self, id: &Identity) -> bool {
|
||||
fn should_respond_to(&self, id: &Verified<Identity>) -> bool {
|
||||
self.vl1_auth_provider.should_respond_to(id)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn has_trust_relationship(&self, id: &Identity) -> bool {
|
||||
fn has_trust_relationship(&self, id: &Verified<Identity>) -> bool {
|
||||
self.vl1_auth_provider.has_trust_relationship(id)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue