close to finish a tun/smoltcp

This commit is contained in:
2026-03-07 20:17:49 +07:00
parent 4a789dd128
commit b1cc4c14f4
14 changed files with 912 additions and 279 deletions
+35
View File
@@ -0,0 +1,35 @@
use hickory_proto::op::{Message, MessageType, ResponseCode};
use hickory_proto::rr::{RData, Record};
use crate::connections::ip_store::FakeIpStore;
pub fn handle_dns_query(data: &[u8], store: &mut FakeIpStore) -> Option<Vec<u8>> {
// 1. Парсим входящий запрос
let request = Message::from_vec(data).ok()?;
// 2. Берем первый вопрос (обычно запрос только один)
let query = request.queries().first()?;
let name = query.name().to_string().trim_end_matches('.').to_string();
// 3. Получаем Fake IP
let fake_ip = store.get_or_assign(&name);
// 4. Формируем ответ
let mut response = Message::new();
response
.set_id(request.id())
.set_message_type(MessageType::Response)
.set_response_code(ResponseCode::NoError)
.add_query(query.clone());
// Создаем запись A (IPv4)
let record = Record::from_rdata(
query.name().clone(),
1, // TTL = 1 сек
RData::A(fake_ip.into()),
);
response.add_answer(record);
// 5. Сериализуем обратно в байты
response.to_vec().ok()
}
+36
View File
@@ -0,0 +1,36 @@
use lru::LruCache;
use std::net::Ipv4Addr;
use std::num::NonZeroUsize;
pub struct FakeIpStore {
cache: LruCache<String, Ipv4Addr>,
pub rev_cache: LruCache<Ipv4Addr, String>,
next_ip: u32,
}
const START_IP: u32 = 0x64400001; // 100.64.0.1 (IP for Service Networks/Shared Address Space)
impl FakeIpStore {
pub fn new() -> Self {
Self {
cache: LruCache::new(NonZeroUsize::new(2000).unwrap()),
rev_cache: LruCache::new(NonZeroUsize::new(2000).unwrap()),
next_ip: START_IP,
}
}
pub fn get_or_assign(&mut self, host: &str) -> Ipv4Addr {
if let Some(&ip) = self.cache.get(host) {
return ip;
}
let ip = Ipv4Addr::from(self.next_ip);
self.next_ip += 1;
self.cache.put(host.to_string(), ip);
self.rev_cache.put(ip, host.to_string());
ip
}
pub fn lookup_by_ip(&self, ip: &Ipv4Addr) -> Option<String> {
self.rev_cache.peek(ip).cloned()
}
}
+3
View File
@@ -1 +1,4 @@
pub mod dns;
pub mod ip_store;
pub mod tcp_connection;
pub mod udp_connection;
+98 -30
View File
@@ -1,18 +1,15 @@
use netrunner_common::protocol::codec::socks::SocksRequest;
use netrunner_common::protocol::codec::socks::{SocksRequest, TargetAddress};
use smoltcp::iface::SocketHandle;
use smoltcp::socket::tcp;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream; // Твой код парсера
use tokio::sync::mpsc;
use tracing::{debug, info, trace};
pub enum ConnectionState {
/// Сокет только что принял соединение (SYN-ACK завершен)
Established,
/// Мы в процессе SOCKS5 рукопожатия с локальным прокси
Handshaking,
/// Соединение готово к передаче данных (Bridge)
Active,
/// Ошибка или закрытие
Closed,
}
@@ -21,33 +18,46 @@ pub struct TcpConnection {
state: ConnectionState,
tx: mpsc::UnboundedSender<Vec<u8>>,
rx: mpsc::UnboundedReceiver<Vec<u8>>,
pending_data: Option<Vec<u8>>,
}
impl TcpConnection {
pub fn new(
handle: SocketHandle,
proxy_addr: String,
target_addr: std::net::SocketAddr,
) -> Self {
pub fn new(handle: SocketHandle, proxy_addr: String, target_addr: TargetAddress) -> Self {
let (tx_to_proxy, mut rx_from_smol) = mpsc::unbounded_channel::<Vec<u8>>();
let (tx_to_smol, rx_from_proxy) = mpsc::unbounded_channel::<Vec<u8>>();
// Запускаем асинхронную логику в фоне
let proxy_addr_clone = proxy_addr.clone();
let target_addr_clone = target_addr.clone();
tokio::spawn(async move {
// 1. Подключаемся
debug!(
%handle,
target = ?target_addr_clone,
proxy = %proxy_addr_clone,
"Attempting to connect through proxy"
);
let mut stream = match TcpStream::connect(&proxy_addr).await {
Ok(s) => s,
Err(_) => return, // Тут можно добавить логирование
Ok(s) => {
debug!(%handle, "Connected to proxy successfully");
s
}
Err(e) => {
debug!(%handle, error = %e, "Failed to connect to proxy");
return;
} // Тут можно добавить логирование
};
// 2. SOCKS Handshake
if SocksRequest::perform_client_handshake(&mut stream, &target_addr)
.await
.is_err()
if let Err(e) =
SocksRequest::perform_client_handshake(&mut stream, &target_addr_clone).await
{
debug!(%handle, error = %e, "SOCKS handshake failed");
return;
}
debug!(%handle, "SOCKS handshake successful, starting data bridge");
// 3. Копирование данных (Bridge)
let (mut reader, mut writer) = stream.into_split();
@@ -83,29 +93,87 @@ impl TcpConnection {
Self {
handle,
state: ConnectionState::Active, // Сразу переходим в Active, т.к. задача пошла
state: ConnectionState::Handshaking, // Сразу переходим в Active, т.к. задача пошла
tx: tx_to_proxy,
rx: rx_from_proxy,
pending_data: None,
}
}
pub fn poll_and_process(&mut self, socket: &mut tcp::Socket) {
// 1. Из smoltcp -> В канал задачи
pub fn tick(&mut self, socket: &mut tcp::Socket) -> bool {
trace!(handle=%self.handle, state=?socket.state(), "Tick");
match self.state {
ConnectionState::Handshaking => {
info!("Connection handshaking");
return true;
}
ConnectionState::Active => {
self.poll_and_process(socket);
// Проверяем условия закрытия
if self.is_finished(socket) {
self.state = ConnectionState::Closed;
socket.abort(); // Принудительно разрываем стек
return false; // Сигнализируем, что соединение мертво
}
}
ConnectionState::Closed => return false,
_ => {}
}
true
}
pub fn is_finished(&self, socket: &tcp::Socket) -> bool {
use tcp::State;
let socket_closed = matches!(
socket.state(),
State::Closed | State::TimeWait | State::FinWait1 | State::FinWait2
);
let task_finished = self.rx.is_closed();
socket_closed || task_finished
}
pub fn is_active(&self) -> bool {
matches!(self.state, ConnectionState::Active)
}
fn poll_and_process(&mut self, socket: &mut tcp::Socket) {
if let Some(data) = self.pending_data.take() {
if socket.send_slice(&data).is_ok() {
} else {
self.pending_data = Some(data);
return;
}
}
if socket.can_recv() {
let mut buf = [0u8; 4096];
if let Ok(n) = socket.recv_slice(&mut buf) {
if n > 0 {
let _ = self.tx.send(buf[..n].to_vec());
let _ = socket.recv(|data| {
let len = data.len();
if len > 0 {
let _ = self.tx.send(data.to_vec());
}
(len, ())
});
}
if socket.can_send() {
while let Ok(data) = self.rx.try_recv() {
match socket.send_slice(&data) {
Ok(_) => { /* Успешно */ }
Err(_) => {
// Стек полон, запоминаем данные для следующего вызова
self.pending_data = Some(data);
break;
}
}
}
}
// 2. Из канала задачи -> В smoltcp
if socket.can_send() {
// try_recv не блокирует поток, что нам и нужно
if let Ok(data) = self.rx.try_recv() {
let _ = socket.send_slice(&data);
}
if socket.state() == tcp::State::CloseWait {
debug!(handle=%self.handle, "!!! Triggering socket.close() for CLOSE-WAIT");
socket.close();
}
}
}
+33
View File
@@ -0,0 +1,33 @@
use crate::connections::dns::handle_dns_query;
use crate::connections::ip_store::FakeIpStore;
use smoltcp::socket::udp;
pub struct UdpConnection;
impl UdpConnection {
pub fn process_incoming(socket: &mut udp::Socket, store: &mut FakeIpStore) {
// Мы используем peek или recv, чтобы понять, куда идти дальше
while socket.can_recv() {
let (data, metadata) = match socket.recv() {
Ok(res) => res,
Err(_) => break,
};
// Диспетчер: определяем тип трафика по порту
match metadata.endpoint.port {
53 => {
// Это DNS
if let Some(response) = handle_dns_query(&data, store) {
let _ = socket.send_slice(&response, metadata);
}
}
// Тут в будущем можно добавить обработку других протоколов
// 443 => process_quic(...),
_ => {
// Можно логировать неизвестный трафик или просто дропать
// trace!("Received UDP on unknown port: {}", endpoint.port);
}
}
}
}
}
+7 -5
View File
@@ -1,3 +1,5 @@
use std::net::Ipv4Addr;
use netrunner_client::{tun::engine::Engine, tun::tun::Tun};
use netrunner_common::{
logger_init,
@@ -21,8 +23,7 @@ async fn main() {
})
.expect("Failed to initialize TUN device");
tun_device.clear_default_route();
tun_device.setup_linux_routes();
tun_device.setup_routing();
info!("TUN interface is UP: 10.0.0.1/24");
@@ -35,7 +36,7 @@ async fn main() {
let network = Network::new(8080, ConnectionRole::Client, Some(remote_address));
let socks_addr = network.get_self_local_address();
let proxy_ip = network.get_self_local_address();
// 2. ВЫНОСИМ СЕТЬ В ОТДЕЛЬНЫЙ ЦИКЛ
// Это запустит SOCKS5 сервер и TLS туннель параллельно движку
@@ -44,10 +45,11 @@ async fn main() {
network.run().await;
});
let mut engine = Engine::new(config, caps, socks_addr);
let mut engine = Engine::new(config, caps, proxy_ip);
engine.set_any_ip(true);
engine.set_transparent_mode();
engine.set_default_gateway(Ipv4Addr::new(10, 0, 0, 2)); // to smoltcp
engine.activate();
info!("Stack IP initialized: 10.0.0.2");
// 5. Запуск
+102 -142
View File
@@ -1,19 +1,26 @@
use netrunner_common::protocol::codec::socks::TargetAddress;
use smoltcp::{
iface::{SocketHandle, SocketSet},
socket::{AnySocket, icmp, tcp, udp},
wire::IpListenEndpoint,
wire::{IpAddress, IpListenEndpoint},
};
use std::{
collections::HashMap,
time::{Duration, Instant as StdInstant},
};
use tracing::{debug, info};
use tracing::{debug, info, warn};
use crate::{connections::tcp_connection::TcpConnection, tun::engine::START_TIME};
use crate::{
connections::{
ip_store::FakeIpStore, tcp_connection::TcpConnection, udp_connection::UdpConnection,
},
tun::engine::START_TIME,
};
pub struct ConnectionManager {
last_activity: HashMap<SocketHandle, StdInstant>,
active_tcp_sessions: HashMap<SocketHandle, TcpConnection>,
//active_udp_sessions: HashMap<SocketHandle, UdpSession>,
fake_ip_store: FakeIpStore,
proxy_ip: String,
}
@@ -23,79 +30,113 @@ impl ConnectionManager {
last_activity: HashMap::new(),
active_tcp_sessions: HashMap::new(),
proxy_ip: ip,
fake_ip_store: FakeIpStore::new(),
}
}
/// Основной метод, который вызывается в цикле Engine
pub fn start_listening(&mut self, socket_set: &mut SocketSet) {
for (_, socket) in socket_set.iter_mut() {
if let Some(tcp) = tcp::Socket::downcast_mut(socket) {
if !tcp.is_open() {
let endpoint = IpListenEndpoint {
addr: None,
port: 443,
};
match tcp.listen(endpoint) {
Ok(_) => debug!("Socket is now listening"),
Err(e) => warn!(error=?e, "Failed to listen on socket"),
}
}
}
}
}
fn resolve_target(&self, socket: &tcp::Socket) -> TargetAddress {
// Безопасно получаем эндпоинт
let remote_endpoint = match socket.remote_endpoint() {
Some(ep) => ep,
None => {
warn!(handle=?socket, "Attempted to resolve target for an unconnected socket");
// Возвращаем дефолт, чтобы не падать
return TargetAddress::Domain("disconnected".to_string(), 0);
}
};
let port = remote_endpoint.port;
let ip = remote_endpoint.addr;
match ip {
smoltcp::wire::IpAddress::Ipv4(ipv4_addr) => {
let std_ip = std::net::Ipv4Addr::from(ipv4_addr);
// Ищем домен в нашем FakeIpStore
if let Some(domain) = self.fake_ip_store.lookup_by_ip(&std_ip) {
debug!(target=%domain, port=%port, "Resolved fake IP to domain");
return TargetAddress::Domain(domain, port);
}
debug!(ip=%std_ip, port=%port, "Using raw IP target");
TargetAddress::Ipv4(std_ip, port)
}
smoltcp::wire::IpAddress::Ipv6(ipv6_addr) => {
let std_ip = std::net::Ipv6Addr::from(ipv6_addr);
debug!(ip=%std_ip, port=%port, "Using IPv6 target");
TargetAddress::Ipv6(std_ip, port)
}
}
}
pub fn process_sockets(&mut self, socket_set: &mut SocketSet) {
for (handle, socket) in socket_set.iter_mut() {
// 1. Пытаемся даункастить сокет до TCP
if let Some(tcp) = tcp::Socket::downcast_mut(socket) {
self.handle_tcp(handle, tcp);
continue;
}
// 2. До UDP
if let Some(udp) = udp::Socket::downcast_mut(socket) {
} else if let Some(udp) = udp::Socket::downcast_mut(socket) {
self.handle_udp(handle, udp);
continue;
}
// 3. До ICMP
if let Some(icmp) = icmp::Socket::downcast_mut(socket) {
} else if let Some(icmp) = icmp::Socket::downcast_mut(socket) {
self.handle_icmp(handle, icmp);
continue;
}
}
}
fn handle_tcp(&mut self, handle: SocketHandle, socket: &mut tcp::Socket) {
if socket.state() == tcp::State::Established {
let proxy_ip = self.proxy_ip.clone(); // Берем из конфига менеджера
let target = self.resolve_target(socket);
debug!(
handle=%handle,
local=?socket.local_endpoint(),
remote=?socket.remote_endpoint(),
"Socket details"
);
let conn = self.active_tcp_sessions.entry(handle).or_insert_with(|| {
// 1. Получаем endpoint и безопасно распаковываем его
let endpoint = socket
.remote_endpoint()
.expect("TCP socket in Established state must have a remote endpoint");
let mut conn = TcpConnection::new(handle, self.proxy_ip.clone(), target);
// 2. Конвертируем smoltcp::wire::IpAddress в std::net::IpAddr
let ip: std::net::IpAddr = match endpoint.addr {
smoltcp::wire::IpAddress::Ipv4(v4) => std::net::IpAddr::V4(v4.into()),
smoltcp::wire::IpAddress::Ipv6(v6) => std::net::IpAddr::V6(v6.into()),
};
conn.tick(socket);
// 3. Собираем финальный SocketAddr
let target_addr = std::net::SocketAddr::new(ip, endpoint.port);
info!(handle=%handle, target=%target_addr, "Creating new TcpConnection bridge");
TcpConnection::new(handle, proxy_ip, target_addr)
});
conn.poll_and_process(socket);
if conn.is_active() {
self.active_tcp_sessions.insert(handle, conn);
} else {
socket.abort();
}
}
if socket.state() == tcp::State::Closed {
self.active_tcp_sessions.remove(&handle);
if let Some(conn) = self.active_tcp_sessions.get_mut(&handle) {
if !conn.tick(socket) {
self.active_tcp_sessions.remove(&handle);
}
}
}
fn handle_udp(&mut self, handle: SocketHandle, socket: &mut udp::Socket) {
if socket.can_recv() {
match socket.recv() {
Ok((data, endpoint)) => {
info!(handle=%handle, from=?endpoint, len=data.len(), "UDP: packet received");
// МОК: Обработка UDP датаграммы
}
Err(_) => {}
}
}
self.last_activity.insert(handle, StdInstant::now());
UdpConnection::process_incoming(socket, &mut self.fake_ip_store);
}
fn handle_icmp(&mut self, handle: SocketHandle, socket: &mut icmp::Socket) {
if socket.can_recv() {
match socket.recv() {
Ok((data, endpoint)) => {
debug!(handle=%handle, from=?endpoint, "ICMP: packet received");
// МОК: Ответ на пинг или обработка ошибок
debug!(handle=%handle, from=?endpoint, data=?data, "ICMP: packet received");
}
Err(_) => {}
}
@@ -126,106 +167,25 @@ impl ConnectionManager {
icmp::Socket::new(icmp_rx_buffer, icmp_tx_buffer)
}
pub fn refill_sockets(&mut self, socket_set: &mut SocketSet) {
self.prune_sockets(socket_set);
const TARGET_FREE_TCP: usize = 16;
const TARGET_FREE_UDP: usize = 8;
pub fn setup_sockets(n_tcp: usize, n_udp: usize, n_icmp: usize) -> SocketSet<'static> {
// Создаем хранилище с запасом на все типы сокетов
let mut sockets = SocketSet::new(Vec::with_capacity(n_tcp + n_udp + n_icmp));
for &port in &[80, 443, 8080] {
let current_port_sockets = socket_set
.iter()
.filter(|(_, s)| {
if let Some(tcp) = tcp::Socket::downcast(s) {
// Если эндпоинт есть - сверяем порт
if let Some(endpoint) = tcp.local_endpoint() {
return endpoint.port == port;
}
// КЛЮЧЕВОЙ МОМЕНТ:
// Если эндпоинта НЕТ, но сокет НЕ в состоянии CLOSED,
// или он только что был создан для прослушивания.
// В smoltcp после listen() сокет переходит в LISTEN,
// но local_endpoint может появиться чуть позже.
tcp.state() == tcp::State::Listen
} else {
false
}
})
.count();
if current_port_sockets < 5 {
let mut s = Self::create_tcp_socket();
let endpoint = IpListenEndpoint { addr: None, port };
// Попробуй сначала listen, а потом добавлять
if s.listen(endpoint).is_ok() {
socket_set.add(s);
info!(
"--- REAL ADD --- Port: {}, Sockets for this port: {}",
port,
current_port_sockets + 1
);
}
}
// 1. Добавляем TCP сокеты
for _ in 0..n_tcp {
sockets.add(Self::create_tcp_socket());
}
let udp_active = socket_set
.iter()
.filter(|(_, s)| udp::Socket::downcast(s).is_some())
.count();
let has_icmp = socket_set
.iter()
.any(|(_, s)| icmp::Socket::downcast(s).is_some());
if udp_active < TARGET_FREE_UDP {
let diff = TARGET_FREE_UDP - udp_active;
debug!("Refilling UDP pool: adding {} sockets", diff);
for _ in 0..diff {
let s = Self::create_udp_socket();
socket_set.add(s);
}
// 2. Добавляем UDP сокеты
for _ in 0..n_udp {
sockets.add(Self::create_udp_socket());
}
if !has_icmp {
debug!("Adding ICMP socket for echo requests");
let s = Self::create_icmp_socket();
socket_set.add(s);
}
}
fn prune_sockets(&mut self, socket_set: &mut SocketSet) {
let now = StdInstant::now();
let udp_timeout = Duration::from_secs(60); // 1 минута для UDP
let mut to_remove = Vec::new();
for (handle, socket) in socket_set.iter() {
if let Some(tcp) = tcp::Socket::downcast(socket) {
if tcp.state() == tcp::State::Closed {
to_remove.push(handle);
continue;
}
}
if let Some(udp) = udp::Socket::downcast(socket) {
if udp.endpoint().port == 0 {
continue;
}
let last = self.last_activity.get(&handle).unwrap_or(&START_TIME);
if now.duration_since(*last) > udp_timeout {
debug!(handle=%handle, "UDP socket timeout reached");
to_remove.push(handle);
}
}
if let Some(_icmp) = icmp::Socket::downcast(socket) {
continue;
}
// 3. Добавляем ICMP сокет
for _ in 0..n_icmp {
sockets.add(Self::create_icmp_socket());
}
for handle in to_remove {
socket_set.remove(handle);
self.last_activity.remove(&handle);
}
sockets
}
}
+2
View File
@@ -16,6 +16,7 @@ use smoltcp::{
time::Instant,
};
use tokio::sync::mpsc;
use tracing::trace;
pub struct VirtTunDevice {
capabilities: DeviceCapabilities,
@@ -63,6 +64,7 @@ impl Device for VirtTunDevice {
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
if let Ok(buffer) = self.in_buf.try_recv() {
trace!("--- TUN RX: {} bytes ---", buffer.len()); // Посмотри, что именно прилетает
let rx = Self::RxToken {
buffer,
phantom_device: PhantomData,
+35 -38
View File
@@ -1,4 +1,5 @@
use smoltcp::time::Instant;
use smoltcp::wire::{IpAddress, IpCidr};
use smoltcp::{
iface::{Config, Interface, SocketSet},
phy::DeviceCapabilities,
@@ -35,9 +36,10 @@ impl Engine {
pub fn new(config: Config, caps: DeviceCapabilities, ip: String) -> Self {
let now = Engine::current_time();
let (mut device, bridge_rx, bridge_tx, avail) = VirtTunDevice::new(caps);
let mut interface = Interface::new(config, &mut device, now);
let interface = Interface::new(config, &mut device, now);
let socket_set = SocketSet::new(vec![]);
let mut socket_set = ConnectionManager::setup_sockets(16, 4, 1);
let mut manager = ConnectionManager::new(ip);
Self {
interface,
socket_set,
@@ -45,11 +47,12 @@ impl Engine {
bridge_tx,
bridge_rx,
avail,
manager: ConnectionManager::new(ip),
manager,
}
}
pub async fn run(&mut self, tun: Tun) {
info!("Current routes: {:?}", self.interface.routes());
//Bridge from tun to stack and stack to tun
let (writer, reader) = tun.split().expect("Failed to split TUN");
// Забираем bridge_rx, так как он нам нужен только в одной задаче
@@ -58,25 +61,27 @@ impl Engine {
Self::spawn_engine_to_tun(writer, from_engine);
loop {
self.manager.refill_sockets(&mut self.socket_set);
self.poll();
self.manager.process_sockets(&mut self.socket_set);
if self.avail.load(std::sync::atomic::Ordering::Acquire) {
tokio::task::yield_now().await;
continue;
loop {
self.poll();
self.manager.process_sockets(&mut self.socket_set);
if self.avail.load(std::sync::atomic::Ordering::Acquire) {
tokio::task::yield_now().await;
continue;
}
self.poll_delay().await;
}
self.poll_delay().await;
}
}
pub fn poll(&mut self) {
fn poll(&mut self) {
let now = Self::current_time();
// Передаем девайс и сокеты в интерфейс
self.interface
.poll(now, &mut self.device, &mut self.socket_set);
}
pub async fn poll_delay(&mut self) {
async fn poll_delay(&mut self) {
let timestamp = Self::current_time();
let delay = self.interface.poll_delay(timestamp, &self.socket_set);
let sleep_duration = match delay {
@@ -99,6 +104,13 @@ impl Engine {
break;
}
if n >= 20 {
let dst_ip = std::net::Ipv4Addr::new(buf[16], buf[17], buf[18], buf[19]);
let dst_port = u16::from_be_bytes([buf[22], buf[23]]); // Порт для TCP
debug!("Сырой пакет: назначение {}:{}", dst_ip, dst_port);
}
let mut token = TokenBuffer::with_capacity(n);
token.extend_from_slice(&buf[..n]);
@@ -132,42 +144,20 @@ impl Engine {
Instant::from_micros(duration.as_micros() as i64)
}
pub fn add_address(&mut self, address: smoltcp::wire::IpCidr) {
self.interface.update_ip_addrs(|addrs| {
addrs
.push(address)
.expect("Failed to add IP: address list is full");
});
self.interface
.routes_mut()
.add_default_ipv4_route(smoltcp::wire::Ipv4Address::new(10, 0, 0, 1))
.ok();
}
pub fn set_any_ip(&mut self, state: bool) -> () {
self.interface.set_any_ip(state)
}
pub fn set_transparent_mode(&mut self) {
info!("Switching engine to transparent mode (AnyIP + 0.0.0.0/0)");
self.interface.set_any_ip(true);
self.interface.update_ip_addrs(|addrs| {
addrs.clear();
//accept all internet
addrs
.push(smoltcp::wire::IpCidr::new(
smoltcp::wire::IpAddress::v4(0, 0, 0, 0),
0,
))
.expect("Failed to set 0.0.0.0/0");
.push(IpCidr::new(IpAddress::v4(10, 0, 0, 2), 24))
.unwrap();
});
// Устанавливаем дефолтный маршрут "в никуда" (локально)
self.interface.routes_mut().remove_default_ipv4_route();
self.interface
.routes_mut()
.add_default_ipv4_route(smoltcp::wire::Ipv4Address::new(0, 0, 0, 0))
.ok();
}
pub fn set_default_gateway(&mut self, gateway: smoltcp::wire::Ipv4Address) {
@@ -178,4 +168,11 @@ impl Engine {
.add_default_ipv4_route(gateway)
.expect("Failed to set default gateway");
}
pub fn activate(&mut self) {
let now = Self::current_time();
self.interface
.poll(now, &mut self.device, &mut self.socket_set);
self.manager.start_listening(&mut self.socket_set);
}
}
+9 -27
View File
@@ -43,37 +43,19 @@ impl Tun {
Ok((writer, reader))
}
pub fn setup_linux_routes(&self) -> io::Result<()> {
pub fn setup_routing(&self) -> io::Result<()> {
use std::process::Command;
// Направляем трафик через IP, который слушает твой smoltcp Engine
// Предположим, smoltcp настроен на 10.0.0.2
let status = Command::new("ip")
.args(&["route", "add", "default", "via", "10.0.0.2", "dev", "tun0"])
.status()?;
// Теперь, когда мы знаем, что tun0 имеет IP 10.0.0.1,
// мы можем смело ставить его шлюзом.
if !status.success() {
return Err(io::Error::new(
io::ErrorKind::Other,
"Failed to setup routes",
));
}
Ok(())
}
// 1. Устанавливаем маршрут через созданный интерфейс tun0
let _ = Command::new("sudo")
.args(&[
"ip", "route", "add", "default", "via", "10.0.0.2", "dev", "tun0", "metric", "1",
])
.status();
pub fn clear_default_route(&self) -> io::Result<()> {
use std::process::Command;
info!("Removing existing default route...");
// Удаляем текущий маршрут по умолчанию
let status = Command::new("sudo")
.args(&["ip", "route", "del", "default"])
.status()?;
if !status.success() {
warn!("Could not delete default route (maybe it doesn't exist?)");
}
Ok(())
}
}