mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-07-27 12:42:49 +02:00
A bunch of reorg and other cleanup.
This commit is contained in:
parent
6d232f817c
commit
1f79a2a707
11 changed files with 152 additions and 100 deletions
|
@ -35,21 +35,30 @@ impl C25519KeyPair {
|
||||||
|
|
||||||
pub fn from_bytes(public_key: &[u8], secret_key: &[u8]) -> Option<C25519KeyPair> {
|
pub fn from_bytes(public_key: &[u8], secret_key: &[u8]) -> Option<C25519KeyPair> {
|
||||||
if public_key.len() == 32 && secret_key.len() == 32 {
|
if public_key.len() == 32 && secret_key.len() == 32 {
|
||||||
// NOTE: we keep the original secret separately from x25519_dalek's StaticSecret
|
/* NOTE: we keep the original secret separately from x25519_dalek's StaticSecret
|
||||||
// due to how "clamping" is done in the old C++ code vs x25519_dalek. Clamping
|
* due to how "clamping" is done in the old C++ code vs x25519_dalek. Clamping
|
||||||
// is explained here:
|
* is explained here:
|
||||||
//
|
*
|
||||||
// https://www.jcraige.com/an-explainer-on-ed25519-clamping
|
* https://www.jcraige.com/an-explainer-on-ed25519-clamping
|
||||||
//
|
*
|
||||||
// In the old C++ code clamping is done when the secret key is actually used.
|
* The old code does clamping at the time of use. In other words the code that
|
||||||
// In x25519_dalek it's done when the key is loaded into one of the secret
|
* performs things like key agreement or signing clamps the secret before doing
|
||||||
// containers. Unfortunately this means that identities' secret keys won't look
|
* the operation. The x25519_dalek code does clamping at generation or when
|
||||||
// the same in the actual identity structure vs. what you would get from the C++
|
* from() is used to get a key from a raw byte array.
|
||||||
// v0 ZeroTier implementation. The cryptographic results are identical but we
|
*
|
||||||
// still need to have our identity spit out identical bits when exported.
|
* Unfortunately this introduces issues when interoperating with old code. The
|
||||||
//
|
* old system generates secrets that are not clamped (since they're clamped at
|
||||||
// Newly generated keys will be clamped at generation time, which will also yield
|
* use!) and assumes that these exact binary keys will be preserved in e.g.
|
||||||
// identical results in both cases.
|
* identities. So to preserve this behavior we store the secret separately
|
||||||
|
* so secret_bytes() will return it as-is.
|
||||||
|
*
|
||||||
|
* The new code will still clamp at generation resulting in secrets that are
|
||||||
|
* pre-clamped, but the old code won't care about this. It's only a problem when
|
||||||
|
* going the other way.
|
||||||
|
*
|
||||||
|
* This has no cryptographic implication since regardless of where, the clamping
|
||||||
|
* is done. It's just an API thing.
|
||||||
|
*/
|
||||||
let pk: [u8; 32] = public_key.try_into().unwrap();
|
let pk: [u8; 32] = public_key.try_into().unwrap();
|
||||||
let sk_orig: Secret<32> = Secret(secret_key.try_into().unwrap());
|
let sk_orig: Secret<32> = Secret(secret_key.try_into().unwrap());
|
||||||
let pk = x25519_dalek::PublicKey::from(pk);
|
let pk = x25519_dalek::PublicKey::from(pk);
|
||||||
|
|
|
@ -13,15 +13,20 @@ use crate::util::pool::PoolFactory;
|
||||||
|
|
||||||
/// Annotates a structure as containing only primitive types.
|
/// Annotates a structure as containing only primitive types.
|
||||||
///
|
///
|
||||||
/// The structure must be safe to copy in raw form and access without concern for alignment, or if
|
/// This means the structure is safe to copy in raw form, does not need to be dropped, and otherwise
|
||||||
/// it does contain elements that require alignment special care must be taken when accessing them
|
/// contains nothing complex that requires any special handling. It also implies that it is safe to
|
||||||
/// at least on platforms where it matters.
|
/// access without concern for alignment on platforms on which this is an issue, or at least that
|
||||||
pub unsafe trait RawObject: Sized {}
|
/// the implementer must take care to guard any unaligned access in appropriate ways. FlatBlob
|
||||||
|
/// structures are generally repr(C, packed) as well to make them deterministic across systems.
|
||||||
|
///
|
||||||
|
/// The Buffer has special methods allowing these structs to be read and written in place, which
|
||||||
|
/// would be unsafe without these concerns being flagged as not applicable.
|
||||||
|
pub unsafe trait FlatBlob: Sized {}
|
||||||
|
|
||||||
/// A safe bounds checked I/O buffer with extensions for convenient appending of RawObject types.
|
/// A safe bounds checked I/O buffer with extensions for convenient appending of RawObject types.
|
||||||
pub struct Buffer<const L: usize>(usize, [u8; L]);
|
pub struct Buffer<const L: usize>(usize, [u8; L]);
|
||||||
|
|
||||||
unsafe impl<const L: usize> RawObject for Buffer<L> {}
|
unsafe impl<const L: usize> FlatBlob for Buffer<L> {}
|
||||||
|
|
||||||
impl<const L: usize> Default for Buffer<L> {
|
impl<const L: usize> Default for Buffer<L> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -146,7 +151,7 @@ impl<const L: usize> Buffer<L> {
|
||||||
|
|
||||||
/// Append a structure and return a mutable reference to its memory.
|
/// Append a structure and return a mutable reference to its memory.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn append_struct_get_mut<T: RawObject>(&mut self) -> std::io::Result<&mut T> {
|
pub fn append_struct_get_mut<T: FlatBlob>(&mut self) -> std::io::Result<&mut T> {
|
||||||
let ptr = self.0;
|
let ptr = self.0;
|
||||||
let end = ptr + size_of::<T>();
|
let end = ptr + size_of::<T>();
|
||||||
if end <= L {
|
if end <= L {
|
||||||
|
@ -322,7 +327,7 @@ impl<const L: usize> Buffer<L> {
|
||||||
|
|
||||||
/// Get a structure at a given position in the buffer.
|
/// Get a structure at a given position in the buffer.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn struct_at<T: RawObject>(&self, ptr: usize) -> std::io::Result<&T> {
|
pub fn struct_at<T: FlatBlob>(&self, ptr: usize) -> std::io::Result<&T> {
|
||||||
if (ptr + size_of::<T>()) <= self.0 {
|
if (ptr + size_of::<T>()) <= self.0 {
|
||||||
unsafe { Ok(&*self.1.as_ptr().cast::<u8>().offset(ptr as isize).cast::<T>()) }
|
unsafe { Ok(&*self.1.as_ptr().cast::<u8>().offset(ptr as isize).cast::<T>()) }
|
||||||
} else {
|
} else {
|
||||||
|
@ -332,7 +337,7 @@ impl<const L: usize> Buffer<L> {
|
||||||
|
|
||||||
/// Get a structure at a given position in the buffer.
|
/// Get a structure at a given position in the buffer.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn struct_mut_at<T: RawObject>(&mut self, ptr: usize) -> std::io::Result<&mut T> {
|
pub fn struct_mut_at<T: FlatBlob>(&mut self, ptr: usize) -> std::io::Result<&mut T> {
|
||||||
if (ptr + size_of::<T>()) <= self.0 {
|
if (ptr + size_of::<T>()) <= self.0 {
|
||||||
unsafe { Ok(&mut *self.1.as_mut_ptr().cast::<u8>().offset(ptr as isize).cast::<T>()) }
|
unsafe { Ok(&mut *self.1.as_mut_ptr().cast::<u8>().offset(ptr as isize).cast::<T>()) }
|
||||||
} else {
|
} else {
|
||||||
|
@ -351,7 +356,7 @@ impl<const L: usize> Buffer<L> {
|
||||||
|
|
||||||
/// Get a structure at a given position in the buffer and advance the cursor.
|
/// Get a structure at a given position in the buffer and advance the cursor.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn read_struct<T: RawObject>(&self, cursor: &mut usize) -> std::io::Result<&T> {
|
pub fn read_struct<T: FlatBlob>(&self, cursor: &mut usize) -> std::io::Result<&T> {
|
||||||
let ptr = *cursor;
|
let ptr = *cursor;
|
||||||
let end = ptr + size_of::<T>();
|
let end = ptr + size_of::<T>();
|
||||||
debug_assert!(end <= L);
|
debug_assert!(end <= L);
|
||||||
|
|
|
@ -56,11 +56,6 @@ impl std::hash::Hasher for U64NoOpHasher {
|
||||||
self.0.wrapping_add(self.0.wrapping_shr(32))
|
self.0.wrapping_add(self.0.wrapping_shr(32))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn write(&mut self, _: &[u8]) {
|
|
||||||
panic!("U64NoOpHasher should only be used with u64 and i64 types");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn write_u64(&mut self, i: u64) {
|
fn write_u64(&mut self, i: u64) {
|
||||||
self.0 = self.0.wrapping_add(i);
|
self.0 = self.0.wrapping_add(i);
|
||||||
|
@ -70,6 +65,31 @@ impl std::hash::Hasher for U64NoOpHasher {
|
||||||
fn write_i64(&mut self, i: i64) {
|
fn write_i64(&mut self, i: i64) {
|
||||||
self.0 = self.0.wrapping_add(i as u64);
|
self.0 = self.0.wrapping_add(i as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn write_usize(&mut self, i: usize) {
|
||||||
|
self.0 = self.0.wrapping_add(i as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn write_isize(&mut self, i: isize) {
|
||||||
|
self.0 = self.0.wrapping_add(i as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn write_u32(&mut self, i: u32) {
|
||||||
|
self.0 = self.0.wrapping_add(i as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn write_i32(&mut self, i: i32) {
|
||||||
|
self.0 = self.0.wrapping_add(i as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn write(&mut self, _: &[u8]) {
|
||||||
|
panic!("U64NoOpHasher should only be used with u64 and i64 types");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::hash::BuildHasher for U64NoOpHasher {
|
impl std::hash::BuildHasher for U64NoOpHasher {
|
||||||
|
|
|
@ -40,7 +40,7 @@ pub enum Endpoint {
|
||||||
Nil,
|
Nil,
|
||||||
|
|
||||||
/// Via another node using unencapsulated relaying (e.g. via a root)
|
/// Via another node using unencapsulated relaying (e.g. via a root)
|
||||||
/// Hash is a full hash of the identity for strong verification.
|
/// This is the address and the full identity fingerprint.
|
||||||
ZeroTier(Address, [u8; SHA512_HASH_SIZE]),
|
ZeroTier(Address, [u8; SHA512_HASH_SIZE]),
|
||||||
|
|
||||||
/// Direct L2 Ethernet
|
/// Direct L2 Ethernet
|
||||||
|
@ -68,7 +68,7 @@ pub enum Endpoint {
|
||||||
WebRTC(Vec<u8>),
|
WebRTC(Vec<u8>),
|
||||||
|
|
||||||
/// Via another node using inner encapsulation via VERB_ENCAP.
|
/// Via another node using inner encapsulation via VERB_ENCAP.
|
||||||
/// Hash is a full hash of the identity for strong verification.
|
/// This is the address and the full identity fingerprint.
|
||||||
ZeroTierEncap(Address, [u8; SHA512_HASH_SIZE]),
|
ZeroTierEncap(Address, [u8; SHA512_HASH_SIZE]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,9 @@ use crate::PacketBuffer;
|
||||||
/// Performance note: PacketBuffer is Pooled<Buffer> which is NotNull<*mut Buffer>.
|
/// Performance note: PacketBuffer is Pooled<Buffer> which is NotNull<*mut Buffer>.
|
||||||
/// That means Option<PacketBuffer> is just a pointer, since NotNull permits the
|
/// That means Option<PacketBuffer> is just a pointer, since NotNull permits the
|
||||||
/// compiler to optimize out any additional state in Option.
|
/// compiler to optimize out any additional state in Option.
|
||||||
|
///
|
||||||
|
/// This will need to be modified if we ever support more than 8 fragments to increase
|
||||||
|
/// the size of frags[] and the number of bits in 'have' and 'expecting'.
|
||||||
pub(crate) struct FragmentedPacket {
|
pub(crate) struct FragmentedPacket {
|
||||||
pub ts_ticks: i64,
|
pub ts_ticks: i64,
|
||||||
pub frags: [Option<PacketBuffer>; PACKET_FRAGMENT_COUNT_MAX],
|
pub frags: [Option<PacketBuffer>; PACKET_FRAGMENT_COUNT_MAX],
|
||||||
|
@ -24,6 +27,7 @@ pub(crate) struct FragmentedPacket {
|
||||||
impl FragmentedPacket {
|
impl FragmentedPacket {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(ts: i64) -> Self {
|
pub fn new(ts: i64) -> Self {
|
||||||
|
debug_assert_eq!(PACKET_FRAGMENT_COUNT_MAX, 8);
|
||||||
Self {
|
Self {
|
||||||
ts_ticks: ts,
|
ts_ticks: ts,
|
||||||
frags: [None, None, None, None, None, None, None, None],
|
frags: [None, None, None, None, None, None, None, None],
|
||||||
|
@ -36,17 +40,33 @@ impl FragmentedPacket {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn add_fragment(&mut self, frag: PacketBuffer, no: u8, expecting: u8) -> bool {
|
pub fn add_fragment(&mut self, frag: PacketBuffer, no: u8, expecting: u8) -> bool {
|
||||||
self.frags.get_mut(no as usize).map_or(false, |entry| {
|
self.frags.get_mut(no as usize).map_or(false, |entry| {
|
||||||
// Note that a duplicate fragment just gets silently replaced. This shouldn't happen
|
/*
|
||||||
// unless a dupe occurred at the network level, in which case this is usually a
|
* This works by setting bit N in the 'have' bit mask and then setting X bits
|
||||||
// no-op event. There is no security implication since the whole packet gets MAC'd
|
* in 'expecting' if the 'expecting' field is non-zero. Since the packet head
|
||||||
// after assembly.
|
* does not carry the expecting fragment count (it will be provided as zero) and
|
||||||
if entry.replace(frag).is_none() {
|
* all subsequent fragments should have the same fragment count, this will yield
|
||||||
self.have += 1;
|
* a 'have' of 1 and an 'expecting' of 0 after the head arrives. Then 'expecting'
|
||||||
self.expecting |= expecting; // expecting is either 0 or the expected total
|
* will be set to the right bit pattern by the first fragment and 'true' will get
|
||||||
self.have == self.expecting
|
* returned once all fragments have arrived and therefore all flags in 'have' are
|
||||||
} else {
|
* set.
|
||||||
false
|
*
|
||||||
}
|
* Receipt of a four-fragment packet would look like:
|
||||||
|
*
|
||||||
|
* after head : have == 0x01, expecting == 0x00 -> false
|
||||||
|
* after fragment 1: have == 0x03, expecting == 0x0f -> false
|
||||||
|
* after fragment 2: have == 0x07, expecting == 0x0f -> false
|
||||||
|
* after fragment 3: have == 0x0f, expecting == 0x0f -> true (done!)
|
||||||
|
*
|
||||||
|
* This algorithm is just a few instructions in ASM and also correctly handles
|
||||||
|
* duplicated packet fragments. If all fragments never arrive receipt eventually
|
||||||
|
* times out and this is discarded.
|
||||||
|
*/
|
||||||
|
|
||||||
|
let _ = entry.insert(frag);
|
||||||
|
|
||||||
|
self.have |= 1_u8.wrapping_shl(no as u32);
|
||||||
|
self.expecting |= 0xff_u8.wrapping_shr(8 - (expecting as u32));
|
||||||
|
self.have == self.expecting
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -349,7 +349,6 @@ impl Identity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_bytes(&self, include_algorithms: u8, include_private: bool) -> Buffer<MAX_MARSHAL_SIZE> {
|
pub fn to_bytes(&self, include_algorithms: u8, include_private: bool) -> Buffer<MAX_MARSHAL_SIZE> {
|
||||||
let mut b: Buffer<MAX_MARSHAL_SIZE> = Buffer::new();
|
let mut b: Buffer<MAX_MARSHAL_SIZE> = Buffer::new();
|
||||||
assert!(self.marshal(&mut b, include_algorithms, include_private).is_ok());
|
assert!(self.marshal(&mut b, include_algorithms, include_private).is_ok());
|
||||||
|
|
|
@ -81,6 +81,7 @@ pub union InetAddress {
|
||||||
impl TryInto<IpAddr> for InetAddress {
|
impl TryInto<IpAddr> for InetAddress {
|
||||||
type Error = crate::error::InvalidParameterError;
|
type Error = crate::error::InvalidParameterError;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn try_into(self) -> Result<IpAddr, Self::Error> {
|
fn try_into(self) -> Result<IpAddr, Self::Error> {
|
||||||
match unsafe { self.sa.sa_family } {
|
match unsafe { self.sa.sa_family } {
|
||||||
AF_INET => Ok(IpAddr::V4(Ipv4Addr::from(unsafe { self.sin.sin_addr.s_addr.to_ne_bytes() }))),
|
AF_INET => Ok(IpAddr::V4(Ipv4Addr::from(unsafe { self.sin.sin_addr.s_addr.to_ne_bytes() }))),
|
||||||
|
@ -93,6 +94,7 @@ impl TryInto<IpAddr> for InetAddress {
|
||||||
impl TryInto<Ipv4Addr> for InetAddress {
|
impl TryInto<Ipv4Addr> for InetAddress {
|
||||||
type Error = crate::error::InvalidParameterError;
|
type Error = crate::error::InvalidParameterError;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn try_into(self) -> Result<Ipv4Addr, Self::Error> {
|
fn try_into(self) -> Result<Ipv4Addr, Self::Error> {
|
||||||
match unsafe { self.sa.sa_family } {
|
match unsafe { self.sa.sa_family } {
|
||||||
AF_INET => Ok(Ipv4Addr::from(unsafe { self.sin.sin_addr.s_addr.to_ne_bytes() })),
|
AF_INET => Ok(Ipv4Addr::from(unsafe { self.sin.sin_addr.s_addr.to_ne_bytes() })),
|
||||||
|
@ -104,6 +106,7 @@ impl TryInto<Ipv4Addr> for InetAddress {
|
||||||
impl TryInto<Ipv6Addr> for InetAddress {
|
impl TryInto<Ipv6Addr> for InetAddress {
|
||||||
type Error = crate::error::InvalidParameterError;
|
type Error = crate::error::InvalidParameterError;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn try_into(self) -> Result<Ipv6Addr, Self::Error> {
|
fn try_into(self) -> Result<Ipv6Addr, Self::Error> {
|
||||||
match unsafe { self.sa.sa_family } {
|
match unsafe { self.sa.sa_family } {
|
||||||
AF_INET6 => Ok(Ipv6Addr::from(unsafe { self.sin6.sin6_addr.s6_addr })),
|
AF_INET6 => Ok(Ipv6Addr::from(unsafe { self.sin6.sin6_addr.s6_addr })),
|
||||||
|
@ -115,6 +118,7 @@ impl TryInto<Ipv6Addr> for InetAddress {
|
||||||
impl TryInto<SocketAddr> for InetAddress {
|
impl TryInto<SocketAddr> for InetAddress {
|
||||||
type Error = crate::error::InvalidParameterError;
|
type Error = crate::error::InvalidParameterError;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn try_into(self) -> Result<SocketAddr, Self::Error> {
|
fn try_into(self) -> Result<SocketAddr, Self::Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
match self.sa.sa_family {
|
match self.sa.sa_family {
|
||||||
|
@ -129,6 +133,7 @@ impl TryInto<SocketAddr> for InetAddress {
|
||||||
impl TryInto<SocketAddrV4> for InetAddress {
|
impl TryInto<SocketAddrV4> for InetAddress {
|
||||||
type Error = crate::error::InvalidParameterError;
|
type Error = crate::error::InvalidParameterError;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn try_into(self) -> Result<SocketAddrV4, Self::Error> {
|
fn try_into(self) -> Result<SocketAddrV4, Self::Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
match self.sa.sa_family {
|
match self.sa.sa_family {
|
||||||
|
@ -142,6 +147,7 @@ impl TryInto<SocketAddrV4> for InetAddress {
|
||||||
impl TryInto<SocketAddrV6> for InetAddress {
|
impl TryInto<SocketAddrV6> for InetAddress {
|
||||||
type Error = crate::error::InvalidParameterError;
|
type Error = crate::error::InvalidParameterError;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn try_into(self) -> Result<SocketAddrV6, Self::Error> {
|
fn try_into(self) -> Result<SocketAddrV6, Self::Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
match self.sa.sa_family {
|
match self.sa.sa_family {
|
||||||
|
@ -153,6 +159,7 @@ impl TryInto<SocketAddrV6> for InetAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&IpAddr> for InetAddress {
|
impl From<&IpAddr> for InetAddress {
|
||||||
|
#[inline(always)]
|
||||||
fn from(ip: &IpAddr) -> Self {
|
fn from(ip: &IpAddr) -> Self {
|
||||||
match ip {
|
match ip {
|
||||||
IpAddr::V4(ip4) => Self::from(ip4),
|
IpAddr::V4(ip4) => Self::from(ip4),
|
||||||
|
@ -197,6 +204,7 @@ impl From<Ipv6Addr> for InetAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&SocketAddr> for InetAddress {
|
impl From<&SocketAddr> for InetAddress {
|
||||||
|
#[inline(always)]
|
||||||
fn from(sa: &SocketAddr) -> Self {
|
fn from(sa: &SocketAddr) -> Self {
|
||||||
match sa {
|
match sa {
|
||||||
SocketAddr::V4(sa4) => Self::from(sa4),
|
SocketAddr::V4(sa4) => Self::from(sa4),
|
||||||
|
@ -255,6 +263,7 @@ impl Default for InetAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for InetAddress {
|
impl std::fmt::Debug for InetAddress {
|
||||||
|
#[inline(always)]
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_str(&self.to_string())
|
f.write_str(&self.to_string())
|
||||||
}
|
}
|
||||||
|
@ -406,6 +415,7 @@ impl InetAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the address family of this InetAddress: AF_INET, AF_INET6, or 0 if uninitialized.
|
/// Get the address family of this InetAddress: AF_INET, AF_INET6, or 0 if uninitialized.
|
||||||
|
#[inline(always)]
|
||||||
pub fn family(&self) -> u8 {
|
pub fn family(&self) -> u8 {
|
||||||
unsafe { self.sa.sa_family as u8 }
|
unsafe { self.sa.sa_family as u8 }
|
||||||
}
|
}
|
||||||
|
@ -449,7 +459,6 @@ impl InetAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get raw IP bytes, with length dependent on address family (4 or 16).
|
/// Get raw IP bytes, with length dependent on address family (4 or 16).
|
||||||
#[inline(always)]
|
|
||||||
pub fn ip_bytes(&self) -> &[u8] {
|
pub fn ip_bytes(&self) -> &[u8] {
|
||||||
unsafe {
|
unsafe {
|
||||||
match self.sa.sa_family as u8 {
|
match self.sa.sa_family as u8 {
|
||||||
|
@ -464,7 +473,7 @@ impl InetAddress {
|
||||||
/// Bytes are packed in native endian so the resulting u128 may not be the same between systems.
|
/// Bytes are packed in native endian so the resulting u128 may not be the same between systems.
|
||||||
/// This value is intended for local lookup use only.
|
/// This value is intended for local lookup use only.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn ip_as_native_u128(&self) -> u128 {
|
pub(crate) fn ip_as_native_u128(&self) -> u128 {
|
||||||
unsafe {
|
unsafe {
|
||||||
match self.sa.sa_family as u8 {
|
match self.sa.sa_family as u8 {
|
||||||
AF_INET => self.sin.sin_addr.s_addr as u128,
|
AF_INET => self.sin.sin_addr.s_addr as u128,
|
||||||
|
@ -475,7 +484,6 @@ impl InetAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the IP port for this InetAddress.
|
/// Get the IP port for this InetAddress.
|
||||||
#[inline(always)]
|
|
||||||
pub fn port(&self) -> u16 {
|
pub fn port(&self) -> u16 {
|
||||||
unsafe {
|
unsafe {
|
||||||
u16::from_be(match self.sa.sa_family as u8 {
|
u16::from_be(match self.sa.sa_family as u8 {
|
||||||
|
@ -490,7 +498,6 @@ impl InetAddress {
|
||||||
///
|
///
|
||||||
/// This does nothing on uninitialized InetAddress objects. An address must first
|
/// This does nothing on uninitialized InetAddress objects. An address must first
|
||||||
/// be initialized with an IP to select the correct address type.
|
/// be initialized with an IP to select the correct address type.
|
||||||
#[inline(always)]
|
|
||||||
pub fn set_port(&mut self, port: u16) {
|
pub fn set_port(&mut self, port: u16) {
|
||||||
let port = port.to_be();
|
let port = port.to_be();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -10,14 +10,15 @@ pub mod endpoint;
|
||||||
pub mod identity;
|
pub mod identity;
|
||||||
pub mod inetaddress;
|
pub mod inetaddress;
|
||||||
|
|
||||||
pub(crate) mod address;
|
mod address;
|
||||||
pub(crate) mod dictionary;
|
mod dictionary;
|
||||||
|
mod mac;
|
||||||
|
mod path;
|
||||||
|
mod peer;
|
||||||
|
|
||||||
pub(crate) mod fragmentedpacket;
|
pub(crate) mod fragmentedpacket;
|
||||||
pub(crate) mod hybridkey;
|
pub(crate) mod hybridkey;
|
||||||
pub(crate) mod mac;
|
|
||||||
pub(crate) mod node;
|
pub(crate) mod node;
|
||||||
pub(crate) mod path;
|
|
||||||
pub(crate) mod peer;
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub(crate) mod protocol;
|
pub(crate) mod protocol;
|
||||||
pub(crate) mod symmetricsecret;
|
pub(crate) mod symmetricsecret;
|
||||||
|
@ -32,5 +33,3 @@ pub use mac::MAC;
|
||||||
pub use node::{Node, SystemInterface};
|
pub use node::{Node, SystemInterface};
|
||||||
pub use path::Path;
|
pub use path::Path;
|
||||||
pub use peer::Peer;
|
pub use peer::Peer;
|
||||||
|
|
||||||
pub use protocol::{PACKET_FRAGMENT_COUNT_MAX, PACKET_SIZE_MAX};
|
|
||||||
|
|
|
@ -41,8 +41,8 @@ lazy_static! {
|
||||||
/// for them and uniform application of things like keepalives.
|
/// for them and uniform application of things like keepalives.
|
||||||
pub struct Path {
|
pub struct Path {
|
||||||
endpoint: Mutex<Arc<Endpoint>>,
|
endpoint: Mutex<Arc<Endpoint>>,
|
||||||
local_socket: Option<NonZeroI64>,
|
pub(crate) local_socket: Option<NonZeroI64>,
|
||||||
local_interface: Option<NonZeroI64>,
|
pub(crate) local_interface: Option<NonZeroI64>,
|
||||||
last_send_time_ticks: AtomicI64,
|
last_send_time_ticks: AtomicI64,
|
||||||
last_receive_time_ticks: AtomicI64,
|
last_receive_time_ticks: AtomicI64,
|
||||||
fragmented_packets: Mutex<HashMap<u64, FragmentedPacket, U64NoOpHasher>>,
|
fragmented_packets: Mutex<HashMap<u64, FragmentedPacket, U64NoOpHasher>>,
|
||||||
|
@ -98,26 +98,6 @@ impl Path {
|
||||||
self.endpoint.lock().clone()
|
self.endpoint.lock().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn local_socket(&self) -> Option<NonZeroI64> {
|
|
||||||
self.local_socket
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn local_interface(&self) -> Option<NonZeroI64> {
|
|
||||||
self.local_interface
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn last_send_time_ticks(&self) -> i64 {
|
|
||||||
self.last_send_time_ticks.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn last_receive_time_ticks(&self) -> i64 {
|
|
||||||
self.last_receive_time_ticks.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Receive a fragment and return a FragmentedPacket if the entire packet was assembled.
|
/// Receive a fragment and return a FragmentedPacket if the entire packet was assembled.
|
||||||
/// This returns None if more fragments are needed to assemble the packet.
|
/// This returns None if more fragments are needed to assemble the packet.
|
||||||
pub(crate) fn receive_fragment(&self, packet_id: u64, fragment_no: u8, fragment_expecting_count: u8, packet: PacketBuffer, time_ticks: i64) -> Option<FragmentedPacket> {
|
pub(crate) fn receive_fragment(&self, packet_id: u64, fragment_no: u8, fragment_expecting_count: u8, packet: PacketBuffer, time_ticks: i64) -> Option<FragmentedPacket> {
|
||||||
|
@ -145,31 +125,34 @@ impl Path {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Called when any packet is received.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn log_receive_anything(&self, time_ticks: i64) {
|
pub(crate) fn log_receive_anything(&self, time_ticks: i64) {
|
||||||
self.last_receive_time_ticks.store(time_ticks, Ordering::Relaxed);
|
self.last_receive_time_ticks.store(time_ticks, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Called when a real packet is received and passes authentication checks.
|
||||||
pub(crate) fn log_receive_authenticated_packet(&self, _bytes: usize, source_endpoint: &Endpoint) {
|
pub(crate) fn log_receive_authenticated_packet(&self, _bytes: usize, source_endpoint: &Endpoint) {
|
||||||
let mut replace = false;
|
|
||||||
match source_endpoint {
|
match source_endpoint {
|
||||||
Endpoint::IpUdp(ip) => {
|
Endpoint::IpUdp(ip) => {
|
||||||
let ep = self.endpoint.lock().clone();
|
// If an IPv4 UDP remote IP is the same but the port changes, learn the new port by replacing the
|
||||||
match ep.as_ref() {
|
// endpoint with the new one. This is because IPv4 NATs will occasionally remap IPs at random.
|
||||||
Endpoint::IpUdp(ip_orig) => {
|
if ip.is_ipv4() {
|
||||||
debug_assert!(ip_orig.ip_bytes().eq(ip.ip_bytes()));
|
let mut ep = self.endpoint.lock();
|
||||||
if ip_orig.port() != ip.port() {
|
match ep.as_ref() {
|
||||||
replace = true;
|
Endpoint::IpUdp(ip_orig) => {
|
||||||
|
// These should always be equal because this path would have been looked up by IP, but sanity check in debug.
|
||||||
|
debug_assert_eq!(ip_orig.ip_bytes(), ip.ip_bytes());
|
||||||
|
if ip_orig.port() != ip.port() {
|
||||||
|
(*ep) = Arc::new(source_endpoint.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
if replace {
|
|
||||||
(*self.endpoint.lock()) = Arc::new(source_endpoint.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -178,7 +161,6 @@ impl Path {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const CALL_EVERY_INTERVAL_MS: i64 = PATH_KEEPALIVE_INTERVAL;
|
pub(crate) const CALL_EVERY_INTERVAL_MS: i64 = PATH_KEEPALIVE_INTERVAL;
|
||||||
|
|
||||||
pub(crate) fn call_every_interval<SI: SystemInterface>(&self, _si: &SI, time_ticks: i64) {
|
pub(crate) fn call_every_interval<SI: SystemInterface>(&self, _si: &SI, time_ticks: i64) {
|
||||||
self.fragmented_packets.lock().retain(|_, frag| (time_ticks - frag.ts_ticks) < PACKET_FRAGMENT_EXPIRATION);
|
self.fragmented_packets.lock().retain(|_, frag| (time_ticks - frag.ts_ticks) < PACKET_FRAGMENT_EXPIRATION);
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,7 +221,18 @@ impl 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
|
||||||
/// those fragments after the main packet header and first chunk.
|
/// those fragments after the main packet header and first chunk.
|
||||||
pub(crate) fn receive<SI: SystemInterface, VI: InnerProtocolInterface>(&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: InnerProtocolInterface>(
|
||||||
|
&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 _ = 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() };
|
let mut payload: Buffer<PACKET_SIZE_MAX> = unsafe { Buffer::new_without_memzero() };
|
||||||
|
|
||||||
|
@ -375,7 +386,7 @@ impl Peer {
|
||||||
/// via a root or some other route.
|
/// via a root or some other route.
|
||||||
pub(crate) fn send<SI: SystemInterface>(&self, si: &SI, node: &Node, time_ticks: i64, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool {
|
pub(crate) fn send<SI: SystemInterface>(&self, si: &SI, node: &Node, time_ticks: i64, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool {
|
||||||
self.path(node).map_or(false, |path| {
|
self.path(node).map_or(false, |path| {
|
||||||
if self.send_to_endpoint(si, path.endpoint().as_ref(), path.local_socket(), path.local_interface(), packet) {
|
if self.send_to_endpoint(si, path.endpoint().as_ref(), path.local_socket, path.local_interface, packet) {
|
||||||
self.last_send_time_ticks.store(time_ticks, Ordering::Relaxed);
|
self.last_send_time_ticks.store(time_ticks, Ordering::Relaxed);
|
||||||
self.total_bytes_sent.fetch_add(packet.len() as u64, Ordering::Relaxed);
|
self.total_bytes_sent.fetch_add(packet.len() as u64, Ordering::Relaxed);
|
||||||
true
|
true
|
||||||
|
@ -394,7 +405,7 @@ impl Peer {
|
||||||
/// Intermediates don't need to adjust fragmentation.
|
/// Intermediates don't need to adjust fragmentation.
|
||||||
pub(crate) fn forward<SI: SystemInterface>(&self, si: &SI, time_ticks: i64, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool {
|
pub(crate) fn forward<SI: SystemInterface>(&self, si: &SI, time_ticks: i64, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool {
|
||||||
self.direct_path().map_or(false, |path| {
|
self.direct_path().map_or(false, |path| {
|
||||||
if si.wire_send(path.endpoint().as_ref(), path.local_socket(), path.local_interface(), &[packet.as_bytes()], 0) {
|
if si.wire_send(path.endpoint().as_ref(), path.local_socket, path.local_interface, &[packet.as_bytes()], 0) {
|
||||||
self.last_forward_time_ticks.store(time_ticks, Ordering::Relaxed);
|
self.last_forward_time_ticks.store(time_ticks, Ordering::Relaxed);
|
||||||
self.total_bytes_forwarded.fetch_add(packet.len() as u64, Ordering::Relaxed);
|
self.total_bytes_forwarded.fetch_add(packet.len() as u64, Ordering::Relaxed);
|
||||||
true
|
true
|
||||||
|
@ -517,7 +528,7 @@ impl Peer {
|
||||||
path.map_or_else(
|
path.map_or_else(
|
||||||
|| self.send_to_endpoint(si, &destination, None, None, &packet),
|
|| self.send_to_endpoint(si, &destination, None, None, &packet),
|
||||||
|p| {
|
|p| {
|
||||||
if self.send_to_endpoint(si, &destination, p.local_socket(), p.local_interface(), &packet) {
|
if self.send_to_endpoint(si, &destination, p.local_socket, p.local_interface, &packet) {
|
||||||
p.log_send_anything(time_ticks);
|
p.log_send_anything(time_ticks);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
use crate::util::buffer::{Buffer, RawObject};
|
use crate::util::buffer::{Buffer, FlatBlob};
|
||||||
use crate::vl1::Address;
|
use crate::vl1::Address;
|
||||||
|
|
||||||
pub const VERB_VL1_NOP: u8 = 0x00;
|
pub const VERB_VL1_NOP: u8 = 0x00;
|
||||||
|
@ -220,7 +220,7 @@ pub struct PacketHeader {
|
||||||
pub mac: [u8; 8],
|
pub mac: [u8; 8],
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl RawObject for PacketHeader {}
|
unsafe impl FlatBlob for PacketHeader {}
|
||||||
|
|
||||||
impl PacketHeader {
|
impl PacketHeader {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -284,7 +284,7 @@ pub struct FragmentHeader {
|
||||||
pub reserved_hops: u8, // rrrrrHHH (3 hops bits, rest reserved)
|
pub reserved_hops: u8, // rrrrrHHH (3 hops bits, rest reserved)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl RawObject for FragmentHeader {}
|
unsafe impl FlatBlob for FragmentHeader {}
|
||||||
|
|
||||||
impl FragmentHeader {
|
impl FragmentHeader {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -322,7 +322,7 @@ impl FragmentHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod message_component_structs {
|
pub(crate) mod message_component_structs {
|
||||||
use crate::util::buffer::RawObject;
|
use crate::util::buffer::FlatBlob;
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct OkHeader {
|
pub struct OkHeader {
|
||||||
|
@ -330,7 +330,7 @@ pub(crate) mod message_component_structs {
|
||||||
pub in_re_message_id: [u8; 8],
|
pub in_re_message_id: [u8; 8],
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl RawObject for OkHeader {}
|
unsafe impl FlatBlob for OkHeader {}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct ErrorHeader {
|
pub struct ErrorHeader {
|
||||||
|
@ -339,7 +339,7 @@ pub(crate) mod message_component_structs {
|
||||||
pub error_code: u8,
|
pub error_code: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl RawObject for ErrorHeader {}
|
unsafe impl FlatBlob for ErrorHeader {}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct HelloFixedHeaderFields {
|
pub struct HelloFixedHeaderFields {
|
||||||
|
@ -351,7 +351,7 @@ pub(crate) mod message_component_structs {
|
||||||
pub timestamp: [u8; 8], // u64
|
pub timestamp: [u8; 8], // u64
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl RawObject for HelloFixedHeaderFields {}
|
unsafe impl FlatBlob for HelloFixedHeaderFields {}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct OkHelloFixedHeaderFields {
|
pub struct OkHelloFixedHeaderFields {
|
||||||
|
@ -362,7 +362,7 @@ pub(crate) mod message_component_structs {
|
||||||
pub version_revision: [u8; 2], // u16
|
pub version_revision: [u8; 2], // u16
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl RawObject for OkHelloFixedHeaderFields {}
|
unsafe impl FlatBlob for OkHelloFixedHeaderFields {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Add table
Reference in a new issue