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 anyhow::Context as _;
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;
22use {
23    fidl_fuchsia_net as fnet, fidl_fuchsia_net_policy_properties as fnp_properties,
24    fidl_fuchsia_net_policy_socketproxy as fnp_socketproxy,
25};
26
27mod default_network_watcher;
28mod dns_watcher;
29mod registry;
30mod socket_provider;
31
32pub use registry::{NetworkConversionError, NetworkExt, NetworkRegistryError};
33
34#[derive(Copy, Clone, Debug)]
35struct SocketMarks {
36    mark_1: OptionalUint32,
37    mark_2: OptionalUint32,
38}
39
40impl From<SocketMarks> for fnet::Marks {
41    fn from(SocketMarks { mark_1, mark_2 }: SocketMarks) -> Self {
42        let into_option_u32 = |opt| match opt {
43            OptionalUint32::Unset(fposix_socket::Empty) => None,
44            OptionalUint32::Value(val) => Some(val),
45        };
46        Self {
47            mark_1: into_option_u32(mark_1),
48            mark_2: into_option_u32(mark_2),
49            __source_breaking: fidl::marker::SourceBreaking,
50        }
51    }
52}
53
54impl SocketMarks {
55    fn has_value(&self) -> bool {
56        match (self.mark_1, self.mark_2) {
57            (OptionalUint32::Value(_), _) => true,
58            (_, OptionalUint32::Value(_)) => true,
59            _ => false,
60        }
61    }
62}
63
64impl Default for SocketMarks {
65    fn default() -> Self {
66        Self {
67            mark_1: OptionalUint32::Unset(fposix_socket::Empty),
68            mark_2: OptionalUint32::Unset(fposix_socket::Empty),
69        }
70    }
71}
72
73#[derive(Inspect)]
74struct SocketProxy {
75    registry: registry::Registry,
76    dns_watcher: dns_watcher::DnsServerWatcher,
77    default_network_watcher: default_network_watcher::Watcher,
78    socket_provider: socket_provider::SocketProvider,
79}
80
81impl SocketProxy {
82    fn new() -> Result<Self, anyhow::Error> {
83        let mark = Arc::new(Mutex::new(SocketMarks::default()));
84        let (dns_tx, dns_rx) = mpsc::channel(1);
85        let (default_network_tx, default_network_rx) = mpsc::channel(1);
86        Ok(Self {
87            registry: registry::Registry::new(mark.clone(), dns_tx, default_network_tx)
88                .context("while creating registry")?,
89            dns_watcher: dns_watcher::DnsServerWatcher::new(Arc::new(Mutex::new(dns_rx))),
90            default_network_watcher: default_network_watcher::Watcher::new(Arc::new(Mutex::new(
91                default_network_rx,
92            ))),
93            socket_provider: socket_provider::SocketProvider::new(mark),
94        })
95    }
96}
97
98enum IncomingService {
99    StarnixNetworks(fnp_socketproxy::StarnixNetworksRequestStream),
100    FuchsiaNetworks(fnp_socketproxy::FuchsiaNetworksRequestStream),
101    DnsServerWatcher(fnp_socketproxy::DnsServerWatcherRequestStream),
102    PosixSocket(fidl_fuchsia_posix_socket::ProviderRequestStream),
103    PosixSocketRaw(fidl_fuchsia_posix_socket_raw::ProviderRequestStream),
104    DefaultNetworkWatcher(fnp_properties::DefaultNetworkWatcherRequestStream),
105}
106
107/// Main entry point for the network socket proxy.
108pub async fn run() -> Result<(), anyhow::Error> {
109    fuchsia_inspect::component::health().set_starting_up();
110
111    let inspector = fuchsia_inspect::component::inspector();
112    let _inspect_server_task =
113        inspect_runtime::publish(inspector, inspect_runtime::PublishOptions::default());
114
115    let proxy = SocketProxy::new()?.with_inspect(inspector.root(), "root")?;
116
117    let mut fs = ServiceFs::new_local();
118    let _: &mut ServiceFsDir<'_, _> = fs
119        .dir("svc")
120        .add_fidl_service(IncomingService::StarnixNetworks)
121        .add_fidl_service(IncomingService::FuchsiaNetworks)
122        .add_fidl_service(IncomingService::DnsServerWatcher)
123        .add_fidl_service(IncomingService::PosixSocket)
124        .add_fidl_service(IncomingService::PosixSocketRaw)
125        .add_fidl_service(IncomingService::DefaultNetworkWatcher);
126
127    let _: &mut ServiceFs<_> = fs.take_and_serve_directory_handle()?;
128
129    fuchsia_inspect::component::health().set_ok();
130
131    fs.for_each_concurrent(100, |service| async {
132        match service {
133            IncomingService::StarnixNetworks(stream) => proxy.registry.run_starnix(stream).await,
134            IncomingService::FuchsiaNetworks(stream) => proxy.registry.run_fuchsia(stream).await,
135            IncomingService::DnsServerWatcher(stream) => proxy.dns_watcher.run(stream).await,
136            IncomingService::PosixSocket(stream) => proxy.socket_provider.run(stream).await,
137            IncomingService::PosixSocketRaw(stream) => proxy.socket_provider.run_raw(stream).await,
138            IncomingService::DefaultNetworkWatcher(stream) => {
139                proxy.default_network_watcher.run(stream).await
140            }
141        }
142        .unwrap_or_else(|e| error!("{e:?}"))
143    })
144    .await;
145
146    Ok(())
147}