aboutsummaryrefslogtreecommitdiff
path: root/crates/tor-hsservice/src/req.rs
blob: 4f8a5c5c2c41f80805a0c662446e2eddd7751146 (plain)
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
155
156
157
//! Request objects used to implement onion services.
//!
//! These requests are yielded on a stream, and the calling code needs to decide
//! whether to permit or reject them.

use futures::{channel::mpsc, Stream};
use std::net::SocketAddr;
use tor_cell::relaycell::msg::Introduce2;

use tor_error::Bug;
use tor_proto::{circuit::handshake::hs_ntor::HsNtorServiceInput, stream::DataStream};

use crate::{svc::rend_handshake, ClientError, IptLocalId};

/// Request to complete an introduction/rendezvous handshake.
///
/// A request of this kind indicates that a client has asked permission to
/// connect to an onion service through an introduction point.  The caller needs
/// to decide whether or not to complete the handshake.
///
/// Protocol details: More specifically, we create one of these whenever we get a well-formed
/// `INTRODUCE2` message.  Based on this, the caller decides whether to send a
/// `RENDEZVOUS1` message.
#[derive(Debug)]
pub struct RendRequest {
    /// The introduction point that sent this request.
    ipt_lid: IptLocalId,

    /// The message as received from the remote introduction point.
    raw: Introduce2,

    /// The introduce2 message that we've decrypted and processed.
    ///
    /// We do not compute this immediately upon receiving the Introduce2 cell,
    /// since there is a bit of cryptography involved and we don't want to add
    /// any extra latency to the message handler.
    ///
    /// TODO: This also contains `raw`, which is maybe not so great; it would be
    /// neat to implement more efficiently.
    expanded: once_cell::unsync::OnceCell<rend_handshake::IntroRequest>,
}

/// The cryptographic state needed to complete an introduce/rendezvous
/// handshake.
#[derive(Debug, Clone)]
struct HandshakeState {
    // TODO HSS: replace this type or its contents as needed.
}

/// Information about a proof of work received from a client's introduction
/// point.
///  
// Todo: use Beth's API instead.
#[derive(Debug, Clone)]
enum ProofOfWork {
    /// TODO HSS document or replace.
    EquixV1 {
        /// TODO HSS document or replace
        effort_level: usize,
    },
}

/// A request from a client to open a new stream to an onion service.
///
/// We can only receive these _after_ we have already permitted the client to
/// connect via a [`RendRequest`].
///
/// Protocol details: More specifically, we create one of these whenever we get a well-formed
/// `BEGIN` message.  Based on this, the caller decides whether to send a
/// `CONNECTED` message.
#[derive(Debug)]
pub struct StreamRequest {
    /// The object that will be used to send data to and from the client.
    ///
    /// TODO HSS: Possibly instead this will be some type from tor_proto that
    /// can turn into a DataStream.
    stream: DataStream,

    /// The address that the client has asked to connect to.
    ///
    /// TODO HSS: This is the wrong type! It may be a hostname.
    target: SocketAddr,
}

/// A stream opened over an onion service.
//
// TODO HSS: This may belong in another module.
#[derive(Debug)]
pub struct OnionServiceDataStream {
    /// The underlying data stream; this type is just a thin wrapper.
    inner: DataStream,
}

impl RendRequest {
    /// Construct a new RendRequest from its parts.
    pub(crate) fn new(ipt_lid: IptLocalId, msg: Introduce2) -> Self {
        Self {
            ipt_lid,
            raw: msg,
            expanded: Default::default(),
        }
    }

    /// Try to return a reference to the intro_request, creating it if it did
    /// not previously exist.
    ///
    // TODO HSS: Perhaps we need to have an Arc<HsNtorServiceInput> as a member
    // of this type instead of an argument here.
    fn intro_request(
        &self,
        keys: &HsNtorServiceInput,
    ) -> Result<&rend_handshake::IntroRequest, rend_handshake::IntroRequestError> {
        self.expanded.get_or_try_init(|| {
            rend_handshake::IntroRequest::decrypt_from_introduce2(self.raw.clone(), keys)
        })
    }

    /// Mark this request as accepted, and try to connect to the client's
    /// provided rendezvous point.
    ///
    /// TODO HSS: Should this really be async?  It might be nicer if it weren't.
    pub async fn accept(self) -> Result<impl Stream<Item = StreamRequest>, ClientError> {
        let r: Result<mpsc::Receiver<StreamRequest>, ClientError>;
        todo!();
        #[allow(unreachable_code)]
        r
    }
    /// Reject this request.  (The client will receive no notification.)
    ///
    /// TODO HSS: Should this really be async?  It might be nicer if it weren't.
    /// TODO HSS: Should this really be fallible?  How might it fail?
    pub async fn reject(self) -> Result<(), Bug> {
        // nothing to do.
        Ok(())
    }
    //
    // TODO HSS: also add various accessors
}

impl StreamRequest {
    /// Accept this request and send the client a `CONNECTED` message.
    pub async fn accept(self) -> Result<OnionServiceDataStream, ClientError> {
        todo!()
    }
    /// Reject this request, and send the client an `END` message.
    /// TODO HSS: Should this really be fallible?  How might it fail?
    pub async fn reject(self) -> Result<(), Bug> {
        todo!()
    }
    /// Reject this request and close the rendezvous circuit entirely,
    /// along with all other streams attached to the circuit.
    /// TODO HSS: Should this really be fallible?  How might it fail?
    pub fn shutdown_circuit(self) -> Result<(), Bug> {
        todo!()
    }
    // TODO HSS various accessors, including for circuit.
}