mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
fix(client): flush the OS' DNS cache whenever resources change (#5700)
Closes #5052 On my dev VMs: - systemd-resolved = 15 ms to flush - Windows = 600 ms to flush I tested with the headless Clients on Linux and Windows and it fixes the issue. On Windows I didn't replicate the issue with the GUI Client, on Linux this patch also fixes it for the GUI Client.
This commit is contained in:
@@ -164,7 +164,7 @@ impl TunDeviceManager {
|
||||
}
|
||||
|
||||
for route in self.routes.difference(&new_routes) {
|
||||
delete_route(route, index, handle).await?;
|
||||
remove_route(route, index, handle).await?;
|
||||
}
|
||||
|
||||
self.routes = new_routes;
|
||||
@@ -232,7 +232,7 @@ async fn add_route(route: &IpNetwork, idx: u32, handle: &Handle) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_route(route: &IpNetwork, idx: u32, handle: &Handle) -> Result<()> {
|
||||
async fn remove_route(route: &IpNetwork, idx: u32, handle: &Handle) -> Result<()> {
|
||||
let message = match route {
|
||||
IpNetwork::V4(ipnet) => make_route_v4(idx, handle, *ipnet).message_mut().clone(),
|
||||
IpNetwork::V6(ipnet) => make_route_v6(idx, handle, *ipnet).message_mut().clone(),
|
||||
|
||||
@@ -134,8 +134,6 @@ impl Tun {
|
||||
self.remove_route(*old_route)?;
|
||||
}
|
||||
|
||||
// TODO: Might be calling this more often than it needs
|
||||
flush_dns().expect("Should be able to flush Windows' DNS cache");
|
||||
self.routes = new_routes;
|
||||
Ok(())
|
||||
}
|
||||
@@ -245,16 +243,6 @@ impl Tun {
|
||||
}
|
||||
}
|
||||
|
||||
/// Flush Windows' system-wide DNS cache
|
||||
pub(crate) fn flush_dns() -> Result<()> {
|
||||
tracing::info!("Flushing Windows DNS cache");
|
||||
Command::new("powershell")
|
||||
.creation_flags(CREATE_NO_WINDOW)
|
||||
.args(["-Command", "Clear-DnsClientCache"])
|
||||
.status()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Moves packets from the user towards the Internet
|
||||
fn start_recv_thread(
|
||||
packet_tx: mpsc::Sender<wintun::Packet>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use anyhow::{bail, Context as _, Result};
|
||||
use connlib_shared::tun_device_manager::linux::IFACE_NAME;
|
||||
use std::{net::IpAddr, str::FromStr};
|
||||
use std::{net::IpAddr, process::Command, str::FromStr};
|
||||
|
||||
mod etc_resolv_conf;
|
||||
|
||||
@@ -63,6 +63,19 @@ impl DnsController {
|
||||
}
|
||||
.context("Failed to control DNS")
|
||||
}
|
||||
|
||||
/// Flush systemd-resolved's system-wide DNS cache
|
||||
///
|
||||
/// Does nothing if we're using other DNS control methods or none at all
|
||||
pub(crate) fn flush(&self) -> Result<()> {
|
||||
// Flushing is only implemented for systemd-resolved
|
||||
if matches!(self.dns_control_method, Some(DnsControlMethod::Systemd)) {
|
||||
tracing::debug!("Flushing systemd-resolved DNS cache...");
|
||||
Command::new("resolvectl").arg("flush-caches").status()?;
|
||||
tracing::debug!("Flushed DNS.");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads FIREZONE_DNS_CONTROL. Returns None if invalid or not set
|
||||
|
||||
@@ -51,6 +51,19 @@ impl DnsController {
|
||||
activate(dns_config).context("Failed to activate DNS control")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Flush Windows' system-wide DNS cache
|
||||
///
|
||||
/// `&self` is needed to match the Linux signature
|
||||
pub(crate) fn flush(&self) -> Result<()> {
|
||||
tracing::debug!("Flushing Windows DNS cache...");
|
||||
Command::new("powershell")
|
||||
.creation_flags(CREATE_NO_WINDOW)
|
||||
.args(["-Command", "Clear-DnsClientCache"])
|
||||
.status()?;
|
||||
tracing::debug!("Flushed DNS.");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn system_resolvers() -> Result<Vec<IpAddr>> {
|
||||
|
||||
@@ -209,6 +209,9 @@ impl Handler {
|
||||
let dur = instant.elapsed();
|
||||
tracing::info!(?dur, "Connlib started");
|
||||
}
|
||||
|
||||
// On every resources update, flush DNS to mitigate <https://github.com/firezone/firezone/issues/5052>
|
||||
self.dns_controller.flush()?;
|
||||
}
|
||||
self.ipc_tx
|
||||
.send(&msg)
|
||||
|
||||
@@ -78,6 +78,7 @@ struct CliCommon {
|
||||
max_partition_time: Option<humantime::Duration>,
|
||||
}
|
||||
|
||||
/// Messages we get from connlib, including ones that aren't sent to IPC clients
|
||||
enum InternalServerMsg {
|
||||
Ipc(IpcServerMsg),
|
||||
OnSetInterfaceConfig {
|
||||
@@ -91,6 +92,7 @@ enum InternalServerMsg {
|
||||
},
|
||||
}
|
||||
|
||||
/// Messages that we can send to IPC clients
|
||||
#[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
pub enum IpcServerMsg {
|
||||
Ok,
|
||||
|
||||
@@ -192,7 +192,10 @@ pub fn run_only_headless_client() -> Result<()> {
|
||||
}) => return Err(anyhow!(error_msg).context("Firezone disconnected")),
|
||||
InternalServerMsg::Ipc(IpcServerMsg::Ok)
|
||||
| InternalServerMsg::Ipc(IpcServerMsg::OnTunnelReady)
|
||||
| InternalServerMsg::Ipc(IpcServerMsg::OnUpdateResources(_)) => {}
|
||||
| InternalServerMsg::Ipc(IpcServerMsg::OnUpdateResources(_)) => {
|
||||
// On every resources update, flush DNS to mitigate <https://github.com/firezone/firezone/issues/5052>
|
||||
dns_controller.flush()?;
|
||||
}
|
||||
InternalServerMsg::OnSetInterfaceConfig { ipv4, ipv6, dns } => {
|
||||
tun_device.set_ips(ipv4, ipv6).await?;
|
||||
dns_controller.set_dns(&dns).await?;
|
||||
|
||||
Reference in New Issue
Block a user