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