Skip to content

Commit

Permalink
Merge of #7977
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Nov 24, 2023
2 parents ca062d0 + 60e35d3 commit 0f785d2
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 29 deletions.
19 changes: 12 additions & 7 deletions zebra-network/src/peer/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,13 +541,16 @@ where
/// other state handling.
pub(super) request_timer: Option<Pin<Box<Sleep>>>,

/// A cached copy of the last unsolicited `addr` or `addrv2` message from this peer.
/// Unused peers from recent `addr` or `addrv2` messages from this peer.
/// Also holds the initial addresses sent in `version` messages, or guessed from the remote IP.
///
/// When Zebra requests peers, the cache is consumed and returned as a synthetic response.
/// This works around `zcashd`'s address response rate-limit.
/// When peers send solicited or unsolicited peer advertisements, Zebra puts them in this cache.
///
/// Multi-peer `addr` or `addrv2` messages replace single-peer messages in the cache.
/// (`zcashd` also gossips its own address at regular intervals.)
/// When Zebra's components request peers, some cached peers are randomly selected,
/// consumed, and returned as a modified response. This works around `zcashd`'s address
/// response rate-limit.
///
/// The cache size is limited to avoid denial of service attacks.
pub(super) cached_addrs: Vec<MetaAddr>,

/// The `inbound` service, used to answer requests from this connection's peer.
Expand Down Expand Up @@ -609,6 +612,7 @@ where
.field("error_slot", &self.error_slot)
.field("metrics_label", &self.metrics_label)
.field("last_metrics_state", &self.last_metrics_state)
.field("last_overload_time", &self.last_overload_time)
.finish()
}
}
Expand All @@ -617,22 +621,23 @@ impl<S, Tx> Connection<S, Tx>
where
Tx: Sink<Message, Error = SerializationError> + Unpin,
{
/// Return a new connection from its channels, services, and shared state.
/// Return a new connection from its channels, services, shared state, and metadata.
pub(crate) fn new(
inbound_service: S,
client_rx: futures::channel::mpsc::Receiver<ClientRequest>,
error_slot: ErrorSlot,
peer_tx: Tx,
connection_tracker: ConnectionTracker,
connection_info: Arc<ConnectionInfo>,
initial_cached_addrs: Vec<MetaAddr>,
) -> Self {
let metrics_label = connection_info.connected_addr.get_transient_addr_label();

Connection {
connection_info,
state: State::AwaitingRequest,
request_timer: None,
cached_addrs: Vec::new(),
cached_addrs: initial_cached_addrs,
svc: inbound_service,
client_rx: client_rx.into(),
error_slot,
Expand Down
1 change: 1 addition & 0 deletions zebra-network/src/peer/connection/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ fn new_test_connection<A>() -> (
peer_tx,
ActiveConnectionCounter::new_counter().track_connection(),
Arc::new(connection_info),
Vec::new(),
);

(
Expand Down
51 changes: 29 additions & 22 deletions zebra-network/src/peer/handshake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use tracing_futures::Instrument;
use zebra_chain::{
chain_tip::{ChainTip, NoChainTip},
parameters::Network,
serialization::SerializationError,
serialization::{DateTime32, SerializationError},
};

use crate::{
Expand Down Expand Up @@ -915,29 +915,8 @@ where
)
.await?;

let remote_canonical_addr = connection_info.remote.address_from.addr();
let remote_services = connection_info.remote.services;

// If we've learned potential peer addresses from an inbound
// connection or handshake, add those addresses to our address book.
//
// # Security
//
// We must handle alternate addresses separately from connected
// addresses. Otherwise, malicious peers could interfere with the
// address book state of other peers by providing their addresses in
// `Version` messages.
//
// New alternate peer address and peer responded updates are rate-limited because:
// - opening connections is rate-limited
// - we only send these messages once per handshake
let alternate_addrs = connected_addr.get_alternate_addrs(remote_canonical_addr);
for alt_addr in alternate_addrs {
let alt_addr = MetaAddr::new_alternate(alt_addr, &remote_services);
// awaiting a local task won't hang
let _ = address_book_updater.send(alt_addr).await;
}

// The handshake succeeded: update the peer status from AttemptPending to Responded,
// and send initial connection info.
if let Some(book_addr) = connected_addr.get_address_book_addr() {
Expand Down Expand Up @@ -1055,13 +1034,41 @@ where
})
.boxed();

// If we've learned potential peer addresses from the inbound connection remote address
// or the handshake version message, add those addresses to the peer cache for this
// peer.
//
// # Security
//
// We can't add these alternate addresses directly to the address book. If we did,
// malicious peers could interfere with the address book state of other peers by
// providing their addresses in `Version` messages. Or they could fill the address book
// with fake addresses.
//
// These peer addresses are rate-limited because:
// - opening connections is rate-limited
// - these addresses are put in the peer address cache
// - the peer address cache is only used when Zebra requests addresses from that peer
let remote_canonical_addr = connection_info.remote.address_from.addr();
let alternate_addrs = connected_addr
.get_alternate_addrs(remote_canonical_addr)
.map(|addr| {
// Assume the connecting node is a server node, and it's available now.
MetaAddr::new_gossiped_meta_addr(
addr,
PeerServices::NODE_NETWORK,
DateTime32::now(),
)
});

let server = Connection::new(
inbound_service,
server_rx,
error_slot.clone(),
peer_tx,
connection_tracker,
connection_info.clone(),
alternate_addrs.collect(),
);

let connection_task = tokio::spawn(
Expand Down

0 comments on commit 0f785d2

Please sign in to comment.