mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-26 08:57:26 +02:00
A bunch of reorg to consolidate utils, controller work, and rework identity binary marshaling for better backward compability.
This commit is contained in:
parent
051292f461
commit
38f8ee808e
20 changed files with 446 additions and 748 deletions
|
@ -6,10 +6,10 @@ use tokio::time::{Duration, Instant};
|
|||
use zerotier_utils::tokio;
|
||||
|
||||
use zerotier_network_hypervisor::protocol::{verbs, PacketBuffer};
|
||||
use zerotier_network_hypervisor::util::dictionary::Dictionary;
|
||||
use zerotier_network_hypervisor::vl1::{HostSystem, Identity, InnerProtocol, PacketHandlerResult, Path, Peer};
|
||||
use zerotier_network_hypervisor::vl2::NetworkId;
|
||||
|
||||
use zerotier_utils::dictionary::Dictionary;
|
||||
use zerotier_utils::reaper::Reaper;
|
||||
|
||||
use crate::database::Database;
|
||||
|
|
|
@ -4,9 +4,7 @@ pub const VERSION_MAJOR: u8 = 1;
|
|||
pub const VERSION_MINOR: u8 = 99;
|
||||
pub const VERSION_REVISION: u16 = 1;
|
||||
|
||||
pub mod error;
|
||||
#[allow(unused)]
|
||||
pub mod protocol;
|
||||
pub mod util;
|
||||
pub mod vl1;
|
||||
pub mod vl2;
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||
|
||||
pub mod dictionary;
|
||||
pub(crate) mod gate;
|
||||
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;
|
|
@ -6,9 +6,9 @@ use std::str::FromStr;
|
|||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::error::InvalidFormatError;
|
||||
use crate::protocol::{ADDRESS_RESERVED_PREFIX, ADDRESS_SIZE};
|
||||
|
||||
use zerotier_utils::error::InvalidFormatError;
|
||||
use zerotier_utils::hex;
|
||||
|
||||
/// A unique address on the global ZeroTier VL1 network.
|
||||
|
|
|
@ -6,13 +6,13 @@ use std::str::FromStr;
|
|||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::error::InvalidFormatError;
|
||||
use crate::util::marshalable::*;
|
||||
use crate::vl1::identity::IDENTITY_FINGERPRINT_SIZE;
|
||||
use crate::vl1::inetaddress::InetAddress;
|
||||
use crate::vl1::{Address, MAC};
|
||||
|
||||
use zerotier_utils::buffer::Buffer;
|
||||
use zerotier_utils::error::InvalidFormatError;
|
||||
use zerotier_utils::marshalable::{Marshalable, UnmarshalError};
|
||||
|
||||
pub const TYPE_NIL: u8 = 0;
|
||||
pub const TYPE_ZEROTIER: u8 = 1;
|
||||
|
@ -118,11 +118,14 @@ impl Endpoint {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if this is an endpoint type that requires that large packets be fragmented.
|
||||
pub fn requires_fragmentation(&self) -> bool {
|
||||
/// Get the maximum fragment size for this endpoint or usize::MAX if there is no hard limit.
|
||||
#[inline(always)]
|
||||
pub fn max_fragment_size(&self) -> usize {
|
||||
match self {
|
||||
Endpoint::Icmp(_) | Endpoint::IpUdp(_) | Endpoint::Ethernet(_) | Endpoint::Bluetooth(_) | Endpoint::WifiDirect(_) => true,
|
||||
_ => false,
|
||||
Endpoint::Icmp(_) | Endpoint::IpUdp(_) | Endpoint::Ethernet(_) | Endpoint::Bluetooth(_) | Endpoint::WifiDirect(_) => {
|
||||
crate::protocol::UDP_DEFAULT_MTU
|
||||
}
|
||||
_ => usize::MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +133,7 @@ impl Endpoint {
|
|||
impl Marshalable for Endpoint {
|
||||
const MAX_MARSHAL_SIZE: usize = MAX_MARSHAL_SIZE;
|
||||
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), MarshalUnmarshalError> {
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), UnmarshalError> {
|
||||
match self {
|
||||
Endpoint::Nil => {
|
||||
buf.append_u8(16 + TYPE_NIL)?;
|
||||
|
@ -189,7 +192,7 @@ impl Marshalable for Endpoint {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<Endpoint, MarshalUnmarshalError> {
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<Endpoint, UnmarshalError> {
|
||||
let type_byte = buf.read_u8(cursor)?;
|
||||
if type_byte < 16 {
|
||||
if type_byte == 4 {
|
||||
|
@ -205,13 +208,13 @@ impl Marshalable for Endpoint {
|
|||
u16::from_be_bytes(b[16..18].try_into().unwrap()),
|
||||
)))
|
||||
} else {
|
||||
Err(MarshalUnmarshalError::InvalidData)
|
||||
Err(UnmarshalError::InvalidData)
|
||||
}
|
||||
} else {
|
||||
match type_byte - 16 {
|
||||
TYPE_NIL => Ok(Endpoint::Nil),
|
||||
TYPE_ZEROTIER => {
|
||||
let zt = Address::from_bytes_fixed(buf.read_bytes_fixed(cursor)?).ok_or(MarshalUnmarshalError::InvalidData)?;
|
||||
let zt = Address::from_bytes_fixed(buf.read_bytes_fixed(cursor)?).ok_or(UnmarshalError::InvalidData)?;
|
||||
Ok(Endpoint::ZeroTier(
|
||||
zt,
|
||||
buf.read_bytes_fixed::<IDENTITY_FINGERPRINT_SIZE>(cursor)?.clone(),
|
||||
|
@ -230,10 +233,10 @@ impl Marshalable for Endpoint {
|
|||
buf.read_bytes(buf.read_varint(cursor)? as usize, cursor)?.to_vec(),
|
||||
)),
|
||||
TYPE_ZEROTIER_ENCAP => {
|
||||
let zt = Address::from_bytes_fixed(buf.read_bytes_fixed(cursor)?).ok_or(MarshalUnmarshalError::InvalidData)?;
|
||||
let zt = Address::from_bytes_fixed(buf.read_bytes_fixed(cursor)?).ok_or(UnmarshalError::InvalidData)?;
|
||||
Ok(Endpoint::ZeroTierEncap(zt, buf.read_bytes_fixed(cursor)?.clone()))
|
||||
}
|
||||
_ => Err(MarshalUnmarshalError::InvalidData),
|
||||
_ => Err(UnmarshalError::InvalidData),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::convert::TryInto;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io::{Read, Write};
|
||||
use std::io::Write;
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
@ -15,10 +15,11 @@ use zerotier_crypto::secret::Secret;
|
|||
use zerotier_crypto::x25519::*;
|
||||
|
||||
use zerotier_utils::arrayvec::ArrayVec;
|
||||
use zerotier_utils::buffer::Buffer;
|
||||
use zerotier_utils::error::{InvalidFormatError, InvalidParameterError};
|
||||
use zerotier_utils::hex;
|
||||
use zerotier_utils::memory::{as_byte_array, as_flat_object};
|
||||
use zerotier_utils::marshalable::{Marshalable, UnmarshalError};
|
||||
|
||||
use crate::error::{InvalidFormatError, InvalidParameterError};
|
||||
use crate::protocol::{ADDRESS_SIZE, ADDRESS_SIZE_STRING, IDENTITY_POW_THRESHOLD};
|
||||
use crate::vl1::Address;
|
||||
|
||||
|
@ -142,30 +143,22 @@ fn zt_address_derivation_work_function(digest: &mut [u8; 64]) {
|
|||
}
|
||||
|
||||
impl Identity {
|
||||
/// Length of an x25519-only public identity in byte array form.
|
||||
pub const BYTE_LENGTH_X25519_PUBLIC: usize = ADDRESS_SIZE + 1 + C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + 1 + 1 + 2;
|
||||
|
||||
/// Length of an x25519-only secret identity in byte array form.
|
||||
pub const BYTE_LENGTH_X25519_SECRET: usize = Self::BYTE_LENGTH_X25519_PUBLIC + C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE;
|
||||
|
||||
/// Length of a new dual-key public identity in byte array form.
|
||||
pub const BYTE_LENGTH_X25519P384_PUBLIC: usize = Self::BYTE_LENGTH_X25519_PUBLIC
|
||||
pub const BYTE_LENGTH_MAX: usize = ADDRESS_SIZE
|
||||
+ 1
|
||||
+ P384_PUBLIC_KEY_SIZE
|
||||
+ P384_PUBLIC_KEY_SIZE
|
||||
+ P384_ECDSA_SIGNATURE_SIZE
|
||||
+ ED25519_SIGNATURE_SIZE;
|
||||
|
||||
/// Length of a new dual-key secret identity in byte array form.
|
||||
pub const BYTE_LENGTH_X25519P384_SECRET: usize = Self::BYTE_LENGTH_X25519P384_PUBLIC
|
||||
+ C25519_PUBLIC_KEY_SIZE
|
||||
+ ED25519_PUBLIC_KEY_SIZE
|
||||
+ C25519_SECRET_KEY_SIZE
|
||||
+ ED25519_SECRET_KEY_SIZE
|
||||
+ P384_PUBLIC_KEY_SIZE
|
||||
+ P384_SECRET_KEY_SIZE
|
||||
+ P384_SECRET_KEY_SIZE;
|
||||
+ P384_PUBLIC_KEY_SIZE
|
||||
+ P384_SECRET_KEY_SIZE
|
||||
+ P384_ECDSA_SIGNATURE_SIZE
|
||||
+ P384_ECDSA_SIGNATURE_SIZE;
|
||||
|
||||
const ALGORITHM_X25519: u8 = 0x01;
|
||||
const ALGORITHM_EC_NIST_P384: u8 = 0x02;
|
||||
const FLAG_INCLUDES_SECRET: u8 = 0x80;
|
||||
const FLAG_INCLUDES_SECRETS: u8 = 0x80;
|
||||
|
||||
/// Generate a new identity.
|
||||
pub fn generate() -> Self {
|
||||
|
@ -270,7 +263,7 @@ impl Identity {
|
|||
.p384
|
||||
.insert(IdentityP384Secret { ecdh: p384_ecdh, ecdsa: p384_ecdsa });
|
||||
|
||||
self.fingerprint = SHA384::hash(self.to_public_bytes().as_bytes());
|
||||
self.fill_in_fingerprint();
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
@ -398,222 +391,67 @@ impl Identity {
|
|||
return false;
|
||||
}
|
||||
|
||||
pub fn to_public_bytes(&self) -> IdentityBytes {
|
||||
if let Some(p384) = self.p384.as_ref() {
|
||||
IdentityBytes::X25519P384Public(
|
||||
as_byte_array(&packed::V1 {
|
||||
v0: packed::V0 {
|
||||
address: self.address.to_bytes(),
|
||||
key_type: 0,
|
||||
x25519: self.x25519,
|
||||
ed25519: self.ed25519,
|
||||
secret_length: 0,
|
||||
reserved: 0x03,
|
||||
ext_len: ((Self::BYTE_LENGTH_X25519P384_PUBLIC - Self::BYTE_LENGTH_X25519_PUBLIC) as u16).to_be_bytes(),
|
||||
},
|
||||
key_type_flags: Self::ALGORITHM_EC_NIST_P384,
|
||||
ecdh: p384.ecdh.as_bytes().clone(),
|
||||
ecdsa: p384.ecdsa.as_bytes().clone(),
|
||||
ecdsa_self_signature: p384.ecdsa_self_signature,
|
||||
ed25519_self_signature: p384.ed25519_self_signature,
|
||||
})
|
||||
.clone(),
|
||||
)
|
||||
pub fn write_public<W: Write>(&self, w: &mut W, legacy_v0: bool) -> std::io::Result<()> {
|
||||
w.write_all(&self.address.to_bytes())?;
|
||||
if !legacy_v0 && self.p384.is_some() {
|
||||
let p384 = self.p384.as_ref().unwrap();
|
||||
w.write_all(&[Self::ALGORITHM_X25519 | Self::ALGORITHM_EC_NIST_P384])?;
|
||||
w.write_all(&self.x25519)?;
|
||||
w.write_all(&self.ed25519)?;
|
||||
w.write_all(p384.ecdh.as_bytes())?;
|
||||
w.write_all(p384.ecdsa.as_bytes())?;
|
||||
w.write_all(&p384.ecdsa_self_signature)?;
|
||||
w.write_all(&p384.ed25519_self_signature)?;
|
||||
} else {
|
||||
IdentityBytes::X25519Public(
|
||||
as_byte_array(&packed::V0 {
|
||||
address: self.address.to_bytes(),
|
||||
key_type: 0,
|
||||
x25519: self.x25519,
|
||||
ed25519: self.ed25519,
|
||||
secret_length: 0,
|
||||
reserved: 0x03,
|
||||
ext_len: [0; 2],
|
||||
})
|
||||
.clone(),
|
||||
)
|
||||
w.write_all(&[0])?;
|
||||
w.write_all(&self.x25519)?;
|
||||
w.write_all(&self.ed25519)?;
|
||||
w.write_all(&[0])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_secret<W: Write>(&self, w: &mut W, legacy_v0: bool) -> std::io::Result<()> {
|
||||
if let Some(s) = self.secret.as_ref() {
|
||||
w.write_all(&self.address.to_bytes());
|
||||
if !legacy_v0 && self.p384.is_some() && s.p384.is_some() {
|
||||
let p384 = self.p384.as_ref().unwrap();
|
||||
let p384s = s.p384.as_ref().unwrap();
|
||||
w.write_all(&[Self::ALGORITHM_X25519 | Self::ALGORITHM_EC_NIST_P384 | Self::FLAG_INCLUDES_SECRETS]);
|
||||
w.write_all(&self.x25519);
|
||||
w.write_all(&self.ed25519);
|
||||
w.write_all(s.x25519.secret_bytes().as_bytes());
|
||||
w.write_all(s.ed25519.secret_bytes().as_bytes());
|
||||
w.write_all(p384.ecdh.as_bytes());
|
||||
w.write_all(p384.ecdsa.as_bytes());
|
||||
w.write_all(p384s.ecdh.secret_key_bytes().as_bytes());
|
||||
w.write_all(p384s.ecdsa.secret_key_bytes().as_bytes());
|
||||
w.write_all(&p384.ecdsa_self_signature);
|
||||
w.write_all(&p384.ed25519_self_signature);
|
||||
} else {
|
||||
w.write_all(&[0])?;
|
||||
w.write_all(&self.x25519)?;
|
||||
w.write_all(&self.ed25519)?;
|
||||
w.write_all(&[(C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE) as u8])?;
|
||||
w.write_all(s.x25519.secret_bytes().as_bytes())?;
|
||||
w.write_all(s.ed25519.secret_bytes().as_bytes())?;
|
||||
}
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::Other, "no secret"));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_secret_bytes(&self) -> Option<IdentityBytes> {
|
||||
self.secret.as_ref().map(|s| {
|
||||
if let Some(p384) = s.p384.as_ref() {
|
||||
IdentityBytes::X25519P384Secret(
|
||||
as_byte_array(&packed::V1S {
|
||||
v0s: packed::V0S {
|
||||
address: self.address.to_bytes(),
|
||||
key_type: 0,
|
||||
x25519: self.x25519,
|
||||
ed25519: self.ed25519,
|
||||
secret_length: (C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE) as u8,
|
||||
x25519_secret: s.x25519.secret_bytes().0.clone(),
|
||||
ed25519_secret: s.ed25519.secret_bytes().0.clone(),
|
||||
reserved: 0x03,
|
||||
ext_len: ((Self::BYTE_LENGTH_X25519P384_SECRET - Self::BYTE_LENGTH_X25519_SECRET) as u16).to_be_bytes(),
|
||||
},
|
||||
key_type_flags: Self::ALGORITHM_EC_NIST_P384 | Self::FLAG_INCLUDES_SECRET,
|
||||
ecdh: p384.ecdh.public_key_bytes().clone(),
|
||||
ecdsa: p384.ecdsa.public_key_bytes().clone(),
|
||||
ecdsa_self_signature: self.p384.as_ref().unwrap().ecdsa_self_signature,
|
||||
ed25519_self_signature: self.p384.as_ref().unwrap().ed25519_self_signature,
|
||||
ecdh_secret: p384.ecdh.secret_key_bytes().0.clone(),
|
||||
ecdsa_secret: p384.ecdsa.secret_key_bytes().0.clone(),
|
||||
})
|
||||
.clone(),
|
||||
)
|
||||
} else {
|
||||
IdentityBytes::X25519Secret(
|
||||
as_byte_array(&packed::V0S {
|
||||
address: self.address.to_bytes(),
|
||||
key_type: 0,
|
||||
x25519: self.x25519,
|
||||
ed25519: self.ed25519,
|
||||
secret_length: (C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE) as u8,
|
||||
x25519_secret: s.x25519.secret_bytes().0.clone(),
|
||||
ed25519_secret: s.ed25519.secret_bytes().0.clone(),
|
||||
reserved: 0x03,
|
||||
ext_len: [0; 2],
|
||||
})
|
||||
.clone(),
|
||||
)
|
||||
}
|
||||
})
|
||||
pub fn to_public_bytes(&self, legacy_v8: bool) -> std::io::Result<Buffer<{ Self::BYTE_LENGTH_MAX }>> {
|
||||
let mut buf = Buffer::<{ Self::BYTE_LENGTH_MAX }>::new();
|
||||
self.write_public(&mut buf, false)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
/// Convert a byte respresentation into an identity.
|
||||
///
|
||||
/// WARNING: this performs basic sanity checking but does NOT perform a full validation of address derivation or self-signatures.
|
||||
pub fn from_bytes(bytes: &IdentityBytes) -> Option<Self> {
|
||||
let mut id = match bytes {
|
||||
IdentityBytes::X25519Public(b) => {
|
||||
let b: &packed::V0 = as_flat_object(b);
|
||||
if b.key_type == 0 && b.secret_length == 0 && b.reserved == 0x03 && u16::from_be_bytes(b.ext_len) == 0 {
|
||||
Some(Self {
|
||||
address: Address::from_bytes_fixed(&b.address)?,
|
||||
x25519: b.x25519,
|
||||
ed25519: b.ed25519,
|
||||
p384: None,
|
||||
secret: None,
|
||||
fingerprint: [0; 48],
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
IdentityBytes::X25519Secret(b) => {
|
||||
let b: &packed::V0S = as_flat_object(b);
|
||||
if b.key_type == 0
|
||||
&& b.secret_length == (C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE) as u8
|
||||
&& b.reserved == 0x03
|
||||
&& u16::from_be_bytes(b.ext_len) == 0
|
||||
{
|
||||
Some(Self {
|
||||
address: Address::from_bytes_fixed(&b.address)?,
|
||||
x25519: b.x25519,
|
||||
ed25519: b.ed25519,
|
||||
p384: None,
|
||||
secret: Some(IdentitySecret {
|
||||
x25519: X25519KeyPair::from_bytes(&b.x25519, &b.x25519_secret)?,
|
||||
ed25519: Ed25519KeyPair::from_bytes(&b.ed25519, &b.ed25519_secret)?,
|
||||
p384: None,
|
||||
}),
|
||||
fingerprint: [0; 48],
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
IdentityBytes::X25519P384Public(b) => {
|
||||
let b: &packed::V1 = as_flat_object(b);
|
||||
if b.v0.key_type == 0
|
||||
&& b.v0.secret_length == 0
|
||||
&& b.v0.reserved == 0x03
|
||||
&& u16::from_be_bytes(b.v0.ext_len) == (Self::BYTE_LENGTH_X25519P384_PUBLIC - Self::BYTE_LENGTH_X25519_PUBLIC) as u16
|
||||
&& b.key_type_flags == Self::ALGORITHM_EC_NIST_P384
|
||||
{
|
||||
Some(Self {
|
||||
address: Address::from_bytes_fixed(&b.v0.address)?,
|
||||
x25519: b.v0.x25519,
|
||||
ed25519: b.v0.ed25519,
|
||||
p384: Some(IdentityP384Public {
|
||||
ecdh: P384PublicKey::from_bytes(&b.ecdh)?,
|
||||
ecdsa: P384PublicKey::from_bytes(&b.ecdsa)?,
|
||||
ecdsa_self_signature: b.ecdsa_self_signature,
|
||||
ed25519_self_signature: b.ed25519_self_signature,
|
||||
}),
|
||||
secret: None,
|
||||
fingerprint: [0; 48],
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
IdentityBytes::X25519P384Secret(b) => {
|
||||
let b: &packed::V1S = as_flat_object(b);
|
||||
if b.v0s.key_type == 0
|
||||
&& b.v0s.secret_length == (C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE) as u8
|
||||
&& b.v0s.reserved == 0x03
|
||||
&& u16::from_be_bytes(b.v0s.ext_len) == (Self::BYTE_LENGTH_X25519P384_SECRET - Self::BYTE_LENGTH_X25519_SECRET) as u16
|
||||
&& b.key_type_flags == (Self::ALGORITHM_EC_NIST_P384 | Self::FLAG_INCLUDES_SECRET)
|
||||
{
|
||||
Some(Self {
|
||||
address: Address::from_bytes_fixed(&b.v0s.address)?,
|
||||
x25519: b.v0s.x25519,
|
||||
ed25519: b.v0s.ed25519,
|
||||
p384: Some(IdentityP384Public {
|
||||
ecdh: P384PublicKey::from_bytes(&b.ecdh)?,
|
||||
ecdsa: P384PublicKey::from_bytes(&b.ecdsa)?,
|
||||
ecdsa_self_signature: b.ecdsa_self_signature,
|
||||
ed25519_self_signature: b.ed25519_self_signature,
|
||||
}),
|
||||
secret: Some(IdentitySecret {
|
||||
x25519: X25519KeyPair::from_bytes(&b.v0s.x25519, &b.v0s.x25519_secret)?,
|
||||
ed25519: Ed25519KeyPair::from_bytes(&b.v0s.ed25519, &b.v0s.ed25519_secret)?,
|
||||
p384: Some(IdentityP384Secret {
|
||||
ecdh: P384KeyPair::from_bytes(&b.ecdh, &b.ecdh_secret)?,
|
||||
ecdsa: P384KeyPair::from_bytes(&b.ecdsa, &b.ecdsa_secret)?,
|
||||
}),
|
||||
}),
|
||||
fingerprint: [0; 48],
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
let fingerprint = SHA384::hash(id.as_ref().unwrap().to_public_bytes().as_bytes());
|
||||
id.as_mut().unwrap().fingerprint = fingerprint;
|
||||
id
|
||||
}
|
||||
|
||||
/// Read an identity from a reader, inferring its total length from the stream.
|
||||
pub fn read_bytes<R: Read>(r: &mut R) -> std::io::Result<Self> {
|
||||
let mut buf = [0_u8; 512];
|
||||
r.read_exact(&mut buf[..Self::BYTE_LENGTH_X25519_PUBLIC])?;
|
||||
let x25519_public: &packed::V0 = as_flat_object(&buf);
|
||||
let ext_len = u16::from_be_bytes(x25519_public.ext_len) as usize;
|
||||
let obj_len = if x25519_public.secret_length == 0 {
|
||||
let obj_len = ext_len + Self::BYTE_LENGTH_X25519_PUBLIC;
|
||||
if ext_len > 0 {
|
||||
r.read_exact(&mut buf[Self::BYTE_LENGTH_X25519_PUBLIC..obj_len])?;
|
||||
}
|
||||
obj_len
|
||||
} else {
|
||||
let obj_len = ext_len + Self::BYTE_LENGTH_X25519_SECRET;
|
||||
if ext_len > 0 {
|
||||
r.read_exact(&mut buf[Self::BYTE_LENGTH_X25519_PUBLIC..obj_len])?;
|
||||
}
|
||||
obj_len
|
||||
};
|
||||
IdentityBytes::try_from(&buf[..obj_len]).map_or_else(
|
||||
|_| Err(std::io::Error::new(std::io::ErrorKind::Other, "invalid identity")),
|
||||
|b| {
|
||||
Identity::from_bytes(&b).map_or_else(
|
||||
|| Err(std::io::Error::new(std::io::ErrorKind::Other, "invalid identity")),
|
||||
|id| Ok(id),
|
||||
)
|
||||
},
|
||||
)
|
||||
pub fn to_secret_bytes(&self, legacy_v8: bool) -> std::io::Result<Buffer<{ Self::BYTE_LENGTH_MAX }>> {
|
||||
let mut buf = Buffer::<{ Self::BYTE_LENGTH_MAX }>::new();
|
||||
self.write_secret(&mut buf, false)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn to_string_internal(&self, include_private: bool) -> String {
|
||||
|
@ -660,6 +498,12 @@ impl Identity {
|
|||
s
|
||||
}
|
||||
|
||||
fn fill_in_fingerprint(&mut self) {
|
||||
let mut h = SHA384::new();
|
||||
self.write_public(&mut h, false);
|
||||
self.fingerprint = h.finish();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn to_public_string(&self) -> String {
|
||||
self.to_string_internal(false)
|
||||
|
@ -821,10 +665,108 @@ impl FromStr for Identity {
|
|||
},
|
||||
fingerprint: [0; 48],
|
||||
});
|
||||
id.as_mut().unwrap().fill_in_fingerprint();
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
let fingerprint = SHA384::hash(id.as_ref().unwrap().to_public_bytes().as_bytes());
|
||||
id.as_mut().unwrap().fingerprint = fingerprint;
|
||||
impl Marshalable for Identity {
|
||||
const MAX_MARSHAL_SIZE: usize = Self::BYTE_LENGTH_MAX;
|
||||
|
||||
#[inline(always)]
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), UnmarshalError> {
|
||||
self.write_public(buf, false).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<Self, UnmarshalError> {
|
||||
let address = Address::from_bytes_fixed(buf.read_bytes_fixed(cursor)?).ok_or(UnmarshalError::InvalidData)?;
|
||||
let type_flags = buf.read_u8(cursor)?;
|
||||
let x25519 = buf.read_bytes_fixed::<C25519_PUBLIC_KEY_SIZE>(cursor)?;
|
||||
let ed25519 = buf.read_bytes_fixed::<ED25519_PUBLIC_KEY_SIZE>(cursor)?;
|
||||
|
||||
let (
|
||||
mut ecdh,
|
||||
mut ecdsa,
|
||||
mut ecdsa_self_signature,
|
||||
mut ed25519_self_signature,
|
||||
mut x25519_s,
|
||||
mut ed25519_s,
|
||||
mut ecdh_s,
|
||||
mut ecdsa_s,
|
||||
) = (None, None, None, None, None, None, None, None);
|
||||
|
||||
if type_flags == 0 {
|
||||
const C25519_SECRETS_SIZE: u8 = (C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE) as u8;
|
||||
match buf.read_u8(cursor)? {
|
||||
0 => {
|
||||
x25519_s = None;
|
||||
ed25519_s = None;
|
||||
}
|
||||
C25519_SECRETS_SIZE => {
|
||||
x25519_s = Some(buf.read_bytes_fixed::<C25519_SECRET_KEY_SIZE>(cursor)?);
|
||||
ed25519_s = Some(buf.read_bytes_fixed::<ED25519_SECRET_KEY_SIZE>(cursor)?);
|
||||
}
|
||||
_ => return Err(UnmarshalError::InvalidData),
|
||||
}
|
||||
} else {
|
||||
if (type_flags & (Self::ALGORITHM_X25519 | Self::FLAG_INCLUDES_SECRETS))
|
||||
== (Self::ALGORITHM_X25519 | Self::FLAG_INCLUDES_SECRETS)
|
||||
{
|
||||
x25519_s = Some(buf.read_bytes_fixed::<C25519_SECRET_KEY_SIZE>(cursor)?);
|
||||
ed25519_s = Some(buf.read_bytes_fixed::<ED25519_SECRET_KEY_SIZE>(cursor)?);
|
||||
}
|
||||
|
||||
if (type_flags & Self::ALGORITHM_EC_NIST_P384) != 0 {
|
||||
ecdh = Some(buf.read_bytes_fixed::<P384_PUBLIC_KEY_SIZE>(cursor)?);
|
||||
ecdsa = Some(buf.read_bytes_fixed::<P384_PUBLIC_KEY_SIZE>(cursor)?);
|
||||
if (type_flags & Self::FLAG_INCLUDES_SECRETS) != 0 {
|
||||
ecdh_s = Some(buf.read_bytes_fixed::<P384_SECRET_KEY_SIZE>(cursor)?);
|
||||
ecdsa_s = Some(buf.read_bytes_fixed::<P384_SECRET_KEY_SIZE>(cursor)?);
|
||||
}
|
||||
ecdsa_self_signature = Some(buf.read_bytes_fixed::<P384_ECDSA_SIGNATURE_SIZE>(cursor)?);
|
||||
ed25519_self_signature = Some(buf.read_bytes_fixed::<ED25519_SIGNATURE_SIZE>(cursor)?);
|
||||
}
|
||||
}
|
||||
|
||||
let mut id = Ok(Identity {
|
||||
address,
|
||||
x25519: x25519.clone(),
|
||||
ed25519: ed25519.clone(),
|
||||
p384: if let Some(ecdh) = ecdh {
|
||||
Some(IdentityP384Public {
|
||||
ecdh: P384PublicKey::from_bytes(ecdh).ok_or(UnmarshalError::InvalidData)?,
|
||||
ecdsa: P384PublicKey::from_bytes(ecdsa.ok_or(UnmarshalError::InvalidData)?).ok_or(UnmarshalError::InvalidData)?,
|
||||
ecdsa_self_signature: ecdsa_self_signature.ok_or(UnmarshalError::InvalidData)?.clone(),
|
||||
ed25519_self_signature: ed25519_self_signature.ok_or(UnmarshalError::InvalidData)?.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
},
|
||||
secret: if let Some(x25519_s) = x25519_s {
|
||||
Some(IdentitySecret {
|
||||
x25519: X25519KeyPair::from_bytes(x25519, x25519_s).ok_or(UnmarshalError::InvalidData)?,
|
||||
ed25519: Ed25519KeyPair::from_bytes(ed25519, ed25519_s.ok_or(UnmarshalError::InvalidData)?)
|
||||
.ok_or(UnmarshalError::InvalidData)?,
|
||||
p384: if let Some(ecdh_s) = ecdh_s {
|
||||
Some(IdentityP384Secret {
|
||||
ecdh: P384KeyPair::from_bytes(ecdh.ok_or(UnmarshalError::InvalidData)?, ecdh_s)
|
||||
.ok_or(UnmarshalError::InvalidData)?,
|
||||
ecdsa: P384KeyPair::from_bytes(
|
||||
ecdsa.ok_or(UnmarshalError::InvalidData)?,
|
||||
ecdsa_s.ok_or(UnmarshalError::InvalidData)?,
|
||||
)
|
||||
.ok_or(UnmarshalError::InvalidData)?,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
} else {
|
||||
None
|
||||
},
|
||||
fingerprint: [0u8; IDENTITY_FINGERPRINT_SIZE],
|
||||
});
|
||||
id.as_mut().unwrap().fill_in_fingerprint();
|
||||
id
|
||||
}
|
||||
}
|
||||
|
@ -832,7 +774,7 @@ impl FromStr for Identity {
|
|||
impl PartialEq for Identity {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.fingerprint == other.fingerprint
|
||||
self.fingerprint.eq(&other.fingerprint)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -861,114 +803,6 @@ impl Hash for Identity {
|
|||
}
|
||||
}
|
||||
|
||||
mod packed {
|
||||
use super::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct V0 {
|
||||
pub address: [u8; ADDRESS_SIZE],
|
||||
pub key_type: u8,
|
||||
pub x25519: [u8; C25519_PUBLIC_KEY_SIZE],
|
||||
pub ed25519: [u8; ED25519_PUBLIC_KEY_SIZE],
|
||||
pub secret_length: u8,
|
||||
pub reserved: u8,
|
||||
pub ext_len: [u8; 2],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct V0S {
|
||||
pub address: [u8; ADDRESS_SIZE],
|
||||
pub key_type: u8,
|
||||
pub x25519: [u8; C25519_PUBLIC_KEY_SIZE],
|
||||
pub ed25519: [u8; ED25519_PUBLIC_KEY_SIZE],
|
||||
pub secret_length: u8,
|
||||
pub x25519_secret: [u8; C25519_SECRET_KEY_SIZE],
|
||||
pub ed25519_secret: [u8; ED25519_SECRET_KEY_SIZE],
|
||||
pub reserved: u8,
|
||||
pub ext_len: [u8; 2],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct V1 {
|
||||
pub v0: V0,
|
||||
pub key_type_flags: u8,
|
||||
pub ecdh: [u8; P384_PUBLIC_KEY_SIZE],
|
||||
pub ecdsa: [u8; P384_PUBLIC_KEY_SIZE],
|
||||
pub ecdsa_self_signature: [u8; P384_ECDSA_SIGNATURE_SIZE],
|
||||
pub ed25519_self_signature: [u8; ED25519_SIGNATURE_SIZE],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct V1S {
|
||||
pub v0s: V0S,
|
||||
pub key_type_flags: u8,
|
||||
pub ecdh: [u8; P384_PUBLIC_KEY_SIZE],
|
||||
pub ecdsa: [u8; P384_PUBLIC_KEY_SIZE],
|
||||
pub ecdsa_self_signature: [u8; P384_ECDSA_SIGNATURE_SIZE],
|
||||
pub ed25519_self_signature: [u8; ED25519_SIGNATURE_SIZE],
|
||||
pub ecdh_secret: [u8; P384_SECRET_KEY_SIZE],
|
||||
pub ecdsa_secret: [u8; P384_SECRET_KEY_SIZE],
|
||||
}
|
||||
}
|
||||
|
||||
/// Identity rendered as a flat byte array.
|
||||
///
|
||||
/// Note that try_from() and into() here perform a straight conversion or cast between this and
|
||||
/// byte slices. They don't check the actual format of the contained identity data.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum IdentityBytes {
|
||||
X25519Public([u8; Identity::BYTE_LENGTH_X25519_PUBLIC]),
|
||||
X25519Secret([u8; Identity::BYTE_LENGTH_X25519_SECRET]),
|
||||
X25519P384Public([u8; Identity::BYTE_LENGTH_X25519P384_PUBLIC]),
|
||||
X25519P384Secret([u8; Identity::BYTE_LENGTH_X25519P384_SECRET]),
|
||||
}
|
||||
|
||||
impl IdentityBytes {
|
||||
#[inline(always)]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a IdentityBytes> for &'a [u8] {
|
||||
fn from(b: &'a IdentityBytes) -> Self {
|
||||
match b {
|
||||
IdentityBytes::X25519Public(b) => b,
|
||||
IdentityBytes::X25519Secret(b) => b,
|
||||
IdentityBytes::X25519P384Public(b) => b,
|
||||
IdentityBytes::X25519P384Secret(b) => b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for IdentityBytes {
|
||||
type Error = std::array::TryFromSliceError;
|
||||
|
||||
fn try_from(b: &[u8]) -> Result<Self, Self::Error> {
|
||||
match b.len() {
|
||||
Identity::BYTE_LENGTH_X25519_PUBLIC => Ok(Self::X25519Public(b.try_into()?)),
|
||||
Identity::BYTE_LENGTH_X25519_SECRET => Ok(Self::X25519Secret(b.try_into()?)),
|
||||
Identity::BYTE_LENGTH_X25519P384_PUBLIC => Ok(Self::X25519P384Public(b.try_into()?)),
|
||||
_ => Ok(Self::X25519P384Secret(b.try_into()?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for IdentityBytes {
|
||||
fn drop(&mut self) {
|
||||
// This can contain secrets, so zero it like Secret<> in the crypto core.
|
||||
unsafe {
|
||||
for i in 0..std::mem::size_of::<Self>() {
|
||||
std::ptr::write_volatile((self as *mut Self).cast::<u8>().add(i), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Identity {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
|
@ -977,7 +811,7 @@ impl Serialize for Identity {
|
|||
if serializer.is_human_readable() {
|
||||
serializer.serialize_str(self.to_public_string().as_str())
|
||||
} else {
|
||||
serializer.serialize_bytes((&self.to_public_bytes()).into())
|
||||
serializer.serialize_bytes(self.to_bytes().as_slice())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -995,10 +829,7 @@ impl<'de> serde::de::Visitor<'de> for IdentityVisitor {
|
|||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
IdentityBytes::try_from(v).map_or_else(
|
||||
|e| Err(E::custom(e.to_string())),
|
||||
|b| Identity::from_bytes(&b).map_or_else(|| Err(E::custom("invalid identity")), |id| Ok(id)),
|
||||
)
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
|
@ -1071,11 +902,11 @@ mod tests {
|
|||
let gen = Identity::generate();
|
||||
assert!(gen.agree(&gen).is_some());
|
||||
assert!(gen.validate_identity());
|
||||
let bytes = gen.to_secret_bytes().unwrap();
|
||||
let bytes = gen.to_secret_bytes(false).unwrap();
|
||||
let string = gen.to_secret_string();
|
||||
assert!(Identity::from_str(string.as_str()).unwrap().eq(&gen));
|
||||
|
||||
let gen_unmarshaled = Identity::from_bytes(&bytes).unwrap();
|
||||
let gen_unmarshaled = Identity::from_bytes(bytes.as_bytes()).unwrap();
|
||||
assert!(gen_unmarshaled.secret.is_some());
|
||||
if !gen_unmarshaled.eq(&gen) {
|
||||
println!(
|
||||
|
@ -1098,12 +929,12 @@ mod tests {
|
|||
assert!(id.validate_identity());
|
||||
assert!(id.p384.is_none());
|
||||
|
||||
let idb = id.to_secret_bytes().unwrap();
|
||||
let id_unmarshal = Identity::from_bytes(&idb).unwrap();
|
||||
let idb = id.to_secret_bytes(false).unwrap();
|
||||
let id_unmarshal = Identity::from_bytes(idb.as_bytes()).unwrap();
|
||||
assert!(id == id_unmarshal);
|
||||
assert!(id_unmarshal.secret.is_some());
|
||||
|
||||
let idb2 = id_unmarshal.to_public_bytes();
|
||||
let idb2 = id_unmarshal.to_bytes();
|
||||
let id_unmarshal2 = Identity::from_bytes(&idb2).unwrap();
|
||||
assert!(id_unmarshal2 == id_unmarshal);
|
||||
assert!(id_unmarshal2 == id);
|
||||
|
@ -1128,11 +959,11 @@ mod tests {
|
|||
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).unwrap();
|
||||
let idb = id.to_secret_bytes(false).unwrap();
|
||||
let id_unmarshal = Identity::from_bytes(idb.as_bytes()).unwrap();
|
||||
assert!(id == id_unmarshal);
|
||||
|
||||
let idb2 = id_unmarshal.to_public_bytes();
|
||||
let idb2 = id_unmarshal.to_bytes();
|
||||
let id_unmarshal2 = Identity::from_bytes(&idb2).unwrap();
|
||||
assert!(id_unmarshal2 == id_unmarshal);
|
||||
assert!(id_unmarshal2 == id);
|
||||
|
|
|
@ -9,11 +9,9 @@ use std::str::FromStr;
|
|||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::util::marshalable::*;
|
||||
|
||||
use crate::error::InvalidFormatError;
|
||||
|
||||
use zerotier_utils::buffer::Buffer;
|
||||
use zerotier_utils::error::{InvalidFormatError, InvalidParameterError};
|
||||
use zerotier_utils::marshalable::{Marshalable, UnmarshalError};
|
||||
|
||||
#[cfg(windows)]
|
||||
use winapi::um::winsock2;
|
||||
|
@ -91,7 +89,7 @@ impl ToSocketAddrs for InetAddress {
|
|||
}
|
||||
|
||||
impl TryInto<IpAddr> for InetAddress {
|
||||
type Error = crate::error::InvalidParameterError;
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_into(self) -> Result<IpAddr, Self::Error> {
|
||||
|
@ -100,20 +98,20 @@ impl TryInto<IpAddr> for InetAddress {
|
|||
}
|
||||
|
||||
impl TryInto<IpAddr> for &InetAddress {
|
||||
type Error = crate::error::InvalidParameterError;
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_into(self) -> Result<IpAddr, Self::Error> {
|
||||
match unsafe { self.sa.sa_family } {
|
||||
AF_INET => Ok(IpAddr::V4(Ipv4Addr::from(unsafe { self.sin.sin_addr.s_addr.to_ne_bytes() }))),
|
||||
AF_INET6 => Ok(IpAddr::V6(Ipv6Addr::from(unsafe { self.sin6.sin6_addr.s6_addr }))),
|
||||
_ => Err(crate::error::InvalidParameterError("not an IP address")),
|
||||
_ => Err(InvalidParameterError("not an IP address")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<Ipv4Addr> for InetAddress {
|
||||
type Error = crate::error::InvalidParameterError;
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_into(self) -> Result<Ipv4Addr, Self::Error> {
|
||||
|
@ -122,19 +120,19 @@ impl TryInto<Ipv4Addr> for InetAddress {
|
|||
}
|
||||
|
||||
impl TryInto<Ipv4Addr> for &InetAddress {
|
||||
type Error = crate::error::InvalidParameterError;
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_into(self) -> Result<Ipv4Addr, Self::Error> {
|
||||
match unsafe { self.sa.sa_family } {
|
||||
AF_INET => Ok(Ipv4Addr::from(unsafe { self.sin.sin_addr.s_addr.to_ne_bytes() })),
|
||||
_ => Err(crate::error::InvalidParameterError("not an IPv4 address")),
|
||||
_ => Err(InvalidParameterError("not an IPv4 address")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<Ipv6Addr> for InetAddress {
|
||||
type Error = crate::error::InvalidParameterError;
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_into(self) -> Result<Ipv6Addr, Self::Error> {
|
||||
|
@ -143,19 +141,19 @@ impl TryInto<Ipv6Addr> for InetAddress {
|
|||
}
|
||||
|
||||
impl TryInto<Ipv6Addr> for &InetAddress {
|
||||
type Error = crate::error::InvalidParameterError;
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_into(self) -> Result<Ipv6Addr, Self::Error> {
|
||||
match unsafe { self.sa.sa_family } {
|
||||
AF_INET6 => Ok(Ipv6Addr::from(unsafe { self.sin6.sin6_addr.s6_addr })),
|
||||
_ => Err(crate::error::InvalidParameterError("not an IPv6 address")),
|
||||
_ => Err(InvalidParameterError("not an IPv6 address")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<SocketAddr> for InetAddress {
|
||||
type Error = crate::error::InvalidParameterError;
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_into(self) -> Result<SocketAddr, Self::Error> {
|
||||
|
@ -164,7 +162,7 @@ impl TryInto<SocketAddr> for InetAddress {
|
|||
}
|
||||
|
||||
impl TryInto<SocketAddr> for &InetAddress {
|
||||
type Error = crate::error::InvalidParameterError;
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_into(self) -> Result<SocketAddr, Self::Error> {
|
||||
|
@ -180,14 +178,14 @@ impl TryInto<SocketAddr> for &InetAddress {
|
|||
0,
|
||||
0,
|
||||
))),
|
||||
_ => Err(crate::error::InvalidParameterError("not an IP address")),
|
||||
_ => Err(InvalidParameterError("not an IP address")),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<SocketAddrV4> for InetAddress {
|
||||
type Error = crate::error::InvalidParameterError;
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_into(self) -> Result<SocketAddrV4, Self::Error> {
|
||||
|
@ -196,7 +194,7 @@ impl TryInto<SocketAddrV4> for InetAddress {
|
|||
}
|
||||
|
||||
impl TryInto<SocketAddrV4> for &InetAddress {
|
||||
type Error = crate::error::InvalidParameterError;
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_into(self) -> Result<SocketAddrV4, Self::Error> {
|
||||
|
@ -206,14 +204,14 @@ impl TryInto<SocketAddrV4> for &InetAddress {
|
|||
Ipv4Addr::from(self.sin.sin_addr.s_addr.to_ne_bytes()),
|
||||
u16::from_be(self.sin.sin_port as u16),
|
||||
)),
|
||||
_ => Err(crate::error::InvalidParameterError("not an IPv4 address")),
|
||||
_ => Err(InvalidParameterError("not an IPv4 address")),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<SocketAddrV6> for InetAddress {
|
||||
type Error = crate::error::InvalidParameterError;
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_into(self) -> Result<SocketAddrV6, Self::Error> {
|
||||
|
@ -222,7 +220,7 @@ impl TryInto<SocketAddrV6> for InetAddress {
|
|||
}
|
||||
|
||||
impl TryInto<SocketAddrV6> for &InetAddress {
|
||||
type Error = crate::error::InvalidParameterError;
|
||||
type Error = InvalidParameterError;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_into(self) -> Result<SocketAddrV6, Self::Error> {
|
||||
|
@ -234,7 +232,7 @@ impl TryInto<SocketAddrV6> for &InetAddress {
|
|||
0,
|
||||
0,
|
||||
)),
|
||||
_ => Err(crate::error::InvalidParameterError("not an IPv6 address")),
|
||||
_ => Err(InvalidParameterError("not an IPv6 address")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -783,7 +781,7 @@ impl InetAddress {
|
|||
impl Marshalable for InetAddress {
|
||||
const MAX_MARSHAL_SIZE: usize = 19;
|
||||
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), MarshalUnmarshalError> {
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), UnmarshalError> {
|
||||
unsafe {
|
||||
match self.sa.sa_family as AddressFamilyType {
|
||||
AF_INET => {
|
||||
|
@ -810,7 +808,7 @@ impl Marshalable for InetAddress {
|
|||
}
|
||||
}
|
||||
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<InetAddress, MarshalUnmarshalError> {
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<InetAddress, UnmarshalError> {
|
||||
let t = buf.read_u8(cursor)?;
|
||||
if t == 4 {
|
||||
let b: &[u8; 6] = buf.read_bytes_fixed(cursor)?;
|
||||
|
|
|
@ -7,11 +7,10 @@ use std::str::FromStr;
|
|||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::error::InvalidFormatError;
|
||||
use crate::util::marshalable::*;
|
||||
|
||||
use zerotier_utils::buffer::Buffer;
|
||||
use zerotier_utils::error::InvalidFormatError;
|
||||
use zerotier_utils::hex;
|
||||
use zerotier_utils::marshalable::{Marshalable, UnmarshalError};
|
||||
|
||||
/// An Ethernet MAC address.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
@ -87,14 +86,14 @@ impl Marshalable for MAC {
|
|||
const MAX_MARSHAL_SIZE: usize = 6;
|
||||
|
||||
#[inline(always)]
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), MarshalUnmarshalError> {
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), UnmarshalError> {
|
||||
buf.append_bytes(&self.0.get().to_be_bytes()[2..])
|
||||
.map_err(|_| MarshalUnmarshalError::OutOfBounds)
|
||||
.map_err(|_| UnmarshalError::OutOfBounds)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<Self, MarshalUnmarshalError> {
|
||||
Self::from_bytes_fixed(buf.read_bytes_fixed(cursor)?).ok_or(MarshalUnmarshalError::InvalidData)
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<Self, UnmarshalError> {
|
||||
Self::from_bytes_fixed(buf.read_bytes_fixed(cursor)?).ok_or(UnmarshalError::InvalidData)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,10 +9,7 @@ use std::time::Duration;
|
|||
|
||||
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
|
||||
|
||||
use crate::error::InvalidParameterError;
|
||||
use crate::protocol::*;
|
||||
use crate::util::gate::IntervalGate;
|
||||
use crate::util::marshalable::Marshalable;
|
||||
use crate::vl1::address::Address;
|
||||
use crate::vl1::debug_event;
|
||||
use crate::vl1::endpoint::Endpoint;
|
||||
|
@ -24,7 +21,10 @@ use crate::vl1::rootset::RootSet;
|
|||
|
||||
use zerotier_crypto::random;
|
||||
use zerotier_crypto::verified::Verified;
|
||||
use zerotier_utils::error::InvalidParameterError;
|
||||
use zerotier_utils::gate::IntervalGate;
|
||||
use zerotier_utils::hex;
|
||||
use zerotier_utils::marshalable::Marshalable;
|
||||
use zerotier_utils::ringbuffer::RingBuffer;
|
||||
|
||||
/// Trait implemented by external code to handle events and provide an interface to the system or application.
|
||||
|
@ -820,11 +820,12 @@ impl<HostSystemImpl: HostSystem> Node<HostSystemImpl> {
|
|||
packet.clear();
|
||||
packet.set_size(v1::HEADER_SIZE);
|
||||
let _ = packet.append_u8(verbs::VL1_WHOIS);
|
||||
} else {
|
||||
let _ = packet.append_bytes_fixed(&a.to_bytes());
|
||||
}
|
||||
let _ = packet.append_bytes_fixed(&a.to_bytes());
|
||||
}
|
||||
if packet.len() > (v1::HEADER_SIZE + 1) {
|
||||
root.send(host_system, None, self, time_ticks, &mut packet);
|
||||
}
|
||||
root.send(host_system, None, self, time_ticks, &mut packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use crate::vl1::fragmentedpacket::FragmentedPacket;
|
|||
use crate::vl1::node::*;
|
||||
|
||||
use zerotier_crypto::random;
|
||||
use zerotier_utils::NEVER_HAPPENED_TICKS;
|
||||
|
||||
pub(crate) const SERVICE_INTERVAL_MS: i64 = PATH_KEEPALIVE_INTERVAL;
|
||||
|
||||
|
@ -46,8 +47,8 @@ impl<HostSystemImpl: HostSystem> Path<HostSystemImpl> {
|
|||
endpoint,
|
||||
local_socket,
|
||||
local_interface,
|
||||
last_send_time_ticks: AtomicI64::new(crate::util::NEVER_HAPPENED_TICKS),
|
||||
last_receive_time_ticks: AtomicI64::new(crate::util::NEVER_HAPPENED_TICKS),
|
||||
last_send_time_ticks: AtomicI64::new(NEVER_HAPPENED_TICKS),
|
||||
last_receive_time_ticks: AtomicI64::new(NEVER_HAPPENED_TICKS),
|
||||
create_time_ticks: time_ticks,
|
||||
fragmented_packets: Mutex::new(HashMap::with_capacity_and_hasher(4, PacketIdHasher(random::xorshift64_random()))),
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ use zerotier_crypto::poly1305;
|
|||
use zerotier_crypto::random;
|
||||
use zerotier_crypto::salsa::Salsa;
|
||||
use zerotier_crypto::secret::Secret;
|
||||
use zerotier_utils::buffer::BufferReader;
|
||||
use zerotier_utils::marshalable::Marshalable;
|
||||
use zerotier_utils::memory::array_range;
|
||||
use zerotier_utils::NEVER_HAPPENED_TICKS;
|
||||
|
||||
use crate::protocol::*;
|
||||
use crate::util::marshalable::Marshalable;
|
||||
use crate::vl1::address::Address;
|
||||
use crate::vl1::debug_event;
|
||||
use crate::vl1::node::*;
|
||||
|
@ -69,10 +69,10 @@ impl<HostSystemImpl: HostSystem> Peer<HostSystemImpl> {
|
|||
identity: id,
|
||||
static_symmetric_key: SymmetricSecret::new(static_secret),
|
||||
paths: Mutex::new(Vec::with_capacity(4)),
|
||||
last_send_time_ticks: AtomicI64::new(crate::util::NEVER_HAPPENED_TICKS),
|
||||
last_receive_time_ticks: AtomicI64::new(crate::util::NEVER_HAPPENED_TICKS),
|
||||
last_forward_time_ticks: AtomicI64::new(crate::util::NEVER_HAPPENED_TICKS),
|
||||
last_hello_reply_time_ticks: AtomicI64::new(crate::util::NEVER_HAPPENED_TICKS),
|
||||
last_send_time_ticks: AtomicI64::new(NEVER_HAPPENED_TICKS),
|
||||
last_receive_time_ticks: AtomicI64::new(NEVER_HAPPENED_TICKS),
|
||||
last_forward_time_ticks: AtomicI64::new(NEVER_HAPPENED_TICKS),
|
||||
last_hello_reply_time_ticks: AtomicI64::new(NEVER_HAPPENED_TICKS),
|
||||
create_time_ticks: time_ticks,
|
||||
random_ticks_offset: random::xorshift64_random() as u32,
|
||||
message_id_counter: AtomicU64::new(random::xorshift64_random()),
|
||||
|
@ -279,37 +279,64 @@ impl<HostSystemImpl: HostSystem> Peer<HostSystemImpl> {
|
|||
}
|
||||
};
|
||||
|
||||
let max_fragment_size = if path.endpoint.requires_fragmentation() {
|
||||
UDP_DEFAULT_MTU
|
||||
} else {
|
||||
usize::MAX
|
||||
};
|
||||
let flags_cipher_hops = if packet.len() > max_fragment_size {
|
||||
v1::HEADER_FLAG_FRAGMENTED | v1::CIPHER_AES_GMAC_SIV
|
||||
} else {
|
||||
v1::CIPHER_AES_GMAC_SIV
|
||||
};
|
||||
let max_fragment_size = path.endpoint.max_fragment_size();
|
||||
if self.remote_node_info.read().remote_protocol_version >= 12 {
|
||||
let flags_cipher_hops = if packet.len() > max_fragment_size {
|
||||
v1::HEADER_FLAG_FRAGMENTED | v1::CIPHER_AES_GMAC_SIV
|
||||
} else {
|
||||
v1::CIPHER_AES_GMAC_SIV
|
||||
};
|
||||
|
||||
let mut aes_gmac_siv = self.static_symmetric_key.aes_gmac_siv.get();
|
||||
aes_gmac_siv.encrypt_init(&self.next_message_id().to_ne_bytes());
|
||||
aes_gmac_siv.encrypt_set_aad(&v1::get_packet_aad_bytes(
|
||||
self.identity.address,
|
||||
node.identity.address,
|
||||
flags_cipher_hops,
|
||||
));
|
||||
let tag = if let Ok(payload) = packet.as_bytes_starting_at_mut(v1::HEADER_SIZE) {
|
||||
aes_gmac_siv.encrypt_first_pass(payload);
|
||||
aes_gmac_siv.encrypt_first_pass_finish();
|
||||
aes_gmac_siv.encrypt_second_pass_in_place(payload);
|
||||
aes_gmac_siv.encrypt_second_pass_finish()
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let mut aes_gmac_siv = self.static_symmetric_key.aes_gmac_siv.get();
|
||||
aes_gmac_siv.encrypt_init(&self.next_message_id().to_ne_bytes());
|
||||
aes_gmac_siv.encrypt_set_aad(&v1::get_packet_aad_bytes(
|
||||
self.identity.address,
|
||||
node.identity.address,
|
||||
flags_cipher_hops,
|
||||
));
|
||||
if let Ok(payload) = packet.as_bytes_starting_at_mut(v1::HEADER_SIZE) {
|
||||
aes_gmac_siv.encrypt_first_pass(payload);
|
||||
aes_gmac_siv.encrypt_first_pass_finish();
|
||||
aes_gmac_siv.encrypt_second_pass_in_place(payload);
|
||||
let tag = aes_gmac_siv.encrypt_second_pass_finish();
|
||||
let header = packet.struct_mut_at::<v1::PacketHeader>(0).unwrap();
|
||||
header.id = *array_range::<u8, 16, 0, 8>(tag);
|
||||
header.id.copy_from_slice(&tag[0..8]);
|
||||
header.dest = self.identity.address.to_bytes();
|
||||
header.src = node.identity.address.to_bytes();
|
||||
header.flags_cipher_hops = flags_cipher_hops;
|
||||
header.mac = *array_range::<u8, 16, 8, 8>(tag);
|
||||
header.mac.copy_from_slice(&tag[8..16]);
|
||||
} else {
|
||||
return false;
|
||||
let packet_len = packet.len();
|
||||
let flags_cipher_hops = if packet.len() > max_fragment_size {
|
||||
v1::HEADER_FLAG_FRAGMENTED | v1::CIPHER_SALSA2012_POLY1305
|
||||
} else {
|
||||
v1::CIPHER_SALSA2012_POLY1305
|
||||
};
|
||||
|
||||
let (mut salsa, poly1305_otk) = salsa_poly_create(
|
||||
&self.static_symmetric_key,
|
||||
{
|
||||
let header = packet.struct_mut_at::<v1::PacketHeader>(0).unwrap();
|
||||
header.id = self.next_message_id().to_ne_bytes();
|
||||
header.dest = self.identity.address.to_bytes();
|
||||
header.src = node.identity.address.to_bytes();
|
||||
header.flags_cipher_hops = flags_cipher_hops;
|
||||
header
|
||||
},
|
||||
packet_len,
|
||||
);
|
||||
|
||||
let tag = if let Ok(payload) = packet.as_bytes_starting_at_mut(v1::HEADER_SIZE) {
|
||||
salsa.crypt_in_place(payload);
|
||||
poly1305::compute(&poly1305_otk, payload)
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
packet.as_bytes_mut()[v1::MAC_FIELD_INDEX..(v1::MAC_FIELD_INDEX + 8)].copy_from_slice(&tag[0..8]);
|
||||
}
|
||||
|
||||
self.internal_send(
|
||||
|
@ -374,11 +401,7 @@ impl<HostSystemImpl: HostSystem> Peer<HostSystemImpl> {
|
|||
}
|
||||
};
|
||||
|
||||
let max_fragment_size = if destination.requires_fragmentation() {
|
||||
UDP_DEFAULT_MTU
|
||||
} else {
|
||||
usize::MAX
|
||||
};
|
||||
let max_fragment_size = destination.max_fragment_size();
|
||||
let time_ticks = host_system.time_ticks();
|
||||
|
||||
let mut packet = PacketBuffer::new();
|
||||
|
@ -401,7 +424,7 @@ impl<HostSystemImpl: HostSystem> Peer<HostSystemImpl> {
|
|||
}
|
||||
|
||||
debug_assert_eq!(packet.len(), 41);
|
||||
assert!(packet.append_bytes((&node.identity.to_public_bytes()).into()).is_ok());
|
||||
assert!(node.identity.write_public(&mut packet, self.identity.p384.is_none()).is_ok());
|
||||
|
||||
let (_, poly1305_key) = salsa_poly_create(
|
||||
&self.static_symmetric_key,
|
||||
|
@ -575,7 +598,7 @@ impl<HostSystemImpl: HostSystem> Peer<HostSystemImpl> {
|
|||
|
||||
let mut cursor = 0;
|
||||
if let Ok(hello_fixed_headers) = payload.read_struct::<v1::message_component_structs::HelloFixedHeaderFields>(&mut cursor) {
|
||||
if let Ok(identity) = Identity::read_bytes(&mut BufferReader::new(payload, &mut cursor)) {
|
||||
if let Ok(identity) = Identity::unmarshal(payload, &mut cursor) {
|
||||
if identity.eq(&self.identity) {
|
||||
{
|
||||
let mut remote_node_info = self.remote_node_info.write();
|
||||
|
@ -698,15 +721,22 @@ impl<HostSystemImpl: HostSystem> Peer<HostSystemImpl> {
|
|||
verbs::VL1_WHOIS => {
|
||||
if node.is_peer_root(self) {
|
||||
while cursor < payload.len() {
|
||||
if let Ok(received_identity) = Identity::read_bytes(&mut BufferReader::new(payload, &mut cursor)) {
|
||||
let r = Identity::unmarshal(payload, &mut cursor);
|
||||
if let Ok(received_identity) = r {
|
||||
debug_event!(
|
||||
host_system,
|
||||
"[vl1] {} OK(WHOIS): {}",
|
||||
"[vl1] {} OK(WHOIS): new identity: {}",
|
||||
self.identity.address.to_string(),
|
||||
received_identity.to_string()
|
||||
);
|
||||
node.handle_incoming_identity(host_system, inner, received_identity, time_ticks, true);
|
||||
} else {
|
||||
debug_event!(
|
||||
host_system,
|
||||
"[vl1] {} OK(WHOIS): bad identity: {}",
|
||||
self.identity.address.to_string(),
|
||||
r.err().unwrap().to_string()
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -750,14 +780,14 @@ impl<HostSystemImpl: HostSystem> Peer<HostSystemImpl> {
|
|||
if addresses.len() >= ADDRESS_SIZE {
|
||||
if let Some(zt_address) = Address::from_bytes(&addresses[..ADDRESS_SIZE]) {
|
||||
if let Some(peer) = node.peer(zt_address) {
|
||||
let id_bytes_tmp = peer.identity.to_public_bytes();
|
||||
let id_bytes = id_bytes_tmp.as_bytes();
|
||||
if (packet.capacity() - packet.len()) < id_bytes.len() {
|
||||
self.send(host_system, None, node, time_ticks, &mut packet);
|
||||
packet.clear();
|
||||
init_packet(&mut packet);
|
||||
if let Ok(id_bytes) = peer.identity.to_public_bytes(self.identity.p384.is_none()) {
|
||||
if (packet.capacity() - packet.len()) < id_bytes.len() {
|
||||
self.send(host_system, None, node, time_ticks, &mut packet);
|
||||
packet.clear();
|
||||
init_packet(&mut packet);
|
||||
}
|
||||
let _ = packet.append_bytes(id_bytes.as_bytes());
|
||||
}
|
||||
let _ = packet.append_bytes(id_bytes);
|
||||
}
|
||||
}
|
||||
addresses = &addresses[ADDRESS_SIZE..];
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
use std::collections::BTreeSet;
|
||||
use std::io::Write;
|
||||
|
||||
use crate::util::marshalable::*;
|
||||
use crate::vl1::identity::{Identity, IDENTITY_MAX_SIGNATURE_SIZE};
|
||||
use crate::vl1::Endpoint;
|
||||
|
||||
use zerotier_utils::arrayvec::ArrayVec;
|
||||
use zerotier_utils::buffer::{Buffer, BufferReader};
|
||||
use zerotier_utils::buffer::Buffer;
|
||||
use zerotier_utils::marshalable::{Marshalable, UnmarshalError};
|
||||
|
||||
use zerotier_crypto::verified::Verified;
|
||||
|
||||
|
@ -100,43 +100,6 @@ impl RootSet {
|
|||
rs.verify().unwrap()
|
||||
}
|
||||
|
||||
fn marshal_internal<const BL: usize>(&self, buf: &mut Buffer<BL>, include_signatures: bool) -> Result<(), MarshalUnmarshalError> {
|
||||
buf.append_u8(0)?; // version byte for future use
|
||||
buf.append_varint(self.name.as_bytes().len() as u64)?;
|
||||
buf.append_bytes(self.name.as_bytes())?;
|
||||
if self.url.is_some() {
|
||||
let url = self.url.as_ref().unwrap().as_bytes();
|
||||
buf.append_varint(url.len() as u64)?;
|
||||
buf.append_bytes(url)?;
|
||||
} else {
|
||||
buf.append_varint(0)?;
|
||||
}
|
||||
buf.append_varint(self.revision)?;
|
||||
buf.append_varint(self.members.len() as u64)?;
|
||||
for m in self.members.iter() {
|
||||
buf.append_bytes((&m.identity.to_public_bytes()).into())?;
|
||||
if m.endpoints.is_some() {
|
||||
let endpoints = m.endpoints.as_ref().unwrap();
|
||||
buf.append_varint(endpoints.len() as u64)?;
|
||||
for a in endpoints.iter() {
|
||||
a.marshal(buf)?;
|
||||
}
|
||||
} else {
|
||||
buf.append_varint(0)?;
|
||||
}
|
||||
if include_signatures {
|
||||
buf.append_varint(m.signature.len() as u64)?;
|
||||
buf.append_bytes(m.signature.as_ref())?;
|
||||
}
|
||||
buf.append_varint(0)?; // flags, currently always 0
|
||||
buf.append_u8(m.priority)?;
|
||||
buf.append_u8(m.protocol_version)?;
|
||||
buf.append_varint(0)?; // size of additional fields for future use
|
||||
}
|
||||
buf.append_varint(0)?; // size of additional fields for future use
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Internal method to marshal without signatures for use during sign and verify.
|
||||
fn marshal_for_signing(&self) -> Buffer<{ Self::MAX_MARSHAL_SIZE }> {
|
||||
let mut tmp = Buffer::<{ Self::MAX_MARSHAL_SIZE }>::new();
|
||||
|
@ -254,20 +217,57 @@ impl RootSet {
|
|||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn marshal_internal<const BL: usize>(&self, buf: &mut Buffer<BL>, include_signatures: bool) -> Result<(), UnmarshalError> {
|
||||
buf.append_u8(0)?; // version byte for future use
|
||||
buf.append_varint(self.name.as_bytes().len() as u64)?;
|
||||
buf.append_bytes(self.name.as_bytes())?;
|
||||
if self.url.is_some() {
|
||||
let url = self.url.as_ref().unwrap().as_bytes();
|
||||
buf.append_varint(url.len() as u64)?;
|
||||
buf.append_bytes(url)?;
|
||||
} else {
|
||||
buf.append_varint(0)?;
|
||||
}
|
||||
buf.append_varint(self.revision)?;
|
||||
buf.append_varint(self.members.len() as u64)?;
|
||||
for m in self.members.iter() {
|
||||
m.identity.marshal(buf)?;
|
||||
if m.endpoints.is_some() {
|
||||
let endpoints = m.endpoints.as_ref().unwrap();
|
||||
buf.append_varint(endpoints.len() as u64)?;
|
||||
for a in endpoints.iter() {
|
||||
a.marshal(buf)?;
|
||||
}
|
||||
} else {
|
||||
buf.append_varint(0)?;
|
||||
}
|
||||
if include_signatures {
|
||||
buf.append_varint(m.signature.len() as u64)?;
|
||||
buf.append_bytes(m.signature.as_ref())?;
|
||||
}
|
||||
buf.append_varint(0)?; // flags, currently always 0
|
||||
buf.append_u8(m.priority)?;
|
||||
buf.append_u8(m.protocol_version)?;
|
||||
buf.append_varint(0)?; // size of additional fields for future use
|
||||
}
|
||||
buf.append_varint(0)?; // size of additional fields for future use
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Marshalable for RootSet {
|
||||
const MAX_MARSHAL_SIZE: usize = crate::protocol::v1::SIZE_MAX;
|
||||
|
||||
#[inline(always)]
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), MarshalUnmarshalError> {
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), UnmarshalError> {
|
||||
self.marshal_internal(buf, true)
|
||||
}
|
||||
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<Self, MarshalUnmarshalError> {
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<Self, UnmarshalError> {
|
||||
let mut rc = Self::new(String::new(), None, 0);
|
||||
if buf.read_u8(cursor)? != 0 {
|
||||
return Err(MarshalUnmarshalError::UnsupportedVersion);
|
||||
return Err(UnmarshalError::UnsupportedVersion);
|
||||
}
|
||||
|
||||
let name_len = buf.read_varint(cursor)?;
|
||||
|
@ -283,7 +283,7 @@ impl Marshalable for RootSet {
|
|||
let member_count = buf.read_varint(cursor)?;
|
||||
for _ in 0..member_count {
|
||||
let mut m = Root {
|
||||
identity: Identity::read_bytes(&mut BufferReader::new(buf, cursor)).map_err(|e| MarshalUnmarshalError::IoError(e))?,
|
||||
identity: Identity::unmarshal(buf, cursor)?,
|
||||
endpoints: None,
|
||||
signature: ArrayVec::new(),
|
||||
priority: 0,
|
||||
|
@ -313,7 +313,7 @@ impl Marshalable for RootSet {
|
|||
|
||||
*cursor += buf.read_varint(cursor)? as usize;
|
||||
if *cursor > buf.len() {
|
||||
return Err(MarshalUnmarshalError::OutOfBounds);
|
||||
return Err(UnmarshalError::OutOfBounds);
|
||||
}
|
||||
|
||||
rc.members.sort();
|
||||
|
|
|
@ -6,12 +6,11 @@ use std::str::FromStr;
|
|||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::error::InvalidFormatError;
|
||||
use crate::util::marshalable::*;
|
||||
|
||||
use zerotier_utils::buffer::Buffer;
|
||||
use zerotier_utils::error::InvalidFormatError;
|
||||
use zerotier_utils::hex;
|
||||
use zerotier_utils::hex::HEX_CHARS;
|
||||
use zerotier_utils::marshalable::{Marshalable, UnmarshalError};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[repr(transparent)]
|
||||
|
@ -61,13 +60,13 @@ impl Marshalable for NetworkId {
|
|||
const MAX_MARSHAL_SIZE: usize = 8;
|
||||
|
||||
#[inline(always)]
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), MarshalUnmarshalError> {
|
||||
buf.append_u64(self.0.get()).map_err(|_| MarshalUnmarshalError::OutOfBounds)
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), UnmarshalError> {
|
||||
buf.append_u64(self.0.get()).map_err(|_| UnmarshalError::OutOfBounds)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<Self, MarshalUnmarshalError> {
|
||||
Self::from_u64(buf.read_u64(cursor)?).ok_or(MarshalUnmarshalError::InvalidData)
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<Self, UnmarshalError> {
|
||||
Self::from_u64(buf.read_u64(cursor)?).ok_or(UnmarshalError::InvalidData)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,10 @@ use clap::ArgMatches;
|
|||
|
||||
use crate::{exitcode, Flags};
|
||||
|
||||
use zerotier_network_hypervisor::util::marshalable::Marshalable;
|
||||
use zerotier_network_hypervisor::vl1::RootSet;
|
||||
|
||||
use zerotier_utils::json::to_json_pretty;
|
||||
use zerotier_utils::marshalable::Marshalable;
|
||||
|
||||
pub fn cmd(_: Flags, cmd_args: &ArgMatches) -> i32 {
|
||||
match cmd_args.subcommand() {
|
||||
|
|
|
@ -191,6 +191,22 @@ impl<T, const C: usize> ArrayVec<T, C> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, const C: usize> ArrayVec<T, C> {
|
||||
/// Push a slice of copyable objects, panic if capacity exceeded.
|
||||
pub fn push_slice(&mut self, v: &[T]) {
|
||||
let start = self.s;
|
||||
let end = self.s + v.len();
|
||||
if end <= C {
|
||||
for i in start..end {
|
||||
unsafe { self.a.get_unchecked_mut(i).write(*v.get_unchecked(i - start)) };
|
||||
}
|
||||
self.s = end;
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const C: usize> Drop for ArrayVec<T, C> {
|
||||
#[inline(always)]
|
||||
fn drop(&mut self) {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::io::Write;
|
||||
|
||||
use zerotier_utils::hex;
|
||||
use zerotier_utils::hex::HEX_CHARS;
|
||||
use crate::hex;
|
||||
|
||||
const BOOL_TRUTH: &str = "1tTyY";
|
||||
|
||||
|
@ -55,8 +54,8 @@ fn append_printable(s: &mut String, b: &[u8]) {
|
|||
} else {
|
||||
s.push('\\');
|
||||
s.push('x');
|
||||
s.push(HEX_CHARS[((c as u8) >> 4) as usize] as char);
|
||||
s.push(HEX_CHARS[((c as u8) & 0xf) as usize] as char);
|
||||
s.push(hex::HEX_CHARS[((c as u8) >> 4) as usize] as char);
|
||||
s.push(hex::HEX_CHARS[((c as u8) & 0xf) as usize] as char);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,163 +211,3 @@ impl ToString for Dictionary {
|
|||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
enum Type {
|
||||
String,
|
||||
Bytes,
|
||||
U64,
|
||||
Bool,
|
||||
}
|
||||
|
||||
type TypeMap = HashMap<String, Type>;
|
||||
|
||||
use super::{Dictionary, BOOL_TRUTH};
|
||||
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();
|
||||
|
||||
for _ in 0..(rand::random::<usize>() % 20) + 1 {
|
||||
// NOTE: just doing this twice because I want to keep the code a little cleaner.
|
||||
let selection = rand::random::<usize>() % 4;
|
||||
|
||||
let key = randstring(10);
|
||||
|
||||
// set the key
|
||||
match selection {
|
||||
0 => d.set_str(&key, &randstring(10)),
|
||||
1 => d.set_u64(&key, rand::random()),
|
||||
2 => d.set_bytes(
|
||||
&key,
|
||||
(0..((rand::random::<usize>() % 10) + 1))
|
||||
.into_iter()
|
||||
.map(|_| rand::random())
|
||||
.collect::<Vec<u8>>(),
|
||||
),
|
||||
3 => d.set_bool(&key, rand::random::<bool>()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
match selection {
|
||||
0 => tm.insert(key, Type::String),
|
||||
1 => tm.insert(key, Type::U64),
|
||||
2 => tm.insert(key, Type::Bytes),
|
||||
3 => tm.insert(key, Type::Bool),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
(d, tm)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dictionary_basic() {
|
||||
let mut d = Dictionary::new();
|
||||
d.set_str("foo", "bar");
|
||||
d.set_u64("bar", 0xfeedcafebabebeef);
|
||||
d.set_bytes("baz", vec![1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
d.set_bool("lala", true);
|
||||
d.set_bool("haha", false);
|
||||
let bytes = d.to_bytes();
|
||||
let d2 = Dictionary::from_bytes(bytes.as_slice()).unwrap();
|
||||
assert!(d.eq(&d2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dictionary_to_string() {
|
||||
for _ in 0..1000 {
|
||||
let (d, _) = make_dictionary();
|
||||
assert_ne!(d.to_string().len(), 0)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dictionary_clear() {
|
||||
for _ in 0..1000 {
|
||||
let (mut d, _) = make_dictionary();
|
||||
assert_ne!(d.len(), 0);
|
||||
assert!(!d.is_empty());
|
||||
d.clear();
|
||||
assert!(d.is_empty());
|
||||
assert_eq!(d.len(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dictionary_io() {
|
||||
for _ in 0..1000 {
|
||||
let (d, _) = make_dictionary();
|
||||
assert_ne!(d.len(), 0);
|
||||
assert!(!d.is_empty());
|
||||
|
||||
let mut v = Vec::new();
|
||||
let mut cursor = std::io::Cursor::new(&mut v);
|
||||
assert!(d.write_to(&mut cursor).is_ok());
|
||||
drop(cursor);
|
||||
assert!(!v.is_empty());
|
||||
|
||||
let d2 = super::Dictionary::from_bytes(v.as_slice());
|
||||
assert!(d2.is_some());
|
||||
let d2 = d2.unwrap();
|
||||
assert_eq!(d, d2);
|
||||
|
||||
let d2 = super::Dictionary::from_bytes(&d.to_bytes());
|
||||
assert!(d2.is_some());
|
||||
let d2 = d2.unwrap();
|
||||
assert_eq!(d, d2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dictionary_accessors() {
|
||||
for _ in 0..1000 {
|
||||
let (d, tm) = make_dictionary();
|
||||
|
||||
for (k, v) in d.iter() {
|
||||
match tm.get(k).unwrap() {
|
||||
Type::String => {
|
||||
let v2 = d.get_str(k);
|
||||
assert!(v2.is_some());
|
||||
assert_eq!(String::from_utf8(v.to_vec()).unwrap(), String::from(v2.unwrap()));
|
||||
}
|
||||
Type::Bytes => {
|
||||
let v2 = d.get_bytes(k);
|
||||
assert!(v2.is_some());
|
||||
assert_eq!(v, v2.unwrap());
|
||||
}
|
||||
Type::Bool => {
|
||||
let v2 = d.get_bool(k);
|
||||
assert!(v2.is_some());
|
||||
// FIXME move this lettering to a constant
|
||||
assert_eq!(BOOL_TRUTH.contains(*v.iter().nth(0).unwrap() as char), v2.unwrap());
|
||||
}
|
||||
Type::U64 => {
|
||||
let v2 = d.get_u64(k);
|
||||
assert!(v2.is_some());
|
||||
|
||||
assert_eq!(u64::from_str_radix(d.get_str(k).unwrap(), 16).unwrap(), v2.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,7 +37,7 @@ impl Debug for InvalidFormatError {
|
|||
|
||||
impl Error for InvalidFormatError {}
|
||||
|
||||
pub struct InvalidParameterError(pub(crate) &'static str);
|
||||
pub struct InvalidParameterError(pub &'static str);
|
||||
|
||||
impl Display for InvalidParameterError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
@ -53,20 +53,3 @@ impl Debug for InvalidParameterError {
|
|||
}
|
||||
|
||||
impl Error for InvalidParameterError {}
|
||||
|
||||
pub struct MalformedRecordError(pub(crate) &'static str);
|
||||
|
||||
impl Display for MalformedRecordError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "InvalidParameterError: {}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for MalformedRecordError {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
<Self as Display>::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for MalformedRecordError {}
|
|
@ -9,7 +9,7 @@ pub struct IntervalGate<const FREQ: i64>(i64);
|
|||
impl<const FREQ: i64> Default for IntervalGate<FREQ> {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
Self(crate::util::NEVER_HAPPENED_TICKS)
|
||||
Self(crate::NEVER_HAPPENED_TICKS)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,11 +3,15 @@
|
|||
pub mod arrayvec;
|
||||
pub mod blob;
|
||||
pub mod buffer;
|
||||
pub mod dictionary;
|
||||
pub mod error;
|
||||
#[allow(unused)]
|
||||
pub mod exitcode;
|
||||
pub mod gate;
|
||||
pub mod gatherarray;
|
||||
pub mod hex;
|
||||
pub mod json;
|
||||
pub mod marshalable;
|
||||
pub mod memory;
|
||||
pub mod pool;
|
||||
pub mod ringbuffer;
|
||||
|
@ -20,6 +24,9 @@ pub mod reaper;
|
|||
#[cfg(feature = "tokio")]
|
||||
pub use tokio;
|
||||
|
||||
/// A monotonic ticks value for "never happened" that should be lower than any initial value.
|
||||
pub const NEVER_HAPPENED_TICKS: i64 = i64::MIN / 2;
|
||||
|
||||
/// Get milliseconds since unix epoch.
|
||||
pub fn ms_since_epoch() -> i64 {
|
||||
std::time::SystemTime::now()
|
||||
|
|
|
@ -3,72 +3,31 @@
|
|||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
use zerotier_utils::buffer::{Buffer, OutOfBoundsError};
|
||||
use crate::buffer::Buffer;
|
||||
|
||||
/// Must be larger than any object we want to use with to_bytes() or from_bytes().
|
||||
/// This hack can go away once Rust allows us to reference trait consts as generics.
|
||||
const TEMP_BUF_SIZE: usize = 8192;
|
||||
|
||||
pub enum MarshalUnmarshalError {
|
||||
OutOfBounds,
|
||||
InvalidData,
|
||||
UnsupportedVersion,
|
||||
IoError(std::io::Error),
|
||||
}
|
||||
|
||||
impl Display for MarshalUnmarshalError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::OutOfBounds => f.write_str("out of bounds"),
|
||||
Self::InvalidData => f.write_str("invalid data"),
|
||||
Self::UnsupportedVersion => f.write_str("unsupported version"),
|
||||
Self::IoError(e) => f.write_str(e.to_string().as_str()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for MarshalUnmarshalError {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for MarshalUnmarshalError {}
|
||||
|
||||
impl From<OutOfBoundsError> for MarshalUnmarshalError {
|
||||
#[inline(always)]
|
||||
fn from(_: OutOfBoundsError) -> Self {
|
||||
Self::OutOfBounds
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for MarshalUnmarshalError {
|
||||
#[inline(always)]
|
||||
fn from(e: std::io::Error) -> Self {
|
||||
Self::IoError(e)
|
||||
}
|
||||
}
|
||||
|
||||
/// A super-lightweight zero-allocation serialization interface.
|
||||
pub trait Marshalable: Sized {
|
||||
const MAX_MARSHAL_SIZE: usize;
|
||||
|
||||
/// Write this object into a buffer.
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), MarshalUnmarshalError>;
|
||||
fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> Result<(), UnmarshalError>;
|
||||
|
||||
/// Read this object from a buffer.
|
||||
///
|
||||
/// The supplied cursor is advanced by the number of bytes read. If an Err is returned
|
||||
/// the value of the cursor is undefined but likely points to about where the error
|
||||
/// occurred. It may also point beyond the buffer, which would indicate an overrun error.
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<Self, MarshalUnmarshalError>;
|
||||
fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> Result<Self, UnmarshalError>;
|
||||
|
||||
/// Write this marshalable entity into a buffer of the given size.
|
||||
///
|
||||
/// This will return an Err if the buffer is too small or some other error occurs. It's just
|
||||
/// a shortcut to creating a buffer and marshaling into it.
|
||||
fn to_buffer<const BL: usize>(&self) -> Result<Buffer<BL>, MarshalUnmarshalError> {
|
||||
fn to_buffer<const BL: usize>(&self) -> Result<Buffer<BL>, UnmarshalError> {
|
||||
let mut tmp = Buffer::new();
|
||||
self.marshal(&mut tmp)?;
|
||||
Ok(tmp)
|
||||
|
@ -77,7 +36,7 @@ pub trait Marshalable: Sized {
|
|||
/// Unmarshal this object from a buffer.
|
||||
///
|
||||
/// This is just a shortcut to calling unmarshal() with a zero cursor and then discarding the cursor.
|
||||
fn from_buffer<const BL: usize>(buf: &Buffer<BL>) -> Result<Self, MarshalUnmarshalError> {
|
||||
fn from_buffer<const BL: usize>(buf: &Buffer<BL>) -> Result<Self, UnmarshalError> {
|
||||
let mut tmp = 0;
|
||||
Self::unmarshal(buf, &mut tmp)
|
||||
}
|
||||
|
@ -90,14 +49,55 @@ pub trait Marshalable: Sized {
|
|||
}
|
||||
|
||||
/// Unmarshal from a raw slice.
|
||||
fn from_bytes(b: &[u8]) -> Result<Self, MarshalUnmarshalError> {
|
||||
fn from_bytes(b: &[u8]) -> Result<Self, UnmarshalError> {
|
||||
if b.len() <= TEMP_BUF_SIZE {
|
||||
let mut tmp = Buffer::<TEMP_BUF_SIZE>::new_boxed();
|
||||
assert!(tmp.append_bytes(b).is_ok());
|
||||
let mut cursor = 0;
|
||||
Self::unmarshal(&tmp, &mut cursor)
|
||||
} else {
|
||||
Err(MarshalUnmarshalError::OutOfBounds)
|
||||
Err(UnmarshalError::OutOfBounds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum UnmarshalError {
|
||||
OutOfBounds,
|
||||
InvalidData,
|
||||
UnsupportedVersion,
|
||||
IoError(std::io::Error),
|
||||
}
|
||||
|
||||
impl Display for UnmarshalError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::OutOfBounds => f.write_str("out of bounds"),
|
||||
Self::InvalidData => f.write_str("invalid data"),
|
||||
Self::UnsupportedVersion => f.write_str("unsupported version"),
|
||||
Self::IoError(e) => f.write_str(e.to_string().as_str()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for UnmarshalError {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for UnmarshalError {}
|
||||
|
||||
impl From<crate::buffer::OutOfBoundsError> for UnmarshalError {
|
||||
#[inline(always)]
|
||||
fn from(_: crate::buffer::OutOfBoundsError) -> Self {
|
||||
Self::OutOfBounds
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for UnmarshalError {
|
||||
#[inline(always)]
|
||||
fn from(e: std::io::Error) -> Self {
|
||||
Self::IoError(e)
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue