diff --git a/network-hypervisor/src/defaults.rs b/network-hypervisor/src/defaults.rs new file mode 100644 index 000000000..45fdc11ef --- /dev/null +++ b/network-hypervisor/src/defaults.rs @@ -0,0 +1,9 @@ +/// Default root set that uses ZeroTier's own global roots. +pub const ROOT_SET: [u8; 570] = [ 0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x78,0xcc,0x8e,0xf8,0xcb,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x31,0xdc,0x40,0xa9,0xc7,0xb5,0xd2,0xf9,0x8e,0xd9,0x7b,0xf6,0x41,0x27,0x29,0x02,0xb6,0xb3,0x34,0x6f,0x56,0x16,0x11,0x45,0x82,0x44,0x55,0x85,0x78,0x79,0xb9,0x30,0xcb,0x01,0x51,0x15,0x49,0xf3,0x38,0x24,0xd8,0xd4,0x78,0x7d,0x77,0x23,0xda,0xc3,0x51,0x50,0x0b,0xe7,0xdf,0x5b,0x8f,0x72,0xdd,0x25,0x81,0xa5,0x0b,0x4a,0x36,0x01,0x46,0x85,0x95,0xbe,0x4d,0x5e,0xe6,0x3b,0x46,0xc2,0x9b,0x15,0x3c,0x43,0x8a,0x30,0xe0,0xa2,0xbf,0xba,0x1a,0x57,0xfc,0x98,0x7b,0x42,0x71,0xde,0x9c,0x53,0x6c,0x00,0x04,0x61,0xd2,0x94,0xb9,0xcb,0x00,0xe6,0x53,0xef,0x7a,0xd9,0x25,0x59,0x52,0xb7,0xc9,0xfc,0xa1,0x68,0x6d,0x3b,0x17,0xc6,0x10,0xb0,0x4e,0x6b,0x6c,0x82,0xd2,0xd3,0x7c,0xd3,0xa6,0xef,0xb2,0x56,0x3d,0x57,0x7f,0x81,0x22,0x24,0x37,0x62,0x02,0x09,0xe9,0x23,0x48,0xad,0x33,0x7b,0xd1,0x91,0xac,0x00,0xb7,0x49,0x2c,0xfd,0x55,0xce,0x0f,0xa0,0x36,0xd8,0xc5,0x62,0x83,0x00,0x02,0x04,0x32,0x07,0x49,0x22,0x27,0x09,0x06,0x20,0x01,0x49,0xf0,0xd0,0x02,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x77,0x8c,0xde,0x71,0x90,0x00,0x3f,0x66,0x81,0xa9,0x9e,0x5a,0xd1,0x89,0x5e,0x9f,0xba,0x33,0xe6,0x21,0x2d,0x44,0x54,0xe1,0x68,0xbc,0xec,0x71,0x12,0x10,0x1b,0xf0,0x00,0x95,0x6e,0xd8,0xe9,0x2e,0x42,0x89,0x2c,0xb6,0xf2,0xec,0x41,0x08,0x81,0xa8,0x4a,0xb1,0x9d,0xa5,0x0e,0x12,0x87,0xba,0x3d,0x92,0x6c,0x3a,0x1f,0x75,0x5c,0xcc,0xf2,0x99,0xa1,0x20,0x70,0x55,0x00,0x02,0x04,0x67,0xc3,0x67,0x42,0x27,0x09,0x06,0x26,0x05,0x98,0x80,0x04,0x00,0x00,0xc3,0x02,0x54,0xf2,0xbc,0xa1,0xf7,0x00,0x19,0x27,0x09,0x62,0xf8,0x65,0xae,0x71,0x00,0xe2,0x07,0x6c,0x57,0xde,0x87,0x0e,0x62,0x88,0xd7,0xd5,0xe7,0x40,0x44,0x08,0xb1,0x54,0x5e,0xfc,0xa3,0x7d,0x67,0xf7,0x7b,0x87,0xe9,0xe5,0x41,0x68,0xc2,0x5d,0x3e,0xf1,0xa9,0xab,0xf2,0x90,0x5e,0xa5,0xe7,0x85,0xc0,0x1d,0xff,0x23,0x88,0x7a,0xd4,0x23,0x2d,0x95,0xc7,0xa8,0xfd,0x2c,0x27,0x11,0x1a,0x72,0xbd,0x15,0x93,0x22,0xdc,0x00,0x02,0x04,0x32,0x07,0xfc,0x8a,0x27,0x09,0x06,0x20,0x01,0x49,0xf0,0xd0,0xdb,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x99,0x2f,0xcf,0x1d,0xb7,0x00,0x20,0x6e,0xd5,0x93,0x50,0xb3,0x19,0x16,0xf7,0x49,0xa1,0xf8,0x5d,0xff,0xb3,0xa8,0x78,0x7d,0xcb,0xf8,0x3b,0x8c,0x6e,0x94,0x48,0xd4,0xe3,0xea,0x0e,0x33,0x69,0x30,0x1b,0xe7,0x16,0xc3,0x60,0x93,0x44,0xa9,0xd1,0x53,0x38,0x50,0xfb,0x44,0x60,0xc5,0x0a,0xf4,0x33,0x22,0xbc,0xfc,0x8e,0x13,0xd3,0x30,0x1a,0x1f,0x10,0x03,0xce,0xb6,0x00,0x02,0x04,0xc3,0xb5,0xad,0x9f,0x27,0x09,0x06,0x2a,0x02,0x6e,0xa0,0xc0,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x09 ]; + +/// Default maximum payload size for UDP transport. +/// +/// This is small enough to traverse numerous weird networks including PPPoE and Google Cloud's +/// weird exit MTU restriction, but is large enough that a standard 2800 byte frame creates only +/// two fragments. +pub const UDP_DEFAULT_MTU: usize = 1432; diff --git a/network-hypervisor/src/lib.rs b/network-hypervisor/src/lib.rs index 42c5687e6..9a1008eb4 100644 --- a/network-hypervisor/src/lib.rs +++ b/network-hypervisor/src/lib.rs @@ -3,6 +3,7 @@ pub mod util; pub mod error; pub mod vl1; pub mod vl2; +pub mod defaults; pub const VERSION_MAJOR: u8 = 1; pub const VERSION_MINOR: u8 = 99; diff --git a/network-hypervisor/src/vl1/fragmentedpacket.rs b/network-hypervisor/src/vl1/fragmentedpacket.rs index d5038febb..f410c5ab6 100644 --- a/network-hypervisor/src/vl1/fragmentedpacket.rs +++ b/network-hypervisor/src/vl1/fragmentedpacket.rs @@ -1,5 +1,5 @@ use crate::vl1::node::PacketBuffer; -use crate::vl1::constants::FRAGMENT_COUNT_MAX; +use crate::vl1::protocol::FRAGMENT_COUNT_MAX; /// Packet fragment re-assembler and container. /// This is only used in the receive path. diff --git a/network-hypervisor/src/vl1/identity.rs b/network-hypervisor/src/vl1/identity.rs index d9289f4f8..1419fa651 100644 --- a/network-hypervisor/src/vl1/identity.rs +++ b/network-hypervisor/src/vl1/identity.rs @@ -594,10 +594,7 @@ impl FromStr for Identity { impl PartialEq for Identity { fn eq(&self, other: &Self) -> bool { - self.address.eq(&other.address) && - self.c25519.eq(&other.c25519) && - self.ed25519.eq(&other.ed25519) && - self.v1.as_ref().map_or_else(|| other.v1.is_none(), |v1| other.v1.as_ref().map_or(false, |other_v1| (*v1).0.eq(&(*other_v1).0) && (*v1).1.eq(&(*other_v1).1))) + self.address.eq(&other.address) && self.c25519.eq(&other.c25519) && self.ed25519.eq(&other.ed25519) && self.v1.as_ref().map_or_else(|| other.v1.is_none(), |v1| other.v1.as_ref().map_or(false, |other_v1| (*v1).0.eq(&(*other_v1).0) && (*v1).1.eq(&(*other_v1).1))) } } diff --git a/network-hypervisor/src/vl1/locator.rs b/network-hypervisor/src/vl1/locator.rs index 6bace8080..224e94b1f 100644 --- a/network-hypervisor/src/vl1/locator.rs +++ b/network-hypervisor/src/vl1/locator.rs @@ -149,15 +149,6 @@ impl Locator { signature: signature.to_vec(), }) } - - pub fn to_bytes(&self) -> Option> { - let mut buf: Buffer<{ PACKET_SIZE_MAX }> = Buffer::new(); - if self.marshal_internal(&mut buf, false).is_ok() { - Some(buf.as_bytes().to_vec()) - } else { - None - } - } } impl Hash for Locator { diff --git a/network-hypervisor/src/vl1/node.rs b/network-hypervisor/src/vl1/node.rs index 1532c8ee6..a01468f44 100644 --- a/network-hypervisor/src/vl1/node.rs +++ b/network-hypervisor/src/vl1/node.rs @@ -11,7 +11,7 @@ use crate::util::gate::IntervalGate; use crate::util::pool::{Pool, Pooled}; use crate::vl1::{Address, Endpoint, Identity, Locator}; use crate::vl1::buffer::{Buffer, PooledBufferFactory}; -use crate::vl1::constants::{PACKET_SIZE_MAX, FORWARD_MAX_HOPS}; +use crate::vl1::constants::*; use crate::vl1::path::Path; use crate::vl1::peer::Peer; use crate::vl1::protocol::*; @@ -67,7 +67,7 @@ pub trait VL1CallerInterface { /// If packet TTL is non-zero it should be used to set the packet TTL for outgoing packets /// for supported protocols such as UDP, but otherwise it can be ignored. It can also be /// ignored if the platform does not support setting the TTL. - fn wire_send(&self, endpoint: &Endpoint, local_socket: Option, local_interface: Option, data: PacketBuffer, packet_ttl: u8) -> bool; + fn wire_send(&self, endpoint: &Endpoint, local_socket: Option, local_interface: Option, data: &[&[u8]], packet_ttl: u8) -> bool; /// Called to check and see if a physical address should be used for ZeroTier traffic to a node. fn check_path(&self, id: &Identity, endpoint: &Endpoint, local_socket: Option, local_interface: Option) -> bool; @@ -268,7 +268,7 @@ impl Node { let source = Address::from(&packet_header.src); let peer = self.peer(source); if peer.is_some() { - peer.unwrap().receive(self, ci, ph, time_ticks, &path, &packet_header, frag0.as_ref(), &assembled_packet.frags[1..(assembled_packet.have as usize)]); + peer.unwrap().receive(self, ci, ph, time_ticks, &path, &packet_header, frag0, &assembled_packet.frags[1..(assembled_packet.have as usize)]); } else { self.whois.query(self, ci, source, Some(QueuedPacket::Fragmented(assembled_packet))); } diff --git a/network-hypervisor/src/vl1/peer.rs b/network-hypervisor/src/vl1/peer.rs index 45126930c..cd1cc6b15 100644 --- a/network-hypervisor/src/vl1/peer.rs +++ b/network-hypervisor/src/vl1/peer.rs @@ -1,24 +1,28 @@ +use std::convert::TryInto; +use std::mem::MaybeUninit; use std::sync::Arc; use std::sync::atomic::{AtomicI64, AtomicU64, AtomicU8, Ordering}; use parking_lot::Mutex; -use aes_gmac_siv::{AesGmacSiv, AesCtr}; +use aes_gmac_siv::{AesCtr, AesGmacSiv}; + +use crate::{VERSION_MAJOR, VERSION_MINOR, VERSION_PROTO, VERSION_REVISION}; use crate::crypto::c25519::C25519KeyPair; +use crate::crypto::hash::SHA384; use crate::crypto::kbkdf::zt_kbkdf_hmac_sha384; use crate::crypto::p521::P521KeyPair; use crate::crypto::poly1305::Poly1305; use crate::crypto::random::next_u64_secure; use crate::crypto::salsa::Salsa; use crate::crypto::secret::Secret; +use crate::defaults::UDP_DEFAULT_MTU; use crate::util::pool::{Pool, PoolFactory}; -use crate::vl1::{Identity, Path, Endpoint, InetAddress, Dictionary}; +use crate::vl1::{Dictionary, Endpoint, Identity, InetAddress, Path}; use crate::vl1::buffer::Buffer; use crate::vl1::constants::*; use crate::vl1::node::*; use crate::vl1::protocol::*; -use crate::{VERSION_PROTO, VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION}; -use crate::crypto::hash::SHA384; struct AesGmacSivPoolFactory(Secret<48>, Secret<48>); @@ -117,6 +121,7 @@ pub struct Peer { /// is different the key will be wrong and MAC will fail. /// /// This is only used for Salsa/Poly modes. +#[inline(always)] fn salsa_derive_per_packet_key(key: &Secret<48>, header: &PacketHeader, packet_size: usize) -> Secret<48> { let hb = header.as_bytes(); let mut k = key.clone(); @@ -130,8 +135,9 @@ fn salsa_derive_per_packet_key(key: &Secret<48>, header: &PacketHeader, packet_s } /// Create initialized instances of Salsa20/12 and Poly1305 for a packet. +#[inline(always)] fn salsa_poly_create(secret: &PeerSecret, header: &PacketHeader, packet_size: usize) -> (Salsa, Poly1305) { - let key = salsa_derive_per_packet_key(&secret.secret, header, payload.len()); + let key = salsa_derive_per_packet_key(&secret.secret, header, packet_size); let mut salsa = Salsa::new(&key.0[0..32], header.id_bytes(), true).unwrap(); let mut poly1305_key = [0_u8; 32]; salsa.crypt_in_place(&mut poly1305_key); @@ -304,6 +310,54 @@ impl Peer { self.paths.lock().last().map(|p| p.clone()) } + /// Send a packet as one or more UDP fragments. + /// + /// Calling this with anything other than a UDP endpoint is invalid. + fn send_udp(&self, ci: &CI, endpoint: &Endpoint, local_socket: Option, local_interface: Option, packet_id: PacketID, data: &Buffer<{ PACKET_SIZE_MAX }>) -> bool { + debug_assert!(matches!(endpoint, Endpoint::IpUdp(_))); + debug_assert!(data.len() <= PACKET_SIZE_MAX); + + let packet_size = data.len(); + if packet_size > UDP_DEFAULT_MTU { + let bytes = data.as_bytes(); + if !ci.wire_send(endpoint, local_socket, local_interface, &[&bytes[0..UDP_DEFAULT_MTU]], 0) { + return false; + } + + let mut pos = UDP_DEFAULT_MTU; + + let fragment_count = (((packet_size - UDP_DEFAULT_MTU) as u32) / ((UDP_DEFAULT_MTU - FRAGMENT_HEADER_SIZE) as u32)) + ((((packet_size - UDP_DEFAULT_MTU) as u32) % ((UDP_DEFAULT_MTU - FRAGMENT_HEADER_SIZE) as u32)) != 0) as u32; + debug_assert!(fragment_count <= FRAGMENT_COUNT_MAX as u32); + + let mut header = FragmentHeader { + id: packet_id, + dest: bytes[PACKET_DESTINATION_INDEX..PACKET_DESTINATION_INDEX + ADDRESS_SIZE].try_into().unwrap(), + fragment_indicator: FRAGMENT_INDICATOR, + total_and_fragment_no: ((fragment_count + 1) << 4) as u8, + reserved_hops: 0, + }; + + let mut chunk_size = (packet_size - pos).min(UDP_DEFAULT_MTU - FRAGMENT_HEADER_SIZE); + loop { + header.total_and_fragment_no += 1; + let next_pos = pos + chunk_size; + if !ci.wire_send(endpoint, local_socket, local_interface, &[header.as_bytes(), &bytes[pos..next_pos]], 0) { + return false; + } + pos = next_pos; + if pos < packet_size { + chunk_size = (packet_size - pos).min(UDP_DEFAULT_MTU - FRAGMENT_HEADER_SIZE); + } else { + break; + } + } + + return true; + } + + return ci.wire_send(endpoint, local_socket, local_interface, &[data.as_bytes()], 0); + } + /// Send a packet to this peer. /// /// This will go directly if there is an active path, or otherwise indirectly @@ -332,24 +386,28 @@ impl Peer { /// If try_new_endpoint is not None the packet will be sent directly to this endpoint. /// Otherwise it will be sent via the best direct or indirect path. pub(crate) fn send_hello(&self, ci: &CI, node: &Node, try_new_endpoint: Option) { - let (endpoint, path) = try_new_endpoint.as_ref().map_or_else(|| { + let path = if try_new_endpoint.is_none() { self.best_path().map_or_else(|| { - node.root().map_or_else(|| (None, None), |root| { - root.best_path().map_or_else(|| (None, None), |bp| (Some(&bp.endpoint), Some(bp))) + node.root().map_or(None, |root| { + root.best_path().map_or(None, |bp| Some(bp)) }) - }, |bp| (Some(&bp.endpoint), Some(bp))) - }, |ep| (Some(ep), None)); - let _ = endpoint.map(|endpoint| { - let mut buf = node.get_packet_buffer(); + }, |bp| Some(bp)) + } else { + None + }; + + let _ = try_new_endpoint.as_ref().map_or_else(|| Some(&path.as_ref().unwrap().endpoint), |ep| Some(ep)).map(|endpoint| { + let mut packet: Buffer<{ PACKET_SIZE_MAX }> = Buffer::new(); let this_peer_is_root = node.is_root(self); - debug_assert!(buf.append_and_init_struct(|header: &mut PacketHeader| { - header.id = self.next_packet_iv(); + let packet_id = self.next_packet_iv(); + debug_assert!(packet.append_and_init_struct(|header: &mut PacketHeader| { + header.id = packet_id; header.dest = self.identity.address().to_bytes(); header.src = node.address().to_bytes(); header.flags_cipher_hops = CIPHER_NOCRYPT_POLY1305; }).is_ok()); - debug_assert!(buf.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.version_proto = VERSION_PROTO; header.version_major = VERSION_MAJOR; @@ -358,20 +416,24 @@ impl Peer { header.timestamp = (ci.time_ticks() as u64).to_be(); }).is_ok()); - debug_assert!(self.identity.marshal(&mut buf, false).is_ok()); - debug_assert!(endpoint.marshal(&mut buf).is_ok()); + debug_assert!(self.identity.marshal(&mut packet, false).is_ok()); + debug_assert!(endpoint.marshal(&mut packet).is_ok()); - let aes_ctr_iv_position = buf.len(); - debug_assert!(buf.append_and_init_bytes_fixed(|iv: &mut [u8; 18]| { - crate::crypto::random::fill_bytes_secure(&mut buf[0..12]); + let aes_ctr_iv_position = packet.len(); + debug_assert!(packet.append_and_init_bytes_fixed(|iv: &mut [u8; 18]| { + crate::crypto::random::fill_bytes_secure(&mut iv[0..12]); todo!() - })); - let dictionary_position = buf.len(); + }).is_ok()); + let dictionary_position = packet.len(); let mut dict = Dictionary::new(); dict.set_u64(HELLO_DICT_KEY_INSTANCE_ID, node.instance_id); dict.set_u64(HELLO_DICT_KEY_CLOCK, ci.time_clock() as u64); - let _ = node.locator().map(|loc| loc.to_bytes().map(|loc| dict.set_bytes(HELLO_DICT_KEY_LOCATOR, loc))); - let _ = self.ephemeral_pair.lock().map(|ephemeral_pair| { + let _ = node.locator().map(|loc| { + let mut tmp: Buffer<{ PACKET_SIZE_MAX }> = Buffer::new(); + debug_assert!(loc.marshal(&mut tmp).is_ok()); + dict.set_bytes(HELLO_DICT_KEY_LOCATOR, tmp.as_bytes().to_vec()); + }); + let _ = self.ephemeral_pair.lock().as_ref().map(|ephemeral_pair| { dict.set_bytes(HELLO_DICT_KEY_EPHEMERAL_C25519, ephemeral_pair.c25519.public_bytes().to_vec()); dict.set_bytes(HELLO_DICT_KEY_EPHEMERAL_P521, ephemeral_pair.p521.public_key_bytes().to_vec()); }); @@ -379,7 +441,12 @@ impl Peer { // If the peer is a root we include some extra information for diagnostic and statistics // purposes such as the CPU type, bits, and OS info. This is not sent to other peers. dict.set_str(HELLO_DICT_KEY_SYS_ARCH, std::env::consts::ARCH); - dict.set_u64(HELLO_DICT_KEY_SYS_BITS, (std::mem::size_of::<*const ()>() * 8) as u64); + #[cfg(target_pointer_width = "32")] { + dict.set_u64(HELLO_DICT_KEY_SYS_BITS, 32); + } + #[cfg(target_pointer_width = "64")] { + dict.set_u64(HELLO_DICT_KEY_SYS_BITS, 64); + } dict.set_str(HELLO_DICT_KEY_OS_NAME, std::env::consts::OS); } let mut flags = String::new(); @@ -390,20 +457,20 @@ impl Peer { flags.push('w'); } dict.set_str(HELLO_DICT_KEY_FLAGS, flags.as_str()); - assert!(dict.write_to(&mut buf).is_ok()); + debug_assert!(dict.write_to(&mut packet).is_ok()); let mut dict_aes = self.static_secret_hello_dictionary.lock(); - dict_aes.init(&buf.as_bytes()[aes_ctr_iv_position..aes_ctr_iv_position + 12]); - dict_aes.crypt_in_place(&mut buf.as_bytes_mut()[dictionary_position..]); + dict_aes.init(&packet.as_bytes()[aes_ctr_iv_position..aes_ctr_iv_position + 12]); + dict_aes.crypt_in_place(&mut packet.as_bytes_mut()[dictionary_position..]); drop(dict_aes); - assert!(buf.append_bytes_fixed(&SHA384::hmac(self.static_secret_packet_hmac.as_ref(), &buf.as_bytes()[PACKET_HEADER_SIZE + 1..])).is_ok()); + debug_assert!(packet.append_bytes_fixed(&SHA384::hmac(self.static_secret_packet_hmac.as_ref(), &packet.as_bytes()[PACKET_HEADER_SIZE + 1..])).is_ok()); - let (_, mut poly) = salsa_poly_create(secret, header, packet.len()); - poly.update(buf.as_bytes_starting_at(PACKET_HEADER_SIZE).unwrap()); - buf.as_bytes_mut()[HEADER_MAC_FIELD_INDEX..HEADER_MAC_FIELD_INDEX + 8].copy_from_slice(&poly.finish()[0..8]); + let (_, mut poly) = salsa_poly_create(&self.static_secret, packet.struct_at::(0).unwrap(), packet.len()); + poly.update(packet.as_bytes_starting_at(PACKET_HEADER_SIZE).unwrap()); + packet.as_bytes_mut()[HEADER_MAC_FIELD_INDEX..HEADER_MAC_FIELD_INDEX + 8].copy_from_slice(&poly.finish()[0..8]); - ci.wire_send(endpoint, path.map(|p| p.local_socket), path.map(|p| p.local_interface), buf, 0); + self.send_udp(ci, endpoint, path.as_ref().map(|p| p.local_socket), path.as_ref().map(|p| p.local_interface), packet_id, &packet); }); } diff --git a/network-hypervisor/src/vl1/protocol.rs b/network-hypervisor/src/vl1/protocol.rs index d39de21a0..02d243e56 100644 --- a/network-hypervisor/src/vl1/protocol.rs +++ b/network-hypervisor/src/vl1/protocol.rs @@ -231,6 +231,11 @@ impl FragmentHeader { h } + #[inline(always)] + pub fn as_bytes(&self) -> &[u8; FRAGMENT_HEADER_SIZE] { + unsafe { &*(self as *const Self).cast::<[u8; FRAGMENT_HEADER_SIZE]>() } + } + #[inline(always)] pub fn destination(&self) -> Address { Address::from(&self.dest) @@ -238,6 +243,8 @@ impl FragmentHeader { } pub(crate) mod message_component_structs { + use crate::vl1::buffer::RawObject; + #[repr(packed)] pub struct HelloFixedHeaderFields { pub verb: u8, @@ -248,6 +255,8 @@ pub(crate) mod message_component_structs { pub timestamp: u64, } + unsafe impl RawObject for HelloFixedHeaderFields {} + #[repr(packed)] pub struct OkHelloFixedHeaderFields { pub timestamp_echo: u64, @@ -256,14 +265,16 @@ pub(crate) mod message_component_structs { pub version_minor: u8, pub version_revision: u16, } + + unsafe impl RawObject for OkHelloFixedHeaderFields {} } #[cfg(test)] mod tests { use std::mem::size_of; - use crate::vl1::constants::{FRAGMENT_HEADER_SIZE, PACKET_HEADER_SIZE}; - use crate::vl1::protocol::{FragmentHeader, PacketHeader}; + use crate::vl1::constants::*; + use crate::vl1::protocol::*; #[test] fn representation() {