1use crate::InterfaceId;
6use crate::dns::DNS_PORT;
7use crate::telemetry::{NetworkEventMetadata, TelemetryEvent, TelemetrySender};
8use anyhow::Context as _;
9use async_utils::stream::{Tagged, WithTag as _};
10use dns_server_watcher::DnsServers;
11use fidl::endpoints::Responder as _;
12use futures::StreamExt as _;
13use log::{error, info, warn};
14use policy_properties::NetworkTokenExt as _;
15use std::collections::HashMap;
16use std::collections::hash_map::Entry;
17
18mod token_registry;
19
20use fidl_fuchsia_net as fnet;
21use fidl_fuchsia_net_name as fnet_name;
22use fidl_fuchsia_net_policy_properties as fnp_properties;
23use fidl_fuchsia_net_policy_socketproxy as fnp_socketproxy;
24use fidl_fuchsia_posix_socket as fposix_socket;
25
26#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
31pub enum NetworkId {
32 Fuchsia(InterfaceId),
33 Delegated(InterfaceId),
34}
35
36impl std::fmt::Display for NetworkId {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 match self {
39 NetworkId::Fuchsia(interface_id) => write!(f, "fuchsia:{interface_id}"),
40 NetworkId::Delegated(interface_id) => write!(f, "delegated:{interface_id}"),
41 }
42 }
43}
44
45impl NetworkId {
46 pub fn get(&self) -> InterfaceId {
47 match self {
48 NetworkId::Fuchsia(interface_id) => *interface_id,
49 NetworkId::Delegated(interface_id) => *interface_id,
50 }
51 }
52
53 pub fn fuchsia<I: Into<InterfaceId>>(id: I) -> Self {
54 NetworkId::Fuchsia(id.into())
55 }
56
57 pub fn delegated<I: Into<InterfaceId>>(id: I) -> Self {
58 NetworkId::Delegated(id.into())
59 }
60
61 pub fn is_fuchsia(&self) -> bool {
62 matches!(self, NetworkId::Fuchsia(_))
63 }
64
65 pub fn is_delegated(&self) -> bool {
66 matches!(self, NetworkId::Delegated(_))
67 }
68}
69
70#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
71pub(crate) struct NetworkTokenContents {
72 network_id: NetworkId,
73 is_default: bool,
74}
75
76#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
77pub struct ConnectionId(usize);
78
79impl ConnectionId {
80 fn increment(&mut self) {
81 self.0 += 1;
82 }
83}
84
85#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
86pub struct UpdateGeneration {
87 default_network: usize,
90
91 properties: usize,
94}
95
96#[derive(Clone, Debug, Default)]
97pub struct UpdateGenerations(HashMap<ConnectionId, UpdateGeneration>);
98
99impl UpdateGenerations {
100 fn default_network(&self, id: &ConnectionId) -> Option<usize> {
101 self.0.get(id).map(|g| g.default_network)
102 }
103
104 fn set_default_network(&mut self, id: ConnectionId, generation: UpdateGeneration) {
105 self.0.entry(id).or_default().default_network = generation.default_network;
106 }
107
108 fn properties(&self, id: &ConnectionId) -> Option<usize> {
109 self.0.get(id).map(|g| g.properties)
110 }
111
112 fn set_properties(&mut self, id: ConnectionId, generation: UpdateGeneration) {
113 self.0.entry(id).or_default().properties = generation.properties;
114 }
115
116 fn remove(&mut self, id: &ConnectionId) -> Option<UpdateGeneration> {
117 self.0.remove(id)
118 }
119}
120
121trait SetMark {
122 fn set_mark(&mut self, domain: fnet::MarkDomain, value: Option<u32>);
123}
124
125impl SetMark for fnet::Marks {
126 fn set_mark(&mut self, domain: fnet::MarkDomain, value: Option<u32>) {
127 match domain {
128 fnet::MarkDomain::Mark1 => self.mark_1 = value,
129 fnet::MarkDomain::Mark2 => self.mark_2 = value,
130 }
131 }
132}
133
134#[derive(Debug)]
135pub(crate) struct NetworkPropertyResponder {
136 token: fnp_properties::NetworkToken,
137 watched_properties: Vec<fnp_properties::Property>,
138 responder: fnp_properties::NetworksWatchPropertiesResponder,
139}
140
141impl NetworkPropertyResponder {
142 fn respond(
143 self,
144 response: Result<&[fnp_properties::PropertyUpdate], fnp_properties::WatchError>,
145 ) -> Result<(), fidl::Error> {
146 self.responder.send(response)
147 }
148}
149
150#[derive(Debug, PartialEq, Default, Clone)]
151struct NetworkProperties {
152 socket_marks: Option<fnet::Marks>,
153 dns_servers: Vec<fnet_name::DnsServer_>,
154 #[allow(dead_code)]
156 connectivity_state: Option<fnp_socketproxy::ConnectivityState>,
157 name: Option<String>,
158 network_type: Option<fnp_socketproxy::NetworkType>,
159}
160
161impl NetworkProperties {
162 fn get_marks(&self) -> Option<&fnet::Marks> {
163 self.socket_marks.as_ref()
164 }
165}
166
167#[derive(Default, Clone)]
169struct RegisteredNetworks {
170 default_network: Option<NetworkId>,
173 starnix_default: Option<NetworkId>,
175 networks: HashMap<NetworkId, NetworkProperties>,
176 dns_servers: Vec<fnet_name::DnsServer_>,
177}
178
179impl RegisteredNetworks {
180 fn calculate_active_default(&self) -> Option<NetworkId> {
184 let first_fuchsia = self.networks.keys().filter(|id| id.is_fuchsia()).cloned().min();
187 if let Some(fd) = first_fuchsia {
188 return Some(fd);
189 }
190
191 if let Some(starnix_default) = self.starnix_default {
193 assert!(self.networks.contains_key(&starnix_default));
195 }
196 self.starnix_default
197 }
198
199 fn handle_default_network_update(&mut self) -> Option<DefaultChangedEvent> {
204 let next_default = self.calculate_active_default();
205 if next_default != self.default_network {
206 let old_default = self.default_network;
207 self.default_network = next_default;
208 Some(DefaultChangedEvent { previous_default: old_default })
209 } else {
210 None
211 }
212 }
213
214 fn apply(&mut self, update: PropertyUpdate) -> RegistryUpdateResult {
215 match update {
216 PropertyUpdate::LoseDefaultNetwork => {
217 self.starnix_default = None;
219 RegistryUpdateResult {
220 event: UpdateApplied::None,
221 default_changed: self.handle_default_network_update(),
222 }
223 }
224 PropertyUpdate::ChangeNetwork(network_id, network_change) => match network_change {
225 NetworkUpdate::Properties(event) => RegistryUpdateResult {
226 event: self.handle_changed_network(network_id, event),
227 default_changed: self.handle_default_network_update(),
228 },
229 NetworkUpdate::Remove => {
230 if self.starnix_default == Some(network_id) {
231 error!("Cannot remove the default delegated network. Update ignored.");
232 RegistryUpdateResult { event: UpdateApplied::None, default_changed: None }
233 } else if self.networks.remove(&network_id).is_some() {
234 RegistryUpdateResult {
236 event: UpdateApplied::NetworkRemoved(network_id),
237 default_changed: self.handle_default_network_update(),
238 }
239 } else {
240 error!("Cannot remove a non-existent network. Update ignored.");
241 RegistryUpdateResult { event: UpdateApplied::None, default_changed: None }
242 }
243 }
244 NetworkUpdate::MakeDefault => {
245 match network_id {
246 NetworkId::Fuchsia(_) => {}
249 NetworkId::Delegated(_) => self.starnix_default = Some(network_id),
250 }
251 let default_changed = self.handle_default_network_update();
252 RegistryUpdateResult { event: UpdateApplied::None, default_changed }
253 }
254 },
255 PropertyUpdate::UpdateDns(dns_servers) => {
256 let event = if self.dns_servers != dns_servers {
257 self.dns_servers = dns_servers;
258 UpdateApplied::DnsChanged
259 } else {
260 UpdateApplied::None
261 };
262 RegistryUpdateResult { event, default_changed: None }
263 }
264 }
265 }
266
267 fn handle_changed_network(
272 &mut self,
273 network_id: NetworkId,
274 event: NetworkPropertiesChange,
275 ) -> UpdateApplied {
276 let NetworkPropertiesChange {
277 added,
278 marks: socket_marks,
279 dns_servers: changed_dns_servers,
280 connectivity_state,
281 name,
282 network_type,
283 } = event;
284 let entry = self.networks.entry(network_id);
285 let result = match (added, &entry, network_id, socket_marks) {
286 (true, Entry::Occupied(_), _, _) => Err("add already added network"),
287 (false, Entry::Vacant(_), _, _) => Err("update a non-added network"),
288 (_, _, NetworkId::Fuchsia(_), Some(_)) => Err("have a fuchsia network with marks"),
289 (_, _, NetworkId::Delegated(_), None) => Err("have a delegated network without marks"),
290 (_, entry, NetworkId::Fuchsia(_), None) => {
291 let new_dns = changed_dns_servers.unwrap_or_default();
292 let changed_dns = match entry {
293 Entry::Occupied(e) => e.get().dns_servers != new_dns,
294 Entry::Vacant(_) => true,
297 };
298 Ok((
299 NetworkProperties { dns_servers: new_dns, ..Default::default() },
300 added,
301 changed_dns,
302 ))
303 }
304 (_, entry, NetworkId::Delegated(_), Some(socket_marks)) => {
305 let new_dns = changed_dns_servers.unwrap_or_default();
306 let (changed_marks, changed_dns) = match entry {
307 Entry::Occupied(e) => {
308 (e.get().get_marks() != Some(&socket_marks), e.get().dns_servers != new_dns)
309 }
310 Entry::Vacant(_) => (true, true),
313 };
314 Ok((
315 NetworkProperties {
316 socket_marks: Some(socket_marks),
317 dns_servers: new_dns,
318 ..Default::default()
319 },
320 changed_marks,
321 changed_dns,
322 ))
323 }
324 };
325
326 match result {
327 Ok((mut properties, changed_marks, changed_dns)) => {
328 properties.connectivity_state = connectivity_state;
329 properties.network_type = network_type;
330 properties.name = name.clone();
331 let _ = entry.insert_entry(properties);
332 UpdateApplied::NetworkChanged {
333 network_id,
334 added,
335 changed_marks,
336 changed_dns,
337 name,
338 network_type,
339 }
340 }
341 Err(e) => {
342 error!("Cannot {e}. Update ignored.");
343 UpdateApplied::None
344 }
345 }
346 }
347
348 pub fn consolidated_dns_servers(&self) -> Vec<fnet_name::DnsServer_> {
353 if let Some(NetworkId::Fuchsia(if_id)) = self.default_network {
354 self.networks
355 .get(&NetworkId::Fuchsia(if_id))
356 .map(|p| p.dns_servers.clone())
357 .unwrap_or_default()
358 } else {
359 self.networks
360 .iter()
361 .filter(|(id, _)| matches!(id, NetworkId::Delegated(_)))
362 .flat_map(|(_, p)| &p.dns_servers)
363 .cloned()
364 .collect()
365 }
366 }
367
368 fn maybe_respond(
369 &self,
370 network: &NetworkTokenContents,
371 responder: NetworkPropertyResponder,
372 ) -> Option<NetworkPropertyResponder> {
373 let mut updates = Vec::new();
374 updates.add_socket_marks(self, network, &responder);
375 updates.add_dns(self, network, &responder);
376
377 if updates.is_empty() {
378 Some(responder)
379 } else {
380 if let Err(e) = responder.respond(Ok(&updates)) {
381 warn!("Could not send to responder: {e}");
382 }
383 None
384 }
385 }
386}
387
388trait PropertyUpdates {
389 fn add_socket_marks(
390 &mut self,
391 network_registry: &RegisteredNetworks,
392 network: &NetworkTokenContents,
393 responder: &NetworkPropertyResponder,
394 );
395 fn add_dns(
396 &mut self,
397 network_registry: &RegisteredNetworks,
398 network: &NetworkTokenContents,
399 responder: &NetworkPropertyResponder,
400 );
401}
402
403impl PropertyUpdates for Vec<fnp_properties::PropertyUpdate> {
404 fn add_socket_marks(
405 &mut self,
406 network_registry: &RegisteredNetworks,
407 network: &NetworkTokenContents,
408 responder: &NetworkPropertyResponder,
409 ) {
410 if !responder.watched_properties.contains(&fnp_properties::Property::SocketMarks) {
411 return;
412 }
413
414 match network_registry.networks.get(&network.network_id) {
415 Some(network) => {
416 if let Some(socket_marks) = network.get_marks() {
417 self.push(fnp_properties::PropertyUpdate::SocketMarks(socket_marks.clone()));
418 }
419 return;
420 }
421 None => {
422 error!(
423 "State is inconsistent. We attempted to add marks for a \
424 network that is not known: {:?}",
425 network.network_id
426 );
427 }
428 }
429 }
430
431 fn add_dns(
432 &mut self,
433 network_registry: &RegisteredNetworks,
434 network: &NetworkTokenContents,
435 responder: &NetworkPropertyResponder,
436 ) {
437 if !responder.watched_properties.contains(&fnp_properties::Property::DnsConfiguration) {
438 return;
439 }
440
441 let interface_id = network.network_id;
442 self.push(fnp_properties::PropertyUpdate::DnsConfiguration(
443 fnp_properties::DnsConfiguration {
444 servers: Some(
445 network_registry
446 .dns_servers
447 .iter()
448 .filter(|d| {
449 match &d.source {
450 Some(source) => match source {
451 fnet_name::DnsServerSource::StaticSource(_) => true,
452 fnet_name::DnsServerSource::SocketProxy(
456 fnet_name::SocketProxyDnsServerSource {
457 source_interface,
458 ..
459 },
460 ) => match (interface_id, source_interface) {
461 (_, None) => true,
462 (id1, Some(id2)) => {
463 Ok(id1)
464 == InterfaceId::try_from(*id2)
465 .map(|id| NetworkId::delegated(id))
466 }
467 },
468 fnet_name::DnsServerSource::Dhcp(
469 fnet_name::DhcpDnsServerSource { source_interface, .. },
470 )
471 | fnet_name::DnsServerSource::Ndp(
472 fnet_name::NdpDnsServerSource { source_interface, .. },
473 )
474 | fnet_name::DnsServerSource::Dhcpv6(
475 fnet_name::Dhcpv6DnsServerSource {
476 source_interface, ..
477 },
478 ) => match (interface_id, source_interface) {
479 (_, None) => true,
480 (id1, Some(id2)) => {
481 Ok(id1)
482 == InterfaceId::try_from(*id2)
483 .map(|id| NetworkId::fuchsia(id))
484 }
485 },
486
487 _ => {
488 error!("unhandled DnsServerSource: {source:?}");
489 false
490 }
491 },
492
493 None => true,
495 }
496 })
497 .cloned()
498 .collect::<Vec<_>>(),
499 ),
500 ..Default::default()
501 },
502 ));
503 }
504}
505
506#[derive(Clone, Debug, Default)]
508pub struct NetworkPropertiesChange {
509 pub added: bool,
512 pub marks: Option<fnet::Marks>,
514 pub dns_servers: Option<Vec<fnet_name::DnsServer_>>,
516 pub connectivity_state: Option<fnp_socketproxy::ConnectivityState>,
518 pub name: Option<String>,
520 pub network_type: Option<fnp_socketproxy::NetworkType>,
522}
523
524#[derive(Debug, Clone)]
525pub enum NetworkUpdate {
526 Properties(NetworkPropertiesChange),
528 Remove,
529 MakeDefault,
530}
531
532#[derive(Debug, PartialEq, Eq, Clone)]
533struct DefaultChangedEvent {
534 previous_default: Option<NetworkId>,
535}
536
537#[derive(Debug, PartialEq, Eq)]
538struct RegistryUpdateResult {
539 event: UpdateApplied,
540 default_changed: Option<DefaultChangedEvent>,
543}
544
545#[derive(Debug, PartialEq, Eq, Clone)]
546enum UpdateApplied {
547 None,
549
550 DnsChanged,
552
553 NetworkChanged {
555 network_id: NetworkId,
556 added: bool,
557 changed_marks: bool,
558 changed_dns: bool,
559 name: Option<String>,
560 network_type: Option<fnp_socketproxy::NetworkType>,
561 },
562
563 NetworkRemoved(NetworkId),
565}
566
567#[derive(Debug, Clone)]
568pub enum PropertyUpdate {
569 LoseDefaultNetwork,
570 ChangeNetwork(NetworkId, NetworkUpdate),
571 UpdateDns(Vec<fnet_name::DnsServer_>),
572}
573
574impl PropertyUpdate {
575 pub fn default_network_lost() -> Self {
576 PropertyUpdate::LoseDefaultNetwork
577 }
578
579 pub fn dns(dns_servers: &DnsServers) -> Self {
580 PropertyUpdate::UpdateDns(dns_servers.consolidated_dns_servers())
583 }
584}
585
586#[derive(Debug, PartialEq)]
591pub struct DelegatedNetworkUpdateResult {
592 pub dns_servers: Option<Vec<fnet_name::DnsServer_>>,
595}
596
597pub enum NetworkRequestStream {
598 Networks(fnp_properties::NetworksRequestStream),
599 NetworkTokenResolver(fnp_properties::NetworkTokenResolverRequestStream),
600 DelegatedNetworks(fnp_socketproxy::NetworkRegistryRequestStream),
601}
602
603impl From<fnp_properties::NetworksRequestStream> for NetworkRequestStream {
604 fn from(s: fnp_properties::NetworksRequestStream) -> Self {
605 Self::Networks(s)
606 }
607}
608impl From<fnp_properties::NetworkTokenResolverRequestStream> for NetworkRequestStream {
609 fn from(s: fnp_properties::NetworkTokenResolverRequestStream) -> Self {
610 Self::NetworkTokenResolver(s)
611 }
612}
613impl From<fnp_socketproxy::NetworkRegistryRequestStream> for NetworkRequestStream {
614 fn from(s: fnp_socketproxy::NetworkRegistryRequestStream) -> Self {
615 Self::DelegatedNetworks(s)
616 }
617}
618
619pub struct NetworkAttributesRequest {
620 pub id: ConnectionId,
621 pub request: Result<fnp_properties::NetworksRequest, fidl::Error>,
622}
623
624pub struct NetworkTokenResolverRequest {
625 pub request: Result<fnp_properties::NetworkTokenResolverRequest, fidl::Error>,
626}
627
628pub struct DelegatedNetworksRequest {
629 pub request: Result<fnp_socketproxy::NetworkRegistryRequest, fidl::Error>,
630}
631
632pub enum NetworkRequest {
633 NetworkAttributes(NetworkAttributesRequest),
634 NetworkTokenResolver(NetworkTokenResolverRequest),
635 DelegatedNetworks(DelegatedNetworksRequest),
636}
637
638enum NetworkRequestStreamInner {
639 Networks(Tagged<ConnectionId, fnp_properties::NetworksRequestStream>),
640 NetworkTokenResolver(fnp_properties::NetworkTokenResolverRequestStream),
641 DelegatedNetworks(fnp_socketproxy::NetworkRegistryRequestStream),
642}
643
644impl futures::Stream for NetworkRequestStreamInner {
645 type Item = NetworkRequest;
646
647 fn poll_next(
648 mut self: std::pin::Pin<&mut Self>,
649 cx: &mut std::task::Context<'_>,
650 ) -> std::task::Poll<Option<Self::Item>> {
651 match *self {
652 NetworkRequestStreamInner::Networks(ref mut stream) => {
653 stream.poll_next_unpin(cx).map(|o| {
654 o.map(|(id, request)| NetworkAttributesRequest { id, request })
655 .map(NetworkRequest::NetworkAttributes)
656 })
657 }
658 NetworkRequestStreamInner::NetworkTokenResolver(ref mut stream) => {
659 stream.poll_next_unpin(cx).map(|o| {
660 o.map(|request| NetworkTokenResolverRequest { request })
661 .map(NetworkRequest::NetworkTokenResolver)
662 })
663 }
664 NetworkRequestStreamInner::DelegatedNetworks(ref mut stream) => {
665 stream.poll_next_unpin(cx).map(|o| {
666 o.map(|request| DelegatedNetworksRequest { request })
667 .map(NetworkRequest::DelegatedNetworks)
668 })
669 }
670 }
671 }
672}
673
674impl futures::Stream for NetpolNetworksService {
675 type Item = NetworkRequest;
676
677 fn poll_next(
678 mut self: std::pin::Pin<&mut Self>,
679 cx: &mut std::task::Context<'_>,
680 ) -> std::task::Poll<Option<Self::Item>> {
681 self.streams.poll_next_unpin(cx)
682 }
683}
684
685impl futures::stream::FusedStream for NetpolNetworksService {
686 fn is_terminated(&self) -> bool {
687 self.streams.is_terminated()
688 }
689}
690
691#[derive(Default)]
692pub struct NetpolNetworksService {
693 current_generation: UpdateGeneration,
695 generations_by_connection: UpdateGenerations,
697 default_network_responders:
699 HashMap<ConnectionId, fnp_properties::NetworksWatchDefaultResponder>,
700 tokens: token_registry::TokenRegistry<NetworkTokenContents>,
701 property_responders: HashMap<ConnectionId, NetworkPropertyResponder>,
703 network_registry: RegisteredNetworks,
705 telemetry: Option<TelemetrySender>,
706 next_networks_id: ConnectionId,
707 streams: futures::stream::SelectAll<NetworkRequestStreamInner>,
708}
709
710impl NetpolNetworksService {
711 pub fn set_telemetry(&mut self, telemetry: TelemetrySender) {
712 self.telemetry = Some(telemetry);
713 }
714
715 pub fn add_stream<S: Into<NetworkRequestStream>>(&mut self, s: S) {
716 match s.into() {
717 NetworkRequestStream::Networks(stream) => {
718 self.streams.push(NetworkRequestStreamInner::Networks(
719 stream.tagged(self.next_networks_id),
720 ));
721 self.next_networks_id.increment();
722 }
723 NetworkRequestStream::NetworkTokenResolver(stream) => {
724 self.streams.push(NetworkRequestStreamInner::NetworkTokenResolver(stream));
725 }
726 NetworkRequestStream::DelegatedNetworks(stream) => {
727 self.streams.push(NetworkRequestStreamInner::DelegatedNetworks(stream));
728 }
729 }
730 }
731
732 pub async fn handle_event(
733 &mut self,
734 event: NetworkRequest,
735 ) -> Result<DelegatedNetworkUpdateResult, anyhow::Error> {
736 match event {
737 NetworkRequest::NetworkAttributes(NetworkAttributesRequest { id, request }) => {
738 self.handle_network_attributes_request(id, request).await?;
739 Ok(DelegatedNetworkUpdateResult { dns_servers: None })
740 }
741 NetworkRequest::NetworkTokenResolver(NetworkTokenResolverRequest { request }) => {
742 self.handle_network_token_resolver_request(request).await?;
743 Ok(DelegatedNetworkUpdateResult { dns_servers: None })
744 }
745 NetworkRequest::DelegatedNetworks(DelegatedNetworksRequest { request }) => {
746 self.handle_delegated_networks_update(request).await
747 }
748 }
749 }
750
751 pub fn consolidated_dns_servers(&self) -> Vec<fnet_name::DnsServer_> {
753 self.network_registry.consolidated_dns_servers()
754 }
755
756 pub async fn handle_network_attributes_request(
757 &mut self,
758 id: ConnectionId,
759 req: Result<fnp_properties::NetworksRequest, fidl::Error>,
760 ) -> Result<(), anyhow::Error> {
761 let req = req.context("network attributes request")?;
762 match req {
763 fnp_properties::NetworksRequest::WatchDefault { responder } => {
764 match self.default_network_responders.entry(id) {
765 std::collections::hash_map::Entry::Occupied(_) => {
766 warn!(
767 "Only one call to fuchsia.net.policy.properties/Networks.WatchDefault \
768 may be active per connection"
769 );
770 responder
771 .control_handle()
772 .shutdown_with_epitaph(zx::Status::CONNECTION_ABORTED)
773 }
774 std::collections::hash_map::Entry::Vacant(vacant_entry) => {
775 let network_id = if self
776 .generations_by_connection
777 .default_network(&id)
778 .unwrap_or_default()
779 < self.current_generation.default_network
780 {
781 self.network_registry.default_network
782 } else {
783 None
784 };
785 if let Some(network_id) = network_id {
786 self.generations_by_connection
787 .set_default_network(id, self.current_generation);
788 let token = self
789 .tokens
790 .ensure_token(NetworkTokenContents { network_id, is_default: true })
791 .get()
792 .duplicate()
793 .context("could not duplicate token")?;
794 responder.send(
795 fnp_properties::NetworksWatchDefaultResponse::Network(token),
796 )?;
797
798 if let Some(responder) = self.property_responders.remove(&id) {
799 let _: Option<_> = self.generations_by_connection.remove(&id);
800 let _: Result<(), fidl::Error> =
801 responder.respond(Err(fnp_properties::WatchError::NetworkGone));
802 }
803 } else {
804 let _: &mut _ = vacant_entry.insert(responder);
805 }
806 }
807 }
808 }
809 fnp_properties::NetworksRequest::WatchProperties {
810 payload: fnp_properties::NetworksWatchPropertiesRequest { network, properties, .. },
811 responder,
812 } => match (network, properties) {
813 (None, _) | (_, None) => {
814 responder.send(Err(fnp_properties::WatchError::MissingRequiredArgument))?
815 }
816 (Some(network), Some(properties)) => {
817 if properties.is_empty() {
818 responder.send(Err(fnp_properties::WatchError::NoProperties))?;
819 } else {
820 match self.property_responders.entry(id) {
821 std::collections::hash_map::Entry::Occupied(_) => {
822 warn!(
823 "Only one call to \
824 fuchsia.net.policy.properties/Networks.WatchProperties may be \
825 active per connection"
826 );
827 responder
828 .control_handle()
829 .shutdown_with_epitaph(zx::Status::CONNECTION_ABORTED)
830 }
831 std::collections::hash_map::Entry::Vacant(vacant_entry) => {
832 match self.tokens.get_contents(&network) {
833 Err(e) => {
834 warn!("Unknown network token. ({network:?}: {e})");
835 responder.send(Err(
836 fnp_properties::WatchError::InvalidNetworkToken,
837 ))?;
838 }
839 Ok(network_contents) => {
840 let responder = NetworkPropertyResponder {
841 token: network,
842 watched_properties: properties,
843 responder,
844 };
845 if self
846 .generations_by_connection
847 .properties(&id)
848 .unwrap_or_default()
849 < self.current_generation.properties
850 {
851 self.generations_by_connection
852 .set_properties(id, self.current_generation);
853 if let Some(responder) = self
854 .network_registry
855 .maybe_respond(&network_contents, responder)
856 {
857 let _: &mut NetworkPropertyResponder =
858 vacant_entry.insert(responder);
859 }
860 } else {
861 let _: &mut NetworkPropertyResponder =
862 vacant_entry.insert(responder);
863 }
864 }
865 }
866 }
867 }
868 }
869 }
870 },
871 _ => {
872 warn!("Received unexpected request {req:?}");
873 }
874 }
875
876 Ok(())
877 }
878
879 pub async fn handle_delegated_networks_update(
888 &mut self,
889 update: Result<fnp_socketproxy::NetworkRegistryRequest, fidl::Error>,
890 ) -> Result<DelegatedNetworkUpdateResult, anyhow::Error> {
891 use fnp_socketproxy::{
892 NetworkInfo, NetworkRegistryAddError, NetworkRegistryRemoveError,
893 NetworkRegistryRequest, NetworkRegistrySetDefaultError, NetworkRegistryUpdateError,
894 };
895
896 let action_result = match update {
897 Err(e) => {
898 error!(
899 "Encountered error watching for delegated network \
900 updates: {e:?}"
901 );
902 return Err(anyhow::anyhow!(e));
903 }
904 Ok(NetworkRegistryRequest::SetDefault { network_id, responder }) => {
905 let update_result = match network_id {
906 fposix_socket::OptionalUint32::Value(interface_id) => {
907 match InterfaceId::try_from(interface_id) {
908 Ok(id) => {
909 let delegated_id = NetworkId::delegated(id);
910 self.update(PropertyUpdate::ChangeNetwork(
911 delegated_id,
912 NetworkUpdate::MakeDefault,
913 ))
914 .await;
915 Ok(())
916 }
917 Err(_) => Err(NetworkRegistrySetDefaultError::NotFound),
918 }
919 }
920 fposix_socket::OptionalUint32::Unset(_) => {
921 self.update(PropertyUpdate::default_network_lost()).await;
922 Ok(())
923 }
924 };
925
926 self.respond_to_delegated_network_update(
927 update_result,
928 |reply| responder.send(reply),
929 "failed to send SetDefault result",
930 )
931 }
932 Ok(NetworkRegistryRequest::Add { network, responder }) => {
933 let extracted_properties = (|| {
934 let raw_network_id =
935 network.network_id.ok_or(NetworkRegistryAddError::MissingNetworkId)?;
936 let network_id = InterfaceId::try_from(raw_network_id)
937 .map(|id| NetworkId::delegated(id))
938 .map_err(|_| NetworkRegistryAddError::MissingNetworkId)?;
939 let NetworkInfo::Starnix(info) =
940 network.info.ok_or(NetworkRegistryAddError::MissingNetworkInfo)?
941 else {
942 return Err(NetworkRegistryAddError::MissingNetworkInfo);
943 };
944
945 let mut marks = fnet::Marks::default();
946 marks.set_mark(fnet::MARK_DOMAIN_SO_MARK, info.mark);
947
948 let dns_servers =
949 Self::extract_dns_servers(&network.dns_servers, raw_network_id.into());
950
951 Ok((network_id, marks, dns_servers))
952 })();
953
954 let update_result = match extracted_properties {
955 Ok((network_id, marks, dns_servers)) => {
956 self.update(PropertyUpdate::ChangeNetwork(
957 network_id,
958 NetworkUpdate::Properties(NetworkPropertiesChange {
959 added: true,
960 marks: Some(marks),
961 dns_servers: Some(dns_servers.clone()),
962 connectivity_state: network.connectivity,
963 name: network.name,
964 network_type: network.network_type,
965 }),
966 ))
967 .await;
968 Ok(())
969 }
970 Err(e) => Err(e),
971 };
972
973 self.respond_to_delegated_network_update(
974 update_result,
975 |reply| responder.send(reply),
976 "failed to send Add result",
977 )
978 }
979 Ok(NetworkRegistryRequest::Update { network, responder }) => {
980 let extracted_properties = (|| {
981 let raw_network_id =
982 network.network_id.ok_or(NetworkRegistryUpdateError::MissingNetworkId)?;
983 let network_id = InterfaceId::try_from(raw_network_id)
984 .map(|id| NetworkId::delegated(id))
985 .map_err(|_| NetworkRegistryUpdateError::MissingNetworkId)?;
986 let NetworkInfo::Starnix(info) =
987 network.info.ok_or(NetworkRegistryUpdateError::MissingNetworkInfo)?
988 else {
989 return Err(NetworkRegistryUpdateError::MissingNetworkInfo);
990 };
991
992 let mut marks = fnet::Marks::default();
993 marks.set_mark(fnet::MARK_DOMAIN_SO_MARK, info.mark);
994
995 let dns_servers =
996 Self::extract_dns_servers(&network.dns_servers, raw_network_id.into());
997
998 Ok((network_id, marks, dns_servers))
999 })();
1000
1001 let update_result = match extracted_properties {
1002 Ok((network_id, marks, dns_servers)) => {
1003 self.update(PropertyUpdate::ChangeNetwork(
1004 network_id,
1005 NetworkUpdate::Properties(NetworkPropertiesChange {
1006 added: false,
1007 marks: Some(marks),
1008 dns_servers: Some(dns_servers.clone()),
1009 connectivity_state: network.connectivity,
1010 name: network.name,
1011 network_type: network.network_type,
1012 }),
1013 ))
1014 .await;
1015 Ok(())
1016 }
1017 Err(e) => Err(e),
1018 };
1019
1020 self.respond_to_delegated_network_update(
1021 update_result,
1022 |reply| responder.send(reply),
1023 "failed to send Update result",
1024 )
1025 }
1026 Ok(NetworkRegistryRequest::Remove { network_id, responder }) => {
1027 let update_result = match InterfaceId::try_from(network_id) {
1028 Ok(id) => {
1029 let delegated_id = NetworkId::delegated(id);
1030 self.update(PropertyUpdate::ChangeNetwork(
1031 delegated_id,
1032 NetworkUpdate::Remove,
1033 ))
1034 .await;
1035 Ok(())
1036 }
1037 Err(_) => Err(NetworkRegistryRemoveError::NotFound),
1038 };
1039
1040 self.respond_to_delegated_network_update(
1041 update_result,
1042 |reply| responder.send(reply),
1043 "failed to send Remove result",
1044 )
1045 }
1046 };
1047
1048 Ok(action_result)
1049 }
1050
1051 fn respond_to_delegated_network_update<E, F>(
1054 &self,
1055 operation_result: Result<(), E>,
1056 send_response: F,
1057 context_message: &'static str,
1058 ) -> DelegatedNetworkUpdateResult
1059 where
1060 F: FnOnce(Result<(), E>) -> Result<(), fidl::Error>,
1061 {
1062 let dns_servers = operation_result
1064 .as_ref()
1065 .ok()
1066 .map(|()| self.network_registry.consolidated_dns_servers());
1067
1068 if let Err(e) = send_response(operation_result) {
1070 if !e.is_closed() {
1071 error!(
1072 "Failed to send delegated network update result \
1073 for {context_message}: {e}"
1074 );
1075 }
1076 }
1077
1078 DelegatedNetworkUpdateResult { dns_servers }
1079 }
1080
1081 fn extract_dns_servers(
1086 dns_servers: &Option<fnp_socketproxy::NetworkDnsServers>,
1087 network_id: u64,
1088 ) -> Vec<fnet_name::DnsServer_> {
1089 let make_server = |address| fnet_name::DnsServer_ {
1090 address: Some(address),
1091 source: Some(fnet_name::DnsServerSource::SocketProxy(
1092 fnet_name::SocketProxyDnsServerSource {
1093 source_interface: Some(network_id),
1094 ..Default::default()
1095 },
1096 )),
1097 ..Default::default()
1098 };
1099
1100 dns_servers
1101 .as_ref()
1102 .map(|dns| {
1103 dns.v4
1104 .as_ref()
1105 .into_iter()
1106 .flatten()
1107 .map(|&address| {
1108 make_server(fnet::SocketAddress::Ipv4(fnet::Ipv4SocketAddress {
1109 address,
1110 port: DNS_PORT,
1111 }))
1112 })
1113 .chain(dns.v6.as_ref().into_iter().flatten().map(|&address| {
1114 make_server(fnet::SocketAddress::Ipv6(fnet::Ipv6SocketAddress {
1115 address,
1116 port: DNS_PORT,
1117 zone_index: 0,
1118 }))
1119 }))
1120 .collect()
1121 })
1122 .unwrap_or_default()
1123 }
1124
1125 pub(crate) async fn handle_network_token_resolver_request(
1126 &mut self,
1127 request: Result<fnp_properties::NetworkTokenResolverRequest, fidl::Error>,
1128 ) -> Result<(), anyhow::Error> {
1129 use fnp_properties::NetworkTokenResolverResolveTokenError as ResolveTokenError;
1130
1131 let request = request.context("while handling NetworkTokenResolver request")?;
1132 match request {
1133 fnp_properties::NetworkTokenResolverRequest::ResolveToken { token, responder } => {
1134 let maybe_contents = self.tokens.get_contents(&token).copied();
1135 match maybe_contents {
1136 Err(e) => {
1137 warn!("Unknown network token. ({token:?}: {e})");
1138 responder.send(Err(ResolveTokenError::InvalidNetworkToken))?;
1139 }
1140 Ok(contents) => {
1141 if contents.is_default {
1142 let query = NetworkTokenContents { is_default: false, ..contents };
1145 if let Some(tok) = self.tokens.get_token(&query) {
1146 responder.send(tok.duplicate().map_err(|e| {
1147 warn!("Encountered issue duplicating generated token. {e}");
1148 ResolveTokenError::InvalidNetworkToken
1149 }))?;
1150 } else {
1151 warn!("Requested canonical version of unregistered network.");
1152 responder.send(Err(ResolveTokenError::InvalidNetworkToken))?;
1153 }
1154 } else {
1155 responder.send(Ok(token))?;
1156 }
1157 }
1158 }
1159 }
1160 fidl_fuchsia_net_policy_properties::NetworkTokenResolverRequest::_UnknownMethod {
1161 ordinal,
1162 control_handle,
1163 method_type,
1164 ..
1165 } => warn!(
1166 "Encountered unknown method call on NetworkTokenResolver: {ordinal} \
1167 {control_handle:?} {method_type:?}"
1168 ),
1169 }
1170
1171 Ok(())
1172 }
1173
1174 async fn changed_default_network(
1175 &mut self,
1176 previous_default_network: Option<NetworkId>,
1177 responders: &mut HashMap<ConnectionId, NetworkPropertyResponder>,
1178 ) {
1179 let mut r = HashMap::new();
1180 std::mem::swap(&mut r, responders);
1181 r = r
1182 .into_iter()
1183 .filter_map(|(id, responder)| {
1184 match self.tokens.get_contents(&responder.token) {
1185 Ok(contents) => {
1186 if contents.is_default {
1188 let _: Option<_> = self.generations_by_connection.remove(&id);
1189 let _: Result<(), fidl::Error> =
1190 responder.respond(Err(fnp_properties::WatchError::NetworkGone));
1191 return None;
1192 }
1193 }
1194 Err(zx::Status::NOT_FOUND) => {
1195 warn!("Token provided to get_contents is not valid.");
1196 }
1197 Err(e) => {
1198 warn!("Encountered unknown issue while getting contents: {e}");
1199 }
1200 }
1201 Some((id, responder))
1202 })
1203 .collect::<HashMap<_, _>>();
1204 std::mem::swap(&mut r, responders);
1205 self.tokens.drop_if(|&c| {
1206 c.is_default && previous_default_network.is_some_and(|i| i == c.network_id)
1207 });
1208 }
1209
1210 pub(crate) async fn remove_network(&mut self, network_id: NetworkId) {
1211 info!("Removing interface {network_id}. Reporting NETWORK_GONE to all clients.");
1212 let mut responders = HashMap::new();
1213 std::mem::swap(&mut self.property_responders, &mut responders);
1214 for (id, responder) in responders {
1215 let network = match self.tokens.get_contents(&responder.token) {
1216 Ok(network) => network,
1217 Err(e) => {
1218 warn!("Could not fetch network data for responder: {e}");
1219 continue;
1220 }
1221 };
1222 if network.network_id == network_id {
1223 if let Err(e) = responder.respond(Err(fnp_properties::WatchError::NetworkGone)) {
1225 warn!("Could not send to responder: {e}");
1226 }
1227 } else {
1228 if self.property_responders.insert(id, responder).is_some() {
1229 error!("Re-inserted in an existing responder slot. This should be impossible.");
1230 }
1231 }
1232 }
1233 }
1234
1235 pub async fn update(&mut self, update: PropertyUpdate) {
1236 self.current_generation.properties += 1;
1237 let RegistryUpdateResult { event, default_changed } = self.network_registry.apply(update);
1238
1239 if let UpdateApplied::None = event {
1240 if default_changed.is_none() {
1241 return;
1243 }
1244 }
1245
1246 let mut property_responders = HashMap::new();
1247 std::mem::swap(&mut self.property_responders, &mut property_responders);
1248
1249 match event {
1251 UpdateApplied::NetworkChanged { network_id, added: true, .. } => {
1252 let _ = self
1253 .tokens
1254 .ensure_token(NetworkTokenContents { network_id, is_default: false });
1255 }
1256 UpdateApplied::NetworkRemoved(network_id) => {
1257 self.tokens.drop_if(|c| !c.is_default && c.network_id == network_id);
1258 }
1259 UpdateApplied::NetworkChanged { added: false, .. }
1260 | UpdateApplied::DnsChanged
1261 | UpdateApplied::None => {}
1262 }
1263
1264 if let Some(DefaultChangedEvent { previous_default }) = default_changed {
1266 self.notify_default_network_changed(previous_default, &mut property_responders).await;
1267 return;
1268 }
1269
1270 if let UpdateApplied::NetworkChanged { network_id, .. } = event {
1271 if let Some(telemetry) = &self.telemetry {
1272 if let Some(props) = self.network_registry.networks.get(&network_id) {
1273 telemetry.send(TelemetryEvent::NetworkChanged(NetworkEventMetadata {
1274 id: network_id.get().get(),
1275 name: props.name.clone(),
1276 transport: props
1277 .network_type
1278 .unwrap_or(fnp_socketproxy::NetworkType::Unknown),
1279 is_fuchsia_provisioned: network_id.is_fuchsia(),
1280 connectivity_state: props.connectivity_state,
1281 }));
1282 }
1283 }
1284 }
1285
1286 for (id, responder) in property_responders {
1287 let mut updates = Vec::new();
1288 let network = match self.tokens.get_contents(&responder.token) {
1289 Ok(network) => network,
1290 Err(e) => {
1291 warn!("Could not fetch network data for responder: {e}");
1292 continue;
1293 }
1294 };
1295
1296 if let UpdateApplied::NetworkChanged {
1297 network_id, changed_marks, changed_dns, ..
1298 } = event
1299 {
1300 if network.network_id == network_id {
1301 if changed_marks {
1302 updates.add_socket_marks(&self.network_registry, &network, &responder);
1303 }
1304 if changed_dns {
1305 updates.add_dns(&self.network_registry, &network, &responder);
1306 }
1307 }
1308 }
1309 if let UpdateApplied::DnsChanged = event {
1310 updates.add_dns(&self.network_registry, &network, &responder);
1311 }
1312
1313 self.generations_by_connection.set_properties(id, self.current_generation);
1314 if updates.is_empty() {
1315 if self.property_responders.insert(id, responder).is_some() {
1316 warn!("Re-inserted in an existing responder slot. This should be impossible.");
1317 }
1318 } else {
1319 if let Err(e) = responder.respond(Ok(&updates)) {
1320 warn!("Could not send to responder: {e}");
1321 }
1322 }
1323 }
1324 }
1325
1326 async fn notify_default_network_changed(
1327 &mut self,
1328 old_default: Option<NetworkId>,
1329 property_responders: &mut HashMap<ConnectionId, NetworkPropertyResponder>,
1330 ) {
1331 self.changed_default_network(old_default, property_responders).await;
1332 match self.network_registry.default_network {
1333 Some(default_network) => {
1334 if let Some(telemetry) = &self.telemetry {
1335 if let Some(props) = self.network_registry.networks.get(&default_network) {
1336 telemetry.send(TelemetryEvent::DefaultNetworkChanged(
1337 NetworkEventMetadata {
1338 id: default_network.get().get(),
1339 name: props.name.clone(),
1340 transport: props
1341 .network_type
1342 .unwrap_or(fnp_socketproxy::NetworkType::Unknown),
1343 is_fuchsia_provisioned: default_network.is_fuchsia(),
1344 connectivity_state: props.connectivity_state,
1345 },
1346 ));
1347 } else {
1348 warn!("Could not fetch network data for default network.");
1349 }
1350 }
1351 self.current_generation.default_network += 1;
1352 let mut responders = HashMap::new();
1353 std::mem::swap(&mut self.default_network_responders, &mut responders);
1354 for (id, responder) in responders {
1355 self.generations_by_connection.set_default_network(id, self.current_generation);
1356 match self
1357 .tokens
1358 .ensure_token(NetworkTokenContents {
1359 network_id: default_network,
1360 is_default: true,
1361 })
1362 .get()
1363 .duplicate()
1364 {
1365 Ok(token) => {
1366 if let Err(e) = responder
1367 .send(fnp_properties::NetworksWatchDefaultResponse::Network(token))
1368 {
1369 warn!("Could not send to responder: {e}");
1370 }
1371 }
1372 Err(e) => warn!("Could not duplicate token: {e}"),
1373 };
1374 }
1375 }
1376 None => {
1377 if let Some(telemetry) = &self.telemetry {
1378 telemetry.send(TelemetryEvent::DefaultNetworkLost);
1379 }
1380 self.current_generation.default_network += 1;
1382 let mut responders = HashMap::new();
1383 std::mem::swap(&mut self.default_network_responders, &mut responders);
1384 for (id, responder) in responders {
1385 self.generations_by_connection.set_default_network(id, self.current_generation);
1386 if let Err(e) = responder.send(
1387 fnp_properties::NetworksWatchDefaultResponse::NoDefaultNetwork(
1388 fnp_properties::Empty,
1389 ),
1390 ) {
1391 warn!("Could not send to responder: {e}");
1392 }
1393 }
1394 }
1395 }
1396 }
1397}
1398
1399pub struct ConnectionTagged<Stream: futures::Stream + Unpin> {
1400 next_id: ConnectionId,
1401 streams: futures::stream::SelectAll<Tagged<ConnectionId, Stream>>,
1402}
1403
1404impl<Stream: futures::Stream + Unpin> Default for ConnectionTagged<Stream> {
1405 fn default() -> Self {
1406 Self { next_id: Default::default(), streams: Default::default() }
1407 }
1408}
1409
1410impl<Stream: futures::Stream + Unpin> ConnectionTagged<Stream> {
1411 pub fn push(&mut self, stream: Stream) {
1412 self.streams.push(stream.tagged(self.next_id));
1413 self.next_id.0 += 1;
1414 }
1415}
1416
1417impl<Stream: futures::Stream + Unpin> futures::Stream for ConnectionTagged<Stream> {
1418 type Item = (ConnectionId, <Stream as futures::Stream>::Item);
1419
1420 fn poll_next(
1421 mut self: std::pin::Pin<&mut Self>,
1422 cx: &mut std::task::Context<'_>,
1423 ) -> std::task::Poll<Option<Self::Item>> {
1424 std::pin::Pin::new(&mut self.streams).poll_next(cx)
1425 }
1426}
1427
1428impl<Stream: futures::Stream + Unpin> futures::stream::FusedStream for ConnectionTagged<Stream> {
1429 fn is_terminated(&self) -> bool {
1430 self.streams.is_terminated()
1431 }
1432}
1433
1434#[cfg(test)]
1435mod tests {
1436 use super::*;
1437 use assert_matches::assert_matches;
1438 use std::num::NonZeroU64;
1439 use test_case::test_case;
1440
1441 const ID_1: InterfaceId = InterfaceId(NonZeroU64::new(1).unwrap());
1442 const ID_2: InterfaceId = InterfaceId(NonZeroU64::new(2).unwrap());
1443 const NAME_1: &str = "testif1";
1444 const NAME_2: &str = "testif2";
1445
1446 const FUCHSIA_ID_1: NetworkId = NetworkId::Fuchsia(ID_1);
1447 const FUCHSIA_ID_2: NetworkId = NetworkId::Fuchsia(ID_2);
1448 const DELEGATED_ID_1: NetworkId = NetworkId::Delegated(ID_1);
1449 const DELEGATED_ID_2: NetworkId = NetworkId::Delegated(ID_2);
1450
1451 #[derive(Clone, Copy)]
1452 struct TestNetwork {
1453 id: NetworkId,
1454 name: &'static str,
1455 network_type: fnp_socketproxy::NetworkType,
1456 }
1457
1458 #[derive(Default)]
1459 struct AppliedChanges {
1460 added: bool,
1461 changed_marks: bool,
1462 changed_dns: bool,
1463 }
1464
1465 impl TestNetwork {
1466 fn added(&self, added: bool) -> NetworkPropertiesChange {
1467 NetworkPropertiesChange {
1468 added,
1469 name: Some(self.name.to_string()),
1470 network_type: Some(self.network_type),
1471 ..Default::default()
1472 }
1473 }
1474
1475 fn change_with(
1476 &self,
1477 added: bool,
1478 marks: Option<fnet::Marks>,
1479 dns_servers: Option<Vec<fnet_name::DnsServer_>>,
1480 connectivity_state: Option<fnp_socketproxy::ConnectivityState>,
1481 ) -> NetworkPropertiesChange {
1482 NetworkPropertiesChange {
1483 added,
1484 marks,
1485 dns_servers,
1486 connectivity_state,
1487 name: Some(self.name.to_string()),
1488 network_type: Some(self.network_type),
1489 }
1490 }
1491
1492 fn applied(&self, changes: AppliedChanges) -> UpdateApplied {
1493 let AppliedChanges { added, changed_marks, changed_dns } = changes;
1494 UpdateApplied::NetworkChanged {
1495 network_id: self.id,
1496 added,
1497 changed_marks,
1498 changed_dns,
1499 name: Some(self.name.to_string()),
1500 network_type: Some(self.network_type),
1501 }
1502 }
1503 }
1504
1505 const DELEGATED_NET_1: TestNetwork = TestNetwork {
1506 id: DELEGATED_ID_1,
1507 name: NAME_1,
1508 network_type: fnp_socketproxy::NetworkType::Ethernet,
1509 };
1510 const FUCHSIA_NET_1: TestNetwork = TestNetwork {
1511 id: FUCHSIA_ID_1,
1512 name: NAME_1,
1513 network_type: fnp_socketproxy::NetworkType::Ethernet,
1514 };
1515 const FUCHSIA_NET_2: TestNetwork = TestNetwork {
1516 id: FUCHSIA_ID_2,
1517 name: NAME_2,
1518 network_type: fnp_socketproxy::NetworkType::Wifi,
1519 };
1520
1521 fn test_marks() -> fnet::Marks {
1522 fnet::Marks { mark_1: Some(123), ..Default::default() }
1523 }
1524
1525 fn test_marks_updated() -> fnet::Marks {
1526 fnet::Marks { mark_1: Some(456), ..Default::default() }
1527 }
1528
1529 fn test_dns_1() -> Vec<fnet_name::DnsServer_> {
1530 vec![fnet_name::DnsServer_ {
1531 address: Some(net_declare::fidl_socket_addr!("192.0.2.1:53")),
1532 ..Default::default()
1533 }]
1534 }
1535
1536 fn test_dns_2() -> Vec<fnet_name::DnsServer_> {
1537 vec![fnet_name::DnsServer_ {
1538 address: Some(net_declare::fidl_socket_addr!("192.0.2.2:53")),
1539 ..Default::default()
1540 }]
1541 }
1542
1543 fn delegated_properties() -> NetworkProperties {
1544 NetworkProperties { socket_marks: Some(test_marks()), ..Default::default() }
1545 }
1546
1547 fn fuchsia_properties() -> NetworkProperties {
1548 NetworkProperties::default()
1549 }
1550
1551 fn added_properties(name: &str) -> NetworkPropertiesChange {
1552 NetworkPropertiesChange {
1553 added: true,
1554 marks: None,
1555 dns_servers: None,
1556 connectivity_state: None,
1557 name: Some(name.to_string()),
1558 network_type: Some(fnp_socketproxy::NetworkType::Ethernet),
1559 }
1560 }
1561
1562 impl NetpolNetworksService {
1563 pub(crate) fn default_network(&self) -> Option<NetworkId> {
1564 self.network_registry.default_network
1565 }
1566
1567 pub(crate) fn has_network(&self, id: NetworkId) -> bool {
1568 self.network_registry.networks.contains_key(&id)
1569 }
1570
1571 pub(crate) fn has_token(&self, network_id: NetworkId, is_default: bool) -> bool {
1572 self.tokens.get_token(&NetworkTokenContents { network_id, is_default }).is_some()
1573 }
1574
1575 pub(crate) fn ensure_token_for_test(&mut self, network_id: NetworkId, is_default: bool) {
1576 let _token: crate::network::token_registry::TokenEntry<'_, _> =
1577 self.tokens.ensure_token(NetworkTokenContents { network_id, is_default });
1578 }
1579 }
1580
1581 #[test_case(
1582 DELEGATED_NET_1,
1583 Some(test_marks()),
1584 Some(test_marks_updated()); "delegated network"
1585 )]
1586 #[test_case(FUCHSIA_NET_2, None, None; "fuchsia network")]
1587 fn test_handle_changed_network(
1588 net: TestNetwork,
1589 initial_marks: Option<fnet::Marks>,
1590 updated_marks: Option<fnet::Marks>,
1591 ) {
1592 let mut networks = RegisteredNetworks::default();
1593 let dns1 = test_dns_1();
1594 let dns2 = test_dns_2();
1595
1596 let event = net.change_with(
1598 true,
1599 initial_marks.clone(),
1600 Some(dns1.clone()),
1601 Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
1602 );
1603 assert_eq!(
1604 networks.handle_changed_network(net.id, event),
1605 net.applied(AppliedChanges { added: true, changed_marks: true, changed_dns: true }),
1606 );
1607 assert_eq!(
1608 networks.networks.get(&net.id).expect("network should be present"),
1609 &NetworkProperties {
1610 socket_marks: initial_marks.clone(),
1611 dns_servers: dns1,
1612 connectivity_state: Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
1613 name: Some(net.name.to_string()),
1614 network_type: Some(net.network_type),
1615 }
1616 );
1617
1618 let event = net.change_with(
1621 false,
1622 initial_marks.clone(),
1623 Some(dns2.clone()),
1624 Some(fnp_socketproxy::ConnectivityState::NoConnectivity),
1625 );
1626 assert_eq!(
1627 networks.handle_changed_network(net.id, event),
1628 net.applied(AppliedChanges { added: false, changed_marks: false, changed_dns: true }),
1629 );
1630 assert_eq!(
1631 networks.networks.get(&net.id).expect("network should be present"),
1632 &NetworkProperties {
1633 socket_marks: initial_marks.clone(),
1634 dns_servers: dns2.clone(),
1635 connectivity_state: Some(fnp_socketproxy::ConnectivityState::NoConnectivity),
1636 name: Some(net.name.to_string()),
1637 network_type: Some(net.network_type),
1638 }
1639 );
1640
1641 let marks_changed = initial_marks != updated_marks;
1643 let event = net.change_with(
1644 false,
1645 updated_marks.clone(),
1646 Some(dns2.clone()),
1647 Some(fnp_socketproxy::ConnectivityState::NoConnectivity),
1648 );
1649 assert_eq!(
1650 networks.handle_changed_network(net.id, event),
1651 net.applied(AppliedChanges {
1652 added: false,
1653 changed_marks: marks_changed,
1654 changed_dns: false,
1655 }),
1656 );
1657 assert_eq!(
1658 networks.networks.get(&net.id).expect("network should be present"),
1659 &NetworkProperties {
1660 socket_marks: updated_marks,
1661 dns_servers: dns2.clone(),
1662 connectivity_state: Some(fnp_socketproxy::ConnectivityState::NoConnectivity),
1663 name: Some(net.name.to_string()),
1664 network_type: Some(net.network_type),
1665 }
1666 );
1667 }
1668
1669 #[test]
1670 fn test_handle_changed_network_validation() {
1671 let mut networks = RegisteredNetworks::default();
1672 let marks = test_marks();
1673 let net = DELEGATED_NET_1;
1674
1675 let event = NetworkPropertiesChange { marks: Some(marks.clone()), ..net.added(false) };
1677 assert_eq!(networks.handle_changed_network(net.id, event), UpdateApplied::None);
1678
1679 let event = NetworkPropertiesChange { marks: Some(marks.clone()), ..net.added(true) };
1681 assert_eq!(
1682 networks.handle_changed_network(net.id, event),
1683 net.applied(AppliedChanges { added: true, changed_marks: true, changed_dns: true }),
1684 );
1685
1686 let event = NetworkPropertiesChange { marks: Some(marks.clone()), ..net.added(true) };
1688 assert_eq!(networks.handle_changed_network(net.id, event), UpdateApplied::None);
1689
1690 let fuchsia_net = FUCHSIA_NET_1;
1692 let event =
1693 NetworkPropertiesChange { marks: Some(marks.clone()), ..fuchsia_net.added(true) };
1694 assert_eq!(networks.handle_changed_network(fuchsia_net.id, event), UpdateApplied::None);
1695
1696 let event = net.added(true);
1698 assert_eq!(networks.handle_changed_network(net.id, event), UpdateApplied::None);
1699 }
1700
1701 #[test]
1704 fn fallback_election_and_prioritization() {
1705 let mut networks = RegisteredNetworks::default();
1706
1707 assert_eq!(networks.calculate_active_default(), None);
1709
1710 let _ = networks.networks.insert(DELEGATED_ID_1, delegated_properties());
1712 networks.starnix_default = Some(DELEGATED_ID_1);
1713 assert_eq!(
1714 networks.handle_default_network_update(),
1715 Some(DefaultChangedEvent { previous_default: None })
1716 );
1717 assert_eq!(networks.default_network, Some(DELEGATED_ID_1));
1718
1719 let _ = networks.networks.insert(DELEGATED_ID_2, delegated_properties());
1722 networks.starnix_default = Some(DELEGATED_ID_2);
1723 assert_eq!(
1724 networks.handle_default_network_update(),
1725 Some(DefaultChangedEvent { previous_default: Some(DELEGATED_ID_1) })
1726 );
1727 assert_eq!(networks.default_network, Some(DELEGATED_ID_2));
1728
1729 let _ = networks.networks.insert(FUCHSIA_ID_2, fuchsia_properties());
1732 assert_eq!(
1733 networks.handle_default_network_update(),
1734 Some(DefaultChangedEvent { previous_default: Some(DELEGATED_ID_2) })
1735 );
1736 assert_eq!(networks.default_network, Some(FUCHSIA_ID_2));
1737
1738 let _ = networks.networks.insert(FUCHSIA_ID_1, fuchsia_properties());
1741 assert_eq!(
1742 networks.handle_default_network_update(),
1743 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_2) })
1744 );
1745 assert_eq!(networks.default_network, Some(FUCHSIA_ID_1));
1746
1747 let _ = networks.networks.remove(&FUCHSIA_ID_1);
1749 assert_eq!(
1750 networks.handle_default_network_update(),
1751 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_1) })
1752 );
1753 assert_eq!(networks.default_network, Some(FUCHSIA_ID_2));
1754
1755 let _ = networks.networks.remove(&FUCHSIA_ID_2);
1758 assert_eq!(
1759 networks.handle_default_network_update(),
1760 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_2) })
1761 );
1762 assert_eq!(networks.default_network, Some(DELEGATED_ID_2));
1763
1764 assert_eq!(
1766 networks.apply(PropertyUpdate::LoseDefaultNetwork),
1767 RegistryUpdateResult {
1768 event: UpdateApplied::None,
1769 default_changed: Some(DefaultChangedEvent {
1770 previous_default: Some(DELEGATED_ID_2)
1771 })
1772 }
1773 );
1774 assert_eq!(networks.default_network, None);
1775
1776 assert_eq!(
1778 networks.apply(PropertyUpdate::ChangeNetwork(DELEGATED_ID_1, NetworkUpdate::Remove)),
1779 RegistryUpdateResult {
1780 event: UpdateApplied::NetworkRemoved(DELEGATED_ID_1),
1781 default_changed: None
1782 }
1783 );
1784 }
1785
1786 #[test]
1790 fn test_remove_fuchsia_network_fallback() {
1791 let mut networks = RegisteredNetworks::default();
1792 let marks = test_marks();
1793 let fuchsia_added = NetworkPropertiesChange { added: true, ..Default::default() };
1794
1795 let result = networks.apply(PropertyUpdate::ChangeNetwork(
1797 FUCHSIA_ID_1,
1798 NetworkUpdate::Properties(fuchsia_added.clone()),
1799 ));
1800 assert_matches!(
1801 result.event,
1802 UpdateApplied::NetworkChanged { network_id: id, added: true, .. }
1803 if id == FUCHSIA_ID_1
1804 );
1805 assert_eq!(result.default_changed, Some(DefaultChangedEvent { previous_default: None }));
1806
1807 let result = networks.apply(PropertyUpdate::ChangeNetwork(
1809 FUCHSIA_ID_2,
1810 NetworkUpdate::Properties(fuchsia_added),
1811 ));
1812 assert_matches!(
1813 result.event,
1814 UpdateApplied::NetworkChanged { network_id: id, added: true, .. }
1815 if id == FUCHSIA_ID_2
1816 );
1817 assert_eq!(result.default_changed, None);
1818
1819 let result = networks.apply(PropertyUpdate::ChangeNetwork(
1821 DELEGATED_ID_1,
1822 NetworkUpdate::Properties(NetworkPropertiesChange {
1823 added: true,
1824 marks: Some(marks),
1825 ..Default::default()
1826 }),
1827 ));
1828 assert_matches!(
1829 result.event,
1830 UpdateApplied::NetworkChanged { network_id: id, added: true, .. }
1831 if id == DELEGATED_ID_1
1832 );
1833 assert_eq!(result.default_changed, None);
1834
1835 let result = networks
1838 .apply(PropertyUpdate::ChangeNetwork(DELEGATED_ID_1, NetworkUpdate::MakeDefault));
1839 assert_eq!(
1840 result,
1841 RegistryUpdateResult { event: UpdateApplied::None, default_changed: None }
1842 );
1843 assert_eq!(networks.default_network, Some(FUCHSIA_ID_1));
1844
1845 let result =
1848 networks.apply(PropertyUpdate::ChangeNetwork(FUCHSIA_ID_1, NetworkUpdate::Remove));
1849 assert_eq!(result.event, UpdateApplied::NetworkRemoved(FUCHSIA_ID_1));
1850 assert_eq!(
1851 result.default_changed,
1852 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_1) })
1853 );
1854 assert_eq!(networks.default_network, Some(FUCHSIA_ID_2));
1855
1856 let result =
1859 networks.apply(PropertyUpdate::ChangeNetwork(FUCHSIA_ID_2, NetworkUpdate::Remove));
1860 assert_eq!(result.event, UpdateApplied::NetworkRemoved(FUCHSIA_ID_2));
1861 assert_eq!(
1862 result.default_changed,
1863 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_2) })
1864 );
1865 assert_eq!(networks.default_network, Some(DELEGATED_ID_1));
1866
1867 let result =
1869 networks.apply(PropertyUpdate::ChangeNetwork(DELEGATED_ID_1, NetworkUpdate::Remove));
1870 assert_eq!(
1871 result,
1872 RegistryUpdateResult { event: UpdateApplied::None, default_changed: None }
1873 );
1874 assert!(networks.networks.contains_key(&DELEGATED_ID_1));
1875 assert_eq!(networks.default_network, Some(DELEGATED_ID_1));
1876 }
1877
1878 #[test]
1879 fn remove_non_default_fuchsia_preserves_default() {
1880 let mut networks = RegisteredNetworks::default();
1881
1882 let _ = networks.networks.insert(FUCHSIA_ID_1, NetworkProperties::default());
1884 let _ = networks.networks.insert(FUCHSIA_ID_2, NetworkProperties::default());
1885
1886 assert_eq!(
1888 networks.handle_default_network_update(),
1889 Some(DefaultChangedEvent { previous_default: None })
1890 );
1891 assert_eq!(networks.default_network, Some(FUCHSIA_ID_1));
1892
1893 assert_eq!(
1895 networks.apply(PropertyUpdate::ChangeNetwork(FUCHSIA_ID_2, NetworkUpdate::Remove)),
1896 RegistryUpdateResult {
1897 event: UpdateApplied::NetworkRemoved(FUCHSIA_ID_2),
1898 default_changed: None
1899 }
1900 );
1901
1902 assert_eq!(networks.default_network, Some(FUCHSIA_ID_1));
1904 }
1905
1906 #[fuchsia::test]
1907 async fn remove_default_network_cleans_up_tokens() {
1908 let mut service = NetpolNetworksService::default();
1909
1910 service
1912 .update(PropertyUpdate::ChangeNetwork(
1913 FUCHSIA_ID_1,
1914 NetworkUpdate::Properties(added_properties(NAME_1)),
1915 ))
1916 .await;
1917
1918 service
1919 .update(PropertyUpdate::ChangeNetwork(
1920 FUCHSIA_ID_2,
1921 NetworkUpdate::Properties(added_properties(NAME_2)),
1922 ))
1923 .await;
1924
1925 assert_eq!(service.default_network(), Some(FUCHSIA_ID_1));
1927
1928 assert!(service.has_token(FUCHSIA_ID_1, false ));
1930 assert!(service.has_token(FUCHSIA_ID_2, false ));
1931
1932 service.ensure_token_for_test(FUCHSIA_ID_1, true );
1934 assert!(service.has_token(FUCHSIA_ID_1, true ));
1935
1936 service.update(PropertyUpdate::ChangeNetwork(FUCHSIA_ID_1, NetworkUpdate::Remove)).await;
1939
1940 assert_eq!(service.default_network(), Some(FUCHSIA_ID_2));
1942
1943 assert!(!service.has_token(FUCHSIA_ID_1, false ));
1945 assert!(!service.has_token(FUCHSIA_ID_1, true ));
1946
1947 assert!(service.has_token(FUCHSIA_ID_2, false ));
1949 }
1950}