Branch data Line data Source code
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 : 1 : class TorControlReply
38 : : {
39 : : public:
40 : 1 : TorControlReply() { Clear(); }
41 : :
42 : : int code;
43 : : std::vector<std::string> lines;
44 : :
45 : 2 : void Clear()
46 : : {
47 : 2 : code = 0;
48 [ + - ]: 2 : lines.clear();
49 : 0 : }
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 : : /** Main control thread */
155 : : void ThreadControl();
156 : :
157 : : public:
158 : : /** Callback for GETINFO net/listeners/socks result */
159 : : void get_socks_cb(TorControlConnection& conn, const TorControlReply& reply);
160 : : /** Callback for ADD_ONION result */
161 : : void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply, bool pow_was_enabled);
162 : : /** Callback for AUTHENTICATE result */
163 : : void auth_cb(TorControlConnection& conn, const TorControlReply& reply);
164 : : /** Callback for AUTHCHALLENGE result */
165 : : void authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply);
166 : : /** Callback for PROTOCOLINFO result */
167 : : void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply);
168 : : /** Callback after successful connection */
169 : : void connected_cb(TorControlConnection& conn);
170 : : /** Callback after connection lost or failed connection attempt */
171 : : void disconnected_cb(TorControlConnection& conn);
172 : : };
173 : :
174 : : #endif // BITCOIN_TORCONTROL_H
|