Deny connection with local PeerId (#859)

This commit is contained in:
Pierre Krieger
2019-01-17 12:20:02 +01:00
committed by GitHub
parent c3e29a2654
commit ad27a468f8

View File

@ -61,7 +61,7 @@ where
listeners: ListenersStream<TTrans>, listeners: ListenersStream<TTrans>,
/// The nodes currently active. /// The nodes currently active.
active_nodes: CollectionStream<TInEvent, TOutEvent, THandler, RawSwarmReachError<TTrans::Error>, THandlerErr>, active_nodes: CollectionStream<TInEvent, TOutEvent, THandler, InternalReachErr<TTrans::Error>, THandlerErr>,
/// The reach attempts of the swarm. /// The reach attempts of the swarm.
/// This needs to be a separate struct in order to handle multiple mutable borrows issues. /// This needs to be a separate struct in order to handle multiple mutable borrows issues.
@ -190,7 +190,7 @@ where
multiaddr: Multiaddr, multiaddr: Multiaddr,
/// The error that happened. /// The error that happened.
error: TransportError<TTrans::Error>, error: UnknownPeerDialErr<TTrans::Error>,
/// The handler that was passed to `dial()`. /// The handler that was passed to `dial()`.
handler: THandler, handler: THandler,
@ -283,12 +283,55 @@ where
} }
} }
/// Internal error type that contains all the possible errors that can happen in a reach attempt.
#[derive(Debug)]
enum InternalReachErr<TTransErr> {
/// Error in the transport layer.
Transport(TransportError<TTransErr>),
/// We successfully reached the peer, but there was a mismatch between the expected id and the
/// actual id of the peer.
PeerIdMismatch {
/// The peer id that the node reports.
obtained: PeerId,
},
/// The negotiated `PeerId` is the same as the one of the local node.
FoundLocalPeerId,
}
impl<TTransErr> fmt::Display for InternalReachErr<TTransErr>
where TTransErr: fmt::Display
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
InternalReachErr::Transport(err) => write!(f, "{}", err),
InternalReachErr::PeerIdMismatch { obtained } => {
write!(f, "Peer ID mismatch, obtained: {}", obtained.to_base58())
},
InternalReachErr::FoundLocalPeerId => {
write!(f, "Remote has the same PeerId as us")
}
}
}
}
impl<TTransErr> error::Error for InternalReachErr<TTransErr>
where TTransErr: error::Error + 'static
{
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
InternalReachErr::Transport(err) => Some(err),
InternalReachErr::PeerIdMismatch { .. } => None,
InternalReachErr::FoundLocalPeerId => None,
}
}
}
/// Error that can happen when trying to reach a node. /// Error that can happen when trying to reach a node.
#[derive(Debug)] #[derive(Debug)]
pub enum RawSwarmReachError<TTransErr> { pub enum RawSwarmReachError<TTransErr> {
/// Error in the transport layer. /// Error in the transport layer.
// TODO: is a TransportError correct here?
Transport(TransportError<TTransErr>), Transport(TransportError<TTransErr>),
/// We successfully reached the peer, but there was a mismatch between the expected id and the /// We successfully reached the peer, but there was a mismatch between the expected id and the
/// actual id of the peer. /// actual id of the peer.
PeerIdMismatch { PeerIdMismatch {
@ -321,6 +364,39 @@ where TTransErr: error::Error + 'static
} }
} }
/// Error that can happen when dialing a node with an unknown peer ID.
#[derive(Debug)]
pub enum UnknownPeerDialErr<TTransErr> {
/// Error in the transport layer.
Transport(TransportError<TTransErr>),
/// The negotiated `PeerId` is the same as the local node.
FoundLocalPeerId,
}
impl<TTransErr> fmt::Display for UnknownPeerDialErr<TTransErr>
where TTransErr: fmt::Display
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
UnknownPeerDialErr::Transport(err) => write!(f, "{}", err),
UnknownPeerDialErr::FoundLocalPeerId => {
write!(f, "Unknown peer has same PeerId as us")
},
}
}
}
impl<TTransErr> error::Error for UnknownPeerDialErr<TTransErr>
where TTransErr: error::Error + 'static
{
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
UnknownPeerDialErr::Transport(err) => Some(err),
UnknownPeerDialErr::FoundLocalPeerId => None,
}
}
}
/// Error that can happen on an incoming connection. /// Error that can happen on an incoming connection.
#[derive(Debug)] #[derive(Debug)]
pub enum IncomingError<TTransErr> { pub enum IncomingError<TTransErr> {
@ -330,6 +406,8 @@ pub enum IncomingError<TTransErr> {
/// Denied the incoming connection because we're already connected to this peer as a dialer /// Denied the incoming connection because we're already connected to this peer as a dialer
/// and we have a higher priority than the remote. /// and we have a higher priority than the remote.
DeniedLowerPriority, DeniedLowerPriority,
/// The negotiated `PeerId` is the same as the local node.
FoundLocalPeerId,
} }
impl<TTransErr> fmt::Display for IncomingError<TTransErr> impl<TTransErr> fmt::Display for IncomingError<TTransErr>
@ -341,6 +419,9 @@ where TTransErr: fmt::Display
IncomingError::DeniedLowerPriority => { IncomingError::DeniedLowerPriority => {
write!(f, "Denied because of lower priority") write!(f, "Denied because of lower priority")
}, },
IncomingError::FoundLocalPeerId => {
write!(f, "Incoming connection has same PeerId as us")
},
} }
} }
} }
@ -352,6 +433,7 @@ where TTransErr: error::Error + 'static
match self { match self {
IncomingError::Transport(err) => Some(err), IncomingError::Transport(err) => Some(err),
IncomingError::DeniedLowerPriority => None, IncomingError::DeniedLowerPriority => None,
IncomingError::FoundLocalPeerId => None,
} }
} }
} }
@ -362,12 +444,14 @@ where TTrans: Transport
{ {
/// The produced upgrade. /// The produced upgrade.
upgrade: TTrans::ListenerUpgrade, upgrade: TTrans::ListenerUpgrade,
/// PeerId of the local node.
local_peer_id: PeerId,
/// Address of the listener which received the connection. /// Address of the listener which received the connection.
listen_addr: Multiaddr, listen_addr: Multiaddr,
/// Address used to send back data to the remote. /// Address used to send back data to the remote.
send_back_addr: Multiaddr, send_back_addr: Multiaddr,
/// Reference to the `active_nodes` field of the swarm. /// Reference to the `active_nodes` field of the swarm.
active_nodes: &'a mut CollectionStream<TInEvent, TOutEvent, THandler, RawSwarmReachError<TTrans::Error>, THandlerErr>, active_nodes: &'a mut CollectionStream<TInEvent, TOutEvent, THandler, InternalReachErr<TTrans::Error>, THandlerErr>,
/// Reference to the `other_reach_attempts` field of the swarm. /// Reference to the `other_reach_attempts` field of the swarm.
other_reach_attempts: &'a mut Vec<(ReachAttemptId, ConnectedPoint)>, other_reach_attempts: &'a mut Vec<(ReachAttemptId, ConnectedPoint)>,
} }
@ -400,7 +484,17 @@ where
{ {
let connected_point = self.to_connected_point(); let connected_point = self.to_connected_point();
let handler = builder(self.info()); let handler = builder(self.info());
let id = self.active_nodes.add_reach_attempt(self.upgrade.map_err(|err| RawSwarmReachError::Transport(TransportError::Other(err))), handler); let local_peer_id = self.local_peer_id;
let upgrade = self.upgrade
.map_err(|err| InternalReachErr::Transport(TransportError::Other(err)))
.and_then(move |(peer_id, muxer)| {
if peer_id == local_peer_id {
Err(InternalReachErr::FoundLocalPeerId)
} else {
Ok((peer_id, muxer))
}
});
let id = self.active_nodes.add_reach_attempt(upgrade, handler);
self.other_reach_attempts.push(( self.other_reach_attempts.push((
id, id,
connected_point, connected_point,
@ -605,10 +699,19 @@ where
TInEvent: Send + 'static, TInEvent: Send + 'static,
TOutEvent: Send + 'static, TOutEvent: Send + 'static,
{ {
let future = self.transport().clone().dial(addr.clone())?; let local_peer_id = self.reach_attempts.local_peer_id.clone();
let future = self.transport().clone().dial(addr.clone())?
.map_err(|err| InternalReachErr::Transport(TransportError::Other(err)))
.and_then(move |(peer_id, muxer)| {
if peer_id == local_peer_id {
Err(InternalReachErr::FoundLocalPeerId)
} else {
Ok((peer_id, muxer))
}
});
let connected_point = ConnectedPoint::Dialer { address: addr }; let connected_point = ConnectedPoint::Dialer { address: addr };
let reach_id = self.active_nodes.add_reach_attempt(future.map_err(|err| RawSwarmReachError::Transport(TransportError::Other(err))), handler); let reach_id = self.active_nodes.add_reach_attempt(future, handler);
self.reach_attempts.other_reach_attempts.push((reach_id, connected_point)); self.reach_attempts.other_reach_attempts.push((reach_id, connected_point));
Ok(()) Ok(())
} }
@ -715,18 +818,18 @@ where
Ok(fut) => { Ok(fut) => {
let expected_peer_id = peer_id.clone(); let expected_peer_id = peer_id.clone();
let fut = fut let fut = fut
.map_err(|err| RawSwarmReachError::Transport(TransportError::Other(err))) .map_err(|err| InternalReachErr::Transport(TransportError::Other(err)))
.and_then(move |(actual_peer_id, muxer)| { .and_then(move |(actual_peer_id, muxer)| {
if actual_peer_id == expected_peer_id { if actual_peer_id == expected_peer_id {
Ok((actual_peer_id, muxer)) Ok((actual_peer_id, muxer))
} else { } else {
Err(RawSwarmReachError::PeerIdMismatch { obtained: actual_peer_id }) Err(InternalReachErr::PeerIdMismatch { obtained: actual_peer_id })
} }
}); });
self.active_nodes.add_reach_attempt(fut, handler) self.active_nodes.add_reach_attempt(fut, handler)
}, },
Err(err) => { Err(err) => {
let fut = future::err(RawSwarmReachError::Transport(err)); let fut = future::err(InternalReachErr::Transport(err));
self.active_nodes.add_reach_attempt(fut, handler) self.active_nodes.add_reach_attempt(fut, handler)
}, },
}; };
@ -766,6 +869,7 @@ where
Async::Ready(ListenersEvent::Incoming { upgrade, listen_addr, send_back_addr }) => { Async::Ready(ListenersEvent::Incoming { upgrade, listen_addr, send_back_addr }) => {
let event = IncomingConnectionEvent { let event = IncomingConnectionEvent {
upgrade, upgrade,
local_peer_id: self.reach_attempts.local_peer_id.clone(),
listen_addr, listen_addr,
send_back_addr, send_back_addr,
active_nodes: &mut self.active_nodes, active_nodes: &mut self.active_nodes,
@ -876,7 +980,7 @@ impl<THandler> Default for ActionItem<THandler> {
/// > panics will likely happen. /// > panics will likely happen.
fn handle_node_reached<'a, TTrans, TMuxer, TInEvent, TOutEvent, THandler, THandlerErr>( fn handle_node_reached<'a, TTrans, TMuxer, TInEvent, TOutEvent, THandler, THandlerErr>(
reach_attempts: &mut ReachAttempts, reach_attempts: &mut ReachAttempts,
event: CollectionReachEvent<TInEvent, TOutEvent, THandler, RawSwarmReachError<TTrans::Error>, THandlerErr> event: CollectionReachEvent<TInEvent, TOutEvent, THandler, InternalReachErr<TTrans::Error>, THandlerErr>
) -> (ActionItem<THandler>, RawSwarmEvent<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>) ) -> (ActionItem<THandler>, RawSwarmEvent<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>)
where where
TTrans: Transport<Output = (PeerId, TMuxer)> + Clone, TTrans: Transport<Output = (PeerId, TMuxer)> + Clone,
@ -1005,7 +1109,7 @@ fn has_dial_prio(local: &PeerId, other: &PeerId) -> bool {
fn handle_reach_error<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>( fn handle_reach_error<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>(
reach_attempts: &mut ReachAttempts, reach_attempts: &mut ReachAttempts,
reach_id: ReachAttemptId, reach_id: ReachAttemptId,
error: RawSwarmReachError<TTrans::Error>, error: InternalReachErr<TTrans::Error>,
handler: THandler, handler: THandler,
) -> (ActionItem<THandler>, RawSwarmEvent<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>) ) -> (ActionItem<THandler>, RawSwarmEvent<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>)
where TTrans: Transport where TTrans: Transport
@ -1035,6 +1139,17 @@ where TTrans: Transport
Default::default() Default::default()
}; };
let error = match error {
InternalReachErr::Transport(err) => RawSwarmReachError::Transport(err),
InternalReachErr::PeerIdMismatch { obtained } => {
RawSwarmReachError::PeerIdMismatch { obtained }
},
InternalReachErr::FoundLocalPeerId => {
unreachable!("We only generate FoundLocalPeerId within dial() or accept(); neither \
of these methods add an entry to out_reach_attempts; QED")
},
};
return (action, RawSwarmEvent::DialError { return (action, RawSwarmEvent::DialError {
remain_addrs_attempt: num_remain, remain_addrs_attempt: num_remain,
peer_id, peer_id,
@ -1050,12 +1165,16 @@ where TTrans: Transport
.position(|i| i.0 == reach_id) .position(|i| i.0 == reach_id)
{ {
let (_, endpoint) = reach_attempts.other_reach_attempts.swap_remove(in_pos); let (_, endpoint) = reach_attempts.other_reach_attempts.swap_remove(in_pos);
let error = match error {
RawSwarmReachError::Transport(err) => err,
RawSwarmReachError::PeerIdMismatch { .. } => unreachable!(), // TODO: prove
};
match endpoint { match endpoint {
ConnectedPoint::Dialer { address } => { ConnectedPoint::Dialer { address } => {
let error = match error {
InternalReachErr::Transport(err) => UnknownPeerDialErr::Transport(err),
InternalReachErr::FoundLocalPeerId => UnknownPeerDialErr::FoundLocalPeerId,
InternalReachErr::PeerIdMismatch { .. } => {
unreachable!("We only generate PeerIdMismatch within start_dial_out(),
which doesn't add any entry in other_reach_attempts; QED")
},
};
return (Default::default(), RawSwarmEvent::UnknownPeerDialError { return (Default::default(), RawSwarmEvent::UnknownPeerDialError {
multiaddr: address, multiaddr: address,
error, error,
@ -1063,8 +1182,19 @@ where TTrans: Transport
}); });
} }
ConnectedPoint::Listener { listen_addr, send_back_addr } => { ConnectedPoint::Listener { listen_addr, send_back_addr } => {
let error = IncomingError::Transport(error); let error = match error {
return (Default::default(), RawSwarmEvent::IncomingConnectionError { listen_addr, send_back_addr, error }); InternalReachErr::Transport(err) => IncomingError::Transport(err),
InternalReachErr::FoundLocalPeerId => IncomingError::FoundLocalPeerId,
InternalReachErr::PeerIdMismatch { .. } => {
unreachable!("We only generate PeerIdMismatch within start_dial_out(),
which doesn't add any entry in other_reach_attempts; QED")
},
};
return (Default::default(), RawSwarmEvent::IncomingConnectionError {
listen_addr,
send_back_addr,
error
});
} }
} }
} }
@ -1301,7 +1431,7 @@ where
TTrans: Transport TTrans: Transport
{ {
attempt: OccupiedEntry<'a, PeerId, OutReachAttempt>, attempt: OccupiedEntry<'a, PeerId, OutReachAttempt>,
active_nodes: &'a mut CollectionStream<TInEvent, TOutEvent, THandler, RawSwarmReachError<TTrans::Error>, THandlerErr>, active_nodes: &'a mut CollectionStream<TInEvent, TOutEvent, THandler, InternalReachErr<TTrans::Error>, THandlerErr>,
} }
impl<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr> PeerPendingConnect<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr> impl<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr> PeerPendingConnect<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>