diff --git a/rust/connlib/tunnel/src/device_channel.rs b/rust/connlib/tunnel/src/device_channel.rs index 6396f6b9f..c4d10a39f 100644 --- a/rust/connlib/tunnel/src/device_channel.rs +++ b/rust/connlib/tunnel/src/device_channel.rs @@ -116,9 +116,11 @@ impl Device { dns_config: Vec, _: &impl Callbacks, ) -> Result<(), ConnlibError> { - let tun = Tun::new(config, dns_config)?; + if self.tun.is_none() { + self.tun = Some(Tun::new()?); + } - self.tun = Some(tun); + self.tun.as_ref().unwrap().set_config(config, &dns_config)?; if let Some(waker) = self.waker.take() { waker.wake(); diff --git a/rust/connlib/tunnel/src/device_channel/tun_windows.rs b/rust/connlib/tunnel/src/device_channel/tun_windows.rs index a058e19da..a30e3af1e 100644 --- a/rust/connlib/tunnel/src/device_channel/tun_windows.rs +++ b/rust/connlib/tunnel/src/device_channel/tun_windows.rs @@ -27,7 +27,7 @@ const TUNNEL_NAME: &str = "Firezone"; // TODO: Double-check that all these get dropped gracefully on disconnect pub struct Tun { - _adapter: Arc, + adapter: Arc, /// The index of our network adapter, we can use this when asking Windows to add / remove routes / DNS rules /// It's stable across app restarts and I'm assuming across system reboots too. iface_idx: u32, @@ -53,7 +53,7 @@ const CREATE_NO_WINDOW: u32 = 0x08000000; const DEFAULT_MTU: u32 = 1280; impl Tun { - pub fn new(config: &InterfaceConfig, dns_config: Vec) -> Result { + pub fn new() -> Result { const TUNNEL_UUID: &str = "e9245bc1-b8c1-44ca-ab1d-c6aad4f13b9c"; // SAFETY: we're loading a DLL from disk and it has arbitrary C code in it. @@ -73,6 +73,39 @@ impl Tun { } }; + let iface_idx = adapter.get_adapter_index()?; + + // Remove any routes that were previously associated with us + // TODO: Pick a more elegant way to do this + Command::new("powershell") + .creation_flags(CREATE_NO_WINDOW) + .arg("-Command") + .arg(format!( + "Remove-NetRoute -InterfaceIndex {iface_idx} -Confirm:$false" + )) + .stdout(Stdio::null()) + .status()?; + + set_iface_config(adapter.get_luid(), DEFAULT_MTU)?; + + let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY)?); + + let (packet_tx, packet_rx) = mpsc::channel(5); + + let recv_thread = start_recv_thread(packet_tx, Arc::clone(&session))?; + let packet_rx = std::sync::Mutex::new(packet_rx); + + Ok(Self { + adapter, + iface_idx, + _recv_thread: recv_thread, + packet_rx, + session: Arc::clone(&session), + routes: HashSet::new(), + }) + } + + pub fn set_config(&self, config: &InterfaceConfig, dns_config: &[IpAddr]) -> Result<()> { tracing::debug!("Setting our IPv4 = {}", config.ipv4); tracing::debug!("Setting our IPv6 = {}", config.ipv6); @@ -102,22 +135,9 @@ impl Tun { .stdout(Stdio::null()) .status()?; - tracing::debug!("Our IPs are {:?}", adapter.get_addresses()?); + tracing::debug!("Our IPs are {:?}", self.adapter.get_addresses()?); - let iface_idx = adapter.get_adapter_index()?; - - // Remove any routes that were previously associated with us - // TODO: Pick a more elegant way to do this - Command::new("powershell") - .creation_flags(CREATE_NO_WINDOW) - .arg("-Command") - .arg(format!( - "Remove-NetRoute -InterfaceIndex {iface_idx} -Confirm:$false" - )) - .stdout(Stdio::null()) - .status()?; - - set_iface_config(adapter.get_luid(), DEFAULT_MTU)?; + let iface_idx = self.adapter.get_adapter_index()?; // Set our DNS IP as the DNS server for our interface // TODO: Known issue where web browsers will keep a connection open to a site, @@ -139,21 +159,7 @@ impl Tun { .stdout(Stdio::null()) .status()?; - let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY)?); - - let (packet_tx, packet_rx) = mpsc::channel(5); - - let recv_thread = start_recv_thread(packet_tx, Arc::clone(&session))?; - let packet_rx = std::sync::Mutex::new(packet_rx); - - Ok(Self { - _adapter: adapter, - iface_idx, - _recv_thread: recv_thread, - packet_rx, - session: Arc::clone(&session), - routes: HashSet::new(), - }) + Ok(()) } // It's okay if this blocks until the route is added in the OS.