fix: http/https proxy (#7821)

* add http(s) proxy

* Add front-end translation

* fix ui description

* For linux platform, add rustls support

* fix: Fix the proxy address test function.

* add: Added default prompts for agency agreement and some multi-language translations

* add: Http proxy request client

* fix: add async http proxy func and format the code

* add: Preliminary support for flutter front-end calling rust back-end http request

* Optimize HTTP calls

* Optimize HTTP calls

* fix: Optimize HTTP requests, refine translations, and fix dependencies

* fix: Win and macOS compilation errors

* fix: web platforms

* fix: Optimize import

* fix: Fix web platform issues

* fix: Fix web platform issues

* fix: update ci

* fix: test ci

* test: test CI

* Revert "fix: update ci"

This reverts commit 2e5f247b2e.

* test: test CI

* test: test CI

* fix: fix lock file

* fix: Optimize imports
This commit is contained in:
yuluo
2024-04-25 11:46:21 +08:00
committed by GitHub
parent 66d1af63b0
commit 43a0a4f8e0
68 changed files with 1174 additions and 131 deletions

View File

@@ -1,4 +1,4 @@
use crate::{bail, bytes_codec::BytesCodec, ResultType};
use crate::{bail, bytes_codec::BytesCodec, ResultType, config::Socks5Server, proxy::Proxy};
use anyhow::Context as AnyhowCtx;
use bytes::{BufMut, Bytes, BytesMut};
use futures::{SinkExt, StreamExt};
@@ -18,20 +18,20 @@ use tokio::{
io::{AsyncRead, AsyncWrite, ReadBuf},
net::{lookup_host, TcpListener, TcpSocket, ToSocketAddrs},
};
use tokio_socks::{tcp::Socks5Stream, IntoTargetAddr, ToProxyAddrs};
use tokio_socks::IntoTargetAddr;
use tokio_util::codec::Framed;
pub trait TcpStreamTrait: AsyncRead + AsyncWrite + Unpin {}
pub struct DynTcpStream(Box<dyn TcpStreamTrait + Send + Sync>);
pub struct DynTcpStream(pub(crate) Box<dyn TcpStreamTrait + Send + Sync>);
#[derive(Clone)]
pub struct Encrypt(Key, u64, u64);
pub struct FramedStream(
Framed<DynTcpStream, BytesCodec>,
SocketAddr,
Option<Encrypt>,
u64,
pub(crate) Framed<DynTcpStream, BytesCodec>,
pub(crate) SocketAddr,
pub(crate) Option<Encrypt>,
pub(crate) u64,
);
impl Deref for FramedStream {
@@ -62,7 +62,7 @@ impl DerefMut for DynTcpStream {
}
}
fn new_socket(addr: std::net::SocketAddr, reuse: bool) -> Result<TcpSocket, std::io::Error> {
pub(crate) fn new_socket(addr: std::net::SocketAddr, reuse: bool) -> Result<TcpSocket, std::io::Error> {
let socket = match addr {
std::net::SocketAddr::V4(..) => TcpSocket::new_v4()?,
std::net::SocketAddr::V6(..) => TcpSocket::new_v6()?,
@@ -109,51 +109,17 @@ impl FramedStream {
bail!(format!("Failed to connect to {remote_addr}"));
}
pub async fn connect<'a, 't, P, T>(
proxy: P,
pub async fn connect<'t, T>(
target: T,
local_addr: Option<SocketAddr>,
username: &'a str,
password: &'a str,
proxy_conf: &Socks5Server,
ms_timeout: u64,
) -> ResultType<Self>
where
P: ToProxyAddrs,
T: IntoTargetAddr<'t>,
{
if let Some(Ok(proxy)) = proxy.to_proxy_addrs().next().await {
let local = if let Some(addr) = local_addr {
addr
} else {
crate::config::Config::get_any_listen_addr(proxy.is_ipv4())
};
let stream =
super::timeout(ms_timeout, new_socket(local, true)?.connect(proxy)).await??;
stream.set_nodelay(true).ok();
let stream = if username.trim().is_empty() {
super::timeout(
ms_timeout,
Socks5Stream::connect_with_socket(stream, target),
)
.await??
} else {
super::timeout(
ms_timeout,
Socks5Stream::connect_with_password_and_socket(
stream, target, username, password,
),
)
.await??
};
let addr = stream.local_addr()?;
return Ok(Self(
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
addr,
None,
0,
));
}
bail!("could not resolve to any address");
let proxy = Proxy::from_conf(proxy_conf, Some(ms_timeout))?;
proxy.connect::<T>(target, local_addr).await
}
pub fn local_addr(&self) -> SocketAddr {