Skip to content

Commit 256de2b

Browse files
authored
fix(proxy): restore default port 1080 for SOCKS proxies without explicit port (#821)
1 parent d5d60ab commit 256de2b

2 files changed

Lines changed: 63 additions & 6 deletions

File tree

src/core/client/proxy/matcher.rs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use std::{fmt, net::IpAddr};
1616

1717
use bytes::Bytes;
18-
use http::header::HeaderValue;
18+
use http::{header::HeaderValue, uri::Authority};
1919
use ipnet::IpNet;
2020
use percent_encoding::percent_decode_str;
2121

@@ -328,14 +328,16 @@ fn parse_env_uri(val: &str) -> Option<Intercept> {
328328
let uri = val.parse::<http::Uri>().ok()?;
329329
let mut builder = http::Uri::builder();
330330
let mut is_httpish = false;
331+
let mut is_socks = false;
331332
let mut auth = Auth::Empty;
332333

333334
builder = builder.scheme(match uri.scheme() {
334335
Some(s) => {
335336
if s == &http::uri::Scheme::HTTP || s == &http::uri::Scheme::HTTPS {
336337
is_httpish = true;
337338
s.clone()
338-
} else if s.as_str() == "socks5" || s.as_str() == "socks5h" {
339+
} else if matches!(s.as_str(), "socks4" | "socks4a" | "socks5" | "socks5h") {
340+
is_socks = true;
339341
s.clone()
340342
} else {
341343
// can't use this proxy scheme
@@ -349,7 +351,13 @@ fn parse_env_uri(val: &str) -> Option<Intercept> {
349351
}
350352
});
351353

354+
// If the scheme is a SOCKS protocol and no port is specified, set the default port to 1080.
352355
let authority = uri.authority()?;
356+
let authority = if is_socks && authority.port().is_none() {
357+
format!("{authority}:1080").parse::<Authority>().ok()?
358+
} else {
359+
authority.clone()
360+
};
353361

354362
if let Some((userinfo, host_port)) = authority.as_str().split_once('@') {
355363
let (user, pass) = userinfo.split_once(':')?;
@@ -365,15 +373,15 @@ fn parse_env_uri(val: &str) -> Option<Intercept> {
365373
}
366374
builder = builder.authority(host_port);
367375
} else {
368-
builder = builder.authority(authority.clone());
376+
builder = builder.authority(authority);
369377
}
370378

371379
// removing any path, but we MUST specify one or the builder errors
372380
builder = builder.path_and_query("/");
373381

374-
let dst = builder.build().ok()?;
382+
let uri = builder.build().ok()?;
375383

376-
Some(Intercept { uri: dst, auth })
384+
Some(Intercept { uri, auth })
377385
}
378386

379387
fn encode_basic_auth(user: &str, pass: Option<&str>) -> HeaderValue {
@@ -838,4 +846,25 @@ mod tests {
838846

839847
assert!(m.intercept(&"http://rick.roll".parse().unwrap()).is_none());
840848
}
849+
850+
fn test_parse_socks(url: &str) {
851+
let p = p! {
852+
all = url,
853+
};
854+
855+
let proxy = intercept(&p, "https://example.local");
856+
assert_eq!(proxy.uri(), url);
857+
}
858+
859+
#[test]
860+
fn test_parse_socks4() {
861+
test_parse_socks("socks4://localhost:8887");
862+
test_parse_socks("socks4a://localhost:8887");
863+
}
864+
865+
#[test]
866+
fn test_parse_socks5() {
867+
test_parse_socks("socks5://localhost:8887");
868+
test_parse_socks("socks5h://localhost:8887");
869+
}
841870
}

src/proxy.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ pub trait IntoProxy {
126126
impl<S: IntoUrl> IntoProxy for S {
127127
fn into_proxy(self) -> crate::Result<Url> {
128128
match self.as_str().into_url() {
129-
Ok(ok) => Ok(ok),
129+
Ok(url) => Ok(url),
130130
Err(e) => {
131131
let mut presumed_to_have_scheme = true;
132132
let mut source = e.source();
@@ -602,4 +602,32 @@ mod tests {
602602
.into_matcher();
603603
assert!(m.maybe_has_http_auth(), "http forwards");
604604
}
605+
606+
fn test_socks_proxy_default_port(url: &str, url2: &str, port: u16) {
607+
let m = Proxy::all(url).unwrap().into_matcher();
608+
609+
let http = "http://hyper.rs";
610+
let https = "https://hyper.rs";
611+
612+
assert_eq!(intercepted_uri(&m, http).port_u16(), Some(1080));
613+
assert_eq!(intercepted_uri(&m, https).port_u16(), Some(1080));
614+
615+
// custom port
616+
let m = Proxy::all(url2).unwrap().into_matcher();
617+
618+
assert_eq!(intercepted_uri(&m, http).port_u16(), Some(port));
619+
assert_eq!(intercepted_uri(&m, https).port_u16(), Some(port));
620+
}
621+
622+
#[test]
623+
fn test_socks4_proxy_default_port() {
624+
test_socks_proxy_default_port("socks4://example.com", "socks4://example.com:1234", 1234);
625+
test_socks_proxy_default_port("socks4a://example.com", "socks4a://example.com:1234", 1234);
626+
}
627+
628+
#[test]
629+
fn test_socks5_proxy_default_port() {
630+
test_socks_proxy_default_port("socks5://example.com", "socks5://example.com:1234", 1234);
631+
test_socks_proxy_default_port("socks5h://example.com", "socks5h://example.com:1234", 1234);
632+
}
605633
}

0 commit comments

Comments
 (0)