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::reactor::test::new_reactor;
22
use crate::channel::{
23
    BoxedChannelSink, BoxedChannelStream, Canonicity, Channel, ChannelMode, Reactor, UniqId,
24
};
25
use crate::client::circuit::{PendingClientTunnel, TimeoutEstimator};
26
use crate::memquota::{ChannelAccount, SpecificAccount};
27
use crate::peer::{PeerAddr, PeerInfo};
28

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

            
38
pub(crate) use crate::channel::reactor::test::CodecResult;
39

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

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

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

            
78
32
    (chan, reactor)
79
32
}
80

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

            
97
16
    let circ_net_params = CircNetParameters {
98
16
        cc: CongestionControlNetParams::defaults_for_tests(),
99
16
    };
100

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

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

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

            
130
16
    (c_to_r_tx, c_to_r_rx) = mpsc::channel(32);
131
16
    (r_to_c_tx, r_to_c_rx) = mpsc::channel(32);
132

            
133
    // `BoxedChannelStream` requires `Item = Result<AnyChanCell, _>`.
134
16
    let c_to_r_rx = c_to_r_rx.map(Ok);
135
16
    let r_to_c_rx = r_to_c_rx.map(Ok);
136

            
137
    // `BoxedChannelSink` requires `Error = crate::Error`.
138
16
    let c_to_r_tx = c_to_r_tx.sink_map_err(|e| crate::Error::CellDecodeErr {
139
        object: "reactor test",
140
2
        err: tor_cell::Error::ChanProto(format!("Sink error: {e:?}")),
141
2
    });
142
16
    let r_to_c_tx = r_to_c_tx.sink_map_err(|e| crate::Error::CellDecodeErr {
143
        object: "reactor test",
144
6
        err: tor_cell::Error::ChanProto(format!("Sink error: {e:?}")),
145
6
    });
146

            
147
    // We want to clone cells that the client channel or relay channel sends,
148
    // and store a copy in the connection inspector.
149
    // The connection inspector may also want to modify the cells.
150

            
151
    // Integrate the connection inspector with the client-to-relay sink.
152
16
    let client_inspector_tx = conn_inspector.client_inspector_tx.clone();
153
16
    let client_cell_modify_fn = Arc::clone(&conn_inspector.client_cell_modify_fn);
154
46
    let c_to_r_tx = c_to_r_tx.with(move |cell: AnyChanCell| {
155
46
        let (mut cell, cell_clone) = clone_chan_cell(cell);
156
46
        client_cell_modify_fn(&mut cell);
157
        // The connection inspector gets the original cell,
158
        // and the modified cell is sent to the relay.
159
46
        let _ = client_inspector_tx.unbounded_send(cell_clone);
160
46
        async move { Ok(cell) }
161
46
    });
162
16
    let c_to_r_tx = Box::pin(c_to_r_tx);
163

            
164
    // Integrate the connection inspector with the relay-to-client sink.
165
16
    let relay_inspector_tx = conn_inspector.relay_inspector_tx.clone();
166
16
    let relay_cell_modify_fn = Arc::clone(&conn_inspector.relay_cell_modify_fn);
167
30
    let r_to_c_tx = r_to_c_tx.with(move |cell: AnyChanCell| {
168
30
        let (mut cell, cell_clone) = clone_chan_cell(cell);
169
30
        relay_cell_modify_fn(&mut cell);
170
        // The connection inspector gets the original cell,
171
        // and the modified cell is sent to the client.
172
30
        let _ = relay_inspector_tx.unbounded_send(cell_clone);
173
30
        async move { Ok(cell) }
174
30
    });
175
16
    let r_to_c_tx = Box::pin(r_to_c_tx);
176

            
177
    // The `Channel` requires these to be boxed trait objects.
178
16
    let (c_to_r_tx, c_to_r_rx) = (Box::new(c_to_r_tx), Box::new(c_to_r_rx));
179
16
    let (r_to_c_tx, r_to_c_rx) = (Box::new(r_to_c_tx), Box::new(r_to_c_rx));
180

            
181
16
    let (client_chan, client_reactor) =
182
16
        new_channel(rt, client_mode, relay_info, c_to_r_tx, r_to_c_rx);
183

            
184
16
    let (relay_chan, relay_reactor) =
185
16
        new_channel(rt, relay_mode, client_info, r_to_c_tx, c_to_r_rx);
186

            
187
16
    rt.spawn(async {
188
16
        let _ = futures::future::join(client_reactor.run(), relay_reactor.run()).await;
189
16
    })
190
16
    .unwrap();
191

            
192
16
    (client_chan, relay_chan, circuit_stream_rx)
193
16
}
194

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

            
213
    // Keys are chosen arbitrarily.
214
16
    let relay_ids = RelayIds::builder()
215
16
        .ed_identity([6_u8; 32].into())
