From fac5cf0c05edd145c7dfa13a7fdeeaaa70788505 Mon Sep 17 00:00:00 2001 From: aggstam Date: Fri, 7 Oct 2022 14:14:41 +0300 Subject: [PATCH] p2pnet/hosts.rs: refactor filterring, debug logging added --- src/net/hosts.rs | 118 +++++++++++++++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 39 deletions(-) diff --git a/src/net/hosts.rs b/src/net/hosts.rs index e089353c1..bb03f4019 100644 --- a/src/net/hosts.rs +++ b/src/net/hosts.rs @@ -1,9 +1,10 @@ use async_std::sync::{Arc, Mutex}; use std::net::IpAddr; -use fxhash::FxHashSet; +use fxhash::{FxHashMap, FxHashSet}; use ipnet::{Ipv4Net, Ipv6Net}; use iprange::IpRange; +use log::debug; use url::Url; use super::constants::{IP4_PRIV_RANGES, IP6_PRIV_RANGES, LOCALNET}; @@ -37,32 +38,39 @@ impl Hosts { /// Add a new host to the host list, after filtering. pub async fn store(&self, input_addrs: Vec) { + debug!(target: "net", "hosts::store() [Start]"); let addrs = if !self.localnet { let filtered = filter_localnet(input_addrs); - filter_invalid(&self.ipv4_range, &self.ipv6_range, filtered) + let filtered = filter_invalid(&self.ipv4_range, &self.ipv6_range, filtered); + filtered.into_iter().map(|(k, _)| k).collect() } else { + debug!(target: "net", "hosts::store() [Localnet mode, skipping filterring.]"); input_addrs }; let mut addrs_map = self.addrs.lock().await; for addr in addrs { addrs_map.insert(addr); } + debug!(target: "net", "hosts::store() [End]"); } /// Add a new hosts external adders to the host list, after filtering and verifying /// the address url resolves to the provided connection address. pub async fn store_ext(&self, connection_addr: Url, input_addrs: Vec) { + debug!(target: "net", "hosts::store_ext() [Start]"); let addrs = if !self.localnet { let filtered = filter_localnet(input_addrs); let filtered = filter_invalid(&self.ipv4_range, &self.ipv6_range, filtered); filter_non_resolving(connection_addr, filtered) } else { + debug!(target: "net", "hosts::store_ext() [Localnet mode, skipping filterring.]"); input_addrs }; let mut addrs_map = self.addrs.lock().await; for addr in addrs { addrs_map.insert(addr); } + debug!(target: "net", "hosts::store_ext() [End]"); } /// Return the list of hosts. @@ -83,18 +91,24 @@ impl Hosts { /// Auxiliary function to filter localnet hosts. fn filter_localnet(input_addrs: Vec) -> Vec { + debug!(target: "net", "hosts::filter_localnet() [Input addresses: {:?}]", input_addrs); let mut filtered = vec![]; for addr in &input_addrs { match addr.host_str() { Some(host_str) => { if LOCALNET.contains(&host_str) { + debug!(target: "net", "hosts::filter_localnet() [Filtered LOCALNET host_str: {}]", host_str); continue } } - None => continue, + None => { + debug!(target: "net", "hosts::filter_localnet() [Filtered None host_str for addr: {}]", addr); + continue + } } filtered.push(addr.clone()); } + debug!(target: "net", "hosts::filter_localnet() [Filtered addresses: {:?}]", filtered); filtered } @@ -103,58 +117,80 @@ fn filter_invalid( ipv4_range: &IpRange, ipv6_range: &IpRange, input_addrs: Vec, -) -> Vec { - let mut filtered = vec![]; +) -> FxHashMap> { + debug!(target: "net", "hosts::filter_invalid() [Input addresses: {:?}]", input_addrs); + let mut filtered = FxHashMap::default(); for addr in &input_addrs { // Discard domainless Urls let domain = match addr.domain() { Some(d) => d, - None => continue, + None => { + debug!(target: "net", "hosts::filter_invalid() [Filtered domainless url: {}]", addr); + continue + } }; // Validate onion domain if domain.ends_with(".onion") && is_valid_onion(domain) { - filtered.push(addr.clone()); + filtered.insert(addr.clone(), vec![]); continue } // Validate normal domain - if let Ok(socket_addrs) = addr.socket_addrs(|| None) { - // Check if domain resolved to anything - if socket_addrs.is_empty() { - continue - } - // Checking resolved IP validity - let mut valid = true; - for i in socket_addrs { - match i.ip() { - IpAddr::V4(a) => { - if ipv4_range.contains(&a) { - valid = false; - break + match addr.socket_addrs(|| None) { + Ok(socket_addrs) => { + // Check if domain resolved to anything + if socket_addrs.is_empty() { + debug!(target: "net", "hosts::filter_invalid() [Filtered unresolvable url: {}]", addr); + continue + } + // Checking resolved IP validity + let mut resolves = vec![]; + for i in socket_addrs { + let ip = i.ip(); + match ip { + IpAddr::V4(a) => { + if ipv4_range.contains(&a) { + debug!(target: "net", "hosts::filter_invalid() [Filtered invalid ip: {}]", a); + continue + } + resolves.push(ip); } - } - IpAddr::V6(a) => { - if ipv6_range.contains(&a) { - valid = false; - break + IpAddr::V6(a) => { + if ipv6_range.contains(&a) { + debug!(target: "net", "hosts::filter_invalid() [Filtered invalid ip: {}]", a); + continue + } + resolves.push(ip); } } } + if resolves.is_empty() { + debug!(target: "net", "hosts::filter_invalid() [Filtered unresolvable url: {}]", addr); + continue + } + filtered.insert(addr.clone(), resolves); } - if valid { - filtered.push(addr.clone()); + Err(err) => { + debug!(target: "net", "hosts::filter_invalid() [Filtered Err(socket_addrs) for url {}: {}]", addr, err) } } } + debug!(target: "net", "hosts::filter_invalid() [Filtered addresses: {:?}]", filtered); filtered } /// Auxiliary function to filter unresolvable hosts, based on provided connection addr (excluding onion). -fn filter_non_resolving(connection_addr: Url, input_addrs: Vec) -> Vec { +fn filter_non_resolving( + connection_addr: Url, + input_addrs: FxHashMap>, +) -> Vec { + debug!(target: "net", "hosts::filter_non_resolving() [Input addresses: {:?}]", input_addrs); + debug!(target: "net", "hosts::filter_non_resolving() [Connection address: {}]", connection_addr); let connection_domain = connection_addr.domain().unwrap(); // Validate connection onion domain if connection_domain.ends_with(".onion") && !is_valid_onion(connection_domain) { + debug!(target: "net", "hosts::filter_non_resolving() [Tor connection detected, skipping filterring.]"); return vec![] } @@ -171,10 +207,12 @@ fn filter_non_resolving(connection_addr: Url, input_addrs: Vec) -> Vec } } } + debug!(target: "net", "hosts::filter_non_resolving() [ipv4_range: {:?}]", ipv4_range); + debug!(target: "net", "hosts::filter_non_resolving() [ipv6_range: {:?}]", ipv6_range); // Filter input addresses let mut filtered = vec![]; - for addr in input_addrs { + for (addr, resolves) in &input_addrs { // Keep valid onion domains let addr_domain = addr.domain().unwrap(); if addr_domain.ends_with(".onion") && addr_domain == connection_domain { @@ -183,28 +221,30 @@ fn filter_non_resolving(connection_addr: Url, input_addrs: Vec) -> Vec } // Checking IP validity - let mut valid = true; - let socket_addrs = addr.socket_addrs(|| None).unwrap(); - for i in socket_addrs { - match i.ip() { + let mut valid = false; + for ip in resolves { + match ip { IpAddr::V4(a) => { - if !ipv4_range.contains(&a) { - valid = false; + if ipv4_range.contains(&a) { + valid = true; break } } IpAddr::V6(a) => { - if !ipv6_range.contains(&a) { - valid = false; + if ipv6_range.contains(&a) { + valid = true; break } } } } - if valid { - filtered.push(addr.clone()); + if !valid { + debug!(target: "net", "hosts::filter_non_resolving() [Filtered unresolvable url: {}]", addr); + continue } + filtered.push(addr.clone()); } + debug!(target: "net", "hosts::filter_non_resolving() [Filtered addresses: {:?}]", filtered); filtered }