2022-07-13 11:18:53 +08:00
|
|
|
use crate::server::{check_zombie, new as new_server, ServerPtr};
|
2021-03-29 15:59:14 +08:00
|
|
|
use hbb_common::{
|
|
|
|
allow_err,
|
2022-01-02 22:55:33 +08:00
|
|
|
anyhow::bail,
|
2022-01-15 02:16:00 +08:00
|
|
|
config::{self, Config, REG_INTERVAL, RENDEZVOUS_PORT, RENDEZVOUS_TIMEOUT},
|
2021-03-29 15:59:14 +08:00
|
|
|
futures::future::join_all,
|
|
|
|
log,
|
|
|
|
protobuf::Message as _,
|
|
|
|
rendezvous_proto::*,
|
2022-01-02 22:55:33 +08:00
|
|
|
sleep, socket_client,
|
2021-03-29 15:59:14 +08:00
|
|
|
tokio::{
|
|
|
|
self, select,
|
2022-07-13 11:18:53 +08:00
|
|
|
sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
2021-03-29 15:59:14 +08:00
|
|
|
time::{interval, Duration},
|
|
|
|
},
|
2022-01-14 23:02:08 +08:00
|
|
|
udp::FramedSocket,
|
2022-01-05 13:21:14 +08:00
|
|
|
AddrMangle, IntoTargetAddr, ResultType, TargetAddr,
|
2021-03-29 15:59:14 +08:00
|
|
|
};
|
|
|
|
use std::{
|
2022-07-13 11:18:53 +08:00
|
|
|
collections::{HashMap, HashSet},
|
2022-07-12 22:34:05 +08:00
|
|
|
net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs, UdpSocket},
|
2022-01-04 17:44:06 +08:00
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, Ordering},
|
|
|
|
Arc, Mutex,
|
|
|
|
},
|
2022-04-22 02:05:11 +08:00
|
|
|
time::Instant,
|
2021-03-29 15:59:14 +08:00
|
|
|
};
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
|
|
type Message = RendezvousMessage;
|
|
|
|
|
|
|
|
lazy_static::lazy_static! {
|
2022-01-05 18:34:30 +08:00
|
|
|
static ref SOLVING_PK_MISMATCH: Arc<Mutex<String>> = Default::default();
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2022-01-04 17:45:52 +08:00
|
|
|
static SHOULD_EXIT: AtomicBool = AtomicBool::new(false);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
2022-01-05 14:38:38 +08:00
|
|
|
#[derive(Clone)]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub struct RendezvousMediator {
|
2022-01-05 13:21:14 +08:00
|
|
|
addr: TargetAddr<'static>,
|
2021-03-29 15:59:14 +08:00
|
|
|
host: String,
|
|
|
|
host_prefix: String,
|
2021-11-14 18:52:05 +03:30
|
|
|
last_id_pk_registry: String,
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RendezvousMediator {
|
2022-01-05 18:34:30 +08:00
|
|
|
pub fn restart() {
|
|
|
|
SHOULD_EXIT.store(true, Ordering::SeqCst);
|
2022-02-08 18:10:32 +08:00
|
|
|
log::info!("server restart");
|
2022-01-05 18:34:30 +08:00
|
|
|
}
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
pub async fn start_all() {
|
2021-05-23 00:14:00 +08:00
|
|
|
let mut nat_tested = false;
|
2021-03-29 15:59:14 +08:00
|
|
|
check_zombie();
|
|
|
|
let server = new_server();
|
2021-05-23 00:14:00 +08:00
|
|
|
if Config::get_nat_type() == NatType::UNKNOWN_NAT as i32 {
|
2022-07-14 15:21:26 +08:00
|
|
|
crate::test_nat_type();
|
2021-05-23 00:14:00 +08:00
|
|
|
nat_tested = true;
|
|
|
|
}
|
2022-07-14 15:21:26 +08:00
|
|
|
if !Config::get_option("stop-service").is_empty() {
|
|
|
|
crate::test_rendezvous_server();
|
|
|
|
}
|
2022-01-05 23:50:13 +08:00
|
|
|
let server_cloned = server.clone();
|
|
|
|
tokio::spawn(async move {
|
2022-02-19 15:30:09 +08:00
|
|
|
direct_server(server_cloned).await;
|
2022-01-05 23:50:13 +08:00
|
|
|
});
|
2022-05-12 17:35:25 +08:00
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2022-07-14 03:35:00 +08:00
|
|
|
if crate::platform::is_installed() {
|
|
|
|
std::thread::spawn(move || {
|
|
|
|
allow_err!(lan_discovery());
|
|
|
|
});
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
loop {
|
|
|
|
Config::reset_online();
|
|
|
|
if Config::get_option("stop-service").is_empty() {
|
2021-05-23 00:14:00 +08:00
|
|
|
if !nat_tested {
|
2022-07-14 15:21:26 +08:00
|
|
|
crate::test_nat_type();
|
2021-05-23 00:14:00 +08:00
|
|
|
nat_tested = true;
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
let mut futs = Vec::new();
|
|
|
|
let servers = Config::get_rendezvous_servers();
|
2022-01-04 17:45:52 +08:00
|
|
|
SHOULD_EXIT.store(false, Ordering::SeqCst);
|
2021-03-29 15:59:14 +08:00
|
|
|
for host in servers.clone() {
|
|
|
|
let server = server.clone();
|
|
|
|
futs.push(tokio::spawn(async move {
|
2022-02-07 18:39:49 +08:00
|
|
|
allow_err!(Self::start(server, host).await);
|
2022-01-04 17:45:52 +08:00
|
|
|
// SHOULD_EXIT here is to ensure once one exits, the others also exit.
|
|
|
|
SHOULD_EXIT.store(true, Ordering::SeqCst);
|
2021-03-29 15:59:14 +08:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
join_all(futs).await;
|
|
|
|
}
|
|
|
|
sleep(1.).await;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-07 18:39:49 +08:00
|
|
|
pub async fn start(server: ServerPtr, host: String) -> ResultType<()> {
|
2021-03-29 15:59:14 +08:00
|
|
|
log::info!("start rendezvous mediator of {}", host);
|
|
|
|
let host_prefix: String = host
|
|
|
|
.split(".")
|
|
|
|
.next()
|
|
|
|
.map(|x| {
|
|
|
|
if x.parse::<i32>().is_ok() {
|
|
|
|
host.clone()
|
|
|
|
} else {
|
|
|
|
x.to_string()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.unwrap_or(host.to_owned());
|
|
|
|
let mut rz = Self {
|
2022-01-05 13:21:14 +08:00
|
|
|
addr: Config::get_any_listen_addr().into_target_addr()?,
|
2021-03-29 15:59:14 +08:00
|
|
|
host: host.clone(),
|
|
|
|
host_prefix,
|
2021-11-14 18:52:05 +03:30
|
|
|
last_id_pk_registry: "".to_owned(),
|
2021-03-29 15:59:14 +08:00
|
|
|
};
|
2022-01-05 13:21:14 +08:00
|
|
|
|
|
|
|
rz.addr = socket_client::get_target_addr(&crate::check_port(&host, RENDEZVOUS_PORT))?;
|
|
|
|
let any_addr = Config::get_any_listen_addr();
|
|
|
|
let mut socket = socket_client::new_udp(any_addr, RENDEZVOUS_TIMEOUT).await?;
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
const TIMER_OUT: Duration = Duration::from_secs(1);
|
|
|
|
let mut timer = interval(TIMER_OUT);
|
2022-04-22 02:05:11 +08:00
|
|
|
let mut last_timer: Option<Instant> = None;
|
2021-03-29 15:59:14 +08:00
|
|
|
const REG_TIMEOUT: i64 = 3_000;
|
|
|
|
const MAX_FAILS1: i64 = 3;
|
|
|
|
const MAX_FAILS2: i64 = 6;
|
|
|
|
const DNS_INTERVAL: i64 = 60_000;
|
|
|
|
let mut fails = 0;
|
2022-04-22 02:05:11 +08:00
|
|
|
let mut last_register_resp: Option<Instant> = None;
|
|
|
|
let mut last_register_sent: Option<Instant> = None;
|
|
|
|
let mut last_dns_check = Instant::now();
|
2021-03-29 15:59:14 +08:00
|
|
|
let mut old_latency = 0;
|
|
|
|
let mut ema_latency = 0;
|
|
|
|
loop {
|
2021-06-05 19:53:34 +08:00
|
|
|
let mut update_latency = || {
|
2022-04-22 02:05:11 +08:00
|
|
|
last_register_resp = Some(Instant::now());
|
2021-08-12 10:55:21 +08:00
|
|
|
fails = 0;
|
2022-04-22 02:05:11 +08:00
|
|
|
let mut latency = last_register_sent
|
|
|
|
.map(|x| x.elapsed().as_micros() as i64)
|
2021-06-05 19:53:34 +08:00
|
|
|
.unwrap_or(0);
|
2021-08-12 10:55:21 +08:00
|
|
|
if latency < 0 || latency > 1_000_000 {
|
|
|
|
return;
|
|
|
|
}
|
2021-06-05 19:53:34 +08:00
|
|
|
if ema_latency == 0 {
|
|
|
|
ema_latency = latency;
|
|
|
|
} else {
|
|
|
|
ema_latency = latency / 30 + (ema_latency * 29 / 30);
|
|
|
|
latency = ema_latency;
|
|
|
|
}
|
|
|
|
let mut n = latency / 5;
|
|
|
|
if n < 3000 {
|
|
|
|
n = 3000;
|
|
|
|
}
|
|
|
|
if (latency - old_latency).abs() > n || old_latency <= 0 {
|
|
|
|
Config::update_latency(&host, latency);
|
|
|
|
log::debug!("Latency of {}: {}ms", host, latency as f64 / 1000.);
|
|
|
|
old_latency = latency;
|
|
|
|
}
|
|
|
|
};
|
2021-03-29 15:59:14 +08:00
|
|
|
select! {
|
2022-01-02 22:55:33 +08:00
|
|
|
n = socket.next() => {
|
|
|
|
match n {
|
|
|
|
Some(Ok((bytes, _))) => {
|
|
|
|
if let Ok(msg_in) = Message::parse_from_bytes(&bytes) {
|
|
|
|
match msg_in.union {
|
2022-07-14 17:20:01 +08:00
|
|
|
Some(rendezvous_message::Union::RegisterPeerResponse(rpr)) => {
|
2022-01-02 22:55:33 +08:00
|
|
|
update_latency();
|
|
|
|
if rpr.request_pk {
|
|
|
|
log::info!("request_pk received from {}", host);
|
|
|
|
allow_err!(rz.register_pk(&mut socket).await);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
Some(rendezvous_message::Union::RegisterPkResponse(rpr)) => {
|
2022-01-02 22:55:33 +08:00
|
|
|
update_latency();
|
|
|
|
match rpr.result.enum_value_or_default() {
|
|
|
|
register_pk_response::Result::OK => {
|
|
|
|
Config::set_key_confirmed(true);
|
|
|
|
Config::set_host_key_confirmed(&rz.host_prefix, true);
|
|
|
|
*SOLVING_PK_MISMATCH.lock().unwrap() = "".to_owned();
|
|
|
|
}
|
|
|
|
register_pk_response::Result::UUID_MISMATCH => {
|
|
|
|
allow_err!(rz.handle_uuid_mismatch(&mut socket).await);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
Some(rendezvous_message::Union::PunchHole(ph)) => {
|
2022-01-02 22:55:33 +08:00
|
|
|
let rz = rz.clone();
|
|
|
|
let server = server.clone();
|
|
|
|
tokio::spawn(async move {
|
|
|
|
allow_err!(rz.handle_punch_hole(ph, server).await);
|
|
|
|
});
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
Some(rendezvous_message::Union::RequestRelay(rr)) => {
|
2022-01-02 22:55:33 +08:00
|
|
|
let rz = rz.clone();
|
|
|
|
let server = server.clone();
|
|
|
|
tokio::spawn(async move {
|
|
|
|
allow_err!(rz.handle_request_relay(rr, server).await);
|
|
|
|
});
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
Some(rendezvous_message::Union::FetchLocalAddr(fla)) => {
|
2022-01-02 22:55:33 +08:00
|
|
|
let rz = rz.clone();
|
|
|
|
let server = server.clone();
|
|
|
|
tokio::spawn(async move {
|
|
|
|
allow_err!(rz.handle_intranet(fla, server).await);
|
|
|
|
});
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
Some(rendezvous_message::Union::ConfigureUpdate(cu)) => {
|
2022-02-07 18:39:49 +08:00
|
|
|
let v0 = Config::get_rendezvous_servers();
|
2022-01-02 22:55:33 +08:00
|
|
|
Config::set_option("rendezvous-servers".to_owned(), cu.rendezvous_servers.join(","));
|
|
|
|
Config::set_serial(cu.serial);
|
2022-02-07 18:39:49 +08:00
|
|
|
if v0 != Config::get_rendezvous_servers() {
|
|
|
|
Self::restart();
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2021-07-27 23:53:12 +08:00
|
|
|
_ => {}
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2022-01-02 22:55:33 +08:00
|
|
|
} else {
|
|
|
|
log::debug!("Non-protobuf message bytes received: {:?}", bytes);
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2022-01-02 22:55:33 +08:00
|
|
|
},
|
|
|
|
Some(Err(e)) => bail!("Failed to receive next {}", e), // maybe socks5 tcp disconnected
|
|
|
|
None => {
|
2022-06-23 10:29:22 +08:00
|
|
|
bail!("Socket receive none. Maybe socks5 server is down.");
|
2022-01-02 22:55:33 +08:00
|
|
|
},
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
_ = timer.tick() => {
|
2022-01-04 17:45:52 +08:00
|
|
|
if SHOULD_EXIT.load(Ordering::SeqCst) {
|
2022-01-04 17:44:06 +08:00
|
|
|
break;
|
|
|
|
}
|
2022-04-22 02:05:11 +08:00
|
|
|
let now = Some(Instant::now());
|
|
|
|
if last_timer.map(|x| x.elapsed() < TIMER_OUT).unwrap_or(false) {
|
2021-03-29 15:59:14 +08:00
|
|
|
// a workaround of tokio timer bug
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
last_timer = now;
|
2022-04-22 02:05:11 +08:00
|
|
|
let elapsed_resp = last_register_resp.map(|x| x.elapsed().as_millis() as i64).unwrap_or(REG_INTERVAL);
|
2022-06-24 02:47:46 +08:00
|
|
|
let timeout = (elapsed_resp - last_register_sent.map(|x| x.elapsed().as_millis() as i64).unwrap_or(REG_INTERVAL)) > REG_TIMEOUT;
|
2021-03-29 15:59:14 +08:00
|
|
|
if timeout || elapsed_resp >= REG_INTERVAL {
|
|
|
|
allow_err!(rz.register_peer(&mut socket).await);
|
|
|
|
last_register_sent = now;
|
|
|
|
if timeout {
|
|
|
|
fails += 1;
|
|
|
|
if fails > MAX_FAILS2 {
|
|
|
|
Config::update_latency(&host, -1);
|
|
|
|
old_latency = 0;
|
2022-04-22 02:05:11 +08:00
|
|
|
if last_dns_check.elapsed().as_millis() as i64 > DNS_INTERVAL {
|
2022-01-05 13:21:14 +08:00
|
|
|
rz.addr = socket_client::get_target_addr(&crate::check_port(&host, RENDEZVOUS_PORT))?;
|
|
|
|
// in some case of network reconnect (dial IP network),
|
|
|
|
// old UDP socket not work any more after network recover
|
|
|
|
if let Some(s) = socket_client::rebind_udp(any_addr).await? {
|
|
|
|
socket = s;
|
2022-01-05 23:50:13 +08:00
|
|
|
}
|
2022-04-22 02:05:11 +08:00
|
|
|
last_dns_check = Instant::now();
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
} else if fails > MAX_FAILS1 {
|
|
|
|
Config::update_latency(&host, 0);
|
|
|
|
old_latency = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_request_relay(&self, rr: RequestRelay, server: ServerPtr) -> ResultType<()> {
|
|
|
|
self.create_relay(
|
|
|
|
rr.socket_addr,
|
|
|
|
rr.relay_server,
|
|
|
|
rr.uuid,
|
|
|
|
server,
|
|
|
|
rr.secure,
|
|
|
|
false,
|
|
|
|
)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn create_relay(
|
|
|
|
&self,
|
|
|
|
socket_addr: Vec<u8>,
|
|
|
|
relay_server: String,
|
|
|
|
uuid: String,
|
|
|
|
server: ServerPtr,
|
|
|
|
secure: bool,
|
|
|
|
initiate: bool,
|
|
|
|
) -> ResultType<()> {
|
|
|
|
let peer_addr = AddrMangle::decode(&socket_addr);
|
|
|
|
log::info!(
|
|
|
|
"create_relay requested from from {:?}, relay_server: {}, uuid: {}, secure: {}",
|
|
|
|
peer_addr,
|
|
|
|
relay_server,
|
|
|
|
uuid,
|
|
|
|
secure,
|
|
|
|
);
|
2022-01-02 22:55:33 +08:00
|
|
|
|
|
|
|
let mut socket = socket_client::connect_tcp(
|
2022-01-05 13:21:14 +08:00
|
|
|
self.addr.to_owned(),
|
2022-01-02 22:55:33 +08:00
|
|
|
Config::get_any_listen_addr(),
|
|
|
|
RENDEZVOUS_TIMEOUT,
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
let mut msg_out = Message::new();
|
|
|
|
let mut rr = RelayResponse {
|
|
|
|
socket_addr,
|
2021-11-07 10:18:10 +08:00
|
|
|
version: crate::VERSION.to_owned(),
|
2021-03-29 15:59:14 +08:00
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
if initiate {
|
|
|
|
rr.uuid = uuid.clone();
|
|
|
|
rr.relay_server = relay_server.clone();
|
|
|
|
rr.set_id(Config::get_id());
|
|
|
|
}
|
|
|
|
msg_out.set_relay_response(rr);
|
|
|
|
socket.send(&msg_out).await?;
|
|
|
|
crate::create_relay_connection(server, relay_server, uuid, peer_addr, secure).await;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_intranet(&self, fla: FetchLocalAddr, server: ServerPtr) -> ResultType<()> {
|
|
|
|
let peer_addr = AddrMangle::decode(&fla.socket_addr);
|
|
|
|
log::debug!("Handle intranet from {:?}", peer_addr);
|
2022-01-02 22:55:33 +08:00
|
|
|
let mut socket = socket_client::connect_tcp(
|
2022-01-05 13:21:14 +08:00
|
|
|
self.addr.to_owned(),
|
2022-01-02 22:55:33 +08:00
|
|
|
Config::get_any_listen_addr(),
|
|
|
|
RENDEZVOUS_TIMEOUT,
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
let local_addr = socket.local_addr();
|
|
|
|
let local_addr: SocketAddr =
|
|
|
|
format!("{}:{}", local_addr.ip(), local_addr.port()).parse()?;
|
2021-03-29 15:59:14 +08:00
|
|
|
let mut msg_out = Message::new();
|
2022-03-25 18:39:06 +08:00
|
|
|
let relay_server = self.get_relay_server(fla.relay_server);
|
2021-03-29 15:59:14 +08:00
|
|
|
msg_out.set_local_addr(LocalAddr {
|
2021-05-11 19:02:18 +08:00
|
|
|
id: Config::get_id(),
|
2021-03-29 15:59:14 +08:00
|
|
|
socket_addr: AddrMangle::encode(peer_addr),
|
|
|
|
local_addr: AddrMangle::encode(local_addr),
|
|
|
|
relay_server,
|
2021-11-07 10:18:10 +08:00
|
|
|
version: crate::VERSION.to_owned(),
|
2021-03-29 15:59:14 +08:00
|
|
|
..Default::default()
|
|
|
|
});
|
|
|
|
let bytes = msg_out.write_to_bytes()?;
|
|
|
|
socket.send_raw(bytes).await?;
|
2021-05-11 20:34:04 +08:00
|
|
|
crate::accept_connection(server.clone(), socket, peer_addr, true).await;
|
2021-03-29 15:59:14 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_punch_hole(&self, ph: PunchHole, server: ServerPtr) -> ResultType<()> {
|
2022-03-25 18:39:06 +08:00
|
|
|
let relay_server = self.get_relay_server(ph.relay_server);
|
2021-03-29 15:59:14 +08:00
|
|
|
if ph.nat_type.enum_value_or_default() == NatType::SYMMETRIC
|
|
|
|
|| Config::get_nat_type() == NatType::SYMMETRIC as i32
|
|
|
|
{
|
|
|
|
let uuid = Uuid::new_v4().to_string();
|
|
|
|
return self
|
|
|
|
.create_relay(ph.socket_addr, relay_server, uuid, server, true, true)
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
let peer_addr = AddrMangle::decode(&ph.socket_addr);
|
|
|
|
log::debug!("Punch hole to {:?}", peer_addr);
|
|
|
|
let mut socket = {
|
2022-01-02 22:55:33 +08:00
|
|
|
let socket = socket_client::connect_tcp(
|
2022-01-05 13:21:14 +08:00
|
|
|
self.addr.to_owned(),
|
2022-01-02 22:55:33 +08:00
|
|
|
Config::get_any_listen_addr(),
|
|
|
|
RENDEZVOUS_TIMEOUT,
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
let local_addr = socket.local_addr();
|
|
|
|
allow_err!(socket_client::connect_tcp(peer_addr, local_addr, 300).await);
|
2021-03-29 15:59:14 +08:00
|
|
|
socket
|
|
|
|
};
|
|
|
|
let mut msg_out = Message::new();
|
2022-07-14 17:20:01 +08:00
|
|
|
use hbb_common::protobuf::Enum;
|
2021-03-29 15:59:14 +08:00
|
|
|
let nat_type = NatType::from_i32(Config::get_nat_type()).unwrap_or(NatType::UNKNOWN_NAT);
|
|
|
|
msg_out.set_punch_hole_sent(PunchHoleSent {
|
|
|
|
socket_addr: ph.socket_addr,
|
|
|
|
id: Config::get_id(),
|
|
|
|
relay_server,
|
|
|
|
nat_type: nat_type.into(),
|
2021-11-07 10:18:10 +08:00
|
|
|
version: crate::VERSION.to_owned(),
|
2021-03-29 15:59:14 +08:00
|
|
|
..Default::default()
|
|
|
|
});
|
|
|
|
let bytes = msg_out.write_to_bytes()?;
|
|
|
|
socket.send_raw(bytes).await?;
|
|
|
|
crate::accept_connection(server.clone(), socket, peer_addr, true).await;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-01-04 00:44:50 +08:00
|
|
|
async fn register_pk(&mut self, socket: &mut FramedSocket) -> ResultType<()> {
|
2021-03-29 15:59:14 +08:00
|
|
|
let mut msg_out = Message::new();
|
|
|
|
let pk = Config::get_key_pair().1;
|
2022-05-12 17:35:25 +08:00
|
|
|
let uuid = crate::get_uuid();
|
2021-03-29 15:59:14 +08:00
|
|
|
let id = Config::get_id();
|
2021-11-14 18:52:05 +03:30
|
|
|
self.last_id_pk_registry = id.clone();
|
2021-03-29 15:59:14 +08:00
|
|
|
msg_out.set_register_pk(RegisterPk {
|
|
|
|
id,
|
|
|
|
uuid,
|
|
|
|
pk,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2022-01-05 13:21:14 +08:00
|
|
|
socket.send(&msg_out, self.addr.to_owned()).await?;
|
2021-03-29 15:59:14 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-01-04 00:44:50 +08:00
|
|
|
async fn handle_uuid_mismatch(&mut self, socket: &mut FramedSocket) -> ResultType<()> {
|
2021-11-14 18:52:05 +03:30
|
|
|
if self.last_id_pk_registry != Config::get_id() {
|
2021-03-29 15:59:14 +08:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
{
|
|
|
|
let mut solving = SOLVING_PK_MISMATCH.lock().unwrap();
|
|
|
|
if solving.is_empty() || *solving == self.host {
|
|
|
|
log::info!("UUID_MISMATCH received from {}", self.host);
|
|
|
|
Config::set_key_confirmed(false);
|
|
|
|
Config::update_id();
|
|
|
|
*solving = self.host.clone();
|
|
|
|
} else {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.register_pk(socket).await
|
|
|
|
}
|
|
|
|
|
2022-01-04 00:44:50 +08:00
|
|
|
async fn register_peer(&mut self, socket: &mut FramedSocket) -> ResultType<()> {
|
2021-03-29 15:59:14 +08:00
|
|
|
if !SOLVING_PK_MISMATCH.lock().unwrap().is_empty() {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
if !Config::get_key_confirmed() || !Config::get_host_key_confirmed(&self.host_prefix) {
|
|
|
|
log::info!(
|
|
|
|
"register_pk of {} due to key not confirmed",
|
|
|
|
self.host_prefix
|
|
|
|
);
|
|
|
|
return self.register_pk(socket).await;
|
|
|
|
}
|
|
|
|
let id = Config::get_id();
|
|
|
|
log::trace!(
|
|
|
|
"Register my id {:?} to rendezvous server {:?}",
|
|
|
|
id,
|
|
|
|
self.addr,
|
|
|
|
);
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
let serial = Config::get_serial();
|
|
|
|
msg_out.set_register_peer(RegisterPeer {
|
|
|
|
id,
|
|
|
|
serial,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2022-01-05 13:21:14 +08:00
|
|
|
socket.send(&msg_out, self.addr.to_owned()).await?;
|
2021-03-29 15:59:14 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
2022-03-25 18:39:06 +08:00
|
|
|
|
|
|
|
fn get_relay_server(&self, provided_by_rendzvous_server: String) -> String {
|
|
|
|
let mut relay_server = Config::get_option("relay-server");
|
|
|
|
if relay_server.is_empty() {
|
|
|
|
relay_server = provided_by_rendzvous_server;
|
|
|
|
}
|
|
|
|
if relay_server.is_empty() {
|
|
|
|
if self.host.contains(":") {
|
|
|
|
let tmp: Vec<&str> = self.host.split(":").collect();
|
|
|
|
if tmp.len() == 2 {
|
|
|
|
let port: u16 = tmp[1].parse().unwrap_or(0);
|
|
|
|
relay_server = format!("{}:{}", tmp[0], port + 1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
relay_server = self.host.clone();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
relay_server
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2022-01-05 23:50:13 +08:00
|
|
|
|
2022-02-19 15:30:09 +08:00
|
|
|
fn get_direct_port() -> i32 {
|
|
|
|
let mut port = Config::get_option("direct-access-port")
|
|
|
|
.parse::<i32>()
|
|
|
|
.unwrap_or(0);
|
|
|
|
if port <= 0 {
|
|
|
|
port = RENDEZVOUS_PORT + 2;
|
|
|
|
}
|
|
|
|
port
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn direct_server(server: ServerPtr) {
|
2022-01-05 23:50:13 +08:00
|
|
|
let mut listener = None;
|
2022-02-19 15:30:09 +08:00
|
|
|
let mut port = 0;
|
2022-01-05 23:50:13 +08:00
|
|
|
loop {
|
2022-02-19 15:30:09 +08:00
|
|
|
let disabled = Config::get_option("direct-server").is_empty();
|
|
|
|
if !disabled && listener.is_none() {
|
|
|
|
port = get_direct_port();
|
|
|
|
let addr = format!("0.0.0.0:{}", port);
|
|
|
|
match hbb_common::tcp::new_listener(&addr, false).await {
|
|
|
|
Ok(l) => {
|
|
|
|
listener = Some(l);
|
|
|
|
log::info!(
|
|
|
|
"Direct server listening on: {:?}",
|
|
|
|
listener.as_ref().unwrap().local_addr()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
// to-do: pass to ui
|
|
|
|
log::error!(
|
|
|
|
"Failed to start direct server on : {}, error: {}",
|
|
|
|
addr,
|
|
|
|
err
|
|
|
|
);
|
|
|
|
loop {
|
|
|
|
if port != get_direct_port() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
sleep(1.).await;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-01-05 23:50:13 +08:00
|
|
|
}
|
|
|
|
if let Some(l) = listener.as_mut() {
|
2022-02-19 15:30:09 +08:00
|
|
|
if disabled || port != get_direct_port() {
|
|
|
|
log::info!("Exit direct access listen");
|
|
|
|
listener = None;
|
|
|
|
continue;
|
|
|
|
}
|
2022-01-05 23:50:13 +08:00
|
|
|
if let Ok(Ok((stream, addr))) = hbb_common::timeout(1000, l.accept()).await {
|
2022-01-24 01:50:22 +08:00
|
|
|
stream.set_nodelay(true).ok();
|
2022-01-05 23:50:13 +08:00
|
|
|
log::info!("direct access from {}", addr);
|
2022-02-19 15:30:09 +08:00
|
|
|
let local_addr = stream.local_addr().unwrap_or(Config::get_any_listen_addr());
|
2022-01-05 23:50:13 +08:00
|
|
|
let server = server.clone();
|
|
|
|
tokio::spawn(async move {
|
|
|
|
allow_err!(
|
|
|
|
crate::server::create_tcp_connection(
|
|
|
|
server,
|
|
|
|
hbb_common::Stream::from(stream, local_addr),
|
|
|
|
addr,
|
|
|
|
false,
|
|
|
|
)
|
|
|
|
.await
|
|
|
|
);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
sleep(0.1).await;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sleep(1.).await;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-01-11 16:24:35 +08:00
|
|
|
|
2022-01-14 23:02:08 +08:00
|
|
|
#[inline]
|
|
|
|
pub fn get_broadcast_port() -> u16 {
|
|
|
|
(RENDEZVOUS_PORT + 3) as _
|
2022-01-12 03:10:15 +08:00
|
|
|
}
|
|
|
|
|
2022-07-12 22:34:05 +08:00
|
|
|
pub fn get_mac(ip: &IpAddr) -> String {
|
2022-05-12 17:35:25 +08:00
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2022-07-12 22:34:05 +08:00
|
|
|
if let Ok(mac) = get_mac_by_ip(ip) {
|
2022-01-12 03:10:15 +08:00
|
|
|
mac.to_string()
|
|
|
|
} else {
|
|
|
|
"".to_owned()
|
|
|
|
}
|
2022-05-12 17:35:25 +08:00
|
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
|
|
"".to_owned()
|
2022-01-11 16:24:35 +08:00
|
|
|
}
|
|
|
|
|
2022-07-12 22:34:05 +08:00
|
|
|
fn get_all_ipv4s() -> ResultType<Vec<Ipv4Addr>> {
|
|
|
|
let mut ipv4s = Vec::new();
|
|
|
|
for interface in default_net::get_interfaces() {
|
|
|
|
for ipv4 in &interface.ipv4 {
|
|
|
|
ipv4s.push(ipv4.addr.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(ipv4s)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_mac_by_ip(ip: &IpAddr) -> ResultType<String> {
|
|
|
|
for interface in default_net::get_interfaces() {
|
|
|
|
match ip {
|
|
|
|
IpAddr::V4(local_ipv4) => {
|
|
|
|
if interface.ipv4.iter().any(|x| x.addr == *local_ipv4) {
|
|
|
|
if let Some(mac_addr) = interface.mac_addr {
|
|
|
|
return Ok(mac_addr.address());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
IpAddr::V6(local_ipv6) => {
|
|
|
|
if interface.ipv6.iter().any(|x| x.addr == *local_ipv6) {
|
|
|
|
if let Some(mac_addr) = interface.mac_addr {
|
|
|
|
return Ok(mac_addr.address());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bail!("No interface found for ip: {:?}", ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mainly from https://github.com/shellrow/default-net/blob/cf7ca24e7e6e8e566ed32346c9cfddab3f47e2d6/src/interface/shared.rs#L4
|
|
|
|
pub fn get_ipaddr_by_peer<A: ToSocketAddrs>(peer: A) -> Option<IpAddr> {
|
|
|
|
let socket = match UdpSocket::bind("0.0.0.0:0") {
|
|
|
|
Ok(s) => s,
|
|
|
|
Err(_) => return None,
|
|
|
|
};
|
|
|
|
|
|
|
|
match socket.connect(peer) {
|
|
|
|
Ok(()) => (),
|
|
|
|
Err(_) => return None,
|
|
|
|
};
|
|
|
|
|
|
|
|
match socket.local_addr() {
|
|
|
|
Ok(addr) => return Some(addr.ip()),
|
|
|
|
Err(_) => return None,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-01-14 23:02:08 +08:00
|
|
|
fn lan_discovery() -> ResultType<()> {
|
2022-01-14 23:21:30 +08:00
|
|
|
let addr = SocketAddr::from(([0, 0, 0, 0], get_broadcast_port()));
|
2022-01-14 23:02:08 +08:00
|
|
|
let socket = std::net::UdpSocket::bind(addr)?;
|
|
|
|
socket.set_read_timeout(Some(std::time::Duration::from_millis(1000)))?;
|
|
|
|
log::info!("lan discovery listener started");
|
2022-01-11 16:24:35 +08:00
|
|
|
loop {
|
2022-01-14 23:02:08 +08:00
|
|
|
let mut buf = [0; 2048];
|
|
|
|
if let Ok((len, addr)) = socket.recv_from(&mut buf) {
|
|
|
|
if let Ok(msg_in) = Message::parse_from_bytes(&buf[0..len]) {
|
|
|
|
match msg_in.union {
|
2022-07-14 17:20:01 +08:00
|
|
|
Some(rendezvous_message::Union::PeerDiscovery(p)) => {
|
2022-01-14 23:02:08 +08:00
|
|
|
if p.cmd == "ping" {
|
2022-07-12 22:34:05 +08:00
|
|
|
if let Some(self_addr) = get_ipaddr_by_peer(&addr) {
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
let peer = PeerDiscovery {
|
|
|
|
cmd: "pong".to_owned(),
|
|
|
|
mac: get_mac(&self_addr),
|
|
|
|
id: Config::get_id(),
|
|
|
|
hostname: whoami::hostname(),
|
|
|
|
username: crate::platform::get_active_username(),
|
|
|
|
platform: whoami::platform().to_string(),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
msg_out.set_peer_discovery(peer);
|
|
|
|
socket.send_to(&msg_out.write_to_bytes()?, addr).ok();
|
|
|
|
}
|
2022-01-12 03:10:15 +08:00
|
|
|
}
|
|
|
|
}
|
2022-01-14 23:02:08 +08:00
|
|
|
_ => {}
|
2022-01-12 03:10:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-12 22:34:05 +08:00
|
|
|
fn create_broadcast_sockets() -> ResultType<Vec<UdpSocket>> {
|
|
|
|
let mut sockets = Vec::new();
|
|
|
|
for v4_addr in get_all_ipv4s()? {
|
|
|
|
if v4_addr.is_private() {
|
|
|
|
let s = UdpSocket::bind(SocketAddr::from((v4_addr, 0)))?;
|
|
|
|
s.set_broadcast(true)?;
|
|
|
|
log::debug!("Bind socket to {}", &v4_addr);
|
|
|
|
sockets.push(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(sockets)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn send_query() -> ResultType<Vec<UdpSocket>> {
|
|
|
|
let sockets = create_broadcast_sockets()?;
|
|
|
|
if sockets.is_empty() {
|
|
|
|
bail!("Found no ipv4 addresses");
|
|
|
|
}
|
|
|
|
|
2022-01-12 03:10:15 +08:00
|
|
|
let mut msg_out = Message::new();
|
|
|
|
let peer = PeerDiscovery {
|
|
|
|
cmd: "ping".to_owned(),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
msg_out.set_peer_discovery(peer);
|
2022-01-14 23:21:30 +08:00
|
|
|
let maddr = SocketAddr::from(([255, 255, 255, 255], get_broadcast_port()));
|
2022-07-12 22:34:05 +08:00
|
|
|
for socket in &sockets {
|
|
|
|
socket.send_to(&msg_out.write_to_bytes()?, maddr)?;
|
|
|
|
}
|
2022-01-14 18:16:00 +08:00
|
|
|
log::info!("discover ping sent");
|
2022-07-12 22:34:05 +08:00
|
|
|
Ok(sockets)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn wait_response(
|
|
|
|
socket: UdpSocket,
|
|
|
|
timeout: Option<std::time::Duration>,
|
2022-07-13 18:06:19 +08:00
|
|
|
tx: UnboundedSender<config::DiscoveryPeer>,
|
2022-07-13 11:18:53 +08:00
|
|
|
) -> ResultType<()> {
|
2022-01-12 03:10:15 +08:00
|
|
|
let mut last_recv_time = Instant::now();
|
2022-07-12 22:34:05 +08:00
|
|
|
|
|
|
|
socket.set_read_timeout(timeout)?;
|
2022-01-12 03:10:15 +08:00
|
|
|
loop {
|
2022-01-14 23:02:08 +08:00
|
|
|
let mut buf = [0; 2048];
|
2022-07-12 22:34:05 +08:00
|
|
|
if let Ok((len, addr)) = socket.recv_from(&mut buf) {
|
2022-01-14 23:02:08 +08:00
|
|
|
if let Ok(msg_in) = Message::parse_from_bytes(&buf[0..len]) {
|
|
|
|
match msg_in.union {
|
2022-07-14 17:20:01 +08:00
|
|
|
Some(rendezvous_message::Union::PeerDiscovery(p)) => {
|
2022-01-14 23:02:08 +08:00
|
|
|
last_recv_time = Instant::now();
|
|
|
|
if p.cmd == "pong" {
|
2022-07-12 22:34:05 +08:00
|
|
|
let mac = if let Some(self_addr) = get_ipaddr_by_peer(&addr) {
|
|
|
|
get_mac(&self_addr)
|
|
|
|
} else {
|
|
|
|
"".to_owned()
|
|
|
|
};
|
|
|
|
|
2022-07-13 11:18:53 +08:00
|
|
|
if mac != p.mac {
|
2022-07-13 18:06:19 +08:00
|
|
|
allow_err!(tx.send(config::DiscoveryPeer {
|
2022-07-12 22:34:05 +08:00
|
|
|
id: p.id.clone(),
|
2022-07-14 10:34:56 +08:00
|
|
|
ip_mac: HashMap::from([
|
|
|
|
(addr.ip().to_string(), p.mac.clone(),)
|
|
|
|
]),
|
2022-07-12 22:34:05 +08:00
|
|
|
username: p.username.clone(),
|
|
|
|
hostname: p.hostname.clone(),
|
|
|
|
platform: p.platform.clone(),
|
2022-07-13 11:18:53 +08:00
|
|
|
online: true,
|
|
|
|
}));
|
2022-01-11 16:24:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-01-14 23:02:08 +08:00
|
|
|
_ => {}
|
2022-01-11 16:24:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-01-14 18:16:00 +08:00
|
|
|
if last_recv_time.elapsed().as_millis() > 3_000 {
|
|
|
|
break;
|
|
|
|
}
|
2022-01-11 16:24:35 +08:00
|
|
|
}
|
2022-07-13 11:18:53 +08:00
|
|
|
Ok(())
|
2022-07-12 22:34:05 +08:00
|
|
|
}
|
|
|
|
|
2022-07-13 18:06:19 +08:00
|
|
|
fn spawn_wait_responses(sockets: Vec<UdpSocket>) -> UnboundedReceiver<config::DiscoveryPeer> {
|
2022-07-13 11:18:53 +08:00
|
|
|
let (tx, rx) = unbounded_channel::<_>();
|
2022-07-12 22:34:05 +08:00
|
|
|
for socket in sockets {
|
2022-07-13 11:18:53 +08:00
|
|
|
let tx_clone = tx.clone();
|
|
|
|
std::thread::spawn(move || {
|
|
|
|
allow_err!(wait_response(
|
|
|
|
socket,
|
|
|
|
Some(std::time::Duration::from_millis(10)),
|
|
|
|
tx_clone
|
|
|
|
));
|
2022-07-12 22:34:05 +08:00
|
|
|
});
|
|
|
|
}
|
2022-07-13 11:18:53 +08:00
|
|
|
rx
|
|
|
|
}
|
2022-07-12 22:34:05 +08:00
|
|
|
|
2022-07-13 18:06:19 +08:00
|
|
|
async fn handle_received_peers(mut rx: UnboundedReceiver<config::DiscoveryPeer>) -> ResultType<()> {
|
|
|
|
let mut peers = config::LanPeers::load().peers;
|
2022-07-13 11:18:53 +08:00
|
|
|
peers.iter_mut().for_each(|peer| {
|
|
|
|
peer.online = false;
|
|
|
|
});
|
2022-07-12 22:34:05 +08:00
|
|
|
|
2022-07-13 11:18:53 +08:00
|
|
|
let mut response_set = HashSet::new();
|
|
|
|
let mut last_write_time = Instant::now() - std::time::Duration::from_secs(4);
|
|
|
|
loop {
|
|
|
|
tokio::select! {
|
|
|
|
data = rx.recv() => match data {
|
2022-07-15 12:16:15 +08:00
|
|
|
Some(mut peer) => {
|
2022-07-13 11:18:53 +08:00
|
|
|
let in_response_set = !response_set.insert(peer.id.clone());
|
2022-07-15 12:16:15 +08:00
|
|
|
if let Some(pos) = peers.iter().position(|x| x.is_same_peer(&peer) ) {
|
|
|
|
let peer1 = peers.remove(pos);
|
|
|
|
if in_response_set {
|
|
|
|
peer.ip_mac.extend(peer1.ip_mac);
|
|
|
|
peer.online = true;
|
2022-07-13 11:18:53 +08:00
|
|
|
}
|
|
|
|
}
|
2022-07-15 12:16:15 +08:00
|
|
|
peers.insert(0, peer);
|
2022-07-13 11:18:53 +08:00
|
|
|
if last_write_time.elapsed().as_millis() > 300 {
|
2022-07-13 18:06:19 +08:00
|
|
|
config::LanPeers::store(&peers);
|
2022-07-13 11:18:53 +08:00
|
|
|
last_write_time = Instant::now();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
break
|
|
|
|
}
|
2022-07-12 22:34:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-13 11:18:53 +08:00
|
|
|
|
2022-07-13 18:06:19 +08:00
|
|
|
config::LanPeers::store(&peers);
|
2022-01-12 03:10:15 +08:00
|
|
|
Ok(())
|
2022-01-11 16:24:35 +08:00
|
|
|
}
|
2022-07-13 11:18:53 +08:00
|
|
|
|
|
|
|
#[tokio::main(flavor = "current_thread")]
|
|
|
|
pub async fn discover() -> ResultType<()> {
|
|
|
|
let sockets = send_query()?;
|
|
|
|
let rx = spawn_wait_responses(sockets);
|
|
|
|
handle_received_peers(rx).await?;
|
|
|
|
|
|
|
|
log::info!("discover ping done");
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-07-14 10:34:56 +08:00
|
|
|
|
|
|
|
pub fn send_wol(id: String) {
|
|
|
|
let interfaces = default_net::get_interfaces();
|
|
|
|
for peer in &config::LanPeers::load().peers {
|
|
|
|
if peer.id == id {
|
|
|
|
for (ip, mac) in peer.ip_mac.iter() {
|
|
|
|
if let Ok(mac_addr) = mac.parse() {
|
|
|
|
if let Ok(IpAddr::V4(ip)) = ip.parse() {
|
|
|
|
for interface in &interfaces {
|
|
|
|
for ipv4 in &interface.ipv4 {
|
|
|
|
if (u32::from(ipv4.addr) & u32::from(ipv4.netmask))
|
|
|
|
== (u32::from(ip) & u32::from(ipv4.netmask))
|
|
|
|
{
|
|
|
|
allow_err!(wol::send_wol(
|
|
|
|
mac_addr,
|
|
|
|
None,
|
|
|
|
Some(IpAddr::V4(ipv4.addr))
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|