Skip to content

Commit 77c2aec

Browse files
authored
Fix socks proxy local DNS resolution not respected (#30619)
Closes #30618 Release Notes: - Fixed SOCKS proxy incorrectly always uses remote DNS resolution.
1 parent 3ee56c1 commit 77c2aec

File tree

1 file changed

+111
-16
lines changed

1 file changed

+111
-16
lines changed

crates/client/src/proxy/socks_proxy.rs

Lines changed: 111 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
use anyhow::{Context as _, Result};
44
use http_client::Url;
55
use tokio::net::TcpStream;
6-
use tokio_socks::tcp::{Socks4Stream, Socks5Stream};
6+
use tokio_socks::{
7+
IntoTargetAddr, TargetAddr,
8+
tcp::{Socks4Stream, Socks5Stream},
9+
};
710

811
use super::AsyncReadWrite;
912

@@ -23,8 +26,14 @@ pub(super) struct Socks5Authorization<'a> {
2326
/// V4 allows idenfication using a user_id
2427
/// V5 allows authorization using a username and password
2528
pub(super) enum SocksVersion<'a> {
26-
V4(Option<Socks4Identification<'a>>),
27-
V5(Option<Socks5Authorization<'a>>),
29+
V4 {
30+
local_dns: bool,
31+
identification: Option<Socks4Identification<'a>>,
32+
},
33+
V5 {
34+
local_dns: bool,
35+
authorization: Option<Socks5Authorization<'a>>,
36+
},
2837
}
2938

3039
pub(super) fn parse_socks_proxy<'t>(scheme: &str, proxy: &'t Url) -> SocksVersion<'t> {
@@ -33,13 +42,19 @@ pub(super) fn parse_socks_proxy<'t>(scheme: &str, proxy: &'t Url) -> SocksVersio
3342
"" => None,
3443
username => Some(Socks4Identification { user_id: username }),
3544
};
36-
SocksVersion::V4(identification)
45+
SocksVersion::V4 {
46+
local_dns: scheme != "socks4a",
47+
identification,
48+
}
3749
} else {
3850
let authorization = proxy.password().map(|password| Socks5Authorization {
3951
username: proxy.username(),
4052
password,
4153
});
42-
SocksVersion::V5(authorization)
54+
SocksVersion::V5 {
55+
local_dns: scheme != "socks5h",
56+
authorization,
57+
}
4358
}
4459
}
4560

