forked from rapiz1/rathole
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support SOCKS5 and HTTP proxy (rapiz1#135)
* chore: add comments * feat: support socks5/http proxy * fix: clippy * fix: always validate tcp config * chore: rename directories
- Loading branch information
Showing
9 changed files
with
152 additions
and
28 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -108,6 +108,9 @@ default_token = "default_token_if_not_specify" # Optional. The default token of | |
|
||
[client.transport] # The whole block is optional. Specify which transport to use | ||
type = "tcp" # Optional. Possible values: ["tcp", "tls", "noise"]. Default: "tcp" | ||
|
||
[client.transport.tcp] # Optional | ||
proxy = "socks5://user:[email protected]:1080" # Optional. Use the proxy to connect to the server | ||
nodelay = false # Optional. Determine whether to enable TCP_NODELAY, if applicable, to improve the latency but decrease the bandwidth. Default: false | ||
keepalive_secs = 10 # Optional. Specify `tcp_keepalive_time` in `tcp(7)`, if applicable. Default: 10 seconds | ||
keepalive_interval = 5 # Optional. Specify `tcp_keepalive_intvl` in `tcp(7)`, if applicable. Default: 5 seconds | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[client] | ||
remote_addr = "127.0.0.1:2333" | ||
default_token = "123" | ||
|
||
[client.services.foo1] | ||
local_addr = "127.0.0.1:80" | ||
|
||
[client.transport] | ||
type = "tcp" | ||
[client.transport.tcp] | ||
# `proxy` controls how the client connect to the server | ||
# Use socks5 proxy at 127.0.0.1, with port 1080, username 'myuser' and password 'mypass' | ||
proxy = "socks5://myuser:[email protected]:1080" | ||
# Use http proxy. Similar to socks5 proxy | ||
# proxy = "http://myuser:[email protected]:8080" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
use anyhow::{anyhow, Result}; | ||
use async_http_proxy::{http_connect_tokio, http_connect_tokio_with_basic_auth}; | ||
use backoff::{backoff::Backoff, Notify}; | ||
use socket2::{SockRef, TcpKeepalive}; | ||
use std::{future::Future, net::SocketAddr, time::Duration}; | ||
|
@@ -7,6 +8,7 @@ use tokio::{ | |
sync::broadcast, | ||
}; | ||
use tracing::trace; | ||
use url::Url; | ||
|
||
// Tokio hesitates to expose this option...So we have to do it on our own :( | ||
// The good news is that using socket2 it can be easily done, without losing portability. | ||
|
@@ -38,12 +40,21 @@ pub fn feature_not_compile(feature: &str) -> ! { | |
) | ||
} | ||
|
||
/// Create a UDP socket and connect to `addr` | ||
pub async fn udp_connect<A: ToSocketAddrs>(addr: A) -> Result<UdpSocket> { | ||
let addr = lookup_host(addr) | ||
async fn to_socket_addr<A: ToSocketAddrs>(addr: A) -> Result<SocketAddr> { | ||
lookup_host(addr) | ||
.await? | ||
.next() | ||
.ok_or(anyhow!("Failed to lookup the host"))?; | ||
.ok_or(anyhow!("Failed to lookup the host")) | ||
} | ||
|
||
pub fn host_port_pair(s: &str) -> Result<(&str, u16)> { | ||
let semi = s.rfind(':').expect("missing semicolon"); | ||
Ok((&s[..semi], s[semi + 1..].parse()?)) | ||
} | ||
|
||
/// Create a UDP socket and connect to `addr` | ||
pub async fn udp_connect<A: ToSocketAddrs>(addr: A) -> Result<UdpSocket> { | ||
let addr = to_socket_addr(addr).await?; | ||
|
||
let bind_addr = match addr { | ||
SocketAddr::V4(_) => "0.0.0.0:0", | ||
|
@@ -55,6 +66,52 @@ pub async fn udp_connect<A: ToSocketAddrs>(addr: A) -> Result<UdpSocket> { | |
Ok(s) | ||
} | ||
|
||
/// Create a TcpStream using a proxy | ||
/// e.g. socks5://user:[email protected]:1080 http://127.0.0.1:8080 | ||
pub async fn tcp_connect_with_proxy(addr: &str, proxy: Option<&Url>) -> Result<TcpStream> { | ||
if let Some(url) = proxy { | ||
let mut s = TcpStream::connect(( | ||
url.host_str().expect("proxy url should have host field"), | ||
url.port().expect("proxy url should have port field"), | ||
)) | ||
.await?; | ||
|
||
let auth = if !url.username().is_empty() || url.password().is_some() { | ||
Some(async_socks5::Auth { | ||
username: url.username().into(), | ||
password: url.password().unwrap_or("").into(), | ||
}) | ||
} else { | ||
None | ||
}; | ||
match url.scheme() { | ||
"socks5" => { | ||
async_socks5::connect(&mut s, host_port_pair(addr)?, auth).await?; | ||
} | ||
"http" => { | ||
let (host, port) = host_port_pair(addr)?; | ||
match auth { | ||
Some(auth) => { | ||
http_connect_tokio_with_basic_auth( | ||
&mut s, | ||
host, | ||
port, | ||
&auth.username, | ||
&auth.password, | ||
) | ||
.await? | ||
} | ||
None => http_connect_tokio(&mut s, host, port).await?, | ||
} | ||
} | ||
_ => panic!("unknown proxy scheme"), | ||
} | ||
Ok(s) | ||
} else { | ||
Ok(TcpStream::connect(addr).await?) | ||
} | ||
} | ||
|
||
// Wrapper of retry_notify | ||
pub async fn retry_notify_with_deadline<I, E, Fn, Fut, B, N>( | ||
backoff: B, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters