Skip to content
Open
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
1 change: 1 addition & 0 deletions .unreleased/LLT-7068
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added the `mtu` start option and `set_adapter_mtu`, for setting the adapter interface MTU. Supported on Windows only.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,17 +320,24 @@ We need to provide an instance of the `DeviceConfig` structure:
pub struct DeviceConfig {
pub private_key: SecretKey,
pub adapter: AdapterType,
pub fwmark: Option<u32>,
pub name: Option<String>,
pub tun: Option<Tun>,
pub ext_if_filter: Option<Vec<String>>,
pub mtu: Option<u32>,
}
```

Let's discuss its fields shortly:

- `private_key` a `telio::crypto::SecretKey` instance containing a 256-bit key,
- `adapter` indicating which Wireguard implementation we want to use,
- `fwmark` the firewall mark to set on the sockets opened by Telio, Linux only,
- `name` is the name of the network interface, when omitted, Telio uses the default one,
- `tun` a file descriptor of the already opened tunnel, if it's not provided Telio will open a new one.
- `tun` a file descriptor of the already opened tunnel, if it's not provided Telio will open a new one,
- `ext_if_filter` names of the interfaces to skip while looking for the default interface,
- `mtu` the MTU of the adapter interface, Windows native adapter only. It can also be
changed on a running device with `Device::set_adapter_mtu`.

The API provides a default config which is almost sufficient for simple cases,
the only need that needs to be done is the generation of a private key:
Expand Down
21 changes: 21 additions & 0 deletions crates/telio-core/src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ pub struct DeviceConfig {
pub name: Option<String>,
pub tun: Option<Tun>,
pub ext_if_filter: Option<Vec<String>>,
pub mtu: Option<u32>,
}

pub struct Device {
Expand Down Expand Up @@ -722,6 +723,16 @@ impl Device {
})
}

/// Configure the MTU of the adapter interface, `None` restores the adapter's own handling.
pub fn set_adapter_mtu(&self, mtu: Option<u32>) -> Result {
self.async_runtime()?.block_on(async {
task_exec!(self.rt()?, async move |rt| {
Ok(rt.set_adapter_mtu(mtu).boxed().await)
})
.await?
})
}

/// Retrieves currently configured private key for the interface
pub fn get_private_key(&self) -> Result<SecretKey> {
self.async_runtime()?.block_on(async {
Expand Down Expand Up @@ -1267,6 +1278,7 @@ impl Runtime {
firewall_process_outbound_callback,
firewall_reset_connections,
enable_dynamic_wg_nt_control,
mtu: config.mtu,
skt_buffer_size : Runtime::sanitize_neptun_config(features.wireguard.skt_buffer_size, config.adapter.clone()),
inter_thread_channel_size : Runtime::sanitize_neptun_config(features.wireguard.inter_thread_channel_size, config.adapter.clone()),
max_inter_thread_batched_pkts : Runtime::sanitize_neptun_config(features.wireguard.max_inter_thread_batched_pkts, config.adapter.clone()),
Expand All @@ -1292,6 +1304,7 @@ impl Runtime {
firewall_process_outbound_callback,
firewall_reset_connections,
enable_dynamic_wg_nt_control,
mtu: config.mtu,
skt_buffer_size: features.wireguard.skt_buffer_size,
inter_thread_channel_size: features.wireguard.inter_thread_channel_size,
max_inter_thread_batched_pkts: features.wireguard.max_inter_thread_batched_pkts,
Expand Down Expand Up @@ -1753,6 +1766,14 @@ impl Runtime {
Ok(())
}

async fn set_adapter_mtu(&mut self, mtu: Option<u32>) -> Result {
Ok(self
.entities
.wireguard_interface
.set_adapter_mtu(mtu)
.await?)
}

async fn set_private_key(&mut self, private_key: &SecretKey) -> Result {
// TODO: create a global controll state to consolidate all entities

Expand Down
36 changes: 7 additions & 29 deletions crates/telio-traversal/src/endpoint_providers/stun.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,6 @@ mod stun_msg {
mod tests {
use super::*;
use maplit::hashmap;
use mockall::mock;
use std::{
cell::RefCell,
net::{Ipv4Addr, Ipv6Addr, SocketAddr},
Expand All @@ -1042,16 +1041,15 @@ mod tests {
PublicKey, SecretKey,
encryption::{decrypt_request, decrypt_response, encrypt_request, encrypt_response},
};
use telio_model::mesh::{IpNet, LinkState};
use telio_model::mesh::IpNet;
use telio_proto::{CodecError, PacketRelayed, PartialPongerMsg, PingerMsg};
use telio_sockets::NativeProtector;
use telio_sockets::SocketPool;
use telio_task::io::Chan;
use telio_test::await_timeout;
use telio_utils::exponential_backoff::MockBackoff;
use telio_utils::ip_stack::IpStack;
use telio_wg::{
Error,
MockWireGuard,
uapi::{Interface, Peer},
};
use tokio::{
Expand Down Expand Up @@ -1758,7 +1756,7 @@ mod tests {

#[tokio::test(start_paused = true)]
async fn exponential_backoff_is_applied_even_if_session_start_failed() {
let mut wg = MockWg::new();
let mut wg = MockWireGuard::new();

// Expect a single call to get_interface when we enter the loop first and
// and a second in the finished backoff
Expand Down Expand Up @@ -1800,7 +1798,7 @@ mod tests {

#[tokio::test(start_paused = true)]
async fn wait_with_session_start_until_stun_server_wg_peer_is_available() {
let mut wg = MockWg::default();
let mut wg = MockWireGuard::default();
let wg_port = 12345;

let peer_sock_v4 = UdpSocket::bind((Ipv4Addr::LOCALHOST, 0))
Expand Down Expand Up @@ -1938,26 +1936,6 @@ mod tests {

// Test helpers

mock! {
Wg {}
#[async_trait]
impl WireGuard for Wg {
async fn get_interface(&self) -> Result<Interface, Error>;
async fn get_adapter_luid(&self) -> Result<u64, Error>;
async fn wait_for_listen_port(&self, d: Duration) -> Result<u16, Error>;
async fn get_link_state(&self, key: PublicKey) -> Result<Option<LinkState>, Error>;
async fn set_secret_key(&self, key: SecretKey) -> Result<(), Error>;
async fn set_fwmark(&self, fwmark: u32) -> Result<(), Error>;
async fn add_peer(&self, peer: Peer) -> Result<(), Error>;
async fn del_peer(&self, key: PublicKey) -> Result<(), Error>;
async fn drop_connected_sockets(&self) -> Result<(), Error>;
async fn time_since_last_rx(&self, public_key: PublicKey) -> Result<Option<Duration>, Error>;
async fn stop(self);
async fn reset_existing_connections(&self, exit_pubkey: PublicKey) -> Result<(), Error>;
async fn set_ip_stack(&self, ip_stack: Option<IpStack>) -> Result<(), Error>;
}
}

struct StunPeerSockets {
/// This socket represent a socket that is listening in remote peer.
/// We will not fake entire tunnel, as it correct behavior would basically
Expand All @@ -1975,7 +1953,7 @@ mod tests {
socket_pool: Arc<SocketPool>,

// Tested system
stun_provider: StunEndpointProvider<MockWg, MockBackoff>,
stun_provider: StunEndpointProvider<MockWireGuard, MockBackoff>,
ipv6: bool,

// External behavior
Expand All @@ -1999,7 +1977,7 @@ mod tests {
server_weights: Vec<u32>,
ipv6: bool,
) -> Env {
let mut wg = MockWg::default();
let mut wg = MockWireGuard::default();
let wg_port = 12345;

let mut stun_servers = Vec::<Server>::new();
Expand Down Expand Up @@ -2101,7 +2079,7 @@ mod tests {
backoff_array: Option<[u64; 6]>,
stun_servers: Vec<Server>,
stun_peers: Vec<StunPeerSockets>,
wg: MockWg,
wg: MockWireGuard,
ipv6: bool,
) -> Env {
let socket_pool = SocketPool::new(
Expand Down
33 changes: 4 additions & 29 deletions crates/telio-traversal/src/endpoint_providers/upnp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,6 @@ impl<Wg: WireGuard, I: UpnpEpCommands, E: Backoff> Runtime for State<Wg, I, E> {
mod tests {
use super::{
EPHEMERAL_PORT_RANGE, EndpointCandidate, MockUpnpEpCommands, UpnpEndpointProvider,
async_trait,
};

use std::{
Expand All @@ -832,45 +831,21 @@ mod tests {
use crate::endpoint_providers::Error;
use crate::ping_pong_handler::PingPongHandler;
use lazy_static::lazy_static;
use mockall::mock;
use parking_lot::Mutex;
use serial_test::serial;
use telio_crypto::PublicKey;
use telio_crypto::SecretKey;
use telio_model::mesh::LinkState;
use telio_sockets::{NativeProtector, SocketPool};
use telio_utils::exponential_backoff::{
ExponentialBackoff, ExponentialBackoffBounds, MockBackoff,
};
use telio_utils::ip_stack::IpStack;
use telio_wg::{
Error as wgError, WireGuard,
MockWireGuard,
uapi::{Interface, Peer},
};
use tokio::sync::Mutex as TMutex;

type Result<T> = std::result::Result<T, Error>;
type Result1<T> = std::result::Result<T, wgError>;

mock! {
pub Wg {}
#[async_trait]
impl WireGuard for Wg {
async fn get_interface(&self) -> Result1<Interface,>;
async fn get_adapter_luid(&self) -> Result1<u64>;
async fn wait_for_listen_port(&self, d: Duration) -> Result1<u16>;
async fn get_link_state(&self, key: PublicKey) -> Result1<Option<LinkState>>;
async fn set_secret_key(&self, key: SecretKey) -> Result1<()>;
async fn set_fwmark(&self, fwmark: u32) -> Result1<()>;
async fn add_peer(&self, peer: Peer) -> Result1<()>;
async fn del_peer(&self, key: PublicKey) -> Result1<()>;
async fn drop_connected_sockets(&self) -> Result1<()>;
async fn time_since_last_rx(&self, public_key: PublicKey) -> Result1<Option<Duration>>;
async fn stop(self);
async fn reset_existing_connections(&self, exit_pubkey: PublicKey) -> Result1<()>;
async fn set_ip_stack(&self, ip_stack: Option<IpStack>) -> Result1<()>;
}
}

lazy_static! {
static ref IGD_IS_AVAILABLE: Arc<Mutex<bool>> = Arc::new(Mutex::new(false));
Expand Down Expand Up @@ -921,7 +896,7 @@ mod tests {

pub async fn prepare_test_setup(
is_battery_optimization_on: bool,
) -> UpnpEndpointProvider<MockWg, MockUpnpEpCommands, MockBackoff> {
) -> UpnpEndpointProvider<MockWireGuard, MockUpnpEpCommands, MockBackoff> {
let spool = SocketPool::new(
NativeProtector::new(
#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -953,7 +928,7 @@ mod tests {
epc.udp.set_port(2000);

// These are not properly used yet, just dummy variables
let mut wg = MockWg::default();
let mut wg = MockWireGuard::default();
let wg_port = 55345;
let wg_peers = Vec::<(PublicKey, Peer)>::new();
let backoff_array = [100, 200, 400, 800, 1600, 3200];
Expand Down Expand Up @@ -1107,7 +1082,7 @@ mod tests {
}

// These are not properly used yet, just dummy variables
let mut wg = MockWg::default();
let mut wg = MockWireGuard::default();
let wg_port = 55345;

wg.expect_get_interface().returning(move || {
Expand Down
20 changes: 18 additions & 2 deletions crates/telio-wg/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ pub trait Adapter: Send + Sync {
/// Set the (u)tun file descriptor to be used by the adapter
async fn set_tun(&self, tun: Tun) -> Result<(), Error>;

/// Set the MTU of the adapter interface, `None` restores the adapter's own handling
async fn set_adapter_mtu(&self, _mtu: Option<u32>) -> Result<(), Error> {
Err(Error::UnsupportedAdapter)
}

/// Make a copy of this adapter.
///
/// Only the custom adapters can be cloned this way.
Expand All @@ -107,6 +112,9 @@ pub trait Adapter: Send + Sync {
}
}

/// IPv6 minimum link MTU, the interface MTU applies to both address families
pub const MIN_MTU: u32 = 1280;

/// Enumeration of `Error` types for `Adapter` struct
#[derive(Debug, TError)]
pub enum Error {
Expand All @@ -131,6 +139,10 @@ pub enum Error {
#[error("Unsupported adapter")]
UnsupportedAdapter,

/// MTU below the minimum any adapter accepts
#[error("MTU must be at least {min}, got {0}", min = MIN_MTU)]
MtuTooLow(u32),

/// Unsupported on Windows adapter
#[error("Mismatched windows adapter")]
MismatchedWindowsAdapter,
Expand Down Expand Up @@ -299,8 +311,12 @@ pub(crate) async fn start(cfg: Config) -> Result<Box<dyn Adapter>, Error> {

#[cfg(windows)]
Ok(Box::new(
windows_native_wg::WindowsNativeWg::start(&name, cfg.enable_dynamic_wg_nt_control)
.await?,
windows_native_wg::WindowsNativeWg::start(
&name,
cfg.enable_dynamic_wg_nt_control,
cfg.mtu,
)
.await?,
))
}
AdapterType::Custom(adapter) => adapter.clone_box().ok_or(Error::UnsupportedAdapter),
Expand Down
Loading
Loading