181 lines
5.4 KiB
Rust
181 lines
5.4 KiB
Rust
|
|
use crate::records::memory::connections::CONNECTIONS;
|
||
|
|
use crate::records::memory::response_channels::{generate_uid, Command};
|
||
|
|
use crate::rpc::responses::RpcResponse;
|
||
|
|
use crate::rpc::server::structs::HandshakeTestParams;
|
||
|
|
use crate::rpc::server::tests::{ip_test, is_within_one_second};
|
||
|
|
use crate::wallets::structures::Wallet;
|
||
|
|
use crate::Arc;
|
||
|
|
use crate::Mutex;
|
||
|
|
use crate::TcpStream;
|
||
|
|
|
||
|
|
pub async fn connection_count() -> usize {
|
||
|
|
// get memory read lock
|
||
|
|
let connection_storage = CONNECTIONS.read().await;
|
||
|
|
|
||
|
|
// read number of connected clients or set to 0 if none
|
||
|
|
let count = if let Some(connections) = connection_storage.as_ref() {
|
||
|
|
connections.count_incoming_connections()
|
||
|
|
} else {
|
||
|
|
0
|
||
|
|
};
|
||
|
|
|
||
|
|
drop(connection_storage);
|
||
|
|
count
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn check_max_connections(
|
||
|
|
_map: Arc<Mutex<Command>>,
|
||
|
|
stream: Arc<Mutex<TcpStream>>,
|
||
|
|
count: usize,
|
||
|
|
incoming_connections: u8,
|
||
|
|
) -> bool {
|
||
|
|
if count >= incoming_connections as usize {
|
||
|
|
// Handshake failures still use the normal RPC response framing,
|
||
|
|
// so generate a temporary UID for the error packet.
|
||
|
|
let hashmap_key = generate_uid();
|
||
|
|
let padded_bytes = [hashmap_key[0], hashmap_key[1], hashmap_key[2], 0];
|
||
|
|
let uid = u32::from_le_bytes(padded_bytes);
|
||
|
|
|
||
|
|
let response_bytes = RpcResponse::Binary({
|
||
|
|
let msg = "error: Sorry all our connections are filled. Please try again later."
|
||
|
|
.to_string()
|
||
|
|
.as_bytes()
|
||
|
|
.to_vec();
|
||
|
|
msg
|
||
|
|
});
|
||
|
|
response_bytes.send(&stream, None, uid).await;
|
||
|
|
true
|
||
|
|
} else {
|
||
|
|
false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn verify_timestamp(
|
||
|
|
_map: Arc<Mutex<Command>>,
|
||
|
|
stream: Arc<Mutex<TcpStream>>,
|
||
|
|
peer_time: u32,
|
||
|
|
timestamp: u32,
|
||
|
|
) -> bool {
|
||
|
|
if !is_within_one_second(timestamp, peer_time) {
|
||
|
|
// Tight timestamp checks keep peers from replaying stale signed
|
||
|
|
// handshakes after the connection attempt has passed.
|
||
|
|
let hashmap_key = generate_uid();
|
||
|
|
let padded_bytes = [hashmap_key[0], hashmap_key[1], hashmap_key[2], 0];
|
||
|
|
let uid = u32::from_le_bytes(padded_bytes);
|
||
|
|
|
||
|
|
let response_bytes = RpcResponse::Binary({
|
||
|
|
let msg = format!(
|
||
|
|
"error: Handshake Failed: The time on your computer must be within 1 second of the time of our server. Your local time: {peer_time}. Our server time: {timestamp}. Please consider installing NTP to ensure proper timestamps."
|
||
|
|
)
|
||
|
|
.as_bytes()
|
||
|
|
.to_vec();
|
||
|
|
msg
|
||
|
|
});
|
||
|
|
|
||
|
|
response_bytes.send(&stream, None, uid).await;
|
||
|
|
false
|
||
|
|
} else {
|
||
|
|
true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn verify_ip_address(
|
||
|
|
_map: Arc<Mutex<Command>>,
|
||
|
|
stream: Arc<Mutex<TcpStream>>,
|
||
|
|
received_ip: &str,
|
||
|
|
) -> bool {
|
||
|
|
if !ip_test(received_ip, &stream).await {
|
||
|
|
// The peer must announce the same public endpoint it is using
|
||
|
|
// for this socket, otherwise it cannot be trusted as a node.
|
||
|
|
let hashmap_key = generate_uid();
|
||
|
|
let padded_bytes = [hashmap_key[0], hashmap_key[1], hashmap_key[2], 0];
|
||
|
|
let uid = u32::from_le_bytes(padded_bytes);
|
||
|
|
|
||
|
|
let response_bytes = RpcResponse::Binary({
|
||
|
|
let msg = "error: Handshake Failed: You must use a public IP, and your computer must be accessible by others. Please check your configuration, firewall settings, or NAT settings.".to_string().as_bytes().to_vec();
|
||
|
|
msg
|
||
|
|
});
|
||
|
|
|
||
|
|
response_bytes.send(&stream, None, uid).await;
|
||
|
|
false
|
||
|
|
} else {
|
||
|
|
true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn verify_handshake(
|
||
|
|
stream: Arc<Mutex<TcpStream>>,
|
||
|
|
_map: Arc<Mutex<Command>>,
|
||
|
|
hash: &str,
|
||
|
|
received_signed_message: &str,
|
||
|
|
received_address: &str,
|
||
|
|
) -> bool {
|
||
|
|
// Signature verification proves the peer controls the wallet address
|
||
|
|
// embedded in the handshake request.
|
||
|
|
let hashmap_key = generate_uid();
|
||
|
|
let padded_bytes = [hashmap_key[0], hashmap_key[1], hashmap_key[2], 0];
|
||
|
|
let uid = u32::from_le_bytes(padded_bytes);
|
||
|
|
|
||
|
|
if !Wallet::verify_transaction(hash, received_signed_message, received_address).await {
|
||
|
|
let response_bytes = RpcResponse::Binary({
|
||
|
|
"error: Handshake failed: Invalid handshake"
|
||
|
|
.to_string()
|
||
|
|
.as_bytes()
|
||
|
|
.to_vec()
|
||
|
|
});
|
||
|
|
response_bytes.send(&stream, None, uid).await;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
true
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn perform_handshake_tests(params: HandshakeTestParams<'_>) -> bool {
|
||
|
|
// Stop at the first failed gate because each check sends the exact
|
||
|
|
// error response that explains why the handshake was rejected.
|
||
|
|
//check connection limits
|
||
|
|
if check_max_connections(
|
||
|
|
params.map.clone(),
|
||
|
|
params.stream.clone(),
|
||
|
|
params.count,
|
||
|
|
params.incoming_connections,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
// verify timestmap
|
||
|
|
if !verify_timestamp(
|
||
|
|
params.map.clone(),
|
||
|
|
params.stream.clone(),
|
||
|
|
params.peer_time,
|
||
|
|
params.timestamp,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
// verify IP
|
||
|
|
if !verify_ip_address(
|
||
|
|
params.map.clone(),
|
||
|
|
params.stream.clone(),
|
||
|
|
params.received_ip,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
// verify handshake
|
||
|
|
if !verify_handshake(
|
||
|
|
params.stream.clone(),
|
||
|
|
params.map.clone(),
|
||
|
|
params.hash,
|
||
|
|
params.received_signed_message,
|
||
|
|
params.received_address,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
true
|
||
|
|
}
|