Add QUIC obfuscation to mullvad daemon and management interface
This commit is contained in:
parent
cc5ab4dcb8
commit
f98465aef1
@ -215,6 +215,8 @@ internal fun ManagementInterface.ObfuscationEndpoint.ObfuscationType.toDomain():
|
||||
ManagementInterface.ObfuscationEndpoint.ObfuscationType.UDP2TCP -> ObfuscationType.Udp2Tcp
|
||||
ManagementInterface.ObfuscationEndpoint.ObfuscationType.SHADOWSOCKS ->
|
||||
ObfuscationType.Shadowsocks
|
||||
ManagementInterface.ObfuscationEndpoint.ObfuscationType.QUIC ->
|
||||
throw IllegalArgumentException("Unsupported obfuscation type")
|
||||
ManagementInterface.ObfuscationEndpoint.ObfuscationType.UNRECOGNIZED ->
|
||||
throw IllegalArgumentException("Unrecognized obfuscation type")
|
||||
}
|
||||
@ -419,6 +421,8 @@ internal fun ManagementInterface.ObfuscationSettings.SelectedObfuscation.toDomai
|
||||
ObfuscationMode.Udp2Tcp
|
||||
ManagementInterface.ObfuscationSettings.SelectedObfuscation.SHADOWSOCKS ->
|
||||
ObfuscationMode.Shadowsocks
|
||||
ManagementInterface.ObfuscationSettings.SelectedObfuscation.QUIC ->
|
||||
throw IllegalArgumentException("Unsupported obfuscation type")
|
||||
ManagementInterface.ObfuscationSettings.SelectedObfuscation.UNRECOGNIZED ->
|
||||
throw IllegalArgumentException("Unrecognized selected obfuscation")
|
||||
}
|
||||
|
@ -305,6 +305,11 @@ export class DaemonRpc extends GrpcClient {
|
||||
grpcTypes.ObfuscationSettings.SelectedObfuscation.UDP2TCP,
|
||||
);
|
||||
break;
|
||||
case ObfuscationType.quic:
|
||||
grpcObfuscationSettings.setSelectedObfuscation(
|
||||
grpcTypes.ObfuscationSettings.SelectedObfuscation.QUIC,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
if (obfuscationSettings.udp2tcpSettings) {
|
||||
|
@ -461,6 +461,7 @@ export enum ObfuscationType {
|
||||
off,
|
||||
udp2tcp,
|
||||
shadowsocks,
|
||||
quic,
|
||||
}
|
||||
|
||||
export type ObfuscationSettings = {
|
||||
|
@ -296,6 +296,7 @@ message ObfuscationEndpoint {
|
||||
enum ObfuscationType {
|
||||
UDP2TCP = 0;
|
||||
SHADOWSOCKS = 1;
|
||||
QUIC = 2;
|
||||
}
|
||||
|
||||
string address = 1;
|
||||
@ -390,6 +391,7 @@ message ObfuscationSettings {
|
||||
OFF = 1;
|
||||
UDP2TCP = 2;
|
||||
SHADOWSOCKS = 3;
|
||||
QUIC = 4;
|
||||
}
|
||||
SelectedObfuscation selected_obfuscation = 1;
|
||||
Udp2TcpObfuscationSettings udp2tcp = 2;
|
||||
|
@ -39,6 +39,9 @@ impl From<talpid_types::net::TunnelEndpoint> for proto::TunnelEndpoint {
|
||||
net::ObfuscationType::Shadowsocks => {
|
||||
i32::from(proto::obfuscation_endpoint::ObfuscationType::Shadowsocks)
|
||||
}
|
||||
net::ObfuscationType::Quic => {
|
||||
i32::from(proto::obfuscation_endpoint::ObfuscationType::Quic)
|
||||
}
|
||||
},
|
||||
}
|
||||
}),
|
||||
@ -123,6 +126,9 @@ impl TryFrom<proto::TunnelEndpoint> for talpid_types::net::TunnelEndpoint {
|
||||
Ok(proto::obfuscation_endpoint::ObfuscationType::Shadowsocks) => {
|
||||
talpid_net::ObfuscationType::Shadowsocks
|
||||
}
|
||||
Ok(proto::obfuscation_endpoint::ObfuscationType::Quic) => {
|
||||
talpid_net::ObfuscationType::Quic
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(FromProtobufTypeError::InvalidArgument(
|
||||
"unknown obfuscation type",
|
||||
|
@ -151,6 +151,7 @@ impl From<&mullvad_types::relay_constraints::ObfuscationSettings> for proto::Obf
|
||||
SelectedObfuscation::Shadowsocks => {
|
||||
proto::obfuscation_settings::SelectedObfuscation::Shadowsocks
|
||||
}
|
||||
SelectedObfuscation::Quic => proto::obfuscation_settings::SelectedObfuscation::Quic,
|
||||
});
|
||||
Self {
|
||||
selected_obfuscation,
|
||||
@ -437,6 +438,7 @@ impl TryFrom<proto::ObfuscationSettings> for mullvad_types::relay_constraints::O
|
||||
Ok(IpcSelectedObfuscation::Off) => SelectedObfuscation::Off,
|
||||
Ok(IpcSelectedObfuscation::Udp2tcp) => SelectedObfuscation::Udp2Tcp,
|
||||
Ok(IpcSelectedObfuscation::Shadowsocks) => SelectedObfuscation::Shadowsocks,
|
||||
Ok(IpcSelectedObfuscation::Quic) => SelectedObfuscation::Quic,
|
||||
Err(_) => {
|
||||
return Err(FromProtobufTypeError::InvalidArgument(
|
||||
"invalid obfuscation settings",
|
||||
|
@ -38,7 +38,7 @@ pub struct ClientArgs {
|
||||
/// fwmark to use for the `server_addr` connection
|
||||
#[cfg(target_os = "linux")]
|
||||
#[arg(long)]
|
||||
fwmark: Option<u16>,
|
||||
fwmark: Option<u32>,
|
||||
|
||||
/// Maximum duration of inactivity (in seconds) until the tunnel times out.
|
||||
/// Inactivity happens when no data is sent over the proxy.
|
||||
|
@ -140,7 +140,7 @@ pub struct ClientConfig {
|
||||
/// Optional fwmark to set on the QUIC endpoint socket
|
||||
#[cfg(target_os = "linux")]
|
||||
#[builder(default)]
|
||||
pub fwmark: Option<u16>,
|
||||
pub fwmark: Option<u32>,
|
||||
|
||||
/// Optional timeout when no data is sent in the proxy.
|
||||
#[builder(default)]
|
||||
@ -224,7 +224,7 @@ impl Client {
|
||||
fn setup_quic_endpoint(
|
||||
local_addr: SocketAddr,
|
||||
max_udp_payload_size: u16,
|
||||
#[cfg(target_os = "linux")] fwmark: Option<u16>,
|
||||
#[cfg(target_os = "linux")] fwmark: Option<u32>,
|
||||
) -> Result<Endpoint> {
|
||||
let local_socket = socket2::Socket::new(
|
||||
socket2::Domain::IPV4,
|
||||
@ -235,9 +235,7 @@ impl Client {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
if let Some(fwmark) = fwmark {
|
||||
local_socket
|
||||
.set_mark(u32::from(fwmark))
|
||||
.map_err(Error::Fwmark)?;
|
||||
local_socket.set_mark(fwmark).map_err(Error::Fwmark)?;
|
||||
}
|
||||
|
||||
local_socket.bind(&local_addr.into()).map_err(Error::Bind)?;
|
||||
|
@ -912,6 +912,18 @@ impl RelaySelector {
|
||||
|
||||
Ok(Some(obfuscation))
|
||||
}
|
||||
ObfuscationQuery::Quic => {
|
||||
let obfuscator = SelectedObfuscator {
|
||||
config: ObfuscatorConfig::Quic {
|
||||
// TODO: do not hardcode port
|
||||
endpoint: std::net::SocketAddr::from((endpoint.peer.endpoint.ip(), 443)),
|
||||
// TODO: do not hardcode
|
||||
hostname: "test.mullvad.net".to_owned(),
|
||||
},
|
||||
relay: obfuscator_relay,
|
||||
};
|
||||
Ok(Some(obfuscator))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,6 +283,7 @@ pub enum ObfuscationQuery {
|
||||
Auto,
|
||||
Udp2tcp(Udp2TcpObfuscationSettings),
|
||||
Shadowsocks(ShadowsocksSettings),
|
||||
Quic,
|
||||
}
|
||||
|
||||
impl ObfuscationQuery {
|
||||
@ -306,6 +307,10 @@ impl ObfuscationQuery {
|
||||
shadowsocks: settings,
|
||||
..Default::default()
|
||||
},
|
||||
ObfuscationQuery::Quic => ObfuscationSettings {
|
||||
selected_obfuscation: SelectedObfuscation::Quic,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -323,6 +328,7 @@ impl From<ObfuscationSettings> for ObfuscationQuery {
|
||||
SelectedObfuscation::Shadowsocks => {
|
||||
ObfuscationQuery::Shadowsocks(obfuscation.shadowsocks)
|
||||
}
|
||||
SelectedObfuscation::Quic => ObfuscationQuery::Quic,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -424,8 +424,9 @@ fn test_wireguard_retry_order() {
|
||||
assert!(match &query.wireguard_constraints().obfuscation {
|
||||
ObfuscationQuery::Auto => true,
|
||||
ObfuscationQuery::Off => obfuscator.is_none(),
|
||||
ObfuscationQuery::Udp2tcp(_) | ObfuscationQuery::Shadowsocks(_) =>
|
||||
obfuscator.is_some(),
|
||||
ObfuscationQuery::Quic
|
||||
| ObfuscationQuery::Udp2tcp(_)
|
||||
| ObfuscationQuery::Shadowsocks(_) => obfuscator.is_some(),
|
||||
});
|
||||
}
|
||||
_ => unreachable!(),
|
||||
|
@ -509,6 +509,10 @@ pub enum SelectedObfuscation {
|
||||
#[cfg_attr(feature = "clap", clap(name = "udp2tcp"))]
|
||||
Udp2Tcp,
|
||||
Shadowsocks,
|
||||
// TODO: Remove 'debug_assertions' condition
|
||||
// See https://linear.app/mullvad/issue/DES-2105
|
||||
#[cfg_attr(all(feature = "clap", not(debug_assertions)), value(skip))]
|
||||
Quic,
|
||||
}
|
||||
|
||||
impl Intersection for SelectedObfuscation {
|
||||
@ -533,6 +537,7 @@ impl fmt::Display for SelectedObfuscation {
|
||||
SelectedObfuscation::Off => "off".fmt(f),
|
||||
SelectedObfuscation::Udp2Tcp => "udp2tcp".fmt(f),
|
||||
SelectedObfuscation::Shadowsocks => "shadowsocks".fmt(f),
|
||||
SelectedObfuscation::Quic => "quic".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -239,6 +239,7 @@ pub enum ObfuscationType {
|
||||
#[serde(rename = "udp2tcp")]
|
||||
Udp2Tcp,
|
||||
Shadowsocks,
|
||||
Quic,
|
||||
}
|
||||
|
||||
impl fmt::Display for ObfuscationType {
|
||||
@ -246,6 +247,7 @@ impl fmt::Display for ObfuscationType {
|
||||
match self {
|
||||
ObfuscationType::Udp2Tcp => "Udp2Tcp".fmt(f),
|
||||
ObfuscationType::Shadowsocks => "Shadowsocks".fmt(f),
|
||||
ObfuscationType::Quic => "QUIC".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -274,6 +276,16 @@ impl From<&ObfuscatorConfig> for ObfuscationEndpoint {
|
||||
},
|
||||
ObfuscationType::Shadowsocks,
|
||||
),
|
||||
ObfuscatorConfig::Quic {
|
||||
hostname: _,
|
||||
endpoint,
|
||||
} => (
|
||||
Endpoint {
|
||||
address: *endpoint,
|
||||
protocol: TransportProtocol::Udp,
|
||||
},
|
||||
ObfuscationType::Quic,
|
||||
),
|
||||
};
|
||||
|
||||
ObfuscationEndpoint {
|
||||
|
@ -5,8 +5,16 @@ use super::{Endpoint, TransportProtocol};
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Deserialize, Serialize, Debug)]
|
||||
pub enum ObfuscatorConfig {
|
||||
Udp2Tcp { endpoint: SocketAddr },
|
||||
Shadowsocks { endpoint: SocketAddr },
|
||||
Udp2Tcp {
|
||||
endpoint: SocketAddr,
|
||||
},
|
||||
Shadowsocks {
|
||||
endpoint: SocketAddr,
|
||||
},
|
||||
Quic {
|
||||
hostname: String,
|
||||
endpoint: SocketAddr,
|
||||
},
|
||||
}
|
||||
|
||||
impl ObfuscatorConfig {
|
||||
@ -20,6 +28,13 @@ impl ObfuscatorConfig {
|
||||
address: *endpoint,
|
||||
protocol: TransportProtocol::Udp,
|
||||
},
|
||||
ObfuscatorConfig::Quic {
|
||||
hostname: _,
|
||||
endpoint,
|
||||
} => Endpoint {
|
||||
address: *endpoint,
|
||||
protocol: TransportProtocol::Udp,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use talpid_tunnel::tun_provider::TunProvider;
|
||||
use talpid_types::{net::obfuscation::ObfuscatorConfig, ErrorExt};
|
||||
|
||||
use tunnel_obfuscation::{
|
||||
create_obfuscator, shadowsocks, udp2tcp, Settings as ObfuscationSettings,
|
||||
create_obfuscator, quic, shadowsocks, udp2tcp, Settings as ObfuscationSettings,
|
||||
};
|
||||
|
||||
/// Begin running obfuscation machine, if configured. This function will patch `config`'s endpoint
|
||||
@ -96,6 +96,15 @@ fn settings_from_config(
|
||||
fwmark,
|
||||
})
|
||||
}
|
||||
ObfuscatorConfig::Quic { hostname, endpoint } => {
|
||||
ObfuscationSettings::Quic(quic::Settings {
|
||||
quic_endpoint: *endpoint,
|
||||
wireguard_endpoint: SocketAddr::from((Ipv4Addr::LOCALHOST, 51820)),
|
||||
hostname: hostname.to_owned(),
|
||||
#[cfg(target_os = "linux")]
|
||||
fwmark,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,9 @@ pub struct Settings {
|
||||
pub wireguard_endpoint: SocketAddr,
|
||||
/// Hostname to use for QUIC
|
||||
pub hostname: String,
|
||||
/// fwmark to apply to use for the QUIC connection
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fwmark: Option<u32>,
|
||||
}
|
||||
|
||||
impl Quic {
|
||||
@ -54,6 +57,9 @@ impl Quic {
|
||||
.target_addr(settings.wireguard_endpoint)
|
||||
.auth_header(Some(AUTH_HEADER.to_owned()));
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
let config_builder = config_builder.fwmark(settings.fwmark);
|
||||
|
||||
let task = tokio::spawn(async move {
|
||||
let client = Client::connect(config_builder.build())
|
||||
.await
|
||||
|
Loading…
x
Reference in New Issue
Block a user