routing, cfg compile and routing reset
This commit is contained in:
+13
-93
@@ -1,24 +1,13 @@
|
||||
uniffi::setup_scaffolding!();
|
||||
pub mod connections;
|
||||
mod connections;
|
||||
pub mod tun;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use netrunner_core::{
|
||||
logger_init,
|
||||
proxy::{connection::connection::ConnectionRole, network::Network},
|
||||
};
|
||||
use smoltcp::{iface::Config, phy::DeviceCapabilities};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::OnceLock;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::sync::oneshot;
|
||||
use tracing::{error, info};
|
||||
pub mod platform;
|
||||
use tracing::info;
|
||||
mod session;
|
||||
|
||||
use crate::{
|
||||
platform::setup_platform_routing,
|
||||
tun::{engine::Engine, tun::Tun},
|
||||
};
|
||||
static RUNTIME: OnceLock<Runtime> = OnceLock::new();
|
||||
|
||||
fn get_runtime() -> &'static Runtime {
|
||||
@@ -29,10 +18,9 @@ fn get_runtime() -> &'static Runtime {
|
||||
.expect("Failed to create tokio runtime")
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(uniffi::Object)]
|
||||
pub struct Session {
|
||||
shutdown_tx: Mutex<Option<oneshot::Sender<()>>>,
|
||||
pub(crate) shutdown_tx: Mutex<Option<oneshot::Sender<()>>>,
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
@@ -45,82 +33,14 @@ impl Session {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(uniffi::Object)]
|
||||
pub struct SessionManager;
|
||||
|
||||
#[uniffi::export]
|
||||
impl SessionManager {
|
||||
#[uniffi::constructor]
|
||||
pub fn new() -> Self {
|
||||
logger_init();
|
||||
info!("SessionManager initialized");
|
||||
Self
|
||||
}
|
||||
|
||||
pub fn start(&self, remote_address: String, tun_fd: Option<i32>) -> Arc<Session> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let runtime = get_runtime();
|
||||
runtime.spawn(async move {
|
||||
info!("Starting VPN session thread...");
|
||||
|
||||
let tun_device = if let Some(fd) = tun_fd {
|
||||
info!("Using provided FD for TUN: {}", fd);
|
||||
Tun::from_android_fd(fd).expect("Failed to init TUN from FD")
|
||||
} else {
|
||||
info!("Creating TUN device manually");
|
||||
Tun::create(|config| {
|
||||
config.tun_name("tun0").address((10, 0, 0, 1)).up();
|
||||
})
|
||||
.expect("Failed to init TUN")
|
||||
};
|
||||
|
||||
setup_platform_routing(&tun_device, &remote_address);
|
||||
|
||||
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
|
||||
let mut caps = DeviceCapabilities::default();
|
||||
caps.max_transmission_unit = 1500;
|
||||
caps.medium = smoltcp::phy::Medium::Ip;
|
||||
|
||||
info!("Initializing Network with remote: {}", remote_address);
|
||||
let network = Network::new(
|
||||
"0.0.0.0".into(),
|
||||
8080,
|
||||
ConnectionRole::Client,
|
||||
Some(remote_address),
|
||||
);
|
||||
|
||||
let proxy_ip = network.get_self_local_address();
|
||||
info!("Proxy self address: {:?}", proxy_ip);
|
||||
|
||||
let net_handle = tokio::spawn(async move {
|
||||
network.run().await;
|
||||
});
|
||||
|
||||
info!("Configuring Engine...");
|
||||
|
||||
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));
|
||||
engine.activate();
|
||||
|
||||
info!("Engine activated");
|
||||
|
||||
tokio::select! {
|
||||
res = engine.run(tun_device) => {
|
||||
error!("Engine loop terminated unexpectedly: {:?}", res);
|
||||
}
|
||||
_ = rx => {
|
||||
info!("Shutdown signal received. Cleaning up...");
|
||||
}
|
||||
impl Drop for Session {
|
||||
fn drop(&mut self) {
|
||||
info!("Session dropped, resetting platform routing...");
|
||||
if let Ok(mut tx) = self.shutdown_tx.lock() {
|
||||
if let Some(tx) = tx.take() {
|
||||
let _ = tx.send(());
|
||||
}
|
||||
|
||||
net_handle.abort();
|
||||
info!("VPN session fully stopped.");
|
||||
});
|
||||
|
||||
Arc::new(Session {
|
||||
shutdown_tx: Mutex::new(Some(tx)),
|
||||
})
|
||||
}
|
||||
let _ = crate::tun::routing::reset_platform_routing();
|
||||
}
|
||||
}
|
||||
|
||||
+26
-6
@@ -1,8 +1,9 @@
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use netrunner_client::{
|
||||
platform::setup_platform_routing,
|
||||
tun::{engine::Engine, tun::Tun},
|
||||
use netrunner_client::tun::{
|
||||
engine::Engine,
|
||||
routing::{reset_platform_routing, setup_platform_routing},
|
||||
tun::Tun,
|
||||
};
|
||||
use netrunner_core::{
|
||||
logger_init,
|
||||
@@ -17,7 +18,7 @@ async fn main() {
|
||||
info!("Initializing NetRunner Stack...");
|
||||
let tun_device = Tun::create(|config| {
|
||||
config
|
||||
.tun_name("tun0")
|
||||
.tun_name("netr0")
|
||||
.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.destination((10, 0, 0, 2))
|
||||
@@ -25,7 +26,7 @@ async fn main() {
|
||||
})
|
||||
.expect("Failed to initialize TUN device");
|
||||
let remote_address: String = "62.60.244.156:443".into();
|
||||
setup_platform_routing(&tun_device, &remote_address);
|
||||
setup_platform_routing(&remote_address).expect("Failed to setup routing");
|
||||
|
||||
info!("TUN interface is UP: 10.0.0.1/24");
|
||||
|
||||
@@ -58,5 +59,24 @@ async fn main() {
|
||||
info!("Stack IP initialized: 10.0.0.2");
|
||||
|
||||
info!("Engine starting process loop...");
|
||||
engine.run(tun_device).await;
|
||||
|
||||
// 3. Используем select для перехвата сигнала завершения
|
||||
let ctrl_c = tokio::signal::ctrl_c();
|
||||
|
||||
tokio::select! {
|
||||
res = engine.run(tun_device) => {
|
||||
error!("Engine loop error: {:?}", res);
|
||||
},
|
||||
_ = ctrl_c => {
|
||||
info!("Ctrl+C received, shutting down...");
|
||||
}
|
||||
}
|
||||
|
||||
// 4. ГАРАНТИРОВАННЫЙ СБРОС
|
||||
info!("Restoring system routing...");
|
||||
if let Err(e) = reset_platform_routing() {
|
||||
error!("Failed to reset routing: {}", e);
|
||||
} else {
|
||||
info!("System routing restored successfully.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@ namespace netrunner_client {};
|
||||
|
||||
interface SessionManager {
|
||||
constructor();
|
||||
Session start(string remote_address, optional i32 tun_fd);
|
||||
Session start_mobile(string remote_address, optional i32 tun_fd);
|
||||
Session start_desktop(string remote_address);
|
||||
};
|
||||
|
||||
interface Session {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
use crate::tun::tun::Tun;
|
||||
use std::io;
|
||||
|
||||
pub fn setup_platform_routing(tun_device: &Tun, remote_address: &str) -> io::Result<()> {
|
||||
let proxy_ip = remote_address.split(':').next().unwrap_or(remote_address);
|
||||
tun_device.setup_routing(proxy_ip)?;
|
||||
tun_device.setup_dns_redirection()?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
use crate::tun::tun::Tun;
|
||||
use std::io;
|
||||
|
||||
pub fn setup_platform_routing(_tun_device: &Tun, _remote_address: &str) -> io::Result<()> {
|
||||
eprintln!("Android routing on Kotlin side");
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#[cfg(feature = "desktop")]
|
||||
pub mod desktop;
|
||||
#[cfg(feature = "mobile")]
|
||||
pub mod mobile;
|
||||
|
||||
pub fn setup_platform_routing(tun: &crate::tun::tun::Tun, addr: &str) -> std::io::Result<()> {
|
||||
#[cfg(feature = "desktop")]
|
||||
{
|
||||
desktop::setup_platform_routing(tun, addr)
|
||||
}
|
||||
#[cfg(not(feature = "desktop"))]
|
||||
{
|
||||
mobile::setup_platform_routing(tun, addr)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
use crate::session::{Session, SessionManager};
|
||||
use std::sync::Arc;
|
||||
use uniffi;
|
||||
|
||||
#[uniffi::export]
|
||||
impl SessionManager {
|
||||
pub fn start_desktop(&self, remote_address: String) -> Arc<Session> {
|
||||
self.spawn_session(remote_address, None)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
use crate::session::{Session, SessionManager};
|
||||
use std::sync::Arc;
|
||||
use uniffi;
|
||||
|
||||
#[uniffi::export]
|
||||
impl SessionManager {
|
||||
pub fn start_mobile(&self, remote_address: String, tun_fd: i32) -> Arc<Session> {
|
||||
self.spawn_session(remote_address, Some(tun_fd))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
#[cfg(feature = "desktop")]
|
||||
pub mod desktop;
|
||||
|
||||
#[cfg(feature = "mobile")]
|
||||
pub mod mobile;
|
||||
|
||||
use crate::{
|
||||
Session, get_runtime,
|
||||
tun::{
|
||||
engine::Engine,
|
||||
routing::{reset_platform_routing, setup_platform_routing},
|
||||
tun::Tun,
|
||||
},
|
||||
};
|
||||
use netrunner_core::{
|
||||
logger_init,
|
||||
proxy::{connection::connection::ConnectionRole, network::Network},
|
||||
};
|
||||
use smoltcp::{iface::Config, phy::DeviceCapabilities};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tokio::signal;
|
||||
use tokio::sync::oneshot;
|
||||
use tracing::{error, info};
|
||||
|
||||
#[derive(uniffi::Object)]
|
||||
pub struct SessionManager;
|
||||
|
||||
#[uniffi::export]
|
||||
impl SessionManager {
|
||||
#[uniffi::constructor]
|
||||
pub fn new() -> Self {
|
||||
logger_init();
|
||||
info!("SessionManager initialized");
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl SessionManager {
|
||||
pub(crate) fn spawn_session(
|
||||
&self,
|
||||
remote_address: String,
|
||||
tun_fd: Option<i32>,
|
||||
) -> Arc<Session> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let runtime = get_runtime();
|
||||
|
||||
let shutdown_signal = signal::ctrl_c();
|
||||
|
||||
runtime.spawn(async move {
|
||||
info!("Starting VPN session thread...");
|
||||
|
||||
let tun_device = {
|
||||
#[cfg(feature = "mobile")]
|
||||
{
|
||||
Tun::from_fd(tun_fd.expect("TUN FD required on mobile"))
|
||||
.expect("Failed to init TUN from FD")
|
||||
}
|
||||
#[cfg(feature = "desktop")]
|
||||
{
|
||||
Tun::create(|config| {
|
||||
config
|
||||
.tun_name("netr0")
|
||||
.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.up();
|
||||
})
|
||||
.expect("Failed to init TUN")
|
||||
}
|
||||
};
|
||||
|
||||
setup_platform_routing(&remote_address).expect("Failed to setup routing");
|
||||
|
||||
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
|
||||
let mut caps = DeviceCapabilities::default();
|
||||
caps.max_transmission_unit = 1500;
|
||||
caps.medium = smoltcp::phy::Medium::Ip;
|
||||
|
||||
let network = Network::new(
|
||||
"0.0.0.0".into(),
|
||||
8080,
|
||||
ConnectionRole::Client,
|
||||
Some(remote_address.clone()),
|
||||
);
|
||||
let proxy_ip = network.get_self_local_address();
|
||||
|
||||
let net_handle = tokio::spawn(async move {
|
||||
network.run().await;
|
||||
});
|
||||
|
||||
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));
|
||||
engine.activate();
|
||||
|
||||
tokio::select! {
|
||||
res = engine.run(tun_device) => error!("Engine loop error: {:?}", res),
|
||||
_ = rx => {
|
||||
info!("Shutdown signal received");
|
||||
let _ = reset_platform_routing(); // Очистка при сигнале
|
||||
},
|
||||
_ = shutdown_signal => {
|
||||
info!("Ctrl+C detected, shutting down gracefully...");
|
||||
info!("Restoring routing...");
|
||||
let _ = reset_platform_routing();
|
||||
net_handle.abort();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Arc::new(Session {
|
||||
shutdown_tx: Mutex::new(Some(tx)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod connection_manager;
|
||||
pub mod device;
|
||||
pub mod engine;
|
||||
pub mod routing;
|
||||
pub mod tun;
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
use crate::tun::tun::Tun;
|
||||
use std::io;
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
#[cfg(any(feature = "linux", feature = "windows"))]
|
||||
use std::process::Command;
|
||||
|
||||
pub fn setup_platform_routing(remote_address: &str) -> io::Result<()> {
|
||||
let proxy_ip = remote_address.split(':').next().unwrap_or(remote_address);
|
||||
|
||||
#[cfg(feature = "linux")]
|
||||
{
|
||||
// 1. Бэкап и получение текущего маршрута по умолчанию
|
||||
let _ = Command::new("sudo")
|
||||
.args(&["cp", "/etc/resolv.conf", "/etc/resolv.conf.bak"])
|
||||
.status();
|
||||
|
||||
let output = Command::new("ip")
|
||||
.args(&["route", "show", "default"])
|
||||
.output()?;
|
||||
let default_route = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
|
||||
if default_route.is_empty() {
|
||||
error!("Default route не найден!");
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
"No default route found",
|
||||
));
|
||||
}
|
||||
std::fs::write("/tmp/netrunner_default_route", &default_route)?;
|
||||
|
||||
// 2. Парсинг параметров из маршрута по умолчанию
|
||||
let parts: Vec<&str> = default_route.split_whitespace().collect();
|
||||
let dev = parts
|
||||
.iter()
|
||||
.position(|&x| x == "dev")
|
||||
.and_then(|i| parts.get(i + 1))
|
||||
.copied()
|
||||
.unwrap_or("eth0");
|
||||
let via = parts
|
||||
.iter()
|
||||
.position(|&x| x == "via")
|
||||
.and_then(|i| parts.get(i + 1))
|
||||
.copied();
|
||||
|
||||
// 3. Добавляем маршрут до прокси-сервера
|
||||
let mut proxy_route = vec!["ip", "route", "add", proxy_ip, "dev", dev];
|
||||
if let Some(gw) = via {
|
||||
proxy_route.extend_from_slice(&["via", gw]);
|
||||
}
|
||||
let _ = Command::new("sudo").args(proxy_route).status();
|
||||
|
||||
// 4. Заменяем default маршрут на наш TUN
|
||||
let _ = Command::new("sudo")
|
||||
.args(&["ip", "route", "del", "default"])
|
||||
.status();
|
||||
let status = Command::new("sudo")
|
||||
.args(&[
|
||||
"ip", "route", "add", "default", "via", "10.0.0.2", "dev", "netr0", "metric", "1",
|
||||
])
|
||||
.status()?;
|
||||
|
||||
if status.success() {
|
||||
info!("Linux TUN default set.");
|
||||
}
|
||||
|
||||
// 5. DNS
|
||||
std::fs::write("/tmp/resolv.conf.netrunner", "nameserver 10.0.0.2\n")?;
|
||||
Command::new("sudo")
|
||||
.args(&["cp", "/tmp/resolv.conf.netrunner", "/etc/resolv.conf"])
|
||||
.status()?;
|
||||
}
|
||||
|
||||
#[cfg(feature = "windows")]
|
||||
{
|
||||
// Логика Windows
|
||||
Command::new("route")
|
||||
.args(&[
|
||||
"add",
|
||||
proxy_ip,
|
||||
"mask",
|
||||
"255.255.255.255",
|
||||
"0.0.0.0",
|
||||
"metric",
|
||||
"1",
|
||||
])
|
||||
.status()?;
|
||||
Command::new("netsh")
|
||||
.args(&[
|
||||
"interface",
|
||||
"ipv4",
|
||||
"set",
|
||||
"address",
|
||||
"name=netr0",
|
||||
"static",
|
||||
"10.0.0.1",
|
||||
"255.255.255.0",
|
||||
"10.0.0.2",
|
||||
])
|
||||
.status()?;
|
||||
|
||||
// DNS
|
||||
Command::new("netsh")
|
||||
.args(&[
|
||||
"interface",
|
||||
"ipv4",
|
||||
"set",
|
||||
"dnsservers",
|
||||
"name=netr0",
|
||||
"static",
|
||||
"10.0.0.2",
|
||||
"primary",
|
||||
])
|
||||
.status()?;
|
||||
}
|
||||
|
||||
#[cfg(feature = "mobile")]
|
||||
{
|
||||
eprintln!("Android/Mobile routing on native side");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn reset_platform_routing() -> io::Result<()> {
|
||||
#[cfg(feature = "linux")]
|
||||
{
|
||||
// 1. Возвращаем дефолтный маршрут из файла
|
||||
if let Ok(saved_route) = std::fs::read_to_string("/tmp/netrunner_default_route") {
|
||||
let _ = Command::new("sudo")
|
||||
.args(&["ip", "route", "del", "default"])
|
||||
.status();
|
||||
let args: Vec<&str> = saved_route.split_whitespace().collect();
|
||||
let _ = Command::new("sudo")
|
||||
.args(&["ip", "route", "add"])
|
||||
.args(args)
|
||||
.status();
|
||||
}
|
||||
|
||||
// 2. Удаляем наш специфичный маршрут к прокси
|
||||
// (Опционально, если он был добавлен)
|
||||
|
||||
// 3. Восстанавливаем DNS (если есть бэкап)
|
||||
let _ = Command::new("sudo")
|
||||
.args(&["cp", "/etc/resolv.conf.bak", "/etc/resolv.conf"])
|
||||
.status();
|
||||
|
||||
info!("Linux routing restored.");
|
||||
}
|
||||
|
||||
#[cfg(feature = "windows")]
|
||||
{
|
||||
// В Windows можно просто удалить маршрут и интерфейс
|
||||
let _ = Command::new("route").args(&["delete", "0.0.0.0"]).status();
|
||||
// При переподключении сети (или ipconfig /renew) Windows сам подтянет настройки
|
||||
info!("Windows routing reset requested.");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
+3
-79
@@ -21,6 +21,7 @@ impl Tun {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "desktop")]
|
||||
pub fn create<F>(f: F) -> io::Result<Self>
|
||||
where
|
||||
F: FnOnce(&mut Configuration),
|
||||
@@ -30,7 +31,8 @@ impl Tun {
|
||||
Self::new(&config)
|
||||
}
|
||||
|
||||
pub fn from_android_fd(fd: i32) -> io::Result<Self> {
|
||||
#[cfg(feature = "mobile")]
|
||||
pub fn from_fd(fd: i32) -> io::Result<Self> {
|
||||
let mut config = Configuration::default();
|
||||
config.raw_fd(fd);
|
||||
config.up();
|
||||
@@ -42,82 +44,4 @@ impl Tun {
|
||||
let (writer, reader) = self.device.split()?;
|
||||
Ok((writer, reader))
|
||||
}
|
||||
|
||||
fn get_route_part<'a>(parts: &'a [&'a str], key: &str) -> Option<&'a str> {
|
||||
parts
|
||||
.iter()
|
||||
.position(|&x| x == key)
|
||||
.and_then(|i| parts.get(i + 1))
|
||||
.copied()
|
||||
}
|
||||
|
||||
#[cfg(feature = "desktop")]
|
||||
pub fn setup_routing(&self, remote_address: &str) -> io::Result<()> {
|
||||
use std::process::Command;
|
||||
|
||||
info!(
|
||||
"Начинаем настройку маршрутизации для прокси: {}",
|
||||
remote_address
|
||||
);
|
||||
|
||||
let output = Command::new("ip")
|
||||
.args(&["route", "get", remote_address])
|
||||
.output()?;
|
||||
let route_info = String::from_utf8_lossy(&output.stdout);
|
||||
let parts: Vec<&str> = route_info.split_whitespace().collect();
|
||||
|
||||
let dev = Self::get_route_part(&parts, "dev").unwrap_or("eth0");
|
||||
let via = Self::get_route_part(&parts, "via");
|
||||
|
||||
info!("Обнаружен физический маршрут: dev={}, via={:?}", dev, via);
|
||||
|
||||
info!("Добавляем статический маршрут для прокси...");
|
||||
let mut proxy_route = vec!["ip", "route", "add", remote_address, "dev", dev];
|
||||
if let Some(gw) = via {
|
||||
proxy_route.extend_from_slice(&["via", gw]);
|
||||
}
|
||||
let status = Command::new("sudo").args(proxy_route).status()?;
|
||||
if !status.success() {
|
||||
warn!("Маршрут к прокси уже существует или возникла ошибка (это нормально).");
|
||||
}
|
||||
|
||||
info!("Переключаем default маршрут на tun0...");
|
||||
let _ = Command::new("sudo")
|
||||
.args(&["ip", "route", "del", "default"])
|
||||
.status();
|
||||
|
||||
let status = Command::new("sudo")
|
||||
.args(&[
|
||||
"ip", "route", "add", "default", "via", "10.0.0.2", "dev", "tun0", "metric", "1",
|
||||
])
|
||||
.status()?;
|
||||
if status.success() {
|
||||
info!("TUN успешно установлен как основной default.");
|
||||
} else {
|
||||
error!("Не удалось установить tun0 как default!");
|
||||
}
|
||||
|
||||
if let Some(gw) = via {
|
||||
info!("Добавляем резервный маршрут через {} с метрикой 100", dev);
|
||||
let _ = Command::new("sudo")
|
||||
.args(&[
|
||||
"ip", "route", "add", "default", "via", gw, "dev", dev, "metric", "100",
|
||||
])
|
||||
.status();
|
||||
}
|
||||
|
||||
info!("Маршрутизация полностью настроена.");
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "desktop")]
|
||||
pub fn setup_dns_redirection(&self) -> io::Result<()> {
|
||||
let _ = std::fs::write("/tmp/resolv.conf.netrunner", "nameserver 10.0.0.2\n");
|
||||
|
||||
let _ = std::process::Command::new("sudo")
|
||||
.args(&["cp", "/tmp/resolv.conf.netrunner", "/etc/resolv.conf"])
|
||||
.status();
|
||||
|
||||
info!("DNS перенаправлен на 10.0.0.1");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user