Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip: re-architect how we initialize the TUN device #4159

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/connlib/clients/android/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ serde_json = "1"
thiserror = "1"
url = "2.4.0"
tokio = { version = "1.36", default-features = false, features = ["rt"] }
firezone-tunnel = { workspace = true }

[target.'cfg(target_os = "android")'.dependencies]
tracing-android = "0.2"
160 changes: 96 additions & 64 deletions rust/connlib/clients/android/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use connlib_client_shared::{
file_logger, keypair, Callbacks, Cidrv4, Cidrv6, Error, LoginUrl, LoginUrlError,
ResourceDescription, Session,
};
use firezone_tunnel::Tun;
use jni::{
objects::{GlobalRef, JByteArray, JClass, JObject, JObjectArray, JString, JValue, JValueGen},
strings::JNIString,
Expand All @@ -16,7 +17,6 @@ use secrecy::SecretString;
use std::{io, net::IpAddr, path::Path};
use std::{
net::{Ipv4Addr, Ipv6Addr},
os::fd::RawFd,
path::PathBuf,
};
use std::{sync::OnceLock, time::Duration};
Expand All @@ -34,6 +34,7 @@ pub struct CallbackHandler {
vm: JavaVM,
callback_handler: GlobalRef,
handle: file_logger::Handle,
new_tun_sender: tokio::sync::mpsc::Sender<Tun>,
}

impl Clone for CallbackHandler {
Expand All @@ -47,6 +48,7 @@ impl Clone for CallbackHandler {
vm: unsafe { std::ptr::read(&self.vm) },
callback_handler: self.callback_handler.clone(),
handle: self.handle.clone(),
new_tun_sender: self.new_tun_sender.clone(),
}
}
}
Expand Down Expand Up @@ -143,42 +145,54 @@ impl Callbacks for CallbackHandler {
tunnel_address_v4: Ipv4Addr,
tunnel_address_v6: Ipv6Addr,
dns_addresses: Vec<IpAddr>,
) -> Option<RawFd> {
self.env(|mut env| {
let tunnel_address_v4 =
env.new_string(tunnel_address_v4.to_string())
.map_err(|source| CallbackError::NewStringFailed {
name: "tunnel_address_v4",
source,
})?;
let tunnel_address_v6 =
env.new_string(tunnel_address_v6.to_string())
) {
let new_fd = self
.env(|mut env| {
let tunnel_address_v4 =
env.new_string(tunnel_address_v4.to_string())
.map_err(|source| CallbackError::NewStringFailed {
name: "tunnel_address_v4",
source,
})?;
let tunnel_address_v6 =
env.new_string(tunnel_address_v6.to_string())
.map_err(|source| CallbackError::NewStringFailed {
name: "tunnel_address_v6",
source,
})?;
let dns_addresses = env
.new_string(serde_json::to_string(&dns_addresses)?)
.map_err(|source| CallbackError::NewStringFailed {
name: "tunnel_address_v6",
name: "dns_addresses",
source,
})?;
let dns_addresses = env
.new_string(serde_json::to_string(&dns_addresses)?)
.map_err(|source| CallbackError::NewStringFailed {
name: "dns_addresses",
source,
})?;
let name = "onSetInterfaceConfig";
env.call_method(
&self.callback_handler,
name,
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
&[
JValue::from(&tunnel_address_v4),
JValue::from(&tunnel_address_v6),
JValue::from(&dns_addresses),
],
)
.and_then(|val| val.i())
.map(Some)
.map_err(|source| CallbackError::CallMethodFailed { name, source })
})
.expect("onSetInterfaceConfig callback failed")
let name = "onSetInterfaceConfig";
env.call_method(
&self.callback_handler,
name,
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
&[
JValue::from(&tunnel_address_v4),
JValue::from(&tunnel_address_v6),
JValue::from(&dns_addresses),
],
)
.and_then(|val| val.i())
.map_err(|source| CallbackError::CallMethodFailed { name, source })
})
.expect("onSetInterfaceConfig callback failed");

let tun = match Tun::new(new_fd) {
Ok(tun) => tun,
Err(e) => {
tracing::error!("Failed to make new TUN device");
return;
}
};

let _ = self.new_tun_sender.try_send(tun);

// TODO: Make new `Tun` from new file descriptor and re-initialize it on the Tunnel.
}

