mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-03-26 22:51:03 +03:00
enc punch
This commit is contained in:
203
src/client.rs
203
src/client.rs
@@ -31,10 +31,7 @@ use hbb_common::{
|
||||
allow_err,
|
||||
anyhow::{anyhow, Context},
|
||||
bail,
|
||||
config::{
|
||||
Config, PeerConfig, PeerInfoSerde, CONNECT_TIMEOUT, READ_TIMEOUT, RELAY_PORT,
|
||||
RENDEZVOUS_TIMEOUT,
|
||||
},
|
||||
config::{Config, PeerConfig, PeerInfoSerde, CONNECT_TIMEOUT, READ_TIMEOUT, RELAY_PORT},
|
||||
get_version_number, log,
|
||||
message_proto::{option_message::BoolOption, *},
|
||||
protobuf::Message as _,
|
||||
@@ -42,6 +39,7 @@ use hbb_common::{
|
||||
rendezvous_proto::*,
|
||||
socket_client,
|
||||
sodiumoxide::crypto::{box_, secretbox, sign},
|
||||
tcp::FramedStream,
|
||||
timeout,
|
||||
tokio::time::Duration,
|
||||
AddrMangle, ResultType, Stream,
|
||||
@@ -239,7 +237,7 @@ impl Client {
|
||||
return Ok((
|
||||
socket_client::connect_tcp(
|
||||
crate::check_port(peer, RELAY_PORT + 1),
|
||||
RENDEZVOUS_TIMEOUT,
|
||||
CONNECT_TIMEOUT,
|
||||
)
|
||||
.await?,
|
||||
true,
|
||||
@@ -249,18 +247,18 @@ impl Client {
|
||||
// Allow connect to {domain}:{port}
|
||||
if hbb_common::is_domain_port_str(peer) {
|
||||
return Ok((
|
||||
socket_client::connect_tcp(peer, RENDEZVOUS_TIMEOUT).await?,
|
||||
socket_client::connect_tcp(peer, CONNECT_TIMEOUT).await?,
|
||||
true,
|
||||
None,
|
||||
));
|
||||
}
|
||||
let (mut rendezvous_server, servers, contained) = crate::get_rendezvous_server(1_000).await;
|
||||
let mut socket = socket_client::connect_tcp(&*rendezvous_server, RENDEZVOUS_TIMEOUT).await;
|
||||
let mut socket = socket_client::connect_tcp(&*rendezvous_server, CONNECT_TIMEOUT).await;
|
||||
debug_assert!(!servers.contains(&rendezvous_server));
|
||||
if socket.is_err() && !servers.is_empty() {
|
||||
log::info!("try the other servers: {:?}", servers);
|
||||
for server in servers {
|
||||
socket = socket_client::connect_tcp(&*server, RENDEZVOUS_TIMEOUT).await;
|
||||
socket = socket_client::connect_tcp(&*server, CONNECT_TIMEOUT).await;
|
||||
if socket.is_ok() {
|
||||
rendezvous_server = server;
|
||||
break;
|
||||
@@ -276,6 +274,11 @@ impl Client {
|
||||
let mut signed_id_pk = Vec::new();
|
||||
let mut relay_server = "".to_owned();
|
||||
|
||||
if !key.is_empty() && !token.is_empty() {
|
||||
// mainly for the security of token
|
||||
allow_err!(secure_punch_connection(&mut socket, key).await);
|
||||
}
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
let mut peer_addr = Config::get_any_listen_addr(true);
|
||||
let mut peer_nat_type = NatType::UNKNOWN_NAT;
|
||||
@@ -299,71 +302,69 @@ impl Client {
|
||||
..Default::default()
|
||||
});
|
||||
socket.send(&msg_out).await?;
|
||||
if let Some(Ok(bytes)) = socket.next_timeout(i * 6000).await {
|
||||
if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) {
|
||||
match msg_in.union {
|
||||
Some(rendezvous_message::Union::PunchHoleResponse(ph)) => {
|
||||
if ph.socket_addr.is_empty() {
|
||||
if !ph.other_failure.is_empty() {
|
||||
bail!(ph.other_failure);
|
||||
}
|
||||
match ph.failure.enum_value_or_default() {
|
||||
punch_hole_response::Failure::ID_NOT_EXIST => {
|
||||
bail!("ID does not exist");
|
||||
}
|
||||
punch_hole_response::Failure::OFFLINE => {
|
||||
bail!("Remote desktop is offline");
|
||||
}
|
||||
punch_hole_response::Failure::LICENSE_MISMATCH => {
|
||||
bail!("Key mismatch");
|
||||
}
|
||||
punch_hole_response::Failure::LICENSE_OVERUSE => {
|
||||
bail!("Key overuse");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
peer_nat_type = ph.nat_type();
|
||||
is_local = ph.is_local();
|
||||
signed_id_pk = ph.pk.into();
|
||||
relay_server = ph.relay_server;
|
||||
peer_addr = AddrMangle::decode(&ph.socket_addr);
|
||||
log::info!("Hole Punched {} = {}", peer, peer_addr);
|
||||
break;
|
||||
if let Some(msg_in) =
|
||||
crate::common::get_next_nonkeyexchange_msg(&mut socket, Some(i * 6000)).await
|
||||
{
|
||||
match msg_in.union {
|
||||
Some(rendezvous_message::Union::PunchHoleResponse(ph)) => {
|
||||
if ph.socket_addr.is_empty() {
|
||||
if !ph.other_failure.is_empty() {
|
||||
bail!(ph.other_failure);
|
||||
}
|
||||
}
|
||||
Some(rendezvous_message::Union::RelayResponse(rr)) => {
|
||||
log::info!(
|
||||
"relay requested from peer, time used: {:?}, relay_server: {}",
|
||||
start.elapsed(),
|
||||
rr.relay_server
|
||||
);
|
||||
signed_id_pk = rr.pk().into();
|
||||
let mut conn = Self::create_relay(
|
||||
peer,
|
||||
rr.uuid,
|
||||
rr.relay_server,
|
||||
key,
|
||||
conn_type,
|
||||
my_addr.is_ipv4(),
|
||||
)
|
||||
.await?;
|
||||
let pk = Self::secure_connection(
|
||||
peer,
|
||||
signed_id_pk,
|
||||
key,
|
||||
&mut conn,
|
||||
false,
|
||||
interface,
|
||||
)
|
||||
.await?;
|
||||
return Ok((conn, false, pk));
|
||||
}
|
||||
_ => {
|
||||
log::error!("Unexpected protobuf msg received: {:?}", msg_in);
|
||||
match ph.failure.enum_value_or_default() {
|
||||
punch_hole_response::Failure::ID_NOT_EXIST => {
|
||||
bail!("ID does not exist");
|
||||
}
|
||||
punch_hole_response::Failure::OFFLINE => {
|
||||
bail!("Remote desktop is offline");
|
||||
}
|
||||
punch_hole_response::Failure::LICENSE_MISMATCH => {
|
||||
bail!("Key mismatch");
|
||||
}
|
||||
punch_hole_response::Failure::LICENSE_OVERUSE => {
|
||||
bail!("Key overuse");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
peer_nat_type = ph.nat_type();
|
||||
is_local = ph.is_local();
|
||||
signed_id_pk = ph.pk.into();
|
||||
relay_server = ph.relay_server;
|
||||
peer_addr = AddrMangle::decode(&ph.socket_addr);
|
||||
log::info!("Hole Punched {} = {}", peer, peer_addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::error!("Non-protobuf message bytes received: {:?}", bytes);
|
||||
Some(rendezvous_message::Union::RelayResponse(rr)) => {
|
||||
log::info!(
|
||||
"relay requested from peer, time used: {:?}, relay_server: {}",
|
||||
start.elapsed(),
|
||||
rr.relay_server
|
||||
);
|
||||
signed_id_pk = rr.pk().into();
|
||||
let mut conn = Self::create_relay(
|
||||
peer,
|
||||
rr.uuid,
|
||||
rr.relay_server,
|
||||
key,
|
||||
conn_type,
|
||||
my_addr.is_ipv4(),
|
||||
)
|
||||
.await?;
|
||||
let pk = Self::secure_connection(
|
||||
peer,
|
||||
signed_id_pk,
|
||||
key,
|
||||
&mut conn,
|
||||
false,
|
||||
interface,
|
||||
)
|
||||
.await?;
|
||||
return Ok((conn, false, pk));
|
||||
}
|
||||
_ => {
|
||||
log::error!("Unexpected protobuf msg received: {:?}", msg_in);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -540,8 +541,15 @@ impl Client {
|
||||
if let Some(message::Union::SignedId(si)) = msg_in.union {
|
||||
if let Ok((id, their_pk_b)) = decode_id_pk(&si.id, &sign_pk) {
|
||||
if id == peer_id {
|
||||
let (msg, key) = create_symmetric_key_msg(their_pk_b);
|
||||
timeout(CONNECT_TIMEOUT, conn.send(&msg)).await??;
|
||||
let (asymmetric_value, symmetric_value, key) =
|
||||
create_symmetric_key_msg(their_pk_b);
|
||||
let mut msg_out = Message::new();
|
||||
msg_out.set_public_key(PublicKey {
|
||||
asymmetric_value,
|
||||
symmetric_value,
|
||||
..Default::default()
|
||||
});
|
||||
timeout(CONNECT_TIMEOUT, conn.send(&msg_out)).await??;
|
||||
conn.set_key(key);
|
||||
} else {
|
||||
log::error!("Handshake failed: sign failure");
|
||||
@@ -585,7 +593,7 @@ impl Client {
|
||||
let mut ipv4 = true;
|
||||
for i in 1..=3 {
|
||||
// use different socket due to current hbbs implement requiring different nat address for each attempt
|
||||
let mut socket = socket_client::connect_tcp(rendezvous_server, RENDEZVOUS_TIMEOUT)
|
||||
let mut socket = socket_client::connect_tcp(rendezvous_server, CONNECT_TIMEOUT)
|
||||
.await
|
||||
.with_context(|| "Failed to connect to rendezvous server")?;
|
||||
|
||||
@@ -2486,21 +2494,52 @@ fn decode_id_pk(signed: &[u8], key: &sign::PublicKey) -> ResultType<(String, [u8
|
||||
if let Some(pk) = get_pk(&res.pk) {
|
||||
Ok((res.id, pk))
|
||||
} else {
|
||||
bail!("Wrong public length");
|
||||
bail!("Wrong their public length");
|
||||
}
|
||||
}
|
||||
|
||||
fn create_symmetric_key_msg(their_pk_b: [u8; 32]) -> (Message, secretbox::Key) {
|
||||
fn create_symmetric_key_msg(their_pk_b: [u8; 32]) -> (Bytes, Bytes, secretbox::Key) {
|
||||
let their_pk_b = box_::PublicKey(their_pk_b);
|
||||
let (our_pk_b, out_sk_b) = box_::gen_keypair();
|
||||
let key = secretbox::gen_key();
|
||||
let nonce = box_::Nonce([0u8; box_::NONCEBYTES]);
|
||||
let sealed_key = box_::seal(&key.0, &nonce, &their_pk_b, &out_sk_b);
|
||||
let mut msg_out = Message::new();
|
||||
msg_out.set_public_key(PublicKey {
|
||||
asymmetric_value: Vec::from(our_pk_b.0).into(),
|
||||
symmetric_value: sealed_key.into(),
|
||||
..Default::default()
|
||||
});
|
||||
(msg_out, key)
|
||||
(Vec::from(our_pk_b.0).into(), sealed_key.into(), key)
|
||||
}
|
||||
|
||||
async fn secure_punch_connection(conn: &mut FramedStream, key: &str) -> ResultType<()> {
|
||||
let rs_pk = get_rs_pk(key);
|
||||
let Some(rs_pk) = rs_pk else {
|
||||
bail!("Handshake failed: invalid public key from rendezvous server");
|
||||
};
|
||||
match timeout(READ_TIMEOUT, conn.next()).await? {
|
||||
Some(Ok(bytes)) => {
|
||||
if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) {
|
||||
match msg_in.union {
|
||||
Some(rendezvous_message::Union::KeyExchange(ex)) => {
|
||||
if ex.keys.len() != 1 {
|
||||
bail!("Handshake failed: invalid key exchange message");
|
||||
}
|
||||
let their_pk_b = sign::verify(&ex.keys[0], &rs_pk)
|
||||
.map_err(|_| anyhow!("Signature mismatch in key exchange"))?;
|
||||
let (asymmetric_value, symmetric_value, key) = create_symmetric_key_msg(
|
||||
get_pk(&their_pk_b)
|
||||
.context("Wrong their public length in key exchange")?,
|
||||
);
|
||||
let mut msg_out = RendezvousMessage::new();
|
||||
msg_out.set_key_exchange(KeyExchange {
|
||||
keys: vec![asymmetric_value, symmetric_value],
|
||||
..Default::default()
|
||||
});
|
||||
timeout(CONNECT_TIMEOUT, conn.send(&msg_out)).await??;
|
||||
conn.set_key(key);
|
||||
log::info!("Token secured");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user