1use crate::InterfaceId;
6use crate::dns::DNS_PORT;
7use crate::telemetry::{NetworkEventMetadata, TelemetryEvent, TelemetrySender};
8use anyhow::Context as _;
9use assert_matches::assert_matches;
10use async_utils::stream::{StreamItem, StreamWithEpitaph, Tagged, WithEpitaph as _, WithTag as _};
11use dns_server_watcher::DnsServers;
12use fidl::endpoints::{ControlHandle as _, RequestStream as _};
13use futures::StreamExt as _;
14use log::{debug, error, info, warn};
15use policy_properties::NetworkTokenExt as _;
16use std::collections::HashMap;
17use std::collections::hash_map::Entry;
18
19mod reachability;
20mod token_registry;
21
22use fidl_fuchsia_net as fnet;
23use fidl_fuchsia_net_ext as fnet_ext;
24use fidl_fuchsia_net_name as fnet_name;
25use fidl_fuchsia_net_policy_properties as fnp_properties;
26use fidl_fuchsia_net_policy_socketproxy as fnp_socketproxy;
27use fidl_fuchsia_net_reachability as freachability;
28use fidl_fuchsia_posix_socket as fposix_socket;
29use fuchsia_inspect::Property as _;
30use fuchsia_inspect_derive::{IValue, Inspect, Unit, WithInspect as _};
31pub use reachability::ReachabilityWatcherConnectionId;
32use reachability::{ReachabilityHandler, ReachabilityStream};
33
34#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
39pub enum NetworkId {
40 Fuchsia(InterfaceId),
41 Delegated(InterfaceId),
42}
43
44impl std::fmt::Display for NetworkId {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 match self {
47 NetworkId::Fuchsia(interface_id) => write!(f, "fuchsia:{interface_id}"),
48 NetworkId::Delegated(interface_id) => write!(f, "delegated:{interface_id}"),
49 }
50 }
51}
52
53impl NetworkId {
54 pub fn get(&self) -> InterfaceId {
55 match self {
56 NetworkId::Fuchsia(interface_id) => *interface_id,
57 NetworkId::Delegated(interface_id) => *interface_id,
58 }
59 }
60
61 pub fn fuchsia<I: Into<InterfaceId>>(id: I) -> Self {
62 NetworkId::Fuchsia(id.into())
63 }
64
65 pub fn delegated<I: Into<InterfaceId>>(id: I) -> Self {
66 NetworkId::Delegated(id.into())
67 }
68
69 pub fn is_fuchsia(&self) -> bool {
70 matches!(self, NetworkId::Fuchsia(_))
71 }
72}
73
74pub(crate) fn determine_interface_state_changed(
82 prev: &fidl_fuchsia_net_interfaces::Properties,
83 curr: &fidl_fuchsia_net_interfaces_ext::Properties<
84 fidl_fuchsia_net_interfaces_ext::DefaultInterest,
85 >,
86) -> Option<bool> {
87 let was_candidate = (prev.has_default_ipv4_route.unwrap_or(curr.has_default_ipv4_route)
88 || prev.has_default_ipv6_route.unwrap_or(curr.has_default_ipv6_route))
89 && prev.online.unwrap_or(curr.online);
90 let is_candidate = (curr.has_default_ipv4_route || curr.has_default_ipv6_route) && curr.online;
91 (is_candidate != was_candidate).then_some(is_candidate)
92}
93
94#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
95pub(crate) struct NetworkTokenContents {
96 network_id: NetworkId,
97 is_default: bool,
98}
99
100macro_rules! connection_id {
106 ($id:ident => $allocator:ident) => {
107 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
109 pub struct $id(usize);
110
111 #[doc = concat!("Mints unique [`", stringify!($id), "`]s.")]
112 #[derive(Default)]
113 pub struct $allocator(usize);
114
115 impl $allocator {
116 pub fn allocate(&mut self) -> $id {
117 let id = $id(self.0);
118 self.0 += 1;
119 id
120 }
121 }
122 };
123}
124pub(crate) use connection_id;
125
126mod id {
127 connection_id!(NetworksConnectionId => NetworksConnectionIdAllocator);
129
130 connection_id!(PropertyWatcherConnectionId => PropertyWatcherConnectionIdAllocator);
132}
133
134pub use id::{NetworksConnectionId, PropertyWatcherConnectionId};
135use id::{NetworksConnectionIdAllocator, PropertyWatcherConnectionIdAllocator};
136
137#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
138pub struct UpdateGeneration {
139 default_network: usize,
142
143 properties: usize,
146}
147
148#[derive(Clone, Debug, Default)]
149pub struct UpdateGenerations {
150 default_network: HashMap<NetworksConnectionId, usize>,
151 properties: HashMap<PropertyWatcherConnectionId, usize>,
152}
153
154impl UpdateGenerations {
155 fn default_network(&self, id: &NetworksConnectionId) -> Option<usize> {
156 self.default_network.get(id).copied()
157 }
158
159 fn set_default_network(&mut self, id: NetworksConnectionId, generation: UpdateGeneration) {
160 *self.default_network.entry(id).or_default() = generation.default_network;
161 }
162
163 fn remove_default(&mut self, id: &NetworksConnectionId) -> Option<usize> {
164 self.default_network.remove(id)
165 }
166
167 fn properties(&self, id: &PropertyWatcherConnectionId) -> Option<usize> {
168 self.properties.get(id).copied()
169 }
170
171 fn set_properties(&mut self, id: PropertyWatcherConnectionId, generation: UpdateGeneration) {
172 *self.properties.entry(id).or_default() = generation.properties;
173 }
174
175 fn remove_properties(&mut self, id: &PropertyWatcherConnectionId) -> Option<usize> {
176 self.properties.remove(id)
177 }
178}
179
180trait SetMark {
181 fn set_mark(&mut self, domain: fnet::MarkDomain, value: Option<u32>);
182}
183
184impl SetMark for fnet::Marks {
185 fn set_mark(&mut self, domain: fnet::MarkDomain, value: Option<u32>) {
186 match domain {
187 fnet::MarkDomain::Mark1 => self.mark_1 = value,
188 fnet::MarkDomain::Mark2 => self.mark_2 = value,
189 }
190 }
191}
192
193#[derive(Debug)]
196struct Registration {
197 token: fnp_properties::NetworkToken,
198 properties: fnp_properties::PropertyInterest,
199 responder: Option<fnp_properties::PropertyWatcherWatchResponder>,
200 control_handle: fnp_properties::PropertyWatcherControlHandle,
203}
204
205impl Registration {
206 fn close(&mut self, epitaph: Option<zx::Status>) {
211 match epitaph {
214 Some(status) => self.control_handle.shutdown_with_epitaph(status),
215 None => self.control_handle.shutdown(),
216 }
217 self.responder = None;
219 }
220}
221
222#[derive(Debug)]
224struct NetworksClient {
225 responder: Option<fnp_properties::NetworksWatchDefaultResponder>,
227 control_handle: fnp_properties::NetworksControlHandle,
230}
231
232impl NetworksClient {
233 fn close(&mut self, epitaph: Option<zx::Status>) {
238 match epitaph {
241 Some(status) => self.control_handle.shutdown_with_epitaph(status),
242 None => self.control_handle.shutdown(),
243 }
244 self.responder = None;
246 }
247}
248
249#[derive(Debug, PartialEq, Default, Clone)]
250struct NetworkProperties {
251 socket_marks: Option<fnet::Marks>,
252 dns_servers: Vec<fnet_name::DnsServer_>,
253 connectivity_state: Option<fnp_socketproxy::ConnectivityState>,
257 name: Option<String>,
258 network_type: Option<fnp_socketproxy::NetworkType>,
259}
260
261impl NetworkProperties {
262 fn get_marks(&self) -> Option<&fnet::Marks> {
263 self.socket_marks.as_ref()
264 }
265}
266
267impl std::fmt::Display for NetworkProperties {
268 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269 let NetworkProperties { name, network_type, connectivity_state, socket_marks, dns_servers } =
270 self;
271
272 if let Some(name) = name {
273 write!(f, "name={name}")?;
274 }
275 if let Some(network_type) = network_type {
276 write!(f, ", type={}", network_type.as_str())?;
277 }
278 if let Some(connectivity_state) = connectivity_state {
279 write!(f, ", state={}", connectivity_state.as_str())?;
280 }
281 if let Some(marks) = socket_marks {
282 write!(f, ", mark={:?}", marks.mark_1)?;
283 }
284 if socket_marks.is_some() || !dns_servers.is_empty() {
285 write!(f, ", dns=[")?;
286 let mut servers = dns_servers.iter().filter_map(|s| {
287 s.address.map(|a| fidl_fuchsia_net_ext::SocketAddress::from(a).0.ip().to_string())
288 });
289 if let Some(first) = servers.next() {
290 write!(f, "{first}")?;
291 for s in servers {
292 write!(f, ", {s}")?;
293 }
294 }
295 write!(f, "]")?;
296 }
297 Ok(())
298 }
299}
300
301const NETWORK_REGISTRY_LOG_TAG: &str = "network_registry";
302
303#[derive(Default, Clone)]
305struct RegisteredNetworks {
306 default_network: Option<NetworkId>,
309 starnix_default: Option<NetworkId>,
311 networks: HashMap<NetworkId, NetworkProperties>,
312 dns_servers: Vec<fnet_name::DnsServer_>,
313}
314
315fn format_opt_network_id(id: Option<NetworkId>) -> String {
316 match id {
317 Some(id) => id.to_string(),
318 None => "None".to_string(),
319 }
320}
321
322impl RegisteredNetworks {
323 fn set_starnix_default(&mut self, next_starnix_default: Option<NetworkId>) {
324 if self.starnix_default != next_starnix_default {
325 info!(
326 tag = NETWORK_REGISTRY_LOG_TAG;
327 "SetStarnixDefault {} (prev={})",
328 format_opt_network_id(next_starnix_default),
329 format_opt_network_id(self.starnix_default),
330 );
331 self.starnix_default = next_starnix_default;
332 }
333 }
334
335 fn calculate_active_default(&self) -> Option<NetworkId> {
339 let first_fuchsia = self.networks.keys().filter(|id| id.is_fuchsia()).cloned().min();
342 if let Some(fd) = first_fuchsia {
343 return Some(fd);
344 }
345
346 if let Some(starnix_default) = self.starnix_default {
348 assert!(self.networks.contains_key(&starnix_default));
350 }
351 self.starnix_default
352 }
353
354 fn handle_default_network_update(&mut self) -> Option<DefaultChangedEvent> {
359 let next_default = self.calculate_active_default();
360 if next_default != self.default_network {
361 let old_default = self.default_network;
362 info!(
363 tag = NETWORK_REGISTRY_LOG_TAG;
364 "SetDefault {} (prev={})",
365 format_opt_network_id(next_default),
366 format_opt_network_id(old_default),
367 );
368 self.default_network = next_default;
369 Some(DefaultChangedEvent { previous_default: old_default })
370 } else {
371 None
372 }
373 }
374
375 fn apply(&mut self, update: NetworkRegistryUpdate) -> RegistryUpdateResult {
376 match update {
377 NetworkRegistryUpdate::UnsetDefaultNetwork => {
378 self.set_starnix_default(None);
380 RegistryUpdateResult {
381 event: UpdateApplied::None,
382 default_changed: self.handle_default_network_update(),
383 }
384 }
385 NetworkRegistryUpdate::ChangeNetwork(network_id, network_change) => {
386 match network_change {
387 NetworkUpdate::Properties(event) => RegistryUpdateResult {
388 event: self.handle_changed_network(network_id, event),
389 default_changed: self.handle_default_network_update(),
390 },
391 NetworkUpdate::Remove => {
392 if self.starnix_default == Some(network_id) {
393 error!("Cannot remove the default delegated network. Update ignored.");
394 RegistryUpdateResult {
395 event: UpdateApplied::None,
396 default_changed: None,
397 }
398 } else if let Some(properties) = self.networks.remove(&network_id) {
399 info!(
400 tag = NETWORK_REGISTRY_LOG_TAG;
401 "Remove {network_id} ({properties})"
402 );
403 RegistryUpdateResult {
405 event: UpdateApplied::NetworkRemoved(network_id),
406 default_changed: self.handle_default_network_update(),
407 }
408 } else {
409 error!(
410 "Cannot remove a non-existent network ({network_id:?}). \
411 Update ignored."
412 );
413 RegistryUpdateResult {
414 event: UpdateApplied::None,
415 default_changed: None,
416 }
417 }
418 }
419 NetworkUpdate::MakeDefault => {
420 match network_id {
421 NetworkId::Fuchsia(_) => {}
424 NetworkId::Delegated(_) => self.set_starnix_default(Some(network_id)),
425 }
426 let default_changed = self.handle_default_network_update();
427 RegistryUpdateResult { event: UpdateApplied::None, default_changed }
428 }
429 }
430 }
431 NetworkRegistryUpdate::UpdateDns(dns_servers) => {
432 let event = if self.dns_servers != dns_servers {
433 self.dns_servers = dns_servers;
434 UpdateApplied::DnsChanged
435 } else {
436 UpdateApplied::None
437 };
438 RegistryUpdateResult { event, default_changed: None }
439 }
440 }
441 }
442
443 fn handle_changed_network(
448 &mut self,
449 network_id: NetworkId,
450 event: NetworkPropertiesChange,
451 ) -> UpdateApplied {
452 let NetworkPropertiesChange {
453 added,
454 marks: socket_marks,
455 dns_servers: changed_dns_servers,
456 connectivity_state,
457 name,
458 network_type,
459 } = event;
460 let entry = self.networks.entry(network_id);
461 let result = match (added, &entry, network_id, socket_marks) {
462 (true, Entry::Occupied(_), _, _) => Err("add already added network"),
463 (false, Entry::Vacant(_), _, _) => Err("update a non-added network"),
464 (_, _, NetworkId::Fuchsia(_), Some(_)) => Err("have a fuchsia network with marks"),
465 (_, _, NetworkId::Delegated(_), None) => Err("have a delegated network without marks"),
466 (_, entry, NetworkId::Fuchsia(_), None) => {
467 let new_dns = changed_dns_servers.unwrap_or_default();
468 let changed_dns = match entry {
469 Entry::Occupied(e) => e.get().dns_servers != new_dns,
470 Entry::Vacant(_) => true,
473 };
474 Ok((
475 NetworkProperties { dns_servers: new_dns, ..Default::default() },
476 added,
477 changed_dns,
478 ))
479 }
480 (_, entry, NetworkId::Delegated(_), Some(socket_marks)) => {
481 let new_dns = changed_dns_servers.unwrap_or_default();
482 let (changed_marks, changed_dns) = match entry {
483 Entry::Occupied(e) => {
484 (e.get().get_marks() != Some(&socket_marks), e.get().dns_servers != new_dns)
485 }
486 Entry::Vacant(_) => (true, true),
489 };
490 Ok((
491 NetworkProperties {
492 socket_marks: Some(socket_marks),
493 dns_servers: new_dns,
494 ..Default::default()
495 },
496 changed_marks,
497 changed_dns,
498 ))
499 }
500 };
501
502 match result {
503 Ok((mut properties, changed_marks, changed_dns)) => {
504 properties.connectivity_state = connectivity_state;
505 properties.network_type = network_type;
506 properties.name = name.clone();
507 match &entry {
508 Entry::Occupied(e) => {
509 if *e.get() != properties {
511 info!(
512 tag = NETWORK_REGISTRY_LOG_TAG; "Update {network_id} ({properties})"
513 );
514 }
515 }
516 Entry::Vacant(_) => {
517 info!(tag = NETWORK_REGISTRY_LOG_TAG; "Add {network_id} ({properties})");
518 }
519 }
520 let _ = entry.insert_entry(properties);
521 UpdateApplied::NetworkChanged {
522 network_id,
523 added,
524 changed_marks,
525 changed_dns,
526 name,
527 network_type,
528 }
529 }
530 Err(e) => {
531 error!("Cannot {e}. Update ignored.");
532 UpdateApplied::None
533 }
534 }
535 }
536
537 pub fn consolidated_dns_servers(&self) -> Vec<fnet_name::DnsServer_> {
542 if let Some(NetworkId::Fuchsia(if_id)) = self.default_network {
543 self.networks
544 .get(&NetworkId::Fuchsia(if_id))
545 .map(|p| p.dns_servers.clone())
546 .unwrap_or_default()
547 } else {
548 self.networks
549 .iter()
550 .filter(|(id, _)| matches!(id, NetworkId::Delegated(_)))
551 .flat_map(|(_, p)| &p.dns_servers)
552 .cloned()
553 .collect()
554 }
555 }
556
557 fn dns_servers_for_network<'a>(
558 &'a self,
559 network_id: NetworkId,
560 properties: &'a NetworkProperties,
561 ) -> Vec<&'a fnet_name::DnsServer_> {
562 match network_id {
563 NetworkId::Delegated(_) => properties.dns_servers.iter().collect(),
564 NetworkId::Fuchsia(InterfaceId(if_id)) => {
565 if !properties.dns_servers.is_empty() {
566 properties.dns_servers.iter().collect()
567 } else {
568 self.dns_servers
569 .iter()
570 .filter(|s| match &s.source {
571 Some(fnet_name::DnsServerSource::Dhcp(d)) => {
572 d.source_interface == Some(if_id.get())
573 }
574 Some(fnet_name::DnsServerSource::Dhcpv6(d)) => {
575 d.source_interface == Some(if_id.get())
576 }
577 Some(fnet_name::DnsServerSource::Ndp(d)) => {
578 d.source_interface == Some(if_id.get())
579 }
580 _ => false,
581 })
582 .collect()
583 }
584 }
585 }
586 }
587
588 fn update_inspect(&self, node: &fuchsia_inspect::Node) {
589 node.clear_recorded();
590
591 if let Some(default_network) = &self.default_network {
592 node.record_string("default_network", default_network.to_string());
593 }
594
595 if let Some(starnix_default) = &self.starnix_default {
596 node.record_string("starnix_default", starnix_default.to_string());
597 }
598
599 if !self.dns_servers.is_empty() {
602 node.record_child("system_dns_servers", |system_node| {
603 for (i, server) in self.dns_servers.iter().enumerate() {
604 server.record_inspect(system_node, &i.to_string());
605 }
606 });
607 }
608
609 let mut sorted_networks: Vec<_> = self.networks.iter().collect();
610 sorted_networks.sort_by_key(|(id, _)| *id);
611
612 for (network_id, properties) in sorted_networks {
613 let network_node_name = match network_id {
614 NetworkId::Fuchsia(InterfaceId(id)) => format!("fuchsia_{id}"),
615 NetworkId::Delegated(InterfaceId(id)) => {
616 format!("delegated_{id}")
617 }
618 };
619
620 node.record_child(network_node_name, |net_node| {
621 if let Some(name) = &properties.name {
622 net_node.record_string("name", name);
623 }
624 if let Some(network_type) = &properties.network_type {
625 net_node.record_string("network_type", network_type.as_str());
626 }
627 if let Some(connectivity_state) = &properties.connectivity_state {
628 net_node.record_string("connectivity_state", connectivity_state.as_str());
629 }
630
631 let network_dns_servers = self.dns_servers_for_network(*network_id, properties);
632
633 if !network_dns_servers.is_empty() {
634 net_node.record_child("dns_servers", |dns_node| {
635 for (i, server) in network_dns_servers.iter().enumerate() {
636 server.record_inspect(dns_node, &i.to_string());
637 }
638 });
639 }
640 });
641 }
642 }
643}
644
645trait DnsServerInspectExt {
646 fn record_inspect(&self, node: &fuchsia_inspect::Node, name: &str);
647}
648
649impl DnsServerInspectExt for fnet_name::DnsServer_ {
650 fn record_inspect(&self, node: &fuchsia_inspect::Node, name: &str) {
651 let Some(address) = &self.address else {
652 return;
653 };
654 let server_str = fnet_ext::SocketAddress::from(*address).to_string();
655 let (source_type, iface_id) = dns_source_info(&self.source);
656
657 node.record_child(name, |entry_node| {
658 entry_node.record_string("server", server_str);
659 entry_node.record_string("type", source_type);
660 if let Some(iface_id) = iface_id {
661 entry_node.record_uint("interface_id", iface_id);
662 }
663 });
664 }
665}
666
667trait NetworkTypeInspectExt {
668 fn as_str(&self) -> &'static str;
669}
670
671impl NetworkTypeInspectExt for fnp_socketproxy::NetworkType {
672 fn as_str(&self) -> &'static str {
673 match self {
674 fnp_socketproxy::NetworkType::Unknown => "Unknown",
675 fnp_socketproxy::NetworkType::Ethernet => "Ethernet",
676 fnp_socketproxy::NetworkType::Wifi => "Wifi",
677 fnp_socketproxy::NetworkType::Bluetooth => "Bluetooth",
678 fnp_socketproxy::NetworkType::Cellular => "Cellular",
679 fnp_socketproxy::NetworkType::__SourceBreaking { .. } => "Unknown",
680 }
681 }
682}
683
684trait ConnectivityStateInspectExt {
685 fn as_str(&self) -> &'static str;
686}
687
688impl ConnectivityStateInspectExt for fnp_socketproxy::ConnectivityState {
689 fn as_str(&self) -> &'static str {
690 match self {
691 fnp_socketproxy::ConnectivityState::NoConnectivity => "NoConnectivity",
692 fnp_socketproxy::ConnectivityState::LocalConnectivity => "LocalConnectivity",
693 fnp_socketproxy::ConnectivityState::PartialConnectivity => "PartialConnectivity",
694 fnp_socketproxy::ConnectivityState::FullConnectivity => "FullConnectivity",
695 fnp_socketproxy::ConnectivityState::__SourceBreaking { .. } => "Unknown",
696 }
697 }
698}
699
700fn dns_source_info(source: &Option<fnet_name::DnsServerSource>) -> (&'static str, Option<u64>) {
701 match source {
702 Some(fnet_name::DnsServerSource::StaticSource(_)) => ("Static", None),
703 Some(fnet_name::DnsServerSource::Dhcp(dhcp)) => ("Dhcpv4", dhcp.source_interface),
704 Some(fnet_name::DnsServerSource::Dhcpv6(dhcpv6)) => ("Dhcpv6", dhcpv6.source_interface),
705 Some(fnet_name::DnsServerSource::Ndp(ndp)) => ("Ndp", ndp.source_interface),
706 Some(fnet_name::DnsServerSource::SocketProxy(_)) => ("SocketProxy", None),
707 Some(fnet_name::DnsServerSource::__SourceBreaking { .. }) | None => ("Unknown", None),
708 }
709}
710
711trait PropertyUpdates {
713 fn add_socket_marks(
714 &mut self,
715 network_registry: &RegisteredNetworks,
716 network: &NetworkTokenContents,
717 watched_properties: fnp_properties::PropertyInterest,
718 );
719 fn add_dns(
720 &mut self,
721 network_registry: &RegisteredNetworks,
722 network: &NetworkTokenContents,
723 watched_properties: fnp_properties::PropertyInterest,
724 );
725}
726
727impl PropertyUpdates for fnp_properties::PropertyUpdate {
728 fn add_socket_marks(
729 &mut self,
730 network_registry: &RegisteredNetworks,
731 network: &NetworkTokenContents,
732 watched_properties: fnp_properties::PropertyInterest,
733 ) {
734 if !watched_properties.contains(fnp_properties::PropertyInterest::SOCKET_MARKS) {
735 return;
736 }
737
738 match network_registry.networks.get(&network.network_id) {
739 Some(network) => {
740 if let Some(socket_marks) = network.get_marks() {
741 self.socket_marks = Some(socket_marks.clone());
742 }
743 return;
744 }
745 None => {
746 error!(
747 "State is inconsistent. We attempted to add marks for a \
748 network that is not known: {:?}",
749 network.network_id
750 );
751 }
752 }
753 }
754
755 fn add_dns(
756 &mut self,
757 network_registry: &RegisteredNetworks,
758 network: &NetworkTokenContents,
759 watched_properties: fnp_properties::PropertyInterest,
760 ) {
761 if !watched_properties.contains(fnp_properties::PropertyInterest::DNS_CONFIGURATION) {
762 return;
763 }
764
765 let interface_id = network.network_id;
766 self.dns_configuration = Some(fnp_properties::DnsConfiguration {
767 servers: Some(
768 network_registry
769 .dns_servers
770 .iter()
771 .filter(|d| {
772 match &d.source {
773 Some(source) => match source {
774 fnet_name::DnsServerSource::StaticSource(_) => true,
775 fnet_name::DnsServerSource::SocketProxy(
779 fnet_name::SocketProxyDnsServerSource {
780 source_interface, ..
781 },
782 ) => match (interface_id, source_interface) {
783 (_, None) => true,
784 (id1, Some(id2)) => {
785 Ok(id1)
786 == InterfaceId::try_from(*id2)
787 .map(|id| NetworkId::delegated(id))
788 }
789 },
790 fnet_name::DnsServerSource::Dhcp(
791 fnet_name::DhcpDnsServerSource { source_interface, .. },
792 )
793 | fnet_name::DnsServerSource::Ndp(
794 fnet_name::NdpDnsServerSource { source_interface, .. },
795 )
796 | fnet_name::DnsServerSource::Dhcpv6(
797 fnet_name::Dhcpv6DnsServerSource { source_interface, .. },
798 ) => match (interface_id, source_interface) {
799 (_, None) => true,
800 (id1, Some(id2)) => {
801 Ok(id1)
802 == InterfaceId::try_from(*id2)
803 .map(|id| NetworkId::fuchsia(id))
804 }
805 },
806
807 _ => {
808 error!("unhandled DnsServerSource: {source:?}");
809 false
810 }
811 },
812
813 None => true,
815 }
816 })
817 .cloned()
818 .collect::<Vec<_>>(),
819 ),
820 ..Default::default()
821 });
822 }
823}
824
825#[derive(Clone, Debug, Default)]
827pub struct NetworkPropertiesChange {
828 pub added: bool,
831 pub marks: Option<fnet::Marks>,
833 pub dns_servers: Option<Vec<fnet_name::DnsServer_>>,
835 pub connectivity_state: Option<fnp_socketproxy::ConnectivityState>,
837 pub name: Option<String>,
839 pub network_type: Option<fnp_socketproxy::NetworkType>,
841}
842
843#[derive(Debug, Clone)]
844pub enum NetworkUpdate {
845 Properties(NetworkPropertiesChange),
847 Remove,
848 MakeDefault,
849}
850
851#[derive(Debug, PartialEq, Eq, Clone)]
852struct DefaultChangedEvent {
853 previous_default: Option<NetworkId>,
854}
855
856#[derive(Debug, PartialEq, Eq)]
857struct RegistryUpdateResult {
858 event: UpdateApplied,
859 default_changed: Option<DefaultChangedEvent>,
862}
863
864#[derive(Debug, PartialEq, Eq, Clone)]
865enum UpdateApplied {
866 None,
868
869 DnsChanged,
871
872 NetworkChanged {
874 network_id: NetworkId,
875 added: bool,
876 changed_marks: bool,
877 changed_dns: bool,
878 name: Option<String>,
879 network_type: Option<fnp_socketproxy::NetworkType>,
880 },
881
882 NetworkRemoved(NetworkId),
884}
885
886#[derive(Debug, Clone)]
887pub enum NetworkRegistryUpdate {
888 UnsetDefaultNetwork,
889 ChangeNetwork(NetworkId, NetworkUpdate),
890 UpdateDns(Vec<fnet_name::DnsServer_>),
891}
892
893impl NetworkRegistryUpdate {
894 pub fn unset_default() -> Self {
895 NetworkRegistryUpdate::UnsetDefaultNetwork
896 }
897
898 pub fn dns(dns_servers: &DnsServers) -> Self {
899 NetworkRegistryUpdate::UpdateDns(dns_servers.consolidated_dns_servers())
902 }
903}
904
905struct ValidatedNetwork {
912 network_id: NetworkId,
913 marks: fnet::Marks,
914 dns_servers: Vec<fnet_name::DnsServer_>,
915 connectivity: Option<fnp_socketproxy::ConnectivityState>,
916 name: Option<String>,
917 network_type: Option<fnp_socketproxy::NetworkType>,
918}
919
920#[derive(Debug, PartialEq, Eq)]
921enum NetworkValidationError {
922 MissingNetworkId,
923 MissingNetworkInfo,
924}
925
926impl From<NetworkValidationError> for fnp_socketproxy::NetworkRegistryAddError {
927 fn from(error: NetworkValidationError) -> Self {
928 match error {
929 NetworkValidationError::MissingNetworkId => Self::MissingNetworkId,
930 NetworkValidationError::MissingNetworkInfo => Self::MissingNetworkInfo,
931 }
932 }
933}
934
935impl From<NetworkValidationError> for fnp_socketproxy::NetworkRegistryUpdateError {
936 fn from(error: NetworkValidationError) -> Self {
937 match error {
938 NetworkValidationError::MissingNetworkId => Self::MissingNetworkId,
939 NetworkValidationError::MissingNetworkInfo => Self::MissingNetworkInfo,
940 }
941 }
942}
943
944impl TryFrom<fnp_socketproxy::Network> for ValidatedNetwork {
945 type Error = NetworkValidationError;
946
947 fn try_from(network: fnp_socketproxy::Network) -> Result<Self, Self::Error> {
948 let raw_network_id = network.network_id.ok_or(NetworkValidationError::MissingNetworkId)?;
949 let network_id = InterfaceId::try_from(raw_network_id)
950 .map(NetworkId::delegated)
951 .map_err(|_| NetworkValidationError::MissingNetworkId)?;
952 let Some(fnp_socketproxy::NetworkInfo::Starnix(info)) = network.info else {
953 return Err(NetworkValidationError::MissingNetworkInfo);
954 };
955
956 let mut marks = fnet::Marks::default();
957 marks.set_mark(fnet::MARK_DOMAIN_SO_MARK, info.mark);
958
959 let dns_servers =
960 NetpolNetworksService::extract_dns_servers(&network.dns_servers, raw_network_id.into());
961
962 Ok(Self {
963 network_id,
964 marks,
965 dns_servers,
966 connectivity: network.connectivity,
967 name: network.name,
968 network_type: network.network_type,
969 })
970 }
971}
972
973#[derive(Debug, Default, PartialEq)]
978pub struct DelegatedNetworkUpdateResult {
979 pub dns_servers: Option<Vec<fnet_name::DnsServer_>>,
982}
983
984pub enum NetworkRequestStream {
989 Networks(fnp_properties::NetworksRequestStream),
990 NetworkTokenResolver(fnp_properties::NetworkTokenResolverRequestStream),
991 PropertyWatcher {
992 connection_id: PropertyWatcherConnectionId,
993 stream: fnp_properties::PropertyWatcherRequestStream,
994 },
995 DelegatedNetworks(fnp_socketproxy::NetworkRegistryRequestStream),
996 Reachability(freachability::MonitorRequestStream),
997}
998
999impl From<fnp_properties::NetworksRequestStream> for NetworkRequestStream {
1000 fn from(s: fnp_properties::NetworksRequestStream) -> Self {
1001 Self::Networks(s)
1002 }
1003}
1004impl From<fnp_properties::NetworkTokenResolverRequestStream> for NetworkRequestStream {
1005 fn from(s: fnp_properties::NetworkTokenResolverRequestStream) -> Self {
1006 Self::NetworkTokenResolver(s)
1007 }
1008}
1009
1010impl From<fnp_socketproxy::NetworkRegistryRequestStream> for NetworkRequestStream {
1011 fn from(s: fnp_socketproxy::NetworkRegistryRequestStream) -> Self {
1012 Self::DelegatedNetworks(s)
1013 }
1014}
1015
1016impl From<freachability::MonitorRequestStream> for NetworkRequestStream {
1017 fn from(s: freachability::MonitorRequestStream) -> Self {
1018 Self::Reachability(s)
1019 }
1020}
1021
1022impl From<(PropertyWatcherConnectionId, fnp_properties::PropertyWatcherRequestStream)>
1023 for NetworkRequestStream
1024{
1025 fn from(
1026 s: (PropertyWatcherConnectionId, fnp_properties::PropertyWatcherRequestStream),
1027 ) -> Self {
1028 let (connection_id, stream) = s;
1029 Self::PropertyWatcher { connection_id, stream }
1030 }
1031}
1032
1033pub(crate) type ConnectionStream<Id, S> = StreamWithEpitaph<Tagged<Id, S>, Id>;
1038
1039fn split_connection_item<Id, T>(item: StreamItem<(Id, T), Id>) -> (Id, Option<T>) {
1042 match item {
1043 StreamItem::Item((id, request)) => (id, Some(request)),
1044 StreamItem::Epitaph(id) => (id, None),
1045 }
1046}
1047
1048type DelegatedNetworksStream = StreamWithEpitaph<fnp_socketproxy::NetworkRegistryRequestStream, ()>;
1051
1052enum NetworkRequestStreamInner {
1055 Networks(ConnectionStream<NetworksConnectionId, fnp_properties::NetworksRequestStream>),
1056 NetworkTokenResolver(fnp_properties::NetworkTokenResolverRequestStream),
1057 PropertyWatcher(
1058 ConnectionStream<PropertyWatcherConnectionId, fnp_properties::PropertyWatcherRequestStream>,
1059 ),
1060 DelegatedNetworks(DelegatedNetworksStream),
1061 Reachability(ReachabilityStream),
1062}
1063
1064impl futures::Stream for NetworkRequestStreamInner {
1065 type Item = NetworkRequest;
1066
1067 fn poll_next(
1068 mut self: std::pin::Pin<&mut Self>,
1069 cx: &mut std::task::Context<'_>,
1070 ) -> std::task::Poll<Option<Self::Item>> {
1071 match *self {
1072 NetworkRequestStreamInner::Networks(ref mut stream) => {
1073 stream.poll_next_unpin(cx).map(|o| {
1074 o.map(split_connection_item)
1075 .map(|(id, request)| NetworkAttributesRequest { id, request })
1076 .map(NetworkRequest::NetworkAttributes)
1077 })
1078 }
1079 NetworkRequestStreamInner::NetworkTokenResolver(ref mut stream) => {
1080 stream.poll_next_unpin(cx).map(|o| {
1081 o.map(|request| NetworkTokenResolverRequest { request })
1082 .map(NetworkRequest::NetworkTokenResolver)
1083 })
1084 }
1085 NetworkRequestStreamInner::PropertyWatcher(ref mut stream) => {
1086 stream.poll_next_unpin(cx).map(|o| {
1087 o.map(split_connection_item)
1088 .map(|(id, request)| PropertyWatcherRequest { id, request })
1089 .map(NetworkRequest::PropertyWatcher)
1090 })
1091 }
1092 NetworkRequestStreamInner::DelegatedNetworks(ref mut stream) => {
1093 stream.poll_next_unpin(cx).map(|o| {
1094 o.map(|item| match item {
1095 StreamItem::Item(request) => {
1096 DelegatedNetworksRequest { request: Some(request) }
1097 }
1098 StreamItem::Epitaph(()) => DelegatedNetworksRequest { request: None },
1099 })
1100 .map(NetworkRequest::DelegatedNetworks)
1101 })
1102 }
1103 NetworkRequestStreamInner::Reachability(ref mut stream) => {
1104 stream.poll_next_unpin(cx).map(|o| {
1105 o.map(split_connection_item)
1106 .map(|(id, request)| ReachabilityRequest { id, request })
1107 .map(NetworkRequest::Reachability)
1108 })
1109 }
1110 }
1111 }
1112}
1113
1114pub struct NetworkAttributesRequest {
1118 pub id: NetworksConnectionId,
1119 pub request: Option<Result<fnp_properties::NetworksRequest, fidl::Error>>,
1120}
1121
1122pub struct NetworkTokenResolverRequest {
1124 pub request: Result<fnp_properties::NetworkTokenResolverRequest, fidl::Error>,
1125}
1126
1127pub struct PropertyWatcherRequest {
1131 pub id: PropertyWatcherConnectionId,
1132 pub request: Option<Result<fnp_properties::PropertyWatcherRequest, fidl::Error>>,
1133}
1134
1135pub struct DelegatedNetworksRequest {
1138 pub request: Option<Result<fnp_socketproxy::NetworkRegistryRequest, fidl::Error>>,
1139}
1140
1141pub struct ReachabilityRequest {
1144 pub id: ReachabilityWatcherConnectionId,
1145 pub request: Option<Result<freachability::MonitorRequest, fidl::Error>>,
1148}
1149
1150pub enum NetworkRequest {
1153 NetworkAttributes(NetworkAttributesRequest),
1154 NetworkTokenResolver(NetworkTokenResolverRequest),
1155 PropertyWatcher(PropertyWatcherRequest),
1156 DelegatedNetworks(DelegatedNetworksRequest),
1157 Reachability(ReachabilityRequest),
1158}
1159
1160impl futures::Stream for NetpolNetworksService {
1161 type Item = NetworkRequest;
1162
1163 fn poll_next(
1164 mut self: std::pin::Pin<&mut Self>,
1165 cx: &mut std::task::Context<'_>,
1166 ) -> std::task::Poll<Option<Self::Item>> {
1167 self.streams.poll_next_unpin(cx)
1168 }
1169}
1170
1171impl futures::stream::FusedStream for NetpolNetworksService {
1172 fn is_terminated(&self) -> bool {
1173 self.streams.is_terminated()
1174 }
1175}
1176
1177#[derive(Unit, Debug, Default, Clone)]
1178struct MethodInspect {
1179 successes: u32,
1180 errors: u32,
1181}
1182
1183#[derive(Unit, Debug, Default, Clone)]
1184struct RegistryMetrics {
1185 adds: MethodInspect,
1186 removes: MethodInspect,
1187 set_defaults: MethodInspect,
1191 updates: MethodInspect,
1192}
1193
1194#[derive(Inspect, Default)]
1195struct OperationsMetrics {
1196 delegated: IValue<RegistryMetrics>,
1197 inspect_node: fuchsia_inspect::Node,
1198}
1199
1200impl OperationsMetrics {
1201 fn record_set_default(
1202 &mut self,
1203 result: &Result<(), fnp_socketproxy::NetworkRegistrySetDefaultError>,
1204 ) {
1205 let mut delegated = self.delegated.as_mut();
1206 match result {
1207 Ok(()) => delegated.set_defaults.successes += 1,
1208 Err(_) => delegated.set_defaults.errors += 1,
1209 }
1210 }
1211
1212 fn record_add(&mut self, result: &Result<(), fnp_socketproxy::NetworkRegistryAddError>) {
1213 let mut delegated = self.delegated.as_mut();
1214 match result {
1215 Ok(()) => delegated.adds.successes += 1,
1216 Err(_) => delegated.adds.errors += 1,
1217 }
1218 }
1219
1220 fn record_update(&mut self, result: &Result<(), fnp_socketproxy::NetworkRegistryUpdateError>) {
1221 let mut delegated = self.delegated.as_mut();
1222 match result {
1223 Ok(()) => delegated.updates.successes += 1,
1224 Err(_) => delegated.updates.errors += 1,
1225 }
1226 }
1227
1228 fn record_remove(&mut self, result: &Result<(), fnp_socketproxy::NetworkRegistryRemoveError>) {
1229 let mut delegated = self.delegated.as_mut();
1230 match result {
1231 Ok(()) => delegated.removes.successes += 1,
1232 Err(_) => delegated.removes.errors += 1,
1233 }
1234 }
1235}
1236
1237const NETWORK_COUNT_PROPERTY_NAME: &str = "network_count";
1239
1240#[derive(Default)]
1241pub struct NetpolNetworksService {
1242 current_generation: UpdateGeneration,
1244 generations_by_connection: UpdateGenerations,
1246 networks_clients: HashMap<NetworksConnectionId, NetworksClient>,
1248 delegated_networks_client: Option<fnp_socketproxy::NetworkRegistryControlHandle>,
1250 tokens: token_registry::TokenRegistry<NetworkTokenContents>,
1251 property_watchers: HashMap<PropertyWatcherConnectionId, Registration>,
1253 network_registry: RegisteredNetworks,
1255 telemetry: Option<TelemetrySender>,
1256 next_networks_id: NetworksConnectionIdAllocator,
1258 next_watcher_id: PropertyWatcherConnectionIdAllocator,
1260 reachability_handler: ReachabilityHandler,
1262 streams: futures::stream::SelectAll<NetworkRequestStreamInner>,
1264
1265 metrics: OperationsMetrics,
1267 networks_inspect_node: Option<fuchsia_inspect::Node>,
1269 network_count: Option<fuchsia_inspect::UintProperty>,
1273}
1274
1275impl NetpolNetworksService {
1276 pub fn with_operations_inspect(
1277 mut self,
1278 parent: &fuchsia_inspect::Node,
1279 name: impl AsRef<str>,
1280 ) -> Result<Self, fuchsia_inspect_derive::AttachError> {
1281 self.metrics = OperationsMetrics::default().with_inspect(parent, name)?;
1282 Ok(self)
1283 }
1284
1285 pub fn with_network_registry_inspect(
1286 mut self,
1287 parent: &fuchsia_inspect::Node,
1288 name: impl AsRef<str>,
1289 ) -> Self {
1290 self.networks_inspect_node = Some(parent.create_child(name.as_ref()));
1291 self.network_count = Some(parent.create_uint(NETWORK_COUNT_PROPERTY_NAME, 0));
1292 self.update_network_inspect();
1293 self
1294 }
1295
1296 fn update_network_inspect(&self) {
1298 if let Some(networks_node) = &self.networks_inspect_node {
1299 self.network_registry.update_inspect(networks_node);
1300 }
1301 if let Some(network_count) = &self.network_count {
1302 network_count.set(self.network_registry.networks.len() as u64);
1303 }
1304 }
1305
1306 pub fn with_inspect(
1307 self,
1308 telemetry_parent: &fuchsia_inspect::Node,
1309 operations_name: impl AsRef<str>,
1310 networks_parent: &fuchsia_inspect::Node,
1311 networks_name: impl AsRef<str>,
1312 ) -> Result<Self, fuchsia_inspect_derive::AttachError> {
1313 let service = self.with_operations_inspect(telemetry_parent, operations_name)?;
1314 Ok(service.with_network_registry_inspect(networks_parent, networks_name))
1315 }
1316
1317 pub fn synthesize_reachability_snapshot(&self) -> freachability::Snapshot {
1318 ReachabilityHandler::synthesize_snapshot(
1319 self.network_registry
1320 .default_network
1321 .and_then(|id| self.network_registry.networks.get(&id)),
1322 )
1323 }
1324
1325 fn maybe_notify_watchers(&mut self) {
1326 let current_snapshot = self.synthesize_reachability_snapshot();
1327 self.reachability_handler.maybe_notify_watchers(¤t_snapshot);
1328 }
1329
1330 fn handle_reachability_request(
1331 &mut self,
1332 id: ReachabilityWatcherConnectionId,
1333 request: Option<Result<freachability::MonitorRequest, fidl::Error>>,
1334 ) {
1335 let current_snapshot = self.synthesize_reachability_snapshot();
1336 self.reachability_handler.handle_request(¤t_snapshot, id, request);
1337 }
1338
1339 #[cfg(test)]
1340 pub fn reachability_watcher_count(&self) -> usize {
1341 self.reachability_handler.watcher_count()
1342 }
1343
1344 pub fn set_telemetry(&mut self, telemetry: TelemetrySender) {
1345 self.telemetry = Some(telemetry);
1346 }
1347
1348 pub fn add_stream<S: Into<NetworkRequestStream>>(&mut self, s: S) {
1349 match s.into() {
1350 NetworkRequestStream::Networks(stream) => {
1351 let id = self.next_networks_id.allocate();
1352 let previous = self.networks_clients.insert(
1353 id,
1354 NetworksClient { responder: None, control_handle: stream.control_handle() },
1355 );
1356 assert!(previous.is_none(), "networks client {id:?} is already registered");
1357 self.streams
1358 .push(NetworkRequestStreamInner::Networks(stream.tagged(id).with_epitaph(id)));
1359 }
1360 NetworkRequestStream::NetworkTokenResolver(stream) => {
1361 self.streams.push(NetworkRequestStreamInner::NetworkTokenResolver(stream));
1362 }
1363 NetworkRequestStream::DelegatedNetworks(stream) => {
1364 if self.delegated_networks_client.is_some() {
1365 warn!(
1366 "Only one connection to \
1367 fuchsia.net.policy.socketproxy/NetworkRegistry is allowed at a time"
1368 );
1369 stream.control_handle().shutdown_with_epitaph(zx::Status::ALREADY_EXISTS);
1370 } else {
1371 self.delegated_networks_client = Some(stream.control_handle());
1372 self.streams.push(NetworkRequestStreamInner::DelegatedNetworks(
1373 stream.with_epitaph(()),
1374 ));
1375 }
1376 }
1377 NetworkRequestStream::PropertyWatcher { connection_id, stream } => {
1378 self.streams.push(NetworkRequestStreamInner::PropertyWatcher(
1379 stream.tagged(connection_id).with_epitaph(connection_id),
1380 ));
1381 }
1382 NetworkRequestStream::Reachability(stream) => {
1383 if let Some(reachability_stream) = self.reachability_handler.add_stream(stream) {
1384 self.streams.push(NetworkRequestStreamInner::Reachability(reachability_stream));
1385 }
1386 }
1387 }
1388 }
1389
1390 pub async fn handle_event(
1391 &mut self,
1392 event: NetworkRequest,
1393 ) -> Result<DelegatedNetworkUpdateResult, anyhow::Error> {
1394 match event {
1395 NetworkRequest::NetworkAttributes(NetworkAttributesRequest { id, request }) => {
1396 self.handle_network_attributes_request(id, request).await?;
1397 Ok(DelegatedNetworkUpdateResult { dns_servers: None })
1398 }
1399 NetworkRequest::NetworkTokenResolver(NetworkTokenResolverRequest { request }) => {
1400 self.handle_network_token_resolver_request(request).await?;
1401 Ok(DelegatedNetworkUpdateResult { dns_servers: None })
1402 }
1403 NetworkRequest::DelegatedNetworks(DelegatedNetworksRequest { request }) => {
1404 Ok(self.handle_delegated_networks_update(request).await)
1405 }
1406 NetworkRequest::PropertyWatcher(PropertyWatcherRequest { id, request }) => {
1407 self.handle_property_watcher_request(id, request).await?;
1408 Ok(DelegatedNetworkUpdateResult { dns_servers: None })
1409 }
1410 NetworkRequest::Reachability(ReachabilityRequest { id, request }) => {
1411 self.handle_reachability_request(id, request);
1412 Ok(DelegatedNetworkUpdateResult { dns_servers: None })
1413 }
1414 }
1415 }
1416
1417 pub fn consolidated_dns_servers(&self) -> Vec<fnet_name::DnsServer_> {
1419 self.network_registry.consolidated_dns_servers()
1420 }
1421
1422 pub async fn handle_network_attributes_request(
1430 &mut self,
1431 id: NetworksConnectionId,
1432 req: Option<Result<fnp_properties::NetworksRequest, fidl::Error>>,
1433 ) -> Result<(), anyhow::Error> {
1434 let mut entry = assert_matches!(
1435 self.networks_clients.entry(id),
1436 Entry::Occupied(entry) => entry,
1437 "request for unknown networks client {id:?}"
1438 );
1439
1440 let req = match req {
1441 Some(Ok(req)) => req,
1442 Some(Err(e)) => {
1443 error!("Networks client {id:?} stream error: {e}");
1447 entry.get_mut().close(None);
1448 return Ok(());
1449 }
1450 None => {
1453 let _: NetworksClient = entry.remove();
1454 let _: Option<_> = self.generations_by_connection.remove_default(&id);
1455 return Ok(());
1456 }
1457 };
1458 match req {
1459 fnp_properties::NetworksRequest::WatchDefault { responder } => {
1460 let client = entry.get_mut();
1461 if client.responder.is_some() {
1462 warn!(
1463 "Only one call to fuchsia.net.policy.properties/Networks.WatchDefault \
1464 may be active per connection"
1465 );
1466 client.close(Some(zx::Status::ALREADY_EXISTS));
1468 } else {
1469 let network_id =
1470 if self.generations_by_connection.default_network(&id).unwrap_or_default()
1471 < self.current_generation.default_network
1472 {
1473 self.network_registry.default_network
1474 } else {
1475 None
1476 };
1477 if let Some(network_id) = network_id {
1478 self.generations_by_connection
1479 .set_default_network(id, self.current_generation);
1480 let token = self
1481 .tokens
1482 .ensure_token(NetworkTokenContents { network_id, is_default: true })
1483 .get()
1484 .duplicate()
1485 .context("could not duplicate token")?;
1486 responder
1487 .send(fnp_properties::NetworksWatchDefaultResponse::Network(token))?;
1488 } else {
1489 client.responder = Some(responder);
1490 }
1491 }
1492 }
1493 fnp_properties::NetworksRequest::WatchProperties {
1494 payload:
1495 fnp_properties::NetworksWatchPropertiesRequest {
1496 network, properties, watcher, ..
1497 },
1498 responder,
1499 } => match (network, properties, watcher) {
1500 (None, _, _) | (_, None, _) | (_, _, None) => {
1501 responder.send(Err(fnp_properties::WatchError::MissingRequiredArgument))?
1502 }
1503 (Some(network), Some(properties), Some(watcher)) => {
1504 if properties == fnp_properties::PropertyInterest::default() {
1505 responder.send(Err(fnp_properties::WatchError::NoProperties))?
1506 } else {
1507 match self.tokens.get_contents(&network) {
1508 Err(e) => {
1509 warn!("Unknown network token. ({network:?}: {e})");
1510 responder
1511 .send(Err(fnp_properties::WatchError::InvalidNetworkToken))?
1512 }
1513 Ok(_network_contents) => {
1514 let watcher_stream = watcher.into_stream();
1518 let watcher_id = self.next_watcher_id.allocate();
1519 let registration = Registration {
1520 token: network,
1521 properties,
1522 responder: None,
1523 control_handle: watcher_stream.control_handle(),
1524 };
1525 let previous =
1526 self.property_watchers.insert(watcher_id, registration);
1527 assert!(
1528 previous.is_none(),
1529 "property watcher {watcher_id:?} is already registered"
1530 );
1531 self.add_stream((watcher_id, watcher_stream));
1532 responder.send(Ok(()))?;
1533 }
1534 }
1535 }
1536 }
1537 },
1538 fnp_properties::NetworksRequest::_UnknownMethod { ordinal, .. } => {
1539 warn!("Received unexpected request {ordinal}")
1540 }
1541 }
1542
1543 Ok(())
1544 }
1545
1546 pub async fn handle_property_watcher_request(
1554 &mut self,
1555 id: PropertyWatcherConnectionId,
1556 req: Option<Result<fnp_properties::PropertyWatcherRequest, fidl::Error>>,
1557 ) -> Result<(), anyhow::Error> {
1558 let mut entry = assert_matches!(
1559 self.property_watchers.entry(id),
1560 Entry::Occupied(entry) => entry,
1561 "request for unknown property watcher {id:?}"
1562 );
1563
1564 let req = match req {
1565 Some(Ok(req)) => req,
1566 Some(Err(e)) => {
1567 error!("Property watcher {id:?} stream error: {e}");
1571 entry.get_mut().close(None);
1572 return Ok(());
1573 }
1574 None => {
1577 let _: Registration = entry.remove();
1578 let _: Option<_> = self.generations_by_connection.remove_properties(&id);
1579 return Ok(());
1580 }
1581 };
1582 match req {
1583 fnp_properties::PropertyWatcherRequest::Watch { responder } => {
1584 let registration = entry.get_mut();
1585 if registration.responder.is_some() {
1586 warn!(
1587 "Only one call to \
1588 fuchsia.net.policy.properties/PropertyWatcher.Watch may be \
1589 active per connection"
1590 );
1591 registration.close(Some(zx::Status::ALREADY_EXISTS));
1593 } else {
1594 registration.responder = Some(responder);
1595 match self.tokens.get_contents(®istration.token) {
1596 Ok(network_contents) => {
1597 let is_initial =
1600 self.generations_by_connection.properties(&id).is_none();
1601 if is_initial
1602 || self
1603 .generations_by_connection
1604 .properties(&id)
1605 .unwrap_or_default()
1606 < self.current_generation.properties
1607 {
1608 let mut updates = fnp_properties::PropertyUpdate::default();
1609 updates.add_socket_marks(
1610 &self.network_registry,
1611 &network_contents,
1612 registration.properties,
1613 );
1614 updates.add_dns(
1615 &self.network_registry,
1616 &network_contents,
1617 registration.properties,
1618 );
1619 let network_is_known = self
1620 .network_registry
1621 .networks
1622 .contains_key(&network_contents.network_id);
1623 if (is_initial && network_is_known)
1624 || updates != fnp_properties::PropertyUpdate::default()
1625 {
1626 self.generations_by_connection
1627 .set_properties(id, self.current_generation);
1628 if let Some(responder) = registration.responder.take() {
1629 responder.send(Ok(&updates))?;
1630 }
1631 }
1632 }
1633 }
1634 Err(e) => {
1637 if e != zx::Status::NOT_FOUND {
1638 warn!("Unexpected error fetching token contents: {e}");
1639 }
1640 let _: Option<_> =
1641 self.generations_by_connection.remove_properties(&id);
1642 if let Some(responder) = registration.responder.take() {
1643 if let Err(e) = responder
1644 .send(Err(fnp_properties::PropertyWatcherError::NetworkGone))
1645 {
1646 warn!("Could not send to responder: {e}");
1647 }
1648 registration.close(None);
1649 }
1650 }
1651 }
1652 }
1653 }
1654 }
1655
1656 Ok(())
1657 }
1658
1659 pub async fn handle_delegated_networks_update(
1674 &mut self,
1675 update: Option<Result<fnp_socketproxy::NetworkRegistryRequest, fidl::Error>>,
1676 ) -> DelegatedNetworkUpdateResult {
1677 use fnp_socketproxy::{
1678 NetworkRegistryAddError, NetworkRegistryRemoveError, NetworkRegistryRequest,
1679 NetworkRegistrySetDefaultError, NetworkRegistryUpdateError,
1680 };
1681
1682 let control_handle = assert_matches!(
1683 self.delegated_networks_client.as_ref(),
1684 Some(control_handle) => control_handle,
1685 "request with no active delegated networks client"
1686 );
1687
1688 let req = match update {
1689 Some(Ok(req)) => req,
1690 Some(Err(e)) => {
1691 error!("Delegated networks client stream error: {e}");
1695 control_handle.shutdown();
1696 return DelegatedNetworkUpdateResult { dns_servers: None };
1697 }
1698 None => {
1701 let _: Option<_> = self.delegated_networks_client.take();
1702 return self.clear_delegated_networks().await;
1703 }
1704 };
1705
1706 let action_result = match req {
1707 NetworkRegistryRequest::SetDefault { network_id, responder } => {
1708 let set_default_result = match network_id {
1709 fposix_socket::OptionalUint32::Value(interface_id) => {
1710 match InterfaceId::try_from(interface_id) {
1711 Ok(id) => {
1712 let delegated_id = NetworkId::delegated(id);
1713 if self.network_registry.networks.contains_key(&delegated_id) {
1714 self.update(NetworkRegistryUpdate::ChangeNetwork(
1715 delegated_id,
1716 NetworkUpdate::MakeDefault,
1717 ))
1718 .await;
1719 Ok(())
1720 } else {
1721 Err(NetworkRegistrySetDefaultError::NotFound)
1722 }
1723 }
1724 Err(_) => Err(NetworkRegistrySetDefaultError::NotFound),
1725 }
1726 }
1727 fposix_socket::OptionalUint32::Unset(_) => {
1728 self.update(NetworkRegistryUpdate::unset_default()).await;
1729 Ok(())
1730 }
1731 };
1732
1733 self.metrics.record_set_default(&set_default_result);
1734
1735 self.respond_to_delegated_network_update(
1736 set_default_result,
1737 |reply| responder.send(reply),
1738 "failed to send SetDefault result",
1739 )
1740 }
1741 NetworkRegistryRequest::Add { network, responder } => {
1742 let add_result = match ValidatedNetwork::try_from(network).map_err(Into::into) {
1743 Ok(valid) => {
1744 if self.network_registry.networks.contains_key(&valid.network_id) {
1745 Err(NetworkRegistryAddError::DuplicateNetworkId)
1746 } else {
1747 self.update(NetworkRegistryUpdate::ChangeNetwork(
1748 valid.network_id,
1749 NetworkUpdate::Properties(NetworkPropertiesChange {
1750 added: true,
1751 marks: Some(valid.marks),
1752 dns_servers: Some(valid.dns_servers),
1753 connectivity_state: valid.connectivity,
1754 name: valid.name,
1755 network_type: valid.network_type,
1756 }),
1757 ))
1758 .await;
1759 Ok(())
1760 }
1761 }
1762 Err(e) => Err(e),
1763 };
1764
1765 self.metrics.record_add(&add_result);
1766
1767 self.respond_to_delegated_network_update(
1768 add_result,
1769 |reply| responder.send(reply),
1770 "failed to send Add result",
1771 )
1772 }
1773 NetworkRegistryRequest::Update { network, responder } => {
1774 let update_result = match ValidatedNetwork::try_from(network).map_err(Into::into) {
1775 Ok(valid) => {
1776 if !self.network_registry.networks.contains_key(&valid.network_id) {
1777 Err(NetworkRegistryUpdateError::NotFound)
1778 } else {
1779 self.update(NetworkRegistryUpdate::ChangeNetwork(
1780 valid.network_id,
1781 NetworkUpdate::Properties(NetworkPropertiesChange {
1782 added: false,
1783 marks: Some(valid.marks),
1784 dns_servers: Some(valid.dns_servers),
1785 connectivity_state: valid.connectivity,
1786 name: valid.name,
1787 network_type: valid.network_type,
1788 }),
1789 ))
1790 .await;
1791 Ok(())
1792 }
1793 }
1794 Err(e) => Err(e),
1795 };
1796
1797 self.metrics.record_update(&update_result);
1798
1799 self.respond_to_delegated_network_update(
1800 update_result,
1801 |reply| responder.send(reply),
1802 "failed to send Update result",
1803 )
1804 }
1805 NetworkRegistryRequest::Remove { network_id, responder } => {
1806 let remove_result = match InterfaceId::try_from(network_id) {
1807 Ok(id) => {
1808 let delegated_id = NetworkId::delegated(id);
1809 if self.network_registry.starnix_default == Some(delegated_id) {
1810 Err(NetworkRegistryRemoveError::CannotRemoveDefaultNetwork)
1811 } else if !self.network_registry.networks.contains_key(&delegated_id) {
1812 Err(NetworkRegistryRemoveError::NotFound)
1813 } else {
1814 self.update(NetworkRegistryUpdate::ChangeNetwork(
1815 delegated_id,
1816 NetworkUpdate::Remove,
1817 ))
1818 .await;
1819 Ok(())
1820 }
1821 }
1822 Err(_) => Err(NetworkRegistryRemoveError::NotFound),
1823 };
1824
1825 self.metrics.record_remove(&remove_result);
1826
1827 self.respond_to_delegated_network_update(
1828 remove_result,
1829 |reply| responder.send(reply),
1830 "failed to send Remove result",
1831 )
1832 }
1833 };
1834
1835 action_result
1836 }
1837
1838 async fn clear_delegated_networks(&mut self) -> DelegatedNetworkUpdateResult {
1842 if self.network_registry.starnix_default.is_some() {
1845 self.update(NetworkRegistryUpdate::unset_default()).await;
1846 }
1847
1848 let delegated_ids = self
1849 .network_registry
1850 .networks
1851 .keys()
1852 .filter(|id| match id {
1853 NetworkId::Delegated(_) => true,
1854 NetworkId::Fuchsia(_) => false,
1855 })
1856 .copied()
1857 .collect::<Vec<_>>();
1858
1859 for id in &delegated_ids {
1860 self.update(NetworkRegistryUpdate::ChangeNetwork(*id, NetworkUpdate::Remove)).await;
1861 }
1862
1863 DelegatedNetworkUpdateResult {
1864 dns_servers: (!delegated_ids.is_empty())
1865 .then(|| self.network_registry.consolidated_dns_servers()),
1866 }
1867 }
1868
1869 fn respond_to_delegated_network_update<E, F>(
1872 &self,
1873 operation_result: Result<(), E>,
1874 send_response: F,
1875 context_message: &'static str,
1876 ) -> DelegatedNetworkUpdateResult
1877 where
1878 F: FnOnce(Result<(), E>) -> Result<(), fidl::Error>,
1879 {
1880 let dns_servers = operation_result
1882 .as_ref()
1883 .ok()
1884 .map(|()| self.network_registry.consolidated_dns_servers());
1885
1886 if let Err(e) = send_response(operation_result) {
1888 if !e.is_closed() {
1889 error!(
1890 "Failed to send delegated network update result \
1891 for {context_message}: {e}"
1892 );
1893 }
1894 }
1895
1896 DelegatedNetworkUpdateResult { dns_servers }
1897 }
1898
1899 fn extract_dns_servers(
1904 dns_servers: &Option<fnp_socketproxy::NetworkDnsServers>,
1905 network_id: u64,
1906 ) -> Vec<fnet_name::DnsServer_> {
1907 let make_server = |address| fnet_name::DnsServer_ {
1908 address: Some(address),
1909 source: Some(fnet_name::DnsServerSource::SocketProxy(
1910 fnet_name::SocketProxyDnsServerSource {
1911 source_interface: Some(network_id),
1912 ..Default::default()
1913 },
1914 )),
1915 ..Default::default()
1916 };
1917
1918 dns_servers
1919 .as_ref()
1920 .map(|dns| {
1921 dns.v4
1922 .as_ref()
1923 .into_iter()
1924 .flatten()
1925 .map(|&address| {
1926 make_server(fnet::SocketAddress::Ipv4(fnet::Ipv4SocketAddress {
1927 address,
1928 port: DNS_PORT,
1929 }))
1930 })
1931 .chain(dns.v6.as_ref().into_iter().flatten().map(|&address| {
1932 make_server(fnet::SocketAddress::Ipv6(fnet::Ipv6SocketAddress {
1933 address,
1934 port: DNS_PORT,
1935 zone_index: 0,
1936 }))
1937 }))
1938 .collect()
1939 })
1940 .unwrap_or_default()
1941 }
1942
1943 pub(crate) async fn handle_network_token_resolver_request(
1944 &mut self,
1945 request: Result<fnp_properties::NetworkTokenResolverRequest, fidl::Error>,
1946 ) -> Result<(), anyhow::Error> {
1947 use fnp_properties::NetworkTokenResolverResolveTokenError as ResolveTokenError;
1948
1949 let request = request.context("while handling NetworkTokenResolver request")?;
1950 match request {
1951 fnp_properties::NetworkTokenResolverRequest::ResolveToken { token, responder } => {
1952 let maybe_contents = self.tokens.get_contents(&token).copied();
1953 match maybe_contents {
1954 Err(e) => {
1955 warn!("Unknown network token. ({token:?}: {e})");
1956 responder.send(Err(ResolveTokenError::InvalidNetworkToken))?;
1957 }
1958 Ok(contents) => {
1959 if contents.is_default {
1960 let query = NetworkTokenContents { is_default: false, ..contents };
1963 if let Some(tok) = self.tokens.get_token(&query) {
1964 responder.send(tok.duplicate().map_err(|e| {
1965 warn!("Encountered issue duplicating generated token. {e}");
1966 ResolveTokenError::InvalidNetworkToken
1967 }))?;
1968 } else {
1969 warn!("Requested canonical version of unregistered network.");
1970 responder.send(Err(ResolveTokenError::InvalidNetworkToken))?;
1971 }
1972 } else {
1973 responder.send(Ok(token))?;
1974 }
1975 }
1976 }
1977 }
1978 fidl_fuchsia_net_policy_properties::NetworkTokenResolverRequest::_UnknownMethod {
1979 ordinal,
1980 control_handle,
1981 method_type,
1982 ..
1983 } => warn!(
1984 "Encountered unknown method call on NetworkTokenResolver: {ordinal} \
1985 {control_handle:?} {method_type:?}"
1986 ),
1987 }
1988
1989 Ok(())
1990 }
1991
1992 async fn changed_default_network(
1993 &mut self,
1994 previous_default_network: Option<NetworkId>,
1995 property_watchers: &mut HashMap<PropertyWatcherConnectionId, Registration>,
1996 ) {
1997 for (id, registration) in property_watchers.iter_mut() {
1998 if let Ok(contents) = self.tokens.get_contents(®istration.token) {
1999 if contents.is_default {
2000 let _: Option<_> = self.generations_by_connection.remove_properties(id);
2001 if let Some(responder) = registration.responder.take() {
2002 if let Err(e) =
2003 responder.send(Err(fnp_properties::PropertyWatcherError::NetworkGone))
2004 {
2005 warn!("Could not send to responder: {e}");
2006 }
2007 registration.close(None);
2008 }
2009 }
2010 }
2011 }
2012 self.tokens.drop_if(|&c| {
2013 c.is_default && previous_default_network.is_some_and(|i| i == c.network_id)
2014 });
2015 }
2016
2017 pub async fn update(&mut self, update: NetworkRegistryUpdate) {
2018 let RegistryUpdateResult { event, default_changed } = self.network_registry.apply(update);
2019
2020 self.update_network_inspect();
2021
2022 if let UpdateApplied::None = event {
2023 if default_changed.is_none() {
2024 return;
2026 }
2027 }
2028
2029 if event != UpdateApplied::None {
2030 self.current_generation.properties += 1;
2031 }
2032
2033 let mut property_watchers = HashMap::new();
2034 std::mem::swap(&mut self.property_watchers, &mut property_watchers);
2035
2036 match event {
2038 UpdateApplied::NetworkChanged { network_id, added: true, .. } => {
2039 let _ = self
2040 .tokens
2041 .ensure_token(NetworkTokenContents { network_id, is_default: false });
2042 }
2043 UpdateApplied::NetworkRemoved(network_id) => {
2044 info!("Removing network {network_id}. Reporting NETWORK_GONE to watchers.");
2045 for (id, registration) in property_watchers.iter_mut() {
2049 if let Ok(network) = self.tokens.get_contents(®istration.token) {
2050 if network.network_id == network_id {
2051 let _: Option<_> = self.generations_by_connection.remove_properties(id);
2052 if let Some(responder) = registration.responder.take() {
2053 if let Err(e) = responder
2054 .send(Err(fnp_properties::PropertyWatcherError::NetworkGone))
2055 {
2056 warn!("Could not send to responder: {e}");
2057 }
2058 registration.close(None);
2059 }
2060 }
2061 }
2062 }
2063 self.tokens.drop_if(|c| !c.is_default && c.network_id == network_id);
2064 }
2065 UpdateApplied::NetworkChanged { added: false, .. }
2066 | UpdateApplied::DnsChanged
2067 | UpdateApplied::None => {}
2068 }
2069
2070 if let Some(DefaultChangedEvent { previous_default }) = default_changed {
2072 self.notify_default_network_changed(previous_default, &mut property_watchers).await;
2073 std::mem::swap(&mut self.property_watchers, &mut property_watchers);
2074 self.maybe_notify_watchers();
2075 return;
2076 }
2077
2078 if let UpdateApplied::NetworkChanged { network_id, .. } = event {
2079 if let Some(telemetry) = &self.telemetry {
2080 if let Some(props) = self.network_registry.networks.get(&network_id) {
2081 telemetry.send(TelemetryEvent::NetworkChanged(NetworkEventMetadata {
2082 id: network_id.get().get(),
2083 name: props.name.clone(),
2084 transport: props
2085 .network_type
2086 .unwrap_or(fnp_socketproxy::NetworkType::Unknown),
2087 is_fuchsia_provisioned: network_id.is_fuchsia(),
2088 connectivity_state: props.connectivity_state,
2089 }));
2090 }
2091 }
2092 }
2093
2094 for (id, mut registration) in property_watchers {
2095 let mut updates = fnp_properties::PropertyUpdate::default();
2096 match self.tokens.get_contents(®istration.token) {
2097 Ok(network) => match event {
2098 UpdateApplied::NetworkChanged {
2099 network_id,
2100 changed_marks,
2101 changed_dns,
2102 ..
2103 } => {
2104 if network.network_id == network_id {
2105 if changed_marks {
2106 updates.add_socket_marks(
2107 &self.network_registry,
2108 &network,
2109 registration.properties,
2110 );
2111 }
2112 if changed_dns {
2113 updates.add_dns(
2114 &self.network_registry,
2115 &network,
2116 registration.properties,
2117 );
2118 }
2119 }
2120 }
2121 UpdateApplied::DnsChanged => {
2122 updates.add_dns(&self.network_registry, &network, registration.properties);
2123 }
2124 UpdateApplied::NetworkRemoved(_id) => {}
2125 UpdateApplied::None => {}
2126 },
2127 Err(e) => {
2128 debug!(
2129 "Token {:?} not found for watcher {:?};
2130 network was likely removed while idle ({})",
2131 registration.token, id, e
2132 );
2133 }
2134 }
2135
2136 let has_updates = updates != fnp_properties::PropertyUpdate::default();
2139 if self.generations_by_connection.properties(&id).is_some() {
2140 match (has_updates, registration.responder.take()) {
2141 (true, Some(responder)) => {
2142 self.generations_by_connection.set_properties(id, self.current_generation);
2144 if let Err(e) = responder.send(Ok(&updates)) {
2145 warn!("Failed to send watch updates: {}", e);
2146 }
2147 }
2148 (false, maybe_responder) => {
2149 self.generations_by_connection.set_properties(id, self.current_generation);
2151 registration.responder = maybe_responder;
2152 }
2153 (true, None) => {
2154 }
2158 }
2159 }
2160
2161 assert_matches!(
2162 self.property_watchers.insert(id, registration),
2163 None,
2164 "Re-inserted in an existing registration slot."
2165 );
2166 }
2167 self.maybe_notify_watchers();
2168 }
2169
2170 async fn notify_default_network_changed(
2171 &mut self,
2172 old_default: Option<NetworkId>,
2173 property_watchers: &mut HashMap<PropertyWatcherConnectionId, Registration>,
2174 ) {
2175 self.changed_default_network(old_default, property_watchers).await;
2176 let default_network = self.network_registry.default_network;
2177 if let Some(telemetry) = &self.telemetry {
2178 match default_network {
2179 Some(default_network) => {
2180 if let Some(props) = self.network_registry.networks.get(&default_network) {
2181 telemetry.send(TelemetryEvent::DefaultNetworkChanged(
2182 NetworkEventMetadata {
2183 id: default_network.get().get(),
2184 name: props.name.clone(),
2185 transport: props
2186 .network_type
2187 .unwrap_or(fnp_socketproxy::NetworkType::Unknown),
2188 is_fuchsia_provisioned: default_network.is_fuchsia(),
2189 connectivity_state: props.connectivity_state,
2190 },
2191 ));
2192 } else {
2193 warn!("Could not fetch network data for default network.");
2194 }
2195 }
2196 None => telemetry.send(TelemetryEvent::DefaultNetworkLost),
2197 }
2198 }
2199 self.current_generation.default_network += 1;
2200 let responders = self
2203 .networks_clients
2204 .iter_mut()
2205 .filter_map(|(id, client)| client.responder.take().map(|responder| (*id, responder)));
2206 for (id, responder) in responders {
2207 self.generations_by_connection.set_default_network(id, self.current_generation);
2208 let response = match default_network {
2209 Some(network_id) => {
2210 match self
2211 .tokens
2212 .ensure_token(NetworkTokenContents { network_id, is_default: true })
2213 .get()
2214 .duplicate()
2215 {
2216 Ok(token) => fnp_properties::NetworksWatchDefaultResponse::Network(token),
2217 Err(e) => {
2218 warn!("Could not duplicate token: {e}");
2219 continue;
2220 }
2221 }
2222 }
2223 None => fnp_properties::NetworksWatchDefaultResponse::NoDefaultNetwork(
2224 fnp_properties::Empty,
2225 ),
2226 };
2227 if let Err(e) = responder.send(response) {
2228 warn!("Could not send to responder: {e}");
2229 }
2230 }
2231 }
2232}
2233
2234#[cfg(test)]
2235mod tests {
2236 use super::*;
2237 use assert_matches::assert_matches;
2238 use diagnostics_assertions::assert_data_tree;
2239 use fnp_socketproxy::{
2240 NetworkInfo, NetworkRegistryAddError, NetworkRegistryMarker, NetworkRegistryRemoveError,
2241 NetworkRegistrySetDefaultError, NetworkRegistryUpdateError, StarnixNetworkInfo,
2242 };
2243 use futures::FutureExt as _;
2244 use std::num::NonZeroU64;
2245 use test_case::test_case;
2246
2247 const ID_1: InterfaceId = InterfaceId(NonZeroU64::new(1).unwrap());
2248 const ID_2: InterfaceId = InterfaceId(NonZeroU64::new(2).unwrap());
2249 const NAME_1: &str = "testif1";
2250 const NAME_2: &str = "testif2";
2251
2252 const FUCHSIA_ID_1: NetworkId = NetworkId::Fuchsia(ID_1);
2253 const FUCHSIA_ID_2: NetworkId = NetworkId::Fuchsia(ID_2);
2254 const DELEGATED_ID_1: NetworkId = NetworkId::Delegated(ID_1);
2255 const DELEGATED_ID_2: NetworkId = NetworkId::Delegated(ID_2);
2256
2257 #[derive(Clone, Copy)]
2258 struct TestNetwork {
2259 id: NetworkId,
2260 name: &'static str,
2261 network_type: fnp_socketproxy::NetworkType,
2262 }
2263
2264 #[derive(Default)]
2265 struct AppliedChanges {
2266 added: bool,
2267 changed_marks: bool,
2268 changed_dns: bool,
2269 }
2270
2271 impl TestNetwork {
2272 fn added(&self, added: bool) -> NetworkPropertiesChange {
2273 NetworkPropertiesChange {
2274 added,
2275 name: Some(self.name.to_string()),
2276 network_type: Some(self.network_type),
2277 ..Default::default()
2278 }
2279 }
2280
2281 fn change_with(
2282 &self,
2283 added: bool,
2284 marks: Option<fnet::Marks>,
2285 dns_servers: Option<Vec<fnet_name::DnsServer_>>,
2286 connectivity_state: Option<fnp_socketproxy::ConnectivityState>,
2287 ) -> NetworkPropertiesChange {
2288 NetworkPropertiesChange {
2289 added,
2290 marks,
2291 dns_servers,
2292 connectivity_state,
2293 name: Some(self.name.to_string()),
2294 network_type: Some(self.network_type),
2295 }
2296 }
2297
2298 fn applied(&self, changes: AppliedChanges) -> UpdateApplied {
2299 let AppliedChanges { added, changed_marks, changed_dns } = changes;
2300 UpdateApplied::NetworkChanged {
2301 network_id: self.id,
2302 added,
2303 changed_marks,
2304 changed_dns,
2305 name: Some(self.name.to_string()),
2306 network_type: Some(self.network_type),
2307 }
2308 }
2309 }
2310
2311 const DELEGATED_NET_1: TestNetwork = TestNetwork {
2312 id: DELEGATED_ID_1,
2313 name: NAME_1,
2314 network_type: fnp_socketproxy::NetworkType::Ethernet,
2315 };
2316 const FUCHSIA_NET_1: TestNetwork = TestNetwork {
2317 id: FUCHSIA_ID_1,
2318 name: NAME_1,
2319 network_type: fnp_socketproxy::NetworkType::Ethernet,
2320 };
2321 const FUCHSIA_NET_2: TestNetwork = TestNetwork {
2322 id: FUCHSIA_ID_2,
2323 name: NAME_2,
2324 network_type: fnp_socketproxy::NetworkType::Wifi,
2325 };
2326
2327 fn test_marks() -> fnet::Marks {
2328 fnet::Marks { mark_1: Some(123), ..Default::default() }
2329 }
2330
2331 fn test_marks_updated() -> fnet::Marks {
2332 fnet::Marks { mark_1: Some(456), ..Default::default() }
2333 }
2334
2335 fn test_dns_1() -> Vec<fnet_name::DnsServer_> {
2336 vec![fnet_name::DnsServer_ {
2337 address: Some(net_declare::fidl_socket_addr!("192.0.2.1:53")),
2338 ..Default::default()
2339 }]
2340 }
2341
2342 fn test_dns_2() -> Vec<fnet_name::DnsServer_> {
2343 vec![fnet_name::DnsServer_ {
2344 address: Some(net_declare::fidl_socket_addr!("192.0.2.2:53")),
2345 ..Default::default()
2346 }]
2347 }
2348
2349 fn delegated_properties() -> NetworkProperties {
2350 NetworkProperties { socket_marks: Some(test_marks()), ..Default::default() }
2351 }
2352
2353 fn fuchsia_properties() -> NetworkProperties {
2354 NetworkProperties::default()
2355 }
2356
2357 fn added_properties(name: &str) -> NetworkPropertiesChange {
2358 NetworkPropertiesChange {
2359 added: true,
2360 marks: None,
2361 dns_servers: None,
2362 connectivity_state: None,
2363 name: Some(name.to_string()),
2364 network_type: Some(fnp_socketproxy::NetworkType::Ethernet),
2365 }
2366 }
2367
2368 impl NetpolNetworksService {
2369 pub(crate) fn default_network(&self) -> Option<NetworkId> {
2370 self.network_registry.default_network
2371 }
2372
2373 pub(crate) fn has_network(&self, id: NetworkId) -> bool {
2374 self.network_registry.networks.contains_key(&id)
2375 }
2376
2377 pub(crate) fn has_token(&self, network_id: NetworkId, is_default: bool) -> bool {
2378 self.tokens.get_token(&NetworkTokenContents { network_id, is_default }).is_some()
2379 }
2380
2381 pub(crate) fn ensure_token_for_test(&mut self, network_id: NetworkId, is_default: bool) {
2382 let _token: crate::network::token_registry::TokenEntry<'_, _> =
2383 self.tokens.ensure_token(NetworkTokenContents { network_id, is_default });
2384 }
2385 }
2386
2387 #[test_case(
2388 DELEGATED_NET_1,
2389 Some(test_marks()),
2390 Some(test_marks_updated()); "delegated network"
2391 )]
2392 #[test_case(FUCHSIA_NET_2, None, None; "fuchsia network")]
2393 fn test_handle_changed_network(
2394 net: TestNetwork,
2395 initial_marks: Option<fnet::Marks>,
2396 updated_marks: Option<fnet::Marks>,
2397 ) {
2398 let mut networks = RegisteredNetworks::default();
2399 let dns1 = test_dns_1();
2400 let dns2 = test_dns_2();
2401
2402 let event = net.change_with(
2404 true,
2405 initial_marks.clone(),
2406 Some(dns1.clone()),
2407 Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
2408 );
2409 assert_eq!(
2410 networks.handle_changed_network(net.id, event),
2411 net.applied(AppliedChanges { added: true, changed_marks: true, changed_dns: true }),
2412 );
2413 assert_eq!(
2414 networks.networks.get(&net.id).expect("network should be present"),
2415 &NetworkProperties {
2416 socket_marks: initial_marks.clone(),
2417 dns_servers: dns1,
2418 connectivity_state: Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
2419 name: Some(net.name.to_string()),
2420 network_type: Some(net.network_type),
2421 }
2422 );
2423
2424 let event = net.change_with(
2427 false,
2428 initial_marks.clone(),
2429 Some(dns2.clone()),
2430 Some(fnp_socketproxy::ConnectivityState::NoConnectivity),
2431 );
2432 assert_eq!(
2433 networks.handle_changed_network(net.id, event),
2434 net.applied(AppliedChanges { added: false, changed_marks: false, changed_dns: true }),
2435 );
2436 assert_eq!(
2437 networks.networks.get(&net.id).expect("network should be present"),
2438 &NetworkProperties {
2439 socket_marks: initial_marks.clone(),
2440 dns_servers: dns2.clone(),
2441 connectivity_state: Some(fnp_socketproxy::ConnectivityState::NoConnectivity),
2442 name: Some(net.name.to_string()),
2443 network_type: Some(net.network_type),
2444 }
2445 );
2446
2447 let marks_changed = initial_marks != updated_marks;
2449 let event = net.change_with(
2450 false,
2451 updated_marks.clone(),
2452 Some(dns2.clone()),
2453 Some(fnp_socketproxy::ConnectivityState::NoConnectivity),
2454 );
2455 assert_eq!(
2456 networks.handle_changed_network(net.id, event),
2457 net.applied(AppliedChanges {
2458 added: false,
2459 changed_marks: marks_changed,
2460 changed_dns: false,
2461 }),
2462 );
2463 assert_eq!(
2464 networks.networks.get(&net.id).expect("network should be present"),
2465 &NetworkProperties {
2466 socket_marks: updated_marks,
2467 dns_servers: dns2,
2468 connectivity_state: Some(fnp_socketproxy::ConnectivityState::NoConnectivity),
2469 name: Some(net.name.to_string()),
2470 network_type: Some(net.network_type),
2471 }
2472 );
2473 }
2474
2475 #[test]
2476 fn test_handle_changed_network_validation() {
2477 let mut networks = RegisteredNetworks::default();
2478 let marks = test_marks();
2479 let net = DELEGATED_NET_1;
2480
2481 let event = NetworkPropertiesChange { marks: Some(marks.clone()), ..net.added(false) };
2483 assert_eq!(networks.handle_changed_network(net.id, event), UpdateApplied::None);
2484
2485 let event = NetworkPropertiesChange { marks: Some(marks.clone()), ..net.added(true) };
2487
2488 assert_eq!(
2489 networks.handle_changed_network(net.id, event),
2490 net.applied(AppliedChanges { added: true, changed_marks: true, changed_dns: true }),
2491 );
2492
2493 let event = NetworkPropertiesChange { marks: Some(marks.clone()), ..net.added(true) };
2495 assert_eq!(networks.handle_changed_network(net.id, event), UpdateApplied::None);
2496
2497 let fuchsia_net = FUCHSIA_NET_1;
2499 let event =
2500 NetworkPropertiesChange { marks: Some(marks.clone()), ..fuchsia_net.added(true) };
2501 assert_eq!(networks.handle_changed_network(fuchsia_net.id, event), UpdateApplied::None);
2502
2503 let event = net.added(true);
2505 assert_eq!(networks.handle_changed_network(net.id, event), UpdateApplied::None);
2506 }
2507
2508 #[test]
2511 fn fallback_election_and_prioritization() {
2512 let mut networks = RegisteredNetworks::default();
2513
2514 assert_eq!(networks.calculate_active_default(), None);
2516
2517 let _ = networks.networks.insert(DELEGATED_ID_1, delegated_properties());
2519 networks.starnix_default = Some(DELEGATED_ID_1);
2520 assert_eq!(
2521 networks.handle_default_network_update(),
2522 Some(DefaultChangedEvent { previous_default: None })
2523 );
2524 assert_eq!(networks.default_network, Some(DELEGATED_ID_1));
2525
2526 let _ = networks.networks.insert(DELEGATED_ID_2, delegated_properties());
2529 networks.starnix_default = Some(DELEGATED_ID_2);
2530 assert_eq!(
2531 networks.handle_default_network_update(),
2532 Some(DefaultChangedEvent { previous_default: Some(DELEGATED_ID_1) })
2533 );
2534 assert_eq!(networks.default_network, Some(DELEGATED_ID_2));
2535
2536 let _ = networks.networks.insert(FUCHSIA_ID_2, fuchsia_properties());
2539 assert_eq!(
2540 networks.handle_default_network_update(),
2541 Some(DefaultChangedEvent { previous_default: Some(DELEGATED_ID_2) })
2542 );
2543 assert_eq!(networks.default_network, Some(FUCHSIA_ID_2));
2544
2545 let _ = networks.networks.insert(FUCHSIA_ID_1, fuchsia_properties());
2548 assert_eq!(
2549 networks.handle_default_network_update(),
2550 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_2) })
2551 );
2552 assert_eq!(networks.default_network, Some(FUCHSIA_ID_1));
2553
2554 let _ = networks.networks.remove(&FUCHSIA_ID_1);
2556 assert_eq!(
2557 networks.handle_default_network_update(),
2558 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_1) })
2559 );
2560 assert_eq!(networks.default_network, Some(FUCHSIA_ID_2));
2561
2562 let _ = networks.networks.remove(&FUCHSIA_ID_2);
2565 assert_eq!(
2566 networks.handle_default_network_update(),
2567 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_2) })
2568 );
2569 assert_eq!(networks.default_network, Some(DELEGATED_ID_2));
2570
2571 assert_eq!(
2573 networks.apply(NetworkRegistryUpdate::UnsetDefaultNetwork),
2574 RegistryUpdateResult {
2575 event: UpdateApplied::None,
2576 default_changed: Some(DefaultChangedEvent {
2577 previous_default: Some(DELEGATED_ID_2)
2578 })
2579 }
2580 );
2581 assert_eq!(networks.default_network, None);
2582
2583 assert_eq!(
2585 networks
2586 .apply(NetworkRegistryUpdate::ChangeNetwork(DELEGATED_ID_1, NetworkUpdate::Remove)),
2587 RegistryUpdateResult {
2588 event: UpdateApplied::NetworkRemoved(DELEGATED_ID_1),
2589 default_changed: None
2590 }
2591 );
2592 }
2593
2594 #[test]
2598 fn test_remove_fuchsia_network_fallback() {
2599 let mut networks = RegisteredNetworks::default();
2600 let marks = test_marks();
2601 let fuchsia_added = NetworkPropertiesChange { added: true, ..Default::default() };
2602
2603 let result = networks.apply(NetworkRegistryUpdate::ChangeNetwork(
2605 FUCHSIA_ID_1,
2606 NetworkUpdate::Properties(fuchsia_added.clone()),
2607 ));
2608 assert_matches!(
2609 result.event,
2610 UpdateApplied::NetworkChanged { network_id: id, added: true, .. }
2611 if id == FUCHSIA_ID_1
2612 );
2613 assert_eq!(result.default_changed, Some(DefaultChangedEvent { previous_default: None }));
2614
2615 let result = networks.apply(NetworkRegistryUpdate::ChangeNetwork(
2617 FUCHSIA_ID_2,
2618 NetworkUpdate::Properties(fuchsia_added),
2619 ));
2620 assert_matches!(
2621 result.event,
2622 UpdateApplied::NetworkChanged { network_id: id, added: true, .. }
2623 if id == FUCHSIA_ID_2
2624 );
2625 assert_eq!(result.default_changed, None);
2626
2627 let result = networks.apply(NetworkRegistryUpdate::ChangeNetwork(
2629 DELEGATED_ID_1,
2630 NetworkUpdate::Properties(NetworkPropertiesChange {
2631 added: true,
2632 marks: Some(marks),
2633 ..Default::default()
2634 }),
2635 ));
2636 assert_matches!(
2637 result.event,
2638 UpdateApplied::NetworkChanged { network_id: id, added: true, .. }
2639 if id == DELEGATED_ID_1
2640 );
2641 assert_eq!(result.default_changed, None);
2642
2643 let result = networks.apply(NetworkRegistryUpdate::ChangeNetwork(
2646 DELEGATED_ID_1,
2647 NetworkUpdate::MakeDefault,
2648 ));
2649 assert_eq!(
2650 result,
2651 RegistryUpdateResult { event: UpdateApplied::None, default_changed: None }
2652 );
2653 assert_eq!(networks.default_network, Some(FUCHSIA_ID_1));
2654
2655 let result = networks
2658 .apply(NetworkRegistryUpdate::ChangeNetwork(FUCHSIA_ID_1, NetworkUpdate::Remove));
2659 assert_eq!(result.event, UpdateApplied::NetworkRemoved(FUCHSIA_ID_1));
2660 assert_eq!(
2661 result.default_changed,
2662 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_1) })
2663 );
2664 assert_eq!(networks.default_network, Some(FUCHSIA_ID_2));
2665
2666 let result = networks
2669 .apply(NetworkRegistryUpdate::ChangeNetwork(FUCHSIA_ID_2, NetworkUpdate::Remove));
2670 assert_eq!(result.event, UpdateApplied::NetworkRemoved(FUCHSIA_ID_2));
2671 assert_eq!(
2672 result.default_changed,
2673 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_2) })
2674 );
2675 assert_eq!(networks.default_network, Some(DELEGATED_ID_1));
2676
2677 let result = networks
2679 .apply(NetworkRegistryUpdate::ChangeNetwork(DELEGATED_ID_1, NetworkUpdate::Remove));
2680 assert_eq!(
2681 result,
2682 RegistryUpdateResult { event: UpdateApplied::None, default_changed: None }
2683 );
2684 assert!(networks.networks.contains_key(&DELEGATED_ID_1));
2685 assert_eq!(networks.default_network, Some(DELEGATED_ID_1));
2686 }
2687
2688 #[test]
2689 fn remove_non_default_fuchsia_preserves_default() {
2690 let mut networks = RegisteredNetworks::default();
2691
2692 let _ = networks.networks.insert(FUCHSIA_ID_1, NetworkProperties::default());
2694 let _ = networks.networks.insert(FUCHSIA_ID_2, NetworkProperties::default());
2695
2696 assert_eq!(
2698 networks.handle_default_network_update(),
2699 Some(DefaultChangedEvent { previous_default: None })
2700 );
2701 assert_eq!(networks.default_network, Some(FUCHSIA_ID_1));
2702
2703 assert_eq!(
2705 networks
2706 .apply(NetworkRegistryUpdate::ChangeNetwork(FUCHSIA_ID_2, NetworkUpdate::Remove)),
2707 RegistryUpdateResult {
2708 event: UpdateApplied::NetworkRemoved(FUCHSIA_ID_2),
2709 default_changed: None
2710 }
2711 );
2712
2713 assert_eq!(networks.default_network, Some(FUCHSIA_ID_1));
2715 }
2716
2717 #[fuchsia::test]
2718 async fn remove_default_network_cleans_up_tokens() {
2719 let mut service = NetpolNetworksService::default();
2720
2721 service
2723 .update(NetworkRegistryUpdate::ChangeNetwork(
2724 FUCHSIA_ID_1,
2725 NetworkUpdate::Properties(added_properties(NAME_1)),
2726 ))
2727 .await;
2728
2729 service
2730 .update(NetworkRegistryUpdate::ChangeNetwork(
2731 FUCHSIA_ID_2,
2732 NetworkUpdate::Properties(added_properties(NAME_2)),
2733 ))
2734 .await;
2735
2736 assert_eq!(service.default_network(), Some(FUCHSIA_ID_1));
2738
2739 assert!(service.has_token(FUCHSIA_ID_1, false ));
2741 assert!(service.has_token(FUCHSIA_ID_2, false ));
2742
2743 service.ensure_token_for_test(FUCHSIA_ID_1, true );
2745 assert!(service.has_token(FUCHSIA_ID_1, true ));
2746
2747 service
2750 .update(NetworkRegistryUpdate::ChangeNetwork(FUCHSIA_ID_1, NetworkUpdate::Remove))
2751 .await;
2752
2753 assert_eq!(service.default_network(), Some(FUCHSIA_ID_2));
2755
2756 assert!(!service.has_token(FUCHSIA_ID_1, false ));
2758 assert!(!service.has_token(FUCHSIA_ID_1, true ));
2759
2760 assert!(service.has_token(FUCHSIA_ID_2, false ));
2762 }
2763
2764 #[fuchsia::test]
2765 async fn test_property_watcher_generation_increment_on_unpolled_update() {
2766 let mut service = NetpolNetworksService::default();
2767
2768 service
2770 .update(NetworkRegistryUpdate::ChangeNetwork(
2771 DELEGATED_ID_1,
2772 NetworkUpdate::Properties(DELEGATED_NET_1.change_with(
2773 true,
2774 Some(test_marks()),
2775 None,
2776 None,
2777 )),
2778 ))
2779 .await;
2780
2781 let token = service
2782 .tokens
2783 .ensure_token(NetworkTokenContents { network_id: DELEGATED_ID_1, is_default: false })
2784 .get()
2785 .duplicate()
2786 .unwrap();
2787
2788 let (watcher, server_end) =
2789 fidl::endpoints::create_proxy::<fnp_properties::PropertyWatcherMarker>();
2790 let (networks_proxy, networks_stream) =
2791 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
2792
2793 service.add_stream(networks_stream);
2794
2795 let request = fnp_properties::NetworksWatchPropertiesRequest {
2797 network: Some(token),
2798 properties: Some(fnp_properties::PropertyInterest::SOCKET_MARKS),
2799 watcher: Some(server_end),
2800 ..Default::default()
2801 };
2802
2803 let watch_req = networks_proxy.watch_properties(request);
2804 let req_event = service.select_next_some().await;
2805 assert_eq!(
2806 service.handle_event(req_event).await.expect("Failed to handle event"),
2807 DelegatedNetworkUpdateResult::default()
2808 );
2809 assert_matches!(watch_req.await, Ok(Ok(())));
2810
2811 let watch_fut1 = watcher.watch();
2813 let pw_event1 = service.select_next_some().await;
2814 assert_eq!(
2815 service.handle_event(pw_event1).await.expect("Failed to handle event"),
2816 DelegatedNetworkUpdateResult::default()
2817 );
2818 let initial_updates = watch_fut1.await.unwrap().unwrap();
2819 assert_eq!(
2820 initial_updates,
2821 fnp_properties::PropertyUpdate {
2822 socket_marks: Some(test_marks()),
2823 dns_configuration: None,
2824 ..Default::default()
2825 }
2826 );
2827
2828 service
2831 .update(NetworkRegistryUpdate::ChangeNetwork(
2832 DELEGATED_ID_1,
2833 NetworkUpdate::Properties(DELEGATED_NET_1.change_with(
2834 false,
2835 Some(test_marks_updated()),
2836 None,
2837 None,
2838 )),
2839 ))
2840 .await;
2841
2842 let watch_fut2 = watcher.watch();
2844 let pw_event2 = service.select_next_some().await;
2845 assert_eq!(
2846 service.handle_event(pw_event2).await.expect("Failed to handle event"),
2847 DelegatedNetworkUpdateResult::default()
2848 );
2849 let updates = watch_fut2.await.unwrap().unwrap();
2850 assert_eq!(
2851 updates,
2852 fnp_properties::PropertyUpdate {
2853 socket_marks: Some(test_marks_updated()),
2854 dns_configuration: None,
2855 ..Default::default()
2856 }
2857 );
2858 }
2859
2860 #[fuchsia::test]
2861 async fn test_watch_should_return_error_on_concurrent_call() {
2862 let mut service = NetpolNetworksService::default();
2863
2864 let token = service
2865 .tokens
2866 .ensure_token(NetworkTokenContents { network_id: DELEGATED_ID_1, is_default: false })
2867 .get()
2868 .duplicate()
2869 .unwrap();
2870
2871 let (watcher, server_end) =
2872 fidl::endpoints::create_proxy::<fnp_properties::PropertyWatcherMarker>();
2873 let (networks_proxy, networks_stream) =
2874 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
2875
2876 service.add_stream(networks_stream);
2877
2878 let watch_req =
2879 networks_proxy.watch_properties(fnp_properties::NetworksWatchPropertiesRequest {
2880 network: Some(token),
2881 properties: Some(fnp_properties::PropertyInterest::SOCKET_MARKS),
2882 watcher: Some(server_end),
2883 ..Default::default()
2884 });
2885 let req_event = service.select_next_some().await;
2886 assert_eq!(
2887 service.handle_event(req_event).await.expect("Failed to handle event"),
2888 DelegatedNetworkUpdateResult::default()
2889 );
2890 assert_matches!(watch_req.await, Ok(Ok(())));
2891
2892 let watch_fut1 = watcher.watch();
2894 let pw_event1 = service.select_next_some().await;
2895 assert_eq!(
2896 service.handle_event(pw_event1).await.expect("Failed to handle event"),
2897 DelegatedNetworkUpdateResult::default()
2898 );
2899
2900 let watch_fut2 = watcher.watch();
2901 let pw_event2 = service.select_next_some().await;
2902 assert_eq!(
2903 service.handle_event(pw_event2).await.expect("Failed to handle event"),
2904 DelegatedNetworkUpdateResult::default()
2905 );
2906
2907 for res in [watch_fut1.await, watch_fut2.await] {
2908 assert_matches!(
2909 res,
2910 Err(fidl::Error::ClientChannelClosed { epitaph, .. })
2911 if epitaph == zx::Status::ALREADY_EXISTS
2912 );
2913 }
2914 let disconnect_event = service.select_next_some().await;
2916 assert_eq!(
2917 service.handle_event(disconnect_event).await.expect("Failed to handle event"),
2918 DelegatedNetworkUpdateResult::default()
2919 );
2920 assert!(service.property_watchers.is_empty());
2921 }
2922
2923 #[fuchsia::test]
2924 async fn test_watch_default_should_return_error_on_concurrent_call() {
2925 let mut service = NetpolNetworksService::default();
2926
2927 let (networks_proxy, networks_stream) =
2928 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
2929
2930 service.add_stream(networks_stream);
2931
2932 let watch_fut1 = networks_proxy.watch_default();
2934 let req_event1 = service.select_next_some().await;
2935 assert_eq!(
2936 service.handle_event(req_event1).await.expect("Failed to handle event"),
2937 DelegatedNetworkUpdateResult::default()
2938 );
2939
2940 let watch_fut2 = networks_proxy.watch_default();
2941 let req_event2 = service.select_next_some().await;
2942 assert_eq!(
2943 service.handle_event(req_event2).await.expect("Failed to handle event"),
2944 DelegatedNetworkUpdateResult::default()
2945 );
2946
2947 for res in [watch_fut1.await, watch_fut2.await] {
2948 assert_matches!(
2949 res,
2950 Err(fidl::Error::ClientChannelClosed { epitaph, .. })
2951 if epitaph == zx::Status::ALREADY_EXISTS
2952 );
2953 }
2954 let disconnect_event = service.select_next_some().await;
2956 assert_eq!(
2957 service.handle_event(disconnect_event).await.expect("Failed to handle event"),
2958 DelegatedNetworkUpdateResult::default()
2959 );
2960 assert!(service.networks_clients.is_empty());
2961 }
2962
2963 #[fuchsia::test]
2964 async fn test_network_removal_reports_network_gone() {
2965 let mut service = NetpolNetworksService::default();
2966
2967 service
2968 .update(NetworkRegistryUpdate::ChangeNetwork(
2969 DELEGATED_ID_1,
2970 NetworkUpdate::Properties(DELEGATED_NET_1.change_with(
2971 true,
2972 Some(test_marks()),
2973 None,
2974 None,
2975 )),
2976 ))
2977 .await;
2978
2979 let token1 = service
2980 .tokens
2981 .ensure_token(NetworkTokenContents { network_id: DELEGATED_ID_1, is_default: false })
2982 .get()
2983 .duplicate()
2984 .unwrap();
2985 let token2 = service
2986 .tokens
2987 .ensure_token(NetworkTokenContents { network_id: DELEGATED_ID_1, is_default: false })
2988 .get()
2989 .duplicate()
2990 .unwrap();
2991
2992 let (active_watcher, active_server_end) =
2993 fidl::endpoints::create_proxy::<fnp_properties::PropertyWatcherMarker>();
2994 let (idle_watcher, idle_server_end) =
2995 fidl::endpoints::create_proxy::<fnp_properties::PropertyWatcherMarker>();
2996 let (networks_proxy, networks_stream) =
2997 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
2998
2999 service.add_stream(networks_stream);
3000
3001 for (token, server_end) in [(token1, active_server_end), (token2, idle_server_end)] {
3002 let watch_req =
3003 networks_proxy.watch_properties(fnp_properties::NetworksWatchPropertiesRequest {
3004 network: Some(token),
3005 properties: Some(fnp_properties::PropertyInterest::SOCKET_MARKS),
3006 watcher: Some(server_end),
3007 ..Default::default()
3008 });
3009 let req_event = service.select_next_some().await;
3010 assert_eq!(
3011 service.handle_event(req_event).await.expect("Failed to handle event"),
3012 DelegatedNetworkUpdateResult::default()
3013 );
3014 assert_matches!(watch_req.await, Ok(Ok(())));
3015 }
3016
3017 let active_watch_fut1 = active_watcher.watch();
3019 let active_pw_event1 = service.select_next_some().await;
3020 assert_eq!(
3021 service.handle_event(active_pw_event1).await.expect("Failed to handle event"),
3022 DelegatedNetworkUpdateResult::default()
3023 );
3024 let initial_updates = active_watch_fut1.await.unwrap().unwrap();
3025 assert_eq!(
3026 initial_updates,
3027 fnp_properties::PropertyUpdate {
3028 socket_marks: Some(test_marks()),
3029 dns_configuration: None,
3030 ..Default::default()
3031 }
3032 );
3033
3034 let mut active_watch_fut2 = active_watcher.watch();
3036 let active_pw_event2 = service.select_next_some().await;
3037 assert_eq!(
3038 service.handle_event(active_pw_event2).await.expect("Failed to handle event"),
3039 DelegatedNetworkUpdateResult::default()
3040 );
3041 assert_matches!((&mut active_watch_fut2).now_or_never(), None);
3042
3043 service
3045 .update(NetworkRegistryUpdate::ChangeNetwork(DELEGATED_ID_1, NetworkUpdate::Remove))
3046 .await;
3047
3048 assert_matches!(
3051 active_watch_fut2.await,
3052 Ok(Err(fnp_properties::PropertyWatcherError::NetworkGone))
3053 );
3054 let active_closed_event = service.select_next_some().await;
3055 assert_eq!(
3056 service.handle_event(active_closed_event).await.expect("Failed to handle event"),
3057 DelegatedNetworkUpdateResult::default()
3058 );
3059
3060 let idle_watch_fut = idle_watcher.watch();
3062 let idle_pw_event = service.select_next_some().await;
3063 assert_eq!(
3064 service.handle_event(idle_pw_event).await.expect("Failed to handle event"),
3065 DelegatedNetworkUpdateResult::default()
3066 );
3067 assert_matches!(
3068 idle_watch_fut.await,
3069 Ok(Err(fnp_properties::PropertyWatcherError::NetworkGone))
3070 );
3071 }
3072
3073 #[fuchsia::test]
3074 async fn test_idle_default_watcher_reports_network_gone_on_default_change() {
3075 let mut service = NetpolNetworksService::default();
3076
3077 service
3079 .update(NetworkRegistryUpdate::ChangeNetwork(
3080 DELEGATED_ID_1,
3081 NetworkUpdate::Properties(DELEGATED_NET_1.change_with(
3082 true,
3083 Some(test_marks()),
3084 None,
3085 None,
3086 )),
3087 ))
3088 .await;
3089 service
3090 .update(NetworkRegistryUpdate::ChangeNetwork(
3091 DELEGATED_ID_1,
3092 NetworkUpdate::MakeDefault,
3093 ))
3094 .await;
3095
3096 let (networks_proxy, networks_stream) =
3097 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
3098 service.add_stream(networks_stream);
3099
3100 let default_fut = networks_proxy.watch_default();
3102 let req_event = service.select_next_some().await;
3103 assert_eq!(
3104 service.handle_event(req_event).await.expect("Failed to handle event"),
3105 DelegatedNetworkUpdateResult::default()
3106 );
3107 let default_token = match default_fut.await.unwrap() {
3108 fnp_properties::NetworksWatchDefaultResponse::Network(token) => token,
3109 res => panic!("Expected Network token, got {res:?}"),
3110 };
3111
3112 let (watcher, server_end) =
3114 fidl::endpoints::create_proxy::<fnp_properties::PropertyWatcherMarker>();
3115 let watch_req =
3116 networks_proxy.watch_properties(fnp_properties::NetworksWatchPropertiesRequest {
3117 network: Some(default_token),
3118 properties: Some(fnp_properties::PropertyInterest::SOCKET_MARKS),
3119 watcher: Some(server_end),
3120 ..Default::default()
3121 });
3122 let req_event = service.select_next_some().await;
3123 assert_eq!(
3124 service.handle_event(req_event).await.expect("Failed to handle event"),
3125 DelegatedNetworkUpdateResult::default()
3126 );
3127 assert_matches!(watch_req.await, Ok(Ok(())));
3128
3129 let initial_fut = watcher.watch();
3131 let pw_event = service.select_next_some().await;
3132 assert_eq!(
3133 service.handle_event(pw_event).await.expect("Failed to handle event"),
3134 DelegatedNetworkUpdateResult::default()
3135 );
3136 assert_matches!(initial_fut.await, Ok(Ok(_)));
3137
3138 service.update(NetworkRegistryUpdate::unset_default()).await;
3140
3141 let idle_watch_fut = watcher.watch();
3143 let idle_pw_event = service.select_next_some().await;
3144 assert_eq!(
3145 service.handle_event(idle_pw_event).await.expect("Failed to handle event"),
3146 DelegatedNetworkUpdateResult::default()
3147 );
3148 assert_matches!(
3149 idle_watch_fut.await,
3150 Ok(Err(fnp_properties::PropertyWatcherError::NetworkGone))
3151 );
3152 }
3153
3154 #[test_case(
3155 None,
3156 Some(fnp_socketproxy::NetworkInfo::Starnix(
3157 fnp_socketproxy::StarnixNetworkInfo {
3158 mark: Some(123),
3159 ..Default::default()
3160 }
3161 )),
3162 Err(NetworkValidationError::MissingNetworkId);
3163 "missing network_id"
3164 )]
3165 #[test_case(
3166 Some(0),
3167 Some(fnp_socketproxy::NetworkInfo::Starnix(
3168 fnp_socketproxy::StarnixNetworkInfo {
3169 mark: Some(123),
3170 ..Default::default()
3171 }
3172 )),
3173 Err(NetworkValidationError::MissingNetworkId);
3174 "zero network_id"
3175 )]
3176 #[test_case(
3177 Some(1),
3178 None,
3179 Err(NetworkValidationError::MissingNetworkInfo);
3180 "missing network_info"
3181 )]
3182 #[test_case(
3183 Some(1),
3184 Some(fnp_socketproxy::NetworkInfo::Fuchsia(Default::default())),
3185 Err(NetworkValidationError::MissingNetworkInfo);
3186 "fuchsia network_info"
3187 )]
3188 #[test_case(
3189 Some(1),
3190 Some(fnp_socketproxy::NetworkInfo::Starnix(
3191 fnp_socketproxy::StarnixNetworkInfo {
3192 mark: Some(123),
3193 ..Default::default()
3194 }
3195 )),
3196 Ok(NetworkId::delegated(InterfaceId::new(1).unwrap()));
3197 "valid starnix network"
3198 )]
3199 fn test_validated_network_validation(
3200 network_id: Option<u32>,
3201 info: Option<fnp_socketproxy::NetworkInfo>,
3202 expected: Result<NetworkId, NetworkValidationError>,
3203 ) {
3204 let net = fnp_socketproxy::Network { network_id, info, ..Default::default() };
3205 let result = ValidatedNetwork::try_from(net).map(|v| v.network_id);
3206 assert_eq!(result, expected);
3207 }
3208
3209 fn starnix_network_payload(id: u32, mark: u32) -> fnp_socketproxy::Network {
3210 fnp_socketproxy::Network {
3211 network_id: Some(id),
3212 info: Some(NetworkInfo::Starnix(StarnixNetworkInfo {
3213 mark: Some(mark),
3214 ..Default::default()
3215 })),
3216 ..Default::default()
3217 }
3218 }
3219
3220 async fn process_fidl_request<E>(
3221 service: &mut NetpolNetworksService,
3222 request_future: impl Future<Output = Result<Result<(), E>, fidl::Error>>,
3223 ) -> Result<(), E> {
3224 let event = service.select_next_some().await;
3225 let update_result = service.handle_event(event).await.expect("failed to handle event");
3226 let client_result = request_future.await.expect("FIDL call failed");
3227 assert_eq!(update_result.dns_servers.is_some(), client_result.is_ok());
3228 client_result
3229 }
3230
3231 #[fuchsia::test]
3232 async fn test_delegated_networks_fidl_errors() {
3233 let mut service = NetpolNetworksService::default();
3234 let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3235 service.add_stream(stream);
3236
3237 const NETWORK_ID_1: u32 = 1;
3238 const NETWORK_ID_2: u32 = 2;
3239 const SOCKET_MARK: u32 = 100;
3240
3241 assert_eq!(
3243 process_fidl_request(
3244 &mut service,
3245 proxy.update(&starnix_network_payload(NETWORK_ID_1, SOCKET_MARK,)),
3246 )
3247 .await,
3248 Err(NetworkRegistryUpdateError::NotFound)
3249 );
3250
3251 assert_eq!(
3253 process_fidl_request(
3254 &mut service,
3255 proxy.add(&starnix_network_payload(NETWORK_ID_1, SOCKET_MARK)),
3256 )
3257 .await,
3258 Ok(())
3259 );
3260
3261 assert_eq!(
3263 process_fidl_request(
3264 &mut service,
3265 proxy.add(&starnix_network_payload(NETWORK_ID_1, SOCKET_MARK)),
3266 )
3267 .await,
3268 Err(NetworkRegistryAddError::DuplicateNetworkId)
3269 );
3270
3271 assert_eq!(
3273 process_fidl_request(&mut service, proxy.remove(NETWORK_ID_2)).await,
3274 Err(NetworkRegistryRemoveError::NotFound)
3275 );
3276
3277 assert_eq!(
3279 process_fidl_request(
3280 &mut service,
3281 proxy.set_default(&fposix_socket::OptionalUint32::Value(NETWORK_ID_2,)),
3282 )
3283 .await,
3284 Err(NetworkRegistrySetDefaultError::NotFound)
3285 );
3286
3287 assert_eq!(
3289 process_fidl_request(
3290 &mut service,
3291 proxy.set_default(&fposix_socket::OptionalUint32::Value(NETWORK_ID_1,)),
3292 )
3293 .await,
3294 Ok(())
3295 );
3296
3297 assert_eq!(
3300 process_fidl_request(&mut service, proxy.remove(NETWORK_ID_1)).await,
3301 Err(NetworkRegistryRemoveError::CannotRemoveDefaultNetwork)
3302 );
3303
3304 assert_eq!(
3306 process_fidl_request(
3307 &mut service,
3308 proxy.set_default(&fposix_socket::OptionalUint32::Unset(fposix_socket::Empty)),
3309 )
3310 .await,
3311 Ok(())
3312 );
3313
3314 assert_eq!(process_fidl_request(&mut service, proxy.remove(NETWORK_ID_1)).await, Ok(()));
3316 }
3317
3318 #[fuchsia::test]
3319 async fn test_inspect_metrics() {
3320 let inspector = fuchsia_inspect::Inspector::default();
3321 let telemetry_node = inspector.root().create_child("telemetry");
3322 let mut service = NetpolNetworksService::default()
3323 .with_inspect(&telemetry_node, "operations", &telemetry_node, "network_registry")
3324 .expect("failed to initialize inspect");
3325 inspector.root().record(telemetry_node);
3326
3327 let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3328 service.add_stream(stream);
3329
3330 let make_network = |id: u32, mark: u32| fnp_socketproxy::Network {
3331 network_id: Some(id),
3332 info: Some(NetworkInfo::Starnix(StarnixNetworkInfo {
3333 mark: Some(mark),
3334 ..Default::default()
3335 })),
3336 name: Some("wlan0".to_string()),
3337 network_type: Some(fnp_socketproxy::NetworkType::Wifi),
3338 connectivity: Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
3339 ..Default::default()
3340 };
3341
3342 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3344 assert_data_tree!(
3345 hierarchy,
3346 root: contains {
3347 telemetry: contains {
3348 operations: contains {
3349 delegated: contains {
3350 adds: contains { successes: 0u64, errors: 0u64 },
3351 removes: contains { successes: 0u64, errors: 0u64 },
3352 set_defaults: contains {
3353 successes: 0u64,
3354 errors: 0u64,
3355 },
3356 updates: contains {
3357 successes: 0u64,
3358 errors: 0u64,
3359 },
3360 }
3361 }
3362 }
3363 }
3364 );
3365
3366 assert_eq!(
3368 process_fidl_request(&mut service, proxy.add(&make_network(1, 100))).await,
3369 Ok(())
3370 );
3371
3372 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3373 assert_data_tree!(
3374 hierarchy,
3375 root: contains {
3376 telemetry: contains {
3377 operations: contains {
3378 delegated: contains {
3379 adds: contains { successes: 1u64, errors: 0u64 },
3380 }
3381 }
3382 }
3383 }
3384 );
3385
3386 assert_eq!(
3388 process_fidl_request(&mut service, proxy.add(&make_network(1, 100))).await,
3389 Err(NetworkRegistryAddError::DuplicateNetworkId)
3390 );
3391
3392 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3393 assert_data_tree!(
3394 hierarchy,
3395 root: contains {
3396 telemetry: contains {
3397 operations: contains {
3398 delegated: contains {
3399 adds: contains { successes: 1u64, errors: 1u64 },
3400 }
3401 }
3402 }
3403 }
3404 );
3405
3406 assert_eq!(
3408 process_fidl_request(&mut service, proxy.update(&make_network(1, 150))).await,
3409 Ok(())
3410 );
3411
3412 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3413 assert_data_tree!(
3414 hierarchy,
3415 root: contains {
3416 telemetry: contains {
3417 operations: contains {
3418 delegated: contains {
3419 updates: contains {
3420 successes: 1u64,
3421 errors: 0u64,
3422 },
3423 }
3424 }
3425 }
3426 }
3427 );
3428
3429 assert_eq!(
3431 process_fidl_request(
3432 &mut service,
3433 proxy.set_default(&fposix_socket::OptionalUint32::Value(1)),
3434 )
3435 .await,
3436 Ok(())
3437 );
3438
3439 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3440 assert_data_tree!(
3441 hierarchy,
3442 root: contains {
3443 telemetry: contains {
3444 operations: contains {
3445 delegated: contains {
3446 set_defaults: contains {
3447 successes: 1u64,
3448 errors: 0u64,
3449 },
3450 }
3451 }
3452 }
3453 }
3454 );
3455
3456 assert_eq!(
3458 process_fidl_request(
3459 &mut service,
3460 proxy.set_default(&fposix_socket::OptionalUint32::Value(2)),
3461 )
3462 .await,
3463 Err(NetworkRegistrySetDefaultError::NotFound)
3464 );
3465
3466 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3467 assert_data_tree!(
3468 hierarchy,
3469 root: contains {
3470 telemetry: contains {
3471 operations: contains {
3472 delegated: contains {
3473 set_defaults: contains {
3474 successes: 1u64,
3475 errors: 1u64,
3476 },
3477 }
3478 }
3479 }
3480 }
3481 );
3482
3483 assert_eq!(
3485 process_fidl_request(&mut service, proxy.remove(1)).await,
3486 Err(NetworkRegistryRemoveError::CannotRemoveDefaultNetwork)
3487 );
3488
3489 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3490 assert_data_tree!(
3491 hierarchy,
3492 root: contains {
3493 telemetry: contains {
3494 operations: contains {
3495 delegated: contains {
3496 removes: contains { successes: 0u64, errors: 1u64 },
3497 }
3498 }
3499 }
3500 }
3501 );
3502
3503 assert_eq!(
3505 process_fidl_request(
3506 &mut service,
3507 proxy.set_default(&fposix_socket::OptionalUint32::Unset(fposix_socket::Empty)),
3508 )
3509 .await,
3510 Ok(())
3511 );
3512
3513 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3514 assert_data_tree!(
3515 hierarchy,
3516 root: contains {
3517 telemetry: contains {
3518 operations: contains {
3519 delegated: contains {
3520 set_defaults: contains {
3521 successes: 2u64,
3522 errors: 1u64,
3523 },
3524 }
3525 }
3526 }
3527 }
3528 );
3529
3530 assert_eq!(process_fidl_request(&mut service, proxy.remove(1)).await, Ok(()));
3532
3533 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3534 assert_data_tree!(
3535 hierarchy,
3536 root: contains {
3537 telemetry: contains {
3538 operations: contains {
3539 delegated: contains {
3540 removes: contains { successes: 1u64, errors: 1u64 },
3541 }
3542 }
3543 }
3544 }
3545 );
3546 }
3547
3548 #[fuchsia::test]
3549 async fn test_network_registry_inspect() {
3550 const FUCHSIA_ID_2: NetworkId = NetworkId::Fuchsia(ID_2);
3551 const DELEGATED_ID_100: NetworkId =
3552 NetworkId::Delegated(InterfaceId(NonZeroU64::new(100).unwrap()));
3553
3554 let inspector = fuchsia_inspect::Inspector::default();
3555 let telemetry_node = inspector.root().create_child("telemetry");
3556 let mut service = NetpolNetworksService::default()
3557 .with_inspect(&telemetry_node, "operations", &telemetry_node, "network_registry")
3558 .expect("failed to initialize inspect");
3559 inspector.root().record(telemetry_node);
3560
3561 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3564 assert_data_tree!(
3565 hierarchy,
3566 root: contains {
3567 telemetry: contains {
3568 network_count: 0u64,
3569 network_registry: {}
3570 }
3571 }
3572 );
3573
3574 service
3576 .update(NetworkRegistryUpdate::ChangeNetwork(
3577 FUCHSIA_ID_2,
3578 NetworkUpdate::Properties(NetworkPropertiesChange {
3579 added: true,
3580 name: Some("wlan0".to_string()),
3581 network_type: Some(fnp_socketproxy::NetworkType::Wifi),
3582 connectivity_state: Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
3583 ..Default::default()
3584 }),
3585 ))
3586 .await;
3587
3588 let mut marks = fnet::Marks::default();
3590 marks.mark_1 = Some(100);
3591 service
3592 .update(NetworkRegistryUpdate::ChangeNetwork(
3593 DELEGATED_ID_100,
3594 NetworkUpdate::Properties(NetworkPropertiesChange {
3595 added: true,
3596 marks: Some(marks.clone()),
3597 name: Some("eth0".to_string()),
3598 network_type: Some(fnp_socketproxy::NetworkType::Ethernet),
3599 connectivity_state: Some(fnp_socketproxy::ConnectivityState::LocalConnectivity),
3600 ..Default::default()
3601 }),
3602 ))
3603 .await;
3604
3605 service
3607 .update(NetworkRegistryUpdate::ChangeNetwork(
3608 DELEGATED_ID_100,
3609 NetworkUpdate::MakeDefault,
3610 ))
3611 .await;
3612
3613 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3614 assert_data_tree!(
3615 hierarchy,
3616 root: contains {
3617 telemetry: contains {
3618 network_count: 2u64,
3619 network_registry: {
3620 default_network: "fuchsia:2",
3621 starnix_default: "delegated:100",
3622 fuchsia_2: {
3623 name: "wlan0",
3624 network_type: "Wifi",
3625 connectivity_state: "FullConnectivity",
3626 },
3627 delegated_100: {
3628 name: "eth0",
3629 network_type: "Ethernet",
3630 connectivity_state: "LocalConnectivity",
3631 },
3632 }
3633 }
3634 }
3635 );
3636
3637 service
3639 .update(NetworkRegistryUpdate::ChangeNetwork(
3640 DELEGATED_ID_100,
3641 NetworkUpdate::Properties(NetworkPropertiesChange {
3642 added: false,
3643 marks: Some(marks),
3644 name: Some("eth0_updated".to_string()),
3645 network_type: Some(fnp_socketproxy::NetworkType::Ethernet),
3646 connectivity_state: Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
3647 ..Default::default()
3648 }),
3649 ))
3650 .await;
3651
3652 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3653 assert_data_tree!(
3654 hierarchy,
3655 root: contains {
3656 telemetry: contains {
3657 network_count: 2u64,
3658 network_registry: {
3659 default_network: "fuchsia:2",
3660 starnix_default: "delegated:100",
3661 fuchsia_2: {
3662 name: "wlan0",
3663 network_type: "Wifi",
3664 connectivity_state: "FullConnectivity",
3665 },
3666 delegated_100: {
3667 name: "eth0_updated",
3668 network_type: "Ethernet",
3669 connectivity_state: "FullConnectivity",
3670 },
3671 }
3672 }
3673 }
3674 );
3675
3676 service
3679 .update(NetworkRegistryUpdate::ChangeNetwork(FUCHSIA_ID_2, NetworkUpdate::Remove))
3680 .await;
3681
3682 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3683 assert_data_tree!(
3684 hierarchy,
3685 root: contains {
3686 telemetry: contains {
3687 network_count: 1u64,
3688 network_registry: {
3689 default_network: "delegated:100",
3690 starnix_default: "delegated:100",
3691 delegated_100: {
3692 name: "eth0_updated",
3693 network_type: "Ethernet",
3694 connectivity_state: "FullConnectivity",
3695 },
3696 }
3697 }
3698 }
3699 );
3700
3701 service.update(NetworkRegistryUpdate::UnsetDefaultNetwork).await;
3704 service
3705 .update(NetworkRegistryUpdate::ChangeNetwork(DELEGATED_ID_100, NetworkUpdate::Remove))
3706 .await;
3707
3708 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3709 assert_data_tree!(
3710 hierarchy,
3711 root: contains {
3712 telemetry: contains {
3713 network_count: 0u64,
3714 network_registry: {}
3715 }
3716 }
3717 );
3718 }
3719
3720 #[fuchsia::test]
3721 async fn test_reachability_service_integration() {
3722 let mut service = NetpolNetworksService::default();
3723
3724 let mut expected_disconnected = freachability::Snapshot::default();
3725 expected_disconnected.gateway_reachable = Some(false);
3726 expected_disconnected.internet_available = Some(false);
3727 expected_disconnected.dns_active = Some(false);
3728 expected_disconnected.http_active = Some(false);
3729
3730 let mut expected_validated = freachability::Snapshot::default();
3731 expected_validated.gateway_reachable = Some(true);
3732 expected_validated.internet_available = Some(true);
3733 expected_validated.dns_active = Some(true);
3734 expected_validated.http_active = Some(true);
3735
3736 let (proxy, stream) =
3737 fidl::endpoints::create_proxy_and_stream::<freachability::MonitorMarker>();
3738 service.add_stream(stream);
3739 assert_eq!(service.reachability_watcher_count(), 1);
3740
3741 let watch_fut = proxy.watch();
3742 let event = service.select_next_some().await;
3743 assert_eq!(
3744 service.handle_event(event).await.expect("handle event"),
3745 DelegatedNetworkUpdateResult::default()
3746 );
3747 let snapshot = watch_fut.await.expect("watch error");
3748 assert_eq!(snapshot, expected_disconnected);
3749
3750 let mut second_watch = proxy.watch();
3751 let event = service.select_next_some().await;
3752 assert_eq!(
3753 service.handle_event(event).await.expect("handle event"),
3754 DelegatedNetworkUpdateResult::default()
3755 );
3756 assert_matches!(futures::poll!(&mut second_watch), std::task::Poll::Pending);
3757
3758 service
3759 .update(NetworkRegistryUpdate::ChangeNetwork(
3760 DELEGATED_ID_1,
3761 NetworkUpdate::Properties(DELEGATED_NET_1.change_with(
3762 true,
3763 Some(test_marks()),
3764 None,
3765 Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
3766 )),
3767 ))
3768 .await;
3769 service
3770 .update(NetworkRegistryUpdate::ChangeNetwork(
3771 DELEGATED_ID_1,
3772 NetworkUpdate::MakeDefault,
3773 ))
3774 .await;
3775
3776 let snapshot = second_watch.await.expect("watch should succeed");
3777 assert_eq!(snapshot, expected_validated);
3778 }
3779
3780 #[fuchsia::test]
3781 async fn test_networks_client_disconnect_cleans_up_state() {
3782 let mut service = NetpolNetworksService::default();
3783 let (proxy, stream) =
3784 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
3785 service.add_stream(stream);
3786
3787 let mut watch_default_fut = proxy.watch_default();
3789 let event = service.select_next_some().await;
3790 assert_eq!(
3791 service.handle_event(event).await.expect("Failed to handle event"),
3792 DelegatedNetworkUpdateResult::default()
3793 );
3794 assert_matches!((&mut watch_default_fut).now_or_never(), None);
3795 assert_matches!(
3796 &service.networks_clients.values().collect::<Vec<_>>()[..],
3797 [NetworksClient { responder: Some(_), .. }]
3798 );
3799
3800 drop(watch_default_fut);
3802 drop(proxy);
3803
3804 let event = service.select_next_some().await;
3805 assert_eq!(
3806 service.handle_event(event).await.expect("Failed to handle event"),
3807 DelegatedNetworkUpdateResult::default()
3808 );
3809 assert!(service.networks_clients.is_empty());
3811 assert!(service.generations_by_connection.default_network.is_empty());
3812 }
3813
3814 #[fuchsia::test]
3815 async fn test_property_watcher_client_disconnect_cleans_up_state() {
3816 let mut service = NetpolNetworksService::default();
3817
3818 service
3819 .update(NetworkRegistryUpdate::ChangeNetwork(
3820 DELEGATED_ID_1,
3821 NetworkUpdate::Properties(DELEGATED_NET_1.change_with(
3822 true,
3823 Some(test_marks()),
3824 None,
3825 None,
3826 )),
3827 ))
3828 .await;
3829
3830 let token = service
3831 .tokens
3832 .ensure_token(NetworkTokenContents { network_id: DELEGATED_ID_1, is_default: false })
3833 .get()
3834 .duplicate()
3835 .unwrap();
3836
3837 let (watcher, server_end) =
3838 fidl::endpoints::create_proxy::<fnp_properties::PropertyWatcherMarker>();
3839 let (networks_proxy, networks_stream) =
3840 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
3841 service.add_stream(networks_stream);
3842
3843 let watch_req =
3844 networks_proxy.watch_properties(fnp_properties::NetworksWatchPropertiesRequest {
3845 network: Some(token),
3846 properties: Some(fnp_properties::PropertyInterest::SOCKET_MARKS),
3847 watcher: Some(server_end),
3848 ..Default::default()
3849 });
3850
3851 let req_event = service.select_next_some().await;
3852 assert_eq!(
3853 service.handle_event(req_event).await.expect("Failed to handle event"),
3854 DelegatedNetworkUpdateResult::default()
3855 );
3856 assert_matches!(watch_req.await, Ok(Ok(())));
3857
3858 let watch_fut1 = watcher.watch();
3860 let pw_event1 = service.select_next_some().await;
3861 assert_eq!(
3862 service.handle_event(pw_event1).await.expect("Failed to handle event"),
3863 DelegatedNetworkUpdateResult::default()
3864 );
3865 let _ = watch_fut1.await.unwrap().unwrap();
3866
3867 let mut watch_fut2 = watcher.watch();
3869 let pw_event2 = service.select_next_some().await;
3870 assert_eq!(
3871 service.handle_event(pw_event2).await.expect("Failed to handle event"),
3872 DelegatedNetworkUpdateResult::default()
3873 );
3874 assert_matches!((&mut watch_fut2).now_or_never(), None);
3875 assert_eq!(service.property_watchers.len(), 1);
3876
3877 drop(watch_fut2);
3879 drop(watcher);
3880
3881 let disconnect_event = service.select_next_some().await;
3882 assert_eq!(
3883 service.handle_event(disconnect_event).await.expect("Failed to handle event"),
3884 DelegatedNetworkUpdateResult::default()
3885 );
3886
3887 assert!(service.property_watchers.is_empty());
3889 assert!(service.generations_by_connection.properties.is_empty());
3890 }
3891
3892 #[fuchsia::test]
3893 async fn test_delegated_networks_single_connection() {
3894 let mut service = NetpolNetworksService::default();
3895 let (proxy1, stream1) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3896 service.add_stream(stream1);
3897 assert!(service.delegated_networks_client.is_some());
3898
3899 assert_eq!(
3901 process_fidl_request(&mut service, proxy1.remove(1)).await,
3902 Err(NetworkRegistryRemoveError::NotFound)
3903 );
3904
3905 let (proxy2, stream2) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3907 service.add_stream(stream2);
3908 assert_matches!(
3909 proxy2.remove(1).await,
3910 Err(fidl::Error::ClientChannelClosed { epitaph, .. })
3911 if epitaph == zx::Status::ALREADY_EXISTS
3912 );
3913
3914 assert_eq!(
3916 process_fidl_request(&mut service, proxy1.remove(1)).await,
3917 Err(NetworkRegistryRemoveError::NotFound)
3918 );
3919
3920 drop(proxy1);
3923 let disconnect_event = service.select_next_some().await;
3924 assert_eq!(
3925 service.handle_event(disconnect_event).await.expect("Failed to handle event"),
3926 DelegatedNetworkUpdateResult::default()
3927 );
3928 assert!(service.delegated_networks_client.is_none());
3929
3930 let (proxy3, stream3) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3931 service.add_stream(stream3);
3932 assert_eq!(
3933 process_fidl_request(&mut service, proxy3.remove(1)).await,
3934 Err(NetworkRegistryRemoveError::NotFound)
3935 );
3936 }
3937
3938 #[fuchsia::test]
3939 async fn test_delegated_networks_client_disconnect_cleans_up_state() {
3940 let mut service = NetpolNetworksService::default();
3941 let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3942 service.add_stream(stream);
3943
3944 const STARNIX_ID_1: u32 = 1;
3946 const STARNIX_ID_2: u32 = 2;
3947 const SOCKET_MARK_1: u32 = 100;
3948 const SOCKET_MARK_2: u32 = 200;
3949
3950 service
3952 .update(NetworkRegistryUpdate::ChangeNetwork(
3953 FUCHSIA_ID_1,
3954 NetworkUpdate::Properties(NetworkPropertiesChange {
3955 added: true,
3956 ..Default::default()
3957 }),
3958 ))
3959 .await;
3960
3961 assert_eq!(
3962 process_fidl_request(
3963 &mut service,
3964 proxy.add(&starnix_network_payload(STARNIX_ID_1, SOCKET_MARK_1))
3965 )
3966 .await,
3967 Ok(())
3968 );
3969 assert_eq!(
3970 process_fidl_request(
3971 &mut service,
3972 proxy.add(&starnix_network_payload(STARNIX_ID_2, SOCKET_MARK_2))
3973 )
3974 .await,
3975 Ok(())
3976 );
3977 assert_eq!(
3978 process_fidl_request(
3979 &mut service,
3980 proxy.set_default(&fposix_socket::OptionalUint32::Value(STARNIX_ID_1)),
3981 )
3982 .await,
3983 Ok(())
3984 );
3985 assert_eq!(service.network_registry.starnix_default, Some(DELEGATED_ID_1));
3986 assert_eq!(service.network_registry.networks.len(), 3);
3987
3988 drop(proxy);
3991 let disconnect_event = service.select_next_some().await;
3992 assert_eq!(
3993 service.handle_event(disconnect_event).await.expect("Failed to handle event"),
3994 DelegatedNetworkUpdateResult { dns_servers: Some(vec![]) }
3995 );
3996 assert_eq!(service.network_registry.starnix_default, None);
3997 assert_eq!(
3998 service.network_registry.networks.keys().copied().collect::<Vec<_>>(),
3999 vec![FUCHSIA_ID_1]
4000 );
4001
4002 let (proxy2, stream2) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
4004 service.add_stream(stream2);
4005 assert_eq!(
4006 process_fidl_request(
4007 &mut service,
4008 proxy2.add(&starnix_network_payload(STARNIX_ID_1, SOCKET_MARK_2)),
4009 )
4010 .await,
4011 Ok(())
4012 );
4013 }
4014
4015 #[fuchsia::test]
4016 async fn test_networks_and_dns_inspect() {
4017 const FUCHSIA_ID_2: NetworkId = NetworkId::Fuchsia(ID_2);
4018 const DELEGATED_ID_100: NetworkId =
4019 NetworkId::Delegated(InterfaceId(NonZeroU64::new(100).unwrap()));
4020
4021 let inspector = fuchsia_inspect::Inspector::default();
4022 let telemetry_node = inspector.root().create_child("telemetry");
4023 let mut service = NetpolNetworksService::default()
4024 .with_inspect(&telemetry_node, "operations", &telemetry_node, "network_registry")
4025 .expect("failed to initialize inspect");
4026 inspector.root().record(telemetry_node);
4027
4028 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
4030 assert_data_tree!(
4031 hierarchy,
4032 root: contains {
4033 telemetry: contains {
4034 network_registry: {}
4035 }
4036 }
4037 );
4038
4039 let static_server_1 = fnet_name::DnsServer_ {
4041 address: Some(net_declare::fidl_socket_addr!("8.8.8.8:53")),
4042 source: Some(fnet_name::DnsServerSource::StaticSource(
4043 fnet_name::StaticDnsServerSource::default(),
4044 )),
4045 ..Default::default()
4046 };
4047 let static_server_2 = fnet_name::DnsServer_ {
4048 address: Some(net_declare::fidl_socket_addr!("8.8.4.4:53")),
4049 source: Some(fnet_name::DnsServerSource::StaticSource(
4050 fnet_name::StaticDnsServerSource::default(),
4051 )),
4052 ..Default::default()
4053 };
4054 let dhcp_server = fnet_name::DnsServer_ {
4055 address: Some(net_declare::fidl_socket_addr!("192.168.1.1:53")),
4056 source: Some(fnet_name::DnsServerSource::Dhcp(fnet_name::DhcpDnsServerSource {
4057 source_interface: Some(ID_2.get()),
4058 ..Default::default()
4059 })),
4060 ..Default::default()
4061 };
4062 let ndp_server = fnet_name::DnsServer_ {
4063 address: Some(net_declare::fidl_socket_addr!("[fe80::1%1]:53")),
4064 source: Some(fnet_name::DnsServerSource::Ndp(fnet_name::NdpDnsServerSource {
4065 source_interface: Some(ID_2.get()),
4066 ..Default::default()
4067 })),
4068 ..Default::default()
4069 };
4070 let dhcpv6_server = fnet_name::DnsServer_ {
4071 address: Some(net_declare::fidl_socket_addr!("[2001:4860:4860::8888]:53")),
4072 source: Some(fnet_name::DnsServerSource::Dhcpv6(fnet_name::Dhcpv6DnsServerSource {
4073 source_interface: Some(ID_2.get()),
4074 ..Default::default()
4075 })),
4076 ..Default::default()
4077 };
4078
4079 service
4080 .update(NetworkRegistryUpdate::UpdateDns(vec![
4081 dhcp_server.clone(),
4082 ndp_server.clone(),
4083 dhcpv6_server.clone(),
4084 static_server_1.clone(),
4085 static_server_2.clone(),
4086 ]))
4087 .await;
4088
4089 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
4090 assert_data_tree!(
4091 hierarchy,
4092 root: contains {
4093 telemetry: contains {
4094 network_registry: contains {
4095 system_dns_servers: {
4096 "0": {
4097 server: "192.168.1.1:53",
4098 type: "Dhcpv4",
4099 interface_id: 2u64,
4100 },
4101 "1": {
4102 server: "[fe80::1%1]:53",
4103 type: "Ndp",
4104 interface_id: 2u64,
4105 },
4106 "2": {
4107 server: "[2001:4860:4860::8888]:53",
4108 type: "Dhcpv6",
4109 interface_id: 2u64,
4110 },
4111 "3": {
4112 server: "8.8.8.8:53",
4113 type: "Static",
4114 },
4115 "4": {
4116 server: "8.8.4.4:53",
4117 type: "Static",
4118 },
4119 },
4120 }
4121 }
4122 }
4123 );
4124
4125 service
4127 .update(NetworkRegistryUpdate::ChangeNetwork(
4128 FUCHSIA_ID_2,
4129 NetworkUpdate::Properties(NetworkPropertiesChange {
4130 added: true,
4131 name: Some("wlan0".to_string()),
4132 network_type: Some(fnp_socketproxy::NetworkType::Wifi),
4133 connectivity_state: Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
4134 ..Default::default()
4135 }),
4136 ))
4137 .await;
4138
4139 let socketproxy_dns = fnet_name::DnsServer_ {
4141 address: Some(net_declare::fidl_socket_addr!("192.168.1.2:53")),
4142 source: Some(fnet_name::DnsServerSource::SocketProxy(
4143 fnet_name::SocketProxyDnsServerSource::default(),
4144 )),
4145 ..Default::default()
4146 };
4147 let mut marks = fnet::Marks::default();
4148 marks.mark_1 = Some(100);
4149 service
4150 .update(NetworkRegistryUpdate::ChangeNetwork(
4151 DELEGATED_ID_100,
4152 NetworkUpdate::Properties(NetworkPropertiesChange {
4153 added: true,
4154 marks: Some(marks),
4155 dns_servers: Some(vec![socketproxy_dns]),
4156 name: Some("wlan0".to_string()),
4157 network_type: Some(fnp_socketproxy::NetworkType::Wifi),
4158 connectivity_state: Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
4159 }),
4160 ))
4161 .await;
4162
4163 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
4164 assert_data_tree!(
4165 hierarchy,
4166 root: contains {
4167 telemetry: contains {
4168 network_registry: {
4169 default_network: "fuchsia:2",
4170 system_dns_servers: {
4171 "0": {
4172 server: "192.168.1.1:53",
4173 type: "Dhcpv4",
4174 interface_id: 2u64,
4175 },
4176 "1": {
4177 server: "[fe80::1%1]:53",
4178 type: "Ndp",
4179 interface_id: 2u64,
4180 },
4181 "2": {
4182 server: "[2001:4860:4860::8888]:53",
4183 type: "Dhcpv6",
4184 interface_id: 2u64,
4185 },
4186 "3": {
4187 server: "8.8.8.8:53",
4188 type: "Static",
4189 },
4190 "4": {
4191 server: "8.8.4.4:53",
4192 type: "Static",
4193 },
4194 },
4195 fuchsia_2: {
4196 name: "wlan0",
4197 network_type: "Wifi",
4198 connectivity_state: "FullConnectivity",
4199 dns_servers: {
4200 "0": {
4201 server: "192.168.1.1:53",
4202 type: "Dhcpv4",
4203 interface_id: 2u64,
4204 },
4205 "1": {
4206 server: "[fe80::1%1]:53",
4207 type: "Ndp",
4208 interface_id: 2u64,
4209 },
4210 "2": {
4211 server: "[2001:4860:4860::8888]:53",
4212 type: "Dhcpv6",
4213 interface_id: 2u64,
4214 },
4215 },
4216 },
4217 delegated_100: {
4218 name: "wlan0",
4219 network_type: "Wifi",
4220 connectivity_state: "FullConnectivity",
4221 dns_servers: {
4222 "0": {
4223 server: "192.168.1.2:53",
4224 type: "SocketProxy",
4225 },
4226 },
4227 },
4228 }
4229 }
4230 }
4231 );
4232 }
4233}