Skip to content

Commit

Permalink
Add configurable transport protocol to local SOCKS5 access method
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkusPettersson98 committed Oct 18, 2023
1 parent 85bb4b1 commit ff90ea7
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 20 deletions.
25 changes: 22 additions & 3 deletions mullvad-cli/src/cmds/api_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use mullvad_types::access_method::{AccessMethod, AccessMethodSetting, CustomAcce
use std::net::IpAddr;

use clap::{Args, Subcommand};
use talpid_types::net::openvpn::SHADOWSOCKS_CIPHERS;
use talpid_types::net::{openvpn::SHADOWSOCKS_CIPHERS, TransportProtocol};

#[derive(Subcommand, Debug, Clone)]
pub enum ApiAccess {
Expand Down Expand Up @@ -119,8 +119,13 @@ impl ApiAccess {
let ip = cmd.params.ip.unwrap_or(local.peer.ip()).to_string();
let port = cmd.params.port.unwrap_or(local.peer.port());
let local_port = cmd.params.local_port.unwrap_or(local.port);
mullvad_types::access_method::Socks5Local::from_args(ip, port, local_port)
.map(AccessMethod::from)
mullvad_types::access_method::Socks5Local::from_args(
ip,
port,
local_port,
local.peer_transport_protol,
)
.map(AccessMethod::from)
}
mullvad_types::access_method::Socks5::Remote(remote) => {
let ip = cmd.params.ip.unwrap_or(remote.peer.ip()).to_string();
Expand Down Expand Up @@ -315,6 +320,18 @@ pub enum AddSocks5Commands {
remote_ip: IpAddr,
/// The port of the remote peer
remote_port: u16,
/// The Mullvad App can not know which transport protocol that the
/// remote peer accepts, but it needs to know this in order to correctly
/// exempt the connection traffic in the firewall.
///
/// By default, the transport protocol is assumed to be `TCP`, but it
/// can optionally be set to `UDP` as well.
///
/// There exists obfuscation protocols which use other transport
/// protocols, such as ICMP. However, by supporting both TCP and UDP we
/// should cover ~99% of all use cases.
#[arg(default_value_t = TransportProtocol::Tcp)]
remote_transport_protocol: TransportProtocol,
/// Disable the use of this custom access method. It has to be manually
/// enabled at a later stage to be used when accessing the Mullvad API.
#[arg(default_value_t = false, short, long)]
Expand Down Expand Up @@ -430,12 +447,14 @@ mod conversions {
remote_port,
name: _,
disabled: _,
remote_transport_protocol,
} => {
println!("Adding SOCKS5-proxy: localhost:{local_port} => {remote_ip}:{remote_port}");
daemon_types::Socks5Local::from_args(
remote_ip.to_string(),
remote_port,
local_port,
remote_transport_protocol,
)
.map(daemon_types::Socks5::Local)
.map(daemon_types::AccessMethod::from)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ message AccessMethod {
string ip = 1;
uint32 port = 2;
uint32 local_port = 3;
TransportProtocol peer_transport_protocol = 4;
}
message SocksAuth {
string username = 1;
Expand Down
41 changes: 27 additions & 14 deletions mullvad-management-interface/src/types/conversions/access_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,19 @@ mod data {
type Error = FromProtobufTypeError;

fn try_from(value: proto::access_method::Socks5Local) -> Result<Self, Self::Error> {
Socks5Local::from_args(value.ip, value.port as u16, value.local_port as u16)
.ok_or(FromProtobufTypeError::InvalidArgument(
"Could not parse Socks5 (local) message from protobuf",
))
.map(AccessMethod::from)
use crate::types::conversions::net::try_transport_protocol_from_i32;
let peer_transport_protocol =
try_transport_protocol_from_i32(value.peer_transport_protocol)?;
Socks5Local::from_args(
value.ip,
value.port as u16,
value.local_port as u16,
peer_transport_protocol,
)
.ok_or(FromProtobufTypeError::InvalidArgument(
"Could not parse Socks5 (local) message from protobuf",
))
.map(AccessMethod::from)
}
}

Expand Down Expand Up @@ -216,15 +224,20 @@ mod data {
},
)
}
CustomAccessMethod::Socks5(Socks5::Local(Socks5Local { peer, port })) => {
proto::access_method::AccessMethod::Socks5local(
proto::access_method::Socks5Local {
ip: peer.ip().to_string(),
port: peer.port() as u32,
local_port: port as u32,
},
)
}
CustomAccessMethod::Socks5(Socks5::Local(Socks5Local {
peer,
port,
peer_transport_protol,
})) => proto::access_method::AccessMethod::Socks5local(
proto::access_method::Socks5Local {
ip: peer.ip().to_string(),
port: peer.port() as u32,
local_port: port as u32,
peer_transport_protocol: i32::from(proto::TransportProtocol::from(
peer_transport_protol,
)),
},
),
CustomAccessMethod::Socks5(Socks5::Remote(Socks5Remote {
peer,
authentication,
Expand Down
34 changes: 31 additions & 3 deletions mullvad-types/src/access_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::str::FromStr;

use serde::{Deserialize, Serialize};
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
use talpid_types::net::TransportProtocol;

/// Daemon settings for API access methods.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
Expand Down Expand Up @@ -202,6 +203,8 @@ pub struct Shadowsocks {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct Socks5Local {
pub peer: SocketAddr,
/// The transport protocol which should be allowed in the firewall.
pub peer_transport_protol: TransportProtocol,
/// Port on localhost where the SOCKS5-proxy listens to.
pub port: u16,
}
Expand Down Expand Up @@ -255,15 +258,40 @@ impl Shadowsocks {

impl Socks5Local {
pub fn new(peer: SocketAddr, port: u16) -> Self {
Self { peer, port }
Self {
peer,
port,
peer_transport_protol: TransportProtocol::Tcp,
}
}

pub fn new_with_transport_protocol(
peer: SocketAddr,
port: u16,
transport_protocol: TransportProtocol,
) -> Self {
Self {
peer,
port,
peer_transport_protol: transport_protocol,
}
}

/// Like [new()], but tries to parse `ip` and `port` into a [`std::net::SocketAddr`] for you.
/// If `ip` or `port` are valid [`Some(Socks5Local)`] is returned, otherwise [`None`].
pub fn from_args(ip: String, port: u16, localport: u16) -> Option<Self> {
pub fn from_args(
ip: String,
port: u16,
localport: u16,
transport_protocol: TransportProtocol,
) -> Option<Self> {
let peer_ip = IpAddr::V4(Ipv4Addr::from_str(&ip).ok()?);
let peer = SocketAddr::new(peer_ip, port);
Some(Self::new(peer, localport))
Some(Self::new_with_transport_protocol(
peer,
localport,
transport_protocol,
))
}
}

Expand Down

0 comments on commit ff90ea7

Please sign in to comment.