summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md3
-rw-r--r--talpid-routing/src/unix/macos/interface.rs100
2 files changed, 55 insertions, 48 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2fed86ec51..e3a0b0b2d9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,9 @@ Line wrap the file at 100 chars. Th
- Fix node native module being unpacked to a temporary folder.
- Fix BSOD caused by routing loop in wireguard-nt.
+#### macOS
+- Fix bug in parsing of network services from SCDynamicStore.
+
## [2025.5] - 2025-03-26
This release is identical to 2025.5-beta1
diff --git a/talpid-routing/src/unix/macos/interface.rs b/talpid-routing/src/unix/macos/interface.rs
index 16f085c969..f23870945f 100644
--- a/talpid-routing/src/unix/macos/interface.rs
+++ b/talpid-routing/src/unix/macos/interface.rs
@@ -228,26 +228,18 @@ impl PrimaryInterfaceMonitor {
.get(key)
.and_then(|v| v.downcast_into::<CFDictionary>())?;
- let name = get_dict_elem_as_string(
+ let service_id = get_dict_elem_as_string(
&global_dict,
- schema_definition!(kSCDynamicStorePropNetPrimaryInterface),
+ schema_definition!(kSCDynamicStorePropNetPrimaryService),
)
.or_else(|| {
- log::debug!("Missing name for primary interface ({family})");
+ log::debug!("Missing service ID for primary interface ({family})");
None
})?;
- let router_ip = get_service_router_ip(&global_dict, family).or_else(|| {
- log::debug!("Missing router IP for primary interface ({name}, {family})");
- None
- })?;
- let first_ip = get_service_first_ip(&global_dict, family).or_else(|| {
- log::debug!("Missing IP for primary interface ({name}, {family})");
+
+ self.get_network_service(&service_id, family).or_else(|| {
+ log::debug!("Invalid service ID for primary interface ({family})");
None
- })?;
- Some(NetworkServiceDetails {
- name,
- router_ip,
- first_ip,
})
}
@@ -255,43 +247,45 @@ impl PrimaryInterfaceMonitor {
SCNetworkSet::new(&self.prefs)
.service_order()
.iter()
- .filter_map(|service_id| {
- let service_id_s = service_id.to_string();
- let service_key = if family == Family::V4 {
- format!("State:/Network/Service/{service_id_s}/IPv4")
- } else {
- format!("State:/Network/Service/{service_id_s}/IPv6")
- };
- let service_dict = self
- .store
- .get(CFString::new(&service_key))
- .and_then(|v| v.downcast_into::<CFDictionary>())?;
-
- let name = get_dict_elem_as_string(
- &service_dict,
- schema_definition!(kSCPropInterfaceName),
- )
- .or_else(|| {
- log::debug!("Missing name for service {service_key} ({family})");
- None
- })?;
- let router_ip = get_service_router_ip(&service_dict, family).or_else(|| {
- log::debug!("Missing router IP for {service_key} ({name}, {family})");
- None
- })?;
- let first_ip = get_service_first_ip(&service_dict, family).or_else(|| {
- log::debug!("Missing IP for \"{service_key}\" ({name}, {family})");
- None
- })?;
- Some(NetworkServiceDetails {
- name,
- router_ip,
- first_ip,
- })
- })
+ .filter_map(|service_id| self.get_network_service(&service_id.to_string(), family))
.collect::<Vec<_>>()
}
+ /// Get details about a specific network interface.
+ ///
+ /// Will return `None` and log a message on any error.
+ fn get_network_service(
+ &self,
+ service_id: &str,
+ family: Family,
+ ) -> Option<NetworkServiceDetails> {
+ let service_key = network_service_key(service_id.to_string(), family);
+ let service_dict = self
+ .store
+ .get(CFString::new(&service_key))
+ .and_then(|v| v.downcast_into::<CFDictionary>())?;
+
+ let name = get_dict_elem_as_string(&service_dict, schema_definition!(kSCPropInterfaceName))
+ .or_else(|| {
+ log::debug!("Missing name for service {service_key} ({family})");
+ None
+ })?;
+ let router_ip = get_service_router_ip(&service_dict, family).or_else(|| {
+ log::debug!("Missing router IP for {service_key} ({name}, {family})");
+ None
+ })?;
+ let first_ip = get_service_first_ip(&service_dict, family).or_else(|| {
+ log::debug!("Missing IP for \"{service_key}\" ({name}, {family})");
+ None
+ })?;
+
+ Some(NetworkServiceDetails {
+ name,
+ router_ip,
+ first_ip,
+ })
+ }
+
pub fn debug(&self) {
for family in [Family::V4, Family::V6] {
log::debug!(
@@ -306,6 +300,16 @@ impl PrimaryInterfaceMonitor {
}
}
+/// Construct the string key for a network service from its ID.
+fn network_service_key(service_id: String, family: Family) -> String {
+ let family = match family {
+ Family::V4 => "IPv4",
+ Family::V6 => "IPv6",
+ };
+
+ format!("State:/Network/Service/{service_id}/{family}")
+}
+
/// Return a map from interface name to link addresses (AF_LINK)
pub fn get_interface_link_addresses() -> io::Result<BTreeMap<String, SockaddrStorage>> {
let mut gateway_link_addrs = BTreeMap::new();