diff options
| author | David Lönnhager <david.l@mullvad.net> | 2022-05-04 14:32:19 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2022-05-04 14:32:19 +0200 |
| commit | e130e04448327369be97929c28032dacd0a8e2ab (patch) | |
| tree | e394aa9e70404ca8150e3fe9aa48ce14c3331552 | |
| parent | b1316278017c43405a94789e647b0d38723f089d (diff) | |
| parent | bb4a8ba6b75643b1cab1f784c9e9f9a9068a7e7c (diff) | |
| download | mullvadvpn-e130e04448327369be97929c28032dacd0a8e2ab.tar.xz mullvadvpn-e130e04448327369be97929c28032dacd0a8e2ab.zip | |
Merge branch 'move-dns-options'
| -rw-r--r-- | mullvad-daemon/src/dns.rs | 55 | ||||
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 62 | ||||
| -rw-r--r-- | mullvad-types/src/settings/dns.rs | 89 | ||||
| -rw-r--r-- | mullvad-types/src/settings/mod.rs | 89 |
4 files changed, 154 insertions, 141 deletions
diff --git a/mullvad-daemon/src/dns.rs b/mullvad-daemon/src/dns.rs new file mode 100644 index 0000000000..e82c50200e --- /dev/null +++ b/mullvad-daemon/src/dns.rs @@ -0,0 +1,55 @@ +use mullvad_types::settings::{DnsOptions, DnsState}; +use std::net::{IpAddr, Ipv4Addr}; + +/// When we want to block certain contents with the help of DNS server side, +/// we compute the resolver IP to use based on these constants. The last +/// byte can be ORed together to combine multiple block lists. +const DNS_BLOCKING_IP_BASE: Ipv4Addr = Ipv4Addr::new(100, 64, 0, 0); +const DNS_AD_BLOCKING_IP_BIT: u8 = 1 << 0; // 0b00000001 +const DNS_TRACKER_BLOCKING_IP_BIT: u8 = 1 << 1; // 0b00000010 +const DNS_MALWARE_BLOCKING_IP_BIT: u8 = 1 << 2; // 0b00000100 +const DNS_ADULT_BLOCKING_IP_BIT: u8 = 1 << 3; // 0b00001000 +const DNS_GAMBLING_BLOCKING_IP_BIT: u8 = 1 << 4; // 0b00010000 + +/// Return the resolvers as a vector of `IpAddr`s. Returns `None` when no special resolvers +/// are requested and the tunnel default gateway should be used. +pub fn addresses_from_options(options: &DnsOptions) -> Option<Vec<IpAddr>> { + match options.state { + DnsState::Default => { + // Check if we should use a custom blocking DNS resolver. + // And if so, compute the IP. + let mut last_byte: u8 = 0; + + if options.default_options.block_ads { + last_byte |= DNS_AD_BLOCKING_IP_BIT; + } + if options.default_options.block_trackers { + last_byte |= DNS_TRACKER_BLOCKING_IP_BIT; + } + if options.default_options.block_malware { + last_byte |= DNS_MALWARE_BLOCKING_IP_BIT; + } + if options.default_options.block_adult_content { + last_byte |= DNS_ADULT_BLOCKING_IP_BIT; + } + if options.default_options.block_gambling { + last_byte |= DNS_GAMBLING_BLOCKING_IP_BIT; + } + + if last_byte != 0 { + let mut dns_ip = DNS_BLOCKING_IP_BASE.octets(); + dns_ip[dns_ip.len() - 1] |= last_byte; + Some(vec![IpAddr::V4(Ipv4Addr::from(dns_ip))]) + } else { + None + } + } + DnsState::Custom => { + if options.custom_options.addresses.is_empty() { + None + } else { + Some(options.custom_options.addresses.clone()) + } + } + } +} diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index 3b75b7ceb2..eb674b5763 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -7,6 +7,7 @@ extern crate serde; pub mod account_history; mod api; pub mod device; +mod dns; pub mod exception_logging; #[cfg(target_os = "macos")] pub mod exclusion_gid; @@ -42,7 +43,7 @@ use mullvad_types::{ location::GeoIpLocation, relay_constraints::{BridgeSettings, BridgeState, ObfuscationSettings, RelaySettingsUpdate}, relay_list::{Relay, RelayList}, - settings::{DnsOptions, DnsState, Settings}, + settings::{DnsOptions, Settings}, states::{TargetState, TunnelState}, version::{AppVersion, AppVersionInfo}, wireguard::{PublicKey, RotationInterval}, @@ -57,7 +58,6 @@ use std::{collections::HashSet, ffi::OsString}; use std::{ marker::PhantomData, mem, - net::{IpAddr, Ipv4Addr}, path::PathBuf, pin::Pin, sync::{mpsc as sync_mpsc, Arc, Weak}, @@ -85,16 +85,6 @@ use tokio::io; /// Delay between generating a new WireGuard key and reconnecting const WG_RECONNECT_DELAY: Duration = Duration::from_secs(4 * 60); -/// When we want to block certain contents with the help of DNS server side, -/// we compute the resolver IP to use based on these constants. The last -/// byte can be ORed together to combine multiple block lists. -const DNS_BLOCKING_IP_BASE: Ipv4Addr = Ipv4Addr::new(100, 64, 0, 0); -const DNS_AD_BLOCKING_IP_BIT: u8 = 1 << 0; // 0b00000001 -const DNS_TRACKER_BLOCKING_IP_BIT: u8 = 1 << 1; // 0b00000010 -const DNS_MALWARE_BLOCKING_IP_BIT: u8 = 1 << 2; // 0b00000100 -const DNS_ADULT_BLOCKING_IP_BIT: u8 = 1 << 3; // 0b00001000 -const DNS_GAMBLING_BLOCKING_IP_BIT: u8 = 1 << 4; // 0b00010000 - pub type ResponseTx<T, E> = oneshot::Sender<Result<T, E>>; #[derive(err_derive::Error, Debug)] @@ -711,7 +701,7 @@ where tunnel_state_machine::InitialTunnelState { allow_lan: settings.allow_lan, block_when_disconnected: settings.block_when_disconnected, - dns_servers: Self::get_dns_resolvers(&settings.tunnel_options.dns_options), + dns_servers: dns::addresses_from_options(&settings.tunnel_options.dns_options), allowed_endpoint: initial_api_endpoint, reset_firewall: *target_state != TargetState::Secured, #[cfg(windows)] @@ -796,49 +786,6 @@ where Ok(daemon) } - /// Get which special DNS resolvers to use. Returns `None` when no special resolvers - /// are requested and the tunnel default gateway should be used. - fn get_dns_resolvers(options: &DnsOptions) -> Option<Vec<IpAddr>> { - match options.state { - DnsState::Default => { - // Check if we should use a custom blocking DNS resolver. - // And if so, compute the IP. - let mut last_byte: u8 = 0; - - if options.default_options.block_ads { - last_byte |= DNS_AD_BLOCKING_IP_BIT; - } - if options.default_options.block_trackers { - last_byte |= DNS_TRACKER_BLOCKING_IP_BIT; - } - if options.default_options.block_malware { - last_byte |= DNS_MALWARE_BLOCKING_IP_BIT; - } - if options.default_options.block_adult_content { - last_byte |= DNS_ADULT_BLOCKING_IP_BIT; - } - if options.default_options.block_gambling { - last_byte |= DNS_GAMBLING_BLOCKING_IP_BIT; - } - - if last_byte != 0 { - let mut dns_ip = DNS_BLOCKING_IP_BASE.octets(); - dns_ip[dns_ip.len() - 1] |= last_byte; - Some(vec![IpAddr::V4(Ipv4Addr::from(dns_ip))]) - } else { - None - } - } - DnsState::Custom => { - if options.custom_options.addresses.is_empty() { - None - } else { - Some(options.custom_options.addresses.clone()) - } - } - } - } - /// Consume the `Daemon` and run the main event loop. Blocks until an error happens or a /// shutdown event is received. pub async fn run(mut self) -> Result<(), Error> { @@ -2256,7 +2203,8 @@ where Self::oneshot_send(tx, Ok(()), "set_dns_options response"); if settings_changed { let settings = self.settings.to_settings(); - let resolvers = Self::get_dns_resolvers(&settings.tunnel_options.dns_options); + let resolvers = + dns::addresses_from_options(&settings.tunnel_options.dns_options); self.event_listener.notify_settings(settings); self.send_tunnel_command(TunnelCommand::Dns(resolvers)); } diff --git a/mullvad-types/src/settings/dns.rs b/mullvad-types/src/settings/dns.rs new file mode 100644 index 0000000000..f379fd286f --- /dev/null +++ b/mullvad-types/src/settings/dns.rs @@ -0,0 +1,89 @@ +#[cfg(target_os = "android")] +use jnix::{jni::objects::JObject, FromJava, IntoJava, JnixEnv}; +use serde::{Deserialize, Serialize}; +use std::net::IpAddr; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[serde(rename_all = "snake_case")] +pub enum DnsState { + Default, + Custom, +} + +impl Default for DnsState { + fn default() -> Self { + Self::Default + } +} + +/// DNS config +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[serde(default)] +#[cfg_attr(target_os = "android", derive(IntoJava))] +#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))] +pub struct DnsOptions { + #[cfg_attr(target_os = "android", jnix(map = "|state| state == DnsState::Custom"))] + pub state: DnsState, + #[cfg_attr(target_os = "android", jnix(skip))] + pub default_options: DefaultDnsOptions, + #[cfg_attr(target_os = "android", jnix(map = "|opts| opts.addresses"))] + pub custom_options: CustomDnsOptions, +} + +#[cfg(target_os = "android")] +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[cfg_attr(target_os = "android", derive(FromJava))] +#[cfg_attr( + target_os = "android", + jnix(class_name = "net.mullvad.mullvadvpn.model.DnsOptions") +)] +pub struct AndroidDnsOptions { + pub custom: bool, + pub addresses: Vec<IpAddr>, +} + +#[cfg(target_os = "android")] +impl From<AndroidDnsOptions> for DnsOptions { + fn from(options: AndroidDnsOptions) -> Self { + Self { + state: if options.custom { + DnsState::Custom + } else { + DnsState::Default + }, + default_options: DefaultDnsOptions::default(), + custom_options: CustomDnsOptions { + addresses: options.addresses, + }, + } + } +} + +#[cfg(target_os = "android")] +impl<'env, 'sub_env> FromJava<'env, JObject<'sub_env>> for DnsOptions +where + 'env: 'sub_env, +{ + const JNI_SIGNATURE: &'static str = "Lnet/mullvad/mullvadvpn/model/DnsOptions"; + + fn from_java(env: &JnixEnv<'env>, object: JObject<'sub_env>) -> Self { + AndroidDnsOptions::from_java(env, object).into() + } +} + +/// Default DNS config +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[serde(default)] +pub struct DefaultDnsOptions { + pub block_ads: bool, + pub block_trackers: bool, + pub block_malware: bool, + pub block_adult_content: bool, + pub block_gambling: bool, +} + +/// Custom DNS config +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +pub struct CustomDnsOptions { + pub addresses: Vec<IpAddr>, +} diff --git a/mullvad-types/src/settings/mod.rs b/mullvad-types/src/settings/mod.rs index 969eb8e4e5..7bfff42824 100644 --- a/mullvad-types/src/settings/mod.rs +++ b/mullvad-types/src/settings/mod.rs @@ -7,13 +7,14 @@ use crate::{ wireguard, }; #[cfg(target_os = "android")] -use jnix::{jni::objects::JObject, FromJava, IntoJava, JnixEnv}; +use jnix::IntoJava; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::net::IpAddr; #[cfg(target_os = "windows")] use std::{collections::HashSet, path::PathBuf}; use talpid_types::net::{self, openvpn, GenericTunnelOptions}; +mod dns; + /// The version used by the current version of the code. Should always be the /// latest version that exists in `SettingsVersion`. /// This should be bumped when a new version is introduced along with a migration @@ -187,90 +188,10 @@ pub struct TunnelOptions { pub dns_options: DnsOptions, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] -#[serde(rename_all = "snake_case")] -pub enum DnsState { - Default, - Custom, -} - -impl Default for DnsState { - fn default() -> Self { - Self::Default - } -} - -/// DNS config -#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] -#[serde(default)] -#[cfg_attr(target_os = "android", derive(IntoJava))] -#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))] -pub struct DnsOptions { - #[cfg_attr(target_os = "android", jnix(map = "|state| state == DnsState::Custom"))] - pub state: DnsState, - #[cfg_attr(target_os = "android", jnix(skip))] - pub default_options: DefaultDnsOptions, - #[cfg_attr(target_os = "android", jnix(map = "|opts| opts.addresses"))] - pub custom_options: CustomDnsOptions, -} - -#[cfg(target_os = "android")] -#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] -#[cfg_attr(target_os = "android", derive(FromJava))] -#[cfg_attr( - target_os = "android", - jnix(class_name = "net.mullvad.mullvadvpn.model.DnsOptions") -)] -pub struct AndroidDnsOptions { - pub custom: bool, - pub addresses: Vec<IpAddr>, -} - -#[cfg(target_os = "android")] -impl From<AndroidDnsOptions> for DnsOptions { - fn from(options: AndroidDnsOptions) -> Self { - Self { - state: if options.custom { - DnsState::Custom - } else { - DnsState::Default - }, - default_options: DefaultDnsOptions::default(), - custom_options: CustomDnsOptions { - addresses: options.addresses, - }, - } - } -} +pub use dns::{CustomDnsOptions, DefaultDnsOptions, DnsOptions, DnsState}; #[cfg(target_os = "android")] -impl<'env, 'sub_env> FromJava<'env, JObject<'sub_env>> for DnsOptions -where - 'env: 'sub_env, -{ - const JNI_SIGNATURE: &'static str = "Lnet/mullvad/mullvadvpn/model/DnsOptions"; - - fn from_java(env: &JnixEnv<'env>, object: JObject<'sub_env>) -> Self { - AndroidDnsOptions::from_java(env, object).into() - } -} - -/// Default DNS config -#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] -#[serde(default)] -pub struct DefaultDnsOptions { - pub block_ads: bool, - pub block_trackers: bool, - pub block_malware: bool, - pub block_adult_content: bool, - pub block_gambling: bool, -} - -/// Custom DNS config -#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] -pub struct CustomDnsOptions { - pub addresses: Vec<IpAddr>, -} +pub use dns::AndroidDnsOptions; impl Default for TunnelOptions { fn default() -> Self { |
