From a23bd89202638a8b7acf5ec3c945a12090dfcf7c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 29 Sep 2021 12:48:36 -0400 Subject: [PATCH] Formatting, build fixes, tests. --- network-hypervisor/src/crypto/hash.rs | 8 +--- network-hypervisor/src/crypto/poly1305.rs | 1 + network-hypervisor/src/crypto/random.rs | 17 +++----- network-hypervisor/src/crypto/salsa.rs | 1 + network-hypervisor/src/util/gate.rs | 42 ++++++++---------- network-hypervisor/src/util/mod.rs | 1 + network-hypervisor/src/util/varint.rs | 53 +++++++++++++++++++++++ network-hypervisor/src/vl1/address.rs | 13 +++++- network-hypervisor/src/vl1/buffer.rs | 30 ++----------- network-hypervisor/src/vl1/dictionary.rs | 13 +----- network-hypervisor/src/vl1/locator.rs | 22 ++++++++-- network-hypervisor/src/vl1/mac.rs | 10 +++-- network-hypervisor/src/vl1/rootset.rs | 2 - 13 files changed, 124 insertions(+), 89 deletions(-) create mode 100644 network-hypervisor/src/util/varint.rs diff --git a/network-hypervisor/src/crypto/hash.rs b/network-hypervisor/src/crypto/hash.rs index 955424e12..562bab02f 100644 --- a/network-hypervisor/src/crypto/hash.rs +++ b/network-hypervisor/src/crypto/hash.rs @@ -55,9 +55,7 @@ impl Write for SHA512 { } #[inline(always)] - fn flush(&mut self) -> std::io::Result<()> { - self.0.flush() - } + fn flush(&mut self) -> std::io::Result<()> { self.0.flush() } } pub struct SHA384(gcrypt::digest::MessageDigest); @@ -110,7 +108,5 @@ impl Write for SHA384 { } #[inline(always)] - fn flush(&mut self) -> std::io::Result<()> { - self.0.flush() - } + fn flush(&mut self) -> std::io::Result<()> { self.0.flush() } } diff --git a/network-hypervisor/src/crypto/poly1305.rs b/network-hypervisor/src/crypto/poly1305.rs index a5f49cb9f..ae1108f5d 100644 --- a/network-hypervisor/src/crypto/poly1305.rs +++ b/network-hypervisor/src/crypto/poly1305.rs @@ -1,3 +1,4 @@ +/// The poly1305 message authentication function. pub struct Poly1305(gcrypt::mac::Mac); pub const POLY1305_ONE_TIME_KEY_SIZE: usize = 32; diff --git a/network-hypervisor/src/crypto/random.rs b/network-hypervisor/src/crypto/random.rs index dbfd3f047..d44af1f74 100644 --- a/network-hypervisor/src/crypto/random.rs +++ b/network-hypervisor/src/crypto/random.rs @@ -2,13 +2,12 @@ use rand_core::{RngCore, Error}; use rand_core::CryptoRng; use gcrypt::rand::{Level, randomize}; +/// Secure random source based on the desired third party library (gcrypt). pub struct SecureRandom; impl SecureRandom { #[inline(always)] - pub fn get() -> Self { - Self - } + pub fn get() -> Self { Self } } impl RngCore for SecureRandom { @@ -27,9 +26,7 @@ impl RngCore for SecureRandom { } #[inline(always)] - fn fill_bytes(&mut self, dest: &mut [u8]) { - randomize(Level::Strong, dest); - } + fn fill_bytes(&mut self, dest: &mut [u8]) { randomize(Level::Strong, dest); } #[inline(always)] fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { @@ -41,20 +38,18 @@ impl RngCore for SecureRandom { impl CryptoRng for SecureRandom {} #[inline(always)] -pub(crate) fn next_u32_secure() -> u32 { +pub fn next_u32_secure() -> u32 { let mut tmp = 0_u32; randomize(Level::Strong, unsafe { &mut *(&mut tmp as *mut u32).cast::<[u8; 4]>() }); tmp } #[inline(always)] -pub(crate) fn next_u64_secure() -> u64 { +pub fn next_u64_secure() -> u64 { let mut tmp = 0_u64; randomize(Level::Strong, unsafe { &mut *(&mut tmp as *mut u64).cast::<[u8; 8]>() }); tmp } #[inline(always)] -pub(crate) fn fill_bytes_secure(dest: &mut [u8]) { - randomize(Level::Strong, dest); -} +pub fn fill_bytes_secure(dest: &mut [u8]) { randomize(Level::Strong, dest); } diff --git a/network-hypervisor/src/crypto/salsa.rs b/network-hypervisor/src/crypto/salsa.rs index ef4195898..5c22d202a 100644 --- a/network-hypervisor/src/crypto/salsa.rs +++ b/network-hypervisor/src/crypto/salsa.rs @@ -1,3 +1,4 @@ +/// The classic Salsa20 stream cipher supporting 20-round and 12-round variants. pub struct Salsa(gcrypt::cipher::Cipher); impl Salsa { diff --git a/network-hypervisor/src/util/gate.rs b/network-hypervisor/src/util/gate.rs index eca35262f..abfde2587 100644 --- a/network-hypervisor/src/util/gate.rs +++ b/network-hypervisor/src/util/gate.rs @@ -11,14 +11,10 @@ impl Default for IntervalGate { impl IntervalGate { #[inline(always)] - pub fn new(initial_ts: i64) -> Self { - Self(initial_ts) - } + pub fn new(initial_ts: i64) -> Self { Self(initial_ts) } #[inline(always)] - pub fn reset(&mut self) { - self.0 = 0; - } + pub fn reset(&mut self) { self.0 = 0; } #[inline(always)] pub fn gate(&mut self, time: i64) -> bool { @@ -35,33 +31,31 @@ impl IntervalGate { pub struct AtomicIntervalGate(AtomicI64); impl Default for AtomicIntervalGate { - fn default() -> Self { - Self(AtomicI64::new(0)) - } + fn default() -> Self { Self(AtomicI64::new(0)) } } impl AtomicIntervalGate { #[inline(always)] - pub fn new(initial_ts: i64) -> Self { - Self(AtomicI64::new(initial_ts)) - } + pub fn new(initial_ts: i64) -> Self { Self(AtomicI64::new(initial_ts)) } #[inline(always)] - pub fn reset(&self) { - self.0.store(0, Ordering::Relaxed); - } + pub fn reset(&self) { self.0.store(0, Ordering::Relaxed); } #[inline(always)] - pub fn gate(&self, time: i64) -> bool { - // Note that if two or more threads are using this at once, any thread's time might - // end up being the one stored. This is okay since these times should either be the - // same or very close, and slight differences won't cause issues with the use cases - // for this. This is primarily used to rate gate operations to prevent DOS attacks. - if (time - self.0.load(Ordering::Relaxed)) >= FREQ { - self.0.store(time, Ordering::Relaxed); - true - } else { + pub fn gate(&self, mut time: i64) -> bool { + let prev_time = self.0.load(Ordering::Relaxed); + if (time - prev_time) < FREQ { false + } else { + loop { + let pt = self.0.swap(time, Ordering::Relaxed); + if pt <= time { + break; + } else { + time = pt; + } + } + true } } } diff --git a/network-hypervisor/src/util/mod.rs b/network-hypervisor/src/util/mod.rs index 0ca2d89f0..0cede85e8 100644 --- a/network-hypervisor/src/util/mod.rs +++ b/network-hypervisor/src/util/mod.rs @@ -1,6 +1,7 @@ pub mod hex; pub mod pool; pub mod gate; +pub mod varint; pub(crate) const ZEROES: [u8; 64] = [0_u8; 64]; diff --git a/network-hypervisor/src/util/varint.rs b/network-hypervisor/src/util/varint.rs new file mode 100644 index 000000000..ff71da34d --- /dev/null +++ b/network-hypervisor/src/util/varint.rs @@ -0,0 +1,53 @@ +use std::io::{Read, Write}; + +pub fn write(w: &mut W, mut v: u64) -> std::io::Result<()> { + let mut b = [0_u8; 10]; + let mut i = 10; + loop { + if v > 0x7f { + i -= 1; + b[i] = (v as u8) & 0x7f; + v >>= 7; + } else { + i -= 1; + b[i] = (v as u8) | 0x80; + break; + } + } + w.write_all(&b[i..]) +} + +pub fn read(r: &mut R) -> std::io::Result { + let mut v = 0_u64; + let mut buf = [0_u8; 1]; + loop { + v <<= 7; + let _ = r.read_exact(&mut buf)?; + let b = buf[0]; + if b <= 0x7f { + v |= b as u64; + } else { + v |= (b & 0x7f) as u64; + return Ok(v); + } + } +} + +pub(crate) fn read_from_bytes(r: &[u8], cursor: &mut usize) -> std::io::Result { + let mut v = 0_u64; + let mut c = *cursor; + while c < r.len() { + v <<= 7; + let b = unsafe { *r.get_unchecked(c) }; + c += 1; + if b <= 0x7f { + v |= b as u64; + } else { + v |= (b & 0x7f) as u64; + *cursor = c; + return Ok(v); + } + } + *cursor = c; + return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "incomplete varint")); +} diff --git a/network-hypervisor/src/vl1/address.rs b/network-hypervisor/src/vl1/address.rs index 74d432766..79a21066d 100644 --- a/network-hypervisor/src/vl1/address.rs +++ b/network-hypervisor/src/vl1/address.rs @@ -23,7 +23,6 @@ impl Address { } } - /// Get an address from a byte slice or return None if it is zero or reserved. #[inline(always)] pub fn from_bytes(b: &[u8]) -> Option
{ if b.len() >= ADDRESS_SIZE { @@ -38,6 +37,16 @@ impl Address { } } + #[inline(always)] + pub fn from_bytes_fixed(b: &[u8; ADDRESS_SIZE]) -> Option
{ + let i = (b[0] as u64) << 32 | (b[1] as u64) << 24 | (b[2] as u64) << 16 | (b[3] as u64) << 8 | b[4] as u64; + if i != 0 && (i >> 32) != ADDRESS_RESERVED_PREFIX as u64 { + Some(Address(unsafe { NonZeroU64::new_unchecked(i) })) + } else { + None + } + } + #[inline(always)] pub fn to_bytes(&self) -> [u8; ADDRESS_SIZE] { let i = self.0.get(); @@ -61,7 +70,7 @@ impl Address { #[inline(always)] pub(crate) fn unmarshal(buf: &Buffer, cursor: &mut usize) -> std::io::Result> { - buf.read_bytes_fixed::<{ ADDRESS_SIZE }>(cursor).map(|b| Self::from_bytes(b)) + buf.read_bytes_fixed::<{ ADDRESS_SIZE }>(cursor).map(|b| Self::from_bytes_fixed(b)) } } diff --git a/network-hypervisor/src/vl1/buffer.rs b/network-hypervisor/src/vl1/buffer.rs index 6f4f3b95b..d267d6580 100644 --- a/network-hypervisor/src/vl1/buffer.rs +++ b/network-hypervisor/src/vl1/buffer.rs @@ -28,7 +28,6 @@ impl Buffer { pub fn new() -> Self { Self(0, [0_u8; L]) } /// Get a Buffer initialized with a copy of a byte slice. - #[inline(always)] pub fn from_bytes(b: &[u8]) -> std::io::Result { let l = b.len(); if l <= L { @@ -165,19 +164,9 @@ impl Buffer { } /// Append a variable length integer to this buffer. - /// - /// Varints are encoded as a series of 7-bit bytes terminated by a final 7-bit byte whose - /// most significant bit is set. Unlike fixed size integers varints are written in little - /// endian order (in 7-bit chunks). - /// - /// They are slower than fixed size values so they should not be used in formats that are - /// created or parsed in very speed-critical paths. + #[inline(always)] pub fn append_varint(&mut self, mut i: u64) -> std::io::Result<()> { - while i >= 0x80 { - self.append_u8((i as u8) & 0x7f)?; - i >>= 7; - } - self.append_u8((i as u8) | 0x80) + crate::util::varint::write(self, i) } /// Append a byte @@ -317,20 +306,9 @@ impl Buffer { } /// Get the next variable length integer and advance the cursor by its length in bytes. + #[inline(always)] pub fn read_varint(&self, cursor: &mut usize) -> std::io::Result { - let mut i = 0_u64; - let mut p = 0; - loop { - let b = self.read_u8(cursor)?; - if (b & 0x80) == 0 { - i |= (b as u64).wrapping_shl(p); - p += 7; - } else { - i |= ((b & 0x7f) as u64) << p; - break; - } - } - Ok(i) + crate::util::varint::read_from_bytes(&(self.1[self.0..]), cursor) } /// Get the next u8 and advance the cursor. diff --git a/network-hypervisor/src/vl1/dictionary.rs b/network-hypervisor/src/vl1/dictionary.rs index 56f84e6ed..3cc905f9d 100644 --- a/network-hypervisor/src/vl1/dictionary.rs +++ b/network-hypervisor/src/vl1/dictionary.rs @@ -71,16 +71,7 @@ impl Dictionary { } pub fn get_bool(&self, k: &str) -> Option { - self.0.get(k).map_or(None, |v| { - if v.is_empty() { - Some(false) - } else { - Some(match v[0] { - b'1' | b't' | b'T' | b'y' | b'Y' => true, - _ => false - }) - } - }) + self.0.get(k).map_or(None, |v| v.first().map_or(Some(false), |c| Some("1tTyY".contains(*c as char)))) } pub fn set_str(&mut self, k: &str, v: &str) { @@ -96,7 +87,7 @@ impl Dictionary { } pub fn set_bool(&mut self, k: &str, v: bool) { - let _ = self.0.insert(String::from(k), (if v { [b'1'] } else { [b'0'] }).to_vec()); + let _ = self.0.insert(String::from(k), vec![if v { b'1' } else { b'0' }]); } /// Write a dictionary in transport format to a writer. diff --git a/network-hypervisor/src/vl1/locator.rs b/network-hypervisor/src/vl1/locator.rs index a1792775e..946880c3f 100644 --- a/network-hypervisor/src/vl1/locator.rs +++ b/network-hypervisor/src/vl1/locator.rs @@ -1,7 +1,7 @@ use std::cmp::Ordering; use std::hash::{Hash, Hasher}; -use crate::vl1::{Address, Endpoint, Identity}; +use crate::vl1::{Address, Endpoint, Identity, Dictionary}; use crate::vl1::buffer::Buffer; use crate::vl1::protocol::PACKET_SIZE_MAX; @@ -15,6 +15,7 @@ pub struct Locator { pub subject: Address, pub signer: Address, pub timestamp: i64, + pub metadata: Option, pub endpoints: Vec, pub signature: Vec, } @@ -34,6 +35,7 @@ impl Locator { subject, signer: signer_identity.address(), timestamp: ts, + metadata: None, endpoints: endpoints.to_vec(), signature: Vec::new() }; @@ -81,12 +83,16 @@ impl Locator { fn marshal_internal(&self, buf: &mut Buffer, exclude_signature: bool) -> std::io::Result<()> { self.subject.marshal(buf)?; self.signer.marshal(buf)?; - buf.append_u64(self.timestamp as u64)?; + buf.append_varint(self.timestamp as u64)?; + self.metadata.map_or_else(|| buf.append_varint(0), |d| { + let db = d.to_bytes(); + buf.append_varint(db.len() as u64)?; + buf.append_bytes(db.as_slice()) + })?; buf.append_varint(self.endpoints.len() as u64)?; for e in self.endpoints.iter() { e.marshal(buf)?; } - buf.append_varint(0)?; // length of any additional fields if !exclude_signature { buf.append_varint(self.signature.len() as u64)?; buf.append_bytes(self.signature.as_slice())?; @@ -104,18 +110,26 @@ impl Locator { return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid subject or signer address")); } let timestamp = buf.read_u64(cursor)? as i64; + let metadata_size = buf.read_varint(cursor)? as usize; + let metadata = if metadata_size > 0 { + let md = Dictionary::from_bytes(buf.read_bytes(metadata_size, cursor)?); + if md.is_none() { + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid meta-data")); + } + md + } else { None }; let endpoint_count = buf.read_varint(cursor)? as usize; let mut endpoints: Vec = Vec::new(); for _ in 0..endpoint_count { endpoints.push(Endpoint::unmarshal(buf, cursor)?); } - *cursor += buf.read_varint(cursor)? as usize; let signature_len = buf.read_varint(cursor)? as usize; let signature = buf.read_bytes(signature_len, cursor)?; Ok(Locator { subject: subject.unwrap(), signer: signer.unwrap(), timestamp, + metadata, endpoints, signature: signature.to_vec(), }) diff --git a/network-hypervisor/src/vl1/mac.rs b/network-hypervisor/src/vl1/mac.rs index fb7b1d061..70146b189 100644 --- a/network-hypervisor/src/vl1/mac.rs +++ b/network-hypervisor/src/vl1/mac.rs @@ -16,12 +16,17 @@ impl MAC { #[inline(always)] pub fn from_bytes(b: &[u8]) -> Option { if b.len() >= 6 { - 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))) + 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(|i| MAC(i)) } else { None } } + #[inline(always)] + pub fn from_bytes_fixed(b: &[u8; 6]) -> Option { + 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(|i| MAC(i)) + } + #[inline(always)] pub fn to_bytes(&self) -> [u8; 6] { let i = self.0.get(); @@ -31,7 +36,6 @@ impl MAC { #[inline(always)] pub fn to_u64(&self) -> u64 { self.0.get() } - #[inline(always)] pub(crate) fn marshal(&self, buf: &mut Buffer) -> std::io::Result<()> { buf.append_and_init_bytes_fixed(|b: &mut [u8; 6]| { let i = self.0.get(); @@ -46,7 +50,7 @@ impl MAC { #[inline(always)] pub(crate) fn unmarshal(buf: &Buffer, cursor: &mut usize) -> std::io::Result> { - buf.read_bytes_fixed::<6>(cursor).map(|b| Self::from_bytes(b)) + buf.read_bytes_fixed::<6>(cursor).map(|b| Self::from_bytes_fixed(b)) } } diff --git a/network-hypervisor/src/vl1/rootset.rs b/network-hypervisor/src/vl1/rootset.rs index 8a256a74d..e5c47fe8e 100644 --- a/network-hypervisor/src/vl1/rootset.rs +++ b/network-hypervisor/src/vl1/rootset.rs @@ -296,13 +296,11 @@ mod tests { #[test] fn default_root_set() { let rs = RootSet::from_bytes(&crate::defaults::ROOT_SET).unwrap(); - /* rs.roots.iter().for_each(|r| { println!("{}", r.identity.to_string()); r.endpoints.iter().for_each(|ep| { println!(" {}", ep.to_string()); }); }); - */ } }