216
16
        .rsa_identity([10_u8; 20].into())
217
16
        .build()
218
16
        .unwrap();
219

            
220
16
    let relay_ntor_keys = tor_llcrypto::pk::curve25519::StaticKeypair::generate(&mut rng).unwrap();
221
16
    let relay_ntor_keys = RelayNtorKeys::new(relay_ntor_keys.into());
222

            
223
    // Since channels only take a `Weak`, it means we need to keep the `Arc` around.
224
    // This is just a test and the channel provider is a no-op,
225
    // so keep a global around forever so that we can forget about it.
226
    static CHAN_PROVIDER: LazyLock<Arc<NoOpChannelProvider>> =
227
2
        LazyLock::new(|| Arc::new(NoOpChannelProvider));
228
16
    let chan_provider = Arc::downgrade(&CHAN_PROVIDER);
229

            
230
16
    let (client_chan, relay_chan, circuit_stream_rx) = new_channel_pair(
231
16
        rt,
232
16
        chan_provider,
233
16
        relay_ids.clone(),
234
16
        relay_ntor_keys.clone(),
235
16
        conn_inspector,
236
16
    );
237

            
238
16
    let mut target_builder = OwnedCircTarget::builder();
239
16
    target_builder.ntor_onion_key(*relay_ntor_keys.latest().public().inner());
240
16
    *target_builder.chan_target().ids() = RelayIdsBuilder::from_relay_ids(&relay_ids);
241

            
242
16
    (client_chan, relay_chan, circuit_stream_rx, target_builder)
