Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support ipv6 connect #332

Closed
sallyyu0 opened this issue Jun 5, 2020 · 4 comments
Closed

support ipv6 connect #332

sallyyu0 opened this issue Jun 5, 2020 · 4 comments

Comments

@sallyyu0
Copy link

sallyyu0 commented Jun 5, 2020

There are places that connect() still uses string url stored in slots(ex: "redis://fd00:10:0:5:5861:50ff:fe00:85:6379") instead of ConnectionInfo. Please update those to use ConnectionInfo instead to avoid parse error. Below is an example for converting string to ConnectionInfo.

fn get_conn_info(redis_url: &str) -> Option<ConnectionInfo> {
    let v: Vec<&str> = redis_url.split("://").collect();
    if v.len() == 2 {
        let h: Vec<&str> = v[1].split(":").collect();
        let port: u16 = h[h.len() - 1].parse().unwrap();
        let (host, _) = v[1].split_at(v[1].len() - port.to_string().len() - 1);
        return Some(ConnectionInfo {
            addr: Box::new(ConnectionAddr::Tcp(host.to_string(), port)),
            db: 0,
            passwd: None,
        });
    } else {
        return None;
    }
}

@sallyyu0
Copy link
Author

sallyyu0 commented Jun 5, 2020

Maybe it's better to fix format "redis://{}:{}" to "redis://[{}]:{}" for IPv6 address as root cause.

@sallyyu0
Copy link
Author

sallyyu0 commented Jun 5, 2020

diff --git a/src/cluster.rs b/src/cluster.rs
index 0d74feb..5b67384 100644
--- a/src/cluster.rs
+++ b/src/cluster.rs
@@ -41,6 +41,8 @@
 use std::cell::RefCell;
 use std::collections::{BTreeMap, HashMap, HashSet};
 use std::iter::Iterator;
+use std::net::Ipv6Addr;
+use std::str::FromStr;
 use std::thread;
 use std::time::Duration;
 
@@ -262,7 +264,10 @@ impl ClusterConnection {
 
         for info in initial_nodes.iter() {
             let addr = match *info.addr {
-                ConnectionAddr::Tcp(ref host, port) => format!("redis://{}:{}", host, port),
+                ConnectionAddr::Tcp(ref host, port) => match Ipv6Addr::from_str(host) {
+                    Ok(_) => format!("redis://[{}]:{}", host, port),
+                    Err(_) => format!("redis://{}:{}", host, port),
+                },
                 _ => panic!("No reach."),
             };
 
@@ -314,12 +319,11 @@ impl ClusterConnection {
                             continue;
                         }
                     }
-
-                    if let Ok(mut conn) =
-                        connect(addr.as_ref(), self.readonly, self.password.clone())
-                    {
-                        if check_connection(&mut conn) {
-                            new_connections.insert(addr.to_string(), conn);
+                    if let Some(info) = get_conn_info(addr.as_ref()) {
+                        if let Ok(mut conn) = connect(info, self.readonly, self.password.clone()) {
+                            if check_connection(&mut conn) {
+                                new_connections.insert(addr.to_string(), conn);
+                            }
                         }
                     }
                 }
@@ -413,8 +417,15 @@ impl ClusterConnection {
         } else {
             // Create new connection.
             // TODO: error handling
-            let conn = connect(addr, self.readonly, self.password.clone())?;
-            Ok(connections.entry(addr.to_string()).or_insert(conn))
+            if let Some(info) = get_conn_info(addr) {
+                let conn = connect(info, self.readonly, self.password.clone())?;
+                Ok(connections.entry(addr.to_string()).or_insert(conn))
+            } else {
+                Err(RedisError::from((
+                    ErrorKind::ExecAbortError,
+                    "Cannot translate url to ConnectionInfo.",
+                )))
+            }
         }
     }
 
@@ -825,7 +836,10 @@ fn get_slots(connection: &mut Connection) -> RedisResult<Vec<Slot>> {
                         } else {
                             return None;
                         };
-                        Some(format!("redis://{}:{}", ip, port))
+                        match Ipv6Addr::from_str(&ip) {
+                            Ok(_) => Some(format!("redis://[{}]:{}", ip, port)),
+                            Err(_) => Some(format!("redis://{}:{}", ip, port)),
+                        }
                     } else {
                         None
                     }
@@ -848,7 +862,27 @@ fn get_slots(connection: &mut Connection) -> RedisResult<Vec<Slot>> {
 
     Ok(result)
 }
-
+// translate redis_url to ConnectionInfo
+fn get_conn_info(redis_url: &str) -> Option<ConnectionInfo> {
+    let v: Vec<&str> = redis_url.split("://").collect();
+    if v.len() == 2 {
+        let h: Vec<&str> = v[1].split(":").collect();
+        let port: u16 = h[h.len() - 1].parse().unwrap();
+        let (host, _) = v[1].split_at(v[1].len() - port.to_string().len() - 1);
+        return Some(ConnectionInfo {
+            addr: Box::new(ConnectionAddr::Tcp(
+                host.trim_start_matches('[')
+                    .trim_end_matches(']')
+                    .to_string(),
+                port,
+            )),
+            db: 0,
+            passwd: None,
+        });
+    } else {
+        return None;
+    }
+}
 #[cfg(test)]

@vstakhov
Copy link

vstakhov commented Nov 7, 2021

Is there any workaround for this issue? I have tried to specify IPv6 address in many ways: as [::1]:6379, as ::1:6379, parse it to url::Url (which worked for [::1]:6379 but still failed with redis-rs with the following error: failed to lookup address information: nodename nor servname provided, or not known).

I'd be happy to use any workaround for IPv6 addresses in fact.

jaymell pushed a commit that referenced this issue Sep 14, 2022
@djc
Copy link
Contributor

djc commented Sep 14, 2022

Should be fixed with #679.

@djc djc closed this as completed Sep 14, 2022
nonirosenfeldredis pushed a commit to nonirosenfeldredis/redis-rs that referenced this issue Feb 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants