From 8d654330aca0dbab31b8e975c40f5729f9772a91 Mon Sep 17 00:00:00 2001 From: "sijie.sun" Date: Sat, 8 Mar 2025 13:19:23 +0800 Subject: [PATCH] fix http_connector 1. use ipv4 first when connect to http server. 2. allow redirect to url like: http://tcp://p.com:11010 3. dns should also use long timeout --- Cargo.lock | 3 ++- easytier/src/connector/dns_connector.rs | 10 ++------ easytier/src/connector/http_connector.rs | 32 ++++++++++++++++-------- easytier/src/connector/manual.rs | 5 +++- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 413baaf..0ca4fa9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3139,9 +3139,10 @@ dependencies = [ [[package]] name = "http_req" version = "0.13.1" -source = "git+https://github.com/EasyTier/http_req.git#e6d9e93c43c940f56f45e91b0923bcea53a718ea" +source = "git+https://github.com/EasyTier/http_req.git#b10aa9fc0db3067cc3d2174683a87250b80a1ea9" dependencies = [ "base64 0.22.1", + "rand 0.8.5", "rustls", "rustls-pemfile", "rustls-pki-types", diff --git a/easytier/src/connector/dns_connector.rs b/easytier/src/connector/dns_connector.rs index ec5280d..22ec16d 100644 --- a/easytier/src/connector/dns_connector.rs +++ b/easytier/src/connector/dns_connector.rs @@ -1,14 +1,8 @@ -use std::{ - net::SocketAddr, - pin::Pin, - sync::{Arc, RwLock}, -}; +use std::{net::SocketAddr, sync::Arc}; use crate::{ common::{error::Error, global_ctx::ArcGlobalCtx}, - tunnel::{ - Tunnel, TunnelConnector, TunnelError, ZCPacketSink, ZCPacketStream, PROTO_PORT_OFFSET, - }, + tunnel::{Tunnel, TunnelConnector, TunnelError, PROTO_PORT_OFFSET}, }; use anyhow::Context; use dashmap::DashSet; diff --git a/easytier/src/connector/http_connector.rs b/easytier/src/connector/http_connector.rs index d88c3f6..3757e3b 100644 --- a/easytier/src/connector/http_connector.rs +++ b/easytier/src/connector/http_connector.rs @@ -7,6 +7,7 @@ use std::{ use anyhow::Context; use http_req::request::{RedirectPolicy, Request}; use rand::seq::SliceRandom as _; +use url::Url; use crate::{ common::{error::Error, global_ctx::ArcGlobalCtx}, @@ -73,10 +74,12 @@ impl HttpTunnelConnector { async fn handle_302_redirect( &mut self, new_url: url::Url, + url_str: &str, ) -> Result, Error> { // the url should be in following format: // 1: http(s)://easytier.cn/?url=tcp://10.147.22.22:11010 (scheme is http, domain is ignored, path is splitted into proto type and addr) - // 2: tcp://10.137.22.22:11010 (scheme is protocol type, the url is used to construct a connector directly) + // 2: http(s)://tcp://10.137.22.22:11010 (connector url is appended to the scheme) + // 3: tcp://10.137.22.22:11010 (scheme is protocol type, the url is used to construct a connector directly) tracing::info!("redirect to {}", new_url); let url = url::Url::parse(new_url.as_str()) .with_context(|| format!("parsing redirect url failed. url: {}", new_url))?; @@ -86,15 +89,22 @@ impl HttpTunnelConnector { .filter_map(|x| url::Url::parse(&x.1).ok()) .collect::>(); query.shuffle(&mut rand::thread_rng()); - if query.is_empty() { - return Err(Error::InvalidUrl(format!( - "no valid connector url found in url: {}", - url - ))); + if !query.is_empty() { + tracing::info!("try to create connector by url: {}", query[0]); + self.redirect_type = HttpRedirectType::RedirectToQuery; + return create_connector_by_url(&query[0].to_string(), &self.global_ctx).await; + } else if let Some(new_url) = url_str + .strip_prefix(format!("{}://", url.scheme()).as_str()) + .and_then(|x| Url::parse(x).ok()) + { + // stripe the scheme and create connector by url + self.redirect_type = HttpRedirectType::RedirectToUrl; + return create_connector_by_url(new_url.as_str(), &self.global_ctx).await; } - tracing::info!("try to create connector by url: {}", query[0]); - self.redirect_type = HttpRedirectType::RedirectToQuery; - return create_connector_by_url(&query[0].to_string(), &self.global_ctx).await; + return Err(Error::InvalidUrl(format!( + "no valid connector url found in url: {}", + url + ))); } else { self.redirect_type = HttpRedirectType::RedirectToUrl; return create_connector_by_url(new_url.as_str(), &self.global_ctx).await; @@ -156,7 +166,7 @@ impl HttpTunnelConnector { Request::new(&uri) .redirect_policy(RedirectPolicy::Limit(0)) - .timeout(std::time::Duration::from_secs(60)) + .timeout(std::time::Duration::from_secs(20)) .send(&mut *body_clone.write().unwrap()) .with_context(|| format!("sending http request failed. url: {}", uri)) }) @@ -172,7 +182,7 @@ impl HttpTunnelConnector { .ok_or_else(|| Error::InvalidUrl("no redirect address found".to_string()))?; let new_url = url::Url::parse(redirect_url.as_str()) .with_context(|| format!("parsing redirect url failed. url: {}", redirect_url))?; - return self.handle_302_redirect(new_url).await; + return self.handle_302_redirect(new_url, &redirect_url).await; } else if res.status_code().is_success() { return self.handle_200_success(&body).await; } else { diff --git a/easytier/src/connector/manual.rs b/easytier/src/connector/manual.rs index 9bcc0cc..7b8a089 100644 --- a/easytier/src/connector/manual.rs +++ b/easytier/src/connector/manual.rs @@ -365,9 +365,12 @@ impl ManualConnectorManager { "cannot get ip from url" ))); for ip_version in ip_versions { + let use_long_timeout = dead_url.starts_with("http") + || dead_url.starts_with("srv") + || dead_url.starts_with("txt"); let ret = timeout( // allow http connector to wait longer - std::time::Duration::from_secs(if dead_url.starts_with("http") { 20 } else { 2 }), + std::time::Duration::from_secs(if use_long_timeout { 20 } else { 2 }), Self::conn_reconnect_with_ip_version( data.clone(), dead_url.clone(),