diff --git a/easytier/src/dns/mod.rs b/easytier/src/dns/mod.rs index 74b4822d..e7636a63 100644 --- a/easytier/src/dns/mod.rs +++ b/easytier/src/dns/mod.rs @@ -1,8 +1,8 @@ pub mod config; -mod node; +pub mod node; mod node_mgr; mod peer_mgr; pub mod server; -pub mod system; +mod system; mod utils; pub mod zone; diff --git a/easytier/src/dns/node.rs b/easytier/src/dns/node.rs index ade588b7..8713d374 100644 --- a/easytier/src/dns/node.rs +++ b/easytier/src/dns/node.rs @@ -3,6 +3,7 @@ use crate::common::PeerId; use crate::dns::config::{DNS_SERVER_ELECTION_INTERVAL, DNS_SERVER_RPC_ADDR}; use crate::dns::peer_mgr::DnsPeerMgr; use crate::dns::server::DnsServer; +use crate::instance::instance::ArcNicCtx; use crate::peers::peer_manager::PeerManager; use crate::peers::NicPacketFilter; use crate::proto::dns::{DnsNodeMgrRpcClientFactory, DnsPeerMgrRpcServer, HeartbeatRequest}; @@ -20,12 +21,19 @@ use uuid::Uuid; pub struct DnsNode { mgr: Arc, + #[cfg(feature = "tun")] + nic_ctx: ArcNicCtx, // TODO: REMOVE THIS + peer_mgr: Arc, global_ctx: ArcGlobalCtx, } impl DnsNode { - pub fn new(peer_mgr: Arc, global_ctx: ArcGlobalCtx) -> Self { + pub fn new( + peer_mgr: Arc, + global_ctx: ArcGlobalCtx, + #[cfg(feature = "tun")] nic_ctx: ArcNicCtx, // TODO: REMOVE THIS + ) -> Self { let mgr = Arc::new(DnsPeerMgr::new(peer_mgr.clone())); peer_mgr .get_peer_rpc_mgr() @@ -38,8 +46,9 @@ impl DnsNode { Self { mgr, - global_ctx, + nic_ctx, peer_mgr, + global_ctx, } } @@ -71,7 +80,13 @@ impl DnsNode { tracing::info!("won DNS server election, starting DnsServer"); - let server = Arc::new(DnsServer::new(self.peer_mgr.clone(), rpc)); + let server = Arc::new(DnsServer::new( + self.peer_mgr.clone(), + self.global_ctx.clone(), + rpc, + #[cfg(feature = "tun")] + self.nic_ctx.clone(), + )); self.global_ctx.set_dns(Some(server.clone())); tokio::join!( diff --git a/easytier/src/dns/server.rs b/easytier/src/dns/server.rs index b12229b1..f5ea197b 100644 --- a/easytier/src/dns/server.rs +++ b/easytier/src/dns/server.rs @@ -1,5 +1,9 @@ +use crate::common::config::ConfigLoader; +use crate::common::global_ctx::ArcGlobalCtx; use crate::dns::node_mgr::DnsNodeMgr; +use crate::dns::system; use crate::dns::utils::addr::NameServerAddr; +use crate::instance::instance::{ArcNicCtx, NicCtx}; use crate::peer_center::instance::PeerCenterPeerManagerTrait; use crate::peers::peer_manager::PeerManager; use crate::peers::NicPacketFilter; @@ -10,6 +14,7 @@ use crate::tunnel::packet_def::ZCPacket; use crate::tunnel::tcp::TcpTunnelListener; use derivative::Derivative; use derive_more::{Deref, DerefMut, From, Into}; +use futures_util::StreamExt; use hickory_proto::rr::Record; use hickory_proto::serialize::binary::{BinDecodable, BinEncoder}; use hickory_proto::xfer::Protocol; @@ -19,6 +24,7 @@ use hickory_server::{ server::{Request, RequestHandler, ResponseHandler, ResponseInfo}, ServerFuture, }; +use itertools::Itertools; use parking_lot::{Mutex, RwLock}; use pnet::packet::icmp::{IcmpTypes, MutableIcmpPacket}; use pnet::packet::ip::IpNextHeaderProtocols; @@ -28,6 +34,7 @@ use pnet::packet::{icmp, ipv4, udp, MutablePacket, Packet}; use std::collections::HashSet; use std::io; use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}; +use std::path::Display; use std::{sync::Arc, time::Duration}; use tokio::task::JoinHandle; use tokio_util::sync::CancellationToken; @@ -152,7 +159,11 @@ impl Drop for DnsServerRuntime { pub struct DnsServer { mgr: Arc, + #[cfg(feature = "tun")] + nic_ctx: ArcNicCtx, // TODO: REMOVE THIS + peer_mgr: Arc, + global_ctx: ArcGlobalCtx, #[derivative(Debug = "ignore")] catalog: DynamicCatalog, @@ -163,7 +174,12 @@ pub struct DnsServer { const DNS_SERVER_LISTENER_TCP_TIMEOUT: Duration = Duration::from_secs(5); impl DnsServer { - pub fn new(peer_mgr: Arc, rpc: StandAloneServer) -> Self { + pub fn new( + peer_mgr: Arc, + global_ctx: ArcGlobalCtx, + rpc: StandAloneServer, + #[cfg(feature = "tun")] nic_ctx: ArcNicCtx, // TODO: REMOVE THIS + ) -> Self { let mgr = Arc::new(DnsNodeMgr::new()); rpc.registry() @@ -171,7 +187,9 @@ impl DnsServer { Self { mgr, + nic_ctx, peer_mgr, + global_ctx, catalog: DynamicCatalog::new(), addresses: Arc::new(Default::default()), } @@ -208,6 +226,50 @@ impl DnsServer { Ok(()) } + async fn reload_addresses( + &self, + addresses: impl IntoIterator, + ) -> anyhow::Result<()> { + let addresses: HashSet<_> = addresses.into_iter().collect(); + + #[cfg(feature = "tun")] + { + let nic_ctx = self.nic_ctx.lock().await; + if let Some(nic_ctx) = nic_ctx + .as_ref() + .and_then(|nic_ctx| nic_ctx.downcast_ref::()) + { + if let Some(system) = nic_ctx + .ifname() + .await + .map(|ifname| system::get(&ifname)) + .transpose()? + .flatten() + { + let config = self.global_ctx.config.get_dns(); + let domain = vec![config.domain.to_string()]; + system.set_dns(&system::SystemConfig { + nameservers: addresses + .iter() + .filter_map(|a| { + (a.protocol == Protocol::Udp).then_some(a.addr.to_string()) + }) + .collect(), + search_domains: domain.clone(), + match_domains: domain + .into_iter() + .chain(config.zones.iter().map(|z| z.origin.to_string())) + .collect(), + })?; + } + } + } + + *self.addresses.write() = addresses; + + Ok(()) + } + pub async fn run(&self) { let dirty = &self.mgr.dirty; let mut runtime = None; @@ -226,7 +288,10 @@ impl DnsServer { loop { dirty.addresses.notified().await; if dirty.addresses.reset() { - *self.addresses.write() = self.mgr.iter_addresses().collect(); + if let Err(e) = self.reload_addresses(self.mgr.iter_addresses()).await { + tracing::error!("failed to reload addresses: {:?}", e); + dirty.addresses.mark(); + } } tokio::time::sleep(Duration::from_secs(1)).await; } diff --git a/easytier/src/dns/system/mod.rs b/easytier/src/dns/system/mod.rs index 6970536c..8135f726 100644 --- a/easytier/src/dns/system/mod.rs +++ b/easytier/src/dns/system/mod.rs @@ -22,7 +22,7 @@ pub trait SystemConfigurator: Send + Sync { } // TODO: move this to nic mod -fn get( +pub fn get( #[allow(unused_variables)] interface: &str, ) -> Result>, anyhow::Error> { #[cfg(target_os = "windows")] diff --git a/easytier/src/instance/instance.rs b/easytier/src/instance/instance.rs index b56fe007..00f3ffb0 100644 --- a/easytier/src/instance/instance.rs +++ b/easytier/src/instance/instance.rs @@ -25,6 +25,7 @@ use crate::connector::direct::DirectConnectorManager; use crate::connector::manual::{ConnectorManagerRpcService, ManualConnectorManager}; use crate::connector::tcp_hole_punch::TcpHolePunchConnector; use crate::connector::udp_hole_punch::UdpHolePunchConnector; +use crate::dns::node::DnsNode; use crate::gateway::icmp_proxy::IcmpProxy; #[cfg(feature = "kcp")] use crate::gateway::kcp_proxy::{KcpProxyDst, KcpProxyDstRpcService, KcpProxySrc}; @@ -127,10 +128,10 @@ impl IpProxy { } #[cfg(feature = "tun")] -type NicCtx = super::virtual_nic::NicCtx; +pub type NicCtx = super::virtual_nic::NicCtx; #[cfg(feature = "tun")] -type ArcNicCtx = Arc>>>; +pub type ArcNicCtx = Arc>>>; pub struct InstanceRpcServerHook { rpc_portal_whitelist: Vec, @@ -469,6 +470,8 @@ pub struct Instance { #[cfg(feature = "tun")] nic_ctx: ArcNicCtx, + #[cfg(feature = "magic-dns")] + dns: DnsNode, peer_packet_receiver: Arc>, peer_manager: Arc,