Coverage Report

Created: 2026-04-29 19:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/torcontrol.h
Line
Count
Source
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
8
    TorControlReply() { Clear(); }
41
42
    int code;
43
    std::vector<std::string> lines;
44
45
    void Clear()
46
41
    {
47
41
        code = 0;
48
41
        lines.clear();
49
41
    }
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
0
    TorController() : m_conn(m_interrupt) {
127
0
        // Used for testing only.
128
0
    }
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