Grin: Peer ban doesn't work as expected

Created on 27 Dec 2018  路  4Comments  路  Source: mimblewimble/grin

A banned peer continue appearing on my peers list, check log and find this:

20181227 17:19:12.838 DEBUG grin_p2p::protocol - handler: consume: peer V4(35.227.48.174:13414) banned, received: GetPeerAddrs, dropping.
20181227 17:19:19.956 DEBUG grin_p2p::peers - clean_peers V4(35.227.48.174:13414), peer banned
20181227 17:19:52.979 DEBUG grin_p2p::peers - Saving newly connected peer 35.227.48.174:13414.
20181227 17:19:52.979 DEBUG grin_p2p::store - save_peer: V4(35.227.48.174:13414) marked Healthy
20181227 17:19:52.982 DEBUG grin_p2p::peers - Saving newly connected peer 35.227.48.174:13414.
20181227 17:19:52.982 DEBUG grin_p2p::store - save_peer: V4(35.227.48.174:13414) marked Healthy

That means when I ban a peer, it works. But after 30 seconds, if this banned peer request connect again, it will connect to my node again!

It will enter an infinite loop here: banned, connected, banned, connected, ...

20181227 17:20:12.843 DEBUG grin_p2p::protocol - handler: consume: peer V4(35.227.48.174:13414) banned, received: GetPeerAddrs, dropping.
20181227 17:20:20.151 DEBUG grin_p2p::peers - clean_peers V4(35.227.48.174:13414), peer banned
20181227 17:20:52.978 DEBUG grin_p2p::peers - Saving newly connected peer 35.227.48.174:13414.
20181227 17:20:52.978 DEBUG grin_p2p::store - save_peer: V4(35.227.48.174:13414) marked Healthy
bug

All 4 comments

It proves that this is caused by a wrong usage.
I called peer.set_banned(); but actually this function call will never write ban state into database. Instead, I should call peers::ban_peer().

Sorry for noise.

Even after switching to peers::ban_peer(), the banned peer still always can connect.

Finally I find the root cause, it looks like a deep buried bug here which was committed on 2018-03-28 since the is_banned() function was written:

------------------------------- p2p/src/peers.rs -------------------------------
index c09dfb00..0e8ccb9b 100644
@@ -638,4 +638,13 @@ impl NetAdapter for Peers {
            }
        }
    }
+
+   fn is_banned(&self, addr: SocketAddr) -> bool {
+       if let Some(peer) = self.get_connected_peer(&addr) {
+           let mut peer = peer.write().unwrap();
+           peer.is_banned()
+       } else {
+           false
+       }
+   }
 }

For each peer connection request, we will call this is_banned() function to decide whether we can accept it or not,

impl MessageHandler for Protocol {
    fn consume<'a>(...) -> Result<Option<Response<'a>>, Error> {
        ...
        // If we received a msg from a banned peer then log and drop it.
        // If we are getting a lot of these then maybe we are not cleaning
        // banned peers up correctly?
        if adapter.is_banned(self.addr.clone()) {
            debug!(
                "handler: consume: peer {:?} banned, received: {:?}, dropping.",
                self.addr, msg.header.msg_type,
            );
            return Ok(None);
        }

The problem is the get_connected_peer() function only get the current peers which is being connected, what we need here is to check all the peers in the peers database.

Will give a PR to fix this.

Confirmed the fix seems doesn't work! will investigate.
With the latest master branch code:

20181231 03:20:27.474 DEBUG grin_p2p::peers - Banning peer 2.95.177.91:13414
20181231 03:20:27.474 DEBUG grin_p2p::peer - Sent ban reason FraudHeight to 2.95.177.91:13414
20181231 03:20:27.474 INFO grin_servers::grin::sync::header_sync - sync: ban a fraud peer: 2.95.177.91:13414, claimed height: 13192, total difficulty: 703099211
20181231 03:20:27.477 DEBUG grin_p2p::conn - Connection close with 2.95.177.91:59948 initiated by us
20181231 03:20:44.178 DEBUG grin_p2p::peers - clean_peers V4(2.95.177.91:13414), peer banned
20181231 03:25:05.439 DEBUG grin_p2p::peer - accept: handshaking from Ok(V4(2.95.177.91:60000))
20181231 03:25:05.439 DEBUG grin_p2p::peers - Saving newly connected peer 2.95.177.91:13414.
20181231 03:25:05.439 DEBUG grin_p2p::store - save_peer: V4(2.95.177.91:13414) marked Healthy

And repeating the ban and connect.

The root cause is clear now:

There're two different address, one is abstracted from the TCP stream (by TcpStream::peer_addr()), another one is abstracted from sender_addr by HandShake protocol:

/// First part of a handshake, sender advertises its version and characteristics.
pub struct Hand {
    ...
    /// network address of the sender
    pub sender_addr: SockAddr,
    ...
}

When we ban a peer, we use this sender_addr. But when we check ban, we're using TcpStream::peer_addr(), that's why a banned peer can always connect again successfully!

            match listener.accept() {
                Ok((stream, peer_addr)) => {
                    if !self.check_banned(&stream) {
                        if let Err(e) = self.handle_new_peer(stream) {
                            warn!("Error accepting peer {}: {:?}", peer_addr.to_string(), e);
                        }
                    }
                }

will write a PR to fix this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

antiochp picture antiochp  路  6Comments

garyyu picture garyyu  路  6Comments

antiochp picture antiochp  路  3Comments

ignopeverell picture ignopeverell  路  3Comments

RiyaKarthi picture RiyaKarthi  路  3Comments