Skip to content
36 changes: 15 additions & 21 deletions config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use std::io::prelude::*;
use std::io::BufReader;
use std::path::PathBuf;

use p2p::types::{TESTNET_PEER_PORT, USERNET_PEER_PORT};

use crate::comments::insert_comments;
use crate::core::global;
use crate::p2p;
Expand All @@ -42,10 +44,7 @@ pub const FOREIGN_API_SECRET_FILE_NAME: &str = ".foreign_api_secret";

fn get_grin_path(chain_type: &global::ChainTypes) -> Result<PathBuf, ConfigError> {
// Check if grin dir exists
let mut grin_path = match dirs::home_dir() {
Some(p) => p,
None => PathBuf::new(),
};
let mut grin_path = dirs::home_dir().unwrap_or_else(|| PathBuf::new());
grin_path.push(GRIN_HOME);
grin_path.push(chain_type.shortname());
// Create if the default path doesn't exist
Expand Down Expand Up @@ -113,7 +112,7 @@ fn check_api_secret_files(
pub fn initial_setup_server(chain_type: &global::ChainTypes) -> Result<GlobalConfig, ConfigError> {
check_api_secret_files(chain_type, API_SECRET_FILE_NAME)?;
check_api_secret_files(chain_type, FOREIGN_API_SECRET_FILE_NAME)?;
// Use config file if current directory if it exists, .grin home otherwise
// Use config file in current directory if it exists, .grin home otherwise
if let Some(p) = check_config_current_dir(SERVER_CONFIG_FILE_NAME) {
GlobalConfig::new(p.to_str().unwrap())
} else {
Expand Down Expand Up @@ -168,7 +167,7 @@ impl GlobalConfig {
global::ChainTypes::Mainnet => {}
global::ChainTypes::Testnet => {
defaults.api_http_addr = "127.0.0.1:13413".to_owned();
defaults.p2p_config.port = 13414;
defaults.p2p_config.port = TESTNET_PEER_PORT;
defaults
.stratum_mining_config
.as_mut()
Expand All @@ -182,7 +181,7 @@ impl GlobalConfig {
}
global::ChainTypes::UserTesting => {
defaults.api_http_addr = "127.0.0.1:23413".to_owned();
defaults.p2p_config.port = 23414;
defaults.p2p_config.port = USERNET_PEER_PORT;
defaults.p2p_config.seeding_type = p2p::Seeding::None;
defaults
.stratum_mining_config
Expand Down Expand Up @@ -234,14 +233,12 @@ impl GlobalConfig {
match decoded {
Ok(gc) => {
self.members = Some(gc);
return Ok(self);
}
Err(e) => {
return Err(ConfigError::ParseError(
self.config_file_path.unwrap().to_str().unwrap().to_string(),
format!("{}", e),
));
Ok(self)
}
Err(e) => Err(ConfigError::ParseError(
self.config_file_path.unwrap().to_str().unwrap().to_string(),
format!("{}", e),
)),
}
}

Expand Down Expand Up @@ -275,27 +272,24 @@ impl GlobalConfig {

/// Enable mining
pub fn stratum_enabled(&mut self) -> bool {
return self
.members
self.members
.as_mut()
.unwrap()
.server
.stratum_mining_config
.as_mut()
.unwrap()
.enable_stratum_server
.unwrap();
.unwrap()
}

/// Serialize config
pub fn ser_config(&mut self) -> Result<String, ConfigError> {
let encoded: Result<String, toml::ser::Error> =
toml::to_string(self.members.as_mut().unwrap());
match encoded {
Ok(enc) => return Ok(enc),
Err(e) => {
return Err(ConfigError::SerializationError(format!("{}", e)));
}
Ok(enc) => Ok(enc),
Err(e) => Err(ConfigError::SerializationError(format!("{}", e))),
}
}

Expand Down
27 changes: 21 additions & 6 deletions p2p/src/peers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use crate::msg::PeerAddrs;
use crate::peer::Peer;
use crate::store::{PeerData, PeerStore, State};
use crate::types::{
Capabilities, ChainAdapter, Error, NetAdapter, P2PConfig, PeerAddr, PeerInfo, ReasonForBan,
TxHashSetRead, MAX_PEER_ADDRS,
is_private_ip, Capabilities, ChainAdapter, Error, NetAdapter, P2PConfig, PeerAddr, PeerInfo,
ReasonForBan, TxHashSetRead, MAX_PEER_ADDRS,
};
use crate::util::secp::pedersen::RangeProof;
use chrono::prelude::*;
Expand Down Expand Up @@ -86,9 +86,14 @@ impl Peers {
peers.insert(peer_data.addr, peer);
}
}
debug!("Saving newly connected peer {}.", peer_data.addr);
if let Err(e) = self.save_peer(&peer_data) {
error!("Could not save connected peer address: {:?}", e);
// Do not save private peer.
if !is_private_ip(&peer_data.addr.0.ip()) {
debug!("Saving newly connected peer {}.", peer_data.addr);
if let Err(e) = self.save_peer(&peer_data) {
error!("Could not save connected peer address: {:?}", e);
}
} else {
debug!("Do not save connected private peer {}.", peer_data.addr);
}
Ok(())
}
Expand Down Expand Up @@ -180,6 +185,12 @@ impl Peers {
// check if peer exist
self.get_peer(peer_addr)?;
if self.is_banned(peer_addr) {
// delete banned private peer
if is_private_ip(&peer_addr.0.ip()) {
if let Ok(mut batch) = self.store.iter_batch() {
batch.delete_peer(peer_addr)?;
Comment thread
ardocrat marked this conversation as resolved.
Outdated
}
}
self.update_state(peer_addr, State::Healthy)
Comment thread
ardocrat marked this conversation as resolved.
Outdated
} else {
Err(Error::PeerNotBanned)
Expand Down Expand Up @@ -328,7 +339,11 @@ impl Peers {

/// Saves updated information about mulitple peers in batch
pub fn save_peers(&self, p: Vec<PeerData>) -> Result<(), Error> {
self.store.save_peers(p).map_err(From::from)
let public_peers = p
.iter()
.filter(|p| !is_private_ip(&p.addr.0.ip()))
.collect::<Vec<&PeerData>>();
self.store.save_peers(public_peers).map_err(From::from)
}

/// Updates the state of a peer in store
Expand Down
9 changes: 8 additions & 1 deletion p2p/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ impl PeerStore {
batch.commit()
}

pub fn save_peers(&self, p: Vec<PeerData>) -> Result<(), Error> {
pub fn save_peers(&self, p: Vec<&PeerData>) -> Result<(), Error> {
let mut batch = self.db.batch()?;
for pd in p {
debug!("save_peers: {:?} marked {:?}", pd.addr, pd.flags);
Expand Down Expand Up @@ -233,6 +233,13 @@ impl<'a> PeersIterBatch<'a> {
Ok(peers)
}

/// Delete a peer by provided address.
pub fn delete_peer(&mut self, peer_addr: PeerAddr) -> Result<(), Error> {
Comment thread
ardocrat marked this conversation as resolved.
Outdated
let key = peer_addr.as_key();
self.db.delete(Some(PEER_PREFIX), key.as_bytes())?;
Ok(())
}

/// Deletes peers from the storage that satisfy some condition `predicate`
pub fn delete_peers<F>(mut self, predicate: F) -> Result<(), Error>
where
Expand Down
116 changes: 82 additions & 34 deletions p2p/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ use crate::msg::PeerAddrs;
use crate::util::secp::pedersen::RangeProof;
use crate::util::RwLock;

/// Default main network peer port.
pub const MAINNET_PEER_PORT: u16 = 3414;
/// Default test network peer port.
pub const TESTNET_PEER_PORT: u16 = 13414;
/// Default user network peer port.
pub const USERNET_PEER_PORT: u16 = 23414;

/// Maximum number of block headers a peer should ever send
pub const MAX_BLOCK_HEADERS: u32 = 512;

Expand Down Expand Up @@ -207,10 +214,10 @@ impl<'de> Deserialize<'de> for PeerAddrs {
}

impl std::hash::Hash for PeerAddr {
/// If loopback address then we care about ip and port.
/// If private address then we care about ip and port.
/// If regular address then we only care about the ip and ignore the port.
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
if self.0.ip().is_loopback() {
if is_private_ip(&self.0.ip()) {
self.0.hash(state);
} else {
self.0.ip().hash(state);
Expand All @@ -219,37 +226,89 @@ impl std::hash::Hash for PeerAddr {
}

impl PartialEq for PeerAddr {
/// If loopback address then we care about ip and port.
/// If private address then we care about ip and port.
/// If regular address then we only care about the ip and ignore the port.
fn eq(&self, other: &PeerAddr) -> bool {
if self.0.ip().is_loopback() {
if is_private_ip(&self.0.ip()) {
self.0 == other.0
} else {
self.0.ip() == other.0.ip()
}
}
}

/// Check if IP address is private.
/// Implementation taken from `core::net:ip_addr` while `is_global` is unstable.
pub fn is_private_ip(ip: &IpAddr) -> bool {
match ip {
IpAddr::V4(ip) => {
ip.is_private() || ip.is_loopback() || ip.is_link_local() || ip.is_documentation()
// addresses reserved for future protocols (`192.0.0.0/24`)
// .9 and .10 are documented as globally reachable so they're excluded
|| (
ip.octets()[0] == 192 && ip.octets()[1] == 0 && ip.octets()[2] == 0
&& ip.octets()[3] != 9 && ip.octets()[3] != 10
// this address is part of the Shared Address Space defined in
// [IETF RFC 6598] (`100.64.0.0/10`).
|| ip.octets()[0] == 100 && (ip.octets()[1] & 0b1100_0000 == 0b0100_0000)
)
}
IpAddr::V6(ip) => {
ip.is_loopback() || ip.is_unspecified()
// IPv4-mapped Address (`::ffff:0:0/96`)
|| matches!(ip.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
// IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
|| matches!(ip.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
// Discard-Only Address Block (`100::/64`)
|| matches!(ip.segments(), [0x100, 0, 0, 0, _, _, _, _])
// IETF Protocol Assignments (`2001::/23`)
|| (matches!(ip.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
&& !(
// Port Control Protocol Anycast (`2001:1::1`)
u128::from_be_bytes(ip.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
// Traversal Using Relays around NAT Anycast (`2001:1::2`)
|| u128::from_be_bytes(ip.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
// AMT (`2001:3::/32`)
|| matches!(ip.segments(), [0x2001, 3, _, _, _, _, _, _])
// AS112-v6 (`2001:4:112::/48`)
|| matches!(ip.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
// ORCHIDv2 (`2001:20::/28`)
// Drone Remote ID Protocol Entity Tags (DETs) Prefix (`2001:30::/28`)`
|| matches!(ip.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x3F)
))
// 6to4 (`2002::/16`) – it's not explicitly documented as globally reachable,
// IANA says N/A.
|| matches!(ip.segments(), [0x2002, _, _, _, _, _, _, _])
// Segment Routing (SRv6) SIDs (`5f00::/16`)
|| matches!(ip.segments(), [0x5f00, ..])
|| ip.is_unique_local()
|| ip.is_unicast_link_local()
}
}
}

impl Eq for PeerAddr {}

impl std::fmt::Display for PeerAddr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl fmt::Display for PeerAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}

impl PeerAddr {
/// Convenient way of constructing a new peer_addr from an ip_addr
/// defaults to port 3414 on mainnet and 13414 on testnet.
/// Convenient way of constructing a new peer address from an ip address.
pub fn from_ip(addr: IpAddr) -> PeerAddr {
let port = if global::is_testnet() { 13414 } else { 3414 };
let port = if global::is_testnet() {
TESTNET_PEER_PORT
} else {
MAINNET_PEER_PORT
};
PeerAddr(SocketAddr::new(addr, port))
}

/// If the ip is loopback then our key is "ip:port" (mainly for local usernet testing).
/// Otherwise we only care about the ip (we disallow multiple peers on the same ip address).
/// If the ip is private then our key is "ip:port".
/// Otherwise, we only care about the ip (we disallow multiple peers on the same ip address).
pub fn as_key(&self) -> String {
if self.0.ip().is_loopback() {
if is_private_ip(&self.0.ip()) {
format!("{}:{}", self.0.ip(), self.0.port())
} else {
format!("{}", self.0.ip())
Expand Down Expand Up @@ -296,7 +355,7 @@ impl Default for P2PConfig {
let ipaddr = "::".parse().unwrap();
P2PConfig {
host: ipaddr,
port: 3414,
port: MAINNET_PEER_PORT,
seeding_type: Seeding::default(),
seeds: None,
peers_allow: None,
Expand All @@ -317,42 +376,31 @@ impl Default for P2PConfig {
impl P2PConfig {
/// return ban window
pub fn ban_window(&self) -> i64 {
match self.ban_window {
Some(n) => n,
None => BAN_WINDOW,
}
self.ban_window.unwrap_or_else(|| BAN_WINDOW)
}

/// return maximum inbound peer connections count
pub fn peer_max_inbound_count(&self) -> u32 {
match self.peer_max_inbound_count {
Some(n) => n,
None => PEER_MAX_INBOUND_COUNT,
}
self.peer_max_inbound_count
.unwrap_or_else(|| PEER_MAX_INBOUND_COUNT)
}

/// return maximum outbound peer connections count
pub fn peer_max_outbound_count(&self) -> u32 {
match self.peer_max_outbound_count {
Some(n) => n,
None => PEER_MAX_OUTBOUND_COUNT,
}
self.peer_max_outbound_count
.unwrap_or_else(|| PEER_MAX_OUTBOUND_COUNT)
}

/// return minimum preferred outbound peer count
pub fn peer_min_preferred_outbound_count(&self) -> u32 {
match self.peer_min_preferred_outbound_count {
Some(n) => n,
None => PEER_MIN_PREFERRED_OUTBOUND_COUNT,
}
self.peer_min_preferred_outbound_count
.unwrap_or_else(|| PEER_MIN_PREFERRED_OUTBOUND_COUNT)
}

/// return peer buffer count for listener
pub fn peer_listener_buffer_count(&self) -> u32 {
match self.peer_listener_buffer_count {
Some(n) => n,
None => PEER_LISTENER_BUFFER_COUNT,
}
self.peer_listener_buffer_count
.unwrap_or_else(|| PEER_LISTENER_BUFFER_COUNT)
}
}

Expand Down
Loading
Loading