mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-06-14 03:32:00 +08:00
refactor: 删除部分多余的代码和注释
This commit is contained in:
@@ -1,8 +1,4 @@
|
||||
//! RustDesk Rendezvous Mediator
|
||||
//!
|
||||
//! This module handles communication with the hbbs rendezvous server.
|
||||
//! It registers the device ID and public key, handles punch hole requests,
|
||||
//! and relay requests.
|
||||
//! HBBS UDP registration; punch / relay / intranet callbacks.
|
||||
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
@@ -24,19 +20,14 @@ use super::protocol::{
|
||||
rendezvous_message, NatType, RendezvousMessage,
|
||||
};
|
||||
|
||||
/// Registration interval in milliseconds
|
||||
const REG_INTERVAL_MS: u64 = 12_000;
|
||||
|
||||
/// Minimum registration timeout
|
||||
const MIN_REG_TIMEOUT_MS: u64 = 3_000;
|
||||
|
||||
/// Maximum registration timeout
|
||||
const MAX_REG_TIMEOUT_MS: u64 = 30_000;
|
||||
|
||||
/// Timer interval for checking registration status
|
||||
const TIMER_INTERVAL_MS: u64 = 300;
|
||||
|
||||
/// Rendezvous mediator status
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum RendezvousStatus {
|
||||
Disconnected,
|
||||
@@ -58,44 +49,13 @@ impl std::fmt::Display for RendezvousStatus {
|
||||
}
|
||||
}
|
||||
|
||||
/// Callback for handling incoming connection requests
|
||||
pub type ConnectionCallback = Arc<dyn Fn(ConnectionRequest) + Send + Sync>;
|
||||
|
||||
/// Incoming connection request from a RustDesk client
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConnectionRequest {
|
||||
/// Peer socket address (encoded)
|
||||
pub socket_addr: Vec<u8>,
|
||||
/// Relay server to use
|
||||
pub relay_server: String,
|
||||
/// NAT type
|
||||
pub nat_type: NatType,
|
||||
/// Connection UUID
|
||||
pub uuid: String,
|
||||
/// Whether to use secure connection
|
||||
pub secure: bool,
|
||||
}
|
||||
|
||||
/// Callback type for relay requests
|
||||
/// Parameters: rendezvous_addr, relay_server, uuid, socket_addr (client's mangled address), device_id
|
||||
pub type RelayCallback = Arc<dyn Fn(String, String, String, Vec<u8>, String) + Send + Sync>;
|
||||
|
||||
/// Callback type for P2P punch hole requests
|
||||
/// Parameters: peer_addr (decoded), relay_callback_params (rendezvous_addr, relay_server, uuid, socket_addr, device_id)
|
||||
/// Returns: should call relay callback if P2P fails
|
||||
pub type PunchCallback =
|
||||
Arc<dyn Fn(Option<SocketAddr>, String, String, String, Vec<u8>, String) + Send + Sync>;
|
||||
|
||||
/// Callback type for intranet/local address connections
|
||||
/// Parameters: rendezvous_addr, peer_socket_addr (mangled), local_addr, relay_server, device_id
|
||||
pub type IntranetCallback = Arc<dyn Fn(String, Vec<u8>, SocketAddr, String, String) + Send + Sync>;
|
||||
|
||||
/// Rendezvous Mediator
|
||||
///
|
||||
/// Handles communication with hbbs rendezvous server:
|
||||
/// - Registers device ID and public key
|
||||
/// - Maintains keep-alive with server
|
||||
/// - Handles punch hole and relay requests
|
||||
pub struct RendezvousMediator {
|
||||
config: Arc<RwLock<RustDeskConfig>>,
|
||||
keypair: Arc<RwLock<Option<KeyPair>>>,
|
||||
@@ -114,11 +74,9 @@ pub struct RendezvousMediator {
|
||||
}
|
||||
|
||||
impl RendezvousMediator {
|
||||
/// Create a new rendezvous mediator
|
||||
pub fn new(mut config: RustDeskConfig) -> Self {
|
||||
let (shutdown_tx, _) = broadcast::channel(1);
|
||||
|
||||
// Get or generate UUID from config (persisted)
|
||||
let (uuid, uuid_needs_save) = config.ensure_uuid();
|
||||
|
||||
Self {
|
||||
@@ -139,88 +97,71 @@ impl RendezvousMediator {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the TCP listen port for direct connections
|
||||
pub fn set_listen_port(&self, port: u16) {
|
||||
let old_port = *self.listen_port.read();
|
||||
if old_port != port {
|
||||
*self.listen_port.write() = port;
|
||||
// Port changed, increment serial to notify server
|
||||
self.increment_serial();
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the TCP listen port
|
||||
pub fn listen_port(&self) -> u16 {
|
||||
*self.listen_port.read()
|
||||
}
|
||||
|
||||
/// Increment the serial number to indicate local state change
|
||||
pub fn increment_serial(&self) {
|
||||
let mut serial = self.serial.write();
|
||||
*serial = serial.wrapping_add(1);
|
||||
debug!("Serial incremented to {}", *serial);
|
||||
}
|
||||
|
||||
/// Get current serial number
|
||||
pub fn serial(&self) -> i32 {
|
||||
*self.serial.read()
|
||||
}
|
||||
|
||||
/// Check if UUID needs to be saved to persistent storage
|
||||
pub fn uuid_needs_save(&self) -> bool {
|
||||
*self.uuid_needs_save.read()
|
||||
}
|
||||
|
||||
/// Get the current config (with UUID set)
|
||||
pub fn config(&self) -> RustDeskConfig {
|
||||
self.config.read().clone()
|
||||
}
|
||||
|
||||
/// Mark UUID as saved
|
||||
pub fn mark_uuid_saved(&self) {
|
||||
*self.uuid_needs_save.write() = false;
|
||||
}
|
||||
|
||||
/// Set the callback for relay requests
|
||||
pub fn set_relay_callback(&self, callback: RelayCallback) {
|
||||
*self.relay_callback.write() = Some(callback);
|
||||
}
|
||||
|
||||
/// Set the callback for P2P punch hole requests
|
||||
pub fn set_punch_callback(&self, callback: PunchCallback) {
|
||||
*self.punch_callback.write() = Some(callback);
|
||||
}
|
||||
|
||||
/// Set the callback for intranet/local address connections
|
||||
pub fn set_intranet_callback(&self, callback: IntranetCallback) {
|
||||
*self.intranet_callback.write() = Some(callback);
|
||||
}
|
||||
|
||||
/// Get current status
|
||||
pub fn status(&self) -> RendezvousStatus {
|
||||
self.status.read().clone()
|
||||
}
|
||||
|
||||
/// Update configuration
|
||||
pub fn update_config(&self, config: RustDeskConfig) {
|
||||
*self.config.write() = config;
|
||||
// Config changed, increment serial to notify server
|
||||
self.increment_serial();
|
||||
}
|
||||
|
||||
/// Initialize or get keypair (Curve25519 for encryption)
|
||||
pub fn ensure_keypair(&self) -> KeyPair {
|
||||
let mut keypair_guard = self.keypair.write();
|
||||
if keypair_guard.is_none() {
|
||||
let config = self.config.read();
|
||||
// Try to load from config first
|
||||
if let (Some(pk), Some(sk)) = (&config.public_key, &config.private_key) {
|
||||
if let Ok(kp) = KeyPair::from_base64(pk, sk) {
|
||||
*keypair_guard = Some(kp.clone());
|
||||
return kp;
|
||||
}
|
||||
}
|
||||
// Generate new keypair
|
||||
let kp = KeyPair::generate();
|
||||
*keypair_guard = Some(kp.clone());
|
||||
kp
|
||||
@@ -229,12 +170,10 @@ impl RendezvousMediator {
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize or get signing keypair (Ed25519 for SignedId)
|
||||
pub fn ensure_signing_keypair(&self) -> SigningKeyPair {
|
||||
let mut signing_guard = self.signing_keypair.write();
|
||||
if signing_guard.is_none() {
|
||||
let config = self.config.read();
|
||||
// Try to load from config first
|
||||
if let (Some(pk), Some(sk)) = (&config.signing_public_key, &config.signing_private_key)
|
||||
{
|
||||
if let Ok(skp) = SigningKeyPair::from_base64(pk, sk) {
|
||||
@@ -245,7 +184,6 @@ impl RendezvousMediator {
|
||||
warn!("Failed to decode signing keypair from config, generating new one");
|
||||
}
|
||||
}
|
||||
// Generate new signing keypair
|
||||
let skp = SigningKeyPair::generate();
|
||||
debug!("Generated new signing keypair");
|
||||
*signing_guard = Some(skp.clone());
|
||||
@@ -255,12 +193,10 @@ impl RendezvousMediator {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the device ID
|
||||
pub fn device_id(&self) -> String {
|
||||
self.config.read().device_id.clone()
|
||||
}
|
||||
|
||||
/// Start the rendezvous mediator
|
||||
pub async fn start(&self) -> anyhow::Result<()> {
|
||||
let config = self.config.read().clone();
|
||||
let effective_server = config.effective_rendezvous_server();
|
||||
@@ -284,13 +220,11 @@ impl RendezvousMediator {
|
||||
config.device_id, addr
|
||||
);
|
||||
|
||||
// Resolve server address
|
||||
let server_addr: SocketAddr = tokio::net::lookup_host(&addr)
|
||||
.await?
|
||||
.next()
|
||||
.ok_or_else(|| anyhow::anyhow!("Failed to resolve {}", addr))?;
|
||||
|
||||
// Create UDP socket (match address family, enforce IPV6_V6ONLY)
|
||||
let bind_addr = match server_addr {
|
||||
SocketAddr::V4(_) => SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0),
|
||||
SocketAddr::V6(_) => SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0),
|
||||
@@ -302,11 +236,9 @@ impl RendezvousMediator {
|
||||
info!("Connected to rendezvous server at {}", server_addr);
|
||||
*self.status.write() = RendezvousStatus::Connected;
|
||||
|
||||
// Start registration loop
|
||||
self.registration_loop(socket).await
|
||||
}
|
||||
|
||||
/// Main registration loop
|
||||
async fn registration_loop(&self, socket: UdpSocket) -> anyhow::Result<()> {
|
||||
let mut timer = interval(Duration::from_millis(TIMER_INTERVAL_MS));
|
||||
let mut recv_buf = vec![0u8; 65535];
|
||||
@@ -318,7 +250,6 @@ impl RendezvousMediator {
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
// Handle incoming messages
|
||||
result = socket.recv(&mut recv_buf) => {
|
||||
match result {
|
||||
Ok(len) => {
|
||||
@@ -336,7 +267,6 @@ impl RendezvousMediator {
|
||||
}
|
||||
}
|
||||
|
||||
// Periodic registration
|
||||
_ = timer.tick() => {
|
||||
let now = Instant::now();
|
||||
let expired = last_register_resp
|
||||
@@ -360,7 +290,6 @@ impl RendezvousMediator {
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown signal
|
||||
_ = shutdown_rx.recv() => {
|
||||
info!("Rendezvous mediator shutting down");
|
||||
break;
|
||||
@@ -372,20 +301,16 @@ impl RendezvousMediator {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Send registration message
|
||||
async fn send_register(&self, socket: &UdpSocket) -> anyhow::Result<()> {
|
||||
let key_confirmed = *self.key_confirmed.read();
|
||||
|
||||
if !key_confirmed {
|
||||
// Send RegisterPk with public key
|
||||
self.send_register_pk(socket).await
|
||||
} else {
|
||||
// Send RegisterPeer heartbeat
|
||||
self.send_register_peer(socket).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Send RegisterPeer message
|
||||
async fn send_register_peer(&self, socket: &UdpSocket) -> anyhow::Result<()> {
|
||||
let id = self.device_id();
|
||||
let serial = *self.serial.read();
|
||||
@@ -398,12 +323,8 @@ impl RendezvousMediator {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Send RegisterPk message
|
||||
/// Uses the Ed25519 signing public key for registration
|
||||
async fn send_register_pk(&self, socket: &UdpSocket) -> anyhow::Result<()> {
|
||||
let id = self.device_id();
|
||||
// Use signing public key (Ed25519) for RegisterPk
|
||||
// This is what clients will use to verify our SignedId signature
|
||||
let signing_keypair = self.ensure_signing_keypair();
|
||||
let pk = signing_keypair.public_key_bytes();
|
||||
let uuid = *self.uuid.read();
|
||||
@@ -417,12 +338,6 @@ impl RendezvousMediator {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Handle FetchLocalAddr - send to callback for proper TCP handling
|
||||
///
|
||||
/// The intranet callback will:
|
||||
/// 1. Open a TCP connection to the rendezvous server
|
||||
/// 2. Send LocalAddr message
|
||||
/// 3. Accept the peer connection over that same TCP stream
|
||||
async fn send_local_addr(
|
||||
&self,
|
||||
_udp_socket: &UdpSocket,
|
||||
@@ -431,21 +346,17 @@ impl RendezvousMediator {
|
||||
) -> anyhow::Result<()> {
|
||||
let id = self.device_id();
|
||||
|
||||
// Get our actual local IP addresses for same-LAN connection
|
||||
let local_addrs = get_local_addresses();
|
||||
if local_addrs.is_empty() {
|
||||
debug!("No local addresses available for LocalAddr response");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Get the rendezvous server address for TCP connection
|
||||
let config = self.config.read().clone();
|
||||
let rendezvous_addr = config.rendezvous_addr();
|
||||
|
||||
// Use TCP listen port for direct connections
|
||||
let listen_port = self.listen_port();
|
||||
|
||||
// Use the first local IP
|
||||
let local_ip = local_addrs[0];
|
||||
let local_sock_addr = SocketAddr::new(local_ip, listen_port);
|
||||
|
||||
@@ -454,7 +365,6 @@ impl RendezvousMediator {
|
||||
local_sock_addr, rendezvous_addr
|
||||
);
|
||||
|
||||
// Call the intranet callback if set
|
||||
if let Some(callback) = self.intranet_callback.read().as_ref() {
|
||||
callback(
|
||||
rendezvous_addr,
|
||||
@@ -470,7 +380,6 @@ impl RendezvousMediator {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Handle response from rendezvous server
|
||||
async fn handle_response(
|
||||
&self,
|
||||
socket: &UdpSocket,
|
||||
@@ -486,7 +395,6 @@ impl RendezvousMediator {
|
||||
match msg.union {
|
||||
Some(rendezvous_message::Union::RegisterPeerResponse(rpr)) => {
|
||||
if rpr.request_pk {
|
||||
// Server wants us to register our public key
|
||||
info!("Server requested public key registration");
|
||||
*self.key_confirmed.write() = false;
|
||||
self.send_register_pk(socket).await?;
|
||||
@@ -497,30 +405,24 @@ impl RendezvousMediator {
|
||||
info!("Received RegisterPkResponse: result={:?}", rpr.result);
|
||||
match rpr.result.value() {
|
||||
0 => {
|
||||
// OK
|
||||
info!("✓ Public key registered successfully with server");
|
||||
*self.key_confirmed.write() = true;
|
||||
// Increment serial after successful registration
|
||||
self.increment_serial();
|
||||
*self.status.write() = RendezvousStatus::Registered;
|
||||
}
|
||||
2 => {
|
||||
// UUID_MISMATCH
|
||||
warn!("UUID mismatch, need to re-register");
|
||||
*self.key_confirmed.write() = false;
|
||||
}
|
||||
3 => {
|
||||
// ID_EXISTS
|
||||
error!("Device ID already exists on server");
|
||||
*self.status.write() =
|
||||
RendezvousStatus::Error("Device ID already exists".to_string());
|
||||
}
|
||||
4 => {
|
||||
// TOO_FREQUENT
|
||||
warn!("Registration too frequent");
|
||||
}
|
||||
5 => {
|
||||
// INVALID_ID_FORMAT
|
||||
error!("Invalid device ID format");
|
||||
*self.status.write() =
|
||||
RendezvousStatus::Error("Invalid ID format".to_string());
|
||||
@@ -540,7 +442,6 @@ impl RendezvousMediator {
|
||||
let effective_relay_server =
|
||||
select_relay_server(config.relay_server.as_deref(), &ph.relay_server);
|
||||
|
||||
// Decode the peer's socket address
|
||||
let peer_addr = if !ph.socket_addr.is_empty() {
|
||||
AddrMangle::decode(&ph.socket_addr)
|
||||
} else {
|
||||
@@ -556,9 +457,7 @@ impl RendezvousMediator {
|
||||
ph.nat_type
|
||||
);
|
||||
|
||||
// Send PunchHoleSent to acknowledge
|
||||
// IMPORTANT: socket_addr in PunchHoleSent should be the PEER's address (from PunchHole),
|
||||
// not our own address. This is how RustDesk protocol works.
|
||||
let id = self.device_id();
|
||||
|
||||
info!(
|
||||
@@ -586,16 +485,11 @@ impl RendezvousMediator {
|
||||
info!("Sent PunchHoleSent response successfully");
|
||||
}
|
||||
|
||||
// Try P2P direct connection first, fall back to relay if needed
|
||||
if let Some(relay_server) = effective_relay_server {
|
||||
// Generate a standard UUID v4 for relay pairing
|
||||
// This must match the format used by RustDesk client
|
||||
let uuid = uuid::Uuid::new_v4().to_string();
|
||||
let rendezvous_addr = config.rendezvous_addr();
|
||||
let device_id = config.device_id.clone();
|
||||
|
||||
// Use punch callback if set (tries P2P first, then relay)
|
||||
// Otherwise fall back to relay callback directly
|
||||
if let Some(callback) = self.punch_callback.read().as_ref() {
|
||||
callback(
|
||||
peer_addr,
|
||||
@@ -630,7 +524,6 @@ impl RendezvousMediator {
|
||||
rr.uuid,
|
||||
rr.secure
|
||||
);
|
||||
// Call the relay callback to handle the connection
|
||||
if let Some(callback) = self.relay_callback.read().as_ref() {
|
||||
if let Some(relay_server) = effective_relay_server {
|
||||
let rendezvous_addr = config.rendezvous_addr();
|
||||
@@ -653,7 +546,6 @@ impl RendezvousMediator {
|
||||
select_relay_server(config.relay_server.as_deref(), &fla.relay_server)
|
||||
.unwrap_or_default();
|
||||
|
||||
// Decode the peer address for logging
|
||||
let peer_addr = AddrMangle::decode(&fla.socket_addr);
|
||||
info!(
|
||||
"Received FetchLocalAddr request: peer_addr={:?}, socket_addr_len={}, relay_server={}, effective_relay_server={}",
|
||||
@@ -662,7 +554,6 @@ impl RendezvousMediator {
|
||||
fla.relay_server,
|
||||
effective_relay_server
|
||||
);
|
||||
// Respond with our local address for same-LAN direct connection
|
||||
self.send_local_addr(socket, &fla.socket_addr, &effective_relay_server)
|
||||
.await?;
|
||||
}
|
||||
@@ -671,7 +562,6 @@ impl RendezvousMediator {
|
||||
*self.serial.write() = cu.serial;
|
||||
}
|
||||
Some(other) => {
|
||||
// Log the actual message type for debugging
|
||||
let type_name = match other {
|
||||
rendezvous_message::Union::PunchHoleRequest(_) => "PunchHoleRequest",
|
||||
rendezvous_message::Union::PunchHoleResponse(_) => "PunchHoleResponse",
|
||||
@@ -696,23 +586,18 @@ impl RendezvousMediator {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Stop the rendezvous mediator
|
||||
pub fn stop(&self) {
|
||||
info!("Stopping rendezvous mediator");
|
||||
let _ = self.shutdown_tx.send(());
|
||||
*self.status.write() = RendezvousStatus::Disconnected;
|
||||
}
|
||||
|
||||
/// Get a shutdown receiver
|
||||
pub fn shutdown_rx(&self) -> broadcast::Receiver<()> {
|
||||
self.shutdown_tx.subscribe()
|
||||
}
|
||||
}
|
||||
|
||||
/// AddrMangle - RustDesk's address encoding scheme
|
||||
///
|
||||
/// Certain routers and firewalls scan packets and modify IP addresses.
|
||||
/// This encoding mangles the address to avoid detection.
|
||||
/// RustDesk mangled socket encoding.
|
||||
pub struct AddrMangle;
|
||||
|
||||
fn normalize_relay_server(server: &str) -> Option<String> {
|
||||
@@ -735,9 +620,7 @@ fn select_relay_server(local_relay: Option<&str>, server_relay: &str) -> Option<
|
||||
}
|
||||
|
||||
impl AddrMangle {
|
||||
/// Encode a SocketAddr to bytes using RustDesk's mangle algorithm
|
||||
pub fn encode(addr: SocketAddr) -> Vec<u8> {
|
||||
// Try to convert IPv6-mapped IPv4 to plain IPv4
|
||||
let addr = try_into_v4(addr);
|
||||
|
||||
match addr {
|
||||
@@ -753,7 +636,6 @@ impl AddrMangle {
|
||||
let v = ((ip + tm) << 49) | (tm << 17) | (port + (tm & 0xFFFF));
|
||||
let bytes = v.to_le_bytes();
|
||||
|
||||
// Remove trailing zeros
|
||||
let mut n_padding = 0;
|
||||
for i in bytes.iter().rev() {
|
||||
if *i == 0u8 {
|
||||
@@ -774,13 +656,11 @@ impl AddrMangle {
|
||||
}
|
||||
}
|
||||
|
||||
/// Decode bytes to SocketAddr using RustDesk's mangle algorithm
|
||||
pub fn decode(bytes: &[u8]) -> Option<SocketAddr> {
|
||||
use std::convert::TryInto;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4};
|
||||
|
||||
if bytes.len() > 16 {
|
||||
// IPv6 format: 16 bytes IP + 2 bytes port
|
||||
if bytes.len() != 18 {
|
||||
return None;
|
||||
}
|
||||
@@ -791,7 +671,6 @@ impl AddrMangle {
|
||||
return Some(SocketAddr::new(std::net::IpAddr::V6(ip), port));
|
||||
}
|
||||
|
||||
// IPv4 mangled format
|
||||
let mut padded = [0u8; 16];
|
||||
padded[..bytes.len()].copy_from_slice(bytes);
|
||||
let number = u128::from_le_bytes(padded);
|
||||
@@ -805,7 +684,6 @@ impl AddrMangle {
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to convert IPv6-mapped IPv4 address to plain IPv4
|
||||
fn try_into_v4(addr: SocketAddr) -> SocketAddr {
|
||||
match addr {
|
||||
SocketAddr::V6(v6) if !addr.ip().is_loopback() => {
|
||||
@@ -818,41 +696,30 @@ fn try_into_v4(addr: SocketAddr) -> SocketAddr {
|
||||
addr
|
||||
}
|
||||
|
||||
/// Check if an interface name belongs to Docker or other virtual networks
|
||||
fn is_virtual_interface(name: &str) -> bool {
|
||||
// Docker interfaces
|
||||
name.starts_with("docker")
|
||||
|| name.starts_with("br-")
|
||||
|| name.starts_with("veth")
|
||||
// Kubernetes/container interfaces
|
||||
|| name.starts_with("cni")
|
||||
|| name.starts_with("flannel")
|
||||
|| name.starts_with("calico")
|
||||
|| name.starts_with("weave")
|
||||
// Virtual bridge interfaces
|
||||
|| name.starts_with("virbr")
|
||||
|| name.starts_with("lxcbr")
|
||||
|| name.starts_with("lxdbr")
|
||||
// VPN interfaces (usually not useful for LAN discovery)
|
||||
|| name.starts_with("tun")
|
||||
|| name.starts_with("tap")
|
||||
}
|
||||
|
||||
/// Check if an IP address is in a Docker/container private range
|
||||
fn is_docker_ip(ip: &std::net::IpAddr) -> bool {
|
||||
if let std::net::IpAddr::V4(ipv4) = ip {
|
||||
let octets = ipv4.octets();
|
||||
// Docker default bridge: 172.17.0.0/16
|
||||
if octets[0] == 172 && octets[1] == 17 {
|
||||
return true;
|
||||
}
|
||||
// Docker user-defined networks: 172.18-31.0.0/16
|
||||
if octets[0] == 172 && (18..=31).contains(&octets[1]) {
|
||||
return true;
|
||||
}
|
||||
// Docker overlay networks: 10.0.0.0/8 (common range)
|
||||
// Note: 10.x.x.x is also used for corporate LANs, so we only filter
|
||||
// specific Docker-like patterns (10.0.x.x with small third octet)
|
||||
if octets[0] == 10 && octets[1] == 0 && octets[2] < 10 {
|
||||
return true;
|
||||
}
|
||||
@@ -860,22 +727,18 @@ fn is_docker_ip(ip: &std::net::IpAddr) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Get local IP addresses (non-loopback, non-Docker)
|
||||
fn get_local_addresses() -> Vec<std::net::IpAddr> {
|
||||
let mut addrs = Vec::new();
|
||||
|
||||
// Use pnet or network-interface crate if available, otherwise use simple method
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
if let Ok(interfaces) = std::fs::read_dir("/sys/class/net") {
|
||||
for entry in interfaces.flatten() {
|
||||
let iface_name = entry.file_name().to_string_lossy().to_string();
|
||||
// Skip loopback and virtual interfaces
|
||||
if iface_name == "lo" || is_virtual_interface(&iface_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to get IP via command (simple approach)
|
||||
if let Ok(output) = std::process::Command::new("ip")
|
||||
.args(["-4", "addr", "show", &iface_name])
|
||||
.output()
|
||||
@@ -886,7 +749,6 @@ fn get_local_addresses() -> Vec<std::net::IpAddr> {
|
||||
let ip_part = &line[inet_pos + 5..];
|
||||
if let Some(slash_pos) = ip_part.find('/') {
|
||||
if let Ok(ip) = ip_part[..slash_pos].parse::<std::net::IpAddr>() {
|
||||
// Skip loopback and Docker IPs
|
||||
if !ip.is_loopback() && !is_docker_ip(&ip) {
|
||||
addrs.push(ip);
|
||||
}
|
||||
@@ -899,15 +761,11 @@ fn get_local_addresses() -> Vec<std::net::IpAddr> {
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: try to get default route interface IP
|
||||
if addrs.is_empty() {
|
||||
// Try using DNS lookup to get local IP (connects to external server)
|
||||
if let Ok(socket) = std::net::UdpSocket::bind("0.0.0.0:0") {
|
||||
// Connect to a public DNS server (doesn't actually send data)
|
||||
if socket.connect("8.8.8.8:53").is_ok() {
|
||||
if let Ok(local_addr) = socket.local_addr() {
|
||||
let ip = local_addr.ip();
|
||||
// Skip loopback and Docker IPs
|
||||
if !ip.is_loopback() && !is_docker_ip(&ip) {
|
||||
addrs.push(ip);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user