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

View File

@ -19,9 +19,14 @@ serde_json = "1.0"
lazy_static = "1.4"
clap = "2.33"
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]
cc = "1.0"
hbb_common = { path = "libs/hbb_common" }
[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 relay_server::*;
use std::sync::{Arc, Mutex};
mod lic;
fn main() -> ResultType<()> {
init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info"));
let args = format!(
"-p, --port=[NUMBER(default={})] 'Sets the listening port'
-k, --key=[KEY] 'Only allow the client with the same key'
{}
",
DEFAULT_PORT
DEFAULT_PORT,
lic::EMAIL_ARG
);
let matches = App::new("hbbr")
.version(hbbs::VERSION)
@ -18,6 +21,9 @@ fn main() -> ResultType<()> {
.about("RustDesk Relay Server")
.args_from_usage(&args)
.get_matches();
if !lic::check_lic(matches.value_of("email").unwrap_or("")) {
return Ok(());
}
let stop: Arc<Mutex<bool>> = Default::default();
start(
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 hbb_common::{env_logger::*, log, ResultType};
use hbbs::*;
mod lic;
use ini::Ini;
use std::sync::{Arc, Mutex};
@ -16,8 +17,11 @@ fn main() -> ResultType<()> {
-R, --rendezvous-servers=[HOSTS] 'Sets rendezvous servers, seperated by colon'
-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'
-C, --change-id=[BOOL(default=Y)] 'Sets if support to change id'
{}
-k, --key=[KEY] 'Only allow the client with the same key'",
DEFAULT_PORT,
lic::EMAIL_ARG
);
let matches = App::new("hbbs")
.version(crate::VERSION)
@ -43,6 +47,9 @@ fn main() -> ResultType<()> {
}
return default.to_owned();
};
if !lic::check_lic(&get_arg("email", "")) {
return Ok(());
}
let port = get_arg("port", DEFAULT_PORT);
let relay_servers: Vec<String> = get_arg("relay-servers", "")
.split(",")
@ -50,6 +57,7 @@ fn main() -> ResultType<()> {
.map(|x| x.to_owned())
.collect();
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", "")
.split(",")
.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("key", ""),
stop,
id_change_support,
)?;
Ok(())
}

View File

@ -164,6 +164,7 @@ impl RendezvousServer {
software_url: String,
key: &str,
stop: Arc<Mutex<bool>>,
id_change_support: bool,
) -> ResultType<()> {
if !key.is_empty() {
log::info!("Key: {}", key);
@ -171,6 +172,7 @@ impl RendezvousServer {
log::info!("Listening on tcp/udp {}", addr);
log::info!("Listening on tcp {}, extra port for NAT test", addr2);
log::info!("relay-servers={:?}", relay_servers);
log::info!("change-id={:?}", id_change_support);
let mut socket = FramedSocket::new(addr).await?;
let (tx, mut rx) = mpsc::unbounded_channel::<(RendezvousMessage, SocketAddr)>();
let version = hbb_common::get_version_from_url(&software_url);
@ -202,6 +204,7 @@ impl RendezvousServer {
&mut socket,
key,
stop.clone(),
id_change_support,
)
.await;
}
@ -215,6 +218,7 @@ impl RendezvousServer {
socket: &mut FramedSocket,
key: &str,
stop: Arc<Mutex<bool>>,
id_change_support: bool,
) {
let mut timer = interval(Duration::from_millis(100));
loop {
@ -321,6 +325,31 @@ impl RendezvousServer {
}
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;
}
@ -372,7 +401,7 @@ impl RendezvousServer {
let id = rk.id;
let mut res = register_pk_response::Result::OK;
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!(
"Peer {} uuid mismatch: {:?} vs {:?}",
id,
@ -380,7 +409,7 @@ impl RendezvousServer {
peer.uuid
);
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);
}
} else {
@ -611,6 +640,17 @@ impl RendezvousServer {
},
};
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 {
log::debug!(
"Fetch local addr {:?} {:?} request from {:?}",
@ -618,13 +658,9 @@ impl RendezvousServer {
&peer.socket_addr,
&addr
);
let i = unsafe {
ROTATION_RELAY_SERVER += 1;
ROTATION_RELAY_SERVER % self.relay_servers.len()
};
msg_out.set_fetch_local_addr(FetchLocalAddr {
socket_addr,
relay_server: self.relay_servers[i].clone(),
relay_server,
..Default::default()
});
} else {
@ -634,14 +670,10 @@ impl RendezvousServer {
&peer.socket_addr,
&addr
);
let i = unsafe {
ROTATION_RELAY_SERVER += 1;
ROTATION_RELAY_SERVER % self.relay_servers.len()
};
msg_out.set_punch_hole(PunchHole {
socket_addr,
nat_type: ph.nat_type,
relay_server: self.relay_servers[i].clone(),
relay_server,
..Default::default()
});
}