فهرست منبع

p2pnet: validate external address of inbound connection

aggstam 3 سال پیش
والد
کامیت
34dff4e2d2
5فایلهای تغییر یافته به همراه116 افزوده شده و 10 حذف شده
  1. 1 0
      src/net/channel.rs
  2. 72 1
      src/net/hosts.rs
  3. 12 0
      src/net/message.rs
  4. 27 5
      src/net/protocol/protocol_address.rs
  5. 4 4
      src/net/protocol/protocol_seed.rs

+ 1 - 0
src/net/channel.rs

@@ -279,6 +279,7 @@ impl Channel {
         message_subsystem.add_dispatch::<message::PongMessage>().await;
         message_subsystem.add_dispatch::<message::GetAddrsMessage>().await;
         message_subsystem.add_dispatch::<message::AddrsMessage>().await;
+        message_subsystem.add_dispatch::<message::ExtAddrsMessage>().await;
     }
 
     /// Convenience function that returns the Message Subsystem.

+ 72 - 1
src/net/hosts.rs

@@ -48,7 +48,20 @@ impl Hosts {
         }
     }
 
-    // TODO: add single host store, which also checks that resolved ips are the same as the connection
+    /// Add a new hosts external adders to the host list, after filtering and verifying
+    /// the address url resolves to the provided connection address.
+    pub async fn store_ext(&self, connection_addr: Url, input_addrs: Vec<Url>) {
+        let addrs = if !self.localnet {
+            let filtered = filter_localnet(input_addrs);
+            let filtered = filter_invalid(&self.ipv4_range, &self.ipv6_range, filtered);
+            filter_non_resolving(connection_addr, filtered)
+        } else {
+            input_addrs
+        };
+        for addr in addrs {
+            self.addrs.lock().await.insert(addr);
+        }
+    }
 
     /// Return the list of hosts.
     pub async fn load_all(&self) -> Vec<Url> {
@@ -135,6 +148,64 @@ fn filter_invalid(
     filtered
 }
 
+/// Auxiliary function to filter unresolvable hosts, based on provided connection addr (excluding onion).
+fn filter_non_resolving(connection_addr: Url, input_addrs: Vec<Url>) -> Vec<Url> {
+    let connection_domain = connection_addr.domain().unwrap();
+    // Validate connection onion domain
+    if connection_domain.ends_with(".onion") && !is_valid_onion(connection_domain) {
+        return vec![]
+    }
+
+    // Retrieve connection IPs
+    let mut ipv4_range = vec![];
+    let mut ipv6_range = vec![];
+    for i in connection_addr.socket_addrs(|| None).unwrap() {
+        match i.ip() {
+            IpAddr::V4(a) => {
+                ipv4_range.push(a);
+            }
+            IpAddr::V6(a) => {
+                ipv6_range.push(a);
+            }
+        }
+    }
+
+    // Filter input addresses
+    let mut filtered = vec![];
+    for addr in input_addrs {
+        // Keep valid onion domains
+        let addr_domain = addr.domain().unwrap();
+        if addr_domain.ends_with(".onion") && addr_domain == connection_domain {
+            filtered.push(addr.clone());
+            continue
+        }
+
+        // Checking IP validity
+        let mut valid = true;
+        let socket_addrs = addr.socket_addrs(|| None).unwrap();
+        for i in socket_addrs {
+            match i.ip() {
+                IpAddr::V4(a) => {
+                    if !ipv4_range.contains(&a) {
+                        valid = false;
+                        break
+                    }
+                }
+                IpAddr::V6(a) => {
+                    if !ipv6_range.contains(&a) {
+                        valid = false;
+                        break
+                    }
+                }
+            }
+        }
+        if valid {
+            filtered.push(addr.clone());
+        }
+    }
+    filtered
+}
+
 /// Auxiliary function to validate an onion.
 fn is_valid_onion(onion: &str) -> bool {
     let onion = match onion.strip_suffix(".onion") {

+ 12 - 0
src/net/message.rs

@@ -37,6 +37,12 @@ pub struct AddrsMessage {
     pub addrs: Vec<Url>,
 }
 
+/// Sends external address information to inbound connection.
+#[derive(SerialEncodable, SerialDecodable)]
+pub struct ExtAddrsMessage {
+    pub ext_addrs: Vec<Url>,
+}
+
 /// Requests version information of outbound connection.
 #[derive(SerialEncodable, SerialDecodable)]
 pub struct VersionMessage {
@@ -74,6 +80,12 @@ impl Message for AddrsMessage {
     }
 }
 
+impl Message for ExtAddrsMessage {
+    fn name() -> &'static str {
+        "extaddr"
+    }
+}
+
 impl Message for VersionMessage {
     fn name() -> &'static str {
         "version"

+ 27 - 5
src/net/protocol/protocol_address.rs

@@ -20,6 +20,7 @@ const SEND_ADDR_SLEEP_SECONDS: u64 = 900;
 pub struct ProtocolAddress {
     channel: ChannelPtr,
     addrs_sub: MessageSubscription<message::AddrsMessage>,
+    ext_addrs_sub: MessageSubscription<message::ExtAddrsMessage>,
     get_addrs_sub: MessageSubscription<message::GetAddrsMessage>,
     hosts: HostsPtr,
     jobsman: ProtocolJobsManagerPtr,
@@ -27,8 +28,8 @@ pub struct ProtocolAddress {
 }
 
 impl ProtocolAddress {
-    /// Create a new address protocol. Makes an address and get-address
-    /// subscription and adds them to the address protocol instance.
+    /// Create a new address protocol. Makes an address, an external address
+    /// and a  get-address subscription and adds them to the address protocol instance.
     pub async fn init(channel: ChannelPtr, p2p: P2pPtr) -> ProtocolBasePtr {
         let settings = p2p.settings();
         let hosts = p2p.hosts();
@@ -40,6 +41,13 @@ impl ProtocolAddress {
             .await
             .expect("Missing addrs dispatcher!");
 
+        // Creates a subscription to external address message.
+        let ext_addrs_sub = channel
+            .clone()
+            .subscribe_msg::<message::ExtAddrsMessage>()
+            .await
+            .expect("Missing ext_addrs dispatcher!");
+
         // Creates a subscription to get-address message.
         let get_addrs_sub = channel
             .clone()
@@ -50,6 +58,7 @@ impl ProtocolAddress {
         Arc::new(Self {
             channel: channel.clone(),
             addrs_sub,
+            ext_addrs_sub,
             get_addrs_sub,
             hosts,
             jobsman: ProtocolJobsManager::new("ProtocolAddress", channel),
@@ -69,6 +78,18 @@ impl ProtocolAddress {
         }
     }
 
+    /// Handles receiving the external address message. Loops to continually recieve
+    /// external address messages on the address subsciption. Adds the recieved
+    /// external addresses to the list of hosts.
+    async fn handle_receive_ext_addrs(self: Arc<Self>) -> Result<()> {
+        debug!(target: "net", "ProtocolAddress::handle_receive_ext_addrs() [START]");
+        loop {
+            let ext_addrs_msg = self.ext_addrs_sub.receive().await?;
+            debug!(target: "net", "ProtocolAddress::handle_receive_ext_addrs() received {} addrs", ext_addrs_msg.ext_addrs.len());
+            self.hosts.store_ext(self.channel.address(), ext_addrs_msg.ext_addrs.clone()).await;
+        }
+    }
+
     /// Handles receiving the get-address message. Continually recieves
     /// get-address messages on the get-address subsciption. Then replies
     /// with an address message.
@@ -92,9 +113,9 @@ impl ProtocolAddress {
     async fn send_my_addrs(self: Arc<Self>) -> Result<()> {
         debug!(target: "net", "ProtocolAddress::send_addrs() [START]");
         loop {
-            let addrs = self.settings.external_addr.clone();
-            let addr_msg = message::AddrsMessage { addrs };
-            self.channel.clone().send(addr_msg).await?;
+            let ext_addrs = self.settings.external_addr.clone();
+            let ext_addr_msg = message::ExtAddrsMessage { ext_addrs };
+            self.channel.clone().send(ext_addr_msg).await?;
             async_util::sleep(SEND_ADDR_SLEEP_SECONDS).await;
         }
     }
@@ -118,6 +139,7 @@ impl ProtocolBase for ProtocolAddress {
         debug!(target: "net", "ProtocolAddress::start() [START]");
         self.jobsman.clone().start(executor.clone());
         self.jobsman.clone().spawn(self.clone().handle_receive_addrs(), executor.clone()).await;
+        self.jobsman.clone().spawn(self.clone().handle_receive_ext_addrs(), executor.clone()).await;
         self.jobsman.clone().spawn(self.clone().handle_receive_get_addrs(), executor).await;
 
         // Send get_address message.

+ 4 - 4
src/net/protocol/protocol_seed.rs

@@ -46,10 +46,10 @@ impl ProtocolSeed {
             return Ok(())
         }
 
-        let addrs = self.settings.external_addr.clone();
-        debug!(target: "net", "ProtocolSeed::send_own_address() addrs={:?}", addrs);
-        let addrs = message::AddrsMessage { addrs };
-        self.channel.clone().send(addrs).await
+        let ext_addrs = self.settings.external_addr.clone();
+        debug!(target: "net", "ProtocolSeed::send_self_address() ext_addrs={:?}", ext_addrs);
+        let ext_addr_msg = message::ExtAddrsMessage { ext_addrs };
+        self.channel.clone().send(ext_addr_msg).await
     }
 }