impl: started writting FakeDNS server (or 'dns hijack')

This commit is contained in:
Namilsk 2026-09-27 21:23:08 +03:00
parent 0d81bae32a
commit 927299baad
No known key found for this signature in database
GPG key ID: 2B2F0A4D870B4F9F
6 changed files with 183 additions and 43 deletions

View file

@ -0,0 +1,136 @@
use hickory_resolver::{
TokioResolver,
config::{NameServerConfig, ResolverConfig},
net::runtime::TokioRuntimeProvider,
proto::rr::IntoName,
};
use rand::RngExt;
use std::net::{IpAddr, Ipv4Addr};
use std::sync::Arc;
struct FakeIPEntry {
domain_name: String,
address: IpAddr,
}
#[derive(Debug, PartialEq, Eq)]
pub enum IPStrategies {
V4Only,
V6Only,
Any,
}
enum Protocols {
DoH,
DoU,
DoT,
DoTCP,
}
pub struct FakeIPStorage {
entries: Vec<FakeIPEntry>,
resolver: Option<TokioResolver>,
}
pub trait FakeIPOptions {
fn add_new(&mut self, domain: String) -> Ipv4Addr;
async fn add_real_ip(
&mut self,
domain: String,
ip_type: IPStrategies,
) -> Result<IpAddr, std::io::Error>;
fn init_resolver(&mut self, link: String, domain: String) -> Result<(), std::io::Error>;
}
fn generate_ip_from(network: Ipv4Addr, prefix: u32) -> Ipv4Addr {
let mut rng = rand::rng();
let network = u32::from(network);
let host_bits = 32 - prefix;
let host = rng.random_range(0..(1u32 << host_bits));
Ipv4Addr::from(network | host)
}
impl FakeIPOptions for FakeIPStorage {
fn init_resolver(&mut self, link: String, domain: String) -> Result<(), std::io::Error> {
let server_string = link.to_lowercase();
let raw_protocol: Vec<&str> = server_string.split("://").collect();
let result = match raw_protocol[0] {
"tls" => Protocols::DoT,
"tcp" => Protocols::DoTCP,
"https" => Protocols::DoH,
"udp" => Protocols::DoU,
_ => {
panic!("Wrong resolver protocol");
}
};
let ns: NameServerConfig = match result {
Protocols::DoT => {
NameServerConfig::tls(raw_protocol[1].to_ip().unwrap(), Arc::from(domain))
}
Protocols::DoTCP => NameServerConfig::tcp(raw_protocol[1].to_ip().unwrap()),
Protocols::DoU => NameServerConfig::udp(raw_protocol[1].to_ip().unwrap()),
_ => panic!("Wrong IP/domain of resolver"),
};
let config = ResolverConfig::from_parts(None, vec![], vec![ns]);
self.resolver = Some(
TokioResolver::builder_with_config(config, TokioRuntimeProvider::default())
.build()
.unwrap(),
);
Ok(())
}
fn add_new(&mut self, domain: String) -> Ipv4Addr {
let gen_ip = generate_ip_from(Ipv4Addr::new(198, 18, 0, 0), 15);
let entry = FakeIPEntry {
domain_name: domain,
address: IpAddr::V4(gen_ip),
};
self.entries.push(entry);
gen_ip
}
async fn add_real_ip(
&mut self,
domain: String,
ip_type: IPStrategies,
) -> Result<IpAddr, std::io::Error> {
let lookup = self
.resolver
.as_ref()
.unwrap()
.lookup_ip(&domain)
.await
.map_err(|e| std::io::Error::other(e))?;
let ip = lookup
.into_iter()
.find(|ip| match ip_type {
IPStrategies::V4Only => ip.is_ipv4(),
IPStrategies::V6Only => ip.is_ipv6(),
IPStrategies::Any => true,
})
.ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::AddrNotAvailable,
"No suitable IP address found",
)
})?;
self.entries.push(FakeIPEntry {
domain_name: domain,
address: ip,
});
Ok(ip)
}
}

1
src/sniffing/dns/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod dnsfaker;

View file

@ -1,47 +1,10 @@
use crate::sniffing::types::*;
use std::fmt;
use tun::Error;
// Here we will recieve bytes and try to get their destanation & apply Rules for them.
use crate::config::Config;
#[derive(Debug, PartialEq)]
pub enum Protocol {
TCP,
UDP,
Unsupported(u8),
}
type SourceV4Ip = Ipv4;
type SourceV6Ip = Ipv6;
#[derive(PartialEq, Debug)]
pub enum IpVersion {
V4,
V6,
}
type Ipv4 = [u8; 4];
type Ipv6 = [u16; 8];
type Port = u16;
#[derive(Debug, PartialEq)]
pub enum PacketInfo {
// <https://www.geeksforgeeks.org/computer-networks/what-is-ipv4/>
V4 {
src_ip: Ipv4,
src_port: Port,
dst_ip: Ipv4,
dst_port: Port,
protocol: Protocol,
dns: bool,
},
// <https://www.geeksforgeeks.org/computer-networks/internet-protocol-version-6-ipv6-header/>
V6 {
src_ip: Ipv6,
src_port: Port,
dst_ip: Ipv6,
dst_port: Port,
protocol: Protocol,
dns: bool,
},
}
impl fmt::Display for PacketInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.version() == &IpVersion::V4 {
@ -155,11 +118,6 @@ impl PacketInfo {
}
}
// TODO: move these to some appropriate file for code readability.
type GenericError = Box<dyn std::error::Error + Send + Sync + 'static>;
type SniffedPacket = Result<PacketInfo, Box<dyn std::error::Error + Send + Sync + 'static>>;
type Packet = [u8];
pub fn sniff_raw_packets(packet: &Packet) -> SniffedPacket {
let ver = packet[0] >> 4;
match ver {

View file

@ -1,2 +1,4 @@
mod dns;
pub mod headers;
mod metadata;
pub mod types;

1
src/sniffing/sniffer.rs Normal file
View file

@ -0,0 +1 @@

42
src/sniffing/types.rs Normal file
View file

@ -0,0 +1,42 @@
#[derive(Debug, PartialEq)]
pub enum PacketInfo {
// <https://www.geeksforgeeks.org/computer-networks/what-is-ipv4/>
V4 {
src_ip: Ipv4,
src_port: Port,
dst_ip: Ipv4,
dst_port: Port,
protocol: Protocol,
dns: bool,
},
// <https://www.geeksforgeeks.org/computer-networks/internet-protocol-version-6-ipv6-header/>
V6 {
src_ip: Ipv6,
src_port: Port,
dst_ip: Ipv6,
dst_port: Port,
protocol: Protocol,
dns: bool,
},
}
#[derive(Debug, PartialEq)]
pub enum Protocol {
TCP,
UDP,
Unsupported(u8),
}
pub type SourceV4Ip = Ipv4;
pub type SourceV6Ip = Ipv6;
#[derive(PartialEq, Debug)]
pub enum IpVersion {
V4,
V6,
}
pub type Ipv4 = [u8; 4];
pub type Ipv6 = [u16; 8];
pub type Port = u16;
pub type GenericError = Box<dyn std::error::Error + Send + Sync + 'static>;
pub type SniffedPacket = Result<PacketInfo, Box<dyn std::error::Error + Send + Sync + 'static>>;
pub type Packet = [u8];