p2pnet/hosts.rs: refactor filterring, debug logging added

This commit is contained in:
aggstam
2022-10-07 14:14:41 +03:00
parent fdcc7b11bd
commit fac5cf0c05

View File

@@ -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<Url>) {
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<Url>) {
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<Url>) -> Vec<Url> {
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<Ipv4Net>,
ipv6_range: &IpRange<Ipv6Net>,
input_addrs: Vec<Url>,
) -> Vec<Url> {
let mut filtered = vec![];
) -> FxHashMap<Url, Vec<IpAddr>> {
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<Url>) -> Vec<Url> {
fn filter_non_resolving(
connection_addr: Url,
input_addrs: FxHashMap<Url, Vec<IpAddr>>,
) -> Vec<Url> {
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<Url>) -> Vec<Url>
}
}
}
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<Url>) -> Vec<Url>
}
// 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
}