1
//! Utilities and helpers for testing channels.
2

            
3
// These are test utilities.
4
#![allow(clippy::unwrap_used)]
5

            
6
use futures::channel::mpsc;
7
use futures::{SinkExt as _, StreamExt as _};
8
use safelog::MaybeSensitive;
9
use std::sync::{Arc, LazyLock, Weak};
10
use std::time::Duration;
11
use tor_cell::chancell::AnyChanCell;
12
use tor_key_forge::Keygen as _;
13
use tor_linkspec::{
14
    HasRelayIds as _, OwnedChanTarget, OwnedCircTarget, OwnedCircTargetBuilder, RelayIds,
15
    RelayIdsBuilder,
16
};
17
use tor_rtcompat::{NoOpStreamOpsHandle, Runtime, SpawnExt as _};
18

            
19
use crate::ClockSkew;
20
use crate::channel::circmap::CircIdRange;
21
use crate::channel::{
22
    BoxedChannelSink, BoxedChannelStream, Canonicity, Channel, ChannelMode, Reactor, UniqId,
23
};
24
use crate::client::circuit::{PendingClientTunnel, TimeoutEstimator};
25
use crate::memquota::{ChannelAccount, SpecificAccount};
26
use crate::peer::{PeerAddr, PeerInfo};
27

            
28
#[cfg(feature = "relay")]
29
use {
30
    crate::relay::CreateRequestHandler,
31
    crate::relay::channel_provider::{ChannelProvider, NoOpChannelProvider},
32
    crate::relay::{CircNetParameters, CircuitIncomingStreamReceiver, CongestionControlNetParams},
33
    crate::stream::incoming::NoOpRequestFilter,
34
    tor_relay_crypto::pk::RelayNtorKeys,
35
};
36

            
37
/// Construct a new channel and its reactor.
38
16
pub(crate) fn new_channel<R: Runtime>(
39
16
    rt: &R,
40
16
    mode: ChannelMode,
41
16
    peer_info: PeerInfo,
42
16
    sender: BoxedChannelSink,
43
16
    receiver: BoxedChannelStream,
44
16
) -> (Arc<Channel>, Reactor<R>) {
45
16
    let mut peer_id = OwnedChanTarget::builder();
46
16
    *peer_id.ids() = RelayIdsBuilder::from_relay_ids(&peer_info);
47
16
    let peer_id = peer_id.build().unwrap();
48

            
49
    // The only link protocol that Arti currently supports.
50
    // This is hardcoded to '4' throughout the rest of tor-proto.
51
16
    let link_protocol = 4;
52
16
    let clock_skew = ClockSkew::None;
53
16
    let canonicity = Canonicity {
54
16
        peer_is_canonical: true,
55
16
        canonical_to_peer: true,
56
16
    };
57
16
    let memquota = ChannelAccount::new_noop();
58

            
59
16
    let (chan, reactor) = Channel::new(
60
16
        mode,
61
16
        link_protocol,
62
16
        sender,
63
16
        receiver,
64
16
        Box::new(NoOpStreamOpsHandle::default()),
65
16
        UniqId::new(),
66
16
        peer_id,
67
16
        MaybeSensitive::not_sensitive(peer_info),
68
16
        clock_skew,
69
16
        rt.clone(),
70
16
        memquota,
71
16
        canonicity,
72
16
    )
73
16
    .unwrap();
74

            
75
16
    (chan, reactor)
76
16
}
77

            
78
/// Initialize connected client and relay channels.
79
///
80
/// Returns a client channel and a relay channel respectively.
81
///
82
/// The [`ConnInspector`] allows you to inspect the cells that they send to each other.
83
#[cfg(feature = "relay")]
84
8
pub(crate) fn new_channel_pair<R: Runtime>(
85
8
    rt: &R,
86
8
    chan_provider: Weak<dyn ChannelProvider<BuildSpec = OwnedChanTarget> + Send + Sync>,
87
8
    relay_ids: RelayIds,
88
8
    relay_ntor_keys: RelayNtorKeys,
89
8
    conn_inspector: &ConnInspector,
90
8
) -> (Arc<Channel>, Arc<Channel>, CircuitIncomingStreamReceiver) {
91
8
    let relay_info = PeerInfo::new(PeerAddr::UNSPECIFIED, relay_ids);
92
8
    let client_info = PeerInfo::new(PeerAddr::UNSPECIFIED, RelayIds::empty());
93

            
94
8
    let circ_net_params = CircNetParameters {
95
8
        cc: CongestionControlNetParams::defaults_for_tests(),
96
8
    };
97

            
98
    // A handler that will process CREATE* requests on channels.
99
8
    let (create_request_handler, circuit_stream_rx) = CreateRequestHandler::new(
100
8
        chan_provider,
101
8
        circ_net_params,
102
8
        relay_ntor_keys,
103
        // Don't filter any stream requests.
104
14
        Box::new(|| Box::new(NoOpRequestFilter) as Box<_>),
105
        // Don't allow any stream commands.
106
8
        &[],
107
    );
108
8
    let create_request_handler = Arc::new(create_request_handler);
109

            
110
8
    let client_mode = ChannelMode::Client;
111
8
    let relay_mode = ChannelMode::Relay {
112
8
        create_request_handler,
113
8
        our_ed25519_id: *relay_info.ed_identity().unwrap(),
114
8
        our_rsa_id: *relay_info.rsa_identity().unwrap(),
115
8
        // The relay is the responder.
116
8
        circ_id_range: CircIdRange::Low,
117
8
    };
118

            
119
    // This simplifies the rustc errors when something goes wrong.
120
    // c_to_r = client -> relay
121
    // r_to_c = relay -> client
122
    let c_to_r_tx: mpsc::Sender<AnyChanCell>;
123
    let r_to_c_tx: mpsc::Sender<AnyChanCell>;
124
    let c_to_r_rx: mpsc::Receiver<AnyChanCell>;
125
    let r_to_c_rx: mpsc::Receiver<AnyChanCell>;
126

            
127
8
    (c_to_r_tx, c_to_r_rx) = mpsc::channel(32);
128
8
    (r_to_c_tx, r_to_c_rx) = mpsc::channel(32);
129

            
130
    // `BoxedChannelStream` requires `Item = Result<AnyChanCell, _>`.
131
8
    let c_to_r_rx = c_to_r_rx.map(Ok);
132
8
    let r_to_c_rx = r_to_c_rx.map(Ok);
133

            
134
    // `BoxedChannelSink` requires `Error = crate::Error`.
135
8
    let c_to_r_tx = c_to_r_tx.sink_map_err(|e| crate::Error::CellDecodeErr {
136
        object: "reactor test",
137
        err: tor_cell::Error::ChanProto(format!("Sink error: {e:?}")),
138
    });
139
8
    let r_to_c_tx = r_to_c_tx.sink_map_err(|e| crate::Error::CellDecodeErr {
140
        object: "reactor test",
141
4
        err: tor_cell::Error::ChanProto(format!("Sink error: {e:?}")),
142
4
    });
143

            
144
    // We want to clone cells that the client channel or relay channel sends,
145
    // and store a copy in the connection inspector.
146
8
    let client_inspector_tx = conn_inspector.client_inspector_tx.clone();
147
26
    let c_to_r_tx = c_to_r_tx.with(move |cell: AnyChanCell| {
148
26
        let client_inspector_tx = client_inspector_tx.clone();
149
26
        async move {
150
26
            let (cell, cell_clone) = clone_chan_cell(cell);
151
26
            let _ = client_inspector_tx.unbounded_send(cell_clone);
152
26
            Ok(cell)
153
26
        }
154
26
    });
155
8
    let c_to_r_tx = Box::pin(c_to_r_tx);
156

            
157
8
    let relay_inspector_tx = conn_inspector.relay_inspector_tx.clone();
158
14
    let r_to_c_tx = r_to_c_tx.with(move |cell: AnyChanCell| {
159
14
        let relay_inspector_tx = relay_inspector_tx.clone();
160
14
        async move {
161
14
            let (cell, cell_clone) = clone_chan_cell(cell);
162
14
            let _ = relay_inspector_tx.unbounded_send(cell_clone);
163
14
            Ok(cell)
164
14
        }
165
14
    });
166
8
    let r_to_c_tx = Box::pin(r_to_c_tx);
167

            
168
    // The `Channel` requires these to be boxed trait objects.
169
8
    let (c_to_r_tx, c_to_r_rx) = (Box::new(c_to_r_tx), Box::new(c_to_r_rx));
170
8
    let (r_to_c_tx, r_to_c_rx) = (Box::new(r_to_c_tx), Box::new(r_to_c_rx));
171

            
172
8
    let (client_chan, client_reactor) =
173
8
        new_channel(rt, client_mode, relay_info, c_to_r_tx, r_to_c_rx);
174

            
175
8
    let (relay_chan, relay_reactor) =
176
8
        new_channel(rt, relay_mode, client_info, r_to_c_tx, c_to_r_rx);
177

            
178
8
    rt.spawn(async {
179
8
        let _ = futures::future::join(client_reactor.run(), relay_reactor.run()).await;
180
8
    })
181
8
    .unwrap();
182

            
183
8
    (client_chan, relay_chan, circuit_stream_rx)
184
8
}
185

            
186
/// Initialize connected client and relay channels with pre-generated keys.
187
///
188
/// Returns a client channel and a relay channel respectively, and a partially built
189
/// [`OwnedCircTarget`] that can be used to build circuits.
190
///
191
/// The [`ConnInspector`] allows you to inspect the cells that they send to each other.
192
#[cfg(feature = "relay")]
193
8
pub(crate) fn new_channel_pair_with_keys<R: Runtime>(
194
8
    rt: &R,
195
8
    conn_inspector: &ConnInspector,
196
8
) -> (
197
8
    Arc<Channel>,
198
8
    Arc<Channel>,
199
8
    CircuitIncomingStreamReceiver,
200
8
    OwnedCircTargetBuilder,
201
8
) {
202
8
    let mut rng = tor_llcrypto::rng::CautiousRng;
203

            
204
    // Keys are chosen arbitrarily.
205
8
    let relay_ids = RelayIds::builder()
206
8
        .ed_identity([6_u8; 32].into())
207
8
        .rsa_identity([10_u8; 20].into())
208
8
        .build()
209
8
        .unwrap();
210

            
211
8
    let relay_ntor_keys = tor_llcrypto::pk::curve25519::StaticKeypair::generate(&mut rng).unwrap();
212
8
    let relay_ntor_keys = RelayNtorKeys::new(relay_ntor_keys.into());
213

            
214
    // Since channels only take a `Weak`, it means we need to keep the `Arc` around.
215
    // This is just a test and the channel provider is a no-op,
216
    // so keep a global around forever so that we can forget about it.
217
    static CHAN_PROVIDER: LazyLock<Arc<NoOpChannelProvider>> =
218
2
        LazyLock::new(|| Arc::new(NoOpChannelProvider));
219
8
    let chan_provider = Arc::downgrade(&CHAN_PROVIDER);
220

            
221
8
    let (client_chan, relay_chan, circuit_stream_rx) = new_channel_pair(
222
8
        rt,
223
8
        chan_provider,
224
8
        relay_ids.clone(),
225
8
        relay_ntor_keys.clone(),
226
8
        conn_inspector,
227
8
    );
228

            
229
8
    let mut target_builder = OwnedCircTarget::builder();
230
8
    target_builder.ntor_onion_key(*relay_ntor_keys.latest().public().inner());
231
8
    *target_builder.chan_target().ids() = RelayIdsBuilder::from_relay_ids(&relay_ids);
232

            
233
8
    (client_chan, relay_chan, circuit_stream_rx, target_builder)
234
8
}
235

            
236
/// Create a new [`PendingClientTunnel`] and start its reactor.
237
14
pub(crate) async fn new_pending_tunnel<R: Runtime>(
238
14
    rt: &R,
239
14
    channel: &Arc<Channel>,
240
14
) -> PendingClientTunnel {
241
    struct Timeouts;
242

            
243
    impl TimeoutEstimator for Timeouts {
244
        fn circuit_build_timeout(&self, _length: usize) -> Duration {
245
            // Chosen arbitrarily.
246
            Duration::from_secs(60)
247
        }
248
    }
249

            
250
14
    let (pending_tunnel, reactor) = channel.new_tunnel(Arc::new(Timeouts)).await.unwrap();
251

            
252
14
    rt.spawn(async {
253
14
        let _ = reactor.run().await;
254
14
    })
255
14
    .unwrap();
256

            
257
14
    pending_tunnel
258
14
}
259

            
260
/// Clone a `ChanCell`.
261
///
262
/// This is a hack since `ChanCell` doesn't implement `Clone`.
263
#[cfg(feature = "relay")]
264
40
fn clone_chan_cell(cell: AnyChanCell) -> (AnyChanCell, AnyChanCell) {
265
40
    let (circ_id, msg) = cell.into_circid_and_msg();
266

            
267
40
    let cell_1 = AnyChanCell::new(circ_id, msg.clone());
268
40
    let cell_2 = AnyChanCell::new(circ_id, msg);
269

            
270
40
    (cell_1, cell_2)
271
40
}
272

            
273
/// Inspect the cells transitting a connection between two channel objects
274
/// corresponding to a client and a relay.
275
#[cfg(feature = "relay")]
276
pub(crate) struct ConnInspector {
277
    /// Cells from the client to relay.
278
    client_inspector_tx: mpsc::UnboundedSender<AnyChanCell>,
279
    client_inspector_rx: mpsc::UnboundedReceiver<AnyChanCell>,
280

            
281
    /// Cells from the relay to client.
282
    relay_inspector_tx: mpsc::UnboundedSender<AnyChanCell>,
283
    relay_inspector_rx: mpsc::UnboundedReceiver<AnyChanCell>,
284
}
285

            
286
#[cfg(feature = "relay")]
287
impl ConnInspector {
288
    /// A new [`ConnInspector`].
289
8
    pub(crate) fn new() -> Self {
290
8
        let (client_inspector_tx, client_inspector_rx) = mpsc::unbounded();
291
8
        let (relay_inspector_tx, relay_inspector_rx) = mpsc::unbounded();
292

            
293
8
        ConnInspector {
294
8
            client_inspector_tx,
295
8
            client_inspector_rx,
296
8
            relay_inspector_tx,
297
8
            relay_inspector_rx,
298
8
        }
299
8
    }
300

            
301
    /// Try to get the next message sent by the client.
302
14
    pub(crate) fn try_client_cell(&mut self) -> Option<AnyChanCell> {
303
14
        self.client_inspector_rx.try_recv().ok()
304
14
    }
305

            
306
    /// Try to get the next message sent by the relay.
307
26
    pub(crate) fn try_relay_cell(&mut self) -> Option<AnyChanCell> {
308
26
        self.relay_inspector_rx.try_recv().ok()
309
26
    }
310

            
311
    /// Wait for the next message sent by the client.
312
18
    pub(crate) async fn client_cell(&mut self) -> Option<AnyChanCell> {
313
12
        self.client_inspector_rx.recv().await.ok()
314
12
    }
315

            
316
    /// Wait for the next message sent by the relay.
317
    #[expect(dead_code)]
318
    pub(crate) async fn relay_cell(&mut self) -> Option<AnyChanCell> {
319
        self.relay_inspector_rx.recv().await.ok()
320
    }
321
}