rules so only ipv4 can mine
This commit is contained in:
parent
9381914a2c
commit
d06b4c83f0
|
|
@ -350,6 +350,7 @@ dependencies = [
|
|||
"shellexpand",
|
||||
"skein",
|
||||
"sled",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tokio-postgres",
|
||||
"windows-service",
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ hex = "0.4"
|
|||
falcon-rs = "0.2.4"
|
||||
fn-dsa = "0.3.0"
|
||||
tokio = { version = "1.45.1", features = ["full", "test-util"] }
|
||||
socket2 = "0.5.7"
|
||||
tokio-postgres = "0.7"
|
||||
rand = "0.8"
|
||||
sled = "0.34"
|
||||
|
|
|
|||
|
|
@ -43,8 +43,15 @@ pub fn ip_to_binary(ip_str: &str) -> Vec<u8> {
|
|||
bytes
|
||||
}
|
||||
Ok(IpAddr::V6(ipv6_addr)) => {
|
||||
// IPv6 already fits the fixed 16-byte network layout.
|
||||
ipv6_addr.octets().to_vec()
|
||||
if let Some(ipv4_addr) = ipv6_addr.to_ipv4_mapped() {
|
||||
// IPv4-mapped IPv6 is the same identity as native IPv4.
|
||||
let mut bytes = vec![0u8; 12];
|
||||
bytes.extend_from_slice(&ipv4_addr.octets());
|
||||
bytes
|
||||
} else {
|
||||
// Native IPv6 already fits the fixed 16-byte layout.
|
||||
ipv6_addr.octets().to_vec()
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
// Invalid IP strings are rejected by returning no bytes.
|
||||
|
|
@ -123,7 +130,15 @@ pub fn ip_port_to_binary(ip_port: &str) -> Result<Vec<u8>, String> {
|
|||
ipv6_bytes[12..].copy_from_slice(&ipv4.octets());
|
||||
ipv6_bytes.to_vec()
|
||||
}
|
||||
IpAddr::V6(ipv6) => ipv6.octets().to_vec(),
|
||||
IpAddr::V6(ipv6) => {
|
||||
if let Some(ipv4) = ipv6.to_ipv4_mapped() {
|
||||
let mut bytes = [0u8; 16];
|
||||
bytes[12..].copy_from_slice(&ipv4.octets());
|
||||
bytes.to_vec()
|
||||
} else {
|
||||
ipv6.octets().to_vec()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Ports are little-endian because the rest of the binary protocol
|
||||
|
|
@ -132,3 +147,26 @@ pub fn ip_port_to_binary(ip_port: &str) -> Result<Vec<u8>, String> {
|
|||
result.extend_from_slice(&port.to_le_bytes());
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn ipv4_mapped_address_uses_native_ipv4_wire_identity() {
|
||||
assert_eq!(
|
||||
ip_to_binary("::ffff:203.0.113.25"),
|
||||
ip_to_binary("203.0.113.25")
|
||||
);
|
||||
assert_eq!(
|
||||
ip_port_to_binary("::ffff:203.0.113.25:50050").unwrap(),
|
||||
ip_port_to_binary("203.0.113.25:50050").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_ipv6_wire_format_remains_available_for_rpc_transport() {
|
||||
assert_eq!(ip_to_binary("2001:db8::1").len(), 16);
|
||||
assert_eq!(ip_port_to_binary("[2001:db8::1]:50055").unwrap().len(), 18);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,44 +1,75 @@
|
|||
use crate::Settings;
|
||||
use ipnetwork::IpNetwork;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use tokio::net::lookup_host;
|
||||
|
||||
fn endpoint_ip(ip_or_endpoint: &str) -> Option<IpAddr> {
|
||||
if let Ok(ip) = ip_or_endpoint.parse::<IpAddr>() {
|
||||
return Some(ip);
|
||||
}
|
||||
|
||||
let host = ip_or_endpoint
|
||||
.strip_prefix('[')
|
||||
.and_then(|value| value.split_once(']').map(|(ip, _)| ip))
|
||||
.or_else(|| ip_or_endpoint.rsplit_once(':').map(|(ip, _)| ip))
|
||||
.unwrap_or(ip_or_endpoint);
|
||||
host.parse::<IpAddr>().ok()
|
||||
}
|
||||
|
||||
pub fn canonical_ipv4(ip: IpAddr) -> Option<Ipv4Addr> {
|
||||
match ip {
|
||||
IpAddr::V4(ip) => Some(ip),
|
||||
IpAddr::V6(ip) => ip.to_ipv4_mapped(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_public_ipv4(ip: Ipv4Addr) -> bool {
|
||||
!ip.is_unspecified()
|
||||
&& !ip.is_loopback()
|
||||
&& !ip.is_private()
|
||||
&& !ip.is_link_local()
|
||||
&& !ip.is_multicast()
|
||||
&& !ip.is_broadcast()
|
||||
&& !(ip.octets()[0] == 100 && (64..=127).contains(&ip.octets()[1]))
|
||||
}
|
||||
|
||||
pub fn is_public_network_address(ip_or_endpoint: &str) -> bool {
|
||||
// These ranges cannot be used as advertised network addresses
|
||||
// because remote peers cannot route to them over the public network.
|
||||
let private_ranges: Vec<IpNetwork> = vec![
|
||||
"127.0.0.0/8".parse().unwrap(),
|
||||
"10.0.0.0/8".parse().unwrap(),
|
||||
"172.16.0.0/12".parse().unwrap(),
|
||||
"192.168.0.0/16".parse().unwrap(),
|
||||
"100.64.0.0/10".parse().unwrap(),
|
||||
"fd00::/8".parse().unwrap(),
|
||||
"fe80::/10".parse().unwrap(),
|
||||
];
|
||||
match endpoint_ip(ip_or_endpoint) {
|
||||
Some(IpAddr::V4(ip)) => is_public_ipv4(ip),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// Accept either a bare IP or an ip:port endpoint. Bare IPv6 addresses
|
||||
// must be tested before splitting on the final port separator.
|
||||
let parsed_ip = match ip_or_endpoint.parse::<IpAddr>() {
|
||||
Ok(ip) => ip,
|
||||
Err(_) => {
|
||||
let host = ip_or_endpoint
|
||||
.strip_prefix('[')
|
||||
.and_then(|value| value.split_once(']').map(|(ip, _)| ip))
|
||||
.or_else(|| ip_or_endpoint.rsplit_once(':').map(|(ip, _)| ip))
|
||||
.unwrap_or(ip_or_endpoint);
|
||||
let Ok(ip) = host.parse::<IpAddr>() else {
|
||||
return false;
|
||||
};
|
||||
ip
|
||||
pub fn canonical_miner_endpoint(endpoint: &str) -> Option<String> {
|
||||
let port = endpoint.rsplit_once(':')?.1.parse::<u16>().ok()?;
|
||||
if port == 0 {
|
||||
return None;
|
||||
}
|
||||
let ip = canonical_ipv4(endpoint_ip(endpoint)?)?;
|
||||
is_public_ipv4(ip).then(|| SocketAddr::new(IpAddr::V4(ip), port).to_string())
|
||||
}
|
||||
|
||||
fn is_routable_address(ip: IpAddr) -> bool {
|
||||
match ip {
|
||||
IpAddr::V4(ip) => is_public_ipv4(ip),
|
||||
IpAddr::V6(ip) => {
|
||||
!ip.is_unspecified()
|
||||
&& !ip.is_loopback()
|
||||
&& !ip.is_unique_local()
|
||||
&& !ip.is_unicast_link_local()
|
||||
&& !ip.is_multicast()
|
||||
}
|
||||
};
|
||||
|
||||
!private_ranges
|
||||
.iter()
|
||||
.any(|range: &IpNetwork| range.contains(parsed_ip))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_connections() -> Vec<String> {
|
||||
get_connections_for_transport(false).await
|
||||
}
|
||||
|
||||
pub async fn get_node_connections() -> Vec<String> {
|
||||
get_connections_for_transport(true).await
|
||||
}
|
||||
|
||||
async fn get_connections_for_transport(ipv4_only: bool) -> Vec<String> {
|
||||
// If settings cannot be loaded, startup simply has no piggyback peers.
|
||||
let settings = match Settings::load() {
|
||||
Ok(settings) => settings,
|
||||
|
|
@ -50,7 +81,7 @@ pub async fn get_connections() -> Vec<String> {
|
|||
let mut resolved_connections = Vec::new();
|
||||
|
||||
for server in settings.piggybacks {
|
||||
if let Some(endpoint) = resolve_bootstrap_peer(&server, &default_port).await {
|
||||
if let Some(endpoint) = resolve_bootstrap_peer(&server, &default_port, ipv4_only).await {
|
||||
resolved_connections.push(endpoint);
|
||||
}
|
||||
|
||||
|
|
@ -97,11 +128,15 @@ fn split_bootstrap_peer(server: &str, default_port: &str) -> Option<(String, u16
|
|||
Some((server.to_string(), default_port))
|
||||
}
|
||||
|
||||
async fn resolve_bootstrap_peer(server: &str, default_port: &str) -> Option<String> {
|
||||
async fn resolve_bootstrap_peer(
|
||||
server: &str,
|
||||
default_port: &str,
|
||||
ipv4_only: bool,
|
||||
) -> Option<String> {
|
||||
let (host, port) = split_bootstrap_peer(server, default_port)?;
|
||||
|
||||
if let Ok(ip) = host.parse::<IpAddr>() {
|
||||
if is_public_network_address(&ip.to_string()) {
|
||||
if (!ipv4_only || canonical_ipv4(ip).is_some()) && is_routable_address(ip) {
|
||||
return Some(SocketAddr::new(ip, port).to_string());
|
||||
}
|
||||
return None;
|
||||
|
|
@ -111,7 +146,8 @@ async fn resolve_bootstrap_peer(server: &str, default_port: &str) -> Option<Stri
|
|||
// The resolved endpoint handed to the rest of the protocol is still an IP.
|
||||
let resolved = lookup_host((host.as_str(), port)).await.ok()?;
|
||||
for socket in resolved {
|
||||
if is_public_network_address(&socket.ip().to_string()) {
|
||||
if (!ipv4_only || canonical_ipv4(socket.ip()).is_some()) && is_routable_address(socket.ip())
|
||||
{
|
||||
return Some(socket.to_string());
|
||||
}
|
||||
}
|
||||
|
|
@ -163,3 +199,33 @@ pub async fn get_listen_ip() -> String {
|
|||
// selection to the operating system and NAT/router.
|
||||
settings.listen_ip
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn miner_endpoint_normalizes_ipv4_mapped_ipv6() {
|
||||
assert_eq!(
|
||||
canonical_miner_endpoint("::ffff:8.8.8.8:50050"),
|
||||
Some("8.8.8.8:50050".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn miner_endpoint_rejects_native_ipv6_and_client_port() {
|
||||
assert_eq!(
|
||||
canonical_miner_endpoint("[2001:4860:4860::8888]:50050"),
|
||||
None
|
||||
);
|
||||
assert_eq!(canonical_miner_endpoint("8.8.8.8:0"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn network_map_requires_canonical_public_ipv4() {
|
||||
assert!(is_public_network_address("8.8.8.8"));
|
||||
assert!(!is_public_network_address("::ffff:8.8.8.8"));
|
||||
assert!(!is_public_network_address("2001:4860:4860::8888"));
|
||||
assert!(!is_public_network_address("192.168.1.10"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::common::check_genesis::genesis_checkup;
|
||||
use crate::common::network_startup::canonical_miner_endpoint;
|
||||
use crate::log::{error, warn};
|
||||
use crate::miner::flag::{begin_chain_sync, ChainOperationGuard};
|
||||
use crate::orphans::structs::OrphanCheckup2;
|
||||
|
|
@ -9,6 +10,7 @@ use crate::records::memory::connections::{
|
|||
mark_peer_network_map_synced, mark_peer_operational, mark_peer_wallet_registry_synced,
|
||||
spawn_peer_setup_retry,
|
||||
};
|
||||
use crate::records::memory::enums::ClientType;
|
||||
use crate::records::memory::response_channels::generate_uid;
|
||||
use crate::records::memory::response_channels::Command;
|
||||
use crate::records::memory::structs::Connection;
|
||||
|
|
@ -414,6 +416,24 @@ pub async fn handle_handshake(
|
|||
// aced is used instead of ping and pong
|
||||
// as its HEX and compressed better
|
||||
if received_message == "aced" {
|
||||
// Port 0 is the explicit RPC-client marker. Classify the socket
|
||||
// before running miner-only public-address checks.
|
||||
let Some(advertised_port) = endpoint_port(&received_ip) else {
|
||||
let hashmap_key = generate_uid();
|
||||
let padded_bytes = [hashmap_key[0], hashmap_key[1], hashmap_key[2], 0];
|
||||
let uid = u32::from_le_bytes(padded_bytes);
|
||||
RpcResponse::Binary(b"error: Invalid advertised endpoint.".to_vec())
|
||||
.send(&stream, None, uid)
|
||||
.await;
|
||||
drop_failed_handshake(&stream).await;
|
||||
return;
|
||||
};
|
||||
let client_type = if advertised_port == 0 {
|
||||
ClientType::Client
|
||||
} else {
|
||||
ClientType::Miner
|
||||
};
|
||||
|
||||
//validate handshake tests
|
||||
if !perform_handshake_tests(HandshakeTestParams {
|
||||
map: map.clone(),
|
||||
|
|
@ -426,6 +446,7 @@ pub async fn handle_handshake(
|
|||
received_signed_message: &received_signed_message,
|
||||
received_address: &received_public_key,
|
||||
received_ip: &received_ip,
|
||||
client_type,
|
||||
})
|
||||
.await
|
||||
{
|
||||
|
|
@ -435,36 +456,46 @@ pub async fn handle_handshake(
|
|||
return;
|
||||
}
|
||||
|
||||
// Port 0 is the explicit client marker. A node advertising a
|
||||
// nonzero miner port must actually be reachable before it can be
|
||||
// stored in connection memory or the network map.
|
||||
let Some(advertised_port) = endpoint_port(&received_ip) else {
|
||||
let hashmap_key = generate_uid();
|
||||
let padded_bytes = [hashmap_key[0], hashmap_key[1], hashmap_key[2], 0];
|
||||
let uid = u32::from_le_bytes(padded_bytes);
|
||||
let response_bytes =
|
||||
RpcResponse::Binary("error: Invalid advertised endpoint.".as_bytes().to_vec());
|
||||
response_bytes.send(&stream, None, uid).await;
|
||||
drop_failed_handshake(&stream).await;
|
||||
return;
|
||||
};
|
||||
|
||||
let connection_type = if advertised_port == 0 {
|
||||
"client"
|
||||
} else if is_port_open(&received_ip).await.unwrap_or(false) {
|
||||
"miner"
|
||||
let (connection_type, connections_endpoint) = if client_type == ClientType::Client {
|
||||
let observed_endpoint = {
|
||||
let stream_guard = stream.lock().await;
|
||||
stream_guard
|
||||
.peer_addr()
|
||||
.ok()
|
||||
.map(|address| address.to_string())
|
||||
};
|
||||
let Some(observed_endpoint) = observed_endpoint else {
|
||||
drop_failed_handshake(&stream).await;
|
||||
return;
|
||||
};
|
||||
("client", observed_endpoint)
|
||||
} else {
|
||||
let hashmap_key = generate_uid();
|
||||
let padded_bytes = [hashmap_key[0], hashmap_key[1], hashmap_key[2], 0];
|
||||
let uid = u32::from_le_bytes(padded_bytes);
|
||||
let response_bytes = RpcResponse::Binary(
|
||||
"error: Handshake failed: advertised miner port is not reachable."
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
);
|
||||
response_bytes.send(&stream, None, uid).await;
|
||||
drop_failed_handshake(&stream).await;
|
||||
return;
|
||||
let Some(canonical_endpoint) = canonical_miner_endpoint(&received_ip) else {
|
||||
let hashmap_key = generate_uid();
|
||||
let padded_bytes = [hashmap_key[0], hashmap_key[1], hashmap_key[2], 0];
|
||||
let uid = u32::from_le_bytes(padded_bytes);
|
||||
RpcResponse::Binary(
|
||||
b"error: Miner nodes must advertise a public IPv4 address.".to_vec(),
|
||||
)
|
||||
.send(&stream, None, uid)
|
||||
.await;
|
||||
drop_failed_handshake(&stream).await;
|
||||
return;
|
||||
};
|
||||
if !is_port_open(&canonical_endpoint).await.unwrap_or(false) {
|
||||
let hashmap_key = generate_uid();
|
||||
let padded_bytes = [hashmap_key[0], hashmap_key[1], hashmap_key[2], 0];
|
||||
let uid = u32::from_le_bytes(padded_bytes);
|
||||
let response_bytes = RpcResponse::Binary(
|
||||
"error: Handshake failed: advertised miner port is not reachable."
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
);
|
||||
response_bytes.send(&stream, None, uid).await;
|
||||
drop_failed_handshake(&stream).await;
|
||||
return;
|
||||
}
|
||||
("miner", canonical_endpoint)
|
||||
};
|
||||
|
||||
if connection_type == "miner" {
|
||||
|
|
@ -508,7 +539,7 @@ pub async fn handle_handshake(
|
|||
|
||||
// write to memory
|
||||
let connections_key = write_to_memory(
|
||||
&received_ip,
|
||||
&connections_endpoint,
|
||||
stream.clone(),
|
||||
connection_type,
|
||||
received_short_address,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::records::memory::connections::CONNECTIONS;
|
||||
use crate::records::memory::enums::ClientType;
|
||||
use crate::records::memory::response_channels::{generate_uid, Command};
|
||||
use crate::rpc::responses::RpcResponse;
|
||||
use crate::rpc::server::structs::HandshakeTestParams;
|
||||
|
|
@ -160,15 +161,18 @@ pub async fn perform_handshake_tests(params: HandshakeTestParams<'_>) -> bool {
|
|||
{
|
||||
return false;
|
||||
}
|
||||
// verify IP
|
||||
if !verify_ip_address(
|
||||
params.map.clone(),
|
||||
params.stream.clone(),
|
||||
params.received_ip,
|
||||
)
|
||||
.await
|
||||
{
|
||||
return false;
|
||||
// RPC clients are identified by the accepted socket. Only miners
|
||||
// advertise a public endpoint that must match the connected peer.
|
||||
if params.client_type == ClientType::Miner {
|
||||
if !verify_ip_address(
|
||||
params.map.clone(),
|
||||
params.stream.clone(),
|
||||
params.received_ip,
|
||||
)
|
||||
.await
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// verify handshake
|
||||
if !verify_handshake(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::log::error;
|
||||
use crate::log::{error, warn};
|
||||
use crate::records::memory::response_channels::Command;
|
||||
use crate::rpc::server::handshake::handle_handshake;
|
||||
use crate::sled::Db;
|
||||
|
|
@ -7,6 +7,7 @@ use crate::Arc;
|
|||
use crate::Mutex;
|
||||
use crate::SocketAddr;
|
||||
use crate::TcpListener;
|
||||
use socket2::{Domain, Protocol, Socket, Type};
|
||||
|
||||
// wait incomming connections
|
||||
pub async fn start_rpc(
|
||||
|
|
@ -45,6 +46,44 @@ async fn rpc_server(
|
|||
return;
|
||||
}
|
||||
};
|
||||
// IPv4 remains the node transport and advertised identity. A second
|
||||
// IPv6-only listener accepts RPC clients on the same configured port;
|
||||
// the handshake rejects any IPv6 socket that advertises a miner port.
|
||||
if server_socket.is_ipv4() {
|
||||
let ipv6_listener = (|| -> std::io::Result<TcpListener> {
|
||||
let socket = Socket::new(Domain::IPV6, Type::STREAM, Some(Protocol::TCP))?;
|
||||
socket.set_only_v6(true)?;
|
||||
let address = SocketAddr::new("::".parse().unwrap(), server_socket.port());
|
||||
socket.bind(&address.into())?;
|
||||
socket.listen(1024)?;
|
||||
let listener: std::net::TcpListener = socket.into();
|
||||
listener.set_nonblocking(true)?;
|
||||
TcpListener::from_std(listener)
|
||||
})();
|
||||
match ipv6_listener {
|
||||
Ok(ipv6_listener) => {
|
||||
let ipv6_db = db.clone();
|
||||
let ipv6_wallet = wallet.clone();
|
||||
let ipv6_map = map.clone();
|
||||
tokio::spawn(async move {
|
||||
accept_connections(ipv6_listener, ipv6_db, ipv6_wallet, ipv6_map).await;
|
||||
});
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("IPv6 RPC client listener unavailable: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
accept_connections(listener, db.clone(), wallet, map).await;
|
||||
}
|
||||
|
||||
async fn accept_connections(
|
||||
listener: TcpListener,
|
||||
db: Db,
|
||||
wallet: Arc<Wallet>,
|
||||
map: Arc<Mutex<Command>>,
|
||||
) {
|
||||
loop {
|
||||
match listener.accept().await {
|
||||
Ok((stream, _)) => {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ pub struct HandshakeTestParams<'a> {
|
|||
pub received_signed_message: &'a str,
|
||||
pub received_address: &'a str,
|
||||
pub received_ip: &'a str,
|
||||
pub client_type: ClientType,
|
||||
}
|
||||
|
||||
// RpcFloodState is stored as a compact sled value so flood counters can
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::common::network_startup::is_public_network_address;
|
||||
use crate::common::network_startup::{canonical_ipv4, canonical_miner_endpoint};
|
||||
use crate::Arc;
|
||||
use crate::Mutex;
|
||||
use crate::SocketAddr;
|
||||
|
|
@ -14,22 +14,20 @@ pub fn endpoint_port(ip_port: &str) -> Option<u16> {
|
|||
pub async fn ip_test(ip_port: &str, stream: &Arc<Mutex<TcpStream>>) -> bool {
|
||||
// Private, loopback, malformed, and otherwise non-public addresses
|
||||
// are rejected before comparing them with the connected socket.
|
||||
if !is_public_network_address(ip_port) {
|
||||
let Some(canonical_endpoint) = canonical_miner_endpoint(ip_port) else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
let stream_guard = stream.lock().await;
|
||||
let remote_addr = stream_guard.peer_addr();
|
||||
|
||||
// Strip the port from either IPv4 host:port or bracketed IPv6
|
||||
// [host]:port forms before comparing against the socket address.
|
||||
let submitted_ip = ip_port
|
||||
.strip_prefix('[')
|
||||
.and_then(|value| value.split_once(']').map(|(ip, _)| ip))
|
||||
.or_else(|| ip_port.rsplit_once(':').map(|(ip, _)| ip))
|
||||
.unwrap_or(ip_port);
|
||||
let submitted_ip = canonical_endpoint
|
||||
.rsplit_once(':')
|
||||
.and_then(|(ip, _)| ip.parse().ok());
|
||||
|
||||
remote_addr.is_ok_and(|addr| addr.ip().to_string() == submitted_ip)
|
||||
remote_addr.is_ok_and(|addr| canonical_ipv4(addr.ip()) == submitted_ip)
|
||||
}
|
||||
|
||||
// check if port is open
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use crate::common::binary_conversions::ip_port_to_binary;
|
||||
use crate::common::network_startup::get_ip_and_port;
|
||||
use crate::common::skein::skein_256_hash_data;
|
||||
use crate::io;
|
||||
use crate::records::memory::response_channels::Byte3;
|
||||
|
|
@ -70,11 +69,9 @@ pub async fn connect_and_handshake(
|
|||
}
|
||||
|
||||
async fn get_client_ip() -> String {
|
||||
// The standalone client announces its local IP with port 0 because it is not opening a server port.
|
||||
let (_port, _ip, real_ip) = get_ip_and_port().await;
|
||||
let parts: Vec<&str> = real_ip.split(':').collect();
|
||||
let ip = parts.first().copied().unwrap_or("127.0.0.1");
|
||||
format!("{ip}:0")
|
||||
// Port 0 identifies an RPC client. The server derives the client's
|
||||
// actual IPv4 or IPv6 address from the accepted socket.
|
||||
"0.0.0.0:0".to_string()
|
||||
}
|
||||
|
||||
async fn perform_handshake(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::common::network_startup::get_connections;
|
||||
use crate::common::network_startup::get_node_connections;
|
||||
use crate::log::{error, info, warn};
|
||||
use crate::miner::flag::{
|
||||
clear_mining_stop_request, is_normal_mode, set_mining_state, set_node_mode, MiningState,
|
||||
|
|
@ -55,7 +55,7 @@ async fn attempt_bootstrap_connections(
|
|||
) -> Result<bool, String> {
|
||||
// Try the configured bootstrap peers one by one until a
|
||||
// handshake succeeds or the list is exhausted.
|
||||
let filtered_servers = get_connections().await;
|
||||
let filtered_servers = get_node_connections().await;
|
||||
let mut last_error: Option<String> = None;
|
||||
|
||||
for server in filtered_servers {
|
||||
|
|
|
|||
Loading…
Reference in New Issue