243
16
}
244

            
245
/// Create a new [`PendingClientTunnel`] and start its reactor.
246
30
pub(crate) async fn new_pending_tunnel<R: Runtime>(
247
30
    rt: &R,
248
30
    channel: &Arc<Channel>,
249
30
) -> PendingClientTunnel {
250
    struct Timeouts;
251

            
252
    impl TimeoutEstimator for Timeouts {
253
        fn circuit_build_timeout(&self, _length: usize) -> Duration {
254
            // Chosen arbitrarily.
255
            Duration::from_secs(60)
256
        }
257
    }
258

            
259
30
    let (pending_tunnel, reactor) = channel.new_tunnel(Arc::new(Timeouts)).await.unwrap();
260

            
261
30
    rt.spawn(async {
262
30
        let _ = reactor.run().await;
263
30
    })
264
30
    .unwrap();
265

            
266
30
    pending_tunnel
267
30
}
268

            
269
/// Dummy channel, for testing.
270
pub(crate) struct DummyChan {
271
    /// Tor channel output
272
    pub(crate) rx: mpsc::Receiver<AnyChanCell>,
273
    /// Tor channel input
274
    pub(crate) tx: mpsc::Sender<CodecResult>,
275
    /// A handle to the Channel object, to prevent the channel reactor
276
    /// from shutting down prematurely.
277
    pub(crate) channel: Arc<Channel>,
278
}
279

            
280
impl DummyChan {
281
    /// Create a dummy channel, and spawn a task for its reactor.
282
424
    pub(crate) fn run<R: Runtime>(rt: &R, mode: ChannelMode) -> DummyChan {
283
424
        let (channel, chan_reactor, rx, tx) = new_reactor(rt.clone(), mode);
284
424
        rt.spawn(async {
285
424
            let _ignore = chan_reactor.run().await;
286
372
        })
287
424
        .unwrap();
288

            
289
424
        DummyChan { tx, rx, channel }
290
424
    }
291
}
292

            
293
/// Clone a `ChanCell`.
294
///
295
/// This is a hack since `ChanCell` doesn't implement `Clone`.
296
#[cfg(feature = "relay")]
297
76
fn clone_chan_cell(cell: AnyChanCell) -> (AnyChanCell, AnyChanCell) {
298
76
    let (circ_id, msg) = cell.into_circid_and_msg();
299

            
300
76
    let cell_1 = AnyChanCell::new(circ_id, msg.clone());
301
76
    let cell_2 = AnyChanCell::new(circ_id, msg);
302

            
303
76
    (cell_1, cell_2)
304
76
}
305

            
306
/// Inspect and modify the cells transitting a connection between two channel objects
307
/// corresponding to a client channel and a relay channel.
308
#[cfg(feature = "relay")]
309
pub(crate) struct ConnInspector {
310
    /// For cells sent from the client to relay.
311
    ///
312
    /// This should be attached to the client channel's [`BoxedChannelSink`],
313
    /// so that when the channel sends a cell,
314
    /// the cell is also copied to this queue.
315
    client_inspector_tx: mpsc::UnboundedSender<AnyChanCell>,
316

            
317
    /// For cells sent from the client to relay.
318
    ///
319
    /// This can be used to inspect cells that were sent on the channel
320
    /// using [`Self::client_cell()`] or [`Self::try_client_cell()`].
321
    client_inspector_rx: mpsc::UnboundedReceiver<AnyChanCell>,
322

            
323
    /// For cells sent from the relay to client.
324
    ///
325
    /// This should be attached to the relay channnel's [`BoxedChannelSink`],
326
    /// so that when the channel sends a cell,
327
    /// the cell is also copied to this queue.
328
    relay_inspector_tx: mpsc::UnboundedSender<AnyChanCell>,
329

            
330
    /// For cells sent from the relay to client.
331
    ///
332
    /// This can be used to inspect cells that were sent on the channel
333
    /// using [`Self::relay_cell()`] or [`Self::try_relay_cell()`].
334
    relay_inspector_rx: mpsc::UnboundedReceiver<AnyChanCell>,
335

            
336
    /// Function to modify cells sent from the client to relay.
337
    ///
338
    /// This should be attached to the client channel's [`BoxedChannelSink`],
339
    /// so that any cell sent by the channel can be modified by this function.
340
    client_cell_modify_fn: Arc<dyn Fn(&mut AnyChanCell) + Send + Sync>,
341

            
342
    /// Function to modify cells sent from the relay to client.
343
    ///
344
    /// This should be attached to the relay channel's [`BoxedChannelSink`],
345
    /// so that any cell sent by the channel can be modified by this function.
346
    relay_cell_modify_fn: Arc<dyn Fn(&mut AnyChanCell) + Send + Sync>,
347
}
348

            
349
#[cfg(feature = "relay")]
350
impl ConnInspector {
351
    /// A new [`ConnInspector`].
352
16
    pub(crate) fn new() -> Self {
353
16
        let (client_inspector_tx, client_inspector_rx) = mpsc::unbounded();
354
16
        let (relay_inspector_tx, relay_inspector_rx) = mpsc::unbounded();
355

            
356
        // By default we don't modify the cells.
357
36
        let client_cell_modify_fn = Arc::new(|_: &mut AnyChanCell| {});
358
38
        let relay_cell_modify_fn = Arc::new(|_: &mut AnyChanCell| {});
359

            
360
16
        ConnInspector {
361
16
            client_inspector_tx,
362
16
            client_inspector_rx,
363
16
            relay_inspector_tx,
364
16
            relay_inspector_rx,
365
16
            client_cell_modify_fn,
366
16
            relay_cell_modify_fn,
367
16
        }
368
16
    }
369

            
370
    /// Set a function that will be applied to all cells sent from the client to relay.
371
8
    pub(crate) fn set_client_cell_modifier(
372
8
        &mut self,
373
8
        mod_fn: impl Fn(&mut AnyChanCell) + Send + Sync + 'static,
374
8
    ) {
375
8
        self.client_cell_modify_fn = Arc::new(mod_fn);
376
8
    }
377

            
378
    /// Set a function that will be applied to all cells sent from the relay to client.
379
    // We don't use this yet, but it complements `set_client_cell_modifier()`.
380
    #[expect(unused)]
381
    pub(crate) fn set_relay_cell_modifier(
382
        &mut self,
383
        mod_fn: impl Fn(&mut AnyChanCell) + Send + Sync + 'static,
384
    ) {
385
        self.relay_cell_modify_fn = Arc::new(mod_fn);
386
    }
387

            
388
    /// Try to get the next message sent by the client.
389
    ///
390
    /// This will return the cell *before* any modification from
391
    /// the function provided to [`Self::set_client_cell_modifier()`].
392
68
    pub(crate) fn try_client_cell(&mut self) -> Option<AnyChanCell> {
393
68
        self.client_inspector_rx.try_recv().ok()
394
68
    }
395

            
396
    /// Try to get the next message sent by the relay.
397
    ///
398
    /// This will return the cell *before* any modification from
399
    /// the function provided to [`Self::set_relay_cell_modifier()`].
400
68
    pub(crate) fn try_relay_cell(&mut self) -> Option<AnyChanCell> {
401
68
        self.relay_inspector_rx.try_recv().ok()
402
68
    }
403

            
404
    /// Wait for the next message sent by the client.
405
    ///
406
    /// This will return the cell *before* any modification from
407
    /// the function provided to [`Self::set_client_cell_modifier()`].
408
21
    pub(crate) async fn client_cell(&mut self) -> Option<AnyChanCell> {
409
14
        self.client_inspector_rx.recv().await.ok()
410
14
    }
411

            
412
    /// Wait for the next message sent by the relay.
413
    ///
414
    /// This will return the cell *before* any modification from
415
    /// the function provided to [`Self::set_relay_cell_modifier()`].
416
    #[expect(dead_code)]
417
    pub(crate) async fn relay_cell(&mut self) -> Option<AnyChanCell> {
418
        self.relay_inspector_rx.recv().await.ok()
419
    }
420
}