Skip to main content

tari_comms/tor/hidden_service/
builder.rs

1// Copyright 2020, The Tari Project
2//
3// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
4// following conditions are met:
5//
6// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
7// disclaimer.
8//
9// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
10// following disclaimer in the documentation and/or other materials provided with the distribution.
11//
12// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
13// products derived from this software without specific prior written permission.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
21// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23use std::sync::Arc;
24
25use bitflags::bitflags;
26use log::*;
27use tari_shutdown::{OptionalShutdownSignal, ShutdownSignal};
28use thiserror::Error;
29
30use super::controller::HiddenServiceControllerError;
31use crate::{
32    multiaddr::Multiaddr,
33    socks,
34    tor::{
35        Authentication,
36        PortMapping,
37        TorIdentity,
38        hidden_service::{TorProxyOpts, controller::HiddenServiceController},
39    },
40};
41
42const LOG_TARGET: &str = "comms::tor::hidden_service";
43
44#[derive(Debug, Error)]
45pub enum HiddenServiceBuilderError {
46    #[error("The proxied port mapping was not provided. Use `with_proxied_port_mapping` to set it.")]
47    ProxiedPortMappingNotProvided,
48    #[error("The control server address was not provided. Use `with_control_server_address` to set it.")]
49    TorControlServerAddressNotProvided,
50    #[error("HiddenServiceControllerError: {0}")]
51    HiddenServiceControllerError(#[from] HiddenServiceControllerError),
52}
53
54bitflags! {
55    /// Hidden service flags
56    #[derive(Default)]
57    pub struct HsFlags: u32 {
58        const NONE = 0x0;
59        /// Detach the service from the control server connection. This keeps the hidden service active even if comms is shutdown.
60        const DETACH = 0x1;
61    }
62}
63
64/// Builder for Tor Hidden Services
65#[derive(Default)]
66pub struct HiddenServiceBuilder {
67    identity: Option<TorIdentity>,
68    port_mapping: Option<PortMapping>,
69    socks_addr_override: Option<Multiaddr>,
70    control_server_addr: Option<Multiaddr>,
71    proxy_opts: TorProxyOpts,
72    control_server_auth: Authentication,
73    socks_auth: socks::Authentication,
74    hs_flags: HsFlags,
75    shutdown_signal: OptionalShutdownSignal,
76}
77
78impl HiddenServiceBuilder {
79    pub fn new() -> Self {
80        Default::default()
81    }
82}
83
84impl HiddenServiceBuilder {
85    setter!(
86        /// The address of the Tor Control Port. An error will result if this is not provided.
87        with_control_server_address,
88        control_server_addr,
89        Option<Multiaddr>
90    );
91
92    setter!(
93        /// Configure the underlying SOCKS transport to bypass the proxy and connect directly to these addresses
94        with_bypass_proxy_addresses,
95        proxy_opts.bypass_addresses,
96        Arc<Vec<Multiaddr>>
97    );
98
99    setter!(
100        /// Authentication settings for the Tor Control Port.
101        with_control_server_auth,
102        control_server_auth,
103        Authentication
104    );
105
106    setter!(
107        /// Authentication to use for the SOCKS5 proxy.
108        with_socks_authentication,
109        socks_auth,
110        socks::Authentication
111    );
112
113    setter!(
114        /// The identity of the hidden service. When set, this key is used to enable routing from the Tor network to
115        /// this address. If this is not set, a new service will be requested from the Tor Control Port.
116        with_tor_identity,
117        identity,
118        Option<TorIdentity>
119    );
120
121    setter!(
122        /// Configuration flags for the hidden service
123        with_hs_flags,
124        hs_flags,
125        HsFlags
126    );
127
128    /// Use a direct TCP/IP connection if a TCP address is given instead of the tor proxy. This is worse for privacy
129    /// but can use the full available connection bandwidth
130    pub fn bypass_tor_for_tcp_addresses(mut self) -> Self {
131        self.proxy_opts.bypass_for_tcpip = true;
132        self
133    }
134
135    /// The address of the SOCKS5 server. If an address is None, the hidden service builder will use the SOCKS
136    /// listener address as given by the tor control port.
137    pub fn with_shutdown_signal(mut self, shutdown_signal: ShutdownSignal) -> Self {
138        self.shutdown_signal.set(shutdown_signal);
139        self
140    }
141
142    /// The address of the SOCKS5 server. If an address is None, the hidden service builder will use the SOCKS
143    /// listener address as given by the tor control port.
144    pub fn with_socks_address_override(mut self, socks_addr_override: Option<Multiaddr>) -> Self {
145        self.socks_addr_override = socks_addr_override;
146        self
147    }
148
149    /// Set the PortMapping to use when creating this hidden service. A PortMapping maps a Tor port to a proxied address
150    /// (usually local). An error will result if this is not provided.
151    pub fn with_port_mapping<P: Into<PortMapping>>(mut self, port_mapping: P) -> Self {
152        self.port_mapping = Some(port_mapping.into());
153        self
154    }
155}
156
157impl HiddenServiceBuilder {
158    /// Create a HiddenService with the given builder parameters.
159    pub fn build(self) -> Result<HiddenServiceController, HiddenServiceBuilderError> {
160        let proxied_port_mapping = self
161            .port_mapping
162            .ok_or(HiddenServiceBuilderError::ProxiedPortMappingNotProvided)?;
163        let control_server_addr = self
164            .control_server_addr
165            .ok_or(HiddenServiceBuilderError::TorControlServerAddressNotProvided)?;
166
167        debug!(
168            target: LOG_TARGET,
169            "Building tor hidden service with control port '{control_server_addr}' and port mapping '{proxied_port_mapping}'"
170        );
171
172        let controller = HiddenServiceController::new(
173            control_server_addr,
174            self.control_server_auth,
175            proxied_port_mapping,
176            self.socks_addr_override,
177            self.socks_auth,
178            self.identity,
179            self.hs_flags,
180            self.proxy_opts,
181            self.shutdown_signal,
182        );
183
184        Ok(controller)
185    }
186}