refactor(connlib): don't recreate the tun device for Apple and Windows (#4260)

This is done to fix a bug where the file descriptor is unregistered from
the reactor after the new `Tun` struct is created if the old one is
dropped after.
This commit is contained in:
Gabi
2024-03-21 21:12:02 -03:00
committed by GitHub
parent 64f0427ef4
commit 4d739a8d27
4 changed files with 33 additions and 14 deletions

View File

@@ -212,7 +212,7 @@ where
let callbacks = self.callbacks.clone();
self.io.device_mut().initialize(
self.io.device_mut().set_config(
&config,
// We can just sort in here because sentinel ips are created in order
dns_mapping.left_values().copied().sorted().collect(),

View File

@@ -63,8 +63,8 @@ impl Device {
}
}
#[cfg(target_family = "unix")]
pub(crate) fn initialize(
#[cfg(any(target_os = "android", target_os = "linux"))]
pub(crate) fn set_config(
&mut self,
config: &Interface,
dns_config: Vec<IpAddr>,
@@ -83,8 +83,34 @@ impl Device {
Ok(())
}
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub(crate) fn set_config(
&mut self,
config: &Interface,
dns_config: Vec<IpAddr>,
callbacks: &impl Callbacks,
) -> Result<(), ConnlibError> {
// For macos the filedescriptor is the same throughout its lifetime.
// If we reinitialzie tun, we might drop the old tun after the new one is created
// this unregisters the file descriptor with the reactor so we never wake up
// in case an event is triggered.
if self.tun.is_none() {
self.tun = Some(Tun::new()?);
}
self.mtu = ioctl::interface_mtu_by_name(self.tun.as_ref().unwrap().name())?;
callbacks.on_set_interface_config(config.ipv4, config.ipv6, dns_config);
if let Some(waker) = self.waker.take() {
waker.wake();
}
Ok(())
}
#[cfg(target_family = "windows")]
pub(crate) fn initialize(
pub(crate) fn set_config(
&mut self,
config: &Interface,
dns_config: Vec<IpAddr>,

View File

@@ -1,12 +1,11 @@
use crate::device_channel::{ipv4, ipv6};
use connlib_shared::{messages::Interface as InterfaceConfig, Callbacks, Error, Result};
use connlib_shared::{Callbacks, Error, Result};
use ip_network::IpNetwork;
use libc::{
ctl_info, fcntl, getpeername, getsockopt, ioctl, iovec, msghdr, recvmsg, sendmsg, sockaddr_ctl,
socklen_t, AF_INET, AF_INET6, AF_SYSTEM, CTLIOCGINFO, F_GETFL, F_SETFL, IF_NAMESIZE,
O_NONBLOCK, SYSPROTO_CONTROL, UTUN_OPT_IFNAME,
};
use std::net::IpAddr;
use std::task::{Context, Poll};
use std::{
collections::HashSet,
@@ -70,11 +69,7 @@ impl Tun {
}
}
pub fn new(
config: &InterfaceConfig,
dns_config: Vec<IpAddr>,
callbacks: &impl Callbacks,
) -> Result<Self> {
pub fn new() -> Result<Self> {
let mut info = ctl_info {
ctl_id: 0,
ctl_name: [0; 96],
@@ -131,8 +126,6 @@ impl Tun {
}
if addr.sc_id == info.ctl_id {
callbacks.on_set_interface_config(config.ipv4, config.ipv6, dns_config);
set_non_blocking(fd)?;
return Ok(Self {

View File

@@ -50,7 +50,7 @@ where
let callbacks = self.callbacks.clone();
self.io
.device_mut()
.initialize(config, vec![], &callbacks)?;
.set_config(config, vec![], &callbacks)?;
self.io.device_mut().set_routes(
HashSet::from([PEERS_IPV4.parse().unwrap(), PEERS_IPV6.parse().unwrap()]),
&callbacks,