enc punch

This commit is contained in:
rustdesk
2023-05-14 18:17:02 +08:00
parent a26de5a86a
commit baecf3edb8
9 changed files with 308 additions and 214 deletions

View File

@@ -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(())
}