From e806cf5612157f6e00ea789b3d330f6c4ecff1c2 Mon Sep 17 00:00:00 2001 From: Revertron Date: Wed, 31 Mar 2021 16:50:22 +0200 Subject: [PATCH] Added config option to ignore all nodes except from Yggdrasil. --- Cargo.toml | 2 +- alfis.toml | 24 +++++++++++------------- src/commons/mod.rs | 30 +++++++++++++++++++++++++++++- src/p2p/network.rs | 21 ++++++++++++++------- src/p2p/peers.rs | 14 +++++++++++--- src/settings.rs | 43 ++++++++++++++++++++++++++++++++----------- 6 files changed, 98 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6f9bd84..924a74a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "alfis" -version = "0.3.6" +version = "0.3.7" authors = ["Revertron "] edition = "2018" build = "build.rs" diff --git a/alfis.toml b/alfis.toml index 7285b69..c1dc974 100644 --- a/alfis.toml +++ b/alfis.toml @@ -1,35 +1,33 @@ -# Main settings - # The hash of first block in a chain to know with which nodes to work origin = "00000102C2F9BFD2803284D93327F089D60FC72A06F19AF2384567F2646B8348" # A path to your key file to load autamatically key_file = "default.key" + +# Network settings +[net] +# All bootstap nodes +peers = ["test-ip4.alfis.name:4244", "test-ip6.alfis.name:4244"] # Your node will listen on that address for other nodes to connect listen = "[::]:4244" # Set true if you want your IP to participate in peer-exchange, or false otherwise public = true - -# Bootstrap nodes - -# All bootstap nodes -#peers = ["test-ip4.alfis.name:4244", "test-ip6.alfis.name:4244"] -# Yggdrasil nodes only -peers = ["test-ip6.alfis.name:4244"] +# Allow connections to/from Yggdrasil only (https://yggdrasil-network.github.io) +yggdrasil_only = false # DNS server options [dns] # Your DNS resolver will be listening on this address and port (Usual port is 53) -listen = "127.0.0.1:5300" +listen = "127.0.0.1:53" # How many threads to spawn by DNS server threads = 20 # AdGuard DNS servers to filter ads and trackers -#forwarders = ["94.140.14.14:53", "94.140.15.15:53"] +forwarders = ["94.140.14.14:53", "94.140.15.15:53"] # Wyrd servers -forwarders = ["[301:2522::53]:53", "[303:8b1a::53]:53"] +#forwarders = ["[301:2522::53]:53", "[303:8b1a::53]:53"] # Cloudflare servers #forwarders = ["1.1.1.1:53", "1.0.0.1:53"] #Mining options [mining] -# How many CPU threads to spawn for mining +# How many CPU threads to spawn for mining, zero = number of cores threads = 0 \ No newline at end of file diff --git a/src/commons/mod.rs b/src/commons/mod.rs index ccc4f8b..4190587 100644 --- a/src/commons/mod.rs +++ b/src/commons/mod.rs @@ -3,6 +3,7 @@ use rand::Rng; pub mod constants; pub use constants::*; +use std::net::IpAddr; /// Convert bytes array to HEX format pub fn to_hex(buf: &[u8]) -> String { @@ -80,9 +81,20 @@ pub fn random_string(length: usize) -> String { result } +/// Checks if this IP is from Yggdrasil network +/// https://yggdrasil-network.github.io +pub fn is_yggdrasil(addr: &IpAddr) -> bool { + if let IpAddr::V6(ipv6) = addr { + let first_byte = ipv6.octets()[0]; + return first_byte == 2 || first_byte == 3; + } + false +} + #[cfg(test)] mod test { - use crate::check_domain; + use crate::{check_domain, is_yggdrasil}; + use std::net::IpAddr; #[test] fn test_check_domain() { @@ -98,4 +110,20 @@ mod test { assert!(!check_domain(".ab.c", true)); assert!(!check_domain("ab.c-", true)); } + + #[test] + fn test_is_yggdrasil() { + let addr: IpAddr = "200::1".parse().unwrap(); + assert!(is_yggdrasil(&addr)); + let addr: IpAddr = "226::1".parse().unwrap(); + assert!(is_yggdrasil(&addr)); + let addr: IpAddr = "300::1".parse().unwrap(); + assert!(is_yggdrasil(&addr)); + let addr: IpAddr = "326::1".parse().unwrap(); + assert!(is_yggdrasil(&addr)); + let addr: IpAddr = "2001::1".parse().unwrap(); + assert!(!is_yggdrasil(&addr)); + let addr: IpAddr = "2201::1".parse().unwrap(); + assert!(!is_yggdrasil(&addr)); + } } diff --git a/src/p2p/network.rs b/src/p2p/network.rs index d62751c..80124db 100644 --- a/src/p2p/network.rs +++ b/src/p2p/network.rs @@ -15,7 +15,7 @@ use log::{trace, debug, info, warn, error}; use std::net::{SocketAddr, IpAddr, SocketAddrV4, Shutdown}; use std::collections::HashSet; -use crate::{Context, Block, p2p::Message, p2p::State, p2p::Peer, p2p::Peers, Bytes}; +use crate::{Context, Block, p2p::Message, p2p::State, p2p::Peer, p2p::Peers, Bytes, is_yggdrasil}; use crate::blockchain::enums::BlockQuality; use crate::commons::CHAIN_VERSION; use std::sync::atomic::{AtomicBool, Ordering}; @@ -36,9 +36,9 @@ impl Network { } pub fn start(&mut self) -> Result<(), String> { - let (listen_addr, peers_addrs) = { + let (listen_addr, peers_addrs, yggdrasil_only) = { let c = self.context.lock().unwrap(); - (c.settings.listen.clone(), c.settings.peers.clone()) + (c.settings.net.listen.clone(), c.settings.net.peers.clone(), c.settings.net.yggdrasil_only) }; let running = Arc::new(AtomicBool::new(true)); @@ -61,7 +61,7 @@ impl Network { // States of peer connections, and some data to send when sockets become writable let mut peers = Peers::new(); // Starting peer connections to bootstrap nodes - peers.connect_peers(peers_addrs, &poll.registry(), &mut unique_token); + peers.connect_peers(peers_addrs, &poll.registry(), &mut unique_token, yggdrasil_only); loop { // Poll Mio for events, blocking until we get an event. @@ -89,6 +89,13 @@ impl Network { } } + if yggdrasil_only && !is_yggdrasil(&address.ip()) { + info!("Dropping connection from Internet"); + stream.shutdown(Shutdown::Both).unwrap_or_else(|e|{ warn!("Error in shutdown, {}", e); }); + let _ = poll.registry().reregister(&mut server, SERVER, Interest::READABLE); + continue; + } + // If connection is from the same IP and not from loopback we ignore it to avoid connection loops let local_ip = stream.local_addr().unwrap_or("0.0.0.0:0".parse().unwrap()); if !local_ip.ip().is_loopback() && local_ip.ip() == address.ip() { @@ -104,7 +111,7 @@ impl Network { } Err(_) => {} } - poll.registry().reregister(&mut server, SERVER, Interest::READABLE).expect("Error reregistering server"); + let _ = poll.registry().reregister(&mut server, SERVER, Interest::READABLE); } token => { if !handle_connection_event(Arc::clone(&context), &mut peers, &poll.registry(), &event) { @@ -130,7 +137,7 @@ impl Network { }; mine_locker_block(Arc::clone(&context)); peers.send_pings(poll.registry(), height, hash); - peers.connect_new_peers(poll.registry(), &mut unique_token); + peers.connect_new_peers(poll.registry(), &mut unique_token, yggdrasil_only); } info!("Network loop finished"); }); @@ -209,7 +216,7 @@ fn handle_connection_event(context: Arc>, peers: &mut Peers, regi debug!("Sending hello to {}", &peer.get_addr()); let data: String = { let c = context.lock().unwrap(); - let message = Message::hand(&c.app_version, &c.settings.origin, CHAIN_VERSION, c.settings.public, peer.get_rand()); + let message = Message::hand(&c.app_version, &c.settings.origin, CHAIN_VERSION, c.settings.net.public, peer.get_rand()); serde_json::to_string(&message).unwrap() }; send_message(peer.get_stream(), &data.into_bytes()).unwrap_or_else(|e| warn!("Error sending hello {}", e)); diff --git a/src/p2p/peers.rs b/src/p2p/peers.rs index 4e46037..0958b07 100644 --- a/src/p2p/peers.rs +++ b/src/p2p/peers.rs @@ -9,7 +9,7 @@ use rand::random; use rand::seq::IteratorRandom; #[allow(unused_imports)] use log::{trace, debug, info, warn, error}; -use crate::Bytes; +use crate::{Bytes, is_yggdrasil}; use crate::commons::MAX_RECONNECTS; pub struct Peers { @@ -252,7 +252,7 @@ impl Peers { } } - pub fn connect_new_peers(&mut self, registry: &Registry, unique_token: &mut Token) { + pub fn connect_new_peers(&mut self, registry: &Registry, unique_token: &mut Token, yggdrasil_only: bool) { if self.new_peers.is_empty() { return; } @@ -260,6 +260,10 @@ impl Peers { if self.ignored.contains(&addr.ip()) { continue; } + if yggdrasil_only && !is_yggdrasil(&addr.ip()) { + info!("Ignoring not Yggdrasil address '{}'", &addr.ip()); + continue; + } match TcpStream::connect(addr.clone()) { Ok(mut stream) => { info!("Created connection to peer {}", &addr); @@ -278,7 +282,7 @@ impl Peers { } /// Connecting to configured (bootstrap) peers - pub fn connect_peers(&mut self, peers_addrs: Vec, registry: &Registry, unique_token: &mut Token) { + pub fn connect_peers(&mut self, peers_addrs: Vec, registry: &Registry, unique_token: &mut Token, yggdrasil_only: bool) { for peer in peers_addrs.iter() { let addresses: Vec = match peer.to_socket_addrs() { Ok(peers) => { peers.collect() } @@ -286,6 +290,10 @@ impl Peers { }; for addr in addresses { + if yggdrasil_only && !is_yggdrasil(&addr.ip()) { + info!("Ignoring not Yggdrasil address '{}'", &addr.ip()); + continue; + } match TcpStream::connect(addr.clone()) { Ok(mut stream) => { info!("Created connection to peer {}", &addr); diff --git a/src/settings.rs b/src/settings.rs index 18a43f5..1b9ba57 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -13,12 +13,8 @@ pub struct Settings { pub origin: String, #[serde(default)] pub key_file: String, - #[serde(default = "default_listen")] - pub listen: String, #[serde(default)] - pub public: bool, - #[serde(default)] - pub peers: Vec, + pub net: Net, #[serde(default)] pub dns: Dns, #[serde(default)] @@ -66,11 +62,9 @@ impl Settings { impl Default for Settings { fn default() -> Self { Self { - origin: "".to_string(), - key_file: "".to_string(), - listen: String::from("[::]:4244"), - public: false, - peers: vec![], + origin: String::from("00000102C2F9BFD2803284D93327F089D60FC72A06F19AF2384567F2646B8348"), + key_file: String::from("default.key"), + net: Net::default(), dns: Default::default(), mining: Mining::default() } @@ -88,7 +82,11 @@ pub struct Dns { impl Default for Dns { fn default() -> Self { - Dns { listen: String::from("0.0.0.0:53"), threads: 20, forwarders: vec!["94.140.14.14:53".to_owned(), "94.140.15.15:53".to_owned()] } + 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")] + } } } @@ -98,6 +96,29 @@ pub struct Mining { pub threads: usize } +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Net { + #[serde(default)] + pub peers: Vec, + #[serde(default = "default_listen")] + pub listen: String, + #[serde(default)] + pub public: bool, + #[serde(default)] + pub yggdrasil_only: bool, +} + +impl Default for Net { + fn default() -> Self { + Net { + peers: vec![String::from("test-ip4.alfis.name:4244"), String::from("test-ip6.alfis.name:4244")], + listen: String::from("[::]:4244"), + public: true, + yggdrasil_only: false + } + } +} + fn default_listen() -> String { String::from("[::]:4244") }