diff --git a/Cargo.toml b/Cargo.toml index 164baa4..cead70a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "vented" description = "Event driven encrypted tcp communicaton" -version = "0.1.2" +version = "0.1.3" authors = ["trivernis "] edition = "2018" readme = "README.md" diff --git a/src/result.rs b/src/result.rs index b3c940c..367804f 100644 --- a/src/result.rs +++ b/src/result.rs @@ -1,3 +1,4 @@ +use crate::server::CRATE_VERSION; use std::error::Error; use std::{fmt, io}; @@ -16,6 +17,7 @@ pub enum VentedError { UnknownNode(String), Rejected, AuthFailed, + VersionMismatch(String), } impl fmt::Display for VentedError { @@ -32,6 +34,11 @@ impl fmt::Display for VentedError { Self::NotAServer(n) => write!(f, "The given node {} is not a server", n), Self::Rejected => write!(f, "The connection was rejected"), Self::AuthFailed => write!(f, "Failed to authenticate the other party"), + Self::VersionMismatch(version) => write!( + f, + "Version mismatch: Expected {} got {}", + CRATE_VERSION, version + ), } } } diff --git a/src/server/mod.rs b/src/server/mod.rs index 635cd48..7bdd2fc 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -11,8 +11,8 @@ use crate::result::VentedError::UnknownNode; use crate::result::{VentedError, VentedResult}; use crate::server::data::{Node, ServerConnectionContext}; use crate::server::server_events::{ - AuthPayload, ChallengePayload, NodeInformationPayload, ACCEPT_EVENT, AUTH_EVENT, - CHALLENGE_EVENT, CONNECT_EVENT, READY_EVENT, REJECT_EVENT, + AuthPayload, ChallengePayload, NodeInformationPayload, VersionMismatchPayload, ACCEPT_EVENT, + AUTH_EVENT, CHALLENGE_EVENT, CONNECT_EVENT, MISMATCH_EVENT, READY_EVENT, REJECT_EVENT, }; use crossbeam_utils::sync::WaitGroup; use parking_lot::Mutex; @@ -24,6 +24,8 @@ use x25519_dalek::StaticSecret; pub mod data; pub mod server_events; +pub(crate) const CRATE_VERSION: &str = env!("CARGO_PKG_VERSION"); + /// The vented server that provides parallel handling of connections /// Usage: /// ```rust @@ -296,6 +298,7 @@ impl VentedServer { &NodeInformationPayload { public_key: secret_key.public_key().to_bytes(), node_id: own_node_id, + vented_version: CRATE_VERSION.to_string(), }, ) .as_bytes(), @@ -308,8 +311,21 @@ impl VentedServer { let NodeInformationPayload { public_key, node_id, + vented_version, } = event.get_payload::().unwrap(); + if !Self::compare_version(&vented_version, CRATE_VERSION) { + stream.write( + &Event::with_payload( + MISMATCH_EVENT, + &VersionMismatchPayload::new(CRATE_VERSION, &vented_version), + ) + .as_bytes(), + )?; + stream.flush()?; + return Err(VentedError::VersionMismatch(vented_version)); + } + let public_key = PublicKey::from(public_key); let secret_box = ChaChaBox::new(&public_key, &secret_key); @@ -348,9 +364,22 @@ impl VentedServer { let NodeInformationPayload { public_key, node_id, + vented_version, } = event.get_payload::().unwrap(); - let public_key = PublicKey::from(public_key); + if !Self::compare_version(&vented_version, CRATE_VERSION) { + stream.write( + &Event::with_payload( + MISMATCH_EVENT, + &VersionMismatchPayload::new(CRATE_VERSION, &vented_version), + ) + .as_bytes(), + )?; + stream.flush()?; + return Err(VentedError::VersionMismatch(vented_version)); + } + + let public_key = PublicKey::from(public_key); let node_data = if let Some(data) = known_nodes.lock().iter().find(|n| n.id == node_id) { data.clone() } else { @@ -365,6 +394,7 @@ impl VentedServer { &NodeInformationPayload { public_key: secret_key.public_key().to_bytes(), node_id: own_node_id, + vented_version: CRATE_VERSION.to_string(), }, ) .as_bytes(), @@ -443,4 +473,12 @@ impl VentedServer { Ok(()) } } + + /// Compares two version for their major and minor value + fn compare_version(a: &str, b: &str) -> bool { + let parts_a = a.split('.').collect::>(); + let parts_b = b.split('.').collect::>(); + + parts_a.get(0) == parts_b.get(0) && parts_a.get(1) == parts_b.get(1) + } } diff --git a/src/server/server_events.rs b/src/server/server_events.rs index c65cb88..c8cd847 100644 --- a/src/server/server_events.rs +++ b/src/server/server_events.rs @@ -5,6 +5,7 @@ pub(crate) const AUTH_EVENT: &str = "conn:authenticate"; pub(crate) const CHALLENGE_EVENT: &str = "conn:challenge"; pub(crate) const ACCEPT_EVENT: &str = "conn:accept"; pub(crate) const REJECT_EVENT: &str = "conn:reject"; +pub(crate) const MISMATCH_EVENT: &str = "conn:reject_version_mismatch"; pub const READY_EVENT: &str = "connection:ready"; @@ -12,6 +13,7 @@ pub const READY_EVENT: &str = "connection:ready"; pub(crate) struct NodeInformationPayload { pub node_id: String, pub public_key: [u8; 32], + pub vented_version: String, } #[derive(Serialize, Deserialize, Debug)] @@ -23,3 +25,18 @@ pub(crate) struct ChallengePayload { pub(crate) struct AuthPayload { pub calculated_secret: [u8; 32], } + +#[derive(Serialize, Deserialize, Debug)] +pub(crate) struct VersionMismatchPayload { + pub expected: String, + pub got: String, +} + +impl VersionMismatchPayload { + pub fn new(expected: &str, got: &str) -> Self { + Self { + expected: expected.to_string(), + got: got.to_string(), + } + } +}