1use anyhow::Context as _;
13use fidl_fuchsia_net as fnet;
14use fidl_fuchsia_net_policy_socketproxy as fnp_socketproxy;
15use fidl_fuchsia_posix_socket::{self as fposix_socket, OptionalUint32};
16use fuchsia_async as fasync;
17use fuchsia_component::server::{ServiceFs, ServiceFsDir};
18use fuchsia_inspect::health::Reporter;
19use fuchsia_inspect_derive::{Inspect, WithInspect as _};
20use futures::StreamExt as _;
21use futures::channel::mpsc;
22use futures::lock::Mutex;
23use log::{error, info};
24use std::sync::Arc;
25
26mod dns_watcher;
27pub mod registry;
28mod socket_provider;
29
30pub use registry::{NetworkConversionError, NetworkExt, NetworkRegistryError};
31
32#[derive(Copy, Clone, Debug)]
33struct SocketMarks {
34 mark_1: OptionalUint32,
35 mark_2: OptionalUint32,
36}
37
38impl From<SocketMarks> for fnet::Marks {
39 fn from(SocketMarks { mark_1, mark_2 }: SocketMarks) -> Self {
40 let into_option_u32 = |opt| match opt {
41 OptionalUint32::Unset(fposix_socket::Empty) => None,
42 OptionalUint32::Value(val) => Some(val),
43 };
44 Self {
45 mark_1: into_option_u32(mark_1),
46 mark_2: into_option_u32(mark_2),
47 __source_breaking: fidl::marker::SourceBreaking,
48 }
49 }
50}
51
52impl SocketMarks {
53 fn has_value(&self) -> bool {
54 match (self.mark_1, self.mark_2) {
55 (OptionalUint32::Value(_), _) => true,
56 (_, OptionalUint32::Value(_)) => true,
57 _ => false,
58 }
59 }
60
61 fn set_mark(&mut self, domain: fnet::MarkDomain, value: Option<u32>) {
62 let value = match value {
63 Some(value) => fposix_socket::OptionalUint32::Value(value),
64 None => fposix_socket::OptionalUint32::Unset(fposix_socket::Empty),
65 };
66
67 match domain {
68 fnet::MarkDomain::Mark1 => self.mark_1 = value,
69 fnet::MarkDomain::Mark2 => self.mark_2 = value,
70 }
71 }
72}
73
74impl Default for SocketMarks {
75 fn default() -> Self {
76 Self {
77 mark_1: OptionalUint32::Unset(fposix_socket::Empty),
78 mark_2: OptionalUint32::Unset(fposix_socket::Empty),
79 }
80 }
81}
82
83#[derive(Inspect)]
84struct SocketProxy {
85 registry: registry::Registry,
86 dns_watcher: dns_watcher::DnsServerWatcher,
87 socket_provider: socket_provider::SocketProvider,
88}
89
90impl SocketProxy {
91 fn new(
92 forwarder_tx: mpsc::Sender<crate::registry::NetworkRegistryRequest>,
93 ) -> Result<Self, anyhow::Error> {
94 let mark = Arc::new(Mutex::new(SocketMarks::default()));
95 let (dns_tx, dns_rx) = mpsc::channel(1);
96 Ok(Self {
97 registry: registry::Registry::new(mark.clone(), dns_tx, forwarder_tx)
98 .context("while creating registry")?,
99 dns_watcher: dns_watcher::DnsServerWatcher::new(Arc::new(Mutex::new(dns_rx))),
100 socket_provider: socket_provider::SocketProvider::new(mark),
101 })
102 }
103}
104
105enum IncomingService {
106 DnsServerWatcher(fnp_socketproxy::DnsServerWatcherRequestStream),
107 FuchsiaNetworks(fnp_socketproxy::FuchsiaNetworksRequestStream),
108 StarnixNetworks(fnp_socketproxy::StarnixNetworksRequestStream),
109 PosixSocket(fidl_fuchsia_posix_socket::ProviderRequestStream),
110 PosixSocketRaw(fidl_fuchsia_posix_socket_raw::ProviderRequestStream),
111}
112
113pub async fn run() -> Result<(), anyhow::Error> {
115 fuchsia_inspect::component::health().set_starting_up();
116
117 let inspector = fuchsia_inspect::component::inspector();
118 let _inspect_server_task =
119 inspect_runtime::publish(inspector, inspect_runtime::PublishOptions::default());
120
121 let (forwarder_tx, forwarder_rx) = mpsc::channel(50);
125 let mut request_forwarder = registry::RequestForwarder::new(forwarder_rx)?;
126 let proxy = Arc::new(SocketProxy::new(forwarder_tx)?.with_inspect(inspector.root(), "root")?);
127
128 let mut fs = ServiceFs::new_local();
129 let _: &mut ServiceFsDir<'_, _> = fs
130 .dir("svc")
131 .add_fidl_service(IncomingService::StarnixNetworks)
132 .add_fidl_service(IncomingService::FuchsiaNetworks)
133 .add_fidl_service(IncomingService::DnsServerWatcher)
134 .add_fidl_service(IncomingService::PosixSocket)
135 .add_fidl_service(IncomingService::PosixSocketRaw);
136
137 let _: &mut ServiceFs<_> = fs.take_and_serve_directory_handle()?;
138
139 fuchsia_inspect::component::health().set_ok();
140
141 let service_fut = fs.for_each_concurrent(100, move |service| {
142 let proxy = Arc::clone(&proxy);
143 async move {
144 match service {
145 IncomingService::StarnixNetworks(stream) => {
146 proxy.registry.run_starnix(stream).await
147 }
148 IncomingService::FuchsiaNetworks(stream) => {
149 proxy.registry.run_fuchsia(stream).await
150 }
151 IncomingService::DnsServerWatcher(stream) => proxy.dns_watcher.run(stream).await,
152 IncomingService::PosixSocket(stream) => proxy.socket_provider.run(stream).await,
153 IncomingService::PosixSocketRaw(stream) => {
154 proxy.socket_provider.run_raw(stream).await
155 }
156 }
157 .unwrap_or_else(|e| error!("{e:?}"))
158 }
159 });
160
161 let scope = fasync::Scope::new();
162
163 let _ = scope.spawn_local(async move {
164 let res = request_forwarder.run().await;
165 info!("RequestForwarder future has terminated: {res:?}");
166 });
167
168 let _ = scope.spawn_local(async move {
169 service_fut.await;
170 error!("The main services future has terminated. It should never terminate");
171 fasync::Scope::current().abort().await;
173 });
174
175 scope.join().await;
176
177 Ok(())
178}