Prechádzať zdrojové kódy

net: add ipv6 addrs to dark list if we do not support ipv6

If ipv6_available is set to false, filter_addrs will send ipv6 addresses
to the darklist.

This is necessary since otherwise they would be deleted by the refinery
and not propagated on the network, even if they are perfectly valid
hosts.

Once on the dark list, these addresses will not be connected to in
OutboundSession.

Note that because there may be a delay when we establish ipv6 connectivity
(since it requires Connector to fail with ENETUNREACH), there is a
possibility of the following happening:

* recv ipv6 addrs, add to greylist
* try to connect to ipv6 addr
* set ipv6_available == false
* recv ivp6 addrs, add to darklist
* we now have duplicate addrs on darklist and greylist.

This is not a problem because the refinery will eventually delete the
greylist entries and from then on the dark list will be the definitive
list for ipv6 addrs.
draoi 2 rokov pred
rodič
commit
8d9510478e
3 zmenil súbory, kde vykonal 58 pridanie a 9 odobranie
  1. 2 2
      src/net/connector.rs
  2. 56 4
      src/net/hosts.rs
  3. 0 3
      src/net/p2p.rs

+ 2 - 2
src/net/connector.rs

@@ -102,9 +102,9 @@ impl Connector {
             Either::Left((Err(e), _)) => {
             Either::Left((Err(e), _)) => {
                 // If we get ENETUNREACH, we don't have IPv6 connectivity so note it down.
                 // If we get ENETUNREACH, we don't have IPv6 connectivity so note it down.
                 if e.raw_os_error() == Some(libc::ENETUNREACH) {
                 if e.raw_os_error() == Some(libc::ENETUNREACH) {
-                    *self.session.upgrade().unwrap().p2p().ipv6_available.lock().await = false;
+                    *self.session.upgrade().unwrap().p2p().hosts().ipv6_available.lock().await =
+                        false;
                 }
                 }
-
                 Err(e.into())
                 Err(e.into())
             }
             }
 
 

+ 56 - 4
src/net/hosts.rs

@@ -20,7 +20,7 @@ use std::{collections::HashMap, fmt, fs, fs::File, sync::Arc, time::Instant};
 
 
 use log::{debug, error, info, trace, warn};
 use log::{debug, error, info, trace, warn};
 use rand::{prelude::IteratorRandom, rngs::OsRng, Rng};
 use rand::{prelude::IteratorRandom, rngs::OsRng, Rng};
-use smol::lock::RwLock;
+use smol::lock::{Mutex, RwLock};
 use url::Url;
 use url::Url;
 
 
 use super::{settings::SettingsPtr, ChannelPtr};
 use super::{settings::SettingsPtr, ChannelPtr};
@@ -796,6 +796,9 @@ pub struct Hosts {
     /// Keeps track of the last time a connection was made.
     /// Keeps track of the last time a connection was made.
     pub(in crate::net) last_connection: RwLock<Instant>,
     pub(in crate::net) last_connection: RwLock<Instant>,
 
 
+    /// Marker for IPv6 availability
+    pub(in crate::net) ipv6_available: Mutex<bool>,
+
     /// Pointer to configured P2P settings
     /// Pointer to configured P2P settings
     settings: SettingsPtr,
     settings: SettingsPtr,
 }
 }
@@ -809,6 +812,7 @@ impl Hosts {
             store_subscriber: Subscriber::new(),
             store_subscriber: Subscriber::new(),
             channel_subscriber: Subscriber::new(),
             channel_subscriber: Subscriber::new(),
             last_connection: RwLock::new(Instant::now()),
             last_connection: RwLock::new(Instant::now()),
+            ipv6_available: Mutex::new(true),
             settings,
             settings,
         })
         })
     }
     }
@@ -1030,6 +1034,22 @@ impl Hosts {
         false
         false
     }
     }
 
 
