1
//! Code related to tunnel object that wraps the tor-proto tunnel.
2
//!
3
//! These tunnel types are part of the public API.
4

            
5
use derive_deftly::{Deftly, define_derive_deftly};
6
use std::{net::IpAddr, sync::Arc};
7

            
8
use tor_cell::relaycell::msg::AnyRelayMsg;
9
use tor_error::internal;
10
use tor_linkspec::{CircTarget, IntoOwnedChanTarget, OwnedChanTarget};
11
use tor_proto::{
12
    ClockSkew, TargetHop,
13
    circuit::UniqId,
14
    client::circuit::{CircParameters, CircuitBinding, ClientCirc},
15
    client::stream::{DataStream, StreamParameters},
16
};
17
use tracing::instrument;
18

            
19
use crate::{Error, Result};
20

            
21
#[cfg(feature = "hs-common")]
22
use tor_proto::client::circuit::handshake;
23

            
24
// The tunnel base methods. This MUST be derived on all tunnel types.
25
define_derive_deftly! {
26
    BaseTunnel for struct:
27

            
28
    impl From<tor_proto::ClientTunnel> for $ttype {
29
        fn from(tunnel: tor_proto::ClientTunnel) -> Self {
30
            Self { tunnel: Arc::new(tunnel) }
31
        }
32
    }
33

            
34
    impl From<Arc<tor_proto::ClientTunnel>> for $ttype {
35
        fn from(tunnel: Arc<tor_proto::ClientTunnel>) -> Self {
36
            Self { tunnel }
37
        }
38
    }
39

            
40
    impl AsRef<tor_proto::ClientTunnel> for $ttype {
41
        fn as_ref(&self) -> &tor_proto::ClientTunnel {
42
            self.tunnel.as_ref()
43
        }
44
    }
45

            
46
    impl $ttype {
47
        /// Return a reference to the underlying tunnel.
48
        ///
49
        /// Note: The "tunnel" name is hardcoded here. If it becomes an annoyance, we could make it
50
        /// as a meta value of the deftly declaration.
51
        fn tunnel_ref(&self) -> &Arc<tor_proto::ClientTunnel> {
52
            &self.tunnel
53
        }
54

            
55
        /// Return true if this tunnel is closed and therefore unusable.
56
        pub fn is_closed(&self) -> bool {
57
            self.tunnel_ref().is_closed()
58
        }
59

            
60
        /// Return a [`TargetHop`] representing precisely the last hop of the circuit as in set as a
61
        /// HopLocation with its id and hop number.
62
        ///
63
        /// Return an error if there is no last hop.
64
        pub fn last_hop(&self) -> Result<TargetHop> {
65
            self.tunnel_ref().last_hop()
66
                .map_err(|error| Error::Protocol {
67
                    action: "get last hop",
68
                    peer: None,
69
                    error,
70
                    unique_id: Some(self.tunnel.unique_id()),
71
                })
72
        }
73

            
74
        /// Shutdown the tunnel meaning this sends a shutdown command to the underlying circuit
75
        /// reactor which will stop asynchronously.
76
        ///
77
        /// Note that it is not necessary to use this method as in if the tunnel reference is
78
        /// dropped, the circuit will close automatically.
79
        pub fn terminate(&self) {
80
            self.tunnel_ref().terminate();
81
        }
82

            
83
        /// Return a process-unique identifier for this tunnel.
84
        pub fn unique_id(&self) -> UniqId {
85
            self.tunnel_ref().unique_id()
86
        }
87

            
88
        /// Send raw message.
89
        #[cfg(feature = "send-control-msg")]
90
        pub async fn send_raw_msg(&self, msg: AnyRelayMsg, hop: TargetHop) -> Result<()> {
91
            self.tunnel_ref()
92
                .send_raw_msg(msg, hop)
93
                .await
94
                .map_err(|error| Error::Protocol {
95
                    action: "send raw msg",
96
                    peer: None,
97
                    error,
98
                    unique_id: Some(self.tunnel.unique_id()),
99
                })
100
        }
101

            
102
        /// Start an ad-hoc protocol exchange to the specified hop on this tunnel.
103
        ///
104
        /// See [`ClientTunnel::start_conversation`](tor_proto::ClientTunnel::start_conversation)
105
        /// documentation for more details.
106
        #[cfg(feature = "send-control-msg")]
107
        pub async fn start_conversation(&self,
108
            msg: Option<tor_cell::relaycell::msg::AnyRelayMsg>,
109
            reply_handler: impl tor_proto::MsgHandler + Send + 'static,
110
            hop: TargetHop
111
        ) -> Result<tor_proto::Conversation<'_>> {
112
            self.tunnel_ref().start_conversation(msg, reply_handler, hop).await
113
                .map_err(|error| Error::Protocol {
114
                    action: "start conversation",
115
                    peer: None,
116
                    error,
117
                    unique_id: Some(self.tunnel_ref().unique_id()),
118
                })
119
        }
120

            
121
        /// Return a future that will resolve once this circuit has closed.
122
        ///
123
        /// Note that this method does not itself cause the circuit to shut down.
124
        ///
125
        // TODO: Perhaps this should return some kind of status indication instead
126
        // of just ()
127
        pub fn wait_for_close(&self) -> impl futures::Future<Output = ()> + Send + Sync + 'static + use<> {
128
            self.tunnel_ref().wait_for_close()
129
        }
