torcontrol.h raw
1 // Copyright (c) 2015-present The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 /**
6 * Functionality for communicating with Tor.
7 */
8 #ifndef BITCOIN_TORCONTROL_H
9 #define BITCOIN_TORCONTROL_H
10
11 #include <netaddress.h>
12 #include <util/fs.h>
13 #include <util/sock.h>
14 #include <util/threadinterrupt.h>
15
16 #include <cstdint>
17 #include <deque>
18 #include <functional>
19 #include <memory>
20 #include <string>
21 #include <thread>
22 #include <vector>
23
24 constexpr uint16_t DEFAULT_TOR_SOCKS_PORT{9050};
25 constexpr int DEFAULT_TOR_CONTROL_PORT = 9051;
26 extern const std::string DEFAULT_TOR_CONTROL;
27 static const bool DEFAULT_LISTEN_ONION = true;
28
29 /** Tor control reply code. Ref: https://spec.torproject.org/control-spec/replies.html */
30 constexpr int TOR_REPLY_OK{250};
31 constexpr int TOR_REPLY_UNRECOGNIZED{510};
32 constexpr int TOR_REPLY_SYNTAX_ERROR{512}; //!< Syntax error in command argument
33
34 CService DefaultOnionServiceTarget(uint16_t port);
35
36 /** Reply from Tor, can be single or multi-line */
37 class TorControlReply
38 {
39 public:
40 TorControlReply() { Clear(); }
41
42 int code;
43 std::vector<std::string> lines;
44
45 void Clear()
46 {
47 code = 0;
48 lines.clear();
49 }
50 };
51
52 /** Low-level handling for Tor control connection.
53 * Speaks the SMTP-like protocol as defined in torspec/control-spec.txt
54 */
55 class TorControlConnection
56 {
57 public:
58 typedef std::function<void(TorControlConnection &,const TorControlReply &)> ReplyHandlerCB;
59
60 /** Create a new TorControlConnection.
61 */
62 explicit TorControlConnection(CThreadInterrupt& interrupt);
63 ~TorControlConnection();
64
65 /**
66 * Connect to a Tor control port.
67 * tor_control_center is address of the form host:port.
68 * Return true on success.
69 */
70 bool Connect(const std::string& tor_control_center);
71
72 /**
73 * Disconnect from Tor control port.
74 */
75 void Disconnect();
76
77 /** Send a command, register a handler for the reply.
78 * A trailing CRLF is automatically added.
79 * Return true on success.
80 */
81 bool Command(const std::string &cmd, const ReplyHandlerCB& reply_handler);
82
83 /**
84 * Check if the connection is established.
85 */
86 bool IsConnected() const;
87
88 /**
89 * Wait for data to be available on the socket.
90 * @param[in] timeout Maximum time to wait
91 * @return true if data is available, false on timeout or error
92 */
93 bool WaitForData(std::chrono::milliseconds timeout);
94
95 /**
96 * Read available data from socket and process complete replies.
97 * Dispatches to registered reply handlers.
98 * @return true if connection is still open, false if connection was closed
99 */
100 bool ReceiveAndProcess();
101
102 private:
103 /** Reference to interrupt object for clean shutdown */
104 CThreadInterrupt& m_interrupt;
105 /** Socket for the connection */
106 std::unique_ptr<Sock> m_sock;
107 /** Message being received */
108 TorControlReply m_message;
109 /** Response handlers */
110 std::deque<ReplyHandlerCB> m_reply_handlers;
111 /** Buffer for incoming data */
112 std::vector<std::byte> m_recv_buffer;
113 /** Process complete lines from the receive buffer */
114 bool ProcessBuffer();
115 };
116
117 /****** Bitcoin specific TorController implementation ********/
118
119 /** Controller that connects to Tor control socket, authenticate, then create
120 * and maintain an ephemeral onion service.
121 */
122 class TorController
123 {
124 public:
125 TorController(const std::string& tor_control_center, const CService& target);
126 TorController() : m_conn(m_interrupt) {
127 // Used for testing only.
128 }
129 ~TorController();
130
131 /** Get name of file to store private key in */
132 fs::path GetPrivateKeyFile();
133
134 /** Interrupt the controller thread */
135 void Interrupt();
136
137 /** Wait for the controller thread to exit */
138 void Join();
139 private:
140 CThreadInterrupt m_interrupt;
141 std::thread m_thread;
142 const std::string m_tor_control_center;
143 TorControlConnection m_conn;
144 std::string m_private_key;
145 std::string m_service_id;
146 std::atomic<bool> m_reconnect;
147 std::chrono::duration<double> m_reconnect_timeout;
148 CService m_service;
149 const CService m_target;
150 /** Cookie for SAFECOOKIE auth */
151 std::vector<uint8_t> m_cookie;
152 /** ClientNonce for SAFECOOKIE auth */
153 std::vector<uint8_t> m_client_nonce;
154
155 /// \anchor torcontrol
156 void ThreadControl();
157
158 public:
159 /** Callback for GETINFO net/listeners/socks result */
160 void get_socks_cb(TorControlConnection& conn, const TorControlReply& reply);
161 /** Callback for ADD_ONION result */
162 void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply, bool pow_was_enabled);
163 /** Callback for AUTHENTICATE result */
164 void auth_cb(TorControlConnection& conn, const TorControlReply& reply);
165 /** Callback for AUTHCHALLENGE result */
166 void authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply);
167 /** Callback for PROTOCOLINFO result */
168 void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply);
169 /** Callback after successful connection */
170 void connected_cb(TorControlConnection& conn);
171 /** Callback after connection lost or failed connection attempt */
172 void disconnected_cb(TorControlConnection& conn);
173 };
174
175 #endif // BITCOIN_TORCONTROL_H
176