socket_proxy/
lib.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Implementation of the network socket proxy.
6//!
7//! Runs proxied versions of fuchsia.posix.socket.Provider and fuchsia.posix.socket.raw.Provider.
8//! Exposes fuchsia.net.policy.socketproxy.StarnixNetworks,
9//! fuchsia.net.policy.socketproxy.FuchsiaNetworks, and
10//! fuchsia.net.policy.socketproxy.DnsServerWatcher.
11
12use fidl_fuchsia_net as fnet;
13use fidl_fuchsia_posix_socket::{self as fposix_socket, OptionalUint32};
14use fuchsia_component::server::{ServiceFs, ServiceFsDir};
15use fuchsia_inspect::health::Reporter;
16use fuchsia_inspect_derive::{Inspect, WithInspect as _};
17use futures::channel::mpsc;
18use futures::lock::Mutex;
19use futures::StreamExt as _;
20use log::error;
21use std::sync::Arc;
22
23mod dns_watcher;
24mod registry;
25mod socket_provider;
26
27pub use registry::{NetworkConversionError, NetworkExt, NetworkRegistryError};
28
29#[derive(Copy, Clone, Debug)]
30struct SocketMarks {
31    mark_1: OptionalUint32,
32    mark_2: OptionalUint32,
33}
34
35impl From<SocketMarks> for fnet::Marks {
36    fn from(SocketMarks { mark_1, mark_2 }: SocketMarks) -> Self {
37        let into_option_u32 = |opt| match opt {
38            OptionalUint32::Unset(fposix_socket::Empty) => None,
39            OptionalUint32::Value(val) => Some(val),
40        };
41        Self {
42            mark_1: into_option_u32(mark_1),
43            mark_2: into_option_u32(mark_2),
44            __source_breaking: fidl::marker::SourceBreaking,
45        }
46    }
47}
48
49impl SocketMarks {
50    fn has_value(&self) -> bool {
51        match (self.mark_1, self.mark_2) {
52            (OptionalUint32::Value(_), _) => true,
53            (_, OptionalUint32::Value(_)) => true,
54            _ => false,
55        }
56    }
57}
58
59impl Default for SocketMarks {
60    fn default() -> Self {
61        Self {
62            mark_1: OptionalUint32::Unset(fposix_socket::Empty),
63            mark_2: OptionalUint32::Unset(fposix_socket::Empty),
64        }
65    }
66}
67
68#[derive(Inspect)]
69struct SocketProxy {
70    registry: registry::Registry,
71    dns_watcher: dns_watcher::DnsServerWatcher,
72    socket_provider: socket_provider::SocketProvider,
73}
74
75impl SocketProxy {
76    fn new() -> Self {
77        let mark = Arc::new(Mutex::new(SocketMarks::default()));
78        let (dns_tx, dns_rx) = mpsc::channel(1);
79        Self {
80            registry: registry::Registry::new(mark.clone(), dns_tx),
81            dns_watcher: dns_watcher::DnsServerWatcher::new(Arc::new(Mutex::new(dns_rx))),
82            socket_provider: socket_provider::SocketProvider::new(mark),
83        }
84    }
85}
86
87enum IncomingService {
88    StarnixNetworks(fidl_fuchsia_net_policy_socketproxy::StarnixNetworksRequestStream),
89    FuchsiaNetworks(fidl_fuchsia_net_policy_socketproxy::FuchsiaNetworksRequestStream),
90    DnsServerWatcher(fidl_fuchsia_net_policy_socketproxy::DnsServerWatcherRequestStream),
91    PosixSocket(fidl_fuchsia_posix_socket::ProviderRequestStream),
92    PosixSocketRaw(fidl_fuchsia_posix_socket_raw::ProviderRequestStream),
93}
94
95/// Main entry point for the network socket proxy.
96pub async fn run() -> Result<(), anyhow::Error> {
97    fuchsia_inspect::component::health().set_starting_up();
98
99    let inspector = fuchsia_inspect::component::inspector();
100    let _inspect_server_task =
101        inspect_runtime::publish(inspector, inspect_runtime::PublishOptions::default());
102
103    let proxy = SocketProxy::new().with_inspect(inspector.root(), "root")?;
104
105    let mut fs = ServiceFs::new_local();
106    let _: &mut ServiceFsDir<'_, _> = fs
107        .dir("svc")
108        .add_fidl_service(IncomingService::StarnixNetworks)
109        .add_fidl_service(IncomingService::FuchsiaNetworks)
110        .add_fidl_service(IncomingService::DnsServerWatcher)
111        .add_fidl_service(IncomingService::PosixSocket)
112        .add_fidl_service(IncomingService::PosixSocketRaw);
113
114    let _: &mut ServiceFs<_> = fs.take_and_serve_directory_handle()?;
115
116    fuchsia_inspect::component::health().set_ok();
117
118    fs.for_each_concurrent(100, |service| async {
119        match service {
120            IncomingService::StarnixNetworks(stream) => proxy.registry.run_starnix(stream).await,
121            IncomingService::FuchsiaNetworks(stream) => proxy.registry.run_fuchsia(stream).await,
122            IncomingService::DnsServerWatcher(stream) => proxy.dns_watcher.run(stream).await,
123            IncomingService::PosixSocket(stream) => proxy.socket_provider.run(stream).await,
124            IncomingService::PosixSocketRaw(stream) => proxy.socket_provider.run_raw(stream).await,
125        }
126        .unwrap_or_else(|e| error!("{e:?}"))
127    })
128    .await;
129
130    Ok(())
131}