diff --git a/src/sniffing/dns/dnsfaker.rs b/src/sniffing/dns/dnsfaker.rs new file mode 100644 index 0000000..e05f0af --- /dev/null +++ b/src/sniffing/dns/dnsfaker.rs @@ -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, + resolver: Option, +} + +pub trait FakeIPOptions { + fn add_new(&mut self, domain: String) -> Ipv4Addr; + async fn add_real_ip( + &mut self, + domain: String, + ip_type: IPStrategies, + ) -> Result; + 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 { + 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) + } +} diff --git a/src/sniffing/dns/mod.rs b/src/sniffing/dns/mod.rs new file mode 100644 index 0000000..40fbed1 --- /dev/null +++ b/src/sniffing/dns/mod.rs @@ -0,0 +1 @@ +pub mod dnsfaker; diff --git a/src/sniffing/headers.rs b/src/sniffing/headers.rs index c68eb50..8dab2c0 100644 --- a/src/sniffing/headers.rs +++ b/src/sniffing/headers.rs @@ -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 { - // - V4 { - src_ip: Ipv4, - src_port: Port, - dst_ip: Ipv4, - dst_port: Port, - protocol: Protocol, - dns: bool, - }, - // - 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; -type SniffedPacket = Result>; -type Packet = [u8]; - pub fn sniff_raw_packets(packet: &Packet) -> SniffedPacket { let ver = packet[0] >> 4; match ver { diff --git a/src/sniffing/mod.rs b/src/sniffing/mod.rs index dec0be3..9bb5c06 100644 --- a/src/sniffing/mod.rs +++ b/src/sniffing/mod.rs @@ -1,2 +1,4 @@ +mod dns; pub mod headers; mod metadata; +pub mod types; diff --git a/src/sniffing/sniffer.rs b/src/sniffing/sniffer.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/sniffing/sniffer.rs @@ -0,0 +1 @@ + diff --git a/src/sniffing/types.rs b/src/sniffing/types.rs new file mode 100644 index 0000000..2db7291 --- /dev/null +++ b/src/sniffing/types.rs @@ -0,0 +1,42 @@ +#[derive(Debug, PartialEq)] +pub enum PacketInfo { + // + V4 { + src_ip: Ipv4, + src_port: Port, + dst_ip: Ipv4, + dst_port: Port, + protocol: Protocol, + dns: bool, + }, + // + 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; +pub type SniffedPacket = Result>; +pub type Packet = [u8];