buffer size changes and dns adds block
This commit is contained in:
+140
-27
@@ -1,35 +1,148 @@
|
||||
use crate::connections::ip_store::FakeIpStore;
|
||||
use hickory_proto::op::{Message, MessageType, Query, ResponseCode};
|
||||
use hickory_proto::op::{Message, MessageType, ResponseCode};
|
||||
use hickory_proto::rr::{RData, Record, RecordType};
|
||||
use netrunner_logger::{debug, error, info, warn};
|
||||
use std::collections::HashSet;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::path::Path;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
pub fn handle_dns_query(data: &[u8], store: &mut FakeIpStore) -> Option<Vec<u8>> {
|
||||
let request = Message::from_vec(data).ok()?;
|
||||
let query = request.queries().first()?;
|
||||
pub struct DnsHandler {
|
||||
block_list: HashSet<String>,
|
||||
forbidden_suffixes: Vec<String>,
|
||||
cache_path: String,
|
||||
}
|
||||
|
||||
let mut response = Message::new();
|
||||
response
|
||||
.set_id(request.id())
|
||||
.set_message_type(MessageType::Response)
|
||||
.set_recursion_available(true)
|
||||
.set_response_code(ResponseCode::NoError)
|
||||
.add_query(query.clone());
|
||||
|
||||
match query.query_type() {
|
||||
RecordType::A => {
|
||||
let name = query.name().to_string().trim_end_matches('.').to_string();
|
||||
let fake_ip = store.get_or_assign(&name);
|
||||
|
||||
let record = Record::from_rdata(query.name().clone(), 1, RData::A(fake_ip.into()));
|
||||
response.add_answer(record);
|
||||
}
|
||||
|
||||
RecordType::AAAA => {
|
||||
response.set_response_code(ResponseCode::NoError);
|
||||
}
|
||||
_ => {
|
||||
response.set_response_code(ResponseCode::NoError);
|
||||
impl DnsHandler {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
block_list: HashSet::new(),
|
||||
forbidden_suffixes: vec![
|
||||
".lan".to_string(),
|
||||
".local".to_string(),
|
||||
".home".to_string(),
|
||||
".arpa".to_string(),
|
||||
],
|
||||
cache_path: "hosts_cache.txt".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
response.to_vec().ok()
|
||||
/// Основной метод инициализации: решает, качать или брать из кэша
|
||||
pub fn init(&mut self) -> anyhow::Result<()> {
|
||||
let url = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts";
|
||||
let path = Path::new(&self.cache_path);
|
||||
|
||||
let should_download = if path.exists() {
|
||||
let metadata = fs::metadata(path)?;
|
||||
let last_modified = metadata.modified()?;
|
||||
let elapsed = SystemTime::now().duration_since(last_modified)?.as_secs();
|
||||
|
||||
elapsed > 604800
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
if should_download {
|
||||
info!("Blocklist is outdated or missing. Trying to download...");
|
||||
if let Err(e) = self.download_and_cache(url) {
|
||||
warn!(
|
||||
"Failed to download blocklist ({}), trying to use cache if available",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if path.exists() {
|
||||
self.load_from_file()?;
|
||||
} else {
|
||||
error!("No blocklist available (neither online nor cache)!");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn download_and_cache(&self, url: &str) -> anyhow::Result<()> {
|
||||
let mut response = reqwest::blocking::get(url)?;
|
||||
if !response.status().is_success() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Server returned status {}",
|
||||
response.status()
|
||||
));
|
||||
}
|
||||
|
||||
let mut file = File::create(&self.cache_path)?;
|
||||
response.copy_to(&mut file)?;
|
||||
info!("Blocklist downloaded and cached locally.");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_from_file(&mut self) -> anyhow::Result<()> {
|
||||
let file = File::open(&self.cache_path)?;
|
||||
let reader = BufReader::new(file);
|
||||
let mut count = 0;
|
||||
|
||||
for line in reader.lines() {
|
||||
let line = line?;
|
||||
if line.starts_with('#') || line.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||
if parts.len() >= 2 {
|
||||
// Берем домен (второй столбец в StevenBlack hosts)
|
||||
self.block_list.insert(parts[1].to_lowercase());
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
info!("Loaded {} domains from cache.", count);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_query(&self, data: &[u8], store: &mut FakeIpStore) -> Option<Vec<u8>> {
|
||||
let request = Message::from_vec(data).ok()?;
|
||||
let query = request.queries().first()?;
|
||||
|
||||
let mut response = Message::new();
|
||||
response
|
||||
.set_id(request.id())
|
||||
.set_message_type(MessageType::Response)
|
||||
.set_recursion_available(true)
|
||||
.add_query(query.clone());
|
||||
|
||||
let name = query
|
||||
.name()
|
||||
.to_string()
|
||||
.trim_end_matches('.')
|
||||
.to_lowercase();
|
||||
|
||||
// 1. Спец. суффиксы
|
||||
if self.forbidden_suffixes.iter().any(|s| name.ends_with(s)) {
|
||||
info!(domain = %name, "DNS: Blocked (Suffix)");
|
||||
response.set_response_code(ResponseCode::NXDomain);
|
||||
return response.to_vec().ok();
|
||||
}
|
||||
|
||||
// 2. Бан-лист (AdBlock)
|
||||
if self.block_list.contains(&name) {
|
||||
info!(domain = %name, "DNS: Blocked (AdList)");
|
||||
response.set_response_code(ResponseCode::NXDomain);
|
||||
return response.to_vec().ok();
|
||||
}
|
||||
|
||||
// 3. Fake IP Logic
|
||||
match query.query_type() {
|
||||
RecordType::A => {
|
||||
let fake_ip = store.get_or_assign(&name);
|
||||
let record = Record::from_rdata(query.name().clone(), 60, RData::A(fake_ip.into()));
|
||||
response.set_response_code(ResponseCode::NoError);
|
||||
response.add_answer(record);
|
||||
}
|
||||
_ => {
|
||||
response.set_response_code(ResponseCode::NoError);
|
||||
}
|
||||
}
|
||||
|
||||
response.to_vec().ok()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
use crate::connections::dns::handle_dns_query;
|
||||
use crate::connections::dns::DnsHandler; // проверь путь
|
||||
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) {
|
||||
pub fn process_incoming(
|
||||
socket: &mut udp::Socket,
|
||||
store: &mut FakeIpStore,
|
||||
dns_handler: &DnsHandler,
|
||||
) {
|
||||
while socket.can_recv() {
|
||||
let (data, metadata) = match socket.recv() {
|
||||
Ok(res) => res,
|
||||
@@ -14,8 +18,8 @@ impl UdpConnection {
|
||||
|
||||
let endpoint = metadata.endpoint;
|
||||
|
||||
if let Some(response) = handle_dns_query(&data, store) {
|
||||
netrunner_logger::debug!(to = %endpoint, "Sending DNS response");
|
||||
if let Some(response) = dns_handler.handle_query(&data, store) {
|
||||
netrunner_logger::debug!(to = %endpoint, "Sending DNS response (filtered)");
|
||||
let _ = socket.send_slice(&response, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
uniffi::setup_scaffolding!();
|
||||
mod connections;
|
||||
pub mod connections;
|
||||
pub mod tun;
|
||||
use netrunner_logger::info;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
+81
-57
@@ -1,80 +1,104 @@
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use netrunner_client::tun::{
|
||||
engine::Engine,
|
||||
routing::{reset_platform_routing, setup_platform_routing},
|
||||
tun::Tun,
|
||||
use netrunner_client::{
|
||||
connections::dns::DnsHandler,
|
||||
tun::{
|
||||
engine::Engine,
|
||||
routing::{reset_platform_routing, setup_platform_routing},
|
||||
tun::Tun,
|
||||
},
|
||||
};
|
||||
use netrunner_core::proxy::{connection::connection::ConnectionRole, network::Network};
|
||||
use netrunner_logger::{error, info};
|
||||
use smoltcp::{iface::Config, phy::DeviceCapabilities};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Убираем макрос #[tokio::main]
|
||||
fn main() -> anyhow::Result<()> {
|
||||
netrunner_logger::Logger::init();
|
||||
info!("Initializing NetRunner Stack...");
|
||||
let tun_device = Tun::create(|config| {
|
||||
config
|
||||
.tun_name("netr0")
|
||||
.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.destination((10, 0, 0, 2))
|
||||
.up();
|
||||
})
|
||||
.expect("Failed to initialize TUN device");
|
||||
let remote_address: String = "62.60.244.156:443".into();
|
||||
setup_platform_routing(&remote_address);
|
||||
|
||||
info!("TUN interface is UP: 10.0.0.1/24");
|
||||
// 1. СИНХРОННАЯ ЧАСТЬ
|
||||
// Здесь reqwest::blocking может спокойно создавать и удалять свои ресурсы
|
||||
let mut dns_handler = DnsHandler::new();
|
||||
if let Err(e) = dns_handler.init() {
|
||||
error!("Failed to initialize DNS blocklist: {}", e);
|
||||
}
|
||||
|
||||
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
|
||||
// 2. АСИНХРОННАЯ ЧАСТЬ
|
||||
// Создаем рантайм вручную
|
||||
let rt = tokio::runtime::Runtime::new()?;
|
||||
|
||||
let mut caps = DeviceCapabilities::default();
|
||||
// Передаем управление в асинхронный блок
|
||||
rt.block_on(async move {
|
||||
let tun_device = Tun::create(|config| {
|
||||
config
|
||||
.tun_name("netr0")
|
||||
.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.destination((10, 0, 0, 2))
|
||||
.up();
|
||||
})
|
||||
.expect("Failed to initialize TUN device");
|
||||
|
||||
caps.max_transmission_unit = 1280;
|
||||
caps.medium = smoltcp::phy::Medium::Ip;
|
||||
let remote_address: String = "62.60.244.156:443".into();
|
||||
setup_platform_routing(&remote_address);
|
||||
|
||||
let network = Network::new(
|
||||
"0.0.0.0".into(),
|
||||
8080,
|
||||
ConnectionRole::Client,
|
||||
Some(remote_address.clone()),
|
||||
);
|
||||
info!("TUN interface is UP: 10.0.0.1/24");
|
||||
|
||||
let proxy_ip = network.get_self_local_address();
|
||||
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
|
||||
let mut caps = DeviceCapabilities::default();
|
||||
caps.max_transmission_unit = 1280;
|
||||
caps.medium = smoltcp::phy::Medium::Ip;
|
||||
|
||||
tokio::spawn(async move {
|
||||
info!("Network thread started");
|
||||
network.run(CancellationToken::new()).await;
|
||||
});
|
||||
let network = Network::new(
|
||||
"0.0.0.0".into(),
|
||||
8080,
|
||||
ConnectionRole::Client,
|
||||
Some(remote_address.clone()),
|
||||
);
|
||||
|
||||
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!("Stack IP initialized: 10.0.0.2");
|
||||
let proxy_ip = network.get_self_local_address();
|
||||
|
||||
info!("Engine starting process loop...");
|
||||
// Запускаем сетевой поток
|
||||
let network_token = CancellationToken::new();
|
||||
tokio::spawn(async move {
|
||||
info!("Network thread started");
|
||||
network.run(network_token).await;
|
||||
});
|
||||
|
||||
let ctrl_c = tokio::signal::ctrl_c();
|
||||
// Создаем Engine и передаем уже готовый dns_handler
|
||||
let mut engine = Engine::new(config, caps, proxy_ip, dns_handler);
|
||||
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);
|
||||
},
|
||||
_ = ctrl_c => {
|
||||
info!("Ctrl+C received, shutting down...");
|
||||
info!("Stack IP initialized: 10.0.0.2");
|
||||
info!("Engine starting process loop...");
|
||||
|
||||
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...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!("Restoring system routing...");
|
||||
let addr: std::net::SocketAddr = remote_address.parse().expect("Invalid address format");
|
||||
let proxy_ip = addr.ip().to_string();
|
||||
if let Err(e) = reset_platform_routing(Some(&proxy_ip)) {
|
||||
error!("Failed to reset routing: {}", e);
|
||||
} else {
|
||||
info!("System routing restored successfully.");
|
||||
}
|
||||
// Очистка при выходе
|
||||
info!("Restoring system routing...");
|
||||
let addr: std::net::SocketAddr = remote_address.parse().expect("Invalid address format");
|
||||
let p_ip = addr.ip().to_string();
|
||||
if let Err(e) = reset_platform_routing(Some(&p_ip)) {
|
||||
error!("Failed to reset routing: {}", e);
|
||||
} else {
|
||||
info!("System routing restored successfully.");
|
||||
}
|
||||
|
||||
Ok::<(), anyhow::Error>(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ pub mod mobile;
|
||||
|
||||
use crate::{
|
||||
RUNTIME, Session,
|
||||
connections::dns::DnsHandler,
|
||||
tun::{
|
||||
engine::Engine,
|
||||
routing::{reset_platform_routing, setup_platform_routing},
|
||||
@@ -103,11 +104,16 @@ impl SessionManager {
|
||||
);
|
||||
let proxy_ip = network.get_self_local_address();
|
||||
|
||||
let mut dns_handler = DnsHandler::new();
|
||||
if let Err(e) = dns_handler.init() {
|
||||
error!("Failed to initialize DNS blocklist: {}", e);
|
||||
}
|
||||
|
||||
tokio::spawn(async move {
|
||||
network.run(net_token).await;
|
||||
});
|
||||
|
||||
let mut engine = Engine::new(config, caps, proxy_ip);
|
||||
let mut engine = Engine::new(config, caps, proxy_ip, dns_handler);
|
||||
engine.set_any_ip(true);
|
||||
engine.set_transparent_mode();
|
||||
engine.set_default_gateway(Ipv4Addr::new(10, 0, 0, 2));
|
||||
|
||||
@@ -1,38 +1,39 @@
|
||||
use netrunner_core::protocol::codec::socks::TargetAddress;
|
||||
use netrunner_logger::{debug, info, warn};
|
||||
use netrunner_logger::{debug, error, info, warn};
|
||||
use smoltcp::{
|
||||
iface::{SocketHandle, SocketSet},
|
||||
socket::{AnySocket, icmp, tcp, udp},
|
||||
wire::{IpAddress, IpListenEndpoint},
|
||||
wire::IpListenEndpoint,
|
||||
};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
time::{Duration, Instant as StdInstant},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
connections::{
|
||||
ip_store::FakeIpStore, tcp_connection::TcpConnection, udp_connection::UdpConnection,
|
||||
},
|
||||
tun::engine::START_TIME,
|
||||
use crate::connections::{
|
||||
dns::DnsHandler, ip_store::FakeIpStore, tcp_connection::TcpConnection,
|
||||
udp_connection::UdpConnection,
|
||||
};
|
||||
pub struct ConnectionManager {
|
||||
last_activity: HashMap<SocketHandle, StdInstant>,
|
||||
active_tcp_sessions: HashMap<SocketHandle, TcpConnection>,
|
||||
|
||||
active_udp_sessions: HashMap<SocketHandle, UdpConnection>,
|
||||
dns_handler: DnsHandler,
|
||||
fake_ip_store: FakeIpStore,
|
||||
proxy_ip: String,
|
||||
failed_until: HashMap<SocketHandle, StdInstant>,
|
||||
}
|
||||
|
||||
impl ConnectionManager {
|
||||
pub fn new(ip: String) -> Self {
|
||||
pub fn new(ip: String, dns_handler: DnsHandler) -> Self {
|
||||
Self {
|
||||
last_activity: HashMap::new(),
|
||||
active_tcp_sessions: HashMap::new(),
|
||||
active_udp_sessions: HashMap::new(),
|
||||
proxy_ip: ip,
|
||||
fake_ip_store: FakeIpStore::new(),
|
||||
failed_until: HashMap::new(),
|
||||
dns_handler, // Просто сохраняем готовый объект
|
||||
}
|
||||
}
|
||||
pub fn start_listening(&mut self, socket_set: &mut SocketSet) {
|
||||
@@ -159,7 +160,7 @@ impl ConnectionManager {
|
||||
fn handle_udp(&mut self, handle: SocketHandle, socket: &mut udp::Socket) {
|
||||
self.last_activity.insert(handle, StdInstant::now());
|
||||
|
||||
UdpConnection::process_incoming(socket, &mut self.fake_ip_store);
|
||||
UdpConnection::process_incoming(socket, &mut self.fake_ip_store, &self.dns_handler);
|
||||
}
|
||||
|
||||
fn handle_icmp(&mut self, handle: SocketHandle, socket: &mut icmp::Socket) {
|
||||
@@ -174,7 +175,7 @@ impl ConnectionManager {
|
||||
}
|
||||
|
||||
fn create_tcp_socket<'a>() -> tcp::Socket<'a> {
|
||||
const BUF_SIZE: usize = 16384;
|
||||
const BUF_SIZE: usize = 65536;
|
||||
tcp::Socket::new(
|
||||
tcp::SocketBuffer::new(vec![0; BUF_SIZE]),
|
||||
tcp::SocketBuffer::new(vec![0; BUF_SIZE]),
|
||||
@@ -182,7 +183,7 @@ impl ConnectionManager {
|
||||
}
|
||||
|
||||
fn create_udp_socket<'a>() -> udp::Socket<'a> {
|
||||
const BUF_SIZE: usize = 16384;
|
||||
const BUF_SIZE: usize = 32768;
|
||||
udp::Socket::new(
|
||||
udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY; 16], vec![0; BUF_SIZE]),
|
||||
udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY; 16], vec![0; BUF_SIZE]),
|
||||
|
||||
@@ -18,6 +18,7 @@ use tun::{DeviceReader, DeviceWriter};
|
||||
|
||||
use netrunner_logger::{debug, info, warn};
|
||||
|
||||
use crate::connections::dns::{self, DnsHandler};
|
||||
use crate::tun::connection_manager::ConnectionManager;
|
||||
use crate::tun::device::{TokenBuffer, VirtTunDevice};
|
||||
use crate::tun::tun::Tun;
|
||||
@@ -34,13 +35,18 @@ pub struct Engine {
|
||||
}
|
||||
|
||||
impl Engine {
|
||||
pub fn new(config: Config, caps: DeviceCapabilities, ip: String) -> Self {
|
||||
pub fn new(
|
||||
config: Config,
|
||||
caps: DeviceCapabilities,
|
||||
ip: String,
|
||||
dns_handler: DnsHandler,
|
||||
) -> Self {
|
||||
let now = Engine::current_time();
|
||||
let (mut device, bridge_rx, bridge_tx, avail) = VirtTunDevice::new(caps);
|
||||
let interface = Interface::new(config, &mut device, now);
|
||||
|
||||
let socket_set = ConnectionManager::setup_sockets(128, 8, 4);
|
||||
let manager = ConnectionManager::new(ip);
|
||||
let socket_set = ConnectionManager::setup_sockets(128, 128, 4);
|
||||
let manager = ConnectionManager::new(ip, dns_handler);
|
||||
Self {
|
||||
interface,
|
||||
socket_set,
|
||||
|
||||
Reference in New Issue
Block a user