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
|
#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))]
//! `tor-ptmgr`: Manage a set of anti-censorship pluggable transports.
//!
//! # Overview
//!
//! This crate is part of [Arti](https://gitlab.torproject.org/tpo/core/arti/),
//! a project to implement [Tor](https://www.torproject.org/) in Rust.
//!
//! In Tor, a "transport" is a mechanism used to avoid censorship by disguising
//! the Tor protocol as some other kind of traffic.
//!
//! A "pluggable transport" is one that is not implemented by default as part of
//! the Tor protocol, but which can instead be added later on by the packager or
//! the user. Pluggable transports are typically provided as external binaries
//! that implement a SOCKS proxy, along with certain other configuration
//! protocols.
//!
//! This crate provides a means to manage a set of configured pluggable
//! transports
//!
//! # Limitations
//!
//! TODO pt-client: Currently, the APIs for this crate make it quite
//! tor-specific. Notably, it can only return Channels! It would be good
//! instead to adapt it so that it was more generally useful by other projects
//! that want to use pluggable transports in rust. For now, I have put the
//! Tor-channel-specific stuff behind a `tor-channel-factory` feature, but there
//! are no APIs for using PTs without that feature currently. That should
//! change.
//!
//! TODO pt-client: Nothing in this crate is actually implemented yet.
//!
//! TODO pt-client: The first version of this crate will probably only conform
//! to the old Tor pluggable transport protocol, and not to more recent variants
//! as documented at `pluggabletransports.info`
// @@ begin lint list maintained by maint/add_warning @@
#![cfg_attr(not(ci_arti_stable), allow(renamed_and_removed_lints))]
#![cfg_attr(not(ci_arti_nightly), allow(unknown_lints))]
#![deny(missing_docs)]
#![warn(noop_method_call)]
#![deny(unreachable_pub)]
#![warn(clippy::all)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::cargo_common_metadata)]
#![deny(clippy::cast_lossless)]
#![deny(clippy::checked_conversions)]
#![warn(clippy::cognitive_complexity)]
#![deny(clippy::debug_assert_with_mut_call)]
#![deny(clippy::exhaustive_enums)]
#![deny(clippy::exhaustive_structs)]
#![deny(clippy::expl_impl_clone_on_copy)]
#![deny(clippy::fallible_impl_from)]
#![deny(clippy::implicit_clone)]
#![deny(clippy::large_stack_arrays)]
#![warn(clippy::manual_ok_or)]
#![deny(clippy::missing_docs_in_private_items)]
#![deny(clippy::missing_panics_doc)]
#![warn(clippy::needless_borrow)]
#![warn(clippy::needless_pass_by_value)]
#![warn(clippy::option_option)]
#![warn(clippy::rc_buffer)]
#![deny(clippy::ref_option_ref)]
#![warn(clippy::semicolon_if_nothing_returned)]
#![warn(clippy::trait_duplication_in_bounds)]
#![deny(clippy::unnecessary_wraps)]
#![warn(clippy::unseparated_literal_suffix)]
#![deny(clippy::unwrap_used)]
#![allow(clippy::let_unit_value)] // This can reasonably be done for explicitness
#![allow(clippy::significant_drop_in_scrutinee)] // arti/-/merge_requests/588/#note_2812945
//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
pub mod config;
use config::PtMgrConfig;
use async_trait::async_trait;
#[cfg(feature = "tor-channel-factory")]
use tor_chanmgr::factory::ChannelFactory;
use tor_linkspec::TransportId;
use tor_rtcompat::Runtime;
/// A pluggable transport manager knows how to make different
/// kinds of connections to the Tor network, for censorship avoidance.
///
/// Currently, we only support two kinds of pluggable transports: Those
/// configured in a PtConfig object, and those added with PtMgr::register.
//
// TODO: Will we need a <R:Runtime constraint> here? I don't know. -nickm
#[derive(Clone, Debug)]
pub struct PtMgr<R> {
/// An underlying `Runtime`, used to spawn background tasks.
runtime: R,
}
#[allow(clippy::missing_panics_doc, clippy::needless_pass_by_value)]
impl<R: Runtime> PtMgr<R> {
/// Create a new PtMgr.
pub fn new(cfg: PtMgrConfig, rt: R) -> Self {
let _ = (cfg, rt);
todo!("TODO pt-client: implement this.")
}
/// Reload the configuration
pub fn reconfigure(&self, cfg: PtMgrConfig) -> Result<(), tor_config::ReconfigureError> {
let _ = cfg;
todo!("TODO pt-client: implement this.")
}
/// Manually add a new channel factory to this registry.
#[cfg(feature = "tor-channel-factory")]
pub fn register_factory(&self, ids: &[TransportId], factory: impl ChannelFactory) {
let _ = (ids, factory);
todo!("TODO pt-client: implement this.")
}
// TODO pt-client: Possibly, this should have a separate function to launch
// its background tasks.
}
#[cfg(feature = "tor-channel-factory")]
#[allow(clippy::missing_panics_doc)]
#[async_trait]
impl<R: Runtime> tor_chanmgr::factory::TransportRegistry for PtMgr<R> {
// There is going to be a lot happening "under the hood" here.
//
// When we are asked to get a ChannelFactory for a given
// connection, we will need to:
// - launch the binary for that transport if it is not already running*.
// - If we launched the binary, talk to it and see which ports it
// is listening on.
// - Return a ChannelFactory that connects via one of those ports,
// using the appropriate version of SOCKS, passing K=V parameters
// encoded properly.
//
// * As in other managers, we'll need to avoid trying to launch the same
// transport twice if we get two concurrent requests.
//
// Later if the binary crashes, we should detect that. We should relaunch
// it on demand.
//
// On reconfigure, we should shut down any no-longer-used transports.
//
// Maybe, we should shut down transports that haven't been used
// for a long time.
async fn get_factory(&self, transport: &TransportId) -> Option<&dyn ChannelFactory> {
let _ = transport;
let _ = &self.runtime;
todo!("TODO pt-client")
}
}
|