close to final of fake ip resolving
This commit is contained in:
@@ -17,6 +17,7 @@ pub fn handle_dns_query(data: &[u8], store: &mut FakeIpStore) -> Option<Vec<u8>>
|
|||||||
// 4. Формируем ответ
|
// 4. Формируем ответ
|
||||||
let mut response = Message::new();
|
let mut response = Message::new();
|
||||||
response
|
response
|
||||||
|
.set_recursion_available(true)
|
||||||
.set_id(request.id())
|
.set_id(request.id())
|
||||||
.set_message_type(MessageType::Response)
|
.set_message_type(MessageType::Response)
|
||||||
.set_response_code(ResponseCode::NoError)
|
.set_response_code(ResponseCode::NoError)
|
||||||
|
|||||||
@@ -1,32 +1,23 @@
|
|||||||
use crate::connections::dns::handle_dns_query;
|
use crate::connections::dns::handle_dns_query;
|
||||||
use crate::connections::ip_store::FakeIpStore;
|
use crate::connections::ip_store::FakeIpStore;
|
||||||
use smoltcp::socket::udp;
|
use smoltcp::socket::udp;
|
||||||
|
use tracing::{debug, trace};
|
||||||
|
|
||||||
pub struct UdpConnection;
|
pub struct UdpConnection;
|
||||||
|
|
||||||
impl 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) {
|
||||||
// Мы используем peek или recv, чтобы понять, куда идти дальше
|
|
||||||
while socket.can_recv() {
|
while socket.can_recv() {
|
||||||
let (data, metadata) = match socket.recv() {
|
let (data, metadata) = match socket.recv() {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
Err(_) => break,
|
Err(_) => break,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Диспетчер: определяем тип трафика по порту
|
let endpoint = metadata.endpoint;
|
||||||
match metadata.endpoint.port {
|
|
||||||
53 => {
|
if let Some(response) = handle_dns_query(&data, store) {
|
||||||
// Это DNS
|
debug!(to = %endpoint, "Sending DNS response");
|
||||||
if let Some(response) = handle_dns_query(&data, store) {
|
let _ = socket.send_slice(&response, metadata);
|
||||||
let _ = socket.send_slice(&response, metadata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Тут в будущем можно добавить обработку других протоколов
|
|
||||||
// 443 => process_quic(...),
|
|
||||||
_ => {
|
|
||||||
// Можно логировать неизвестный трафик или просто дропать
|
|
||||||
// trace!("Received UDP on unknown port: {}", endpoint.port);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-2
@@ -24,17 +24,23 @@ async fn main() {
|
|||||||
.expect("Failed to initialize TUN device");
|
.expect("Failed to initialize TUN device");
|
||||||
|
|
||||||
tun_device.setup_routing();
|
tun_device.setup_routing();
|
||||||
|
tun_device.setup_dns_redirection();
|
||||||
|
|
||||||
info!("TUN interface is UP: 10.0.0.1/24");
|
info!("TUN interface is UP: 10.0.0.1/24");
|
||||||
|
|
||||||
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
|
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
|
||||||
|
|
||||||
let mut caps = DeviceCapabilities::default();
|
let mut caps = DeviceCapabilities::default();
|
||||||
let remote_address: String = "127.0.0.1:4443".into();
|
let remote_address: String = "172.18.151.121:4443".into();
|
||||||
caps.max_transmission_unit = 1500;
|
caps.max_transmission_unit = 1500;
|
||||||
caps.medium = smoltcp::phy::Medium::Ip;
|
caps.medium = smoltcp::phy::Medium::Ip;
|
||||||
|
|
||||||
let network = Network::new(8080, ConnectionRole::Client, Some(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();
|
let proxy_ip = network.get_self_local_address();
|
||||||
|
|
||||||
|
|||||||
@@ -33,19 +33,29 @@ impl ConnectionManager {
|
|||||||
fake_ip_store: FakeIpStore::new(),
|
fake_ip_store: FakeIpStore::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_listening(&mut self, socket_set: &mut SocketSet) {
|
pub fn start_listening(&mut self, socket_set: &mut SocketSet) {
|
||||||
for (_, socket) in socket_set.iter_mut() {
|
for (_, socket) in socket_set.iter_mut() {
|
||||||
|
// Обработка TCP (как было)
|
||||||
if let Some(tcp) = tcp::Socket::downcast_mut(socket) {
|
if let Some(tcp) = tcp::Socket::downcast_mut(socket) {
|
||||||
if !tcp.is_open() {
|
if !tcp.is_open() {
|
||||||
let endpoint = IpListenEndpoint {
|
let endpoint = IpListenEndpoint {
|
||||||
addr: None,
|
addr: None,
|
||||||
port: 443,
|
port: 443,
|
||||||
};
|
};
|
||||||
|
let _ = tcp.listen(endpoint);
|
||||||
match tcp.listen(endpoint) {
|
}
|
||||||
Ok(_) => debug!("Socket is now listening"),
|
}
|
||||||
Err(e) => warn!(error=?e, "Failed to listen on socket"),
|
// Добавляем обработку UDP
|
||||||
|
else if let Some(udp) = udp::Socket::downcast_mut(socket) {
|
||||||
|
if !udp.is_open() {
|
||||||
|
// Биндим на 53 порт, чтобы ловить DNS-запросы
|
||||||
|
let endpoint = IpListenEndpoint {
|
||||||
|
addr: None,
|
||||||
|
port: 53,
|
||||||
|
};
|
||||||
|
match udp.bind(endpoint) {
|
||||||
|
Ok(_) => debug!("UDP socket bound to port 53"),
|
||||||
|
Err(e) => warn!(error=?e, "Failed to bind UDP socket"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,7 +64,7 @@ impl ConnectionManager {
|
|||||||
|
|
||||||
fn resolve_target(&self, socket: &tcp::Socket) -> TargetAddress {
|
fn resolve_target(&self, socket: &tcp::Socket) -> TargetAddress {
|
||||||
// Безопасно получаем эндпоинт
|
// Безопасно получаем эндпоинт
|
||||||
let remote_endpoint = match socket.remote_endpoint() {
|
let local_endpoint = match socket.local_endpoint() {
|
||||||
Some(ep) => ep,
|
Some(ep) => ep,
|
||||||
None => {
|
None => {
|
||||||
warn!(handle=?socket, "Attempted to resolve target for an unconnected socket");
|
warn!(handle=?socket, "Attempted to resolve target for an unconnected socket");
|
||||||
@@ -62,18 +72,21 @@ impl ConnectionManager {
|
|||||||
return TargetAddress::Domain("disconnected".to_string(), 0);
|
return TargetAddress::Domain("disconnected".to_string(), 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
debug!(remote_addr = %local_endpoint.addr, remote_port = %local_endpoint.port, "SMOLTCP RAW REMOTE ENDPOINT");
|
||||||
|
|
||||||
let port = remote_endpoint.port;
|
let port = local_endpoint.port;
|
||||||
let ip = remote_endpoint.addr;
|
let ip = local_endpoint.addr;
|
||||||
|
|
||||||
match ip {
|
match ip {
|
||||||
smoltcp::wire::IpAddress::Ipv4(ipv4_addr) => {
|
smoltcp::wire::IpAddress::Ipv4(ipv4_addr) => {
|
||||||
let std_ip = std::net::Ipv4Addr::from(ipv4_addr);
|
let std_ip = std::net::Ipv4Addr::from(ipv4_addr);
|
||||||
|
|
||||||
// Ищем домен в нашем FakeIpStore
|
debug!(ip=%std_ip, "Trying to resolve IP in FakeIpStore");
|
||||||
if let Some(domain) = self.fake_ip_store.lookup_by_ip(&std_ip) {
|
if let Some(domain) = self.fake_ip_store.lookup_by_ip(&std_ip) {
|
||||||
debug!(target=%domain, port=%port, "Resolved fake IP to domain");
|
debug!(target=%domain, port=%port, "Resolved fake IP to domain");
|
||||||
return TargetAddress::Domain(domain, port);
|
return TargetAddress::Domain(domain, port);
|
||||||
|
} else {
|
||||||
|
warn!(ip=%std_ip, "IP not found in FakeIpStore! SOCKS request will fail.");
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(ip=%std_ip, port=%port, "Using raw IP target");
|
debug!(ip=%std_ip, port=%port, "Using raw IP target");
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use smoltcp::{
|
|||||||
iface::{Config, Interface, SocketSet},
|
iface::{Config, Interface, SocketSet},
|
||||||
phy::DeviceCapabilities,
|
phy::DeviceCapabilities,
|
||||||
};
|
};
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
use std::{
|
use std::{
|
||||||
mem,
|
mem,
|
||||||
sync::{Arc, LazyLock, atomic::AtomicBool},
|
sync::{Arc, LazyLock, atomic::AtomicBool},
|
||||||
@@ -38,8 +37,8 @@ impl Engine {
|
|||||||
let (mut device, bridge_rx, bridge_tx, avail) = VirtTunDevice::new(caps);
|
let (mut device, bridge_rx, bridge_tx, avail) = VirtTunDevice::new(caps);
|
||||||
let interface = Interface::new(config, &mut device, now);
|
let interface = Interface::new(config, &mut device, now);
|
||||||
|
|
||||||
let mut socket_set = ConnectionManager::setup_sockets(16, 4, 1);
|
let socket_set = ConnectionManager::setup_sockets(16, 4, 1);
|
||||||
let mut manager = ConnectionManager::new(ip);
|
let manager = ConnectionManager::new(ip);
|
||||||
Self {
|
Self {
|
||||||
interface,
|
interface,
|
||||||
socket_set,
|
socket_set,
|
||||||
@@ -104,13 +103,6 @@ impl Engine {
|
|||||||
break;
|
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);
|
let mut token = TokenBuffer::with_capacity(n);
|
||||||
token.extend_from_slice(&buf[..n]);
|
token.extend_from_slice(&buf[..n]);
|
||||||
|
|
||||||
|
|||||||
+42
-3
@@ -46,16 +46,55 @@ impl Tun {
|
|||||||
pub fn setup_routing(&self) -> io::Result<()> {
|
pub fn setup_routing(&self) -> io::Result<()> {
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
// Теперь, когда мы знаем, что tun0 имеет IP 10.0.0.1,
|
// 1. Удаляем существующий default-маршрут (чтобы не было конфликтов)
|
||||||
// мы можем смело ставить его шлюзом.
|
// Игнорируем ошибку, если его вдруг нет
|
||||||
|
let _ = Command::new("sudo")
|
||||||
|
.args(&["ip", "route", "del", "default"])
|
||||||
|
.status();
|
||||||
|
|
||||||
// 1. Устанавливаем маршрут через созданный интерфейс tun0
|
// 2. Добавляем tun0 как ГЛАВНЫЙ маршрут (метрика 1 — самый высокий приоритет)
|
||||||
let _ = Command::new("sudo")
|
let _ = Command::new("sudo")
|
||||||
.args(&[
|
.args(&[
|
||||||
"ip", "route", "add", "default", "via", "10.0.0.2", "dev", "tun0", "metric", "1",
|
"ip", "route", "add", "default", "via", "10.0.0.2", "dev", "tun0", "metric", "1",
|
||||||
])
|
])
|
||||||
.status();
|
.status();
|
||||||
|
|
||||||
|
// 3. Добавляем eth0 как РЕЗЕРВНЫЙ маршрут (метрика 100 — низкий приоритет)
|
||||||
|
// ВАЖНО: Тебе нужно знать IP шлюза твоего eth0.
|
||||||
|
// Если ты не знаешь его заранее, можешь попробовать вытащить его из `ip route`
|
||||||
|
// или просто оставить как есть, если eth0 — единственный физический интерфейс.
|
||||||
|
let _ = Command::new("sudo")
|
||||||
|
.args(&[
|
||||||
|
"ip",
|
||||||
|
"route",
|
||||||
|
"add",
|
||||||
|
"default",
|
||||||
|
"via",
|
||||||
|
"172.18.144.1",
|
||||||
|
"dev",
|
||||||
|
"eth0",
|
||||||
|
"metric",
|
||||||
|
"100",
|
||||||
|
])
|
||||||
|
.status();
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Маршрутизация настроена: tun0 (metric 1) -> основной, eth0 (metric 100) -> резервный"
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_dns_redirection(&self) -> io::Result<()> {
|
||||||
|
// 1. Создаем временный файл resolv.conf
|
||||||
|
// Мы говорим системе: "Твой DNS-сервер теперь 10.0.0.1" (твой TUN-IP)
|
||||||
|
let _ = std::fs::write("/tmp/resolv.conf.netrunner", "nameserver 10.0.0.2\n");
|
||||||
|
|
||||||
|
// 2. Применяем его (для Linux/systemd)
|
||||||
|
let _ = std::process::Command::new("sudo")
|
||||||
|
.args(&["cp", "/tmp/resolv.conf.netrunner", "/etc/resolv.conf"])
|
||||||
|
.status();
|
||||||
|
|
||||||
|
info!("DNS перенаправлен на 10.0.0.1");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,14 +15,21 @@ use tokio::{
|
|||||||
use tracing::{error, info, instrument}; // Импортируем макросы
|
use tracing::{error, info, instrument}; // Импортируем макросы
|
||||||
|
|
||||||
pub struct Network {
|
pub struct Network {
|
||||||
|
host: String,
|
||||||
port: u16,
|
port: u16,
|
||||||
role: ConnectionRole,
|
role: ConnectionRole,
|
||||||
remote_proxy_addr: Option<String>,
|
remote_proxy_addr: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Network {
|
impl Network {
|
||||||
pub fn new(port: u16, role: ConnectionRole, remote_proxy_addr: Option<String>) -> Self {
|
pub fn new(
|
||||||
|
host: String,
|
||||||
|
port: u16,
|
||||||
|
role: ConnectionRole,
|
||||||
|
remote_proxy_addr: Option<String>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
host,
|
||||||
port,
|
port,
|
||||||
role,
|
role,
|
||||||
remote_proxy_addr,
|
remote_proxy_addr,
|
||||||
@@ -32,7 +39,7 @@ impl Network {
|
|||||||
// Добавляем инструмент, чтобы видеть параметры запуска сети в логах
|
// Добавляем инструмент, чтобы видеть параметры запуска сети в логах
|
||||||
#[instrument(skip(self), fields(role = ?self.role, port = self.port))]
|
#[instrument(skip(self), fields(role = ?self.role, port = self.port))]
|
||||||
pub async fn run(&self) {
|
pub async fn run(&self) {
|
||||||
let addr = format!("127.0.0.1:{}", self.port);
|
let addr = format!("{}:{}", self.host, self.port);
|
||||||
|
|
||||||
match self.role {
|
match self.role {
|
||||||
ConnectionRole::Client => {
|
ConnectionRole::Client => {
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ struct Args {
|
|||||||
fn main() {
|
fn main() {
|
||||||
logger_init();
|
logger_init();
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let net = Network::new(args.port, ConnectionRole::Server, None);
|
let net = Network::new(args.host, args.port, ConnectionRole::Server, None);
|
||||||
|
|
||||||
// Создаем движок (Runtime)
|
// Создаем движок (Runtime)
|
||||||
let rt = tokio::runtime::Runtime::new().expect("Failed to create Tokio runtime");
|
let rt = tokio::runtime::Runtime::new().expect("Failed to create Tokio runtime");
|
||||||
|
|||||||
Reference in New Issue
Block a user