torcontrol.h
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 /** 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