diff --git a/zerotier-network-hypervisor/src/vl1/node.rs b/zerotier-network-hypervisor/src/vl1/node.rs index 9b149d219..0204c6a72 100644 --- a/zerotier-network-hypervisor/src/vl1/node.rs +++ b/zerotier-network-hypervisor/src/vl1/node.rs @@ -652,6 +652,10 @@ impl Node { self.roots.read().my_root_sets.clone() } + pub(crate) fn this_node_is_root(&self) -> bool { + self.roots.read().my_root_sets.is_some() + } + pub(crate) fn care_of_bytes(&self) -> Vec { self.roots.read().care_of.clone() } diff --git a/zerotier-network-hypervisor/src/vl1/peer.rs b/zerotier-network-hypervisor/src/vl1/peer.rs index 607642827..dadb0e8ae 100644 --- a/zerotier-network-hypervisor/src/vl1/peer.rs +++ b/zerotier-network-hypervisor/src/vl1/peer.rs @@ -67,24 +67,6 @@ pub struct Peer { remote_protocol_version: AtomicU8, } -/// Create initialized instances of Salsa20/12 and Poly1305 for a packet (LEGACY). -fn salsa_poly_create(secret: &SymmetricSecret, header: &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(); - let hb = header.as_bytes(); - for i in 0..18 { - key.0[i] ^= hb[i]; - } - key.0[18] ^= header.flags_cipher_hops & packet_constants::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) -} - /// Attempt AEAD packet encryption and MAC validation. Returns message ID on success. fn try_aead_decrypt(secret: &SymmetricSecret, packet_frag0_payload_bytes: &[u8], packet_header: &PacketHeader, fragments: &[Option], payload: &mut PacketBuffer) -> Option { let cipher = packet_header.cipher(); @@ -150,6 +132,25 @@ fn try_aead_decrypt(secret: &SymmetricSecret, packet_frag0_payload_bytes: &[u8], } } +/// 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: &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(); + let hb = header.as_bytes(); + for i in 0..18 { + key.0[i] ^= hb[i]; + } + key.0[18] ^= header.flags_cipher_hops & packet_constants::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) +} + /// 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()); @@ -596,9 +597,8 @@ impl Peer { async fn handle_incoming_error(&self, si: &SI, ph: &PH, node: &Node, time_ticks: i64, source_path: &Arc>, forward_secrecy: bool, extended_authentication: bool, payload: &PacketBuffer) { let mut cursor: usize = 1; if let Ok(error_header) = payload.read_struct::(&mut cursor) { - let in_re_message_id = u64::from_ne_bytes(error_header.in_re_message_id); - let current_packet_id_counter = self.message_id_counter.load(Ordering::Relaxed); - if current_packet_id_counter.wrapping_sub(in_re_message_id) <= PACKET_RESPONSE_COUNTER_DELTA_MAX { + 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 { _ => { ph.handle_error(self, &source_path, forward_secrecy, extended_authentication, error_header.in_re_verb, in_re_message_id, error_header.error_code, payload, &mut cursor).await; @@ -624,15 +624,31 @@ impl Peer { ) { let mut cursor: usize = 1; if let Ok(ok_header) = payload.read_struct::(&mut cursor) { - let in_re_message_id = u64::from_ne_bytes(ok_header.in_re_message_id); - let current_packet_id_counter = self.message_id_counter.load(Ordering::Relaxed); - if current_packet_id_counter.wrapping_sub(in_re_message_id) <= PACKET_RESPONSE_COUNTER_DELTA_MAX { + 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 hops == 0 && !path_is_known { - self.learn_path(si, source_path, time_ticks); + if let Ok(ok_hello_fixed_header_fields) = payload.read_struct::(&mut cursor) { + if ok_hello_fixed_header_fields.version_proto >= 20 { + if let Ok(session_metadata_len) = payload.read_u16(&mut cursor) { + if session_metadata_len > 0 { + if let Ok(session_metadata) = payload.read_bytes(session_metadata_len as usize, &mut cursor) { + if let Some(session_metadata) = Dictionary::from_bytes(session_metadata) { + // TODO + } + } + } + } + } else { + //let physical_address = Endpoint::unmarshal(&payload, &mut cursor); + // TODO + } + + if hops == 0 && !path_is_known { + self.learn_path(si, source_path, time_ticks); + } + self.last_hello_reply_time_ticks.store(time_ticks, Ordering::Relaxed); } - self.last_hello_reply_time_ticks.store(time_ticks, Ordering::Relaxed); } verbs::VL1_WHOIS => {} diff --git a/zerotier-network-hypervisor/src/vl1/protocol.rs b/zerotier-network-hypervisor/src/vl1/protocol.rs index 408a4a85d..924b74760 100644 --- a/zerotier-network-hypervisor/src/vl1/protocol.rs +++ b/zerotier-network-hypervisor/src/vl1/protocol.rs @@ -253,7 +253,7 @@ pub const PROTOCOL_MAX_HOPS: u8 = 7; pub const FORWARD_MAX_HOPS: u8 = 3; /// Maximum difference between current message ID and OK/ERROR in-re message ID. -pub const PACKET_RESPONSE_COUNTER_DELTA_MAX: u64 = 1024; +pub const PACKET_RESPONSE_COUNTER_DELTA_MAX: u64 = 4096; /// Frequency for WHOIS retries pub const WHOIS_RETRY_INTERVAL: i64 = 1000;