@@ -48,26 +63,58 @@ pub(super) async fn connect_socks_proxy_stream(
4863
socks_version: SocksVersion<'_>,
4964
rpc_host: (&str, u16),
5065
) -> Result<Box<dyn AsyncReadWrite>> {
66+
let rpc_host = rpc_host
67+
.into_target_addr()
68+
.context("Failed to parse target addr")?;
69+
70+
let local_dns = match &socks_version {
71+
SocksVersion::V4 { local_dns, .. } => local_dns,
72+
SocksVersion::V5 { local_dns, .. } => local_dns,
73+
};
74+
let rpc_host = match (rpc_host, local_dns) {
75+
(TargetAddr::Domain(domain, port), true) => {
76+
let ip_addr = tokio::net::lookup_host((domain.as_ref(), port))
77+
.await
78+
.with_context(|| format!("Failed to lookup domain {}", domain))?
79+
.next()
80+
.ok_or_else(|| anyhow::anyhow!("Failed to lookup domain {}", domain))?;
81+
TargetAddr::Ip(ip_addr)
82+
}
83+
(rpc_host, _) => rpc_host,
84+
};
85+
5186
match socks_version {
52-
SocksVersion::V4(None) => {
87+
SocksVersion::V4 {
88+
identification: None,
89+
..
90+
} => {
5391
let socks = Socks4Stream::connect_with_socket(stream, rpc_host)
5492
.await
5593
.context("error connecting to socks")?;
5694
Ok(Box::new(socks))
5795
}
58-
SocksVersion::V4(Some(Socks4Identification { user_id })) => {
96+
SocksVersion::V4 {
97+
identification: Some(Socks4Identification { user_id }),
98+
..
99+
} => {
59100
let socks = Socks4Stream::connect_with_userid_and_socket(stream, rpc_host, user_id)
60101
.await
61102
.context("error connecting to socks")?;
62103
Ok(Box::new(socks))
63104
}
64-
SocksVersion::V5(None) => {
105+
SocksVersion::V5 {
106+
authorization: None,
107+
..
108+
} => {
65109
let socks = Socks5Stream::connect_with_socket(stream, rpc_host)
66110
.await
67111
.context("error connecting to socks")?;
68112
Ok(Box::new(socks))
69113
}
70-
SocksVersion::V5(Some(Socks5Authorization { username, password })) => {
114+
SocksVersion::V5 {
115+
authorization: Some(Socks5Authorization { username, password }),
116+
..
117+
} => {
71118
let socks = Socks5Stream::connect_with_password_and_socket(
72119
stream, rpc_host, username, password,
73120
)
@@ -90,7 +137,13 @@ mod tests {
90137
let scheme = proxy.scheme();
91138

92139
let version = parse_socks_proxy(scheme, &proxy);
93-
assert!(matches!(version, SocksVersion::V4(None)))
140+
assert!(matches!(
141+
version,
142+
SocksVersion::V4 {
143+
local_dns: true,
144+
identification: None
145+
}
146+
))
94147
}
95148

96149
#[test]
@@ -101,7 +154,25 @@ mod tests {
101154
let version = parse_socks_proxy(scheme, &proxy);
102155
assert!(matches!(
103156
version,
104-
SocksVersion::V4(Some(Socks4Identification { user_id: "userid" }))
157+
SocksVersion::V4 {
158+
local_dns: true,
159+
identification: Some(Socks4Identification { user_id: "userid" })
160+
}
161+
))
162+
}
163+
164+
#[test]
165+
fn parse_socks4_with_remote_dns() {
166+
let proxy = Url::parse("socks4a://proxy.example.com:1080").unwrap();
167+
let scheme = proxy.scheme();
168+
169+
let version = parse_socks_proxy(scheme, &proxy);
170+
assert!(matches!(
171+
version,
172+
SocksVersion::V4 {
173+
local_dns: false,
174+
identification: None
175+
}
105176
))
106177
}
107178

@@ -111,7 +182,13 @@ mod tests {
111182
let scheme = proxy.scheme();
112183

113184
let version = parse_socks_proxy(scheme, &proxy);
114-
assert!(matches!(version, SocksVersion::V5(None)))
185+
assert!(matches!(
186+
version,
187+
SocksVersion::V5 {
188+
local_dns: true,
189+
authorization: None
190+
}
191+
))
115192
}
116193

117194
#[test]
@@ -122,10 +199,28 @@ mod tests {
122199
let version = parse_socks_proxy(scheme, &proxy);
123200
assert!(matches!(
124201
version,
125-
SocksVersion::V5(Some(Socks5Authorization {
126-
username: "username",
127-
password: "password"
128-
}))
202+
SocksVersion::V5 {
203+
local_dns: true,
204+
authorization: Some(Socks5Authorization {
205+
username: "username",
206+
password: "password"
207+
})
208+
}
209+
))
210+
}
211+
212+
#[test]
213+
fn parse_socks5_with_remote_dns() {
214+
let proxy = Url::parse("socks5h://proxy.example.com:1080").unwrap();
215+
let scheme = proxy.scheme();
216+
217+
let version = parse_socks_proxy(scheme, &proxy);
218+
assert!(matches!(
219+
version,
220+
SocksVersion::V5 {
221+
local_dns: false,
222+
authorization: None
223+
}
129224
))
130225
}
131226
}

0 commit comments

Comments
 (0)