// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md. use std::collections::HashMap; use std::hash::Hash; use std::sync::atomic::{AtomicI64, AtomicU64, Ordering}; use std::sync::{Arc, Weak}; use parking_lot::{Mutex, RwLock}; use zerotier_crypto::poly1305; use zerotier_crypto::random; use zerotier_crypto::salsa::Salsa; use zerotier_crypto::secret::Secret; use zerotier_utils::buffer::BufferReader; use zerotier_utils::memory::array_range; use crate::protocol::*; use crate::util::marshalable::Marshalable; use crate::vl1::address::Address; use crate::vl1::debug_event; use crate::vl1::node::*; use crate::vl1::symmetricsecret::SymmetricSecret; use crate::vl1::{Endpoint, Identity, Path}; use crate::{VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION}; pub(crate) const SERVICE_INTERVAL_MS: i64 = 10000; pub struct Peer { pub identity: Identity, static_symmetric_key: SymmetricSecret, paths: Mutex>>, pub(crate) last_send_time_ticks: AtomicI64, pub(crate) last_receive_time_ticks: AtomicI64, pub(crate) last_hello_reply_time_ticks: AtomicI64, pub(crate) last_forward_time_ticks: AtomicI64, pub(crate) create_time_ticks: i64, random_ticks_offset: u32, message_id_counter: AtomicU64, remote_node_info: RwLock, } struct PeerPath { path: Weak>, last_receive_time_ticks: i64, } struct RemoteNodeInfo { reported_local_endpoints: HashMap, remote_protocol_version: u8, remote_version: (u8, u8, u16), } /// Sort a list of paths by quality or priority, with best paths first. fn prioritize_paths(paths: &mut Vec>) { paths.sort_unstable_by(|a, b| a.last_receive_time_ticks.cmp(&b.last_receive_time_ticks).reverse()); } impl Peer { /// Create a new peer. /// /// This only returns None if this_node_identity does not have its secrets or if some /// fatal error occurs performing key agreement between the two identities. pub(crate) fn new(this_node_identity: &Identity, id: Identity, time_ticks: i64) -> Option { this_node_identity.agree(&id).map(|static_secret| -> Self { Self { identity: id, static_symmetric_key: SymmetricSecret::new(static_secret), paths: Mutex::new(Vec::with_capacity(4)), last_send_time_ticks: AtomicI64::new(crate::util::NEVER_HAPPENED_TICKS), last_receive_time_ticks: AtomicI64::new(crate::util::NEVER_HAPPENED_TICKS), last_forward_time_ticks: AtomicI64::new(crate::util::NEVER_HAPPENED_TICKS), last_hello_reply_time_ticks: AtomicI64::new(crate::util::NEVER_HAPPENED_TICKS), create_time_ticks: time_ticks, random_ticks_offset: random::xorshift64_random() as u32, message_id_counter: AtomicU64::new(random::xorshift64_random()), remote_node_info: RwLock::new(RemoteNodeInfo { reported_local_endpoints: HashMap::new(), remote_protocol_version: 0, remote_version: (0, 0, 0), }), } }) } /// Get the remote version of this peer: major, minor, revision. /// Returns None if it's not yet known. pub fn version(&self) -> Option<(u8, u8, u16)> { let rv = self.remote_node_info.read().remote_version; if rv.0 != 0 || rv.1 != 0 || rv.2 != 0 { Some(rv) } else { None } } /// Get the remote protocol version of this peer or None if not yet known. pub fn protocol_version(&self) -> Option { let pv = self.remote_node_info.read().remote_protocol_version; if pv != 0 { Some(pv) } else { None } } /// Get the next message ID for sending a message to this peer. #[inline(always)] pub(crate) fn next_message_id(&self) -> MessageId { self.message_id_counter.fetch_add(1, Ordering::SeqCst) } /// Get current best path or None if there are no direct paths to this peer. pub fn direct_path(&self) -> Option>> { for p in self.paths.lock().iter() { let pp = p.path.upgrade(); if pp.is_some() { return pp; } } return None; } /// Get either the current best direct path or an indirect path via e.g. a root. pub fn path(&self, node: &Node) -> Option>> { let direct_path = self.direct_path(); if direct_path.is_some() { return direct_path; } if let Some(root) = node.best_root() { return root.direct_path(); } return None; } fn learn_path(&self, host_system: &HostSystemImpl, new_path: &Arc>, time_ticks: i64) { let mut paths = self.paths.lock(); match &new_path.endpoint { Endpoint::IpUdp(new_ip) => { // If this is an IpUdp endpoint, scan the existing paths and replace any that come from // the same IP address but a different port. This prevents the accumulation of duplicate // paths to the same peer over different ports. for pi in paths.iter_mut() { if std::ptr::eq(pi.path.as_ptr(), new_path.as_ref()) { return; } if let Some(p) = pi.path.upgrade() { match &p.endpoint { Endpoint::IpUdp(existing_ip) => { if existing_ip.ip_bytes().eq(new_ip.ip_bytes()) { debug_event!( host_system, "[vl1] {} replacing path {} with {} (same IP, different port)", self.identity.address.to_string(), p.endpoint.to_string(), new_path.endpoint.to_string() ); pi.path = Arc::downgrade(new_path); pi.last_receive_time_ticks = time_ticks; prioritize_paths(&mut paths); return; } } _ => {} } } } } _ => { for pi in paths.iter() { if std::ptr::eq(pi.path.as_ptr(), new_path.as_ref()) { return; } } } } // Learn new path if it's not a duplicate or should not replace an existing path. debug_event!( host_system, "[vl1] {} learned new path: {}", self.identity.address.to_string(), new_path.endpoint.to_string() ); paths.push(PeerPath:: { path: Arc::downgrade(new_path), last_receive_time_ticks: time_ticks, }); prioritize_paths(&mut paths); } /// Called every SERVICE_INTERVAL_MS by the background service loop in Node. pub(crate) fn service(&self, _: &HostSystemImpl, _: &Node, time_ticks: i64) -> bool { { let mut paths = self.paths.lock(); paths.retain(|p| ((time_ticks - p.last_receive_time_ticks) < PEER_EXPIRATION_TIME) && (p.path.strong_count() > 0)); prioritize_paths(&mut paths); } self.remote_node_info .write() .reported_local_endpoints .retain(|_, ts| (time_ticks - *ts) < PEER_EXPIRATION_TIME); (time_ticks - self.last_receive_time_ticks.load(Ordering::Relaxed).max(self.create_time_ticks)) < PEER_EXPIRATION_TIME } fn internal_send( &self, host_system: &HostSystemImpl, endpoint: &Endpoint, local_socket: Option<&HostSystemImpl::LocalSocket>, local_interface: Option<&HostSystemImpl::LocalInterface>, max_fragment_size: usize, packet: &PacketBuffer, ) { let packet_size = packet.len(); if packet_size > max_fragment_size { let bytes = packet.as_bytes(); host_system.wire_send(endpoint, local_socket, local_interface, &bytes[0..UDP_DEFAULT_MTU], 0); let mut pos = UDP_DEFAULT_MTU; let overrun_size = (packet_size - UDP_DEFAULT_MTU) as u32; let fragment_count = (overrun_size / (UDP_DEFAULT_MTU - v1::FRAGMENT_HEADER_SIZE) as u32) + (((overrun_size % (UDP_DEFAULT_MTU - v1::FRAGMENT_HEADER_SIZE) as u32) != 0) as u32); debug_assert!(fragment_count <= v1::FRAGMENT_COUNT_MAX as u32); let mut header = v1::FragmentHeader { id: *packet.bytes_fixed_at(0).unwrap(), dest: *packet.bytes_fixed_at(v1::DESTINATION_INDEX).unwrap(), fragment_indicator: v1::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 - v1::HEADER_SIZE); let mut tmp_buf: [u8; v1::SIZE_MAX] = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; loop { header.total_and_fragment_no += 1; let next_pos = pos + chunk_size; let fragment_size = v1::FRAGMENT_HEADER_SIZE + chunk_size; tmp_buf[..v1::FRAGMENT_HEADER_SIZE].copy_from_slice(header.as_bytes()); tmp_buf[v1::FRAGMENT_HEADER_SIZE..fragment_size].copy_from_slice(&bytes[pos..next_pos]); host_system.wire_send(endpoint, local_socket, local_interface, &tmp_buf[..fragment_size], 0); pos = next_pos; if pos < packet_size { chunk_size = (packet_size - pos).min(UDP_DEFAULT_MTU - v1::HEADER_SIZE); } else { break; } } } else { host_system.wire_send(endpoint, local_socket, local_interface, packet.as_bytes(), 0); } } /// Send a packet to this peer, returning true on (potential) success. /// /// This will go directly if there is an active path, or otherwise indirectly /// via a root or some other route. pub(crate) fn send( &self, host_system: &HostSystemImpl, path: Option<&Arc>>, node: &Node, time_ticks: i64, packet: &mut PacketBuffer, ) -> bool { let mut _path_arc = None; let path = if let Some(path) = path { path } else { _path_arc = self.path(node); if let Some(path) = _path_arc.as_ref() { path } else { return false; } }; let max_fragment_size = if path.endpoint.requires_fragmentation() { UDP_DEFAULT_MTU } else { usize::MAX }; let flags_cipher_hops = if packet.len() > max_fragment_size { v1::HEADER_FLAG_FRAGMENTED | v1::CIPHER_AES_GMAC_SIV } else { v1::CIPHER_AES_GMAC_SIV }; let mut aes_gmac_siv = self.static_symmetric_key.aes_gmac_siv.get(); aes_gmac_siv.encrypt_init(&self.next_message_id().to_ne_bytes()); aes_gmac_siv.encrypt_set_aad(&v1::get_packet_aad_bytes( self.identity.address, node.identity.address, flags_cipher_hops, )); if let Ok(payload) = packet.as_bytes_starting_at_mut(v1::HEADER_SIZE) { aes_gmac_siv.encrypt_first_pass(payload); aes_gmac_siv.encrypt_first_pass_finish(); aes_gmac_siv.encrypt_second_pass_in_place(payload); let tag = aes_gmac_siv.encrypt_second_pass_finish(); let header = packet.struct_mut_at::(0).unwrap(); header.id = *array_range::(tag); header.dest = self.identity.address.to_bytes(); header.src = node.identity.address.to_bytes(); header.flags_cipher_hops = flags_cipher_hops; header.mac = *array_range::(tag); } else { return false; } self.internal_send( host_system, &path.endpoint, Some(&path.local_socket), Some(&path.local_interface), max_fragment_size, packet, ); self.last_send_time_ticks.store(time_ticks, Ordering::Relaxed); return true; } /// Forward a packet to this peer. /// /// This is called when we receive a packet not addressed to this node and /// want to pass it along. /// /// This doesn't fragment large packets since fragments are forwarded individually. /// Intermediates don't need to adjust fragmentation. pub(crate) fn forward(&self, host_system: &HostSystemImpl, time_ticks: i64, packet: &PacketBuffer) -> bool { if let Some(path) = self.direct_path() { host_system.wire_send( &path.endpoint, Some(&path.local_socket), Some(&path.local_interface), packet.as_bytes(), 0, ); self.last_forward_time_ticks.store(time_ticks, Ordering::Relaxed); return true; } return false; } /// Send a HELLO to this peer. /// /// If explicit_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 known. /// /// Unlike other messages HELLO is sent partially in the clear and always with the long-lived /// static identity key. Authentication in old versions is via Poly1305 and in new versions /// via HMAC-SHA512. pub(crate) fn send_hello( &self, host_system: &HostSystemImpl, node: &Node, explicit_endpoint: Option<&Endpoint>, ) -> bool { let mut path = None; let destination = if let Some(explicit_endpoint) = explicit_endpoint { explicit_endpoint } else { if let Some(p) = self.path(node) { let _ = path.insert(p); &path.as_ref().unwrap().endpoint } else { return false; } }; let max_fragment_size = if destination.requires_fragmentation() { UDP_DEFAULT_MTU } else { usize::MAX }; let time_ticks = host_system.time_ticks(); let mut packet = PacketBuffer::new(); { let message_id = self.next_message_id(); { let f: &mut (v1::PacketHeader, v1::message_component_structs::HelloFixedHeaderFields) = packet.append_struct_get_mut().unwrap(); f.0.id = message_id.to_ne_bytes(); f.0.dest = self.identity.address.to_bytes(); f.0.src = node.identity.address.to_bytes(); f.0.flags_cipher_hops = v1::CIPHER_NOCRYPT_POLY1305; f.1.verb = verbs::VL1_HELLO | v1::VERB_FLAG_EXTENDED_AUTHENTICATION; f.1.version_proto = PROTOCOL_VERSION; f.1.version_major = VERSION_MAJOR; f.1.version_minor = VERSION_MINOR; f.1.version_revision = VERSION_REVISION.to_be_bytes(); f.1.timestamp = (time_ticks as u64).wrapping_add(self.random_ticks_offset as u64).to_be_bytes(); } debug_assert_eq!(packet.len(), 41); assert!(packet.append_bytes((&node.identity.to_public_bytes()).into()).is_ok()); let (_, poly1305_key) = salsa_poly_create( &self.static_symmetric_key, packet.struct_at::(0).unwrap(), packet.len(), ); let mac = poly1305::compute(&poly1305_key, packet.as_bytes_starting_at(v1::HEADER_SIZE).unwrap()); packet.as_mut()[v1::MAC_FIELD_INDEX..v1::MAC_FIELD_INDEX + 8].copy_from_slice(&mac[0..8]); self.last_send_time_ticks.store(time_ticks, Ordering::Relaxed); debug_event!( host_system, "HELLO -> {} @ {} ({} bytes)", self.identity.address.to_string(), destination.to_string(), packet.len() ); } if let Some(p) = path.as_ref() { self.internal_send( host_system, destination, Some(&p.local_socket), Some(&p.local_interface), max_fragment_size, &packet, ); p.log_send_anything(time_ticks); } else { self.internal_send(host_system, destination, None, None, max_fragment_size, &packet); } return true; } /// Receive, decrypt, authenticate, and process an incoming packet from this peer. /// /// If the packet comes in multiple fragments, the fragments slice should contain all /// those fragments after the main packet header and first chunk. /// /// This returns true if the packet decrypted and passed authentication. pub(crate) fn receive( self: &Arc, node: &Node, host_system: &HostSystemImpl, inner: &InnerProtocolImpl, time_ticks: i64, source_path: &Arc>, packet_header: &v1::PacketHeader, frag0: &PacketBuffer, fragments: &[Option], ) -> PacketHandlerResult { if let Ok(packet_frag0_payload_bytes) = frag0.as_bytes_starting_at(v1::VERB_INDEX) { let mut payload = PacketBuffer::new(); let message_id = if let Some(message_id2) = try_aead_decrypt( &self.static_symmetric_key, packet_frag0_payload_bytes, packet_header, fragments, &mut payload, ) { // Decryption successful with static secret. message_id2 } else { // Packet failed to decrypt using either ephemeral or permament key, reject. debug_event!( host_system, "[vl1] #{:0>16x} failed authentication", u64::from_be_bytes(packet_header.id) ); return PacketHandlerResult::Error; }; if let Ok(mut verb) = payload.u8_at(0) { if (verb & v1::VERB_FLAG_COMPRESSED) != 0 { let mut decompressed_payload = [0u8; v1::SIZE_MAX]; decompressed_payload[0] = verb; if let Ok(dlen) = lz4_flex::block::decompress_into(&payload.as_bytes()[1..], &mut decompressed_payload[1..]) { payload.set_to(&decompressed_payload[..(dlen + 1)]); } else { return PacketHandlerResult::Error; } } // --------------------------------------------------------------- // If we made it here it decrypted and passed authentication. // --------------------------------------------------------------- self.last_receive_time_ticks.store(time_ticks, Ordering::Relaxed); let mut path_is_known = false; for p in self.paths.lock().iter_mut() { if std::ptr::eq(p.path.as_ptr(), source_path.as_ref()) { p.last_receive_time_ticks = time_ticks; path_is_known = true; break; } } verb &= v1::VERB_MASK; // mask off flags debug_event!( host_system, "[vl1] #{:0>16x} decrypted and authenticated, verb: {} ({:0>2x})", u64::from_be_bytes(packet_header.id), verbs::name(verb), verb as u32 ); return match verb { verbs::VL1_NOP => PacketHandlerResult::Ok, verbs::VL1_HELLO => self.handle_incoming_hello( host_system, inner, node, time_ticks, message_id, source_path, packet_header.hops(), &payload, ), verbs::VL1_ERROR => self.handle_incoming_error(host_system, inner, node, time_ticks, source_path, &payload), verbs::VL1_OK => self.handle_incoming_ok( host_system, inner, node, time_ticks, source_path, packet_header.hops(), path_is_known, &payload, ), verbs::VL1_WHOIS => self.handle_incoming_whois(host_system, inner, node, time_ticks, message_id, &payload), verbs::VL1_RENDEZVOUS => { self.handle_incoming_rendezvous(host_system, node, time_ticks, message_id, source_path, &payload) } verbs::VL1_ECHO => self.handle_incoming_echo(host_system, inner, node, time_ticks, message_id, &payload), verbs::VL1_PUSH_DIRECT_PATHS => { self.handle_incoming_push_direct_paths(host_system, node, time_ticks, source_path, &payload) } verbs::VL1_USER_MESSAGE => self.handle_incoming_user_message(host_system, node, time_ticks, source_path, &payload), _ => inner.handle_packet(self, &source_path, verb, &payload), }; } } return PacketHandlerResult::Error; } fn handle_incoming_hello( &self, host_system: &HostSystemImpl, inner: &InnerProtocolImpl, node: &Node, time_ticks: i64, message_id: MessageId, source_path: &Arc>, hops: u8, payload: &PacketBuffer, ) -> PacketHandlerResult { if !(inner.should_communicate_with(&self.identity) || node.this_node_is_root() || node.is_peer_root(self)) { debug_event!( host_system, "[vl1] dropping HELLO from {} due to lack of trust relationship", self.identity.address.to_string() ); return PacketHandlerResult::Ok; // packet wasn't invalid, just ignored } let mut cursor = 0; if let Ok(hello_fixed_headers) = payload.read_struct::(&mut cursor) { if let Ok(identity) = Identity::read_bytes(&mut BufferReader::new(payload, &mut cursor)) { if identity.eq(&self.identity) { { let mut remote_node_info = self.remote_node_info.write(); remote_node_info.remote_protocol_version = hello_fixed_headers.version_proto; remote_node_info.remote_version = ( hello_fixed_headers.version_major, hello_fixed_headers.version_minor, u16::from_be_bytes(hello_fixed_headers.version_revision), ); } let mut packet = PacketBuffer::new(); packet.set_size(v1::HEADER_SIZE); { let f: &mut ( v1::message_component_structs::OkHeader, v1::message_component_structs::OkHelloFixedHeaderFields, ) = packet.append_struct_get_mut().unwrap(); f.0.verb = verbs::VL1_OK; f.0.in_re_verb = verbs::VL1_HELLO; f.0.in_re_message_id = message_id.to_ne_bytes(); f.1.timestamp_echo = hello_fixed_headers.timestamp; f.1.version_proto = PROTOCOL_VERSION; f.1.version_major = VERSION_MAJOR; f.1.version_minor = VERSION_MINOR; f.1.version_revision = VERSION_REVISION.to_be_bytes(); } self.send(host_system, Some(source_path), node, time_ticks, &mut packet); return PacketHandlerResult::Ok; } } } return PacketHandlerResult::Error; } fn handle_incoming_error( self: &Arc, _: &HostSystemImpl, inner: &InnerProtocolImpl, _: &Node, _: i64, source_path: &Arc>, payload: &PacketBuffer, ) -> PacketHandlerResult { let mut cursor = 0; if let Ok(error_header) = payload.read_struct::(&mut cursor) { let in_re_message_id: MessageId = u64::from_ne_bytes(error_header.in_re_message_id); if self.message_id_counter.load(Ordering::Relaxed).wrapping_sub(in_re_message_id) <= PACKET_RESPONSE_COUNTER_DELTA_MAX { match error_header.in_re_verb { _ => { return inner.handle_error( self, &source_path, error_header.in_re_verb, in_re_message_id, error_header.error_code, payload, &mut cursor, ); } } } } return PacketHandlerResult::Error; } fn handle_incoming_ok( self: &Arc, host_system: &HostSystemImpl, inner: &InnerProtocolImpl, node: &Node, time_ticks: i64, source_path: &Arc>, hops: u8, path_is_known: bool, payload: &PacketBuffer, ) -> PacketHandlerResult { let mut cursor = 0; if let Ok(ok_header) = payload.read_struct::(&mut cursor) { let in_re_message_id: MessageId = u64::from_ne_bytes(ok_header.in_re_message_id); if self.message_id_counter.load(Ordering::Relaxed).wrapping_sub(in_re_message_id) <= PACKET_RESPONSE_COUNTER_DELTA_MAX { match ok_header.in_re_verb { verbs::VL1_HELLO => { if let Ok(_ok_hello_fixed_header_fields) = payload.read_struct::(&mut cursor) { if hops == 0 { debug_event!(host_system, "[vl1] {} OK(HELLO)", self.identity.address.to_string(),); if let Ok(reported_endpoint) = Endpoint::unmarshal(&payload, &mut cursor) { #[cfg(debug_assertions)] let reported_endpoint2 = reported_endpoint.clone(); if self .remote_node_info .write() .reported_local_endpoints .insert(reported_endpoint, time_ticks) .is_none() { #[cfg(debug_assertions)] debug_event!( host_system, "[vl1] {} reported new remote perspective, local endpoint: {}", self.identity.address.to_string(), reported_endpoint2.to_string() ); } } } if hops == 0 && !path_is_known { self.learn_path(host_system, source_path, time_ticks); } self.last_hello_reply_time_ticks.store(time_ticks, Ordering::Relaxed); } } verbs::VL1_WHOIS => { if node.is_peer_root(self) { while cursor < payload.len() { if let Ok(received_identity) = Identity::read_bytes(&mut BufferReader::new(payload, &mut cursor)) { debug_event!( host_system, "[vl1] {} OK(WHOIS): {}", self.identity.address.to_string(), received_identity.to_string() ); node.handle_incoming_identity(host_system, inner, received_identity, time_ticks, true); } else { break; } } } else { return PacketHandlerResult::Ok; // not invalid, just ignored } } _ => { return inner.handle_ok(self, &source_path, ok_header.in_re_verb, in_re_message_id, payload, &mut cursor); } } } } return PacketHandlerResult::Error; } fn handle_incoming_whois( self: &Arc, host_system: &HostSystemImpl, inner: &InnerProtocolImpl, node: &Node, time_ticks: i64, message_id: MessageId, payload: &PacketBuffer, ) -> PacketHandlerResult { if node.this_node_is_root() || inner.should_communicate_with(&self.identity) { let init_packet = |packet: &mut PacketBuffer| { packet.set_size(v1::HEADER_SIZE); let mut f: &mut v1::message_component_structs::OkHeader = packet.append_struct_get_mut().unwrap(); f.verb = verbs::VL1_OK; f.in_re_verb = verbs::VL1_WHOIS; f.in_re_message_id = message_id.to_ne_bytes(); }; let mut packet = PacketBuffer::new(); init_packet(&mut packet); let mut addresses = payload.as_bytes(); loop { if addresses.len() >= ADDRESS_SIZE { if let Some(zt_address) = Address::from_bytes(&addresses[..ADDRESS_SIZE]) { if let Some(peer) = node.peer(zt_address) { let id_bytes_tmp = peer.identity.to_public_bytes(); let id_bytes = id_bytes_tmp.as_bytes(); if (packet.capacity() - packet.len()) < id_bytes.len() { self.send(host_system, None, node, time_ticks, &mut packet); packet.clear(); init_packet(&mut packet); } let _ = packet.append_bytes(id_bytes); } } addresses = &addresses[ADDRESS_SIZE..]; } else { break; } } self.send(host_system, None, node, time_ticks, &mut packet); } return PacketHandlerResult::Ok; } fn handle_incoming_rendezvous( self: &Arc, host_system: &HostSystemImpl, node: &Node, time_ticks: i64, message_id: MessageId, source_path: &Arc>, payload: &PacketBuffer, ) -> PacketHandlerResult { if node.is_peer_root(self) {} return PacketHandlerResult::Ok; } fn handle_incoming_echo( &self, host_system: &HostSystemImpl, inner: &InnerProtocolImpl, node: &Node, time_ticks: i64, message_id: MessageId, payload: &PacketBuffer, ) -> PacketHandlerResult { if inner.should_communicate_with(&self.identity) || node.is_peer_root(self) { let mut packet = PacketBuffer::new(); packet.set_size(v1::HEADER_SIZE); { let mut f: &mut v1::message_component_structs::OkHeader = packet.append_struct_get_mut().unwrap(); f.verb = verbs::VL1_OK; f.in_re_verb = verbs::VL1_ECHO; f.in_re_message_id = message_id.to_ne_bytes(); } if packet.append_bytes(payload.as_bytes()).is_ok() { self.send(host_system, None, node, time_ticks, &mut packet); } } else { debug_event!( host_system, "[vl1] dropping ECHO from {} due to lack of trust relationship", self.identity.address.to_string() ); } return PacketHandlerResult::Ok; } fn handle_incoming_push_direct_paths( self: &Arc, host_system: &HostSystemImpl, node: &Node, time_ticks: i64, source_path: &Arc>, payload: &PacketBuffer, ) -> PacketHandlerResult { PacketHandlerResult::Ok } fn handle_incoming_user_message( self: &Arc, host_system: &HostSystemImpl, node: &Node, time_ticks: i64, source_path: &Arc>, payload: &PacketBuffer, ) -> PacketHandlerResult { PacketHandlerResult::Ok } } impl Hash for Peer { #[inline(always)] fn hash(&self, state: &mut H) { state.write_u64(self.identity.address.into()); } } impl PartialEq for Peer { #[inline(always)] fn eq(&self, other: &Self) -> bool { self.identity.fingerprint.eq(&other.identity.fingerprint) } } impl Eq for Peer {} /// Attempt ZeroTier V1 protocol AEAD packet encryption and MAC validation. Returns message ID on success. fn try_aead_decrypt( secret: &SymmetricSecret, packet_frag0_payload_bytes: &[u8], packet_header: &v1::PacketHeader, fragments: &[Option], payload: &mut PacketBuffer, ) -> Option { let cipher = packet_header.cipher(); match cipher { v1::CIPHER_NOCRYPT_POLY1305 | v1::CIPHER_SALSA2012_POLY1305 => { let _ = payload.append_bytes(packet_frag0_payload_bytes); for f in fragments.iter() { if let Some(f) = f.as_ref() { if let Ok(f) = f.as_bytes_starting_at(v1::FRAGMENT_HEADER_SIZE) { let _ = payload.append_bytes(f); } } } let (mut salsa, poly1305_key) = salsa_poly_create(secret, packet_header, payload.len() + v1::HEADER_SIZE); let mac = poly1305::compute(&poly1305_key, &payload.as_bytes()); if mac[0..8].eq(&packet_header.mac) { let message_id = u64::from_ne_bytes(packet_header.id); if cipher == v1::CIPHER_SALSA2012_POLY1305 { salsa.crypt_in_place(payload.as_bytes_mut()); Some(message_id) } else if (payload.u8_at(0).unwrap_or(0) & v1::VERB_MASK) == verbs::VL1_HELLO { Some(message_id) } else { // SECURITY: fail if there is no encryption and the message is not HELLO. No other types are allowed // to be sent without full packet encryption. None } } else { None } } v1::CIPHER_AES_GMAC_SIV => { let mut aes_gmac_siv = secret.aes_gmac_siv.get(); aes_gmac_siv.decrypt_init(&packet_header.aes_gmac_siv_tag()); aes_gmac_siv.decrypt_set_aad(&[ packet_header.dest[0], packet_header.dest[1], packet_header.dest[2], packet_header.dest[3], packet_header.dest[4], packet_header.src[0], packet_header.src[1], packet_header.src[2], packet_header.src[3], packet_header.src[4], packet_header.flags_cipher_hops & v1::FLAGS_FIELD_MASK_HIDE_HOPS, ]); if let Ok(b) = payload.append_bytes_get_mut(packet_frag0_payload_bytes.len()) { aes_gmac_siv.decrypt(packet_frag0_payload_bytes, b); } for f in fragments.iter() { if let Some(f) = f.as_ref() { if let Ok(f) = f.as_bytes_starting_at(v1::FRAGMENT_HEADER_SIZE) { if let Ok(b) = payload.append_bytes_get_mut(f.len()) { aes_gmac_siv.decrypt(f, b); } } } } if let Some(tag) = aes_gmac_siv.decrypt_finish() { // AES-GMAC-SIV encrypts the packet ID too as part of its computation of a single // opaque 128-bit tag, so to get the original packet ID we have to grab it from the // decrypted tag. Some(u64::from_ne_bytes(*array_range::(tag))) } else { None } } _ => None, } } /// Create initialized instances of Salsa20/12 and Poly1305 for a packet. /// (Note that this is a legacy cipher suite.) fn salsa_poly_create(secret: &SymmetricSecret, header: &v1::PacketHeader, packet_size: usize) -> (Salsa<12>, [u8; 32]) { // Create a per-packet key from the IV, source, destination, and packet size. let mut key: Secret<32> = secret.key.first_n_clone(); let hb = header.as_bytes(); for i in 0..18 { key.0[i] ^= hb[i]; } key.0[18] ^= header.flags_cipher_hops & v1::FLAGS_FIELD_MASK_HIDE_HOPS; key.0[19] ^= packet_size as u8; key.0[20] ^= packet_size.wrapping_shr(8) as u8; let mut salsa = Salsa::<12>::new(&key.0, &header.id); let mut poly1305_key = [0_u8; 32]; salsa.crypt_in_place(&mut poly1305_key); (salsa, poly1305_key) }