130

            
131
        // TODO(conflux): mq_account() is not needed because it is only used internally in a ClientCirc
132
        // in order to open streams. It might be the case that we need at some point to get the
133
        // CircuitAccount(s) from a tunnel. We would need then to either have a TunnelAccount or return
134
        // a Vec<CircuitAccount>.
135
    }
136
}
137

            
138
// Methods for a single path tunnel.
139
define_derive_deftly! {
140
    SinglePathTunnel for struct:
141

            
142
    impl $ttype {
143
        /// Return a reference to the circuit of this tunnel.
144
        fn circuit(&self) -> Result<&ClientCirc> {
145
            Ok(self.tunnel_ref()
146
                .as_single_circ()
147
                .map_err(|e| internal!("Non single path in a single path tunnel: {}", e))?)
148
        }
149

            
150
        /// Extend the circuit to a new target last hop using the ntor v3 handshake.
151
        ///
152
        /// TODO: Might want to pass which handshake type as a parameter so this function can be a
153
        /// catch all on all possible handshakes. For now, use ntor v3 for all the things.
154
        pub async fn extend<T: CircTarget>(&self, target: &T, params: CircParameters) -> Result<()> {
155
            self.circuit()?
156
                .extend(target, params)
157
                .await
158
                .map_err(|error| Error::Protocol {
159
                    action: "extend tunnel",
160
                    peer: Some(target.to_owned().to_logged()),
161
                    error,
162
                    unique_id: Some(self.tunnel.unique_id()),
163
                })
164
        }
165

            
166
        /// Return the number of hops of the underlying circuit.
167
        pub fn n_hops(&self) -> Result<usize> {
168
            self.circuit()?.n_hops()
169
                .map_err(|error| Error::Protocol {
170
                    action: "get number hops",
171
                    peer: None,
172
                    error,
173
                    unique_id: Some(self.tunnel_ref().unique_id()),
174
                })
175
        }
176

            
177
    }
178
}
179

            
180
// Methods for a multi path tunnel.
181
#[cfg(feature = "conflux")]
182
define_derive_deftly! {
183
    MultiPathTunnel for struct:
184

            
185
    impl $ttype {
186
        // TODO(conflux)
187
        //
188
        // As we add multi path support accross the code, we'll might need or not some specific
189
        // functions that would go here.
190
    }
191
}
192

            
193
// Methods for a tunnel that can transmit data (BEGIN).
194
define_derive_deftly! {
195
    DataTunnel for struct:
196

            
197
    impl $ttype {
198
        /// Start a stream to the given address and port, using a BEGIN cell.
199
        ///
200
        /// The use of a string for the address is intentional: you should let
201
        /// the remote Tor relay do the hostname lookup for you.
202
        #[instrument(skip_all, level = "trace")]
203
        pub async fn begin_stream(
204
            &self,
205
            target: &str,
206
            port: u16,
207
            params: Option<StreamParameters>,
208
        ) -> Result<DataStream> {
209
            self.tunnel_ref()
210
                .begin_stream(target, port, params)
211
                .await
212
                .map_err(|error| Error::Protocol {
213
                    action: "begin stream",
214
                    peer: None,
215
                    error,
216
                    unique_id: Some(self.tunnel.unique_id()),
217
                })
218
        }
219
    }
220

            
221
}
222

            
223
// Methods for a tunnel that can do DNS resolution (RESOLVE).
224
define_derive_deftly! {
225
    DnsTunnel for struct:
226

            
227
    impl $ttype {
228
        /// Perform a DNS lookup, using a RESOLVE cell with the last relay in this circuit.
229
        ///
230
        /// Note that this function does not check for timeouts; that's the caller's responsibility.
231
        pub async fn resolve(&self, hostname: &str) -> Result<Vec<IpAddr>> {
232
            self.tunnel_ref()
233
                .resolve(hostname)
234
                .await
235
                .map_err(|error| Error::Protocol {
236
                    action: "resolve",
237
                    peer: None,
238
                    error,
239
                    unique_id: Some(self.tunnel.unique_id()),
240
                })
241
        }
242

            
243
        /// Perform a reverse DNS lookup, using a RESOLVE cell with the last relay in this circuit.
244
        ///
245
        /// Note that this function does not check for timeouts; that's the caller's responsibility.
246
        pub async fn resolve_ptr(&self, addr: IpAddr) -> Result<Vec<String>> {
247
            self.tunnel_ref()
248
                .resolve_ptr(addr)
249
                .await
250
                .map_err(|error| Error::Protocol {
251
                    action: "resolve PTR",
252
                    peer: None,
253
                    error,
254
                    unique_id: Some(self.tunnel.unique_id()),
255
                })
256
        }
257
    }
258
}
259

            
260
// Methods for a tunnel that can do directory requests (BEGIN_DIR).
261
define_derive_deftly! {
262
    DirTunnel for struct:
263

            
264
    impl $ttype {
265
        /// Start a stream to the given address and port, using a BEGIN_DIR cell.
266
        pub async fn begin_dir_stream(&self) -> Result<DataStream> {
267
            self.tunnel_ref().clone()
268
                .begin_dir_stream()
269
                .await
270
                .map_err(|error| Error::Protocol {
271
                    action: "begin dir stream",
272
                    peer: None,
273
                    error,
274
                    unique_id: Some(self.tunnel.unique_id()),
275
                })
276
        }
277
    }
278
}
279

            
280
// Methods for a tunnel that can transmit data (BEGIN).
281
define_derive_deftly! {
282
    OnionServiceDataTunnel for struct:
283

            
284
    impl $ttype {
285
        /// Extend this circuit by a single, "virtual" hop.
286
        ///
287
        /// A virtual hop is one for which we do not add an actual network connection
288
        /// between separate hosts (such as Relays).  We only add a layer of
289
        /// cryptography.
290
        ///
291
        /// This is used to implement onion services: the client and the service
292
        /// both build a circuit to a single rendezvous point, and tell the
293
        /// rendezvous point to relay traffic between their two circuits.  Having
294
        /// completed a [`handshake`] out of band[^1], the parties each extend their
295
        /// circuits by a single "virtual" encryption hop that represents their
296
        /// shared cryptographic context.
297
        ///
298
        /// Once a circuit has been extended in this way, it is an error to try to
299
        /// extend it in any other way.
300
        ///
301
        /// [^1]: Technically, the handshake is only _mostly_ out of band: the
302
        ///     client sends their half of the handshake in an ` message, and the
303
        ///     service's response is inline in its `RENDEZVOUS2` message.
304
        //
305
        // TODO hs: let's try to enforce the "you can't extend a circuit again once
306
        // it has been extended this way" property.  We could do that with internal
307
        // state, or some kind of a type state pattern.
308
        //
309
        // TODO hs: possibly we should take a set of Protovers, and not just `Params`.
310
        #[cfg(feature = "hs-common")]
311
        pub async fn extend_virtual(
312
            &self,
313
            protocol: handshake::RelayProtocol,
314
            role: handshake::HandshakeRole,
315
            seed: impl handshake::KeyGenerator,
316
            params: CircParameters,
317
            capabilities: &tor_protover::Protocols,
318
        ) -> Result<()> {
319
            self.circuit()?
320
                .extend_virtual(protocol, role, seed, &params, capabilities)
321
                .await
322
                .map_err(|error| Error::Protocol {
323
                    action: "extend virtual tunnel",
324
                    peer: None,
325
                    error,
326
                    unique_id: Some(self.tunnel.unique_id()),
327
                })
328
        }
329
    }
330

            
331
}
332

            
333
/// A client single path data tunnel.
334
#[derive(Debug, Deftly)]
335
#[derive_deftly(BaseTunnel, DataTunnel, DnsTunnel, SinglePathTunnel)]
336
pub struct ClientDataTunnel {
337
    /// The protocol level tunnel.
338
    tunnel: Arc<tor_proto::ClientTunnel>,
339
}
340

            
341
/// A client directory tunnel. This is always single path.
342
#[derive(Debug, Deftly)]
343
#[derive_deftly(BaseTunnel, DirTunnel, SinglePathTunnel)]
344
pub struct ClientDirTunnel {
345
    /// The protocol level tunnel.
346
    tunnel: Arc<tor_proto::ClientTunnel>,
347
}
348

            
349
/// A client onion service single path data tunnel.
350
#[derive(Debug, Deftly)]
351
#[derive_deftly(BaseTunnel, DataTunnel, OnionServiceDataTunnel, SinglePathTunnel)]
352
pub struct ClientOnionServiceDataTunnel {
353
    /// The protocol level tunnel.
354
    tunnel: Arc<tor_proto::ClientTunnel>,
355
}
356

            
357
/// A client onion service directory tunnel (to an HSDir). This is always single path.
358
#[derive(Debug, Deftly)]
359
#[derive_deftly(BaseTunnel, DirTunnel, SinglePathTunnel)]
360
pub struct ClientOnionServiceDirTunnel {
361
    /// The protocol level tunnel.
362
    tunnel: Arc<tor_proto::ClientTunnel>,
363
}
364

            
365
/// A client onion service introduction tunnel. This is always single path.
366
#[derive(Debug, Deftly)]
367
#[derive_deftly(BaseTunnel, SinglePathTunnel)]
368
pub struct ClientOnionServiceIntroTunnel {
369
    /// The protocol level tunnel.
370
    tunnel: Arc<tor_proto::ClientTunnel>,
371
}
372

            
373
/// A service onion service single path data tunnel.
374
#[derive(Debug, Deftly)]
375
#[derive_deftly(BaseTunnel, DataTunnel, OnionServiceDataTunnel, SinglePathTunnel)]
376
pub struct ServiceOnionServiceDataTunnel {
377
    /// The protocol level tunnel.
378
    tunnel: Arc<tor_proto::ClientTunnel>,
379
}
380

            
381
/// A service onion service directory tunnel (to an HSDir). This is always single path.
382
#[derive(Debug, Deftly)]
383
#[derive_deftly(BaseTunnel, DirTunnel, SinglePathTunnel)]
384
pub struct ServiceOnionServiceDirTunnel {
385
    /// The protocol level tunnel.
386
    tunnel: Arc<tor_proto::ClientTunnel>,
387
}
388

            
389
/// A service onion service introduction tunnel. This is always single path.
390
#[derive(Debug, Deftly)]
391
#[derive_deftly(BaseTunnel, SinglePathTunnel)]
392
pub struct ServiceOnionServiceIntroTunnel {
393
    /// The protocol level tunnel.
394
    tunnel: Arc<tor_proto::ClientTunnel>,
395
}
396

            
397
/// A client multi path data tunnel (Conflux).
398
#[cfg(feature = "conflux")]
399
#[derive(Debug, Deftly)]
400
#[derive_deftly(BaseTunnel, DataTunnel, DnsTunnel, MultiPathTunnel)]
401
pub struct ClientMultiPathDataTunnel {
402
    /// The protocol level tunnel.
403
    tunnel: Arc<tor_proto::ClientTunnel>,
404
}
405

            
406
/// A client multi path onion service data tunnel (Conflux, Rendeszvous).
407
#[cfg(feature = "conflux")]
408
#[derive(Debug, Deftly)]
409
#[derive_deftly(BaseTunnel, DataTunnel, MultiPathTunnel)]
410
pub struct ClientMultiPathOnionServiceDataTunnel {
411
    /// The protocol level tunnel.
412
    tunnel: Arc<tor_proto::ClientTunnel>,
413
}
414

            
415
/// A service multi path onion service data tunnel (Conflux, Rendeszvous).
416
#[cfg(feature = "conflux")]
417
#[derive(Debug, Deftly)]
418
#[derive_deftly(BaseTunnel, DataTunnel, MultiPathTunnel)]
419
pub struct ServiceMultiPathOnionServiceDataTunnel {
420
    /// The protocol level tunnel.
421
    tunnel: Arc<tor_proto::ClientTunnel>,
422
}
423

            
424
impl ClientDirTunnel {
425
    /// Return a description of the first hop of this circuit.
426
    pub fn first_hop(&self) -> OwnedChanTarget {
427
        self.tunnel_ref()
428
            .first_hop()
429
            .expect("Bug getting dir tunnel first hop")
430
    }
431

            
432
    /// Get the clock skew claimed by the first hop of the circuit.
433
    ///
434
    /// See [`Channel::clock_skew()`](tor_proto::channel::Channel::clock_skew).
435
    pub async fn first_hop_clock_skew(&self) -> Result<ClockSkew> {
436
        // TODO(conflux): Is this CircCanceled error right?
437
        self.circuit()?
438
            .first_hop_clock_skew()
439
            .await
440
            .map_err(|_| Error::CircCanceled)
441
    }
442
}
443

            
444
impl ServiceOnionServiceDataTunnel {
445
    /// Tell this tunnel to begin allowing the final hop of the tunnel to try
446
    /// to create new Tor streams, and to return those pending requests in an
447
    /// asynchronous stream.
448
    ///
449
    /// Ordinarily, these requests are rejected.
450
    ///
451
    /// There can only be one [`Stream`](futures::Stream) of this type created on a given tunnel.
452
    /// If a such a [`Stream`](futures::Stream) already exists, this method will return
453
    /// an error.
454
    ///
455
    /// After this method has been called on a tunnel, the tunnel is expected
456
    /// to receive requests of this type indefinitely, until it is finally closed.
457
    /// If the `Stream` is dropped, the next request on this tunnel will cause it to close.
458
    ///
459
    /// Only onion services (and eventually) exit relays should call this
460
    /// method.
461
    //
462
    // TODO: Someday, we might want to allow a stream request handler to be
463
    // un-registered.  However, nothing in the Tor protocol requires it.
464
    #[cfg(feature = "hs-service")]
465
    pub async fn allow_stream_requests<'a, FILT>(
466
        &self,
467
        allow_commands: &'a [tor_cell::relaycell::RelayCmd],
468
        hop: TargetHop,
469
        filter: FILT,
470
    ) -> Result<
