From 02ac00096aa5728160b0df9a209aa6889d4f53ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kub=C3=ADk?= Date: Wed, 4 Sep 2024 22:39:45 +0200 Subject: [PATCH] refactor: leverage DNS and gateway configuration from rust-tun --- src/client.rs | 35 +++++++----------- src/network/dns/mod.rs | 5 --- src/network/dns/windows.rs | 10 ----- src/network/interface.rs | 59 +++++++++++++++++++++++------- src/server/mod.rs | 2 +- tests/common/mod.rs | 15 ++++++-- tests/test_client_communication.rs | 1 + tests/test_client_isolation.rs | 1 + tests/test_end_to_end.rs | 1 + tests/test_failed_auth.rs | 1 + 10 files changed, 76 insertions(+), 54 deletions(-) delete mode 100644 src/network/dns/windows.rs diff --git a/src/client.rs b/src/client.rs index 74b55f3..4c7112e 100644 --- a/src/client.rs +++ b/src/client.rs @@ -10,10 +10,8 @@ use quinn::{Connection, Endpoint, VarInt}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}; -use crate::network::dns::{add_dns_servers, delete_dns_servers}; use crate::network::interface::{Interface, InterfaceRead, InterfaceWrite}; use crate::network::packet::Packet; -use crate::network::route::add_routes; use futures::stream::FuturesUnordered; use futures::StreamExt; use std::sync::Arc; @@ -48,34 +46,29 @@ impl QuincyClient { info!("Received client address: {client_address}"); info!("Received server address: {server_address}"); + let routes = &self.config.network.routes; + let dns_servers = &self.config.network.dns_servers; let mtu = self.config.connection.mtu; - let interface = I::create(client_address, mtu)?; + let interface = I::create_client( + client_address, + server_address.addr(), + mtu, + routes, + dns_servers, + )?; let interface_name = interface.name()?; info!("Created interface: {interface_name}"); - - let routes = &self.config.network.routes; - let dns_servers = &self.config.network.dns_servers; - - if !routes.is_empty() { - add_routes(routes, &server_address.addr())?; - for route in routes { - info!("Added route: {route}"); - } - } - - if !dns_servers.is_empty() { - add_dns_servers(dns_servers, &interface_name)?; - for dns_server in dns_servers { - info!("Added DNS server: {dns_server}"); - } - } + info!("Added routes: {routes:?}"); + info!("Set DNS servers: {dns_servers:?}"); let relay_result = self .relay_packets(connection, interface, mtu as usize) .await; - if !dns_servers.is_empty() { + #[cfg(not(target_os = "windows"))] + { + use crate::network::dns::delete_dns_servers; delete_dns_servers()?; } diff --git a/src/network/dns/mod.rs b/src/network/dns/mod.rs index 133d16c..39108c7 100644 --- a/src/network/dns/mod.rs +++ b/src/network/dns/mod.rs @@ -7,8 +7,3 @@ pub use darwin::{add_dns_servers, delete_dns_servers}; mod linux; #[cfg(any(target_os = "linux", target_os = "freebsd"))] pub use linux::{add_dns_servers, delete_dns_servers}; - -#[cfg(target_os = "windows")] -mod windows; -#[cfg(target_os = "windows")] -pub use windows::{add_dns_servers, delete_dns_servers}; diff --git a/src/network/dns/windows.rs b/src/network/dns/windows.rs deleted file mode 100644 index 9a328dd..0000000 --- a/src/network/dns/windows.rs +++ /dev/null @@ -1,10 +0,0 @@ -use anyhow::Result; -use std::net::IpAddr; - -pub fn add_dns_servers(_dns_servers: &[IpAddr], _interface_name: &str) -> Result<()> { - unimplemented!() -} - -pub fn delete_dns_servers() -> Result<()> { - unimplemented!() -} diff --git a/src/network/interface.rs b/src/network/interface.rs index 1f48e43..768771e 100644 --- a/src/network/interface.rs +++ b/src/network/interface.rs @@ -1,9 +1,11 @@ #![allow(async_fn_in_trait)] use crate::network::packet::Packet; +use crate::network::route::add_routes; use anyhow::{Context, Result}; use bytes::BytesMut; use ipnet::IpNet; +use std::net::IpAddr; use tokio::io::{AsyncReadExt, AsyncWriteExt, ReadHalf, WriteHalf}; use tun2::{AbstractDevice, AsyncDevice, Configuration}; @@ -37,9 +39,15 @@ pub trait InterfaceWrite: AsyncWriteExt + Sized + Unpin + Send + 'static { } pub trait Interface: InterfaceRead + InterfaceWrite { - fn create(interface_address: IpNet, mtu: u16) -> Result; + fn create_server(interface_address: IpNet, mtu: u16) -> Result; - fn mtu(&self) -> Result; + fn create_client( + interface_address: IpNet, + tunnel_gateway: IpAddr, + mtu: u16, + routes: &[IpNet], + dns_servers: &[IpAddr], + ) -> Result; fn name(&self) -> Result; @@ -53,33 +61,56 @@ impl InterfaceWrite for WriteHalf {} impl InterfaceRead for AsyncDevice {} impl InterfaceWrite for AsyncDevice {} impl Interface for AsyncDevice { - fn create(interface_address: IpNet, mtu: u16) -> Result { + fn create_server(interface_address: IpNet, mtu: u16) -> Result { let mut config = Configuration::default(); config .address(interface_address.addr()) .netmask(interface_address.netmask()) + .destination(interface_address.network()) .mtu(mtu) .up(); - // Needed due to rust-tun using the destination address as the default GW - #[cfg(not(target_os = "windows"))] - config.destination(interface_address.network()); - let interface = tun2::create_as_async(&config)?; Ok(interface) } - fn mtu(&self) -> Result { - self.as_ref() - .mtu() - .context("failed to retrieve interface MTU") + fn create_client( + interface_address: IpNet, + tunnel_gateway: IpAddr, + mtu: u16, + routes: &[IpNet], + dns_servers: &[IpAddr], + ) -> Result { + let mut config = Configuration::default(); + + config + .address(interface_address.addr()) + .netmask(interface_address.netmask()) + .destination(tunnel_gateway) + .mtu(mtu) + .up(); + + #[cfg(target_os = "windows")] + config.platform_config(|platform| { + platform.dns_servers(dns_servers); + }); + + let interface = tun2::create_as_async(&config)?; + + add_routes(routes, &interface_address.addr())?; + + #[cfg(not(target_os = "windows"))] + { + use crate::network::dns::add_dns_servers; + add_dns_servers(dns_servers, &interface.tun_name()?)?; + } + + Ok(interface) } fn name(&self) -> Result { - self.as_ref() - .tun_name() - .context("failed to retrieve interface name") + self.tun_name().context("failed to retrieve interface name") } } diff --git a/src/server/mod.rs b/src/server/mod.rs index cb4f575..21fc80f 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -50,7 +50,7 @@ impl QuincyServer { /// Starts the tasks for this instance of Quincy tunnel and listens for incoming connections. pub async fn run(&self) -> Result<()> { - let interface = I::create( + let interface = I::create_server( self.config.tunnel_network.into(), self.config.connection.mtu, )?; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index f502898..5dcd354 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -104,15 +104,24 @@ pub const fn make_queue_pair() -> LazyLock<(TestSender, TestReceiver)> { macro_rules! interface_impl { ($name:ident, $test_queue_send:ident, $test_queue_recv:ident) => { impl Interface for $name { - fn create(_interface_address: IpNet, _mtu: u16) -> Result { + fn create_server(_interface_address: IpNet, _mtu: u16) -> Result { Ok(Self::new( $test_queue_send.0.clone(), $test_queue_recv.1.clone(), )) } - fn mtu(&self) -> Result { - Ok(1400) + fn create_client( + _interface_address: IpNet, + _tunnel_gateway: IpAddr, + _mtu: u16, + _routes: &[IpNet], + _dns_servers: &[IpAddr], + ) -> Result { + Ok(Self::new( + $test_queue_send.0.clone(), + $test_queue_recv.1.clone(), + )) } fn name(&self) -> Result { diff --git a/tests/test_client_communication.rs b/tests/test_client_communication.rs index a66b516..c5994b4 100644 --- a/tests/test_client_communication.rs +++ b/tests/test_client_communication.rs @@ -11,6 +11,7 @@ use quincy::{ server::QuincyServer, }; use rstest::rstest; +use std::net::IpAddr; use std::net::Ipv4Addr; use std::sync::LazyLock; diff --git a/tests/test_client_isolation.rs b/tests/test_client_isolation.rs index 700b22b..cd7a4a1 100644 --- a/tests/test_client_isolation.rs +++ b/tests/test_client_isolation.rs @@ -11,6 +11,7 @@ use quincy::{ server::QuincyServer, }; use rstest::rstest; +use std::net::IpAddr; use std::sync::LazyLock; use std::{net::Ipv4Addr, time::Duration}; use tokio::time::timeout; diff --git a/tests/test_end_to_end.rs b/tests/test_end_to_end.rs index 59c1a00..7d151f3 100644 --- a/tests/test_end_to_end.rs +++ b/tests/test_end_to_end.rs @@ -9,6 +9,7 @@ use quincy::config::{ClientConfig, ServerConfig}; use quincy::network::interface::Interface; use quincy::server::QuincyServer; use rstest::rstest; +use std::net::IpAddr; use std::net::Ipv4Addr; use std::sync::LazyLock; diff --git a/tests/test_failed_auth.rs b/tests/test_failed_auth.rs index 4cb384b..711b77f 100644 --- a/tests/test_failed_auth.rs +++ b/tests/test_failed_auth.rs @@ -9,6 +9,7 @@ use quincy::config::{ClientConfig, ServerConfig}; use quincy::network::interface::Interface; use quincy::server::QuincyServer; use rstest::rstest; +use std::net::IpAddr; use std::net::Ipv4Addr; use std::sync::LazyLock; use std::time::Duration;