浏览代码

net: make modification to banning logic for inbound connection and ban an outbound peer during magic bytes & version exchange mismatch

 - when banning a host on an inbound connection, don't ban all ports if we already have a successful connection with that host on a different port
 - if we have magic_bytes mismatch during message decoding or app version mismatch during version exchange ban(blacklist) the peer if it is an outbound session
   so that we don't share this misconfigured or malicious peer with other nodes
oars 1 年之前
父节点
当前提交
8b667eccdb
共有 3 个文件被更改,包括 44 次插入5 次删除
  1. 20 4
      src/net/channel.rs
  2. 13 0
      src/net/hosts.rs
  3. 11 1
      src/net/protocol/protocol_version.rs

+ 20 - 4
src/net/channel.rs

@@ -47,7 +47,8 @@ use super::{
     metering::{MeteringConfiguration, MeteringQueue},
     p2p::P2pPtr,
     session::{
-        Session, SessionBitFlag, SessionWeakPtr, SESSION_ALL, SESSION_INBOUND, SESSION_REFINE,
+        Session, SessionBitFlag, SessionWeakPtr, SESSION_ALL, SESSION_INBOUND, SESSION_OUTBOUND,
+        SESSION_REFINE,
     },
     transport::PtStream,
 };
@@ -337,6 +338,14 @@ impl Channel {
         let magic_bytes = self.p2p().settings().read().await.magic_bytes.0;
         if magic != magic_bytes {
             error!(target: "net::channel::read_command", "Error: Magic bytes mismatch");
+
+            // If it is outbound, ban the host so we don't share it with other nodes
+            if self.session_type_id() & SESSION_OUTBOUND != 0 {
+                if let BanPolicy::Strict = self.p2p().settings().read().await.ban_policy {
+                    self.ban().await;
+                }
+            }
+
             return Err(Error::MalformedPacket)
         }
 
@@ -511,9 +520,16 @@ impl Channel {
                     return
                 }
 
-                let mut addr = self.address().clone();
-                addr.set_port(None).unwrap();
-                addr
+                // If we already have a successful connection with this host on another port,
+                // this might indicate a misconfiguration or unintended overlap between separate P2P networks.
+                // To prevent interference, we block only this specific port rather than the entire host.
+                if self.hosts().has_existing_connection(self.address()) {
+                    self.address().clone()
+                } else {
+                    let mut addr = self.address().clone();
+                    addr.set_port(None).unwrap();
+                    addr
+                }
             } else {
                 self.address().clone()
             }

+ 13 - 0
src/net/hosts.rs

@@ -1600,6 +1600,19 @@ impl Hosts {
         None
     }
 
+    // Checks if we have successful connection with a host on any port
+    pub fn has_existing_connection(&self, url: &Url) -> bool {
+        let host = url.host().unwrap();
+        let colors = [HostColor::Gold, HostColor::White];
+        colors.iter().any(|color| {
+            self.container.hostlists[color.clone() as usize]
+                .read()
+                .unwrap()
+                .iter()
+                .any(|(u, _t)| u.host().unwrap() == host)
+        })
+    }
+
     #[cfg(feature = "p2p-i2p")]
     fn is_i2p_host(host: &str) -> bool {
         if !host.ends_with(".i2p") {

+ 11 - 1
src/net/protocol/protocol_version.rs

@@ -33,7 +33,10 @@ use super::super::{
     message_publisher::MessageSubscription,
     settings::Settings,
 };
-use crate::{Error, Result};
+use crate::{
+    net::{session::SESSION_OUTBOUND, BanPolicy},
+    Error, Result,
+};
 
 /// Implements the protocol version handshake sent out by nodes at
 /// the beginning of a connection.
@@ -190,6 +193,13 @@ impl ProtocolVersion {
                 self.channel.display_address(),
             );
 
+            // If it is outbound, ban the host so we don't share it with other nodes
+            if self.channel.session_type_id() & SESSION_OUTBOUND != 0 {
+                if let BanPolicy::Strict = self.channel.p2p().settings().read().await.ban_policy {
+                    self.channel.ban().await;
+                }
+            }
+
             self.channel.stop().await;
             return Err(Error::ChannelStopped)
         }