Skip to content

Commit

Permalink
refactor: leverage DNS and gateway configuration from rust-tun
Browse files Browse the repository at this point in the history
  • Loading branch information
M0dEx committed Sep 4, 2024
1 parent 0fcfa80 commit 02ac000
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 54 deletions.
35 changes: 14 additions & 21 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()?;

Check warning on line 72 in src/client.rs

View check run for this annotation

Codecov / codecov/patch

src/client.rs#L72

Added line #L72 was not covered by tests
}

Expand Down
5 changes: 0 additions & 5 deletions src/network/dns/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
10 changes: 0 additions & 10 deletions src/network/dns/windows.rs

This file was deleted.

59 changes: 45 additions & 14 deletions src/network/interface.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -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<Self>;
fn create_server(interface_address: IpNet, mtu: u16) -> Result<Self>;

fn mtu(&self) -> Result<u16>;
fn create_client(
interface_address: IpNet,
tunnel_gateway: IpAddr,
mtu: u16,
routes: &[IpNet],
dns_servers: &[IpAddr],
) -> Result<Self>;

fn name(&self) -> Result<String>;

Expand All @@ -53,33 +61,56 @@ impl<I: Interface> InterfaceWrite for WriteHalf<I> {}
impl InterfaceRead for AsyncDevice {}
impl InterfaceWrite for AsyncDevice {}
impl Interface for AsyncDevice {
fn create(interface_address: IpNet, mtu: u16) -> Result<AsyncDevice> {
fn create_server(interface_address: IpNet, mtu: u16) -> Result<Self> {

Check warning on line 64 in src/network/interface.rs

View check run for this annotation

Codecov / codecov/patch

src/network/interface.rs#L64

Added line #L64 was not covered by tests
let mut config = Configuration::default();

config
.address(interface_address.addr())
.netmask(interface_address.netmask())
.destination(interface_address.network())

Check warning on line 70 in src/network/interface.rs

View check run for this annotation

Codecov / codecov/patch

src/network/interface.rs#L70

Added line #L70 was not covered by tests
.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)?;

Check warning on line 74 in src/network/interface.rs

View check run for this annotation

Codecov / codecov/patch

src/network/interface.rs#L74

Added line #L74 was not covered by tests

Ok(interface)
}

Check warning on line 77 in src/network/interface.rs

View check run for this annotation

Codecov / codecov/patch

src/network/interface.rs#L76-L77

Added lines #L76 - L77 were not covered by tests

fn mtu(&self) -> Result<u16> {
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<Self> {
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);
});

Check warning on line 98 in src/network/interface.rs

View check run for this annotation

Codecov / codecov/patch

src/network/interface.rs#L79-L98

Added lines #L79 - L98 were not covered by tests

let interface = tun2::create_as_async(&config)?;

add_routes(routes, &interface_address.addr())?;

Check warning on line 102 in src/network/interface.rs

View check run for this annotation

Codecov / codecov/patch

src/network/interface.rs#L102

Added line #L102 was not covered by tests

#[cfg(not(target_os = "windows"))]
{
use crate::network::dns::add_dns_servers;
add_dns_servers(dns_servers, &interface.tun_name()?)?;

Check warning on line 107 in src/network/interface.rs

View check run for this annotation

Codecov / codecov/patch

src/network/interface.rs#L107

Added line #L107 was not covered by tests
}

Ok(interface)
}

fn name(&self) -> Result<String> {
self.as_ref()
.tun_name()
.context("failed to retrieve interface name")
self.tun_name().context("failed to retrieve interface name")
}

Check warning on line 115 in src/network/interface.rs

View check run for this annotation

Codecov / codecov/patch

src/network/interface.rs#L113-L115

Added lines #L113 - L115 were not covered by tests
}
2 changes: 1 addition & 1 deletion src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl QuincyServer {

/// Starts the tasks for this instance of Quincy tunnel and listens for incoming connections.
pub async fn run<I: Interface>(&self) -> Result<()> {
let interface = I::create(
let interface = I::create_server(
self.config.tunnel_network.into(),
self.config.connection.mtu,
)?;
Expand Down
15 changes: 12 additions & 3 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Self> {
fn create_server(_interface_address: IpNet, _mtu: u16) -> Result<Self> {
Ok(Self::new(
$test_queue_send.0.clone(),
$test_queue_recv.1.clone(),
))
}

fn mtu(&self) -> Result<u16> {
Ok(1400)
fn create_client(
_interface_address: IpNet,
_tunnel_gateway: IpAddr,
_mtu: u16,
_routes: &[IpNet],
_dns_servers: &[IpAddr],
) -> Result<Self> {
Ok(Self::new(
$test_queue_send.0.clone(),
$test_queue_recv.1.clone(),
))
}

fn name(&self) -> Result<String> {
Expand Down
1 change: 1 addition & 0 deletions tests/test_client_communication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use quincy::{
server::QuincyServer,
};
use rstest::rstest;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::sync::LazyLock;

Expand Down
1 change: 1 addition & 0 deletions tests/test_client_isolation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions tests/test_end_to_end.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions tests/test_failed_auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 02ac000

Please sign in to comment.