Implemented hosts-file support. You can resolve local names or block ads on DNS level!
This commit is contained in:
+3586
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"]
|
#forwarders = ["[301:2522::53]:53", "[303:8b1a::53]:53"]
|
||||||
# Cloudflare servers
|
# Cloudflare servers
|
||||||
#forwarders = ["1.1.1.1:53", "1.0.0.1:53"]
|
#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 options
|
||||||
[mining]
|
[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 resolve;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod filter;
|
pub mod filter;
|
||||||
|
pub mod hosts;
|
||||||
|
|
||||||
mod netutil;
|
mod netutil;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::env;
|
||||||
|
|
||||||
use crate::{Context, Settings};
|
use crate::{Context, Settings};
|
||||||
use crate::blockchain::filter::BlockchainFilter;
|
use crate::blockchain::filter::BlockchainFilter;
|
||||||
@@ -6,6 +7,7 @@ use crate::dns::server::{DnsServer, DnsUdpServer, DnsTcpServer};
|
|||||||
use crate::dns::context::{ServerContext, ResolveStrategy};
|
use crate::dns::context::{ServerContext, ResolveStrategy};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use log::{debug, error, info, LevelFilter, trace, warn};
|
use log::{debug, error, info, LevelFilter, trace, warn};
|
||||||
|
use crate::dns::hosts::HostsFilter;
|
||||||
|
|
||||||
/// Starts UDP and TCP DNS-servers
|
/// Starts UDP and TCP DNS-servers
|
||||||
pub fn start_dns_server(context: &Arc<Mutex<Context>>, settings: &Settings) {
|
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 }
|
true => { ResolveStrategy::Recursive }
|
||||||
false => { ResolveStrategy::Forward { upstreams: settings.dns.forwarders.clone() } }
|
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)));
|
server_context.filters.push(Box::new(BlockchainFilter::new(context)));
|
||||||
match server_context.initialize() {
|
match server_context.initialize() {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
|
|||||||
+6
-2
@@ -350,10 +350,14 @@ fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Pe
|
|||||||
let mut context = context.lock().unwrap();
|
let mut context = context.lock().unwrap();
|
||||||
let blocks_count = context.chain.height();
|
let blocks_count = context.chain.height();
|
||||||
context.bus.post(crate::event::Event::NetworkStatus { nodes: active_count + 1, blocks: blocks_count });
|
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.chain.update_max_height(height);
|
||||||
context.bus.post(crate::event::Event::Syncing { have: my_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 {
|
} else {
|
||||||
State::message(Message::GetPeers)
|
State::message(Message::GetPeers)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -78,6 +78,8 @@ pub struct Dns {
|
|||||||
#[serde(default = "default_threads")]
|
#[serde(default = "default_threads")]
|
||||||
pub threads: usize,
|
pub threads: usize,
|
||||||
pub forwarders: Vec<String>,
|
pub forwarders: Vec<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub hosts: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Dns {
|
impl Default for Dns {
|
||||||
@@ -85,7 +87,8 @@ impl Default for Dns {
|
|||||||
Dns {
|
Dns {
|
||||||
listen: String::from("127.0.0.1:53"),
|
listen: String::from("127.0.0.1:53"),
|
||||||
threads: 20,
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user