Add new dependencies and implement TUN interface initialization

- Updated Cargo.toml to include `etherparse` and enable async feature for `tun-rs`.
- Added `ip_match_network` function in network module for IP matching.
- Implemented TUN interface initialization in `tun.rs`.
- Enhanced client handling in `client.rs` to support new features and improved message handling.
- Refactored router messages to use a structured `VpnPacket`.
- Updated settings for spell checking in VSCode.
This commit is contained in:
2026-02-27 11:30:08 +01:00
parent 0c5b860324
commit fb9d6ca9c8
8 changed files with 241 additions and 20 deletions

View File

@@ -1,6 +1,5 @@
use std::net::IpAddr;
use anyhow::Result;
use chrono::Utc;
use clap::Args;
use ipnet::Ipv4Net;
use serde::{Deserialize, Serialize};
@@ -11,7 +10,21 @@ use tokio::{
time::Instant,
};
use crate::router::{CLIENT_REGISTER_TIMEOUT, CliRegMessages, RouterMessages, SERVER_PACKET_SIZE};
use crate::{
network::ip_match_network,
router::{CLIENT_REGISTER_TIMEOUT, CliRegMessages, RouterMessages, SERVER_PACKET_SIZE},
tun::inti_tun_interface,
};
pub struct ClientStaTistic {
pub last_keep_alive: Option<chrono::DateTime<Utc>>,
pub keep_alive_count: usize,
pub total_data_received: usize,
pub total_data_sent: usize,
pub last_data_received: Option<chrono::DateTime<Utc>>,
pub last_data_sent: Option<chrono::DateTime<Utc>>,
pub latency_ms: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Args)]
pub struct ClientCfg {
@@ -19,9 +32,9 @@ pub struct ClientCfg {
#[arg(long, short)]
pub server: String,
/// The local interface IP address (example: 10.8.0.2).
/// The local interface IP address (example: 10.8.0.2/32).
#[arg(long = "interface-ip")]
pub interface_ip: IpAddr,
pub interface_ip: Ipv4Net,
/// The local interface name.
#[arg(long = "interface-name", default_value = "xvpn0")]
@@ -31,6 +44,10 @@ pub struct ClientCfg {
/// Example: --local-route 1.1.1.1/32,10.0.0.0/24
#[arg(long = "local-route", visible_alias = "lr", value_delimiter = ',')]
pub local_routes: Vec<Ipv4Net>,
/// MTU for the TUN interface.
/// If not specified, the default MTU of the system will be used.
#[arg(long = "mtu", default_value = "1400")]
pub mtu: u16,
}
pub async fn start(config: ClientCfg) -> Result<()> {
@@ -41,27 +58,51 @@ pub async fn start(config: ClientCfg) -> Result<()> {
let (mut rx, mut tx) = stream.into_split();
// let client_stream = ClientStream::new(tx);
let mut buf = vec![0u8; SERVER_PACKET_SIZE];
register_client(&mut rx, &mut tx, config, &mut buf).await?;
let mut vpn_buf = vec![0u8; SERVER_PACKET_SIZE];
let mut tun_buf = vec![0u8; config.mtu as usize];
register_client(&mut rx, &mut tx, &config, &mut vpn_buf).await?;
let tun_device = inti_tun_interface(&config).await?;
println!("Client registration successful. Entering main loop to receive messages from router...");
loop {
tokio::select! {
msg = rx.read(&mut buf) => {
msg = rx.read(&mut vpn_buf) => {
match msg {
Ok(0) => {
println!("Connection to router closed by peer.");
return Ok(());
}
Ok(n) => {
println!("Received {} bytes from router: {:?}", n, RouterMessages::from_slice(&buf[..n]));
match RouterMessages::from_slice(&vpn_buf[..n]){
RouterMessages::KeepAlive(timestamp) => {
println!("Received keep-alive message from router with timestamp: {}, delta {} ms", timestamp, (Utc::now().timestamp_micros() - timestamp).abs() as f64 / 1000.0);
}
_ => println!("Received message from router: {:?}", RouterMessages::from_slice(&vpn_buf[..n]))
};
}
Err(e) => {
eprintln!("Error reading from router: {}", e);
return Err(anyhow::anyhow!(format!("Error reading from router: {}", e)));
}
}
}
}
data = tun_device.recv(&mut tun_buf) => {
match data {
Ok(n) => {
let packet = etherparse::Ipv4HeaderSlice::from_slice(&tun_buf[..n])?;
let src = packet.source_addr();
match ip_match_network(src, &config.local_routes).await {
Some(net) => println!("Source IP {} matches local route {}", src, net),
None => {},
}
}
Err(e) => {
eprintln!("Error reading from TUN interface: {}", e);
return Err(anyhow::anyhow!(format!("Error reading from TUN interface: {}", e)));
}
}
}
}
}
@@ -71,10 +112,10 @@ pub async fn start(config: ClientCfg) -> Result<()> {
pub async fn register_client(
rx: &mut OwnedReadHalf,
tx: &mut OwnedWriteHalf,
config: ClientCfg,
config: &ClientCfg,
buf: &mut [u8],
) -> Result<()> {
let register_msg = RouterMessages::CliReg(CliRegMessages::Reg(config));
let register_msg = RouterMessages::CliReg(CliRegMessages::Reg(config.clone()));
let mut client_registration_timeout =
tokio::time::interval_at(Instant::now() + CLIENT_REGISTER_TIMEOUT, CLIENT_REGISTER_TIMEOUT);
tx.write_all(&register_msg.to_bytes()).await?;