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