summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2024-01-08 16:50:36 +0100
committerDavid Lönnhager <david.l@mullvad.net>2024-01-08 16:50:36 +0100
commit4d33d452feaec4c82f134803c152486282ad36c8 (patch)
treeb542a2475982953ce977f202498516db83a9a32a
parentdf0cd903463fcf1c7004b72fee20beb3f2c231d0 (diff)
parent1c5851f624098dd52aa21ee4e3cc87f261e7fc0a (diff)
downloadmullvadvpn-4d33d452feaec4c82f134803c152486282ad36c8.tar.xz
mullvadvpn-4d33d452feaec4c82f134803c152486282ad36c8.zip
Merge branch 'macos-fix-ipv6'
-rw-r--r--CHANGELOG.md4
-rw-r--r--talpid-routing/src/unix/macos/data.rs3
-rw-r--r--talpid-routing/src/unix/macos/interface.rs38
3 files changed, 36 insertions, 9 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 13bb72f6a9..969ffe3775 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -33,6 +33,10 @@ Line wrap the file at 100 chars. Th
#### Linux
- Out IP missing forever when am.i.mullvad.net returns error
+#### macOS
+- Fix default route not being restored when disconnecting when the gateway was a link-local IPv6
+ address.
+
### Changed
- Remove `--location` flag from `mullvad status` CLI. Location and IP will now always
be printed (if available). `mullvad status listen` no longer prints location info.
diff --git a/talpid-routing/src/unix/macos/data.rs b/talpid-routing/src/unix/macos/data.rs
index f0be4186bc..1952578860 100644
--- a/talpid-routing/src/unix/macos/data.rs
+++ b/talpid-routing/src/unix/macos/data.rs
@@ -179,8 +179,7 @@ impl RouteMessage {
self
}
- pub fn set_gateway_addr(mut self, addr: IpAddr) -> Self {
- let gateway: SocketAddr = (addr, 0).into();
+ pub fn set_gateway_addr(mut self, gateway: impl Into<SockaddrStorage>) -> Self {
self.insert_sockaddr(RouteSocketAddress::Gateway(Some(gateway.into())));
self.route_flags |= RouteFlag::RTF_GATEWAY;
diff --git a/talpid-routing/src/unix/macos/interface.rs b/talpid-routing/src/unix/macos/interface.rs
index 5d7f24d9f5..f2b8383d94 100644
--- a/talpid-routing/src/unix/macos/interface.rs
+++ b/talpid-routing/src/unix/macos/interface.rs
@@ -7,7 +7,7 @@ use nix::{
use std::{
collections::BTreeMap,
io,
- net::{IpAddr, Ipv4Addr, Ipv6Addr},
+ net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
};
use super::data::{Destination, RouteMessage};
@@ -155,9 +155,32 @@ impl PrimaryInterfaceMonitor {
})
.next()?;
- // Synthesize a scoped route for the interface
+ let router_addr = (iface.router_ip, 0);
+ let mut router_addr = SocketAddr::from(router_addr);
+
+ // If the gateway is a link-local address, scope ID must be specified
+ if let SocketAddr::V6(ref mut v6_addr) = router_addr {
+ let v6ip = v6_addr.ip();
+
+ if is_link_local_v6(v6ip) {
+ // The second pair of octets should be set to the scope id
+ // See getaddr() in route.c:
+ // https://opensource.apple.com/source/network_cmds/network_cmds-396.6/route.tproj/route.c.auto.html
+
+ let second_octet = u16::try_from(index).unwrap().to_be_bytes();
+
+ let mut octets = v6ip.octets();
+ octets[2] = second_octet[0];
+ octets[3] = second_octet[1];
+
+ let new_ip = Ipv6Addr::from(octets);
+
+ v6_addr.set_ip(new_ip);
+ }
+ }
+
let msg = RouteMessage::new_route(Destination::Network(family.default_network()))
- .set_gateway_addr(iface.router_ip)
+ .set_gateway_addr(router_addr)
.set_interface_index(u16::try_from(index).unwrap());
Some(msg)
}
@@ -301,8 +324,9 @@ fn is_routable_v4(addr: &Ipv4Addr) -> bool {
}
fn is_routable_v6(addr: &Ipv6Addr) -> bool {
- !addr.is_unspecified()
- && !addr.is_loopback()
- // !(link local)
- && (addr.segments()[0] & 0xffc0) != 0xfe80
+ !addr.is_unspecified() && !addr.is_loopback() && !is_link_local_v6(addr)
+}
+
+fn is_link_local_v6(addr: &Ipv6Addr) -> bool {
+ (addr.segments()[0] & 0xffc0) == 0xfe80
}