Merge pull request #3 from zerotier/fix-tests-on-linux

Fix tests on linux
This commit is contained in:
Erik Hollensbe 2022-04-18 14:16:10 -07:00 committed by GitHub
commit 17ea66f255
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 202 additions and 156 deletions

View file

@ -3,4 +3,9 @@ all:
clean: FORCE
rm -rf zerotier-core-crypto/target zerotier-network-hypervisor/target zerotier-system-service/target syncwhole/target aes-gmac-siv/target iblt/target
test:
for i in */Cargo.toml; do cd $$(dirname $$i); cargo test || exit 1; cd ..; done
FORCE:
.PHONY: test

View file

@ -8,7 +8,7 @@
// AES-GMAC-SIV implemented using OpenSSL.
use openssl::symm::{Crypter, Cipher, Mode};
use openssl::symm::{Cipher, Crypter, Mode};
fn aes_ctr_by_key_size(ks: usize) -> Cipher {
match ks {
@ -145,7 +145,8 @@ impl AesGmacSiv {
let gmac = self.gmac.as_mut().unwrap();
let _ = gmac.finalize(&mut self.tmp);
let _ = gmac.get_tag(&mut self.tmp);
unsafe { // tag[8..16] = tmp[0..8] ^ tmp[8..16]
unsafe {
// tag[8..16] = tmp[0..8] ^ tmp[8..16]
let tmp = self.tmp.as_mut_ptr().cast::<u64>();
*self.tag.as_mut_ptr().cast::<u64>().offset(1) = *tmp ^ *tmp.offset(1);
}
@ -185,7 +186,8 @@ impl AesGmacSiv {
let mut tag_tmp = [0_u8; 32];
let _ = Crypter::new(aes_ecb_by_key_size(self.k1.len()), Mode::Decrypt, self.k1.as_slice(), None).unwrap().update(&self.tag, &mut tag_tmp);
self.tag.copy_from_slice(&tag_tmp[0..16]);
unsafe { // tmp[0..8] = tag[0..8], tmp[8..16] = 0
unsafe {
// tmp[0..8] = tag[0..8], tmp[8..16] = 0
let tmp = self.tmp.as_mut_ptr().cast::<u64>();
*tmp = *self.tag.as_mut_ptr().cast::<u64>();
*tmp.offset(1) = 0;
@ -227,13 +229,18 @@ impl AesGmacSiv {
/// Finish decryption and return true if authentication appears valid.
/// If this returns false the message should be dropped.
#[inline(always)]
pub fn decrypt_finish(&mut self) -> bool {
pub fn decrypt_finish(&mut self) -> Option<&[u8; 16]> {
let gmac = self.gmac.as_mut().unwrap();
let _ = gmac.finalize(&mut self.tmp);
let _ = gmac.get_tag(&mut self.tmp);
unsafe { // tag[8..16] == tmp[0..8] ^ tmp[8..16]
unsafe {
// tag[8..16] == tmp[0..8] ^ tmp[8..16]
let tmp = self.tmp.as_mut_ptr().cast::<u64>();
*self.tag.as_mut_ptr().cast::<u64>().offset(1) == *tmp ^ *tmp.offset(1)
if *self.tag.as_mut_ptr().cast::<u64>().offset(1) == *tmp ^ *tmp.offset(1) {
Some(&self.tag)
} else {
None
}
}
}
}

View file

@ -26,9 +26,9 @@ use zerotier_core_crypto::secret::Secret;
use crate::error::{InvalidFormatError, InvalidParameterError};
use crate::util::buffer::Buffer;
use crate::util::pool::{Pool, Pooled, PoolFactory};
use crate::vl1::Address;
use crate::util::pool::{Pool, PoolFactory, Pooled};
use crate::vl1::protocol::{ADDRESS_SIZE, ADDRESS_SIZE_STRING, IDENTITY_POW_THRESHOLD};
use crate::vl1::Address;
/// Curve25519 and Ed25519
pub const IDENTITY_ALGORITHM_X25519: u8 = 0x01;
@ -40,7 +40,8 @@ pub const IDENTITY_ALGORITHM_EC_NIST_P384: u8 = 0x02;
pub const IDENTITY_ALGORITHM_ALL: u8 = 0xff;
/// Current sanity limit for the size of a marshaled Identity (can be increased if needed).
pub const MAX_MARSHAL_SIZE: usize = ADDRESS_SIZE + C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE + P384_PUBLIC_KEY_SIZE + P384_PUBLIC_KEY_SIZE + P384_SECRET_KEY_SIZE + P384_SECRET_KEY_SIZE + P384_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE + 16;
pub const MAX_MARSHAL_SIZE: usize =
ADDRESS_SIZE + C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE + P384_PUBLIC_KEY_SIZE + P384_PUBLIC_KEY_SIZE + P384_SECRET_KEY_SIZE + P384_SECRET_KEY_SIZE + P384_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE + 16;
#[derive(Clone)]
pub struct IdentityP384Secret {
@ -70,7 +71,7 @@ pub struct Identity {
pub ed25519: [u8; ED25519_PUBLIC_KEY_SIZE],
pub p384: Option<IdentityP384Public>,
pub secret: Option<IdentitySecret>,
pub fingerprint: [u8; SHA512_HASH_SIZE]
pub fingerprint: [u8; SHA512_HASH_SIZE],
}
#[inline(always)]
@ -129,12 +130,8 @@ impl Identity {
c25519: c25519_pub,
ed25519: ed25519_pub,
p384: None,
secret: Some(IdentitySecret {
c25519,
ed25519,
p384: None,
}),
fingerprint: [0_u8; 64] // replaced in upgrade()
secret: Some(IdentitySecret { c25519, ed25519, p384: None }),
fingerprint: [0_u8; 64], // replaced in upgrade()
};
assert!(id.upgrade().is_ok());
assert!(id.p384.is_some() && id.secret.as_ref().unwrap().p384.is_some());
@ -176,10 +173,7 @@ impl Identity {
ecdsa_self_signature,
ed25519_self_signature,
});
let _ = self.secret.as_mut().unwrap().p384.insert(IdentityP384Secret {
ecdh: p384_ecdh,
ecdsa: p384_ecdsa,
});
let _ = self.secret.as_mut().unwrap().p384.insert(IdentityP384Secret { ecdh: p384_ecdh, ecdsa: p384_ecdsa });
self.fingerprint = SHA512::hash(self_sign_buf.as_slice());
return Ok(true);
@ -251,9 +245,7 @@ impl Identity {
// for the final result to be technically FIPS compliant. Non-FIPS algorithm secrets are considered
// a salt in the HMAC(salt, key) HKDF construction.
if secret.p384.is_some() && other.p384.is_some() {
secret.p384.as_ref().unwrap().ecdh.agree(&other.p384.as_ref().unwrap().ecdh).map(|p384_secret| {
Secret(hmac_sha512(&c25519_secret.0, &p384_secret.0))
})
secret.p384.as_ref().unwrap().ecdh.agree(&other.p384.as_ref().unwrap().ecdh).map(|p384_secret| Secret(hmac_sha512(&c25519_secret.0, &p384_secret.0)))
} else {
Some(c25519_secret)
}
@ -291,7 +283,8 @@ impl Identity {
/// Verify a signature against this identity.
pub fn verify(&self, msg: &[u8], mut signature: &[u8]) -> bool {
if signature.len() == 96 { // legacy ed25519-only signature with hash included
if signature.len() == 96 {
// legacy ed25519-only signature with hash included
ed25519_verify(&self.ed25519, signature, msg)
} else if signature.len() > 1 {
let algorithms = signature[0];
@ -519,7 +512,7 @@ impl Identity {
} else {
None
},
fingerprint: sha.finish()
fingerprint: sha.finish(),
})
}
@ -532,46 +525,42 @@ impl Identity {
let p384 = self.p384.as_ref().unwrap();
let p384_secret_joined: [u8; P384_SECRET_KEY_SIZE + P384_SECRET_KEY_SIZE] = concat_arrays_2(p384_secret.ecdh.secret_key_bytes().as_bytes(), p384_secret.ecdsa.secret_key_bytes().as_bytes());
let p384_joined: [u8; P384_PUBLIC_KEY_SIZE + P384_PUBLIC_KEY_SIZE + P384_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE] = concat_arrays_4(p384.ecdh.as_bytes(), p384.ecdsa.as_bytes(), &p384.ecdsa_self_signature, &p384.ed25519_self_signature);
format!("{}:0:{}{}:{}{}:2:{}:{}",
format!(
"{}:0:{}{}:{}{}:2:{}:{}",
self.address.to_string(),
hex::to_string(&self.c25519),
hex::to_string(&self.ed25519),
hex::to_string(&secret.c25519.secret_bytes().0),
hex::to_string(&secret.ed25519.secret_bytes().0),
base64::encode_config(p384_joined, base64::URL_SAFE_NO_PAD),
base64::encode_config(p384_secret_joined, base64::URL_SAFE_NO_PAD))
base64::encode_config(p384_secret_joined, base64::URL_SAFE_NO_PAD)
)
} else {
format!("{}:0:{}{}:{}{}",
self.address.to_string(),
hex::to_string(&self.c25519),
hex::to_string(&self.ed25519),
hex::to_string(&secret.c25519.secret_bytes().0),
hex::to_string(&secret.ed25519.secret_bytes().0))
format!("{}:0:{}{}:{}{}", self.address.to_string(), hex::to_string(&self.c25519), hex::to_string(&self.ed25519), hex::to_string(&secret.c25519.secret_bytes().0), hex::to_string(&secret.ed25519.secret_bytes().0))
}
} else {
self.p384.as_ref().map_or_else(|| {
format!("{}:0:{}{}",
self.address.to_string(),
hex::to_string(&self.c25519),hex::to_string(&self.ed25519))
}, |p384| {
let p384_joined: [u8; P384_PUBLIC_KEY_SIZE + P384_PUBLIC_KEY_SIZE + P384_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE] = concat_arrays_4(p384.ecdh.as_bytes(), p384.ecdsa.as_bytes(), &p384.ecdsa_self_signature, &p384.ed25519_self_signature);
format!("{}:0:{}{}::2:{}",
self.address.to_string(),
hex::to_string(&self.c25519),
hex::to_string(&self.ed25519),
base64::encode_config(p384_joined, base64::URL_SAFE_NO_PAD))
})
self.p384.as_ref().map_or_else(
|| format!("{}:0:{}{}", self.address.to_string(), hex::to_string(&self.c25519), hex::to_string(&self.ed25519)),
|p384| {
let p384_joined: [u8; P384_PUBLIC_KEY_SIZE + P384_PUBLIC_KEY_SIZE + P384_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE] = concat_arrays_4(p384.ecdh.as_bytes(), p384.ecdsa.as_bytes(), &p384.ecdsa_self_signature, &p384.ed25519_self_signature);
format!("{}:0:{}{}::2:{}", self.address.to_string(), hex::to_string(&self.c25519), hex::to_string(&self.ed25519), base64::encode_config(p384_joined, base64::URL_SAFE_NO_PAD))
},
)
}
}
/// Get this identity in string form with all ciphers and with secrets (if present)
pub fn to_secret_string(&self) -> String { self.to_string_with_options(IDENTITY_ALGORITHM_ALL, true) }
pub fn to_secret_string(&self) -> String {
self.to_string_with_options(IDENTITY_ALGORITHM_ALL, true)
}
}
impl ToString for Identity {
/// Get only the public portion of this identity as a string, including all cipher suites.
#[inline(always)]
fn to_string(&self) -> String { self.to_string_with_options(IDENTITY_ALGORITHM_ALL, false) }
fn to_string(&self) -> String {
self.to_string_with_options(IDENTITY_ALGORITHM_ALL, false)
}
}
impl FromStr for Identity {
@ -616,7 +605,8 @@ impl FromStr for Identity {
ptr += 1;
}
let keys = [hex::from_string(keys[0].unwrap_or("")), hex::from_string(keys[1].unwrap_or("")), base64::decode_config(keys[2].unwrap_or(""), base64::URL_SAFE_NO_PAD).unwrap_or_else(|_| Vec::new()), base64::decode_config(keys[3].unwrap_or(""), base64::URL_SAFE_NO_PAD).unwrap_or_else(|_| Vec::new())];
let keys =
[hex::from_string(keys[0].unwrap_or("")), hex::from_string(keys[1].unwrap_or("")), base64::decode_config(keys[2].unwrap_or(""), base64::URL_SAFE_NO_PAD).unwrap_or_else(|_| Vec::new()), base64::decode_config(keys[3].unwrap_or(""), base64::URL_SAFE_NO_PAD).unwrap_or_else(|_| Vec::new())];
if keys[0].len() != C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE {
return Err(InvalidFormatError);
}
@ -697,30 +687,38 @@ impl FromStr for Identity {
},
})
},
fingerprint: sha.finish()
fingerprint: sha.finish(),
})
}
}
impl PartialEq for Identity {
#[inline(always)]
fn eq(&self, other: &Self) -> bool { self.fingerprint == other.fingerprint }
fn eq(&self, other: &Self) -> bool {
self.fingerprint == other.fingerprint
}
}
impl Eq for Identity {}
impl Ord for Identity {
fn cmp(&self, other: &Self) -> Ordering { self.address.cmp(&other.address).then_with(|| self.fingerprint.cmp(&other.fingerprint)) }
fn cmp(&self, other: &Self) -> Ordering {
self.address.cmp(&other.address).then_with(|| self.fingerprint.cmp(&other.fingerprint))
}
}
impl PartialOrd for Identity {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Hash for Identity {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) { state.write_u64(self.address.to_u64()) }
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u64(self.address.to_u64())
}
}
const ADDRESS_DERIVATION_HASH_MEMORY_SIZE: usize = 2097152;
@ -767,19 +765,25 @@ struct AddressDerivationMemory(*mut u8);
impl AddressDerivationMemory {
#[inline(always)]
fn get_memory(&mut self) -> *mut u8 { self.0 }
fn get_memory(&mut self) -> *mut u8 {
self.0
}
}
impl Drop for AddressDerivationMemory {
#[inline(always)]
fn drop(&mut self) { unsafe { dealloc(self.0, Layout::from_size_align(ADDRESS_DERIVATION_HASH_MEMORY_SIZE, 8).unwrap()) }; }
fn drop(&mut self) {
unsafe { dealloc(self.0, Layout::from_size_align(ADDRESS_DERIVATION_HASH_MEMORY_SIZE, 8).unwrap()) };
}
}
struct AddressDerivationMemoryFactory;
impl PoolFactory<AddressDerivationMemory> for AddressDerivationMemoryFactory {
#[inline(always)]
fn create(&self) -> AddressDerivationMemory { AddressDerivationMemory(unsafe { alloc(Layout::from_size_align(ADDRESS_DERIVATION_HASH_MEMORY_SIZE, 8).unwrap()) }) }
fn create(&self) -> AddressDerivationMemory {
AddressDerivationMemory(unsafe { alloc(Layout::from_size_align(ADDRESS_DERIVATION_HASH_MEMORY_SIZE, 8).unwrap()) })
}
#[inline(always)]
fn reset(&self, _: &mut AddressDerivationMemory) {}
@ -799,10 +803,10 @@ pub(crate) fn purge_verification_memory_pool() {
#[cfg(test)]
mod tests {
use crate::vl1::identity::{Identity, IDENTITY_ALGORITHM_ALL};
use std::str::FromStr;
use std::time::{Duration, SystemTime};
use zerotier_core_crypto::hex;
use crate::vl1::identity::{Identity, IDENTITY_ALGORITHM_ALL};
const GOOD_V0_IDENTITIES: [&'static str; 10] = [
"51ef313c3a:0:79fee239cf79833be3a9068565661dc33e04759fa0f7e2218d10f1a51d441f1bf71332eba26dfc3755ce60e14650fe68dede66cf145e429972a7f51e026374de:6d12b1c5e0eae3983a5ee5872fa9061963d9e2f8cdd85adab54bdec4bd67f538cafc91b8b5b93fca658a630aab030ec10d66235f2443ccf362c55c41ae01b46e",
@ -814,7 +818,7 @@ mod tests {
"c5bdb4a6a6:0:e0a8575bc0277ecf59aaa4a2724acc55554151fff510c8211b0b863398a04224ed918c16405552336ad4c4da3b98eb6224574f1cacaa69e19cdfde184fd9292d:0d45f17d73337cc1898f7be6aae54a050b39ed0259b608b80619c3f898caf8a3a48ae56e51c3d7d8426ef295c0628d81b1a99616a3ed28da49bf8f81e1bec863",
"c622dedbe4:0:0cfec354be26b4b2fa9ea29166b4acaf9476d169d51fd741d7e4cd9de93f321c6b80628c50da566d0a6b07d58d651eba8af63e0edc36202c05c3f97c828788ad:31a75d2b46c1b0f33228d3869bc807b42b371bbcef4c96f7232a27c62f56397568558f115d9cff3d6f7b8efb726a1ea49a591662d9aacd1049e295cbb0cf3197",
"e28829ab3c:0:8e36c4f6cb524cae6bbea5f26dadb601a76f2a3793961779317365effb17ac6cde4ff4149a1b3480fbdbdbabfe62e1f264e764f95540b63158d1ea8b1eb0df5b:957508a7546df18784cd285da2e6216e4265906c6c7fba9a895f29a724d63a2e0268128c0c9c2cc304c8c3304863cdfe437a7b93b12dc778c0372a116088e9cd",
"aec623e59d:0:d7b1a715d95490611b8d467bbee442e3c88949f677371d3692da92f5b23d9e01bb916596cc1ddd2d5e0e5ecd6c750bb71ad2ba594b614b771c6f07b39dbe4126:ae4e4759d67158dcc54ede8c8ddb08acac49baf8b816883fc0ac5b6e328d17ced5f05ee0b4cd20b03bc5005471795c29206b835081b873fef26d3941416bd626"
"aec623e59d:0:d7b1a715d95490611b8d467bbee442e3c88949f677371d3692da92f5b23d9e01bb916596cc1ddd2d5e0e5ecd6c750bb71ad2ba594b614b771c6f07b39dbe4126:ae4e4759d67158dcc54ede8c8ddb08acac49baf8b816883fc0ac5b6e328d17ced5f05ee0b4cd20b03bc5005471795c29206b835081b873fef26d3941416bd626",
];
const GOOD_V1_IDENTITIES: [&'static str; 10] = [
"a8f6e0566e:0:a13a6394de205384eb75eb62179ef11423295c5ecdccfeed7f2eff6c7a74f8059c99eed164c5dfaf2a4cf395ec7b72b68ee1c3c31916de4bc57c07abfe77f9c2::2:A1Cj2O0hKLlhDQ6guCCv5H1UgzbegZwse0iqTaaZov9LpKifyKH0e1VzmHrPmoKcvgJyzI-BAqRQzBiUjScXIjojneNKOywc0Gvq-zeDCYPcXN393xi3q25mB3ud9iEN-GN6wiXPWFjHy-CBD9tGDJzr-G3ZJZvrdiLGT5rZ5W2cZtx8ORYnp9L9HJJOeb8qgdfVr67B5pT9jPsxSsw8P4qlzFFOlX2WN9Hvvu0TO6S_N4yq173deyr-f-ehcBFiBXsSG96p44oU4uRRBEDZWhzHDuD22Vw8PhsB8mko9IRqVXCGbvlaKJ0vyAZ_PyVRM9n_Z-HAEvLveAT-f61mh4YP",

View file

@ -8,13 +8,13 @@
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::mem::{MaybeUninit, size_of, transmute_copy, zeroed};
use std::mem::{size_of, transmute_copy, zeroed, MaybeUninit};
use std::net::{IpAddr, Ipv6Addr};
use std::ptr::{copy_nonoverlapping, null, slice_from_raw_parts, write_bytes};
use std::str::FromStr;
#[cfg(windows)]
use winapi::um::winsock2 as winsock2;
use winapi::um::winsock2;
use crate::error::InvalidFormatError;
use crate::util::buffer::Buffer;
@ -74,18 +74,24 @@ pub union InetAddress {
impl Clone for InetAddress {
#[inline(always)]
fn clone(&self) -> Self { unsafe { transmute_copy(self) } }
fn clone(&self) -> Self {
unsafe { transmute_copy(self) }
}
}
impl Default for InetAddress {
#[inline(always)]
fn default() -> InetAddress { unsafe { zeroed() } }
fn default() -> InetAddress {
unsafe { zeroed() }
}
}
impl InetAddress {
/// Get a new zero/nil InetAddress.
#[inline(always)]
pub fn new() -> InetAddress { unsafe { zeroed() } }
pub fn new() -> InetAddress {
unsafe { zeroed() }
}
/// Construct from IP and port.
/// If the IP is not either 4 or 16 bytes in length, a nil/0 InetAddress is returned.
@ -100,7 +106,9 @@ impl InetAddress {
/// Zero the contents of this InetAddress.
#[inline(always)]
pub fn zero(&mut self) { unsafe { write_bytes((self as *mut Self).cast::<u8>(), 0, size_of::<Self>()) }; }
pub fn zero(&mut self) {
unsafe { write_bytes((self as *mut Self).cast::<u8>(), 0, size_of::<Self>()) };
}
/// Get an instance of 127.0.0.1/port
pub fn ipv4_loopback(port: u16) -> InetAddress {
@ -138,19 +146,35 @@ impl InetAddress {
/// Returns true if this InetAddress is the nil value (zero).
#[inline(always)]
pub fn is_nil(&self) -> bool { unsafe { self.sa.sa_family == 0 } }
pub fn is_nil(&self) -> bool {
unsafe { self.sa.sa_family == 0 }
}
/// Check if this is an IPv4 address.
#[inline(always)]
pub fn is_ipv4(&self) -> bool { unsafe { self.sa.sa_family as u8 == AF_INET } }
pub fn is_ipv4(&self) -> bool {
unsafe { self.sa.sa_family as u8 == AF_INET }
}
/// Check if this is an IPv6 address.
#[inline(always)]
pub fn is_ipv6(&self) -> bool { unsafe { self.sa.sa_family as u8 == AF_INET6 } }
pub fn is_ipv6(&self) -> bool {
unsafe { self.sa.sa_family as u8 == AF_INET6 }
}
/// Get the address family of this InetAddress: AF_INET, AF_INET6, or 0 if uninitialized.
#[inline(always)]
pub fn family(&self) -> u8 { unsafe { self.sa.sa_family } }
#[cfg(not(target_os = "linux"))]
pub fn family(&self) -> u8 {
unsafe { self.sa.sa_family }
}
/// Get the address family of this InetAddress: AF_INET, AF_INET6, or 0 if uninitialized.
#[inline(always)]
#[cfg(target_os = "linux")]
pub fn family(&self) -> u16 {
unsafe { self.sa.sa_family }
}
/// Get a pointer to the C "sockaddr" structure and the size of the returned structure in bytes.
/// This is useful for interacting with C-level socket APIs. This returns a null pointer if
@ -161,7 +185,7 @@ impl InetAddress {
match self.sa.sa_family as u8 {
AF_INET => ((&self.sin as *const sockaddr_in).cast(), size_of::<sockaddr_in>()),
AF_INET6 => ((&self.sin6 as *const sockaddr_in6).cast(), size_of::<sockaddr_in6>()),
_ => (null(), 0)
_ => (null(), 0),
}
}
}
@ -223,7 +247,7 @@ impl InetAddress {
u16::from_be(match self.sa.sa_family as u8 {
AF_INET => self.sin.sin_port as u16,
AF_INET6 => self.sin6.sin6_port as u16,
_ => 0
_ => 0,
})
}
}
@ -256,42 +280,48 @@ impl InetAddress {
0x0a => IpScope::Private, // 10.0.0.0/8
0x7f => IpScope::Loopback, // 127.0.0.0/8
0x64 => {
if (ip & 0xffc00000) == 0x64400000 { // 100.64.0.0/10
if (ip & 0xffc00000) == 0x64400000 {
// 100.64.0.0/10
IpScope::Private
} else {
IpScope::Global
}
}
0xa9 => {
if (ip & 0xffff0000) == 0xa9fe0000 { // 169.254.0.0/16
if (ip & 0xffff0000) == 0xa9fe0000 {
// 169.254.0.0/16
IpScope::LinkLocal
} else {
IpScope::Global
}
}
0xac => {
if (ip & 0xfff00000) == 0xac100000 { // 172.16.0.0/12
if (ip & 0xfff00000) == 0xac100000 {
// 172.16.0.0/12
IpScope::Private
} else {
IpScope::Global
}
}
0xc0 => {
if (ip & 0xffff0000) == 0xc0a80000 || (ip & 0xffffff00) == 0xc0000200 { // 192.168.0.0/16 and 192.0.2.0/24
if (ip & 0xffff0000) == 0xc0a80000 || (ip & 0xffffff00) == 0xc0000200 {
// 192.168.0.0/16 and 192.0.2.0/24
IpScope::Private
} else {
IpScope::Global
}
}
0xc6 => {
if (ip & 0xfffe0000) == 0xc6120000 || (ip & 0xffffff00) == 0xc6336400 { // 198.18.0.0/15 and 198.51.100.0/24
if (ip & 0xfffe0000) == 0xc6120000 || (ip & 0xffffff00) == 0xc6336400 {
// 198.18.0.0/15 and 198.51.100.0/24
IpScope::Private
} else {
IpScope::Global
}
}
0xcb => {
if (ip & 0xffffff00) == 0xcb007100 { // 203.0.113.0/24
if (ip & 0xffffff00) == 0xcb007100 {
// 203.0.113.0/24
IpScope::Private
} else {
IpScope::Global
@ -310,13 +340,15 @@ impl InetAddress {
0x33_u8, // 51.0.0.0/8 (UK Department of Social Security)
0x37_u8, // 55.0.0.0/8 (US DoD)
0x38_u8, // 56.0.0.0/8 (US Postal Service)
].contains(&class_a) {
]
.contains(&class_a)
{
IpScope::PseudoPrivate
} else {
match ip >> 28 {
0xe => IpScope::Multicast, // 224.0.0.0/4
0xf => IpScope::Private, // 240.0.0.0/4 ("reserved," usually unusable)
_ => IpScope::Global
_ => IpScope::Global,
}
}
}
@ -356,7 +388,7 @@ impl InetAddress {
}
IpScope::Global
}
_ => IpScope::None
_ => IpScope::None,
}
}
}
@ -370,7 +402,7 @@ impl InetAddress {
format!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3])
}
AF_INET6 => Ipv6Addr::from(*(&(self.sin6.sin6_addr) as *const in6_addr).cast::<[u8; 16]>()).to_string(),
_ => String::from("(null)")
_ => String::from("(null)"),
}
}
}
@ -394,7 +426,7 @@ impl InetAddress {
b[18] = *(&self.sin6.sin6_port as *const u16).cast::<u8>().offset(1);
Ok(())
}
_ => buf.append_u8(0)
_ => buf.append_u8(0),
}
}
}
@ -438,33 +470,37 @@ impl FromStr for InetAddress {
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut addr = InetAddress::new();
let (ip_str, port) = s.find('/').map_or_else(|| {
(s, 0)
}, |pos| {
let ss = s.split_at(pos);
let mut port_str = ss.1;
if port_str.starts_with('/') {
port_str = &port_str[1..];
}
(ss.0, u16::from_str_radix(port_str, 10).unwrap_or(0).to_be())
});
IpAddr::from_str(ip_str).map_or_else(|_| Err(InvalidFormatError), |ip| {
unsafe {
match ip {
IpAddr::V4(v4) => {
addr.sin.sin_family = AF_INET.into();
addr.sin.sin_port = port.into();
copy_nonoverlapping(v4.octets().as_ptr(), (&mut (addr.sin.sin_addr.s_addr) as *mut u32).cast(), 4);
}
IpAddr::V6(v6) => {
addr.sin6.sin6_family = AF_INET6.into();
addr.sin6.sin6_port = port.into();
copy_nonoverlapping(v6.octets().as_ptr(), (&mut (addr.sin6.sin6_addr) as *mut in6_addr).cast(), 16);
let (ip_str, port) = s.find('/').map_or_else(
|| (s, 0),
|pos| {
let ss = s.split_at(pos);
let mut port_str = ss.1;
if port_str.starts_with('/') {
port_str = &port_str[1..];
}
(ss.0, u16::from_str_radix(port_str, 10).unwrap_or(0).to_be())
},
);
IpAddr::from_str(ip_str).map_or_else(
|_| Err(InvalidFormatError),
|ip| {
unsafe {
match ip {
IpAddr::V4(v4) => {
addr.sin.sin_family = AF_INET.into();
addr.sin.sin_port = port.into();
copy_nonoverlapping(v4.octets().as_ptr(), (&mut (addr.sin.sin_addr.s_addr) as *mut u32).cast(), 4);
}
IpAddr::V6(v6) => {
addr.sin6.sin6_family = AF_INET6.into();
addr.sin6.sin6_port = port.into();
copy_nonoverlapping(v6.octets().as_ptr(), (&mut (addr.sin6.sin6_addr) as *mut in6_addr).cast(), 16);
}
}
}
}
Ok(addr)
})
Ok(addr)
},
)
}
}
@ -473,7 +509,7 @@ impl PartialEq for InetAddress {
unsafe {
if self.sa.sa_family == other.sa.sa_family {
match self.sa.sa_family as u8 {
AF_INET => { self.sin.sin_port == other.sin.sin_port && self.sin.sin_addr.s_addr == other.sin.sin_addr.s_addr }
AF_INET => self.sin.sin_port == other.sin.sin_port && self.sin.sin_addr.s_addr == other.sin.sin_addr.s_addr,
AF_INET6 => {
if self.sin6.sin6_port == other.sin6.sin6_port {
(*(&(self.sin6.sin6_addr) as *const in6_addr).cast::<[u8; 16]>()).eq(&*(&(other.sin6.sin6_addr) as *const in6_addr).cast::<[u8; 16]>())
@ -481,7 +517,7 @@ impl PartialEq for InetAddress {
false
}
}
_ => true
_ => true,
}
} else {
false
@ -494,7 +530,9 @@ impl Eq for InetAddress {}
impl PartialOrd for InetAddress {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
// Manually implement Ord to ensure consistent sort order across platforms, since we don't know exactly
@ -504,9 +542,7 @@ impl Ord for InetAddress {
unsafe {
if self.sa.sa_family == other.sa.sa_family {
match self.sa.sa_family as u8 {
0 => {
Ordering::Equal
}
0 => Ordering::Equal,
AF_INET => {
let ip_ordering = u32::from_be(self.sin.sin_addr.s_addr as u32).cmp(&u32::from_be(other.sin.sin_addr.s_addr as u32));
if ip_ordering == Ordering::Equal {
@ -532,9 +568,7 @@ impl Ord for InetAddress {
}
} else {
match self.sa.sa_family as u8 {
0 => {
Ordering::Less
}
0 => Ordering::Less,
AF_INET => {
if other.sa.sa_family as u8 == AF_INET6 {
Ordering::Less

View file

@ -9,8 +9,8 @@
use std::convert::TryInto;
use std::mem::MaybeUninit;
use std::num::NonZeroI64;
use std::sync::Arc;
use std::sync::atomic::{AtomicI64, AtomicU64, AtomicU8, Ordering};
use std::sync::Arc;
use parking_lot::Mutex;
@ -22,15 +22,15 @@ use zerotier_core_crypto::random::{fill_bytes_secure, get_bytes_secure, next_u64
use zerotier_core_crypto::salsa::Salsa;
use zerotier_core_crypto::secret::Secret;
use crate::{PacketBuffer, VERSION_MAJOR, VERSION_MINOR, VERSION_PROTO, VERSION_REVISION};
use crate::util::{array_range, u64_as_bytes};
use crate::util::buffer::Buffer;
use crate::vl1::{Dictionary, Endpoint, Identity, InetAddress, Path};
use crate::util::{array_range, u64_as_bytes};
use crate::vl1::hybridkey::{HybridKeyPair, HybridPublicKey};
use crate::vl1::identity::{IDENTITY_ALGORITHM_ALL, IDENTITY_ALGORITHM_X25519};
use crate::vl1::node::*;
use crate::vl1::protocol::*;
use crate::vl1::symmetricsecret::{EphemeralSymmetricSecret, SymmetricSecret};
use crate::vl1::{Dictionary, Endpoint, Identity, InetAddress, Path};
use crate::{PacketBuffer, VERSION_MAJOR, VERSION_MINOR, VERSION_PROTO, VERSION_REVISION};
/// A remote peer known to this node.
/// Sending-related and receiving-related fields are locked separately since concurrent
@ -140,10 +140,12 @@ fn try_aead_decrypt(secret: &SymmetricSecret, packet_frag0_payload_bytes: &[u8],
poly.update(packet_frag0_payload_bytes);
let _ = payload.append_bytes_get_mut(packet_frag0_payload_bytes.len()).map(|b| salsa.crypt(packet_frag0_payload_bytes, b));
for f in fragments.iter() {
let _ = f.as_ref().map(|f| f.as_bytes_starting_at(FRAGMENT_HEADER_SIZE).map(|f| {
poly.update(f);
let _ = payload.append_bytes_get_mut(f.len()).map(|b| salsa.crypt(f, b));
}));
let _ = f.as_ref().map(|f| {
f.as_bytes_starting_at(FRAGMENT_HEADER_SIZE).map(|f| {
poly.update(f);
let _ = payload.append_bytes_get_mut(f.len()).map(|b| salsa.crypt(f, b));
})
});
}
if poly.finish()[0..8].eq(&header.mac) {
Some(u64::from_ne_bytes(header.id))
@ -211,24 +213,15 @@ impl Peer {
/// Get the next message ID for sending a message to this peer.
#[inline(always)]
pub(crate) fn next_message_id(&self) -> u64 { self.message_id_counter.fetch_add(1, Ordering::Relaxed) }
pub(crate) fn next_message_id(&self) -> u64 {
self.message_id_counter.fetch_add(1, Ordering::Relaxed)
}
/// Receive, decrypt, authenticate, and process an incoming packet from this peer.
///
/// If the packet comes in multiple fragments, the fragments slice should contain all
/// those fragments after the main packet header and first chunk.
pub(crate) fn receive<SI: SystemInterface, VI: VL1VirtualInterface>(
&self,
node: &Node,
si: &SI,
vi: &VI,
time_ticks: i64,
source_endpoint: &Endpoint,
source_path: &Arc<Path>,
header: &PacketHeader,
frag0: &Buffer<{ PACKET_SIZE_MAX }>,
fragments: &[Option<PacketBuffer>])
{
pub(crate) fn receive<SI: SystemInterface, VI: VL1VirtualInterface>(&self, node: &Node, si: &SI, vi: &VI, time_ticks: i64, source_endpoint: &Endpoint, source_path: &Arc<Path>, header: &PacketHeader, frag0: &Buffer<{ PACKET_SIZE_MAX }>, fragments: &[Option<PacketBuffer>]) {
let _ = frag0.as_bytes_starting_at(PACKET_VERB_INDEX).map(|packet_frag0_payload_bytes| {
let mut payload: Buffer<PACKET_SIZE_MAX> = unsafe { Buffer::new_without_memzero() };
@ -313,10 +306,11 @@ impl Peer {
}
} else {
// In debug build check to make sure the next layer (VL2) is complying with the API contract.
#[cfg(debug)] {
#[cfg(debug)]
{
if match verb {
VERB_VL1_NOP | VERB_VL1_HELLO | VERB_VL1_ERROR | VERB_VL1_OK | VERB_VL1_WHOIS | VERB_VL1_RENDEZVOUS | VERB_VL1_ECHO | VERB_VL1_PUSH_DIRECT_PATHS | VERB_VL1_USER_MESSAGE => true,
_ => false
_ => false,
} {
panic!("The next layer handled a VL1 packet! It should not do this.");
}
@ -419,14 +413,15 @@ impl Peer {
/// static identity key.
pub(crate) fn send_hello<SI: SystemInterface>(&self, si: &SI, node: &Node, explicit_endpoint: Option<&Endpoint>) -> bool {
let mut path = None;
let destination = explicit_endpoint.map_or_else(|| {
self.path(node).map_or(None, |p| {
path = Some(p.clone());
Some(p.endpoint().as_ref().clone())
})
}, |endpoint| {
Some(endpoint.clone())
});
let destination = explicit_endpoint.map_or_else(
|| {
self.path(node).map_or(None, |p| {
path = Some(p.clone());
Some(p.endpoint().as_ref().clone())
})
},
|endpoint| Some(endpoint.clone()),
);
if destination.is_none() {
return false;
}
@ -519,16 +514,17 @@ impl Peer {
self.last_send_time_ticks.store(time_ticks, Ordering::Relaxed);
self.total_bytes_sent.fetch_add(packet.len() as u64, Ordering::Relaxed);
path.map_or_else(|| {
self.send_to_endpoint(si, &destination, None, None, &packet)
}, |p| {
if self.send_to_endpoint(si, &destination, p.local_socket(), p.local_interface(), &packet) {
p.log_send_anything(time_ticks);
true
} else {
false
}
})
path.map_or_else(
|| self.send_to_endpoint(si, &destination, None, None, &packet),
|p| {
if self.send_to_endpoint(si, &destination, p.local_socket(), p.local_interface(), &packet) {
p.log_send_anything(time_ticks);
true
} else {
false
}
},
)
}
pub(crate) const CALL_EVERY_INTERVAL_MS: i64 = EPHEMERAL_SECRET_REKEY_AFTER_TIME / 10;