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