Skip to content

Commit dd8f474

Browse files
committed
Merge #19288: fuzz: Add fuzzing harness for TorController
10d4477 tests: Add fuzzing harness for TorController (practicalswift) 64219c0 torcontrol: Move TorControlReply, TorControlConnection and TorController to improve testability (practicalswift) Pull request description: Add fuzzing harness for `TorController`. See [`doc/fuzzing.md`](https://github.com/bitcoin/bitcoin/blob/master/doc/fuzzing.md) for information on how to fuzz Bitcoin Core. Don't forget to contribute any coverage increasing inputs you find to the [Bitcoin Core fuzzing corpus repo](https://github.com/bitcoin-core/qa-assets). Happy fuzzing :) ACKs for top commit: laanwj: ACK 10d4477 Tree-SHA512: 2da4b1000afe0e65a234636b8fbf6a26fe9e257852bd837168ca73aa3575959e9aded19054620439e4ed0b2787c70cad4541a8c2d210f5238d7f5e9e0545b734
2 parents 9212e67 + 10d4477 commit dd8f474

File tree

4 files changed

+216
-120
lines changed

4 files changed

+216
-120
lines changed

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ test_fuzz_fuzz_SOURCES = \
291291
test/fuzz/strprintf.cpp \
292292
test/fuzz/system.cpp \
293293
test/fuzz/timedata.cpp \
294+
test/fuzz/torcontrol.cpp \
294295
test/fuzz/transaction.cpp \
295296
test/fuzz/tx_in.cpp \
296297
test/fuzz/tx_out.cpp \

src/test/fuzz/torcontrol.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright (c) 2020 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+
#include <test/fuzz/FuzzedDataProvider.h>
6+
#include <test/fuzz/fuzz.h>
7+
#include <test/fuzz/util.h>
8+
#include <torcontrol.h>
9+
10+
#include <cstdint>
11+
#include <string>
12+
#include <vector>
13+
14+
class DummyTorControlConnection : public TorControlConnection
15+
{
16+
public:
17+
DummyTorControlConnection() : TorControlConnection{nullptr}
18+
{
19+
}
20+
21+
bool Connect(const std::string&, const ConnectionCB&, const ConnectionCB&)
22+
{
23+
return true;
24+
}
25+
26+
void Disconnect()
27+
{
28+
}
29+
30+
bool Command(const std::string&, const ReplyHandlerCB&)
31+
{
32+
return true;
33+
}
34+
};
35+
36+
void initialize_torcontrol()
37+
{
38+
static const auto testing_setup = MakeNoLogFileContext<>();
39+
}
40+
41+
FUZZ_TARGET_INIT(torcontrol, initialize_torcontrol)
42+
{
43+
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
44+
45+
TorController tor_controller;
46+
while (fuzzed_data_provider.ConsumeBool()) {
47+
TorControlReply tor_control_reply;
48+
CallOneOf(
49+
fuzzed_data_provider,
50+
[&] {
51+
tor_control_reply.code = 250;
52+
},
53+
[&] {
54+
tor_control_reply.code = 510;
55+
},
56+
[&] {
57+
tor_control_reply.code = fuzzed_data_provider.ConsumeIntegral<int>();
58+
});
59+
tor_control_reply.lines = ConsumeRandomLengthStringVector(fuzzed_data_provider);
60+
if (tor_control_reply.lines.empty()) {
61+
break;
62+
}
63+
DummyTorControlConnection dummy_tor_control_connection;
64+
CallOneOf(
65+
fuzzed_data_provider,
66+
[&] {
67+
tor_controller.add_onion_cb(dummy_tor_control_connection, tor_control_reply);
68+
},
69+
[&] {
70+
tor_controller.auth_cb(dummy_tor_control_connection, tor_control_reply);
71+
},
72+
[&] {
73+
tor_controller.authchallenge_cb(dummy_tor_control_connection, tor_control_reply);
74+
},
75+
[&] {
76+
tor_controller.protocolinfo_cb(dummy_tor_control_connection, tor_control_reply);
77+
});
78+
}
79+
}

src/torcontrol.cpp

Lines changed: 0 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -56,77 +56,6 @@ static const int MAX_LINE_LENGTH = 100000;
5656

5757
/****** Low-level TorControlConnection ********/
5858

59-
/** Reply from Tor, can be single or multi-line */
60-
class TorControlReply
61-
{
62-
public:
63-
TorControlReply() { Clear(); }
64-
65-
int code;
66-
std::vector<std::string> lines;
67-
68-
void Clear()
69-
{
70-
code = 0;
71-
lines.clear();
72-
}
73-
};
74-
75-
/** Low-level handling for Tor control connection.
76-
* Speaks the SMTP-like protocol as defined in torspec/control-spec.txt
77-
*/
78-
class TorControlConnection
79-
{
80-
public:
81-
typedef std::function<void(TorControlConnection&)> ConnectionCB;
82-
typedef std::function<void(TorControlConnection &,const TorControlReply &)> ReplyHandlerCB;
83-
84-
/** Create a new TorControlConnection.
85-
*/
86-
explicit TorControlConnection(struct event_base *base);
87-
~TorControlConnection();
88-
89-
/**
90-
* Connect to a Tor control port.
91-
* tor_control_center is address of the form host:port.
92-
* connected is the handler that is called when connection is successfully established.
93-
* disconnected is a handler that is called when the connection is broken.
94-
* Return true on success.
95-
*/
96-
bool Connect(const std::string& tor_control_center, const ConnectionCB& connected, const ConnectionCB& disconnected);
97-
98-
/**
99-
* Disconnect from Tor control port.
100-
*/
101-
void Disconnect();
102-
103-
/** Send a command, register a handler for the reply.
104-
* A trailing CRLF is automatically added.
105-
* Return true on success.
106-
*/
107-
bool Command(const std::string &cmd, const ReplyHandlerCB& reply_handler);
108-
109-
/** Response handlers for async replies */
110-
boost::signals2::signal<void(TorControlConnection &,const TorControlReply &)> async_handler;
111-
private:
112-
/** Callback when ready for use */
113-
std::function<void(TorControlConnection&)> connected;
114-
/** Callback when connection lost */
115-
std::function<void(TorControlConnection&)> disconnected;
116-
/** Libevent event base */
117-
struct event_base *base;
118-
/** Connection to control socket */
119-
struct bufferevent *b_conn;
120-
/** Message being received */
121-
TorControlReply message;
122-
/** Response handlers */
123-
std::deque<ReplyHandlerCB> reply_handlers;
124-
125-
/** Libevent handlers: internal */
126-
static void readcb(struct bufferevent *bev, void *ctx);
127-
static void eventcb(struct bufferevent *bev, short what, void *ctx);
128-
};
129-
13059
TorControlConnection::TorControlConnection(struct event_base *_base):
13160
base(_base), b_conn(nullptr)
13261
{
@@ -363,55 +292,6 @@ std::map<std::string,std::string> ParseTorReplyMapping(const std::string &s)
363292
return mapping;
364293
}
365294

366-
/****** Bitcoin specific TorController implementation ********/
367-
368-
/** Controller that connects to Tor control socket, authenticate, then create
369-
* and maintain an ephemeral onion service.
370-
*/
371-
class TorController
372-
{
373-
public:
374-
TorController(struct event_base* base, const std::string& tor_control_center, const CService& target);
375-
~TorController();
376-
377-
/** Get name of file to store private key in */
378-
fs::path GetPrivateKeyFile();
379-
380-
/** Reconnect, after getting disconnected */
381-
void Reconnect();
382-
private:
383-
struct event_base* base;
384-
const std::string m_tor_control_center;
385-
TorControlConnection conn;
386-
std::string private_key;
387-
std::string service_id;
388-
bool reconnect;
389-
struct event *reconnect_ev;
390-
float reconnect_timeout;
391-
CService service;
392-
const CService m_target;
393-
/** Cookie for SAFECOOKIE auth */
394-
std::vector<uint8_t> cookie;
395-
/** ClientNonce for SAFECOOKIE auth */
396-
std::vector<uint8_t> clientNonce;
397-
398-
/** Callback for ADD_ONION result */
399-
void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply);
400-
/** Callback for AUTHENTICATE result */
401-
void auth_cb(TorControlConnection& conn, const TorControlReply& reply);
402-
/** Callback for AUTHCHALLENGE result */
403-
void authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply);
404-
/** Callback for PROTOCOLINFO result */
405-
void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply);
406-
/** Callback after successful connection */
407-
void connected_cb(TorControlConnection& conn);
408-
/** Callback after connection lost or failed connection attempt */
409-
void disconnected_cb(TorControlConnection& conn);
410-
411-
/** Callback for reconnect timer */
412-
static void reconnect_cb(evutil_socket_t fd, short what, void *arg);
413-
};
414-
415295
TorController::TorController(struct event_base* _base, const std::string& tor_control_center, const CService& target):
416296
base(_base),
417297
m_tor_control_center(tor_control_center), conn(base), reconnect(true), reconnect_ev(0),