471
        impl futures::Stream<Item = tor_proto::client::stream::IncomingStream> + use<'a, FILT>,
472
    >
473
    where
474
        FILT: tor_proto::client::stream::IncomingStreamRequestFilter,
475
    {
476
        self.tunnel_ref()
477
            .allow_stream_requests(allow_commands, hop, filter)
478
            .await
479
            .map_err(|error| Error::Protocol {
480
                action: "allow stream requests",
481
                peer: None,
482
                error,
483
                unique_id: Some(self.tunnel.unique_id()),
484
            })
485
    }
486
}
487

            
488
#[cfg(feature = "hs-service")]
489
impl ServiceOnionServiceIntroTunnel {
490
    /// Return the cryptographic material used to prove knowledge of a shared
491
    /// secret with with `hop`.
492
    ///
493
    /// See [`CircuitBinding`] for more information on how this is used.
494
    ///
495
    /// Return None if we have no circuit binding information for the hop, or if
496
    /// the hop does not exist.
497
    pub async fn binding_key(&self, hop: TargetHop) -> Result<Option<CircuitBinding>> {
498
        let circ = self.circuit()?;
499
        circ.binding_key(hop)
500
            .await
501
            .map_err(|error| Error::Protocol {
502
                action: "binding key",
503
                peer: None,
504
                error,
505
                unique_id: Some(self.tunnel.unique_id()),
506
            })
507
    }
508
}