feat: self-connection blocking (A connects to A) server-side solution
This commit is contained in:
1 parent
29a953bd92
commit
18a966c28e
5 files changed
+165
-7
No files matched your search
@@ -40,6 +40,7 @@ use hbb_common::{
|
||||
use ipnetwork::Ipv4Network;
|
||||
|
||||
use crate::jwt;
|
||||
use crate::token_device;
|
||||
use std::io::Error;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
@@ -232,13 +233,16 @@ impl RendezvousServer {
|
||||
|
||||
let must_login = get_arg("must-login");
|
||||
log::debug!("must_login={}", must_login);
|
||||
if must_login.to_uppercase() == "Y"
|
||||
// 默认开启:仅当显式配置为 N(--must-login=N 或环境变量 MUST_LOGIN=N)时关闭
|
||||
if must_login.to_uppercase() == "N"
|
||||
|| (must_login == ""
|
||||
&& std::env::var("MUST_LOGIN")
|
||||
.unwrap_or_default()
|
||||
.to_uppercase()
|
||||
== "Y")
|
||||
== "N")
|
||||
{
|
||||
MUST_LOGIN.store(false, Ordering::SeqCst);
|
||||
} else {
|
||||
MUST_LOGIN.store(true, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
@@ -250,6 +254,11 @@ impl RendezvousServer {
|
||||
"N"
|
||||
}
|
||||
);
|
||||
if MUST_LOGIN.load(Ordering::SeqCst) && jwt::SECRET.is_empty() {
|
||||
log::warn!("RUSTDESK_API_JWT_KEY is not set: client token verification and self-connection blocking are DISABLED (fail-open). Set RUSTDESK_API_JWT_KEY to enable them.");
|
||||
} else if !jwt::SECRET.is_empty() {
|
||||
log::info!("Self-connection blocking: enabled (requires client login)");
|
||||
}
|
||||
if test_addr.to_lowercase() != "no" {
|
||||
let test_addr = if test_addr.is_empty() {
|
||||
listener.local_addr()?
|
||||
@@ -562,6 +571,31 @@ impl RendezvousServer {
|
||||
if let Some(sink) = sink.take() {
|
||||
self.tcp_punch.lock().await.insert(try_into_v4(addr), sink);
|
||||
}
|
||||
// 补上 MUST_LOGIN 强制校验(打洞处已有,中继处此前缺失)
|
||||
if MUST_LOGIN.load(Ordering::SeqCst)
|
||||
&& (rf.token.is_empty()
|
||||
|| (!jwt::SECRET.is_empty()
|
||||
&& jwt::verify_token(&rf.token).is_err()))
|
||||
{
|
||||
log::warn!("RequestRelay rejected from {}: token missing or invalid", addr);
|
||||
return true;
|
||||
}
|
||||
// 自连检测(fail-open:无 token/查询失败时跳过)
|
||||
if !rf.token.is_empty()
|
||||
&& !jwt::SECRET.is_empty()
|
||||
&& jwt::verify_token(&rf.token).is_ok()
|
||||
{
|
||||
if let Some(device_id) = token_device::get_device_id(&rf.token).await {
|
||||
if device_id == rf.id {
|
||||
log::warn!(
|
||||
"Blocked self-connection relay attempt from {} (device id {})",
|
||||
addr,
|
||||
rf.id
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(peer) = self.pm.get_in_memory(&rf.id).await {
|
||||
let mut msg_out = RendezvousMessage::new();
|
||||
rf.socket_addr = AddrMangle::encode(addr).into();
|
||||
@@ -938,8 +972,7 @@ impl RendezvousServer {
|
||||
});
|
||||
return Ok((msg_out, None));
|
||||
} else if !jwt::SECRET.is_empty() {
|
||||
let token = ph.token;
|
||||
let token = jwt::verify_token(token.as_str());
|
||||
let token = jwt::verify_token(&ph.token);
|
||||
if token.is_err() {
|
||||
let mut msg_out = RendezvousMessage::new();
|
||||
msg_out.set_punch_hole_response(PunchHoleResponse {
|
||||
@@ -951,6 +984,30 @@ impl RendezvousServer {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 自连检测:token 有效且查得到登录设备ID时,拦截"远程连接自己"。
|
||||
// 无 token(MUST_LOGIN=N 下未登录)或查询失败时跳过(fail-open,保持现状行为)。
|
||||
if !ph.token.is_empty() && !jwt::SECRET.is_empty() {
|
||||
let token_ok = MUST_LOGIN.load(Ordering::SeqCst) || jwt::verify_token(&ph.token).is_ok();
|
||||
if token_ok {
|
||||
if let Some(device_id) = token_device::get_device_id(&ph.token).await {
|
||||
if device_id == ph.id {
|
||||
log::warn!(
|
||||
"Blocked self-connection attempt from {} (device id {})",
|
||||
addr,
|
||||
ph.id
|
||||
);
|
||||
let mut msg_out = RendezvousMessage::new();
|
||||
msg_out.set_punch_hole_response(PunchHoleResponse {
|
||||
other_failure: String::from(
|
||||
"不能远程自己:发起方与目标是同一台设备 / You are connecting to yourself",
|
||||
),
|
||||
..Default::default()
|
||||
});
|
||||
return Ok((msg_out, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let id = ph.id;
|
||||
// punch hole request from A, relay to B,
|
||||
// check if in same intranet first,
|
||||
|
||||
Reference in new issue
Block a user