This commit is contained in:
rustdesk 2021-04-11 01:34:44 +08:00
commit a8d3ba56b2
7 changed files with 229 additions and 16 deletions

53
Cargo.lock generated
View File

@ -223,6 +223,12 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "cryptoxide"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46212f5d1792f89c3e866fb10636139464060110c568edd7f73ab5e9f736c26d"
[[package]] [[package]]
name = "ct-logs" name = "ct-logs"
version = "0.6.0" version = "0.6.0"
@ -514,6 +520,7 @@ dependencies = [
"protobuf-codegen-pure", "protobuf-codegen-pure",
"quinn", "quinn",
"rand", "rand",
"regex",
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
@ -530,15 +537,20 @@ dependencies = [
name = "hbbs" name = "hbbs"
version = "1.1.3" version = "1.1.3"
dependencies = [ dependencies = [
"cc", "base64 0.13.0",
"clap", "clap",
"cryptoxide",
"hbb_common", "hbb_common",
"lazy_static", "lazy_static",
"mac_address",
"machine-uid",
"minreq",
"rocksdb", "rocksdb",
"rust-ini", "rust-ini",
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
"whoami",
] ]
[[package]] [[package]]
@ -687,12 +699,30 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "machine-uid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f1595709b0a7386bcd56ba34d250d626e5503917d05d32cdccddcd68603e212"
dependencies = [
"winreg",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.3.4" version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "minreq"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "781e56f7d29192378f0a04948b1e6aec67ce561273b2dd26ac510bbe88d7be70"
dependencies = [
"punycode",
]
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.6.22" version = "0.6.22"
@ -945,6 +975,12 @@ dependencies = [
"protobuf-codegen", "protobuf-codegen",
] ]
[[package]]
name = "punycode"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9e1dcb320d6839f6edb64f7a4a59d39b30480d4d1765b56873f7c858538a5fe"
[[package]] [[package]]
name = "quick-error" name = "quick-error"
version = "1.2.3" version = "1.2.3"
@ -1549,6 +1585,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "whoami"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7884773ab69074615cb8f8425d0e53f11710786158704fca70f53e71b0e05504"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.2.8" version = "0.2.8"
@ -1592,6 +1634,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "winreg"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
dependencies = [
"winapi 0.3.9",
]
[[package]] [[package]]
name = "ws2_32-sys" name = "ws2_32-sys"
version = "0.2.1" version = "0.2.1"

View File

@ -19,9 +19,14 @@ serde_json = "1.0"
lazy_static = "1.4" lazy_static = "1.4"
clap = "2.33" clap = "2.33"
rust-ini = "0.16" rust-ini = "0.16"
minreq = { version = "2.3.1", features = ["punycode"] }
machine-uid = "0.2"
mac_address = "1.1"
whoami = "0.9"
base64 = "0.13"
cryptoxide = "0.3"
[build-dependencies] [build-dependencies]
cc = "1.0"
hbb_common = { path = "libs/hbb_common" } hbb_common = { path = "libs/hbb_common" }
[workspace] [workspace]

@ -1 +1 @@
Subproject commit 002939a1037c786d2651a779492a7c813ea4e54a Subproject commit 99487187a6b25380b9a412f040f43f319ece7545

View File

@ -3,14 +3,17 @@ mod relay_server;
use hbb_common::{env_logger::*, ResultType}; use hbb_common::{env_logger::*, ResultType};
use relay_server::*; use relay_server::*;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
mod lic;
fn main() -> ResultType<()> { fn main() -> ResultType<()> {
init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info"));
let args = format!( let args = format!(
"-p, --port=[NUMBER(default={})] 'Sets the listening port' "-p, --port=[NUMBER(default={})] 'Sets the listening port'
-k, --key=[KEY] 'Only allow the client with the same key' -k, --key=[KEY] 'Only allow the client with the same key'
{}
", ",
DEFAULT_PORT DEFAULT_PORT,
lic::EMAIL_ARG
); );
let matches = App::new("hbbr") let matches = App::new("hbbr")
.version(hbbs::VERSION) .version(hbbs::VERSION)
@ -18,6 +21,9 @@ fn main() -> ResultType<()> {
.about("RustDesk Relay Server") .about("RustDesk Relay Server")
.args_from_usage(&args) .args_from_usage(&args)
.get_matches(); .get_matches();
if !lic::check_lic(matches.value_of("email").unwrap_or("")) {
return Ok(());
}
let stop: Arc<Mutex<bool>> = Default::default(); let stop: Arc<Mutex<bool>> = Default::default();
start( start(
matches.value_of("port").unwrap_or(DEFAULT_PORT), matches.value_of("port").unwrap_or(DEFAULT_PORT),

110
src/lic.rs Normal file
View File

@ -0,0 +1,110 @@
use hbb_common::{bail, log, ResultType};
use serde_derive::{Deserialize, Serialize};
use std::io::prelude::*;
use std::path::Path;
#[derive(Debug, PartialEq, Default, Serialize, Deserialize, Clone)]
pub struct Machine {
#[serde(default)]
hostname: String,
#[serde(default)]
uid: String,
#[serde(default)]
mac: String,
}
#[derive(Debug, PartialEq, Default, Serialize, Deserialize, Clone)]
pub struct Post {
#[serde(default)]
machine: String,
#[serde(default)]
email: String,
#[serde(default)]
status: String,
}
const LICENSE_FILE: &'static str = ".license.txt";
pub fn check_lic(email: &str) -> bool {
let machine = get_lic();
let path = Path::new(LICENSE_FILE);
if Path::is_file(&path) {
let contents = std::fs::read_to_string(&path).unwrap_or("".to_owned());
if verify(&contents, &machine) {
return true;
}
}
if email.is_empty() {
log::error!("Registered email required (-m option). Please visit https://rustdesk.com/server for more infomration.");
return false;
}
match check_email(machine, email.to_owned()) {
Ok(v) => {
return v;
}
Err(err) => {
log::error!("{}", err);
return false;
}
}
}
fn write_lic(lic: &str) {
if let Ok(mut f) = std::fs::File::create(LICENSE_FILE) {
f.write_all(lic.as_bytes()).ok();
f.sync_all().ok();
}
}
fn check_email(machine: String, email: String) -> ResultType<bool> {
log::info!("Checking email with the server ...");
let resp = minreq::post("http://rustdesk.com/api/check-email")
.with_body(
serde_json::to_string(&Post {
machine: machine.clone(),
email,
..Default::default()
})
.unwrap(),
)
.send()?;
if resp.reason_phrase == "OK" {
let p: Post = serde_json::from_str(&resp.as_str()?)?;
if !p.status.is_empty() {
bail!("{}", p.status);
}
if !verify(&p.machine, &machine) {
bail!("Verification failure");
}
write_lic(&p.machine);
} else {
bail!("Server error: {}", resp.reason_phrase);
}
Ok(true)
}
fn get_lic() -> String {
let hostname = whoami::hostname();
let uid = machine_uid::get().unwrap_or("".to_owned());
let mac = if let Ok(Some(ma)) = mac_address::get_mac_address() {
base64::encode(ma.bytes())
} else {
"".to_owned()
};
serde_json::to_string(&Machine { hostname, uid, mac }).unwrap()
}
fn verify(enc_str: &str, msg: &str) -> bool {
if let Ok(data) = base64::decode(enc_str) {
let key =
b"\xf1T\xc0\x1c\xffee\x86,S*\xd9.\x91\xcd\x85\x12:\xec\xa9 \x99:\x8a\xa2S\x1f Yy\x93R";
cryptoxide::ed25519::verify(msg.as_bytes(), &key[..], &data)
} else {
false
}
}
pub const EMAIL_ARG: &'static str =
"-m, --email=[EMAIL] 'Sets your email address registered with RustDesk'";

View File

@ -4,6 +4,7 @@
use clap::App; use clap::App;
use hbb_common::{env_logger::*, log, ResultType}; use hbb_common::{env_logger::*, log, ResultType};
use hbbs::*; use hbbs::*;
mod lic;
use ini::Ini; use ini::Ini;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -16,8 +17,11 @@ fn main() -> ResultType<()> {
-R, --rendezvous-servers=[HOSTS] 'Sets rendezvous servers, seperated by colon' -R, --rendezvous-servers=[HOSTS] 'Sets rendezvous servers, seperated by colon'
-u, --software-url=[URL] 'Sets download url of RustDesk software of newest version' -u, --software-url=[URL] 'Sets download url of RustDesk software of newest version'
-r, --relay-servers=[HOST] 'Sets the default relay servers, seperated by colon' -r, --relay-servers=[HOST] 'Sets the default relay servers, seperated by colon'
-C, --change-id=[BOOL(default=Y)] 'Sets if support to change id'
{}
-k, --key=[KEY] 'Only allow the client with the same key'", -k, --key=[KEY] 'Only allow the client with the same key'",
DEFAULT_PORT, DEFAULT_PORT,
lic::EMAIL_ARG
); );
let matches = App::new("hbbs") let matches = App::new("hbbs")
.version(crate::VERSION) .version(crate::VERSION)
@ -43,6 +47,9 @@ fn main() -> ResultType<()> {
} }
return default.to_owned(); return default.to_owned();
}; };
if !lic::check_lic(&get_arg("email", "")) {
return Ok(());
}
let port = get_arg("port", DEFAULT_PORT); let port = get_arg("port", DEFAULT_PORT);
let relay_servers: Vec<String> = get_arg("relay-servers", "") let relay_servers: Vec<String> = get_arg("relay-servers", "")
.split(",") .split(",")
@ -50,6 +57,7 @@ fn main() -> ResultType<()> {
.map(|x| x.to_owned()) .map(|x| x.to_owned())
.collect(); .collect();
let serial: i32 = get_arg("serial", "").parse().unwrap_or(0); let serial: i32 = get_arg("serial", "").parse().unwrap_or(0);
let id_change_support: bool = get_arg("change-id", "Y").to_uppercase() == "Y";
let rendezvous_servers: Vec<String> = get_arg("rendezvous-servers", "") let rendezvous_servers: Vec<String> = get_arg("rendezvous-servers", "")
.split(",") .split(",")
.filter(|x| !x.is_empty() && test_if_valid_server(x, "rendezvous-server").is_ok()) .filter(|x| !x.is_empty() && test_if_valid_server(x, "rendezvous-server").is_ok())
@ -69,6 +77,7 @@ fn main() -> ResultType<()> {
get_arg("software-url", ""), get_arg("software-url", ""),
&get_arg("key", ""), &get_arg("key", ""),
stop, stop,
id_change_support,
)?; )?;
Ok(()) Ok(())
} }

View File

@ -164,6 +164,7 @@ impl RendezvousServer {
software_url: String, software_url: String,
key: &str, key: &str,
stop: Arc<Mutex<bool>>, stop: Arc<Mutex<bool>>,
id_change_support: bool,
) -> ResultType<()> { ) -> ResultType<()> {
if !key.is_empty() { if !key.is_empty() {
log::info!("Key: {}", key); log::info!("Key: {}", key);
@ -171,6 +172,7 @@ impl RendezvousServer {
log::info!("Listening on tcp/udp {}", addr); log::info!("Listening on tcp/udp {}", addr);
log::info!("Listening on tcp {}, extra port for NAT test", addr2); log::info!("Listening on tcp {}, extra port for NAT test", addr2);
log::info!("relay-servers={:?}", relay_servers); log::info!("relay-servers={:?}", relay_servers);
log::info!("change-id={:?}", id_change_support);
let mut socket = FramedSocket::new(addr).await?; let mut socket = FramedSocket::new(addr).await?;
let (tx, mut rx) = mpsc::unbounded_channel::<(RendezvousMessage, SocketAddr)>(); let (tx, mut rx) = mpsc::unbounded_channel::<(RendezvousMessage, SocketAddr)>();
let version = hbb_common::get_version_from_url(&software_url); let version = hbb_common::get_version_from_url(&software_url);
@ -202,6 +204,7 @@ impl RendezvousServer {
&mut socket, &mut socket,
key, key,
stop.clone(), stop.clone(),
id_change_support,
) )
.await; .await;
} }
@ -215,6 +218,7 @@ impl RendezvousServer {
socket: &mut FramedSocket, socket: &mut FramedSocket,
key: &str, key: &str,
stop: Arc<Mutex<bool>>, stop: Arc<Mutex<bool>>,
id_change_support: bool,
) { ) {
let mut timer = interval(Duration::from_millis(100)); let mut timer = interval(Duration::from_millis(100));
loop { loop {
@ -321,6 +325,31 @@ impl RendezvousServer {
} }
break; break;
} }
Some(rendezvous_message::Union::register_pk(rk)) => {
if rk.uuid.is_empty() {
break;
}
let mut res = register_pk_response::Result::OK;
if !id_change_support {
res = register_pk_response::Result::NOT_SUPPORT;
} else if !hbb_common::is_valid_custom_id(&rk.id) {
res = register_pk_response::Result::INVALID_ID_FORMAT;
} else if let Some(peer) = rs.pm.get(&rk.id).await {
if peer.uuid != rk.uuid {
res = register_pk_response::Result::ID_EXISTS;
}
}
let mut msg_out = RendezvousMessage::new();
msg_out.set_register_pk_response(RegisterPkResponse {
result: res.into(),
..Default::default()
});
if let Some(tcp) = sender.as_mut() {
if let Ok(bytes) = msg_out.write_to_bytes() {
allow_err!(tcp.send(Bytes::from(bytes)).await);
}
}
}
_ => { _ => {
break; break;
} }
@ -372,7 +401,7 @@ impl RendezvousServer {
let id = rk.id; let id = rk.id;
let mut res = register_pk_response::Result::OK; let mut res = register_pk_response::Result::OK;
if let Some(peer) = self.pm.get(&id).await { if let Some(peer) = self.pm.get(&id).await {
if !peer.uuid.is_empty() && peer.uuid != rk.uuid { if peer.uuid != rk.uuid {
log::warn!( log::warn!(
"Peer {} uuid mismatch: {:?} vs {:?}", "Peer {} uuid mismatch: {:?} vs {:?}",
id, id,
@ -380,7 +409,7 @@ impl RendezvousServer {
peer.uuid peer.uuid
); );
res = register_pk_response::Result::UUID_MISMATCH; res = register_pk_response::Result::UUID_MISMATCH;
} else if peer.uuid.is_empty() || peer.pk != rk.pk { } else if peer.pk != rk.pk {
self.pm.update_pk(id, addr, rk.uuid, rk.pk); self.pm.update_pk(id, addr, rk.uuid, rk.pk);
} }
} else { } else {
@ -611,6 +640,17 @@ impl RendezvousServer {
}, },
}; };
let socket_addr = AddrMangle::encode(addr); let socket_addr = AddrMangle::encode(addr);
let relay_server = {
if self.relay_servers.is_empty() {
"".to_owned()
} else {
let i = unsafe {
ROTATION_RELAY_SERVER += 1;
ROTATION_RELAY_SERVER % self.relay_servers.len()
};
self.relay_servers[i].clone()
}
};
if same_intranet { if same_intranet {
log::debug!( log::debug!(
"Fetch local addr {:?} {:?} request from {:?}", "Fetch local addr {:?} {:?} request from {:?}",
@ -618,13 +658,9 @@ impl RendezvousServer {
&peer.socket_addr, &peer.socket_addr,
&addr &addr
); );
let i = unsafe {
ROTATION_RELAY_SERVER += 1;
ROTATION_RELAY_SERVER % self.relay_servers.len()
};
msg_out.set_fetch_local_addr(FetchLocalAddr { msg_out.set_fetch_local_addr(FetchLocalAddr {
socket_addr, socket_addr,
relay_server: self.relay_servers[i].clone(), relay_server,
..Default::default() ..Default::default()
}); });
} else { } else {
@ -634,14 +670,10 @@ impl RendezvousServer {
&peer.socket_addr, &peer.socket_addr,
&addr &addr
); );
let i = unsafe {
ROTATION_RELAY_SERVER += 1;
ROTATION_RELAY_SERVER % self.relay_servers.len()
};
msg_out.set_punch_hole(PunchHole { msg_out.set_punch_hole(PunchHole {
socket_addr, socket_addr,
nat_type: ph.nat_type, nat_type: ph.nat_type,
relay_server: self.relay_servers[i].clone(), relay_server,
..Default::default() ..Default::default()
}); });
} }