+    /// Check whether a URL is IPV6
+    pub async fn is_ipv6(&self, url: Url) -> bool {
+        // Reject Urls without host strings.
+        if url.host_str().is_none() {
+            return false
+        }
+
+        // We do this hack in order to parse IPs properly.
+        // https://github.com/whatwg/url/issues/749
+        let addr = Url::parse(&url.as_str().replace(url.scheme(), "http")).unwrap();
+        if let url::Host::Ipv6(_) = addr.host().unwrap() {
+            return true
+        }
+        false
+    }
+
     /// Import blacklisted peers specified in the config file.
     /// Import blacklisted peers specified in the config file.
     pub(in crate::net) async fn import_blacklist(&self) -> Result<()> {
     pub(in crate::net) async fn import_blacklist(&self) -> Result<()> {
         for (mut host, ports) in self.settings.blacklist.clone() {
         for (mut host, ports) in self.settings.blacklist.clone() {
@@ -1060,7 +1080,7 @@ impl Hosts {
     }
     }
 
 
     /// Filter given addresses based on certain rulesets and validity. Strictly called only on
     /// Filter given addresses based on certain rulesets and validity. Strictly called only on
-    /// the first time learning of a new peer.
+    /// the first time learning of new peers.
     async fn filter_addresses(
     async fn filter_addresses(
         &self,
         &self,
         settings: SettingsPtr,
         settings: SettingsPtr,
@@ -1069,6 +1089,7 @@ impl Hosts {
         debug!(target: "net::hosts::filter_addresses()", "Filtering addrs: {:?}", addrs);
         debug!(target: "net::hosts::filter_addresses()", "Filtering addrs: {:?}", addrs);
         let mut ret = vec![];
         let mut ret = vec![];
         let localnet = self.settings.localnet;
         let localnet = self.settings.localnet;
+        let ipv6_available = *self.ipv6_available.lock().await;
 
 
         'addr_loop: for (addr_, last_seen) in addrs {
         'addr_loop: for (addr_, last_seen) in addrs {
             // Validate that the format is `scheme://host_str:port`
             // Validate that the format is `scheme://host_str:port`
@@ -1157,10 +1178,13 @@ impl Hosts {
                 _ => continue,
                 _ => continue,
             }
             }
 
 
-            // Store this peer on Dark list if we do not support this transport.
+            // Store this peer on Dark list if we do not support this transport
+            // or if this peer is IPV6 and we do not support IPV6.
             // We will personally ignore this peer but still send it to others in
             // We will personally ignore this peer but still send it to others in
             // Protocol Addr to ensure all transports get propagated.
             // Protocol Addr to ensure all transports get propagated.
-            if !settings.allowed_transports.contains(&addr_.scheme().to_string()) {
+            if !settings.allowed_transports.contains(&addr_.scheme().to_string()) ||
+                (!ipv6_available && self.is_ipv6(addr_.clone()).await)
+            {
                 self.container.store_or_update(HostColor::Dark, addr_.clone(), *last_seen).await;
                 self.container.store_or_update(HostColor::Dark, addr_.clone(), *last_seen).await;
 
 
                 continue
                 continue
@@ -1317,6 +1341,34 @@ mod tests {
         });
         });
     }
     }
 
 
+    #[test]
+    fn test_is_ipv6() {
+        smol::block_on(async {
+            let settings = Settings { ..Default::default() };
+            let hosts = Hosts::new(Arc::new(settings.clone()));
+
+            let ipv6_hosts: Vec<Url> = vec![
+                Url::parse("tcp+tls://[::1]").unwrap(),
+                Url::parse("tcp://[2001:0000:130F:0000:0000:09C0:876A:130B]").unwrap(),
+                Url::parse("tcp://[2345:0425:2CA1:0000:0000:0567:5673:23b5]").unwrap(),
+            ];
+
+            let ipv4_hosts: Vec<Url> = vec![
+                Url::parse("tcp://192.168.10.65").unwrap(),
+                Url::parse("https://dyne.org").unwrap(),
+                Url::parse("tcp+tls://agorism.xyz").unwrap(),
+            ];
+
+            for host in ipv6_hosts {
+                assert!(hosts.is_ipv6(host).await)
+            }
+
+            for host in ipv4_hosts {
+                assert!(!hosts.is_ipv6(host).await)
+            }
+        });
+    }
+
     #[test]
     #[test]
     fn test_block_all_ports() {
     fn test_block_all_ports() {
         smol::block_on(async {
         smol::block_on(async {

+ 0 - 3
src/net/p2p.rs

@@ -63,8 +63,6 @@ pub struct P2p {
     session_refine: RefineSessionPtr,
     session_refine: RefineSessionPtr,
     /// Reference to configured [`SeedSyncSession`]
     /// Reference to configured [`SeedSyncSession`]
     session_seedsync: SeedSyncSessionPtr,
     session_seedsync: SeedSyncSessionPtr,
-    /// Marker for IPv6 availability
-    pub(in crate::net) ipv6_available: Mutex<bool>,
     /// Enable network debugging
     /// Enable network debugging
     pub dnet_enabled: Mutex<bool>,
     pub dnet_enabled: Mutex<bool>,
     /// The subscriber for which we can give dnet info over
     /// The subscriber for which we can give dnet info over
@@ -94,7 +92,6 @@ impl P2p {
             session_refine: RefineSession::new(),
             session_refine: RefineSession::new(),
             session_seedsync: SeedSyncSession::new(),
             session_seedsync: SeedSyncSession::new(),
 
 
-            ipv6_available: Mutex::new(true),
             dnet_enabled: Mutex::new(false),
             dnet_enabled: Mutex::new(false),
             dnet_subscriber: Subscriber::new(),
             dnet_subscriber: Subscriber::new(),
         });
         });