Skip to main content

arti/rpc/
proxyinfo.rs

1//! Implement RPC functionality for finding what ports are running as proxies.
2
3use std::{net::SocketAddr, sync::Arc};
4use tor_error::{ErrorKind, HasKind};
5use tor_rpcbase::{self as rpc};
6
7use crate::proxy::port_info;
8
9use super::session::ArtiRpcSession;
10
11/// Representation of a single proxy, as delivered by the RPC API.
12#[derive(serde::Serialize, Clone, Debug)]
13#[cfg_attr(test, derive(PartialEq, Eq))]
14pub(super) struct Proxy {
15    /// Where the proxy is listening, what protocol it speaks,
16    /// and what protocol-specific options it expects.
17    pub(super) listener: ProxyListener,
18}
19
20/// Representation of a single proxy's listener location, as delivered by the RPC API.
21#[derive(serde::Serialize, Clone, Debug)]
22#[cfg_attr(test, derive(PartialEq, Eq))]
23pub(super) enum ProxyListener {
24    /// A SOCKS5 proxy.
25    #[serde(rename = "socks5")]
26    Socks5 {
27        /// The address at which we're listening for SOCKS connections.
28        tcp_address: Option<SocketAddr>,
29    },
30    /// An HTTP CONNECT proxy.
31    #[cfg(feature = "http-connect")]
32    #[serde(rename = "http_connect")]
33    HttpConnect {
34        /// The address at which we're listening for HTTP CONNECT connections.
35        tcp_address: Option<SocketAddr>,
36    },
37}
38
39impl ProxyListener {
40    /// Try to represent the given port as a ProxyListener.
41    ///
42    /// Return None if it cannot be represented.
43    pub(crate) fn try_from_portinfo(port: &port_info::Port) -> Option<Self> {
44        use port_info::SupportedProtocol as SP;
45        use tor_rtcompat::general::{self, SocketAddr::Inet};
46
47        match (&port.address, &port.protocol) {
48            (Inet(a), SP::Socks) => Some(Self::Socks5 {
49                tcp_address: Some(*a),
50            }),
51            #[cfg(feature = "http-connect")]
52            (Inet(a), SP::Http) => Some(Self::HttpConnect {
53                tcp_address: Some(*a),
54            }),
55            (Inet(_), SP::DnsUdp) => None,
56            // TODO: Handle unix addresses once we can bind to them
57            (general::SocketAddr::Unix(_), _) => None,
58            (_, _) => None,
59        }
60    }
61}
62
63/// A representation of the set of proxy addresses available from the RPC API.
64#[derive(serde::Serialize, Clone, Debug)]
65#[cfg_attr(test, derive(PartialEq, Eq))]
66pub(super) struct ProxyInfo {
67    /// A list of the supported proxies.
68    pub(super) proxies: Vec<Proxy>,
69}
70
71/// Get a list of all the currently running proxies.
72///
73/// This method should not be used when deciding which proxy
74/// an RPC application should connect to.
75/// Instead, the application should use
76/// [`arti:get_rpc_proxy_info`](GetRpcProxyInfo).
77#[derive(Debug, serde::Deserialize, derive_deftly::Deftly)]
78#[derive_deftly(rpc::DynMethod)]
79#[deftly(rpc(method_name = "arti:get_proxy_info"))]
80struct GetProxyInfo {}
81
82/// Get a list of the currently running proxies
83/// that are integrated with the RPC system.
84///
85/// This method returns a list of proxies.
86/// The RPC application may be not be able to use all proxies from the list,
87/// and may prefer some proxies over other.
88/// When multiple proxies are equally preferred,
89/// the application SHOULD use whichever appears first in the list.
90///
91/// You typically won't need to invoke this method yourself:
92/// your RPC library (like `arti-rpc-client-core`)
93/// should take care if it for you.
94#[derive(Debug, serde::Deserialize, derive_deftly::Deftly)]
95#[derive_deftly(rpc::DynMethod)]
96#[deftly(rpc(method_name = "arti:get_rpc_proxy_info"))]
97struct GetRpcProxyInfo {}
98
99impl rpc::RpcMethod for GetProxyInfo {
100    type Output = ProxyInfo;
101    type Update = rpc::NoUpdates;
102}
103
104impl rpc::RpcMethod for GetRpcProxyInfo {
105    type Output = ProxyInfo;
106    type Update = rpc::NoUpdates;
107}
108
109/// An error encountered while asking for the proxy addresses.
110#[derive(Clone, Debug, thiserror::Error)]
111enum GetProxyInfoError {
112    /// The Sender was dropped without setting any proxy info;
113    /// likely, Arti is shutting down.
114    #[error("Arti appears to be shutting down")]
115    Shutdown,
116}
117impl HasKind for GetProxyInfoError {
118    fn kind(&self) -> ErrorKind {
119        use GetProxyInfoError as E;
120        match self {
121            E::Shutdown => ErrorKind::ArtiShuttingDown,
122        }
123    }
124}
125
126/// Implementation for GetProxyInfo on ArtiRpcSession.
127async fn rpc_session_get_proxy_info(
128    session: Arc<ArtiRpcSession>,
129    _method: Box<GetProxyInfo>,
130    _ctx: Arc<dyn rpc::Context>,
131) -> Result<ProxyInfo, GetProxyInfoError> {
132    let proxy_info = session.arti_state.get_proxy_info().await;
133
134    match proxy_info {
135        Ok(info) => Ok((*info).clone()),
136        Err(()) => Err(GetProxyInfoError::Shutdown),
137    }
138}
139rpc::static_rpc_invoke_fn! {rpc_session_get_proxy_info;}
140
141/// Implementation for GetProxyInfo on ArtiRpcSession.
142async fn rpc_session_get_rpc_proxy_info(
143    session: Arc<ArtiRpcSession>,
144    _method: Box<GetRpcProxyInfo>,
145    _ctx: Arc<dyn rpc::Context>,
146) -> Result<ProxyInfo, GetProxyInfoError> {
147    let proxy_info = session.arti_state.get_proxy_info().await;
148
149    match proxy_info {
150        Ok(info) => Ok((*info).clone()),
151        Err(()) => Err(GetProxyInfoError::Shutdown),
152    }
153}
154rpc::static_rpc_invoke_fn! {rpc_session_get_rpc_proxy_info;}