Implemented hosts-file support. You can resolve local names or block ads on DNS level!

pull/13/head
Revertron 3 years ago
parent 9b3bd780a1
commit 882d826c26

File diff suppressed because it is too large Load Diff

@ -26,6 +26,8 @@ forwarders = ["94.140.14.14:53", "94.140.15.15:53"]
#forwarders = ["[301:2522::53]:53", "[303:8b1a::53]:53"]
# Cloudflare servers
#forwarders = ["1.1.1.1:53", "1.0.0.1:53"]
# Hosts file support (resolve local names or block ads)
#hosts = ["system", "adblock.txt"]
#Mining options
[mining]

@ -0,0 +1,104 @@
use std::net::IpAddr;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use crate::dns::filter::DnsFilter;
use crate::dns::protocol::{DnsPacket, QueryType, DnsRecord, TransientTtl, DnsQuestion};
const NAME_SERVER: & str = "hosts";
pub struct HostsFilter {
hosts: HashMap<String, Vec<IpAddr>>
}
impl HostsFilter {
pub fn new(filename: &str) -> Self {
let hosts = match File::open(filename) {
Ok(mut file) => {
let mut text = String::new();
file.read_to_string(&mut text).unwrap();
let mut map = HashMap::new();
let list: Vec<_> = text.split("\n").collect();
for s in list {
if s.is_empty() || s.starts_with("#") {
continue;
}
let string = s.replace('\t', " ");
let parts: Vec<_> = string.splitn(2, " ").collect();
if parts.len() != 2 {
continue;
}
let ip = parts[0].trim().to_owned();
let domain = parts[1].trim().to_owned();
if let Ok(addr) = ip.parse::<IpAddr>() {
if !domain.is_empty() {
map.entry(domain).or_insert(vec!(addr));
}
}
}
map
}
Err(..) => {
HashMap::new()
}
};
HostsFilter { hosts }
}
pub fn size(&self) -> usize {
self.hosts.len()
}
}
impl DnsFilter for HostsFilter {
fn lookup(&self, qname: &str, qtype: QueryType) -> Option<DnsPacket> {
let mut packet = DnsPacket::new();
if let Some(list) = self.hosts.get(qname) {
for addr in list {
match addr {
IpAddr::V4(addr) if qtype == QueryType::A => {
packet.answers.push(DnsRecord::A { domain: qname.to_owned(), addr: addr.clone(), ttl: TransientTtl(2) });
}
IpAddr::V6(addr) if qtype == QueryType::AAAA => {
packet.answers.push(DnsRecord::AAAA { domain: qname.to_owned(), addr: addr.clone(), ttl: TransientTtl(2) });
}
_ => {}
}
}
if !packet.answers.is_empty() {
packet.header.authoritative_answer = true;
packet.questions.push(DnsQuestion::new(String::from(qname), qtype));
packet.authorities.push(DnsRecord::NS { domain: String::from("hosts"), host: String::from(NAME_SERVER), ttl: TransientTtl(600) });
return Some(packet);
}
}
None
}
}
#[cfg(test)]
mod tests {
use crate::dns::hosts::HostsFilter;
use std::env;
#[test]
pub fn load_hosts() {
let filter = if cfg!(target_os = "windows") {
if let Ok(root) = env::var("SYSTEMROOT") {
let filename = format!("{}{}", &root, "\\System32\\drivers\\etc\\hosts");
HostsFilter::new(&filename)
} else {
unreachable!()
}
} else {
let filename = "/etc/hosts";
HostsFilter::new(filename)
};
assert!(filter.size() > 0);
}
}

@ -23,5 +23,6 @@ pub mod protocol;
pub mod resolve;
pub mod server;
pub mod filter;
pub mod hosts;
mod netutil;

@ -1,4 +1,5 @@
use std::sync::{Arc, Mutex};
use std::env;
use crate::{Context, Settings};
use crate::blockchain::filter::BlockchainFilter;
@ -6,6 +7,7 @@ use crate::dns::server::{DnsServer, DnsUdpServer, DnsTcpServer};
use crate::dns::context::{ServerContext, ResolveStrategy};
#[allow(unused_imports)]
use log::{debug, error, info, LevelFilter, trace, warn};
use crate::dns::hosts::HostsFilter;
/// Starts UDP and TCP DNS-servers
pub fn start_dns_server(context: &Arc<Mutex<Context>>, settings: &Settings) {
@ -35,6 +37,25 @@ fn create_server_context(context: Arc<Mutex<Context>>, settings: &Settings) -> A
true => { ResolveStrategy::Recursive }
false => { ResolveStrategy::Forward { upstreams: settings.dns.forwarders.clone() } }
};
// Add host filters
for host in &settings.dns.hosts {
if host == "system" {
if cfg!(target_os = "windows") {
if let Ok(root) = env::var("SYSTEMROOT") {
let filename = format!("{}{}", &root, "\\System32\\drivers\\etc\\hosts");
info!("Loading hosts from '{}'", &filename);
server_context.filters.push(Box::new(HostsFilter::new(&filename)));
}
} else {
let filename = "/etc/hosts";
info!("Loading hosts from '{}'", filename);
server_context.filters.push(Box::new(HostsFilter::new(filename)));
}
} else {
info!("Loading hosts from '{}'", &host);
server_context.filters.push(Box::new(HostsFilter::new(host)));
}
}
server_context.filters.push(Box::new(BlockchainFilter::new(context)));
match server_context.initialize() {
Ok(_) => {}

@ -350,10 +350,14 @@ fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Pe
let mut context = context.lock().unwrap();
let blocks_count = context.chain.height();
context.bus.post(crate::event::Event::NetworkStatus { nodes: active_count + 1, blocks: blocks_count });
if active_count > 3 && peer.is_higher(my_height) {
if peer.is_higher(my_height) {
context.chain.update_max_height(height);
context.bus.post(crate::event::Event::Syncing { have: my_height, height});
State::message(Message::GetBlock { index: my_height + 1 })
if active_count > 3 {
State::message(Message::GetBlock { index: my_height + 1 })
} else {
State::message(Message::GetPeers)
}
} else {
State::message(Message::GetPeers)
}

@ -78,6 +78,8 @@ pub struct Dns {
#[serde(default = "default_threads")]
pub threads: usize,
pub forwarders: Vec<String>,
#[serde(default)]
pub hosts: Vec<String>,
}
impl Default for Dns {
@ -85,7 +87,8 @@ impl Default for Dns {
Dns {
listen: String::from("127.0.0.1:53"),
threads: 20,
forwarders: vec![String::from("94.140.14.14:53"), String::from("94.140.15.15:53")]
forwarders: vec![String::from("94.140.14.14:53"), String::from("94.140.15.15:53")],
hosts: Vec::new()
}
}
}

Loading…
Cancel
Save