mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-05-07 06:03:43 +02:00
Formatting.
This commit is contained in:
parent
bcfd35a1f7
commit
d2e19c889f
19 changed files with 210 additions and 239 deletions
|
@ -66,6 +66,8 @@ NOP, as the name suggests, does nothing. Any payload is ignored.
|
||||||
| [2] u16 | Length of encrypted Dictionary in bytes |
|
| [2] u16 | Length of encrypted Dictionary in bytes |
|
||||||
| Dictionary | Key/value dictionary containing additional fields |
|
| Dictionary | Key/value dictionary containing additional fields |
|
||||||
| -- | -- END of AES-256-CTR encrypted section -- |
|
| -- | -- END of AES-256-CTR encrypted section -- |
|
||||||
|
| [2] u16 | Length of unencrypted Dictionary in bytes |
|
||||||
|
| Dictionary | Unencrypted dictionary (not currently used) |
|
||||||
|
|
||||||
HELLO establishes a full session with another peer and carries information such as protocol and software versions, the full identity of the peer, and ephemeral keys for forward secrecy. Without a HELLO exchange only limited communication with the most conservative assumptions is possible, and communication without a session may be completely removed in the future. (It's only allowed now for backward compatibility with ZeroTier 1.x, and must be disabled in FIPS mode.)
|
HELLO establishes a full session with another peer and carries information such as protocol and software versions, the full identity of the peer, and ephemeral keys for forward secrecy. Without a HELLO exchange only limited communication with the most conservative assumptions is possible, and communication without a session may be completely removed in the future. (It's only allowed now for backward compatibility with ZeroTier 1.x, and must be disabled in FIPS mode.)
|
||||||
|
|
||||||
|
@ -91,7 +93,7 @@ OK(HELLO) response payload, which must be sent if the HELLO receipient wishes to
|
||||||
| [2] u16 | Length of encrypted Dictionary in bytes |
|
| [2] u16 | Length of encrypted Dictionary in bytes |
|
||||||
| Dictionary | Key/value dictionary containing additional fields |
|
| Dictionary | Key/value dictionary containing additional fields |
|
||||||
|
|
||||||
Recommended dictionary fields in both HELLO and OK(HELLO):
|
The unencrypted dictionary is not currently used. The encrypted dictionary can contain the following fields in both HELLO and OK(HELLO):
|
||||||
|
|
||||||
| Name | Key | Type | Description |
|
| Name | Key | Type | Description |
|
||||||
| -------------------- | --- | ------------ | ------------------------------------------------ |
|
| -------------------- | --- | ------------ | ------------------------------------------------ |
|
||||||
|
@ -120,7 +122,7 @@ Optional dictionary fields that can be included in either HELLO or OK(HELLO):
|
||||||
| VENDOR | `V` | string | Node software vendor if not ZeroTier, Inc. |
|
| VENDOR | `V` | string | Node software vendor if not ZeroTier, Inc. |
|
||||||
| FLAGS | `+` | string | Flags (see below) |
|
| FLAGS | `+` | string | Flags (see below) |
|
||||||
|
|
||||||
FLAGS is a string that can contain the following boolean flags: `F` to indicate that the node is running in FIPS compliant mode, and `w` to indicate that the node is a "wimp." "Wimpy" nodes are things like mobile phones, and this flag can be used to exempt these devices from selection for any intensive role (such as use in VL2 to propagate multicasts).
|
FLAGS is a string that can contain the following boolean flags: `F` to indicate that the node is running in FIPS compliant mode.
|
||||||
|
|
||||||
System information such as OS_NAME is currently only sent to roots and not to any other node. This allows roots to collect a bit of very generic statistical and diagnostic telemtry about the nodes using them.
|
System information such as OS_NAME is currently only sent to roots and not to any other node. This allows roots to collect a bit of very generic statistical and diagnostic telemtry about the nodes using them.
|
||||||
|
|
||||||
|
|
|
@ -38,14 +38,10 @@ impl C25519KeyPair {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn public_bytes(&self) -> [u8; C25519_PUBLIC_KEY_SIZE] {
|
pub fn public_bytes(&self) -> [u8; C25519_PUBLIC_KEY_SIZE] { self.1.to_bytes() }
|
||||||
self.1.to_bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn secret_bytes(&self) -> Secret<{ C25519_SECRET_KEY_SIZE }> {
|
pub fn secret_bytes(&self) -> Secret<{ C25519_SECRET_KEY_SIZE }> { Secret(self.0.to_bytes()) }
|
||||||
Secret(self.0.to_bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Execute ECDH agreement and return a raw (un-hashed) shared secret key.
|
/// Execute ECDH agreement and return a raw (un-hashed) shared secret key.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -86,14 +82,10 @@ impl Ed25519KeyPair {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn public_bytes(&self) -> [u8; ED25519_PUBLIC_KEY_SIZE] {
|
pub fn public_bytes(&self) -> [u8; ED25519_PUBLIC_KEY_SIZE] { self.0.public.to_bytes() }
|
||||||
self.0.public.to_bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn secret_bytes(&self) -> Secret<{ ED25519_SECRET_KEY_SIZE }> {
|
pub fn secret_bytes(&self) -> Secret<{ ED25519_SECRET_KEY_SIZE }> { Secret(self.0.secret.to_bytes()) }
|
||||||
Secret(self.0.secret.to_bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn sign(&self, msg: &[u8]) -> [u8; ED25519_SIGNATURE_SIZE] {
|
pub fn sign(&self, msg: &[u8]) -> [u8; ED25519_SIGNATURE_SIZE] {
|
||||||
|
|
|
@ -26,19 +26,13 @@ impl SHA512 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Self(gcrypt::digest::MessageDigest::new(gcrypt::digest::Algorithm::Sha512).unwrap()) }
|
||||||
Self(gcrypt::digest::MessageDigest::new(gcrypt::digest::Algorithm::Sha512).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) { self.0.reset(); }
|
||||||
self.0.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn update(&mut self, b: &[u8]) {
|
pub fn update(&mut self, b: &[u8]) { self.0.update(b); }
|
||||||
self.0.update(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn finish(&mut self) -> [u8; SHA512_HASH_SIZE] {
|
pub fn finish(&mut self) -> [u8; SHA512_HASH_SIZE] {
|
||||||
|
@ -87,19 +81,13 @@ impl SHA384 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Self(gcrypt::digest::MessageDigest::new(gcrypt::digest::Algorithm::Sha384).unwrap()) }
|
||||||
Self(gcrypt::digest::MessageDigest::new(gcrypt::digest::Algorithm::Sha384).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) { self.0.reset(); }
|
||||||
self.0.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn update(&mut self, b: &[u8]) {
|
pub fn update(&mut self, b: &[u8]) { self.0.update(b); }
|
||||||
self.0.update(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn finish(&mut self) -> [u8; SHA384_HASH_SIZE] {
|
pub fn finish(&mut self) -> [u8; SHA384_HASH_SIZE] {
|
||||||
|
|
|
@ -130,23 +130,17 @@ impl P521KeyPair {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn public_key(&self) -> &P521PublicKey {
|
pub fn public_key(&self) -> &P521PublicKey { &self.public_key }
|
||||||
&self.public_key
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the raw ECC public "q" point for this key pair.
|
/// Get the raw ECC public "q" point for this key pair.
|
||||||
/// The returned point is not compressed. To use this with other interfaces that expect a format
|
/// The returned point is not compressed. To use this with other interfaces that expect a format
|
||||||
/// prefix, prepend 0x04 to the beginning of this public key. This prefix is always the same in
|
/// prefix, prepend 0x04 to the beginning of this public key. This prefix is always the same in
|
||||||
/// our system and so is omitted.
|
/// our system and so is omitted.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn public_key_bytes(&self) -> &[u8; P521_PUBLIC_KEY_SIZE] {
|
pub fn public_key_bytes(&self) -> &[u8; P521_PUBLIC_KEY_SIZE] { &self.public_key.public_key_bytes }
|
||||||
&self.public_key.public_key_bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn secret_key_bytes(&self) -> &Secret<{ P521_SECRET_KEY_SIZE }> {
|
pub fn secret_key_bytes(&self) -> &Secret<{ P521_SECRET_KEY_SIZE }> { &self.secret_key_bytes }
|
||||||
&self.secret_key_bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an ECDSA signature of the input message.
|
/// Create an ECDSA signature of the input message.
|
||||||
/// Message data does not need to be pre-hashed.
|
/// Message data does not need to be pre-hashed.
|
||||||
|
@ -213,17 +207,13 @@ impl P521PublicKey {
|
||||||
|
|
||||||
impl PartialEq for P521PublicKey {
|
impl PartialEq for P521PublicKey {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool { self.public_key_bytes.eq(&other.public_key_bytes) }
|
||||||
self.public_key_bytes.eq(&other.public_key_bytes)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for P521PublicKey {}
|
impl Eq for P521PublicKey {}
|
||||||
|
|
||||||
impl Clone for P521PublicKey {
|
impl Clone for P521PublicKey {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { P521PublicKey::from_bytes(&self.public_key_bytes).unwrap() }
|
||||||
P521PublicKey::from_bytes(&self.public_key_bytes).unwrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -16,34 +16,21 @@ pub struct Secret<const L: usize>(pub(crate) [u8; L]);
|
||||||
|
|
||||||
impl<const L: usize> Secret<L> {
|
impl<const L: usize> Secret<L> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Self([0_u8; L]) }
|
||||||
Self([0_u8; L])
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Copy bytes into secret, will panic if size does not match.
|
/// Copy bytes into secret, will panic if size does not match.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn from_bytes(b: &[u8]) -> Self {
|
pub fn from_bytes(b: &[u8]) -> Self { Self(b.try_into().unwrap()) }
|
||||||
Self(b.try_into().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn as_bytes(&self) -> &[u8; L] {
|
pub fn as_bytes(&self) -> &[u8; L] { return &self.0 }
|
||||||
return &self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const L: usize> Drop for Secret<L> {
|
impl<const L: usize> Drop for Secret<L> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let p = self.0.as_mut_ptr();
|
|
||||||
if (L % size_of::<usize>()) == 0 {
|
|
||||||
for i in 0..(L / size_of::<usize>()) {
|
|
||||||
write_volatile(p.cast::<usize>().offset(i as isize), 0_usize);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i in 0..L {
|
for i in 0..L {
|
||||||
write_volatile(p.offset(i as isize), 0_u8);
|
write_volatile(self.0.as_mut_ptr().offset(i as isize), 0_u8);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,35 +38,25 @@ impl<const L: usize> Drop for Secret<L> {
|
||||||
|
|
||||||
impl<const L: usize> Default for Secret<L> {
|
impl<const L: usize> Default for Secret<L> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn default() -> Self {
|
fn default() -> Self { Self([0_u8; L]) }
|
||||||
Self([0_u8; L])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const L: usize> AsRef<[u8]> for Secret<L> {
|
impl<const L: usize> AsRef<[u8]> for Secret<L> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] { &self.0 }
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const L: usize> AsRef<[u8; L]> for Secret<L> {
|
impl<const L: usize> AsRef<[u8; L]> for Secret<L> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn as_ref(&self) -> &[u8; L] {
|
fn as_ref(&self) -> &[u8; L] { &self.0 }
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const L: usize> AsMut<[u8]> for Secret<L> {
|
impl<const L: usize> AsMut<[u8]> for Secret<L> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn as_mut(&mut self) -> &mut [u8] {
|
fn as_mut(&mut self) -> &mut [u8] { &mut self.0 }
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const L: usize> AsMut<[u8; L]> for Secret<L> {
|
impl<const L: usize> AsMut<[u8; L]> for Secret<L> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn as_mut(&mut self) -> &mut [u8; L] {
|
fn as_mut(&mut self) -> &mut [u8; L] { &mut self.0 }
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,10 @@ pub struct Address(NonZeroU64);
|
||||||
impl Address {
|
impl Address {
|
||||||
/// Get an address from a 64-bit integer or return None if it is zero or reserved.
|
/// Get an address from a 64-bit integer or return None if it is zero or reserved.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn from_u64(i: u64) -> Option<Address> {
|
pub fn from_u64(mut i: u64) -> Option<Address> {
|
||||||
|
i &= 0xffffffffff;
|
||||||
if i != 0 && (i >> 32) != ADDRESS_RESERVED_PREFIX as u64 {
|
if i != 0 && (i >> 32) != ADDRESS_RESERVED_PREFIX as u64 {
|
||||||
Some(Address(unsafe { NonZeroU64::new_unchecked(i & 0xffffffffff) }))
|
Some(Address(unsafe { NonZeroU64::new_unchecked(i) }))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,14 @@ impl<const L: usize> Buffer<L> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn is_empty(&self) -> bool { self.0 == 0 }
|
pub fn is_empty(&self) -> bool { self.0 == 0 }
|
||||||
|
|
||||||
|
/// Set the size of this buffer's data.
|
||||||
|
///
|
||||||
|
/// This is marked unsafe because no bounds checking is done here and because it
|
||||||
|
/// technically violates the assurance that all data in the buffer is valid. Use
|
||||||
|
/// with care.
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn set_size(&mut self, s: usize) { self.0 = s; }
|
||||||
|
|
||||||
/// Append a packed structure and call a function to initialize it in place.
|
/// Append a packed structure and call a function to initialize it in place.
|
||||||
/// Anything not initialized will be zero.
|
/// Anything not initialized will be zero.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -305,7 +313,7 @@ impl<const L: usize> Buffer<L> {
|
||||||
loop {
|
loop {
|
||||||
let b = self.read_u8(cursor)?;
|
let b = self.read_u8(cursor)?;
|
||||||
if (b & 0x80) == 0 {
|
if (b & 0x80) == 0 {
|
||||||
i |= (b as u64) << p;
|
i |= (b as u64).wrapping_shl(p);
|
||||||
p += 7;
|
p += 7;
|
||||||
} else {
|
} else {
|
||||||
i |= ((b & 0x7f) as u64) << p;
|
i |= ((b & 0x7f) as u64) << p;
|
||||||
|
|
|
@ -47,9 +47,7 @@ pub enum Endpoint {
|
||||||
|
|
||||||
impl Default for Endpoint {
|
impl Default for Endpoint {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn default() -> Endpoint {
|
fn default() -> Endpoint { Endpoint::Nil }
|
||||||
Endpoint::Nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Endpoint {
|
impl Endpoint {
|
||||||
|
|
|
@ -6,6 +6,8 @@ use std::io::Write;
|
||||||
use std::ptr::{slice_from_raw_parts, slice_from_raw_parts_mut};
|
use std::ptr::{slice_from_raw_parts, slice_from_raw_parts_mut};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use concat_arrays::concat_arrays;
|
||||||
|
|
||||||
use crate::crypto::balloon;
|
use crate::crypto::balloon;
|
||||||
use crate::crypto::c25519::*;
|
use crate::crypto::c25519::*;
|
||||||
use crate::crypto::hash::*;
|
use crate::crypto::hash::*;
|
||||||
|
@ -17,12 +19,12 @@ use crate::vl1::Address;
|
||||||
use crate::vl1::buffer::Buffer;
|
use crate::vl1::buffer::Buffer;
|
||||||
use crate::vl1::protocol::PACKET_SIZE_MAX;
|
use crate::vl1::protocol::PACKET_SIZE_MAX;
|
||||||
|
|
||||||
use concat_arrays::concat_arrays;
|
pub const IDENTITY_TYPE_0_SIGNATURE_SIZE: usize = 96;
|
||||||
|
pub const IDENTITY_TYPE_1_SIGNATURE_SIZE: usize = P521_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE;
|
||||||
|
|
||||||
// Memory parameter for V0 address derivation work function.
|
const V0_POW_MEMORY: usize = 2097152;
|
||||||
const V0_IDENTITY_GEN_MEMORY: usize = 2097152;
|
const V0_POW_THRESHOLD: u8 = 17;
|
||||||
|
const V1_POW_THRESHOLD: u8 = 5;
|
||||||
// Balloon hash parameters for V1 address derivation work function.
|
|
||||||
const V1_BALLOON_SPACE_COST: usize = 16384;
|
const V1_BALLOON_SPACE_COST: usize = 16384;
|
||||||
const V1_BALLOON_TIME_COST: usize = 3;
|
const V1_BALLOON_TIME_COST: usize = 3;
|
||||||
const V1_BALLOON_DELTA: usize = 3;
|
const V1_BALLOON_DELTA: usize = 3;
|
||||||
|
@ -30,12 +32,6 @@ const V1_BALLOON_SALT: &'static [u8] = b"zt_id_v1";
|
||||||
|
|
||||||
const V1_PUBLIC_KEYS_SIGNATURE_AND_POW_SIZE: usize = C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_ECDSA_SIGNATURE_SIZE + SHA384_HASH_SIZE;
|
const V1_PUBLIC_KEYS_SIGNATURE_AND_POW_SIZE: usize = C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_ECDSA_SIGNATURE_SIZE + SHA384_HASH_SIZE;
|
||||||
|
|
||||||
pub const IDENTITY_TYPE_0_SIGNATURE_SIZE: usize = 96;
|
|
||||||
pub const IDENTITY_TYPE_1_SIGNATURE_SIZE: usize = P521_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE;
|
|
||||||
|
|
||||||
const IDENTITY_V0_POW_THRESHOLD: u8 = 17;
|
|
||||||
const IDENTITY_V1_POW_THRESHOLD: u8 = 5;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
|
@ -62,24 +58,24 @@ pub struct Identity {
|
||||||
/// Compute result from the bespoke "frankenhash" from the old V0 work function.
|
/// Compute result from the bespoke "frankenhash" from the old V0 work function.
|
||||||
/// The supplied genmem_ptr must be of size V0_IDENTITY_GEN_MEMORY and aligned to an 8-byte boundary.
|
/// The supplied genmem_ptr must be of size V0_IDENTITY_GEN_MEMORY and aligned to an 8-byte boundary.
|
||||||
fn v0_frankenhash(digest: &mut [u8; 64], genmem_ptr: *mut u8) {
|
fn v0_frankenhash(digest: &mut [u8; 64], genmem_ptr: *mut u8) {
|
||||||
let (genmem, genmem_alias_hack) = unsafe { (&mut *slice_from_raw_parts_mut(genmem_ptr, V0_IDENTITY_GEN_MEMORY), &*slice_from_raw_parts(genmem_ptr, V0_IDENTITY_GEN_MEMORY)) };
|
let (genmem, genmem_alias_hack) = unsafe { (&mut *slice_from_raw_parts_mut(genmem_ptr, V0_POW_MEMORY), &*slice_from_raw_parts(genmem_ptr, V0_POW_MEMORY)) };
|
||||||
let genmem_u64_ptr = genmem_ptr.cast::<u64>();
|
let genmem_u64_ptr = genmem_ptr.cast::<u64>();
|
||||||
|
|
||||||
let mut s20 = Salsa::new(&digest[0..32], &digest[32..40], false).unwrap();
|
let mut s20 = Salsa::new(&digest[0..32], &digest[32..40], false).unwrap();
|
||||||
|
|
||||||
s20.crypt(&crate::util::ZEROES[0..64], &mut genmem[0..64]);
|
s20.crypt(&crate::util::ZEROES[0..64], &mut genmem[0..64]);
|
||||||
let mut i: usize = 64;
|
let mut i: usize = 64;
|
||||||
while i < V0_IDENTITY_GEN_MEMORY {
|
while i < V0_POW_MEMORY {
|
||||||
let ii = i + 64;
|
let ii = i + 64;
|
||||||
s20.crypt(&genmem_alias_hack[(i - 64)..i], &mut genmem[i..ii]);
|
s20.crypt(&genmem_alias_hack[(i - 64)..i], &mut genmem[i..ii]);
|
||||||
i = ii;
|
i = ii;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while i < (V0_IDENTITY_GEN_MEMORY / 8) {
|
while i < (V0_POW_MEMORY / 8) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let idx1 = (((*genmem_u64_ptr.offset(i as isize)).to_be() % 8) * 8) as usize;
|
let idx1 = (((*genmem_u64_ptr.offset(i as isize)).to_be() % 8) * 8) as usize;
|
||||||
let idx2 = ((*genmem_u64_ptr.offset((i + 1) as isize)).to_be() % (V0_IDENTITY_GEN_MEMORY as u64 / 8)) as usize;
|
let idx2 = ((*genmem_u64_ptr.offset((i + 1) as isize)).to_be() % (V0_POW_MEMORY as u64 / 8)) as usize;
|
||||||
let genmem_u64_at_idx2_ptr = genmem_u64_ptr.offset(idx2 as isize);
|
let genmem_u64_at_idx2_ptr = genmem_u64_ptr.offset(idx2 as isize);
|
||||||
let tmp = *genmem_u64_at_idx2_ptr;
|
let tmp = *genmem_u64_at_idx2_ptr;
|
||||||
let digest_u64_ptr = digest.as_mut_ptr().offset(idx1 as isize).cast::<u64>();
|
let digest_u64_ptr = digest.as_mut_ptr().offset(idx1 as isize).cast::<u64>();
|
||||||
|
@ -93,7 +89,7 @@ fn v0_frankenhash(digest: &mut [u8; 64], genmem_ptr: *mut u8) {
|
||||||
|
|
||||||
impl Identity {
|
impl Identity {
|
||||||
fn generate_c25519() -> Identity {
|
fn generate_c25519() -> Identity {
|
||||||
let genmem_layout = Layout::from_size_align(V0_IDENTITY_GEN_MEMORY, 8).unwrap();
|
let genmem_layout = Layout::from_size_align(V0_POW_MEMORY, 8).unwrap();
|
||||||
let genmem_ptr = unsafe { alloc(genmem_layout) };
|
let genmem_ptr = unsafe { alloc(genmem_layout) };
|
||||||
if genmem_ptr.is_null() {
|
if genmem_ptr.is_null() {
|
||||||
panic!("unable to allocate memory for V0 identity generation");
|
panic!("unable to allocate memory for V0 identity generation");
|
||||||
|
@ -111,7 +107,7 @@ impl Identity {
|
||||||
let mut digest = sha.finish();
|
let mut digest = sha.finish();
|
||||||
|
|
||||||
v0_frankenhash(&mut digest, genmem_ptr);
|
v0_frankenhash(&mut digest, genmem_ptr);
|
||||||
if digest[0] < IDENTITY_V0_POW_THRESHOLD {
|
if digest[0] < V0_POW_THRESHOLD {
|
||||||
let addr = Address::from_bytes(&digest[59..64]);
|
let addr = Address::from_bytes(&digest[59..64]);
|
||||||
if addr.is_some() {
|
if addr.is_some() {
|
||||||
unsafe { dealloc(genmem_ptr, genmem_layout) };
|
unsafe { dealloc(genmem_ptr, genmem_layout) };
|
||||||
|
@ -145,7 +141,7 @@ impl Identity {
|
||||||
// ECDSA is a randomized signature algorithm, so each signature will be different.
|
// ECDSA is a randomized signature algorithm, so each signature will be different.
|
||||||
let sig = p521_ecdsa.sign(&sign_buf).unwrap();
|
let sig = p521_ecdsa.sign(&sign_buf).unwrap();
|
||||||
let bh = balloon::hash::<{ V1_BALLOON_SPACE_COST }, { V1_BALLOON_TIME_COST }, { V1_BALLOON_DELTA }>(&sig, V1_BALLOON_SALT);
|
let bh = balloon::hash::<{ V1_BALLOON_SPACE_COST }, { V1_BALLOON_TIME_COST }, { V1_BALLOON_DELTA }>(&sig, V1_BALLOON_SALT);
|
||||||
if bh[0] < IDENTITY_V1_POW_THRESHOLD {
|
if bh[0] < V1_POW_THRESHOLD {
|
||||||
let addr = Address::from_bytes(&bh[43..48]);
|
let addr = Address::from_bytes(&bh[43..48]);
|
||||||
if addr.is_some() {
|
if addr.is_some() {
|
||||||
let p521_ecdh_pub = p521_ecdh.public_key().clone();
|
let p521_ecdh_pub = p521_ecdh.public_key().clone();
|
||||||
|
@ -210,7 +206,7 @@ impl Identity {
|
||||||
/// to fully validate than V1 identities.
|
/// to fully validate than V1 identities.
|
||||||
pub fn locally_validate(&self) -> bool {
|
pub fn locally_validate(&self) -> bool {
|
||||||
if self.v1.is_none() {
|
if self.v1.is_none() {
|
||||||
let genmem_layout = Layout::from_size_align(V0_IDENTITY_GEN_MEMORY, 8).unwrap();
|
let genmem_layout = Layout::from_size_align(V0_POW_MEMORY, 8).unwrap();
|
||||||
let genmem_ptr = unsafe { alloc(genmem_layout) };
|
let genmem_ptr = unsafe { alloc(genmem_layout) };
|
||||||
if !genmem_ptr.is_null() {
|
if !genmem_ptr.is_null() {
|
||||||
let mut sha = SHA512::new();
|
let mut sha = SHA512::new();
|
||||||
|
@ -219,7 +215,7 @@ impl Identity {
|
||||||
let mut digest = sha.finish();
|
let mut digest = sha.finish();
|
||||||
v0_frankenhash(&mut digest, genmem_ptr);
|
v0_frankenhash(&mut digest, genmem_ptr);
|
||||||
unsafe { dealloc(genmem_ptr, genmem_layout) };
|
unsafe { dealloc(genmem_ptr, genmem_layout) };
|
||||||
(digest[0] < IDENTITY_V0_POW_THRESHOLD) && Address::from_bytes(&digest[59..64]).unwrap().eq(&self.address)
|
(digest[0] < V0_POW_THRESHOLD) && Address::from_bytes(&digest[59..64]).unwrap().eq(&self.address)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -232,7 +228,7 @@ impl Identity {
|
||||||
signing_buf[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)].copy_from_slice((*p521).1.public_key_bytes());
|
signing_buf[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)].copy_from_slice((*p521).1.public_key_bytes());
|
||||||
if (*p521).1.verify(&signing_buf, &(*p521).2) {
|
if (*p521).1.verify(&signing_buf, &(*p521).2) {
|
||||||
let bh = balloon::hash::<{ V1_BALLOON_SPACE_COST }, { V1_BALLOON_TIME_COST }, { V1_BALLOON_DELTA }>(&(*p521).2, V1_BALLOON_SALT);
|
let bh = balloon::hash::<{ V1_BALLOON_SPACE_COST }, { V1_BALLOON_TIME_COST }, { V1_BALLOON_DELTA }>(&(*p521).2, V1_BALLOON_SALT);
|
||||||
(bh[0] < IDENTITY_V1_POW_THRESHOLD) && bh.eq(&(*p521).3) && Address::from_bytes(&bh[43..48]).unwrap().eq(&self.address)
|
(bh[0] < V1_POW_THRESHOLD) && bh.eq(&(*p521).3) && Address::from_bytes(&bh[43..48]).unwrap().eq(&self.address)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -247,12 +243,8 @@ impl Identity {
|
||||||
pub fn agree(&self, other_identity: &Identity) -> Option<Secret<48>> {
|
pub fn agree(&self, other_identity: &Identity) -> Option<Secret<48>> {
|
||||||
self.secrets.as_ref().map_or(None, |secrets| {
|
self.secrets.as_ref().map_or(None, |secrets| {
|
||||||
let c25519_secret = || Secret::<48>(SHA384::hash(&secrets.c25519.agree(&other_identity.c25519).as_ref()));
|
let c25519_secret = || Secret::<48>(SHA384::hash(&secrets.c25519.agree(&other_identity.c25519).as_ref()));
|
||||||
secrets.v1.as_ref().map_or_else(|| {
|
secrets.v1.as_ref().map_or_else(|| Some(c25519_secret()), |p521_secret| {
|
||||||
Some(c25519_secret())
|
other_identity.v1.as_ref().map_or_else(|| Some(c25519_secret()), |other_p521_public| {
|
||||||
}, |p521_secret| {
|
|
||||||
other_identity.v1.as_ref().map_or_else(|| {
|
|
||||||
Some(c25519_secret())
|
|
||||||
}, |other_p521_public| {
|
|
||||||
p521_secret.0.agree(&other_p521_public.0).map_or(None, |p521_secret| {
|
p521_secret.0.agree(&other_p521_public.0).map_or(None, |p521_secret| {
|
||||||
//
|
//
|
||||||
// For NIST P-521 key agreement, we use a single step key derivation function to derive
|
// For NIST P-521 key agreement, we use a single step key derivation function to derive
|
||||||
|
@ -285,10 +277,7 @@ impl Identity {
|
||||||
pub fn sign(&self, msg: &[u8]) -> Option<Vec<u8>> {
|
pub fn sign(&self, msg: &[u8]) -> Option<Vec<u8>> {
|
||||||
self.secrets.as_ref().map_or(None, |secrets| {
|
self.secrets.as_ref().map_or(None, |secrets| {
|
||||||
let c25519_sig = secrets.ed25519.sign_zt(msg);
|
let c25519_sig = secrets.ed25519.sign_zt(msg);
|
||||||
secrets.v1.as_ref().map_or_else(|| {
|
secrets.v1.as_ref().map_or_else(|| Some(c25519_sig.to_vec()), |p521_secret| p521_secret.1.sign(msg).map_or(None, |p521_sig| {
|
||||||
Some(c25519_sig.to_vec())
|
|
||||||
}, |p521_secret| {
|
|
||||||
p521_secret.1.sign(msg).map_or(None, |p521_sig| {
|
|
||||||
//
|
//
|
||||||
// For type 1 identity signatures we sign with both algorithms and append the Ed25519
|
// For type 1 identity signatures we sign with both algorithms and append the Ed25519
|
||||||
// signature to the NIST P-521 signature. The Ed25519 signature is only checked if the
|
// signature to the NIST P-521 signature. The Ed25519 signature is only checked if the
|
||||||
|
@ -302,8 +291,7 @@ impl Identity {
|
||||||
let mut p521_sig = p521_sig.to_vec();
|
let mut p521_sig = p521_sig.to_vec();
|
||||||
let _ = p521_sig.write_all(&c25519_sig[0..64]);
|
let _ = p521_sig.write_all(&c25519_sig[0..64]);
|
||||||
Some(p521_sig)
|
Some(p521_sig)
|
||||||
})
|
}))
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,34 +300,20 @@ impl Identity {
|
||||||
self.v1.as_ref().map_or_else(|| {
|
self.v1.as_ref().map_or_else(|| {
|
||||||
crate::crypto::c25519::ed25519_verify(&self.ed25519, signature, msg)
|
crate::crypto::c25519::ed25519_verify(&self.ed25519, signature, msg)
|
||||||
}, |p521| {
|
}, |p521| {
|
||||||
if signature.len() == IDENTITY_TYPE_1_SIGNATURE_SIZE {
|
signature.len() == IDENTITY_TYPE_1_SIGNATURE_SIZE && (*p521).1.verify(msg, &signature[0..P521_ECDSA_SIGNATURE_SIZE]) && crate::crypto::c25519::ed25519_verify(&self.ed25519, &signature[P521_ECDSA_SIGNATURE_SIZE..], msg)
|
||||||
(*p521).1.verify(msg, &signature[0..P521_ECDSA_SIGNATURE_SIZE]) && crate::crypto::c25519::ed25519_verify(&self.ed25519, &signature[P521_ECDSA_SIGNATURE_SIZE..], msg)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get this identity's type.
|
/// Get this identity's type.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn id_type(&self) -> Type {
|
pub fn id_type(&self) -> Type { if self.v1.is_some() { Type::P521 } else { Type::C25519 } }
|
||||||
if self.v1.is_some() {
|
|
||||||
Type::P521
|
|
||||||
} else {
|
|
||||||
Type::C25519
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if this identity also holds its secret keys.
|
/// Returns true if this identity also holds its secret keys.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn has_secrets(&self) -> bool {
|
pub fn has_secrets(&self) -> bool { self.secrets.is_some() }
|
||||||
self.secrets.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Erase secrets from this identity object, if present.
|
/// Erase secrets from this identity object, if present.
|
||||||
pub fn forget_secrets(&mut self) {
|
pub fn forget_secrets(&mut self) { let _ = self.secrets.take(); }
|
||||||
let _ = self.secrets.take();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Append this in binary format to a buffer.
|
/// Append this in binary format to a buffer.
|
||||||
pub fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>, include_private: bool) -> std::io::Result<()> {
|
pub fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>, include_private: bool) -> std::io::Result<()> {
|
||||||
|
@ -598,9 +572,7 @@ impl Eq for Identity {}
|
||||||
|
|
||||||
impl PartialOrd for Identity {
|
impl PartialOrd for Identity {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for Identity {
|
impl Ord for Identity {
|
||||||
|
|
|
@ -348,12 +348,8 @@ impl InetAddress {
|
||||||
let ip = &*(&self.sin.sin_addr.s_addr as *const u32).cast::<[u8; 4]>();
|
let ip = &*(&self.sin.sin_addr.s_addr as *const u32).cast::<[u8; 4]>();
|
||||||
format!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3])
|
format!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3])
|
||||||
}
|
}
|
||||||
AF_INET6 => {
|
AF_INET6 => Ipv6Addr::from(*(&(self.sin6.sin6_addr) as *const in6_addr).cast::<[u8; 16]>()).to_string(),
|
||||||
Ipv6Addr::from(*(&(self.sin6.sin6_addr) as *const in6_addr).cast::<[u8; 16]>()).to_string()
|
_ => String::from("(null)")
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
String::from("(null)")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,9 +373,7 @@ impl InetAddress {
|
||||||
b[18] = *(&self.sin6.sin6_port as *const u16).cast::<u8>().offset(1);
|
b[18] = *(&self.sin6.sin6_port as *const u16).cast::<u8>().offset(1);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => {
|
_ => buf.append_u8(0)
|
||||||
buf.append_u8(0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,7 +449,6 @@ impl FromStr for InetAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for InetAddress {
|
impl PartialEq for InetAddress {
|
||||||
#[inline(always)]
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
if self.sa.sa_family == other.sa.sa_family {
|
if self.sa.sa_family == other.sa.sa_family {
|
||||||
|
|
|
@ -94,13 +94,13 @@ impl Locator {
|
||||||
self.subject.marshal(buf)?;
|
self.subject.marshal(buf)?;
|
||||||
self.signer.marshal(buf)?;
|
self.signer.marshal(buf)?;
|
||||||
buf.append_u64(self.timestamp as u64)?;
|
buf.append_u64(self.timestamp as u64)?;
|
||||||
buf.append_varint(self.endpoints.len() as u64);
|
buf.append_varint(self.endpoints.len() as u64)?;
|
||||||
for e in self.endpoints.iter() {
|
for e in self.endpoints.iter() {
|
||||||
e.marshal(buf)?;
|
e.marshal(buf)?;
|
||||||
}
|
}
|
||||||
buf.append_varint(0); // length of any additional fields
|
buf.append_varint(0)?; // length of any additional fields
|
||||||
if !exclude_signature {
|
if !exclude_signature {
|
||||||
buf.append_varint(self.signature.len() as u64);
|
buf.append_varint(self.signature.len() as u64)?;
|
||||||
buf.append_bytes(self.signature.as_slice())?;
|
buf.append_bytes(self.signature.as_slice())?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -11,23 +11,12 @@ pub struct MAC(NonZeroU64);
|
||||||
|
|
||||||
impl MAC {
|
impl MAC {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn from_u64(i: u64) -> Option<MAC> {
|
pub fn from_u64(i: u64) -> Option<MAC> { NonZeroU64::new(i & 0xffffffffffff).map_or(None, |i| Some(MAC(i))) }
|
||||||
if i != 0 {
|
|
||||||
Some(MAC(unsafe { NonZeroU64::new_unchecked(i & 0xffffffffffff) }))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn from_bytes(b: &[u8]) -> Option<MAC> {
|
pub fn from_bytes(b: &[u8]) -> Option<MAC> {
|
||||||
if b.len() >= 6 {
|
if b.len() >= 6 {
|
||||||
let i = (b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64;
|
NonZeroU64::new((b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64).map_or(None, |i| Some(MAC(i)))
|
||||||
if i != 0 {
|
|
||||||
Some(MAC(unsafe { NonZeroU64::new_unchecked(i) }))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ pub mod locator;
|
||||||
pub mod rootset;
|
pub mod rootset;
|
||||||
|
|
||||||
// These are either only used inside network-hypervisor or are selectively exported below.
|
// These are either only used inside network-hypervisor or are selectively exported below.
|
||||||
|
#[allow(unused)]
|
||||||
pub(crate) mod protocol;
|
pub(crate) mod protocol;
|
||||||
pub(crate) mod buffer;
|
pub(crate) mod buffer;
|
||||||
pub(crate) mod node;
|
pub(crate) mod node;
|
||||||
|
|
|
@ -86,6 +86,9 @@ pub trait VL1CallerInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait implemented by VL2 to handle messages after they are unwrapped by VL1.
|
/// Trait implemented by VL2 to handle messages after they are unwrapped by VL1.
|
||||||
|
///
|
||||||
|
/// This normally isn't used from outside this crate except for testing or if you want to harness VL1
|
||||||
|
/// for some entirely unrelated purpose.
|
||||||
pub trait VL1PacketHandler {
|
pub trait VL1PacketHandler {
|
||||||
/// Handle a packet, returning true if the verb was recognized.
|
/// Handle a packet, returning true if the verb was recognized.
|
||||||
///
|
///
|
||||||
|
@ -95,10 +98,10 @@ pub trait VL1PacketHandler {
|
||||||
fn handle_packet(&self, peer: &Peer, source_path: &Arc<Path>, forward_secrecy: bool, verb: u8, payload: &Buffer<{ PACKET_SIZE_MAX }>) -> bool;
|
fn handle_packet(&self, peer: &Peer, source_path: &Arc<Path>, forward_secrecy: bool, verb: u8, payload: &Buffer<{ PACKET_SIZE_MAX }>) -> bool;
|
||||||
|
|
||||||
/// Handle errors, returning true if the error was recognized.
|
/// Handle errors, returning true if the error was recognized.
|
||||||
fn handle_error(&self, peer: &Peer, source_path: &Arc<Path>, forward_secrecy: bool, in_re_verb: u8, in_re_packet_id: PacketID, error_code: u8, payload: &Buffer<{ PACKET_SIZE_MAX }>) -> bool;
|
fn handle_error(&self, peer: &Peer, source_path: &Arc<Path>, forward_secrecy: bool, in_re_verb: u8, in_re_packet_id: PacketID, error_code: u8, payload: &Buffer<{ PACKET_SIZE_MAX }>, cursor: &mut usize) -> bool;
|
||||||
|
|
||||||
/// Handle an OK, returing true if the OK was recognized.
|
/// Handle an OK, returing true if the OK was recognized.
|
||||||
fn handle_ok(&self, peer: &Peer, source_path: &Arc<Path>, forward_secrecy: bool, in_re_verb: u8, in_re_packet_id: PacketID, payload: &Buffer<{ PACKET_SIZE_MAX }>) -> bool;
|
fn handle_ok(&self, peer: &Peer, source_path: &Arc<Path>, forward_secrecy: bool, in_re_verb: u8, in_re_packet_id: PacketID, payload: &Buffer<{ PACKET_SIZE_MAX }>, cursor: &mut usize) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -120,8 +123,7 @@ pub struct Node {
|
||||||
whois: WhoisQueue,
|
whois: WhoisQueue,
|
||||||
buffer_pool: Pool<Buffer<{ PACKET_SIZE_MAX }>, PooledBufferFactory<{ PACKET_SIZE_MAX }>>,
|
buffer_pool: Pool<Buffer<{ PACKET_SIZE_MAX }>, PooledBufferFactory<{ PACKET_SIZE_MAX }>>,
|
||||||
secure_prng: SecureRandom,
|
secure_prng: SecureRandom,
|
||||||
pub(crate) fips_mode: bool,
|
fips_mode: bool,
|
||||||
pub(crate) wimp: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
|
@ -164,19 +166,15 @@ impl Node {
|
||||||
buffer_pool: Pool::new(64, PooledBufferFactory),
|
buffer_pool: Pool::new(64, PooledBufferFactory),
|
||||||
secure_prng: SecureRandom::get(),
|
secure_prng: SecureRandom::get(),
|
||||||
fips_mode: false,
|
fips_mode: false,
|
||||||
wimp: false,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get address, short for .identity().address()
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn address(&self) -> Address { self.identity.address() }
|
pub fn address(&self) -> Address { self.identity.address() }
|
||||||
|
|
||||||
/// Get identity, which includes secret keys.
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn identity(&self) -> &Identity { &self.identity }
|
pub fn identity(&self) -> &Identity { &self.identity }
|
||||||
|
|
||||||
/// Get this node's current locator or None if no locator created.
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn locator(&self) -> Option<Arc<Locator>> { self.locator.lock().clone() }
|
pub fn locator(&self) -> Option<Arc<Locator>> { self.locator.lock().clone() }
|
||||||
|
|
||||||
|
@ -187,6 +185,9 @@ impl Node {
|
||||||
/// Get a peer by address.
|
/// Get a peer by address.
|
||||||
pub fn peer(&self, a: Address) -> Option<Arc<Peer>> { self.peers.get(&a).map(|peer| peer.value().clone()) }
|
pub fn peer(&self, a: Address) -> Option<Arc<Peer>> { self.peers.get(&a).map(|peer| peer.value().clone()) }
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fips_mode(&self) -> bool { self.fips_mode }
|
||||||
|
|
||||||
/// Get all peers currently in the peer cache.
|
/// Get all peers currently in the peer cache.
|
||||||
pub fn peers(&self) -> Vec<Arc<Peer>> {
|
pub fn peers(&self) -> Vec<Arc<Peer>> {
|
||||||
let mut v: Vec<Arc<Peer>> = Vec::new();
|
let mut v: Vec<Arc<Peer>> = Vec::new();
|
||||||
|
@ -319,9 +320,7 @@ impl Node {
|
||||||
self.paths.get(ep).map_or_else(|| {
|
self.paths.get(ep).map_or_else(|| {
|
||||||
let p = Arc::new(Path::new(ep.clone(), local_socket, local_interface));
|
let p = Arc::new(Path::new(ep.clone(), local_socket, local_interface));
|
||||||
self.paths.insert(ep.clone(), p.clone()).unwrap_or(p) // if another thread added one, return that instead
|
self.paths.insert(ep.clone(), p.clone()).unwrap_or(p) // if another thread added one, return that instead
|
||||||
}, |path| {
|
}, |path| path.value().clone())
|
||||||
path.value().clone()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ impl Path {
|
||||||
local_interface,
|
local_interface,
|
||||||
last_send_time_ticks: AtomicI64::new(0),
|
last_send_time_ticks: AtomicI64::new(0),
|
||||||
last_receive_time_ticks: AtomicI64::new(0),
|
last_receive_time_ticks: AtomicI64::new(0),
|
||||||
fragmented_packets: Mutex::new(HashMap::with_capacity_and_hasher(8, U64PassThroughHasher::new())),
|
fragmented_packets: Mutex::new(HashMap::with_capacity_and_hasher(4, U64PassThroughHasher::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use aes_gmac_siv::{AesCtr, AesGmacSiv};
|
||||||
|
|
||||||
use crate::{VERSION_MAJOR, VERSION_MINOR, VERSION_PROTO, VERSION_REVISION};
|
use crate::{VERSION_MAJOR, VERSION_MINOR, VERSION_PROTO, VERSION_REVISION};
|
||||||
use crate::crypto::c25519::C25519KeyPair;
|
use crate::crypto::c25519::C25519KeyPair;
|
||||||
use crate::crypto::hash::SHA384;
|
use crate::crypto::hash::{SHA384, SHA384_HASH_SIZE};
|
||||||
use crate::crypto::kbkdf::zt_kbkdf_hmac_sha384;
|
use crate::crypto::kbkdf::zt_kbkdf_hmac_sha384;
|
||||||
use crate::crypto::p521::P521KeyPair;
|
use crate::crypto::p521::P521KeyPair;
|
||||||
use crate::crypto::poly1305::Poly1305;
|
use crate::crypto::poly1305::Poly1305;
|
||||||
|
@ -31,14 +31,10 @@ struct AesGmacSivPoolFactory(Secret<48>, Secret<48>);
|
||||||
|
|
||||||
impl PoolFactory<AesGmacSiv> for AesGmacSivPoolFactory {
|
impl PoolFactory<AesGmacSiv> for AesGmacSivPoolFactory {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn create(&self) -> AesGmacSiv {
|
fn create(&self) -> AesGmacSiv { AesGmacSiv::new(&self.0.0[0..32], &self.1.0[0..32]) }
|
||||||
AesGmacSiv::new(&self.0.0[0..32], &self.1.0[0..32])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn reset(&self, obj: &mut AesGmacSiv) {
|
fn reset(&self, obj: &mut AesGmacSiv) { obj.reset(); }
|
||||||
obj.reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PeerSecret {
|
struct PeerSecret {
|
||||||
|
@ -92,7 +88,7 @@ pub struct Peer {
|
||||||
// Either None or the current ephemeral key pair whose public keys are on offer.
|
// Either None or the current ephemeral key pair whose public keys are on offer.
|
||||||
ephemeral_pair: Mutex<Option<EphemeralKeyPair>>,
|
ephemeral_pair: Mutex<Option<EphemeralKeyPair>>,
|
||||||
|
|
||||||
// Paths sorted in ascending order of quality / preference.
|
// Paths sorted in descending order of quality / preference.
|
||||||
paths: Mutex<Vec<Arc<Path>>>,
|
paths: Mutex<Vec<Arc<Path>>>,
|
||||||
|
|
||||||
// Local external address most recently reported by this peer (IP transport only).
|
// Local external address most recently reported by this peer (IP transport only).
|
||||||
|
@ -144,8 +140,7 @@ fn salsa_poly_create(secret: &PeerSecret, header: &PacketHeader, packet_size: us
|
||||||
let mut salsa = Salsa::new(&key.0[0..32], header.id_bytes(), true).unwrap();
|
let mut salsa = Salsa::new(&key.0[0..32], header.id_bytes(), true).unwrap();
|
||||||
let mut poly1305_key = [0_u8; 32];
|
let mut poly1305_key = [0_u8; 32];
|
||||||
salsa.crypt_in_place(&mut poly1305_key);
|
salsa.crypt_in_place(&mut poly1305_key);
|
||||||
let mut poly = Poly1305::new(&poly1305_key).unwrap();
|
(salsa, Poly1305::new(&poly1305_key).unwrap())
|
||||||
(salsa, poly)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Peer {
|
impl Peer {
|
||||||
|
@ -192,9 +187,7 @@ impl Peer {
|
||||||
|
|
||||||
/// Get the next packet ID / IV.
|
/// Get the next packet ID / IV.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn next_packet_id(&self) -> PacketID {
|
pub(crate) fn next_packet_id(&self) -> PacketID { self.packet_id_counter.fetch_add(1, Ordering::Relaxed) }
|
||||||
self.packet_id_counter.fetch_add(1, Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Receive, decrypt, authenticate, and process an incoming packet from this peer.
|
/// Receive, decrypt, authenticate, and process an incoming packet from this peer.
|
||||||
/// If the packet comes in multiple fragments, the fragments slice should contain all
|
/// If the packet comes in multiple fragments, the fragments slice should contain all
|
||||||
|
@ -287,15 +280,34 @@ impl Peer {
|
||||||
self.total_bytes_received.fetch_add((payload.len() + PACKET_HEADER_SIZE) as u64, Ordering::Relaxed);
|
self.total_bytes_received.fetch_add((payload.len() + PACKET_HEADER_SIZE) as u64, Ordering::Relaxed);
|
||||||
|
|
||||||
let _ = payload.u8_at(0).map(|verb| {
|
let _ = payload.u8_at(0).map(|verb| {
|
||||||
|
let mut extended_authentication = false;
|
||||||
|
if (verb & VERB_FLAG_EXTENDED_AUTHENTICATION) != 0 {
|
||||||
|
let auth_bytes = payload.as_bytes();
|
||||||
|
if auth_bytes.len() >= (1 + SHA384_HASH_SIZE) {
|
||||||
|
let packet_hmac_start = auth_bytes.len() - SHA384_HASH_SIZE;
|
||||||
|
if !SHA384::hmac(self.static_secret_packet_hmac.as_ref(), &auth_bytes[1..packet_hmac_start]).eq(&auth_bytes[packet_hmac_start..]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
extended_authentication = true;
|
||||||
|
unsafe { payload.set_size(payload.len() - SHA384_HASH_SIZE) };
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verb & VERB_FLAG_COMPRESSED) != 0 {
|
||||||
|
}
|
||||||
|
|
||||||
|
let verb = verb & VERB_MASK;
|
||||||
|
|
||||||
// For performance reasons we let VL2 handle packets first. It returns false
|
// For performance reasons we let VL2 handle packets first. It returns false
|
||||||
// if it didn't handle the packet, in which case it's handled at VL1.
|
// if it didn't handle the packet, in which case it's handled at VL1.
|
||||||
let verb = verb & VERB_MASK;
|
|
||||||
if !ph.handle_packet(self, source_path, forward_secrecy, verb, &payload) {
|
if !ph.handle_packet(self, source_path, forward_secrecy, verb, &payload) {
|
||||||
match verb {
|
match verb {
|
||||||
//VERB_VL1_NOP => {}
|
//VERB_VL1_NOP => {}
|
||||||
VERB_VL1_HELLO => self.receive_hello(ci, node, time_ticks, source_path, &payload),
|
VERB_VL1_HELLO => self.receive_hello(ci, node, time_ticks, source_path, &payload),
|
||||||
VERB_VL1_ERROR => self.receive_error(ci, node, time_ticks, source_path, &payload),
|
VERB_VL1_ERROR => self.receive_error(ci, ph, node, time_ticks, source_path, forward_secrecy, &payload),
|
||||||
VERB_VL1_OK => self.receive_ok(ci, node, time_ticks, source_path, &payload),
|
VERB_VL1_OK => self.receive_ok(ci, ph, node, time_ticks, source_path, forward_secrecy, &payload),
|
||||||
VERB_VL1_WHOIS => self.receive_whois(ci, node, time_ticks, source_path, &payload),
|
VERB_VL1_WHOIS => self.receive_whois(ci, node, time_ticks, source_path, &payload),
|
||||||
VERB_VL1_RENDEZVOUS => self.receive_rendezvous(ci, node, time_ticks, source_path, &payload),
|
VERB_VL1_RENDEZVOUS => self.receive_rendezvous(ci, node, time_ticks, source_path, &payload),
|
||||||
VERB_VL1_ECHO => self.receive_echo(ci, node, time_ticks, source_path, &payload),
|
VERB_VL1_ECHO => self.receive_echo(ci, node, time_ticks, source_path, &payload),
|
||||||
|
@ -406,7 +418,7 @@ impl Peer {
|
||||||
header.flags_cipher_hops = CIPHER_NOCRYPT_POLY1305;
|
header.flags_cipher_hops = CIPHER_NOCRYPT_POLY1305;
|
||||||
}).is_ok());
|
}).is_ok());
|
||||||
debug_assert!(packet.append_and_init_struct(|header: &mut message_component_structs::HelloFixedHeaderFields| {
|
debug_assert!(packet.append_and_init_struct(|header: &mut message_component_structs::HelloFixedHeaderFields| {
|
||||||
header.verb = VERB_VL1_HELLO | VERB_FLAG_HMAC;
|
header.verb = VERB_VL1_HELLO | VERB_FLAG_EXTENDED_AUTHENTICATION;
|
||||||
header.version_proto = VERSION_PROTO;
|
header.version_proto = VERSION_PROTO;
|
||||||
header.version_major = VERSION_MAJOR;
|
header.version_major = VERSION_MAJOR;
|
||||||
header.version_minor = VERSION_MINOR;
|
header.version_minor = VERSION_MINOR;
|
||||||
|
@ -456,12 +468,9 @@ impl Peer {
|
||||||
dict.set_str(HELLO_DICT_KEY_OS_NAME, std::env::consts::OS);
|
dict.set_str(HELLO_DICT_KEY_OS_NAME, std::env::consts::OS);
|
||||||
}
|
}
|
||||||
let mut flags = String::new();
|
let mut flags = String::new();
|
||||||
if node.fips_mode {
|
if node.fips_mode() {
|
||||||
flags.push('F');
|
flags.push('F');
|
||||||
}
|
}
|
||||||
if node.wimp {
|
|
||||||
flags.push('w');
|
|
||||||
}
|
|
||||||
dict.set_str(HELLO_DICT_KEY_FLAGS, flags.as_str());
|
dict.set_str(HELLO_DICT_KEY_FLAGS, flags.as_str());
|
||||||
debug_assert!(dict.write_to(&mut packet).is_ok());
|
debug_assert!(dict.write_to(&mut packet).is_ok());
|
||||||
|
|
||||||
|
@ -470,7 +479,9 @@ impl Peer {
|
||||||
dict_aes.crypt_in_place(&mut packet.as_bytes_mut()[dict_start_position..]);
|
dict_aes.crypt_in_place(&mut packet.as_bytes_mut()[dict_start_position..]);
|
||||||
drop(dict_aes);
|
drop(dict_aes);
|
||||||
|
|
||||||
debug_assert!(packet.append_bytes_fixed(&SHA384::hmac(self.static_secret_packet_hmac.as_ref(), &packet.as_bytes()[PACKET_HEADER_SIZE + 1..])).is_ok());
|
debug_assert!(packet.append_u16(0).is_ok());
|
||||||
|
|
||||||
|
debug_assert!(packet.append_bytes_fixed(&SHA384::hmac(self.static_secret_packet_hmac.as_ref(), packet.as_bytes_starting_at(PACKET_HEADER_SIZE).unwrap())).is_ok());
|
||||||
|
|
||||||
let (_, mut poly) = salsa_poly_create(&self.static_secret, packet.struct_at::<PacketHeader>(0).unwrap(), packet.len());
|
let (_, mut poly) = salsa_poly_create(&self.static_secret, packet.struct_at::<PacketHeader>(0).unwrap(), packet.len());
|
||||||
poly.update(packet.as_bytes_starting_at(PACKET_HEADER_SIZE).unwrap());
|
poly.update(packet.as_bytes_starting_at(PACKET_HEADER_SIZE).unwrap());
|
||||||
|
@ -497,10 +508,48 @@ impl Peer {
|
||||||
fn receive_hello<CI: VL1CallerInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
|
fn receive_hello<CI: VL1CallerInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn receive_error<CI: VL1CallerInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
|
fn receive_error<CI: VL1CallerInterface, PH: VL1PacketHandler>(&self, ci: &CI, ph: &PH, node: &Node, time_ticks: i64, source_path: &Arc<Path>, forward_secrecy: bool, payload: &Buffer<{ PACKET_SIZE_MAX }>) {
|
||||||
|
let mut cursor: usize = 0;
|
||||||
|
let _ = payload.read_struct::<message_component_structs::ErrorHeader>(&mut cursor).map(|error_header| {
|
||||||
|
let in_re_packet_id = error_header.in_re_packet_id;
|
||||||
|
let current_packet_id_counter = self.packet_id_counter.load(Ordering::Relaxed);
|
||||||
|
if current_packet_id_counter.checked_sub(in_re_packet_id).map_or_else(|| {
|
||||||
|
(!in_re_packet_id).wrapping_add(current_packet_id_counter) < PACKET_RESPONSE_COUNTER_DELTA_MAX
|
||||||
|
}, |packets_ago| {
|
||||||
|
packets_ago <= PACKET_RESPONSE_COUNTER_DELTA_MAX
|
||||||
|
}) {
|
||||||
|
match error_header.in_re_verb {
|
||||||
|
_ => {
|
||||||
|
ph.handle_error(self, source_path, forward_secrecy, error_header.in_re_verb, in_re_packet_id, error_header.error_code, payload, &mut cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn receive_ok<CI: VL1CallerInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
|
fn receive_ok<CI: VL1CallerInterface, PH: VL1PacketHandler>(&self, ci: &CI, ph: &PH, node: &Node, time_ticks: i64, source_path: &Arc<Path>, forward_secrecy: bool, payload: &Buffer<{ PACKET_SIZE_MAX }>) {
|
||||||
|
let mut cursor: usize = 0;
|
||||||
|
let _ = payload.read_struct::<message_component_structs::OkHeader>(&mut cursor).map(|ok_header| {
|
||||||
|
let in_re_packet_id = ok_header.in_re_packet_id;
|
||||||
|
let current_packet_id_counter = self.packet_id_counter.load(Ordering::Relaxed);
|
||||||
|
if current_packet_id_counter.checked_sub(in_re_packet_id).map_or_else(|| {
|
||||||
|
(!in_re_packet_id).wrapping_add(current_packet_id_counter) < PACKET_RESPONSE_COUNTER_DELTA_MAX
|
||||||
|
}, |packets_ago| {
|
||||||
|
packets_ago <= PACKET_RESPONSE_COUNTER_DELTA_MAX
|
||||||
|
}) {
|
||||||
|
match ok_header.in_re_verb {
|
||||||
|
VERB_VL1_HELLO => {
|
||||||
|
}
|
||||||
|
VERB_VL1_WHOIS => {
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
ph.handle_ok(self, source_path, forward_secrecy, ok_header.in_re_verb, in_re_packet_id, payload, &mut cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn receive_whois<CI: VL1CallerInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
|
fn receive_whois<CI: VL1CallerInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
|
||||||
|
@ -518,9 +567,7 @@ impl Peer {
|
||||||
fn receive_user_message<CI: VL1CallerInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
|
fn receive_user_message<CI: VL1CallerInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
|
||||||
|
|
||||||
/// Get current best path or None if there are no direct paths to this peer.
|
/// Get current best path or None if there are no direct paths to this peer.
|
||||||
pub fn direct_path(&self) -> Option<Arc<Path>> {
|
pub fn direct_path(&self) -> Option<Arc<Path>> { self.paths.lock().first().map(|p| p.clone()) }
|
||||||
self.paths.lock().last().map(|p| p.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get either the current best direct path or an indirect path.
|
/// Get either the current best direct path or an indirect path.
|
||||||
pub fn path(&self, node: &Node) -> Option<Arc<Path>> {
|
pub fn path(&self, node: &Node) -> Option<Arc<Path>> {
|
||||||
|
|
|
@ -131,8 +131,8 @@ pub const FRAGMENT_INDICATOR: u8 = 0xff;
|
||||||
/// Verb (inner) flag indicating that the packet's payload (after the verb) is LZ4 compressed.
|
/// Verb (inner) flag indicating that the packet's payload (after the verb) is LZ4 compressed.
|
||||||
pub const VERB_FLAG_COMPRESSED: u8 = 0x80;
|
pub const VERB_FLAG_COMPRESSED: u8 = 0x80;
|
||||||
|
|
||||||
/// Verb (inner) flag indicating that payload after verb is authenticated with HMAC-SHA384.
|
/// Verb (inner) flag indicating that payload is authenticated with HMAC-SHA384.
|
||||||
pub const VERB_FLAG_HMAC: u8 = 0x40;
|
pub const VERB_FLAG_EXTENDED_AUTHENTICATION: u8 = 0x40;
|
||||||
|
|
||||||
/// Mask to get only the verb from the verb + verb flags byte.
|
/// Mask to get only the verb from the verb + verb flags byte.
|
||||||
pub const VERB_MASK: u8 = 0x1f;
|
pub const VERB_MASK: u8 = 0x1f;
|
||||||
|
@ -146,8 +146,8 @@ pub const PROTOCOL_MAX_HOPS: u8 = 7;
|
||||||
/// Maximum number of hops to allow.
|
/// Maximum number of hops to allow.
|
||||||
pub const FORWARD_MAX_HOPS: u8 = 3;
|
pub const FORWARD_MAX_HOPS: u8 = 3;
|
||||||
|
|
||||||
/// Maximum difference between an OK in-re packet ID and the current packet ID counter.
|
/// Maximum difference between current packet ID counter and OK/ERROR in-re packet ID.
|
||||||
pub const OK_PACKET_SEQUENCE_CUTOFF: u64 = 1000;
|
pub const PACKET_RESPONSE_COUNTER_DELTA_MAX: u64 = 1024;
|
||||||
|
|
||||||
/// Frequency for WHOIS retries
|
/// Frequency for WHOIS retries
|
||||||
pub const WHOIS_RETRY_INTERVAL: i64 = 1000;
|
pub const WHOIS_RETRY_INTERVAL: i64 = 1000;
|
||||||
|
@ -267,6 +267,24 @@ impl FragmentHeader {
|
||||||
|
|
||||||
pub(crate) mod message_component_structs {
|
pub(crate) mod message_component_structs {
|
||||||
use crate::vl1::buffer::RawObject;
|
use crate::vl1::buffer::RawObject;
|
||||||
|
use crate::vl1::protocol::PacketID;
|
||||||
|
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct OkHeader {
|
||||||
|
pub in_re_verb: u8,
|
||||||
|
pub in_re_packet_id: PacketID,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl RawObject for OkHeader {}
|
||||||
|
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct ErrorHeader {
|
||||||
|
pub in_re_verb: u8,
|
||||||
|
pub in_re_packet_id: PacketID,
|
||||||
|
pub error_code: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl RawObject for ErrorHeader {}
|
||||||
|
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
pub struct HelloFixedHeaderFields {
|
pub struct HelloFixedHeaderFields {
|
||||||
|
@ -300,6 +318,8 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn representation() {
|
fn representation() {
|
||||||
|
assert_eq!(size_of::<message_component_structs::OkHeader>(), 9);
|
||||||
|
assert_eq!(size_of::<message_component_structs::ErrorHeader>(), 10);
|
||||||
assert_eq!(size_of::<PacketHeader>(), PACKET_HEADER_SIZE);
|
assert_eq!(size_of::<PacketHeader>(), PACKET_HEADER_SIZE);
|
||||||
assert_eq!(size_of::<FragmentHeader>(), FRAGMENT_HEADER_SIZE);
|
assert_eq!(size_of::<FragmentHeader>(), FRAGMENT_HEADER_SIZE);
|
||||||
|
|
||||||
|
|
|
@ -103,10 +103,10 @@ pub struct Root {
|
||||||
/// as at least one of the old roots is up to distribute the new ones.
|
/// as at least one of the old roots is up to distribute the new ones.
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
pub struct RootSet {
|
pub struct RootSet {
|
||||||
pub timestamp: i64,
|
timestamp: i64,
|
||||||
pub name: String,
|
name: String,
|
||||||
pub contact: String,
|
contact: String,
|
||||||
pub roots: BTreeSet<Root>,
|
roots: BTreeSet<Root>,
|
||||||
signer: Vec<u8>,
|
signer: Vec<u8>,
|
||||||
signature: Vec<u8>,
|
signature: Vec<u8>,
|
||||||
root_set_type: Type,
|
root_set_type: Type,
|
||||||
|
@ -185,9 +185,9 @@ impl RootSet {
|
||||||
buf.append_u8(ROOT_SET_TYPE_ED25519_P521)?;
|
buf.append_u8(ROOT_SET_TYPE_ED25519_P521)?;
|
||||||
buf.append_u64(self.timestamp as u64)?;
|
buf.append_u64(self.timestamp as u64)?;
|
||||||
buf.append_u8(name.len() as u8)?;
|
buf.append_u8(name.len() as u8)?;
|
||||||
buf.append_bytes(name);
|
buf.append_bytes(name)?;
|
||||||
buf.append_u8(contact.len() as u8)?;
|
buf.append_u8(contact.len() as u8)?;
|
||||||
buf.append_bytes(contact);
|
buf.append_bytes(contact)?;
|
||||||
if self.signer.len() != (ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE) {
|
if self.signer.len() != (ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE) {
|
||||||
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "signer can only be 164 bytes"));
|
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "signer can only be 164 bytes"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,21 +19,15 @@ struct WhoisQueueItem {
|
||||||
retry_count: u16,
|
retry_count: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct WhoisQueue {
|
pub(crate) struct WhoisQueue(Mutex<HashMap<Address, WhoisQueueItem>>);
|
||||||
queue: Mutex<HashMap<Address, WhoisQueueItem>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WhoisQueue {
|
impl WhoisQueue {
|
||||||
pub(crate) const INTERVAL: i64 = WHOIS_RETRY_INTERVAL;
|
pub(crate) const INTERVAL: i64 = WHOIS_RETRY_INTERVAL;
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Self(Mutex::new(HashMap::new())) }
|
||||||
Self {
|
|
||||||
queue: Mutex::new(HashMap::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn query<CI: VL1CallerInterface>(&self, node: &Node, ci: &CI, target: Address, packet: Option<QueuedPacket>) {
|
pub fn query<CI: VL1CallerInterface>(&self, node: &Node, ci: &CI, target: Address, packet: Option<QueuedPacket>) {
|
||||||
let mut q = self.queue.lock();
|
let mut q = self.0.lock();
|
||||||
|
|
||||||
let qi = q.entry(target).or_insert_with(|| WhoisQueueItem {
|
let qi = q.entry(target).or_insert_with(|| WhoisQueueItem {
|
||||||
packet_queue: LinkedList::new(),
|
packet_queue: LinkedList::new(),
|
||||||
|
@ -55,14 +49,14 @@ impl WhoisQueue {
|
||||||
|
|
||||||
/// Remove a WHOIS request from the queue and call the supplied function for all queued packets.
|
/// Remove a WHOIS request from the queue and call the supplied function for all queued packets.
|
||||||
pub fn response_received_get_packets<F: FnMut(&mut QueuedPacket)>(&self, address: Address, packet_handler: F) {
|
pub fn response_received_get_packets<F: FnMut(&mut QueuedPacket)>(&self, address: Address, packet_handler: F) {
|
||||||
let mut qi = self.queue.lock().remove(&address);
|
let mut qi = self.0.lock().remove(&address);
|
||||||
let _ = qi.map(|mut qi| qi.packet_queue.iter_mut().for_each(packet_handler));
|
let _ = qi.map(|mut qi| qi.packet_queue.iter_mut().for_each(packet_handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called every INTERVAL during background tasks.
|
/// Called every INTERVAL during background tasks.
|
||||||
pub fn on_interval<CI: VL1CallerInterface>(&self, node: &Node, ci: &CI, time_ticks: i64) {
|
pub fn on_interval<CI: VL1CallerInterface>(&self, node: &Node, ci: &CI, time_ticks: i64) {
|
||||||
let mut targets: Vec<Address> = Vec::new();
|
let mut targets: Vec<Address> = Vec::new();
|
||||||
self.queue.lock().retain(|target, qi| {
|
self.0.lock().retain(|target, qi| {
|
||||||
if qi.retry_count < WHOIS_RETRY_MAX {
|
if qi.retry_count < WHOIS_RETRY_MAX {
|
||||||
if qi.retry_gate.gate(time_ticks) {
|
if qi.retry_gate.gate(time_ticks) {
|
||||||
qi.retry_count += 1;
|
qi.retry_count += 1;
|
||||||
|
|
Loading…
Add table
Reference in a new issue