Skip to content

Commit 2fec20b

Browse files
committed
Ignore family-irrelevant extra Shadowsocks addresses
1 parent 6caa934 commit 2fec20b

File tree

4 files changed

+91
-9
lines changed

4 files changed

+91
-9
lines changed

mullvad-relay-selector/src/relay_selector/detailer.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,22 @@ fn get_address_for_wireguard_relay(
159159
query: &WireguardRelayQuery,
160160
relay: &Relay,
161161
) -> Result<IpAddr, Error> {
162-
match query.ip_version {
163-
Constraint::Any | Constraint::Only(IpVersion::V4) => Ok(relay.ipv4_addr_in.into()),
164-
Constraint::Only(IpVersion::V6) => relay
162+
match resolve_ip_version(query.ip_version) {
163+
IpVersion::V4 => Ok(relay.ipv4_addr_in.into()),
164+
IpVersion::V6 => relay
165165
.ipv6_addr_in
166166
.map(|addr| addr.into())
167167
.ok_or(Error::NoIPv6(Box::new(relay.clone()))),
168168
}
169169
}
170170

171+
pub fn resolve_ip_version(ip_version: Constraint<IpVersion>) -> IpVersion {
172+
match ip_version {
173+
Constraint::Any | Constraint::Only(IpVersion::V4) => IpVersion::V4,
174+
Constraint::Only(IpVersion::V6) => IpVersion::V6,
175+
}
176+
}
177+
171178
/// Try to pick a valid Wireguard port.
172179
fn get_port_for_wireguard_relay(
173180
query: &WireguardRelayQuery,

mullvad-relay-selector/src/relay_selector/helpers.rs

+54
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@ fn get_shadowsocks_obfuscator_inner(
139139
extra_in_addrs: &[IpAddr],
140140
desired_port: Constraint<u16>,
141141
) -> Option<SocketAddr> {
142+
// Filter out addresses for the wrong address family
143+
let extra_in_addrs: Vec<_> = extra_in_addrs
144+
.iter()
145+
.filter(|addr| addr.is_ipv4() == wg_in_addr.is_ipv4())
146+
.copied()
147+
.collect();
148+
142149
let in_ip = extra_in_addrs
143150
.iter()
144151
.choose(&mut rand::thread_rng())
@@ -283,4 +290,51 @@ mod tests {
283290
"expected selected port, got {selected_addr:?}"
284291
);
285292
}
293+
294+
/// Extra addresses that belong to the wrong IP family should be ignored
295+
#[test]
296+
fn test_shadowsocks_irrelevant_extra_addrs() {
297+
const PORT_RANGES: &[(u16, u16)] = &[(100, 200), (1000, 2000)];
298+
const IN_RANGE_PORT: u16 = 100;
299+
const OUT_OF_RANGE_PORT: u16 = 1;
300+
let wg_in_ip: IpAddr = "1.2.3.4".parse().unwrap();
301+
302+
let extra_in_addrs: &[IpAddr] = &["::2".parse().unwrap()];
303+
304+
let selected_addr = get_shadowsocks_obfuscator_inner(
305+
wg_in_ip,
306+
PORT_RANGES,
307+
extra_in_addrs,
308+
Constraint::Any,
309+
)
310+
.expect("should find valid port without constraint");
311+
312+
assert_eq!(
313+
selected_addr.ip(),
314+
wg_in_ip,
315+
"expected extra IP to be ignored"
316+
);
317+
318+
let selected_addr = get_shadowsocks_obfuscator_inner(
319+
wg_in_ip,
320+
PORT_RANGES,
321+
extra_in_addrs,
322+
Constraint::Only(OUT_OF_RANGE_PORT),
323+
);
324+
assert!(
325+
selected_addr.is_none(),
326+
"expected no match for out-of-range port"
327+
);
328+
329+
let selected_addr = get_shadowsocks_obfuscator_inner(
330+
wg_in_ip,
331+
PORT_RANGES,
332+
extra_in_addrs,
333+
Constraint::Only(IN_RANGE_PORT),
334+
);
335+
assert!(
336+
selected_addr.is_some(),
337+
"expected match for within-range port"
338+
);
339+
}
286340
}

mullvad-relay-selector/src/relay_selector/matcher.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use mullvad_types::{
1010
},
1111
relay_list::{Relay, RelayEndpointData, WireguardRelayEndpointData},
1212
};
13-
use talpid_types::net::TunnelType;
13+
use talpid_types::net::{IpVersion, TunnelType};
1414

1515
use super::{
1616
parsed_relays::ParsedRelays,
@@ -142,6 +142,7 @@ fn filter_on_obfuscation(
142142
let wg_data = &relay_list.parsed_list().wireguard;
143143
filter_on_shadowsocks(
144144
&wg_data.shadowsocks_port_ranges,
145+
&query.ip_version,
145146
&query.shadowsocks_port,
146147
relay,
147148
)
@@ -155,20 +156,31 @@ fn filter_on_obfuscation(
155156
/// Returns whether `relay` satisfies the Shadowsocks filter posed by `port`.
156157
fn filter_on_shadowsocks(
157158
port_ranges: &[(u16, u16)],
158-
settings: &Constraint<ShadowsocksSettings>,
159+
ip_version: &Constraint<IpVersion>,
160+
shadowsocks: &Constraint<ShadowsocksSettings>,
159161
relay: &Relay,
160162
) -> bool {
161-
match (&settings, &relay.endpoint_data) {
163+
let ip_version = super::detailer::resolve_ip_version(*ip_version);
164+
165+
match (&shadowsocks, &relay.endpoint_data) {
162166
// If Shadowsocks is specifically asked for, we must check if the specific relay supports our port.
163167
// If there are extra addresses, then all ports are available, so we do not need to do this.
164168
(
165169
Constraint::Only(ShadowsocksSettings {
166170
port: Constraint::Only(desired_port),
167171
}),
168172
RelayEndpointData::Wireguard(wg_data),
169-
) if wg_data.shadowsocks_extra_addr_in.is_empty() => port_ranges
170-
.iter()
171-
.any(|(begin, end)| (*begin..=*end).contains(&desired_port)),
173+
) => {
174+
let filtered_extra_addrs = wg_data
175+
.shadowsocks_extra_addr_in
176+
.iter()
177+
.find(|&&addr| IpVersion::from(addr) == ip_version);
178+
179+
filtered_extra_addrs.is_some()
180+
|| port_ranges
181+
.iter()
182+
.any(|(begin, end)| (*begin..=*end).contains(desired_port))
183+
}
172184

173185
// Otherwise, any relay works.
174186
_ => true,

talpid-types/src/net/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,15 @@ pub enum IpVersion {
438438
V6,
439439
}
440440

441+
impl From<IpAddr> for IpVersion {
442+
fn from(value: IpAddr) -> Self {
443+
match value {
444+
IpAddr::V4(_) => IpVersion::V4,
445+
IpAddr::V6(_) => IpVersion::V6,
446+
}
447+
}
448+
}
449+
441450
impl fmt::Display for IpVersion {
442451
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
443452
match *self {

0 commit comments

Comments
 (0)