src/torcontrol.h

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,19 @@
88
#ifndef BITCOIN_TORCONTROL_H
99
#define BITCOIN_TORCONTROL_H
1010

11+
#include <fs.h>
12+
#include <netaddress.h>
13+
14+
#include <boost/signals2/signal.hpp>
15+
16+
#include <event2/bufferevent.h>
17+
#include <event2/event.h>
18+
19+
#include <cstdlib>
20+
#include <deque>
21+
#include <functional>
1122
#include <string>
23+
#include <vector>
1224

1325
class CService;
1426

@@ -21,4 +33,128 @@ void StopTorControl();
2133

2234
CService DefaultOnionServiceTarget();
2335

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&)> ConnectionCB;
59+
typedef std::function<void(TorControlConnection &,const TorControlReply &)> ReplyHandlerCB;
60+
61+
/** Create a new TorControlConnection.
62+
*/
63+
explicit TorControlConnection(struct event_base *base);
64+
~TorControlConnection();
65+
66+
/**
67+
* Connect to a Tor control port.
68+
* tor_control_center is address of the form host:port.
69+
* connected is the handler that is called when connection is successfully established.
70+
* disconnected is a handler that is called when the connection is broken.
71+
* Return true on success.
72+
*/
73+
bool Connect(const std::string& tor_control_center, const ConnectionCB& connected, const ConnectionCB& disconnected);
74+
75+
/**
76+
* Disconnect from Tor control port.
77+
*/
78+
void Disconnect();
79+
80+
/** Send a command, register a handler for the reply.
81+
* A trailing CRLF is automatically added.
82+
* Return true on success.
83+
*/
84+
bool Command(const std::string &cmd, const ReplyHandlerCB& reply_handler);
85+
86+
/** Response handlers for async replies */
87+
boost::signals2::signal<void(TorControlConnection &,const TorControlReply &)> async_handler;
88+
private:
89+
/** Callback when ready for use */
90+
std::function<void(TorControlConnection&)> connected;
91+
/** Callback when connection lost */
92+
std::function<void(TorControlConnection&)> disconnected;
93+
/** Libevent event base */
94+
struct event_base *base;
95+
/** Connection to control socket */
96+
struct bufferevent *b_conn;
97+
/** Message being received */
98+
TorControlReply message;
99+
/** Response handlers */
100+
std::deque<ReplyHandlerCB> reply_handlers;
101+
102+
/** Libevent handlers: internal */
103+
static void readcb(struct bufferevent *bev, void *ctx);
104+
static void eventcb(struct bufferevent *bev, short what, void *ctx);
105+
};
106+
107+
/****** Bitcoin specific TorController implementation ********/
108+
109+
/** Controller that connects to Tor control socket, authenticate, then create
110+
* and maintain an ephemeral onion service.
111+
*/
112+
class TorController
113+
{
114+
public:
115+
TorController(struct event_base* base, const std::string& tor_control_center, const CService& target);
116+
TorController() : conn{nullptr} {
117+
// Used for testing only.
118+
}
119+
~TorController();
120+
121+
/** Get name of file to store private key in */
122+
fs::path GetPrivateKeyFile();
123+
124+
/** Reconnect, after getting disconnected */
125+
void Reconnect();
126+
private:
127+
struct event_base* base;
128+
const std::string m_tor_control_center;
129+
TorControlConnection conn;
130+
std::string private_key;
131+
std::string service_id;
132+
bool reconnect;
133+
struct event *reconnect_ev = nullptr;
134+
float reconnect_timeout;
135+
CService service;
136+
const CService m_target;
137+
/** Cookie for SAFECOOKIE auth */
138+
std::vector<uint8_t> cookie;
139+
/** ClientNonce for SAFECOOKIE auth */
140+
std::vector<uint8_t> clientNonce;
141+
142+
public:
143+
/** Callback for ADD_ONION result */
144+
void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply);
145+
/** Callback for AUTHENTICATE result */
146+
void auth_cb(TorControlConnection& conn, const TorControlReply& reply);
147+
/** Callback for AUTHCHALLENGE result */
148+
void authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply);
149+
/** Callback for PROTOCOLINFO result */
150+
void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply);
151+
/** Callback after successful connection */
152+
void connected_cb(TorControlConnection& conn);
153+
/** Callback after connection lost or failed connection attempt */
154+
void disconnected_cb(TorControlConnection& conn);
155+
156+
/** Callback for reconnect timer */
157+
static void reconnect_cb(evutil_socket_t fd, short what, void *arg);
158+
};
159+
24160
#endif /* BITCOIN_TORCONTROL_H */

0 commit comments

Comments
 (0)