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}