diff options
24 files changed, 212 insertions, 135 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 86b20c7df1..8986bc1516 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ Line wrap the file at 100 chars. Th - Fix the bug which caused the account token history to remain stale after logout. - Fix some notifications not appearing depending on how the window is shown and hidden while the tunnel state changes. +- Fix DNS when using IPv6. #### Linux - Fix startup failure when network device with a hardware address that's not a MAC address is diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs index d2948ec315..0d2c5c3bca 100644 --- a/mullvad-cli/src/cmds/relay.rs +++ b/mullvad-cli/src/cmds/relay.rs @@ -2,7 +2,7 @@ use crate::{new_rpc_client, Command, Result, ResultExt}; use clap::{value_t, values_t}; use std::{ io::{self, BufRead}, - net::{IpAddr, Ipv4Addr, SocketAddr}, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, str::FromStr, }; @@ -55,11 +55,17 @@ impl Command for Relay { .required(false), ) .arg( - clap::Arg::with_name("gateway") - .help("Gateway address") - .long("gateway") + clap::Arg::with_name("v4-gateway") + .help("IPv4 gateway address") + .long("v4-gateway") .index(4) .required(false), + ).arg( + clap::Arg::with_name("v6-gateway") + .help("IPv6 gateway address") + .long("v6-gateway") + .takes_value(true) + .required(false), ) .arg( clap::Arg::with_name("addr") @@ -224,10 +230,17 @@ impl Relay { let host = value_t!(matches.value_of("host"), String).unwrap_or_else(|e| e.exit()); let port = value_t!(matches.value_of("port"), u16).unwrap_or_else(|e| e.exit()); let addresses = values_t!(matches.values_of("addr"), IpAddr).unwrap_or_else(|e| e.exit()); - println!("addresses - {:?}", addresses); let peer_key_str = value_t!(matches.value_of("peer-key"), String).unwrap_or_else(|e| e.exit()); - let gateway = value_t!(matches.value_of("gateway"), IpAddr).unwrap_or_else(|e| e.exit()); + let ipv4_gateway = + value_t!(matches.value_of("v4-gateway"), Ipv4Addr).unwrap_or_else(|e| e.exit()); + let ipv6_gateway = match value_t!(matches.value_of("v6-gateway"), Ipv6Addr) { + Ok(gateway) => Some(gateway), + Err(e) => match e.kind { + clap::ErrorKind::ArgumentNotFound => None, + _ => e.exit(), + }, + }; let mut private_key_str = String::new(); println!("Reading private key from standard input"); let _ = io::stdin().lock().read_line(&mut private_key_str); @@ -250,7 +263,8 @@ impl Relay { allowed_ips: all_of_the_internet(), endpoint: SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port), }, - gateway, + ipv4_gateway, + ipv6_gateway, }), ) } diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index 07d7cd3e4f..6e2bdd4a79 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -391,7 +391,11 @@ impl Daemon { generic_options: tunnel_options.generic, } .into()), - MullvadEndpoint::Wireguard { peer, gateway } => { + MullvadEndpoint::Wireguard { + peer, + ipv4_gateway, + ipv6_gateway, + } => { let wg_data = self .account_history .get(&account_token)? @@ -408,7 +412,8 @@ impl Daemon { connection: wireguard::ConnectionConfig { tunnel, peer, - gateway, + ipv4_gateway, + ipv6_gateway: Some(ipv6_gateway), }, options: tunnel_options.wireguard, generic_options: tunnel_options.generic, diff --git a/mullvad-daemon/src/relays.rs b/mullvad-daemon/src/relays.rs index 68c7c4bb11..b38ba42cfc 100644 --- a/mullvad-daemon/src/relays.rs +++ b/mullvad-daemon/src/relays.rs @@ -423,7 +423,8 @@ impl RelaySelector { }; Some(MullvadEndpoint::Wireguard { peer: peer_config, - gateway: data.ipv4_gateway.into(), + ipv4_gateway: data.ipv4_gateway, + ipv6_gateway: data.ipv6_gateway, }) } diff --git a/mullvad-types/src/endpoint.rs b/mullvad-types/src/endpoint.rs index f6818a8854..4a2371472e 100644 --- a/mullvad-types/src/endpoint.rs +++ b/mullvad-types/src/endpoint.rs @@ -1,5 +1,8 @@ use serde::{Deserialize, Serialize}; -use std::{fmt, net::IpAddr}; +use std::{ + fmt, + net::{Ipv4Addr, Ipv6Addr}, +}; use talpid_types::net::{wireguard, Endpoint, TransportProtocol}; use crate::relay_list::{OpenVpnEndpointData, WireguardEndpointData}; @@ -11,7 +14,8 @@ pub enum MullvadEndpoint { OpenVpn(Endpoint), Wireguard { peer: wireguard::PeerConfig, - gateway: IpAddr, + ipv4_gateway: Ipv4Addr, + ipv6_gateway: Ipv6Addr, }, } @@ -20,7 +24,11 @@ impl MullvadEndpoint { pub fn to_endpoint(&self) -> Endpoint { match self { MullvadEndpoint::OpenVpn(endpoint) => *endpoint, - MullvadEndpoint::Wireguard { peer, gateway: _ } => Endpoint::new( + MullvadEndpoint::Wireguard { + peer, + ipv4_gateway: _, + ipv6_gateway: _, + } => Endpoint::new( peer.endpoint.ip(), peer.endpoint.port(), TransportProtocol::Udp, diff --git a/talpid-core/build.rs b/talpid-core/build.rs index 5441062edc..a733cfccbc 100644 --- a/talpid-core/build.rs +++ b/talpid-core/build.rs @@ -45,7 +45,7 @@ mod win { #[cfg(windows)] fn main() { - use win::*; + use crate::win::*; const WINFW_DIR_VAR: &str = "WINFW_LIB_DIR"; const WINDNS_DIR_VAR: &str = "WINDNS_LIB_DIR"; diff --git a/talpid-core/src/dns/windows/mod.rs b/talpid-core/src/dns/windows/mod.rs index dfa239cb81..9d2a8245b2 100644 --- a/talpid-core/src/dns/windows/mod.rs +++ b/talpid-core/src/dns/windows/mod.rs @@ -75,29 +75,26 @@ impl super::DnsMonitorT for DnsMonitor { let ipv4 = servers .iter() .filter(|ip| ip.is_ipv4()) - .cloned() + .map(ip_to_widestring) .collect::<Vec<_>>(); let ipv6 = servers .iter() - .map(|ip| match ip { - IpAddr::V4(ip) => IpAddr::V6(ip.to_ipv6_compatible()), - any => any.clone(), - }) + .filter(|ip| ip.is_ipv6()) + .map(ip_to_widestring) .collect::<Vec<_>>(); - let ipv4_addresses = ip_to_string(ipv4.iter()); - let ipv6_addresses = ip_to_string(ipv6.iter()); - let mut ipv4_address_ptrs = ipv4_addresses + + let mut ipv4_address_ptrs = ipv4 .iter() .map(|ip_cstr| ip_cstr.as_ptr()) .collect::<Vec<_>>(); - let mut ipv6_address_ptrs = ipv6_addresses + let mut ipv6_address_ptrs = ipv6 .iter() .map(|ip_cstr| ip_cstr.as_ptr()) .collect::<Vec<_>>(); - trace!("ipv4 ips - {:?} - {}", ipv4_addresses, ipv4_addresses.len()); - trace!("ipv6 ips - {:?} - {}", ipv6_addresses, ipv6_addresses.len()); + trace!("ipv4 ips - {:?} - {}", ipv4, ipv4.len()); + trace!("ipv6 ips - {:?} - {}", ipv6, ipv6.len()); unsafe { WinDns_Set( @@ -150,10 +147,8 @@ impl DnsMonitor { } } -fn ip_to_string<'a>(ips: impl Iterator<Item = &'a IpAddr>) -> Vec<WideCString> { - ips.map(|ip| ip.to_string().encode_utf16().collect::<Vec<_>>()) - .map(|ip| WideCString::new(ip).unwrap()) - .collect::<Vec<_>>() +fn ip_to_widestring(ip: &IpAddr) -> WideCString { + WideCString::new(ip.to_string().encode_utf16().collect::<Vec<_>>()).unwrap() } // typedef void (WINDNS_API *WinDnsErrorSink)(const char *errorMessage, const char **details, diff --git a/talpid-core/src/firewall/linux.rs b/talpid-core/src/firewall/linux.rs index ffec0bc1fd..d073853ad0 100644 --- a/talpid-core/src/firewall/linux.rs +++ b/talpid-core/src/firewall/linux.rs @@ -353,23 +353,39 @@ impl<'a> PolicyBatch<'a> { protocol: TransportProtocol, ) -> Result<()> { // allow DNS traffic to the tunnel gateway + self.add_allow_dns_rule(&tunnel.interface, protocol, tunnel.ipv4_gateway.into())?; + if let Some(ipv6_gateway) = tunnel.ipv6_gateway { + self.add_allow_dns_rule(&tunnel.interface, protocol, ipv6_gateway.into())?; + }; + let mut block_rule = Rule::new(&self.out_chain)?; + check_port(&mut block_rule, protocol, End::Dst, 53)?; + add_verdict(&mut block_rule, &Verdict::Drop)?; + self.batch.add(&block_rule, nftnl::MsgType::Add)?; + + Ok(()) + } + + fn add_allow_dns_rule( + &mut self, + interface: &str, + protocol: TransportProtocol, + host: IpAddr, + ) -> Result<()> { let mut allow_rule = Rule::new(&self.out_chain)?; + let daddr = match host { + IpAddr::V4(_) => nft_expr!(payload ipv4 daddr), + IpAddr::V6(_) => nft_expr!(payload ipv6 daddr), + }; - check_iface(&mut allow_rule, Direction::Out, &tunnel.interface[..])?; + check_iface(&mut allow_rule, Direction::Out, interface)?; check_port(&mut allow_rule, protocol, End::Dst, 53)?; - check_l3proto(&mut allow_rule, tunnel.gateway)?; - - allow_rule.add_expr(&nft_expr!(payload ipv4 daddr))?; - allow_rule.add_expr(&nft_expr!(cmp == tunnel.gateway))?; + check_l3proto(&mut allow_rule, host)?; + allow_rule.add_expr(&daddr)?; + allow_rule.add_expr(&nft_expr!(cmp == host))?; add_verdict(&mut allow_rule, &Verdict::Accept)?; - self.batch.add(&allow_rule, nftnl::MsgType::Add)?; - - let mut block_rule = Rule::new(&self.out_chain)?; - check_port(&mut block_rule, protocol, End::Dst, 53)?; - add_verdict(&mut block_rule, &Verdict::Drop)?; - self.batch.add(&block_rule, nftnl::MsgType::Add)?; + self.batch.add(&allow_rule, nftnl::MsgType::Add)?; Ok(()) } diff --git a/talpid-core/src/firewall/macos.rs b/talpid-core/src/firewall/macos.rs index b411c58a9a..673f834d85 100644 --- a/talpid-core/src/firewall/macos.rs +++ b/talpid-core/src/firewall/macos.rs @@ -102,22 +102,47 @@ impl Firewall { tunnel, allow_lan, } => { + let mut rules = vec![]; let allow_tcp_dns_to_relay_rule = self .create_rule_builder(FilterRuleAction::Pass) .direction(pfctl::Direction::Out) .quick(true) .interface(&tunnel.interface) .proto(pfctl::Proto::Tcp) - .to(pfctl::Endpoint::new(tunnel.gateway, 53)) + .to(pfctl::Endpoint::new(tunnel.ipv4_gateway, 53)) .build()?; + rules.push(allow_tcp_dns_to_relay_rule); let allow_udp_dns_to_relay_rule = self .create_rule_builder(FilterRuleAction::Pass) .direction(pfctl::Direction::Out) .quick(true) .interface(&tunnel.interface) .proto(pfctl::Proto::Udp) - .to(pfctl::Endpoint::new(tunnel.gateway, 53)) + .to(pfctl::Endpoint::new(tunnel.ipv4_gateway, 53)) .build()?; + rules.push(allow_udp_dns_to_relay_rule); + + if let Some(ipv6_gateway) = tunnel.ipv6_gateway { + let v6_dns_rule_tcp = self + .create_rule_builder(FilterRuleAction::Pass) + .direction(pfctl::Direction::Out) + .quick(true) + .interface(&tunnel.interface) + .proto(pfctl::Proto::Tcp) + .to(pfctl::Endpoint::new(ipv6_gateway, 53)) + .build()?; + rules.push(v6_dns_rule_tcp); + let v6_dns_rule_udp = self + .create_rule_builder(FilterRuleAction::Pass) + .direction(pfctl::Direction::Out) + .quick(true) + .interface(&tunnel.interface) + .proto(pfctl::Proto::Udp) + .to(pfctl::Endpoint::new(ipv6_gateway, 53)) + .build()?; + rules.push(v6_dns_rule_udp); + } + let block_tcp_dns_rule = self .create_rule_builder(FilterRuleAction::Drop) .direction(pfctl::Direction::Out) @@ -125,6 +150,7 @@ impl Firewall { .proto(pfctl::Proto::Tcp) .to(pfctl::Port::from(53)) .build()?; + rules.push(block_tcp_dns_rule); let block_udp_dns_rule = self .create_rule_builder(FilterRuleAction::Drop) .direction(pfctl::Direction::Out) @@ -133,18 +159,14 @@ impl Firewall { .to(pfctl::Port::from(53)) .build()?; - let mut rules = vec![ - allow_tcp_dns_to_relay_rule, - allow_udp_dns_to_relay_rule, - block_tcp_dns_rule, - block_udp_dns_rule, - self.get_allow_relay_rule(peer_endpoint)?, - self.get_allow_tunnel_rule(tunnel.interface.as_str())?, - ]; + rules.push(block_udp_dns_rule); + rules.push(self.get_allow_relay_rule(peer_endpoint)?); + rules.push(self.get_allow_tunnel_rule(tunnel.interface.as_str())?); if allow_lan { rules.append(&mut self.get_allow_lan_rules()?); } + Ok(rules) } FirewallPolicy::Blocked { allow_lan } => { diff --git a/talpid-core/src/firewall/mod.rs b/talpid-core/src/firewall/mod.rs index 059a49e326..865226ae4d 100644 --- a/talpid-core/src/firewall/mod.rs +++ b/talpid-core/src/firewall/mod.rs @@ -100,7 +100,7 @@ impl fmt::Display for FirewallPolicy { allow_lan, } => write!( f, - "Connected to {} over \"{}\" (ip: {}, gw: {}), {} LAN", + "Connected to {} over \"{}\" (ip: {}, v4 gw: {}, v6 gw; {:?}), {} LAN", peer_endpoint, tunnel.interface, tunnel @@ -109,7 +109,8 @@ impl fmt::Display for FirewallPolicy { .map(|ip| ip.to_string()) .collect::<Vec<_>>() .join(","), - tunnel.gateway, + tunnel.ipv4_gateway, + tunnel.ipv6_gateway, if *allow_lan { "Allowing" } else { "Blocking" } ), FirewallPolicy::Blocked { allow_lan } => write!( diff --git a/talpid-core/src/firewall/windows.rs b/talpid-core/src/firewall/windows.rs index 16702b62f9..143dd1cd4e 100644 --- a/talpid-core/src/firewall/windows.rs +++ b/talpid-core/src/firewall/windows.rs @@ -116,7 +116,7 @@ impl Firewall { winfw_settings: &WinFwSettings, ) -> Result<()> { trace!("Applying 'connecting' firewall policy"); - let ip_str = Self::widestring_ip(&endpoint.address.ip()); + let ip_str = Self::widestring_ip(endpoint.address.ip()); // ip_str has to outlive winfw_relay let winfw_relay = WinFwRelay { @@ -128,7 +128,7 @@ impl Firewall { unsafe { WinFw_ApplyPolicyConnecting(winfw_settings, &winfw_relay).into_result() } } - fn widestring_ip(ip: &IpAddr) -> WideCString { + fn widestring_ip(ip: IpAddr) -> WideCString { let buf = ip.to_string().encode_utf16().collect::<Vec<_>>(); WideCString::new(buf).unwrap() } @@ -140,8 +140,11 @@ impl Firewall { tunnel_metadata: &crate::tunnel::TunnelMetadata, ) -> Result<()> { trace!("Applying 'connected' firewall policy"); - let ip_str = Self::widestring_ip(&endpoint.address.ip()); - let gateway_str = Self::widestring_ip(&tunnel_metadata.gateway.into()); + let ip_str = Self::widestring_ip(endpoint.address.ip()); + let v4_gateway = Self::widestring_ip(tunnel_metadata.ipv4_gateway.into()); + let v6_gateway = tunnel_metadata + .ipv6_gateway + .map(|v6_ip| Self::widestring_ip(v6_ip.into())); let tunnel_alias = WideCString::new(tunnel_metadata.interface.encode_utf16().collect::<Vec<_>>()).unwrap(); @@ -162,12 +165,18 @@ impl Firewall { debug!("Network interface metrics were not changed"); } + let v6_gateway_ptr = match &v6_gateway { + Some(v6_ip) => v6_ip.as_ptr(), + None => ptr::null(), + }; + unsafe { WinFw_ApplyPolicyConnected( winfw_settings, &winfw_relay, tunnel_alias.as_wide_c_str().as_ptr(), - gateway_str.as_wide_c_str().as_ptr(), + v4_gateway.as_ptr(), + v6_gateway_ptr, ) .into_result() } @@ -260,7 +269,8 @@ mod winfw { settings: &WinFwSettings, relay: &WinFwRelay, tunnelIfaceAlias: *const libc::wchar_t, - primaryDns: *const libc::wchar_t, + v4Gateway: *const libc::wchar_t, + v6Gateway: *const libc::wchar_t, ) -> ApplyConnectedResult; #[link_name = "WinFw_ApplyPolicyBlocked"] diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs index d7506b3b7c..d386fd641c 100644 --- a/talpid-core/src/tunnel/mod.rs +++ b/talpid-core/src/tunnel/mod.rs @@ -3,7 +3,7 @@ use std::{ collections::HashMap, ffi::OsString, io, - net::IpAddr, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, path::{Path, PathBuf}, }; #[cfg(unix)] @@ -71,7 +71,9 @@ pub struct TunnelMetadata { /// The local IPs on the tunnel interface. pub ips: Vec<IpAddr>, /// The IP to the default gateway on the tunnel interface. - pub gateway: IpAddr, + pub ipv4_gateway: Ipv4Addr, + /// The IP to the IPv6 default gateway on the tunnel interface. + pub ipv6_gateway: Option<Ipv6Addr>, } impl TunnelEvent { @@ -96,15 +98,21 @@ impl TunnelEvent { .expect("No \"ifconfig_local\" in tunnel up event") .parse() .expect("Tunnel IP not in valid format")]; - let gateway = env + let ipv4_gateway = env .get("route_vpn_gateway") .expect("No \"route_vpn_gateway\" in tunnel up event") .parse() .expect("Tunnel gateway IP not in valid format"); + let ipv6_gateway = env.get("route_ipv6_gateway_1").map(|v6_str| { + v6_str + .parse() + .expect("V6 Tunnel gateway IP not in valid format") + }); Some(TunnelEvent::Up(TunnelMetadata { interface, ips, - gateway, + ipv4_gateway, + ipv6_gateway, })) } openvpn_plugin::EventType::RoutePredown => Some(TunnelEvent::Down), diff --git a/talpid-core/src/tunnel/wireguard/config.rs b/talpid-core/src/tunnel/wireguard/config.rs index ff167edb7c..e04a45618d 100644 --- a/talpid-core/src/tunnel/wireguard/config.rs +++ b/talpid-core/src/tunnel/wireguard/config.rs @@ -1,10 +1,15 @@ -use std::{borrow::Cow, ffi::CString, net::IpAddr}; +use std::{ + borrow::Cow, + ffi::CString, + net::{Ipv4Addr, Ipv6Addr}, +}; use talpid_types::net::{wireguard, GenericTunnelOptions}; pub struct Config { pub tunnel: wireguard::TunnelConfig, pub peers: Vec<wireguard::PeerConfig>, - pub gateway: IpAddr, + pub ipv4_gateway: Ipv4Addr, + pub ipv6_gateway: Option<Ipv6Addr>, pub mtu: u16, #[cfg(target_os = "linux")] pub fwmark: i32, @@ -37,7 +42,7 @@ impl Config { Self::new( tunnel, peer, - params.connection.gateway, + ¶ms.connection, ¶ms.options, ¶ms.generic_options, ) @@ -46,7 +51,7 @@ impl Config { pub fn new( mut tunnel: wireguard::TunnelConfig, mut peers: Vec<wireguard::PeerConfig>, - gateway: IpAddr, + connection_config: &wireguard::ConnectionConfig, wg_options: &wireguard::TunnelOptions, generic_options: &GenericTunnelOptions, ) -> Result<Config> { @@ -77,7 +82,13 @@ impl Config { Ok(Config { tunnel, peers, - gateway, + ipv4_gateway: connection_config.ipv4_gateway, + // Only set the v6 gateway if setting a v6 gateway makes sense + ipv6_gateway: if is_ipv6_enabled { + connection_config.ipv6_gateway + } else { + None + }, mtu, #[cfg(target_os = "linux")] fwmark: wg_options.fwmark, diff --git a/talpid-core/src/tunnel/wireguard/mod.rs b/talpid-core/src/tunnel/wireguard/mod.rs index 71ccee1b44..925552ad5f 100644 --- a/talpid-core/src/tunnel/wireguard/mod.rs +++ b/talpid-core/src/tunnel/wireguard/mod.rs @@ -1,7 +1,7 @@ use self::config::Config; use super::{TunnelEvent, TunnelMetadata}; use crate::routing; -use std::{path::Path, sync::mpsc}; +use std::{net::IpAddr, path::Path, sync::mpsc}; pub mod config; mod ping_monitor; @@ -79,7 +79,7 @@ impl WireguardMonitor { monitor.tunnel_up(&config); ping_monitor::ping( - config.gateway, + config.ipv4_gateway.into(), PING_TIMEOUT, &monitor.tunnel.get_interface_name().to_string(), ) @@ -152,7 +152,7 @@ impl WireguardMonitor { let close_sender = self.close_msg_sender.clone(); ping_monitor::spawn_ping_monitor( - config.gateway, + IpAddr::from(config.ipv4_gateway), PING_TIMEOUT, self.tunnel.get_interface_name().to_string(), move || { @@ -166,7 +166,8 @@ impl WireguardMonitor { let metadata = TunnelMetadata { interface: interface_name.to_string(), ips: config.tunnel.addresses.clone(), - gateway: config.gateway, + ipv4_gateway: config.ipv4_gateway, + ipv6_gateway: config.ipv6_gateway, }; (self.event_callback)(TunnelEvent::Up(metadata)); } diff --git a/talpid-core/src/tunnel_state_machine/connected_state.rs b/talpid-core/src/tunnel_state_machine/connected_state.rs index 1a979476e7..ffca534565 100644 --- a/talpid-core/src/tunnel_state_machine/connected_state.rs +++ b/talpid-core/src/tunnel_state_machine/connected_state.rs @@ -72,9 +72,14 @@ impl ConnectedState { } fn set_dns(&self, shared_values: &mut SharedTunnelStateValues) -> Result<()> { + let mut dns_ips = vec![self.metadata.ipv4_gateway.into()]; + if let Some(ipv6_gateway) = self.metadata.ipv6_gateway { + dns_ips.push(ipv6_gateway.into()); + }; + shared_values .dns_monitor - .set(&self.metadata.interface, &[self.metadata.gateway.into()]) + .set(&self.metadata.interface, &dns_ips) .chain_err(|| "Failed to set system DNS settings") } diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs index 10c693f5ef..b073ade768 100644 --- a/talpid-core/src/tunnel_state_machine/connecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs @@ -372,7 +372,13 @@ impl TunnelState for ConnectingState { fn gateway_list_from_params(params: &TunnelParameters) -> Vec<IpAddr> { match params { - TunnelParameters::Wireguard(params) => vec![params.connection.gateway], + TunnelParameters::Wireguard(params) => { + let mut gateways = vec![params.connection.ipv4_gateway.into()]; + if let Some(ipv6_gateway) = params.connection.ipv6_gateway { + gateways.push(ipv6_gateway.into()) + }; + gateways + } // No gateway list required when connecting to openvpn TunnelParameters::OpenVpn(_) => vec![], } diff --git a/talpid-types/src/net/wireguard.rs b/talpid-types/src/net/wireguard.rs index fe596fe475..4b8f1084cd 100644 --- a/talpid-types/src/net/wireguard.rs +++ b/talpid-types/src/net/wireguard.rs @@ -3,7 +3,7 @@ use ipnetwork::IpNetwork; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::{ fmt, - net::{IpAddr, SocketAddr}, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, }; use rand::RngCore; @@ -21,7 +21,8 @@ pub struct TunnelParameters { pub struct ConnectionConfig { pub tunnel: TunnelConfig, pub peer: PeerConfig, - pub gateway: IpAddr, + pub ipv4_gateway: Ipv4Addr, + pub ipv6_gateway: Option<Ipv6Addr>, } impl ConnectionConfig { diff --git a/windows/windns/src/windns/windns.cpp b/windows/windns/src/windns/windns.cpp index fe674723e2..e082f0826e 100644 --- a/windows/windns/src/windns/windns.cpp +++ b/windows/windns/src/windns/windns.cpp @@ -104,8 +104,6 @@ WinDns_Set( if (nullptr == g_Context || nullptr == ipv4Servers || 0 == numIpv4Servers - || nullptr == ipv6Servers - || 0 == numIpv6Servers || nullptr == recoverySink) { return false; diff --git a/windows/winfw/src/winfw/fwcontext.cpp b/windows/winfw/src/winfw/fwcontext.cpp index c25dbbbe0c..3a90c97b9f 100644 --- a/windows/winfw/src/winfw/fwcontext.cpp +++ b/windows/winfw/src/winfw/fwcontext.cpp @@ -89,7 +89,7 @@ bool FwContext::applyPolicyConnecting(const WinFwSettings &settings, const WinFw return applyRuleset(ruleset); } -bool FwContext::applyPolicyConnected(const WinFwSettings &settings, const WinFwRelay &relay, const wchar_t *tunnelInterfaceAlias, const wchar_t *primaryDns) +bool FwContext::applyPolicyConnected(const WinFwSettings &settings, const WinFwRelay &relay, const wchar_t *tunnelInterfaceAlias, const wchar_t *v4Gateway, const wchar_t *v6Gateway) { Ruleset ruleset; @@ -110,9 +110,11 @@ bool FwContext::applyPolicyConnected(const WinFwSettings &settings, const WinFwR tunnelInterfaceAlias )); + /// We currently expect DNS servers to only be ran on the tunnel gateway IPs ruleset.emplace_back(std::make_unique<rules::RestrictDns>( tunnelInterfaceAlias, - wfp::IpAddress(primaryDns) + wfp::IpAddress(v4Gateway), + (v6Gateway != nullptr) ? &wfp::IpAddress(v6Gateway) : nullptr )); return applyRuleset(ruleset); diff --git a/windows/winfw/src/winfw/fwcontext.h b/windows/winfw/src/winfw/fwcontext.h index d4198be9e4..65c45ac539 100644 --- a/windows/winfw/src/winfw/fwcontext.h +++ b/windows/winfw/src/winfw/fwcontext.h @@ -14,7 +14,7 @@ public: FwContext(uint32_t timeout); bool applyPolicyConnecting(const WinFwSettings &settings, const WinFwRelay &relay); - bool applyPolicyConnected(const WinFwSettings &settings, const WinFwRelay &relay, const wchar_t *tunnelInterfaceAlias, const wchar_t *primaryDns); + bool applyPolicyConnected(const WinFwSettings &settings, const WinFwRelay &relay, const wchar_t *tunnelInterfaceAlias, const wchar_t *v4DnsHosts, const wchar_t *v6DnsHost); bool applyPolicyBlocked(const WinFwSettings &settings); bool reset(); diff --git a/windows/winfw/src/winfw/rules/restrictdns.cpp b/windows/winfw/src/winfw/rules/restrictdns.cpp index d8a953fb3a..53c303cc47 100644 --- a/windows/winfw/src/winfw/rules/restrictdns.cpp +++ b/windows/winfw/src/winfw/rules/restrictdns.cpp @@ -12,9 +12,11 @@ using namespace wfp::conditions; namespace rules { -RestrictDns::RestrictDns(const std::wstring &tunnelInterfaceAlias, const wfp::IpAddress &dns) +RestrictDns::RestrictDns(const std::wstring &tunnelInterfaceAlias, const wfp::IpAddress v4DnsHost, wfp::IpAddress *v6DnsHost) : m_tunnelInterfaceAlias(tunnelInterfaceAlias) - , m_dns(dns) + , m_v4DnsHost(v4DnsHost) + , m_v6DnsHost(v6DnsHost) + { } @@ -73,52 +75,29 @@ bool RestrictDns::apply(IObjectInstaller &objectInstaller) } } - // - // This next part is a little redundant since the entire rule could be defined - // using three filters. Let's use four filters to maintain some kind of readability. - // - // The reason it would be possible to use three filters is because the single DNS - // is going to be either v4 or v6, so all requests that cannot be sent to the DNS - // will have to be blocked (thereby shadowing one of the filters above). - // filterBuilder - .name(L"Restrict DNS requests inside the VPN tunnel"); + .name(L"Restrict IPv4 DNS requests inside the VPN tunnel") + .key(MullvadGuids::FilterRestrictDns_Outbound_Tunnel_Ipv4()) + .layer(FWPM_LAYER_ALE_AUTH_CONNECT_V4); - if (m_dns.type() == wfp::IpAddress::Type::Ipv4) { - filterBuilder - .key(MullvadGuids::FilterRestrictDns_Outbound_Tunnel_Ipv4()) - .layer(FWPM_LAYER_ALE_AUTH_CONNECT_V4); - - { - wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_CONNECT_V4); - - conditionBuilder.add_condition(ConditionPort::Remote(53)); - conditionBuilder.add_condition(ConditionIp::Remote(m_dns, CompareNeq())); - - if (!objectInstaller.addFilter(filterBuilder, conditionBuilder)) - { - return false; - } - } - - filterBuilder - .key(MullvadGuids::FilterRestrictDns_Outbound_Tunnel_Ipv6()) - .layer(FWPM_LAYER_ALE_AUTH_CONNECT_V6); - - wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_CONNECT_V6); + wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_CONNECT_V4); conditionBuilder.add_condition(ConditionPort::Remote(53)); + conditionBuilder.add_condition(ConditionIp::Remote(m_v4DnsHost, CompareNeq())); - return objectInstaller.addFilter(filterBuilder, conditionBuilder); + if (!objectInstaller.addFilter(filterBuilder, conditionBuilder)) + { + return false; + } } // // Specified DNS is IPv6 // - filterBuilder + .name(L"Restrict IPv6 DNS requests inside the VPN tunnel") .key(MullvadGuids::FilterRestrictDns_Outbound_Tunnel_Ipv6()) .layer(FWPM_LAYER_ALE_AUTH_CONNECT_V6); @@ -126,23 +105,12 @@ bool RestrictDns::apply(IObjectInstaller &objectInstaller) wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_CONNECT_V6); conditionBuilder.add_condition(ConditionPort::Remote(53)); - conditionBuilder.add_condition(ConditionIp::Remote(m_dns, CompareNeq())); - - if (!objectInstaller.addFilter(filterBuilder, conditionBuilder)) - { - return false; + if (m_v6DnsHost != nullptr) { + conditionBuilder.add_condition(ConditionIp::Remote(*m_v6DnsHost, CompareNeq())); } - } - filterBuilder - .key(MullvadGuids::FilterRestrictDns_Outbound_Tunnel_Ipv4()) - .layer(FWPM_LAYER_ALE_AUTH_CONNECT_V4); - - wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_CONNECT_V4); - - conditionBuilder.add_condition(ConditionPort::Remote(53)); - - return objectInstaller.addFilter(filterBuilder, conditionBuilder); + return objectInstaller.addFilter(filterBuilder, conditionBuilder); + } } } diff --git a/windows/winfw/src/winfw/rules/restrictdns.h b/windows/winfw/src/winfw/rules/restrictdns.h index da09e970d3..ca3057a5cd 100644 --- a/windows/winfw/src/winfw/rules/restrictdns.h +++ b/windows/winfw/src/winfw/rules/restrictdns.h @@ -11,14 +11,16 @@ class RestrictDns : public IFirewallRule { public: - RestrictDns(const std::wstring &tunnelInterfaceAlias, const wfp::IpAddress &dns); + RestrictDns(const std::wstring &tunnelInterfaceAlias, const wfp::IpAddress v4DnsHost, wfp::IpAddress *v6DnsHost); bool apply(IObjectInstaller &objectInstaller) override; private: const std::wstring m_tunnelInterfaceAlias; - const wfp::IpAddress m_dns; + const wfp::IpAddress m_v4DnsHost; + const wfp::IpAddress *m_v6DnsHost; + }; } diff --git a/windows/winfw/src/winfw/winfw.cpp b/windows/winfw/src/winfw/winfw.cpp index 233423d1cd..f391d691b2 100644 --- a/windows/winfw/src/winfw/winfw.cpp +++ b/windows/winfw/src/winfw/winfw.cpp @@ -117,7 +117,8 @@ WinFw_ApplyPolicyConnected( const WinFwSettings &settings, const WinFwRelay &relay, const wchar_t *tunnelInterfaceAlias, - const wchar_t *primaryDns + const wchar_t *v4Gateway, + const wchar_t *v6Gateway ) { if (nullptr == g_fwContext) @@ -127,7 +128,7 @@ WinFw_ApplyPolicyConnected( try { - return g_fwContext->applyPolicyConnected(settings, relay, tunnelInterfaceAlias, primaryDns); + return g_fwContext->applyPolicyConnected(settings, relay, tunnelInterfaceAlias, v4Gateway, v6Gateway); } catch (std::exception &err) { diff --git a/windows/winfw/src/winfw/winfw.h b/windows/winfw/src/winfw/winfw.h index 38f92aacf2..f0c1adb2dc 100644 --- a/windows/winfw/src/winfw/winfw.h +++ b/windows/winfw/src/winfw/winfw.h @@ -123,7 +123,8 @@ WinFw_ApplyPolicyConnected( const WinFwSettings &settings, const WinFwRelay &relay, const wchar_t *tunnelInterfaceAlias, - const wchar_t *primaryDns + const wchar_t *v4Gateway, + const wchar_t *v6Gateway ); // |
