From d601a82b5a46b961b6e6cfa08d8ac8091fc92fcf Mon Sep 17 00:00:00 2001 From: qiushiyang Date: Tue, 17 Jan 2023 22:46:11 +0800 Subject: [PATCH 1/4] Allow direct connect to {hostname}:{port} --- libs/hbb_common/src/lib.rs | 22 ++++++++++++++++++++++ src/client.rs | 11 +++++++++++ 2 files changed, 33 insertions(+) diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 49be934fb..1069cb8cf 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -321,6 +321,13 @@ pub fn is_ip_str(id: &str) -> bool { is_ipv4_str(id) || is_ipv6_str(id) } +#[inline] +pub fn is_hostname_port_str(id: &str) -> bool { + regex::Regex::new(r"^[\-.0-9a-zA-Z]+:\d{1,5}$") + .unwrap() + .is_match(id) +} + #[cfg(test)] mod test_lib { use super::*; @@ -340,4 +347,19 @@ mod test_lib { assert_eq!(is_ipv6_str("[1:2::0]:"), false); assert_eq!(is_ipv6_str("1:2::0]:1"), false); } + #[test] + fn test_hostname_port() { + assert_eq!(is_ipv6_str("a:12"), true); + assert_eq!(is_ipv6_str("a.b.c:12"), true); + assert_eq!(is_ipv6_str("test.com:12"), true); + assert_eq!(is_ipv6_str("1.2.3:12"), true); + assert_eq!(is_ipv6_str("a.b.c:123456"), false); + // todo: should we also check for these edge case? + // out-of-range port + assert_eq!(is_ipv6_str("test.com:0"), true); + assert_eq!(is_ipv6_str("test.com:98989"), true); + // invalid hostname + assert_eq!(is_ipv6_str("---:12"), true); + assert_eq!(is_ipv6_str(".:12"), true); + } } diff --git a/src/client.rs b/src/client.rs index 8b2edbcda..f3cca9b36 100644 --- a/src/client.rs +++ b/src/client.rs @@ -181,6 +181,17 @@ impl Client { true, )); } + // Allow connect to {hostname}:{port} + if hbb_common.is_hostname_port_str(peer) { + return Ok(( + socket_client::connect_tcp( + peer, + RENDEZVOUS_TIMEOUT, + ) + .await?, + true, + )); + } let (mut rendezvous_server, servers, contained) = crate::get_rendezvous_server(1_000).await; let mut socket = socket_client::connect_tcp(&*rendezvous_server, RENDEZVOUS_TIMEOUT).await; debug_assert!(!servers.contains(&rendezvous_server)); From f10f969c2c2626251011ab99df1d09c4fa972228 Mon Sep 17 00:00:00 2001 From: qiushiyang Date: Wed, 18 Jan 2023 02:08:44 +0000 Subject: [PATCH 2/4] fix syntax error --- src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.rs b/src/client.rs index f3cca9b36..304314326 100644 --- a/src/client.rs +++ b/src/client.rs @@ -182,7 +182,7 @@ impl Client { )); } // Allow connect to {hostname}:{port} - if hbb_common.is_hostname_port_str(peer) { + if hbb_common::is_hostname_port_str(peer) { return Ok(( socket_client::connect_tcp( peer, From 12d446b217ed5987c43979609440c12aee24c4ce Mon Sep 17 00:00:00 2001 From: qiushiyang Date: Wed, 18 Jan 2023 03:35:13 +0000 Subject: [PATCH 3/4] fix test for is_hostname_port_str --- libs/hbb_common/src/lib.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 1069cb8cf..29b066c66 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -347,19 +347,20 @@ mod test_lib { assert_eq!(is_ipv6_str("[1:2::0]:"), false); assert_eq!(is_ipv6_str("1:2::0]:1"), false); } + #[test] fn test_hostname_port() { - assert_eq!(is_ipv6_str("a:12"), true); - assert_eq!(is_ipv6_str("a.b.c:12"), true); - assert_eq!(is_ipv6_str("test.com:12"), true); - assert_eq!(is_ipv6_str("1.2.3:12"), true); - assert_eq!(is_ipv6_str("a.b.c:123456"), false); + assert_eq!(is_hostname_port_str("a:12"), true); + assert_eq!(is_hostname_port_str("a.b.c:12"), true); + assert_eq!(is_hostname_port_str("test.com:12"), true); + assert_eq!(is_hostname_port_str("1.2.3:12"), true); + assert_eq!(is_hostname_port_str("a.b.c:123456"), false); // todo: should we also check for these edge case? // out-of-range port - assert_eq!(is_ipv6_str("test.com:0"), true); - assert_eq!(is_ipv6_str("test.com:98989"), true); + assert_eq!(is_hostname_port_str("test.com:0"), true); + assert_eq!(is_hostname_port_str("test.com:98989"), true); // invalid hostname - assert_eq!(is_ipv6_str("---:12"), true); - assert_eq!(is_ipv6_str(".:12"), true); + assert_eq!(is_hostname_port_str("---:12"), true); + assert_eq!(is_hostname_port_str(".:12"), true); } } From aa2cd37fb35c791bb9906d80b69206d311d78a11 Mon Sep 17 00:00:00 2001 From: qiushiyang Date: Wed, 18 Jan 2023 06:08:46 +0000 Subject: [PATCH 4/4] use more accurate regex for {domain}:{port} --- libs/hbb_common/src/lib.rs | 40 ++++++++++++++++++++++++-------------- src/client.rs | 12 ++++-------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 29b066c66..e57994f34 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -322,10 +322,15 @@ pub fn is_ip_str(id: &str) -> bool { } #[inline] -pub fn is_hostname_port_str(id: &str) -> bool { - regex::Regex::new(r"^[\-.0-9a-zA-Z]+:\d{1,5}$") - .unwrap() - .is_match(id) +pub fn is_domain_port_str(id: &str) -> bool { + // modified regex for RFC1123 hostname. check https://stackoverflow.com/a/106223 for original version for hostname. + // according to [TLD List](https://data.iana.org/TLD/tlds-alpha-by-domain.txt) version 2023011700, + // there is no digits in TLD, and length is 2~63. + regex::Regex::new( + r"(?i)^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z-]{0,61}[a-z]:\d{1,5}$", + ) + .unwrap() + .is_match(id) } #[cfg(test)] @@ -350,17 +355,22 @@ mod test_lib { #[test] fn test_hostname_port() { - assert_eq!(is_hostname_port_str("a:12"), true); - assert_eq!(is_hostname_port_str("a.b.c:12"), true); - assert_eq!(is_hostname_port_str("test.com:12"), true); - assert_eq!(is_hostname_port_str("1.2.3:12"), true); - assert_eq!(is_hostname_port_str("a.b.c:123456"), false); - // todo: should we also check for these edge case? + assert_eq!(is_domain_port_str("a:12"), false); + assert_eq!(is_domain_port_str("a.b.c:12"), false); + assert_eq!(is_domain_port_str("test.com:12"), true); + assert_eq!(is_domain_port_str("test-UPPER.com:12"), true); + assert_eq!(is_domain_port_str("some-other.domain.com:12"), true); + assert_eq!(is_domain_port_str("under_score:12"), false); + assert_eq!(is_domain_port_str("a@bc:12"), false); + assert_eq!(is_domain_port_str("1.1.1.1:12"), false); + assert_eq!(is_domain_port_str("1.2.3:12"), false); + assert_eq!(is_domain_port_str("1.2.3.45:12"), false); + assert_eq!(is_domain_port_str("a.b.c:123456"), false); + assert_eq!(is_domain_port_str("---:12"), false); + assert_eq!(is_domain_port_str(".:12"), false); + // todo: should we also check for these edge cases? // out-of-range port - assert_eq!(is_hostname_port_str("test.com:0"), true); - assert_eq!(is_hostname_port_str("test.com:98989"), true); - // invalid hostname - assert_eq!(is_hostname_port_str("---:12"), true); - assert_eq!(is_hostname_port_str(".:12"), true); + assert_eq!(is_domain_port_str("test.com:0"), true); + assert_eq!(is_domain_port_str("test.com:98989"), true); } } diff --git a/src/client.rs b/src/client.rs index 304314326..493448c3b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -7,10 +7,10 @@ use cpal::{ use magnum_opus::{Channels::*, Decoder as AudioDecoder}; use sha2::{Digest, Sha256}; use std::{ - str::FromStr, collections::HashMap, net::SocketAddr, ops::{Deref, Not}, + str::FromStr, sync::{atomic::AtomicBool, mpsc, Arc, Mutex, RwLock}, }; use uuid::Uuid; @@ -181,14 +181,10 @@ impl Client { true, )); } - // Allow connect to {hostname}:{port} - if hbb_common::is_hostname_port_str(peer) { + // Allow connect to {domain}:{port} + if hbb_common::is_domain_port_str(peer) { return Ok(( - socket_client::connect_tcp( - peer, - RENDEZVOUS_TIMEOUT, - ) - .await?, + socket_client::connect_tcp(peer, RENDEZVOUS_TIMEOUT).await?, true, )); }