fn on_tunnel_ready(&self) {
Expand All @@ -194,37 +208,43 @@ impl Callbacks for CallbackHandler {
.expect("onTunnelReady callback failed")
}

fn on_update_routes(
&self,
route_list_4: Vec<Cidrv4>,
route_list_6: Vec<Cidrv6>,
) -> Option<RawFd> {
self.env(|mut env| {
let route_list_4 = env
.new_string(serde_json::to_string(&route_list_4)?)
.map_err(|source| CallbackError::NewStringFailed {
name: "route_list_4",
source,
})?;
let route_list_6 = env
.new_string(serde_json::to_string(&route_list_6)?)
.map_err(|source| CallbackError::NewStringFailed {
name: "route_list_6",
source,
})?;
fn on_update_routes(&self, route_list_4: Vec<Cidrv4>, route_list_6: Vec<Cidrv6>) {
let new_fd = self
.env(|mut env| {
let route_list_4 = env
.new_string(serde_json::to_string(&route_list_4)?)
.map_err(|source| CallbackError::NewStringFailed {
name: "route_list_4",
source,
})?;
let route_list_6 = env
.new_string(serde_json::to_string(&route_list_6)?)
.map_err(|source| CallbackError::NewStringFailed {
name: "route_list_6",
source,
})?;

let name = "onUpdateRoutes";
env.call_method(
&self.callback_handler,
name,
"(Ljava/lang/String;Ljava/lang/String;)I",
&[JValue::from(&route_list_4), JValue::from(&route_list_6)],
)
.and_then(|val| val.i())
.map(Some)
.map_err(|source| CallbackError::CallMethodFailed { name, source })
})
.expect("onUpdateRoutes callback failed")
let name = "onUpdateRoutes";
env.call_method(
&self.callback_handler,
name,
"(Ljava/lang/String;Ljava/lang/String;)I",
&[JValue::from(&route_list_4), JValue::from(&route_list_6)],
)
.and_then(|val| val.i())
.map_err(|source| CallbackError::CallMethodFailed { name, source })
})
.expect("onUpdateRoutes callback failed");

let tun = match Tun::new(new_fd) {
Ok(tun) => tun,
Err(e) => {
tracing::error!("Failed to make new TUN device");
return;
}
};

let _ = self.new_tun_sender.try_send(
}

#[cfg(target_os = "android")]
Expand Down Expand Up @@ -400,12 +420,15 @@ fn connect(
let log_dir = string_from_jstring!(env, log_dir);
let log_filter = string_from_jstring!(env, log_filter);

let (new_tun_sender, mut new_tun_receiver) = tokio::sync::mpsc::channel(1);

let handle = init_logging(&PathBuf::from(log_dir), log_filter);

let callback_handler = CallbackHandler {
vm: env.get_java_vm().map_err(ConnectError::GetJavaVmFailed)?,
callback_handler,
handle,
new_tun_sender,
};

let (private_key, public_key) = keypair();
Expand All @@ -432,6 +455,15 @@ fn connect(
runtime.handle().clone(),
)?;

{
let mut session = session.clone();
tokio::spawn(async move {
while let Some(tun) = new_tun_receiver.recv().await {
session.update_tun(tun);
}
});
}

Ok(SessionWrapper {
inner: session,
runtime,
Expand Down
1 change: 1 addition & 0 deletions rust/connlib/clients/apple/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ tracing-subscriber = "0.3"
tracing-appender = "0.2"
url = "2.5.0"
tokio = { version = "1.36", default-features = false, features = ["rt"] }
firezone-tunnel = { workspace = true }

[lib]
name = "connlib"
Expand Down
19 changes: 7 additions & 12 deletions rust/connlib/clients/apple/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
use connlib_client_shared::{
file_logger, keypair, Callbacks, Cidrv4, Cidrv6, Error, LoginUrl, ResourceDescription, Session,
};
use firezone_tunnel::Tun;
use secrecy::SecretString;
use std::{
net::{IpAddr, Ipv4Addr, Ipv6Addr},
os::fd::RawFd,
path::PathBuf,
sync::Arc,
time::Duration,
Expand Down Expand Up @@ -102,32 +102,24 @@ impl Callbacks for CallbackHandler {
tunnel_address_v4: Ipv4Addr,
tunnel_address_v6: Ipv6Addr,
dns_addresses: Vec<IpAddr>,
) -> Option<RawFd> {
) {
self.inner.on_set_interface_config(
tunnel_address_v4.to_string(),
tunnel_address_v6.to_string(),
serde_json::to_string(&dns_addresses)
.expect("developer error: a list of ips should always be serializable"),
);

None
}

fn on_tunnel_ready(&self) {
self.inner.on_tunnel_ready();
}

fn on_update_routes(
&self,
route_list_4: Vec<Cidrv4>,
route_list_6: Vec<Cidrv6>,
) -> Option<RawFd> {
fn on_update_routes(&self, route_list_4: Vec<Cidrv4>, route_list_6: Vec<Cidrv6>) {
self.inner.on_update_routes(
serde_json::to_string(&route_list_4).unwrap(),
serde_json::to_string(&route_list_6).unwrap(),
);

None
}

fn on_update_resources(&self, resource_list: Vec<ResourceDescription>) {
Expand Down Expand Up @@ -210,7 +202,7 @@ impl WrappedSession {
.build()
.map_err(|e| e.to_string())?;

let session = Session::connect(
let mut session = Session::connect(
login,
private_key,
os_version_override,
Expand All @@ -223,6 +215,9 @@ impl WrappedSession {
)
.map_err(|err| err.to_string())?;

let tun = Tun::new().map_err(|e| e.to_string())?;
session.update_tun(tun);

Ok(Self {
inner: session,
runtime,
Expand Down
13 changes: 8 additions & 5 deletions rust/connlib/clients/shared/src/eventloop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use connlib_shared::{
messages::{ConnectionAccepted, GatewayResponse, ResourceAccepted, ResourceId},
Callbacks,
};
use firezone_tunnel::ClientTunnel;
use firezone_tunnel::{ClientTunnel, Tun};
use phoenix_channel::{ErrorReply, OutboundRequestId, PhoenixChannel};
use std::{
collections::HashMap,
Expand All @@ -37,6 +37,7 @@ pub struct Eventloop<C: Callbacks> {
pub enum Command {
Stop,
Reconnect,
Update(Tun),
}

impl<C: Callbacks> Eventloop<C> {
Expand Down Expand Up @@ -71,6 +72,11 @@ where

continue;
}
Poll::Ready(Some(Command::Update(tun))) => {
if let Err(e) = self.tunnel.update_tun(tun) {
tracing::warn!("Failed to update TUN device: {e}");
};
}
Poll::Pending => {}
}

Expand Down Expand Up @@ -180,10 +186,7 @@ where
resources,
}) => {
if !self.tunnel_init {
if let Err(e) = self.tunnel.set_interface(&interface) {
tracing::warn!("Failed to set interface on tunnel: {e}");
return;
}
self.tunnel.set_interface(&interface);

self.tunnel_init = true;
tracing::info!("Firezone Started!");
Expand Down
Loading
Loading