From 8f4e67f152a9625a1c66c20de00679286b2c187c Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 25 Aug 2015 20:12:08 +0200 Subject: net: Automatically create hidden service, listen on Tor Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket API, to create and destroy 'ephemeral' hidden services programmatically. https://stem.torproject.org/api/control.html#stem.control.Controller.create_ephemeral_hidden_service This means that if Tor is running (and proper authorization is available), bitcoin automatically creates a hidden service to listen on, without user manual configuration. This will positively affect the number of available .onion nodes. - When the node is started, connect to Tor through control socket - Send `ADD_ONION` command - First time: - Make it create a hidden service key - Save the key in the data directory for later usage - Make it redirect port 8333 to the local port 8333 (or whatever port we're listening on). - Keep control socket connection open for as long node is running. The hidden service will (by default) automatically go away when the connection is closed. --- src/torcontrol.cpp | 573 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 573 insertions(+) create mode 100644 src/torcontrol.cpp (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp new file mode 100644 index 000000000..bb72315c8 --- /dev/null +++ b/src/torcontrol.cpp @@ -0,0 +1,573 @@ +#include "torcontrol.h" +#include "utilstrencodings.h" +#include "net.h" +#include "util.h" +#include "init.h" // Just for ShutdownRequested + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +const std::string DEFAULT_TOR_CONTROL = "127.0.0.1:9051"; + +/****** Low-level TorControlConnection ********/ + +/** Reply from Tor, can be single or multi-line */ +class TorControlReply +{ +public: + TorControlReply() { Clear(); } + + int code; + std::vector lines; + + void Clear() + { + code = 0; + lines.clear(); + } +}; + +/** Low-level handling for Tor control connection. + * Speaks the SMTP-like protocol as defined in torspec/control-spec.txt + */ +class TorControlConnection +{ +public: + typedef boost::function ConnectionCB; + typedef boost::function ReplyHandlerCB; + + /** Create a new TorControlConnection. + */ + TorControlConnection(struct event_base *base); + ~TorControlConnection(); + + /** + * Connect to a Tor control port. + * target is address of the form host:port. + * connected is the handler that is called when connection is succesfully established. + * disconnected is a handler that is called when the connection is broken. + * Return true on success. + */ + bool Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected); + + /** + * Disconnect from Tor control port. + */ + bool Disconnect(); + + /** Send a command, register a handler for the reply. + * A trailing CRLF is automatically added. + * Return true on success. + */ + bool Command(const std::string &cmd, const ReplyHandlerCB& reply_handler); + + /** Response handlers for async replies */ + boost::signals2::signal async_handler; +private: + /** Callback when ready for use */ + boost::function connected; + /** Callback when connection lost */ + boost::function disconnected; + /** Libevent event base */ + struct event_base *base; + /** Connection to control socket */ + struct bufferevent *b_conn; + /** Message being received */ + TorControlReply message; + /** Response handlers */ + std::deque reply_handlers; + + /** Libevent handlers: internal */ + static void readcb(struct bufferevent *bev, void *ctx); + static void eventcb(struct bufferevent *bev, short what, void *ctx); +}; + +TorControlConnection::TorControlConnection(struct event_base *base): + base(base), b_conn(0) +{ +} + +TorControlConnection::~TorControlConnection() +{ + if (b_conn) + bufferevent_free(b_conn); +} + +void TorControlConnection::readcb(struct bufferevent *bev, void *ctx) +{ + TorControlConnection *self = (TorControlConnection*)ctx; + struct evbuffer *input = bufferevent_get_input(bev); + size_t n_read_out = 0; + char *line; + assert(input); + // If there is not a whole line to read, evbuffer_readln returns NULL + while((line = evbuffer_readln(input, &n_read_out, EVBUFFER_EOL_CRLF)) != NULL) + { + std::string s(line, n_read_out); + free(line); + if (s.size() < 4) // Short line + continue; + // (-|+| ) + self->message.code = atoi(s.substr(0,3).c_str()); + self->message.lines.push_back(s.substr(4)); + char ch = s[3]; // '-','+' or ' ' + if (ch == ' ') { + // Final line, dispatch reply and clean up + if (self->message.code >= 600) { + // Dispatch async notifications to async handler + // Synchronous and asynchronous messages are never interleaved + self->async_handler(*self, self->message); + } else { + if (!self->reply_handlers.empty()) { + // Invoke reply handler with message + self->reply_handlers.front()(*self, self->message); + self->reply_handlers.pop_front(); + } else { + LogPrintf("[tor] Received unexpected sync reply %i\n", self->message.code); + } + } + self->message.Clear(); + } + } +} + +void TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ctx) +{ + TorControlConnection *self = (TorControlConnection*)ctx; + if (what & BEV_EVENT_CONNECTED) { + LogPrintf("[tor] Succesfully connected!\n"); + self->connected(*self); + } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { + if (what & BEV_EVENT_ERROR) + LogPrintf("[tor] Error connecting to Tor control socket\n"); + else + LogPrintf("[tor] End of stream\n"); + self->Disconnect(); + self->disconnected(*self); + } +} + +bool TorControlConnection::Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected) +{ + if (b_conn) + Disconnect(); + // Parse target address:port + struct sockaddr_storage connect_to_addr; + int connect_to_addrlen = sizeof(connect_to_addr); + if (evutil_parse_sockaddr_port(target.c_str(), + (struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0) { + perror("evutil_parse_sockaddr_port\n"); + return false; + } + + // Create a new socket, set up callbacks and enable notification bits + b_conn = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); + if (!b_conn) + return false; + bufferevent_setcb(b_conn, TorControlConnection::readcb, NULL, TorControlConnection::eventcb, this); + bufferevent_enable(b_conn, EV_READ|EV_WRITE); + this->connected = connected; + this->disconnected = disconnected; + + // Finally, connect to target + if (bufferevent_socket_connect(b_conn, (struct sockaddr*)&connect_to_addr, connect_to_addrlen) < 0) { + perror("bufferevent_socket_connect"); + return false; + } + return true; +} + +bool TorControlConnection::Disconnect() +{ + if (b_conn) + bufferevent_free(b_conn); + b_conn = 0; + return true; +} + +bool TorControlConnection::Command(const std::string &cmd, const ReplyHandlerCB& reply_handler) +{ + if (!b_conn) + return false; + struct evbuffer *buf = bufferevent_get_output(b_conn); + if (!buf) + return false; + evbuffer_add(buf, cmd.data(), cmd.size()); + evbuffer_add(buf, "\r\n", 2); + reply_handlers.push_back(reply_handler); + return true; +} + +/****** General parsing utilities ********/ + +/* Split reply line in the form 'AUTH METHODS=...' into a type + * 'AUTH' and arguments 'METHODS=...'. + */ +static std::pair SplitTorReplyLine(const std::string &s) +{ + size_t ptr=0; + std::string type; + while (ptr < s.size() && s[ptr] != ' ') { + type.push_back(s[ptr]); + ++ptr; + } + if (ptr < s.size()) + ++ptr; // skip ' ' + return make_pair(type, s.substr(ptr)); +} + +/** Parse reply arguments in the form 'METHODS=COOKIE,SAFECOOKIE COOKIEFILE=".../control_auth_cookie"'. + */ +static std::map ParseTorReplyMapping(const std::string &s) +{ + std::map mapping; + size_t ptr=0; + while (ptr < s.size()) { + std::string key, value; + while (ptr < s.size() && s[ptr] != '=') { + key.push_back(s[ptr]); + ++ptr; + } + if (ptr == s.size()) // unexpected end of line + return std::map(); + ++ptr; // skip '=' + if (ptr < s.size() && s[ptr] == '"') { // Quoted string + ++ptr; // skip '=' + bool escape_next = false; + while (ptr < s.size() && (!escape_next && s[ptr] != '"')) { + escape_next = (s[ptr] == '\\'); + value.push_back(s[ptr]); + ++ptr; + } + if (ptr == s.size()) // unexpected end of line + return std::map(); + ++ptr; // skip closing '"' + /* TODO: unescape value - according to the spec this depends on the + * context, some strings use C-LogPrintf style escape codes, some + * don't. So may be better handled at the call site. + */ + } else { // Unquoted value. Note that values can contain '=' at will, just no spaces + while (ptr < s.size() && s[ptr] != ' ') { + value.push_back(s[ptr]); + ++ptr; + } + } + if (ptr < s.size() && s[ptr] == ' ') + ++ptr; // skip ' ' after key=value + mapping[key] = value; + } + return mapping; +} + +/** Read full contents of a file and return them in a std::string. */ +static std::pair ReadBinaryFile(const std::string &filename) +{ + FILE *f = fopen(filename.c_str(), "rb"); + if (f == NULL) + return std::make_pair(false,""); + std::string retval; + char buffer[128]; + size_t n; + while ((n=fread(buffer, 1, sizeof(buffer), f)) > 0) + retval.append(buffer, buffer+n); + fclose(f); + return std::make_pair(true,retval); +} + +/** Write contents of std::string to a file. + * @return true on success. + */ +static bool WriteBinaryFile(const std::string &filename, const std::string &data) +{ + FILE *f = fopen(filename.c_str(), "wb"); + if (f == NULL) + return false; + if (fwrite(data.data(), 1, data.size(), f) != data.size()) + return false; + fclose(f); + return true; +} + +/****** Bitcoin specific TorController implementation ********/ + +/** Controller that connects to Tor control socket, authenticate, then create + * and maintain a ephemeral hidden service. + */ +class TorController +{ +public: + TorController(struct event_base* base, const std::string& target); + ~TorController(); + + /** Get name fo file to store private key in */ + std::string GetPrivateKeyFile(); + + /** Reconnect, after getting disconnected */ + void Reconnect(); +private: + struct event_base* base; + std::string target; + TorControlConnection conn; + std::string private_key; + std::string service_id; + bool reconnect; + struct event *shutdown_poll_ev; + struct event *reconnect_ev; + float reconnect_timeout; + + /** Callback for ADD_ONION result */ + void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply); + /** Callback for AUTHENTICATE result */ + void auth_cb(TorControlConnection& conn, const TorControlReply& reply); + /** Callback for PROTOCOLINFO result */ + void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply); + /** Callback after succesful connection */ + void connected_cb(TorControlConnection& conn); + /** Callback after connection lost or failed connection attempt */ + void disconnected_cb(TorControlConnection& conn); + + /** Callback for shutdown poll timer */ + static void shutdown_poll_cb(evutil_socket_t fd, short what, void *arg); + /** Callback for reconnect timer */ + static void reconnect_cb(evutil_socket_t fd, short what, void *arg); +}; + +/** Exponential backoff configuration - initial timeout in seconds */ +static const float RECONNECT_TIMEOUT_START = 1.0; +/** Exponential backoff configuration - growth factor */ +static const float RECONNECT_TIMEOUT_EXP = 1.5; + +TorController::TorController(struct event_base* base, const std::string& target): + base(base), + target(target), conn(base), reconnect(true), shutdown_poll_ev(0), reconnect_ev(0), + reconnect_timeout(RECONNECT_TIMEOUT_START) +{ + // Start connection attempts immediately + if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1), + boost::bind(&TorController::disconnected_cb, this, _1) )) { + LogPrintf("[tor] Initiating connection to Tor control port %s failed\n", target); + } + // Read service private key if cached + std::pair pkf = ReadBinaryFile(GetPrivateKeyFile()); + if (pkf.first) { + LogPrintf("[tor] Reading cached private key from %s\n", GetPrivateKeyFile()); + private_key = pkf.second; + } + // Periodic timer event to poll for shutdown + // The same 200ms as in bitcoind. This is not the nicest solution, but we cannot exactly use + // boost::interrupt here. + struct timeval time; + time.tv_usec = 200000; + time.tv_sec = 0; + shutdown_poll_ev = event_new(base, -1, EV_PERSIST, shutdown_poll_cb, this); + event_add(shutdown_poll_ev, &time); +} + +TorController::~TorController() +{ + if (shutdown_poll_ev) + event_del(shutdown_poll_ev); + if (reconnect_ev) + event_del(reconnect_ev); +} + +void TorController::add_onion_cb(TorControlConnection& conn, const TorControlReply& reply) +{ + if (reply.code == 250) { + LogPrintf("[tor] ADD_ONION succesful\n"); + BOOST_FOREACH(const std::string &s, reply.lines) { + std::map m = ParseTorReplyMapping(s); + std::map::iterator i; + if ((i = m.find("ServiceID")) != m.end()) + service_id = i->second; + if ((i = m.find("PrivateKey")) != m.end()) + private_key = i->second; + } + + CService service(service_id+".onion", GetListenPort(), false); + LogPrintf("[tor] Got service ID %s, advertizing service %s\n", service_id, service.ToString()); + if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) { + LogPrintf("[tor] Cached service private key to %s\n", GetPrivateKeyFile()); + } else { + LogPrintf("[tor] Error writing service private key to %s\n", GetPrivateKeyFile()); + } + AddLocal(service, LOCAL_MANUAL); + // ... onion requested - keep connection open + } else { + LogPrintf("[tor] Add onion failed\n"); + } +} + +void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& reply) +{ + if (reply.code == 250) { + LogPrintf("[tor] Authentication succesful\n"); + // Finally - now create the service + if (private_key.empty()) // No private key, generate one + private_key = "NEW:BEST"; + // Request hidden service, redirect port. + // Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient + // choice. TODO; refactor the shutdown sequence some day. + conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, GetListenPort(), GetListenPort()), + boost::bind(&TorController::add_onion_cb, this, _1, _2)); + } else { + LogPrintf("[tor] Authentication failed\n"); + } +} + +void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply) +{ + if (reply.code == 250) { + std::set methods; + std::string cookiefile; + /* + * 250-AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE="/home/x/.tor/control_auth_cookie" + * 250-AUTH METHODS=NULL + * 250-AUTH METHODS=HASHEDPASSWORD + */ + BOOST_FOREACH(const std::string &s, reply.lines) { + std::pair l = SplitTorReplyLine(s); + if (l.first == "AUTH") { + std::map m = ParseTorReplyMapping(l.second); + std::map::iterator i; + if ((i = m.find("METHODS")) != m.end()) + boost::split(methods, i->second, boost::is_any_of(",")); + if ((i = m.find("COOKIEFILE")) != m.end()) + cookiefile = i->second; + } else if (l.first == "VERSION") { + std::map m = ParseTorReplyMapping(l.second); + std::map::iterator i; + if ((i = m.find("Tor")) != m.end()) { + LogPrintf("[tor] Connected to Tor version %s\n", i->second); + } + } + } + BOOST_FOREACH(const std::string &s, methods) { + LogPrintf("[tor] Supported authentication method: %s\n", s); + } + // Prefer NULL, otherwise COOKIE. If a password is provided, use HASHEDPASSWORD + // We do not support SAFECOOKIE + /* Authentication: + * cookie: hex-encoded ~/.tor/control_auth_cookie + * password: "password" + */ + if (methods.count("NULL")) { + LogPrintf("[tor] Using NULL authentication\n"); + conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2)); + } else if (methods.count("COOKIE")) { + // Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie + LogPrintf("[tor] Using COOKIE authentication, reading cookie authentication from %s\n", cookiefile); + std::string cookie = ReadBinaryFile(cookiefile).second; + if (!cookie.empty()) { + conn.Command("AUTHENTICATE " + HexStr(cookie), boost::bind(&TorController::auth_cb, this, _1, _2)); + } else { + LogPrintf("[tor] Authentication cookie not found\n"); + } + } else { + /* TODO HASHEDPASSWORD w/ manual auth */ + LogPrintf("[tor] No supported authentication method\n"); + } + } else { + LogPrintf("[tor] Requesting protocol info failed\n"); + } +} + +void TorController::connected_cb(TorControlConnection& conn) +{ + reconnect_timeout = RECONNECT_TIMEOUT_START; + // First send a PROTOCOLINFO command to figure out what authentication is expected + if (!conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, _1, _2))) + LogPrintf("[tor] Error sending initial protocolinfo command\n"); +} + +void TorController::disconnected_cb(TorControlConnection& conn) +{ + if (!reconnect) + return; + LogPrintf("[tor] Disconnected from Tor control port %s, trying to reconnect\n", target); + // Single-shot timer for reconnect. Use exponential backoff. + struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0)); + reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); + event_add(reconnect_ev, &time); + reconnect_timeout *= RECONNECT_TIMEOUT_EXP; +} + +void TorController::Reconnect() +{ + /* Try to reconnect and reestablish if we get booted - for example, Tor + * may be restarting. + */ + if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1), + boost::bind(&TorController::disconnected_cb, this, _1) )) { + LogPrintf("[tor] Re-initiating connection to Tor control port %s failed\n", target); + } +} + +std::string TorController::GetPrivateKeyFile() +{ + return (GetDataDir() / "onion_private_key").string(); +} + +void TorController::shutdown_poll_cb(evutil_socket_t fd, short what, void *arg) +{ + TorController *self = (TorController*)arg; + if (ShutdownRequested()) { + // Shutdown was requested. Stop timers, and request control connection to terminate + LogPrintf("[tor] Thread interrupt\n"); + if (self->shutdown_poll_ev) + event_del(self->shutdown_poll_ev); + self->shutdown_poll_ev = 0; + if (self->reconnect_ev) + event_del(self->reconnect_ev); + self->reconnect_ev = 0; + self->reconnect = false; + self->conn.Disconnect(); + } +} + +void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg) +{ + TorController *self = (TorController*)arg; + self->Reconnect(); +} + +/****** Thread ********/ + +static void TorControlThread() +{ + struct event_base *base = event_base_new(); + if (!base) { + LogPrintf("[tor] Unable to create event_base_new"); + return; + } + TorController ctrl(base, GetArg("-torcontrol", DEFAULT_TOR_CONTROL)); + + event_base_dispatch(base); + event_base_free(base); +} + +void StartTorControl(boost::thread_group& threadGroup, CScheduler& scheduler) +{ + threadGroup.create_thread(boost::bind(&TraceThread, "torcontrol", &TorControlThread)); +} + +void StopTorControl() +{ + /* Nothing to do actually. Everything is cleaned up when thread exits */ +} + -- cgit v1.2.3 From 2f796e5fe7a51e4636600b320dc1995e048b4ba2 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Wed, 26 Aug 2015 21:43:18 -0700 Subject: Better error message if Tor version too old --- src/torcontrol.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index bb72315c8..40ffbe61b 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -408,8 +408,10 @@ void TorController::add_onion_cb(TorControlConnection& conn, const TorControlRep } AddLocal(service, LOCAL_MANUAL); // ... onion requested - keep connection open + } else if (reply.code == 510) { // 510 Unrecognized command + LogPrintf("[tor] Add onion failed with unrecognized command (You probably need to upgrade Tor)\n"); } else { - LogPrintf("[tor] Add onion failed\n"); + LogPrintf("[tor] Add onion failed; error code %d\n", reply.code); } } -- cgit v1.2.3 From 09c1ae1c01076f64fe0654f371200668306e5e18 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 8 Sep 2015 17:48:45 +0200 Subject: torcontrol improvements and fixes - Force AUTHCOOKIE size to be 32 bytes: This provides protection against an attack where a process pretends to be Tor and uses the cookie authentication method to nab arbitrary files such as the wallet - torcontrol logging - fix cookie auth - add HASHEDPASSWORD auth, fix fd leak when fwrite() fails - better error reporting when cookie file is not ok - better init/shutdown flow - stop advertizing service when disconnected from tor control port - COOKIE->SAFECOOKIE auth --- src/torcontrol.cpp | 278 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 194 insertions(+), 84 deletions(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 40ffbe61b..08644f296 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -2,7 +2,7 @@ #include "utilstrencodings.h" #include "net.h" #include "util.h" -#include "init.h" // Just for ShutdownRequested +#include "crypto/hmac_sha256.h" #include #include @@ -16,13 +16,33 @@ #include #include #include +#include #include #include #include #include +#include +/** Default control port */ const std::string DEFAULT_TOR_CONTROL = "127.0.0.1:9051"; +/** Tor cookie size (from control-spec.txt) */ +static const int TOR_COOKIE_SIZE = 32; +/** Size of client/server nonce for SAFECOOKIE */ +static const int TOR_NONCE_SIZE = 32; +/** For computing serverHash in SAFECOOKIE */ +static const std::string TOR_SAFE_SERVERKEY = "Tor safe cookie authentication server-to-controller hash"; +/** For computing clientHash in SAFECOOKIE */ +static const std::string TOR_SAFE_CLIENTKEY = "Tor safe cookie authentication controller-to-server hash"; +/** Exponential backoff configuration - initial timeout in seconds */ +static const float RECONNECT_TIMEOUT_START = 1.0; +/** Exponential backoff configuration - growth factor */ +static const float RECONNECT_TIMEOUT_EXP = 1.5; +/** Maximum length for lines received on TorControlConnection. + * tor-control-spec.txt mentions that there is explicitly no limit defined to line length, + * this is belt-and-suspenders sanity limit to prevent memory exhaustion. + */ +static const int MAX_LINE_LENGTH = 100000; /****** Low-level TorControlConnection ********/ @@ -123,7 +143,7 @@ void TorControlConnection::readcb(struct bufferevent *bev, void *ctx) if (s.size() < 4) // Short line continue; // (-|+| ) - self->message.code = atoi(s.substr(0,3).c_str()); + self->message.code = atoi(s.substr(0,3)); self->message.lines.push_back(s.substr(4)); char ch = s[3]; // '-','+' or ' ' if (ch == ' ') { @@ -138,25 +158,32 @@ void TorControlConnection::readcb(struct bufferevent *bev, void *ctx) self->reply_handlers.front()(*self, self->message); self->reply_handlers.pop_front(); } else { - LogPrintf("[tor] Received unexpected sync reply %i\n", self->message.code); + LogPrint("tor", "tor: Received unexpected sync reply %i\n", self->message.code); } } self->message.Clear(); } } + // Check for size of buffer - protect against memory exhaustion with very long lines + // Do this after evbuffer_readln to make sure all full lines have been + // removed from the buffer. Everything left is an incomplete line. + if (evbuffer_get_length(input) > MAX_LINE_LENGTH) { + LogPrintf("tor: Disconnecting because MAX_LINE_LENGTH exceeded\n"); + self->Disconnect(); + } } void TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ctx) { TorControlConnection *self = (TorControlConnection*)ctx; if (what & BEV_EVENT_CONNECTED) { - LogPrintf("[tor] Succesfully connected!\n"); + LogPrint("tor", "tor: Succesfully connected!\n"); self->connected(*self); } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { if (what & BEV_EVENT_ERROR) - LogPrintf("[tor] Error connecting to Tor control socket\n"); + LogPrint("tor", "tor: Error connecting to Tor control socket\n"); else - LogPrintf("[tor] End of stream\n"); + LogPrint("tor", "tor: End of stream\n"); self->Disconnect(); self->disconnected(*self); } @@ -171,7 +198,7 @@ bool TorControlConnection::Connect(const std::string &target, const ConnectionCB int connect_to_addrlen = sizeof(connect_to_addr); if (evutil_parse_sockaddr_port(target.c_str(), (struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0) { - perror("evutil_parse_sockaddr_port\n"); + LogPrintf("tor: Error parsing socket address %s\n", target); return false; } @@ -186,7 +213,7 @@ bool TorControlConnection::Connect(const std::string &target, const ConnectionCB // Finally, connect to target if (bufferevent_socket_connect(b_conn, (struct sockaddr*)&connect_to_addr, connect_to_addrlen) < 0) { - perror("bufferevent_socket_connect"); + LogPrintf("tor: Error connecting to address %s\n", target); return false; } return true; @@ -274,8 +301,14 @@ static std::map ParseTorReplyMapping(const std::string return mapping; } -/** Read full contents of a file and return them in a std::string. */ -static std::pair ReadBinaryFile(const std::string &filename) +/** Read full contents of a file and return them in a std::string. + * Returns a pair . + * If an error occured, status will be false, otherwise status will be true and the data will be returned in string. + * + * @param maxsize Puts a maximum size limit on the file that is read. If the file is larger than this, truncated data + * (with len > maxsize) will be returned. + */ +static std::pair ReadBinaryFile(const std::string &filename, size_t maxsize=std::numeric_limits::max()) { FILE *f = fopen(filename.c_str(), "rb"); if (f == NULL) @@ -283,8 +316,11 @@ static std::pair ReadBinaryFile(const std::string &filename) std::string retval; char buffer[128]; size_t n; - while ((n=fread(buffer, 1, sizeof(buffer), f)) > 0) + while ((n=fread(buffer, 1, sizeof(buffer), f)) > 0) { retval.append(buffer, buffer+n); + if (retval.size() > maxsize) + break; + } fclose(f); return std::make_pair(true,retval); } @@ -297,8 +333,10 @@ static bool WriteBinaryFile(const std::string &filename, const std::string &data FILE *f = fopen(filename.c_str(), "wb"); if (f == NULL) return false; - if (fwrite(data.data(), 1, data.size(), f) != data.size()) + if (fwrite(data.data(), 1, data.size(), f) != data.size()) { + fclose(f); return false; + } fclose(f); return true; } @@ -326,14 +364,20 @@ private: std::string private_key; std::string service_id; bool reconnect; - struct event *shutdown_poll_ev; struct event *reconnect_ev; float reconnect_timeout; + CService service; + /** Cooie for SAFECOOKIE auth */ + std::vector cookie; + /** ClientNonce for SAFECOOKIE auth */ + std::vector clientNonce; /** Callback for ADD_ONION result */ void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply); /** Callback for AUTHENTICATE result */ void auth_cb(TorControlConnection& conn, const TorControlReply& reply); + /** Callback for AUTHCHALLENGE result */ + void authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply); /** Callback for PROTOCOLINFO result */ void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply); /** Callback after succesful connection */ @@ -341,55 +385,41 @@ private: /** Callback after connection lost or failed connection attempt */ void disconnected_cb(TorControlConnection& conn); - /** Callback for shutdown poll timer */ - static void shutdown_poll_cb(evutil_socket_t fd, short what, void *arg); /** Callback for reconnect timer */ static void reconnect_cb(evutil_socket_t fd, short what, void *arg); }; -/** Exponential backoff configuration - initial timeout in seconds */ -static const float RECONNECT_TIMEOUT_START = 1.0; -/** Exponential backoff configuration - growth factor */ -static const float RECONNECT_TIMEOUT_EXP = 1.5; - TorController::TorController(struct event_base* base, const std::string& target): base(base), - target(target), conn(base), reconnect(true), shutdown_poll_ev(0), reconnect_ev(0), + target(target), conn(base), reconnect(true), reconnect_ev(0), reconnect_timeout(RECONNECT_TIMEOUT_START) { // Start connection attempts immediately if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1), boost::bind(&TorController::disconnected_cb, this, _1) )) { - LogPrintf("[tor] Initiating connection to Tor control port %s failed\n", target); + LogPrintf("tor: Initiating connection to Tor control port %s failed\n", target); } // Read service private key if cached std::pair pkf = ReadBinaryFile(GetPrivateKeyFile()); if (pkf.first) { - LogPrintf("[tor] Reading cached private key from %s\n", GetPrivateKeyFile()); + LogPrint("tor", "tor: Reading cached private key from %s\n", GetPrivateKeyFile()); private_key = pkf.second; } - // Periodic timer event to poll for shutdown - // The same 200ms as in bitcoind. This is not the nicest solution, but we cannot exactly use - // boost::interrupt here. - struct timeval time; - time.tv_usec = 200000; - time.tv_sec = 0; - shutdown_poll_ev = event_new(base, -1, EV_PERSIST, shutdown_poll_cb, this); - event_add(shutdown_poll_ev, &time); } TorController::~TorController() { - if (shutdown_poll_ev) - event_del(shutdown_poll_ev); if (reconnect_ev) event_del(reconnect_ev); + if (service.IsValid()) { + RemoveLocal(service); + } } void TorController::add_onion_cb(TorControlConnection& conn, const TorControlReply& reply) { if (reply.code == 250) { - LogPrintf("[tor] ADD_ONION succesful\n"); + LogPrint("tor", "tor: ADD_ONION succesful\n"); BOOST_FOREACH(const std::string &s, reply.lines) { std::map m = ParseTorReplyMapping(s); std::map::iterator i; @@ -399,26 +429,26 @@ void TorController::add_onion_cb(TorControlConnection& conn, const TorControlRep private_key = i->second; } - CService service(service_id+".onion", GetListenPort(), false); - LogPrintf("[tor] Got service ID %s, advertizing service %s\n", service_id, service.ToString()); + service = CService(service_id+".onion", GetListenPort(), false); + LogPrintf("tor: Got service ID %s, advertizing service %s\n", service_id, service.ToString()); if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) { - LogPrintf("[tor] Cached service private key to %s\n", GetPrivateKeyFile()); + LogPrint("tor", "tor: Cached service private key to %s\n", GetPrivateKeyFile()); } else { - LogPrintf("[tor] Error writing service private key to %s\n", GetPrivateKeyFile()); + LogPrintf("tor: Error writing service private key to %s\n", GetPrivateKeyFile()); } AddLocal(service, LOCAL_MANUAL); // ... onion requested - keep connection open } else if (reply.code == 510) { // 510 Unrecognized command - LogPrintf("[tor] Add onion failed with unrecognized command (You probably need to upgrade Tor)\n"); + LogPrintf("tor: Add onion failed with unrecognized command (You probably need to upgrade Tor)\n"); } else { - LogPrintf("[tor] Add onion failed; error code %d\n", reply.code); + LogPrintf("tor: Add onion failed; error code %d\n", reply.code); } } void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& reply) { if (reply.code == 250) { - LogPrintf("[tor] Authentication succesful\n"); + LogPrint("tor", "tor: Authentication succesful\n"); // Finally - now create the service if (private_key.empty()) // No private key, generate one private_key = "NEW:BEST"; @@ -428,7 +458,65 @@ void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& r conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, GetListenPort(), GetListenPort()), boost::bind(&TorController::add_onion_cb, this, _1, _2)); } else { - LogPrintf("[tor] Authentication failed\n"); + LogPrintf("tor: Authentication failed\n"); + } +} + +/** Compute Tor SAFECOOKIE response. + * + * ServerHash is computed as: + * HMAC-SHA256("Tor safe cookie authentication server-to-controller hash", + * CookieString | ClientNonce | ServerNonce) + * (with the HMAC key as its first argument) + * + * After a controller sends a successful AUTHCHALLENGE command, the + * next command sent on the connection must be an AUTHENTICATE command, + * and the only authentication string which that AUTHENTICATE command + * will accept is: + * + * HMAC-SHA256("Tor safe cookie authentication controller-to-server hash", + * CookieString | ClientNonce | ServerNonce) + * + */ +static std::vector ComputeResponse(const std::string &key, const std::vector &cookie, const std::vector &clientNonce, const std::vector &serverNonce) +{ + CHMAC_SHA256 computeHash((const uint8_t*)key.data(), key.size()); + std::vector computedHash(CHMAC_SHA256::OUTPUT_SIZE, 0); + computeHash.Write(begin_ptr(cookie), cookie.size()); + computeHash.Write(begin_ptr(clientNonce), clientNonce.size()); + computeHash.Write(begin_ptr(serverNonce), serverNonce.size()); + computeHash.Finalize(begin_ptr(computedHash)); + return computedHash; +} + +void TorController::authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply) +{ + if (reply.code == 250) { + LogPrint("tor", "tor: SAFECOOKIE authentication challenge succesful\n"); + std::pair l = SplitTorReplyLine(reply.lines[0]); + if (l.first == "AUTHCHALLENGE") { + std::map m = ParseTorReplyMapping(l.second); + std::vector serverHash = ParseHex(m["SERVERHASH"]); + std::vector serverNonce = ParseHex(m["SERVERNONCE"]); + LogPrint("tor", "tor: AUTHCHALLENGE ServerHash %s ServerNonce %s\n", HexStr(serverHash), HexStr(serverNonce)); + if (serverNonce.size() != 32) { + LogPrintf("tor: ServerNonce is not 32 bytes, as required by spec\n"); + return; + } + + std::vector computedServerHash = ComputeResponse(TOR_SAFE_SERVERKEY, cookie, clientNonce, serverNonce); + if (computedServerHash != serverHash) { + LogPrintf("tor: ServerHash %s does not match expected ServerHash %s\n", HexStr(serverHash), HexStr(computedServerHash)); + return; + } + + std::vector computedClientHash = ComputeResponse(TOR_SAFE_CLIENTKEY, cookie, clientNonce, serverNonce); + conn.Command("AUTHENTICATE " + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, _1, _2)); + } else { + LogPrintf("tor: Invalid reply to AUTHCHALLENGE\n"); + } + } else { + LogPrintf("tor: SAFECOOKIE authentication challenge failed\n"); } } @@ -455,37 +543,52 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl std::map m = ParseTorReplyMapping(l.second); std::map::iterator i; if ((i = m.find("Tor")) != m.end()) { - LogPrintf("[tor] Connected to Tor version %s\n", i->second); + LogPrint("tor", "tor: Connected to Tor version %s\n", i->second); } } } BOOST_FOREACH(const std::string &s, methods) { - LogPrintf("[tor] Supported authentication method: %s\n", s); + LogPrint("tor", "tor: Supported authentication method: %s\n", s); } - // Prefer NULL, otherwise COOKIE. If a password is provided, use HASHEDPASSWORD - // We do not support SAFECOOKIE + // Prefer NULL, otherwise SAFECOOKIE. If a password is provided, use HASHEDPASSWORD /* Authentication: * cookie: hex-encoded ~/.tor/control_auth_cookie * password: "password" */ + std::string torpassword = GetArg("-torpassword", ""); if (methods.count("NULL")) { - LogPrintf("[tor] Using NULL authentication\n"); + LogPrint("tor", "tor: Using NULL authentication\n"); conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2)); - } else if (methods.count("COOKIE")) { + } else if (methods.count("SAFECOOKIE")) { // Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie - LogPrintf("[tor] Using COOKIE authentication, reading cookie authentication from %s\n", cookiefile); - std::string cookie = ReadBinaryFile(cookiefile).second; - if (!cookie.empty()) { - conn.Command("AUTHENTICATE " + HexStr(cookie), boost::bind(&TorController::auth_cb, this, _1, _2)); + LogPrint("tor", "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile); + std::pair status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE); + if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) { + // conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, _1, _2)); + cookie = std::vector(status_cookie.second.begin(), status_cookie.second.end()); + clientNonce = std::vector(TOR_NONCE_SIZE, 0); + GetRandBytes(&clientNonce[0], TOR_NONCE_SIZE); + conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2)); } else { - LogPrintf("[tor] Authentication cookie not found\n"); + if (status_cookie.first) { + LogPrintf("tor: Authentication cookie %s is not exactly %i bytes, as is required by the spec\n", cookiefile, TOR_COOKIE_SIZE); + } else { + LogPrintf("tor: Authentication cookie %s could not be opened (check permissions)\n", cookiefile); + } + } + } else if (methods.count("HASHEDPASSWORD")) { + if (!torpassword.empty()) { + LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n"); + boost::replace_all(torpassword, "\"", "\\\""); + conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2)); + } else { + LogPrintf("tor: Password authentication required, but no password provided with -torpassword\n"); } } else { - /* TODO HASHEDPASSWORD w/ manual auth */ - LogPrintf("[tor] No supported authentication method\n"); + LogPrintf("tor: No supported authentication method\n"); } } else { - LogPrintf("[tor] Requesting protocol info failed\n"); + LogPrintf("tor: Requesting protocol info failed\n"); } } @@ -494,14 +597,18 @@ void TorController::connected_cb(TorControlConnection& conn) reconnect_timeout = RECONNECT_TIMEOUT_START; // First send a PROTOCOLINFO command to figure out what authentication is expected if (!conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, _1, _2))) - LogPrintf("[tor] Error sending initial protocolinfo command\n"); + LogPrintf("tor: Error sending initial protocolinfo command\n"); } void TorController::disconnected_cb(TorControlConnection& conn) { + // Stop advertizing service when disconnected + if (service.IsValid()) + RemoveLocal(service); + service = CService(); if (!reconnect) return; - LogPrintf("[tor] Disconnected from Tor control port %s, trying to reconnect\n", target); + LogPrintf("tor: Disconnected from Tor control port %s, trying to reconnect\n", target); // Single-shot timer for reconnect. Use exponential backoff. struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0)); reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); @@ -516,7 +623,7 @@ void TorController::Reconnect() */ if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1), boost::bind(&TorController::disconnected_cb, this, _1) )) { - LogPrintf("[tor] Re-initiating connection to Tor control port %s failed\n", target); + LogPrintf("tor: Re-initiating connection to Tor control port %s failed\n", target); } } @@ -525,23 +632,6 @@ std::string TorController::GetPrivateKeyFile() return (GetDataDir() / "onion_private_key").string(); } -void TorController::shutdown_poll_cb(evutil_socket_t fd, short what, void *arg) -{ - TorController *self = (TorController*)arg; - if (ShutdownRequested()) { - // Shutdown was requested. Stop timers, and request control connection to terminate - LogPrintf("[tor] Thread interrupt\n"); - if (self->shutdown_poll_ev) - event_del(self->shutdown_poll_ev); - self->shutdown_poll_ev = 0; - if (self->reconnect_ev) - event_del(self->reconnect_ev); - self->reconnect_ev = 0; - self->reconnect = false; - self->conn.Disconnect(); - } -} - void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg) { TorController *self = (TorController*)arg; @@ -549,27 +639,47 @@ void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg) } /****** Thread ********/ +struct event_base *base; +boost::thread torControlThread; static void TorControlThread() { - struct event_base *base = event_base_new(); - if (!base) { - LogPrintf("[tor] Unable to create event_base_new"); - return; - } TorController ctrl(base, GetArg("-torcontrol", DEFAULT_TOR_CONTROL)); event_base_dispatch(base); - event_base_free(base); } void StartTorControl(boost::thread_group& threadGroup, CScheduler& scheduler) { - threadGroup.create_thread(boost::bind(&TraceThread, "torcontrol", &TorControlThread)); + assert(!base); +#ifdef WIN32 + evthread_use_windows_threads(); +#else + evthread_use_pthreads(); +#endif + base = event_base_new(); + if (!base) { + LogPrintf("tor: Unable to create event_base\n"); + return; + } + + torControlThread = boost::thread(boost::bind(&TraceThread, "torcontrol", &TorControlThread)); +} + +void InterruptTorControl() +{ + if (base) { + LogPrintf("tor: Thread interrupt\n"); + event_base_loopbreak(base); + } } void StopTorControl() { - /* Nothing to do actually. Everything is cleaned up when thread exits */ + if (base) { + torControlThread.join(); + event_base_free(base); + base = 0; + } } -- cgit v1.2.3 From cde857f2d977fbe3f96c093f6ca3c9810494191d Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Tue, 24 Nov 2015 10:27:38 -0500 Subject: Connect to Tor hidden services by default Adds 127.0.0.1:9050 for the .onion proxy if we can succesfully connect to the control port. Natural followup to creating hidden services automatically. --- src/torcontrol.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 08644f296..31a291720 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -449,6 +449,15 @@ void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& r { if (reply.code == 250) { LogPrint("tor", "tor: Authentication succesful\n"); + + // Now that we know Tor is running setup the proxy for onion addresses + // if -onion isn't set to something else. + if (GetArg("-onion", "") == "") { + proxyType addrOnion = proxyType(CService("127.0.0.1", 9050), true); + SetProxy(NET_TOR, addrOnion); + SetReachable(NET_TOR); + } + // Finally - now create the service if (private_key.empty()) // No private key, generate one private_key = "NEW:BEST"; -- cgit v1.2.3 From 4531fc4272dec4b10c4ed3b21bd90e961b1bf1c3 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Tue, 17 Nov 2015 12:10:28 +1100 Subject: torcontrol: only output disconnect if -debug=tor --- src/torcontrol.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 31a291720..8eccc81e3 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -617,7 +617,9 @@ void TorController::disconnected_cb(TorControlConnection& conn) service = CService(); if (!reconnect) return; - LogPrintf("tor: Disconnected from Tor control port %s, trying to reconnect\n", target); + + LogPrint("tor", "tor: Disconnected from Tor control port %s, trying to reconnect\n", target); + // Single-shot timer for reconnect. Use exponential backoff. struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0)); reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); -- cgit v1.2.3 From fa8c8d7fa6e99fae3f6ab05f7f422598374dff29 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 15 Dec 2015 17:03:08 +0100 Subject: torcontrol debug: Change to a blanket message that covers both cases --- src/torcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 8eccc81e3..4ebcb9b66 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -618,7 +618,7 @@ void TorController::disconnected_cb(TorControlConnection& conn) if (!reconnect) return; - LogPrint("tor", "tor: Disconnected from Tor control port %s, trying to reconnect\n", target); + LogPrint("tor", "tor: Not connected to Tor control port %s, trying to reconnect\n", target); // Single-shot timer for reconnect. Use exponential backoff. struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0)); -- cgit v1.2.3 From fa60d05a4e194b9e3d2991ee2636c40c68737052 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 5 Jan 2015 21:40:24 +0100 Subject: Add missing copyright headers --- src/torcontrol.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 4ebcb9b66..e164b4e9f 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "torcontrol.h" #include "utilstrencodings.h" #include "net.h" -- cgit v1.2.3 From 0331aa350c04253f3b94604a0152042646fc94bb Mon Sep 17 00:00:00 2001 From: calebogden Date: Fri, 8 Jan 2016 13:31:42 -0800 Subject: Fixing typos on security-check.py and torcontrol.cpp --- src/torcontrol.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 4ebcb9b66..9a783b970 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -79,7 +79,7 @@ public: /** * Connect to a Tor control port. * target is address of the form host:port. - * connected is the handler that is called when connection is succesfully established. + * connected is the handler that is called when connection is successfully established. * disconnected is a handler that is called when the connection is broken. * Return true on success. */ @@ -177,7 +177,7 @@ void TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ct { TorControlConnection *self = (TorControlConnection*)ctx; if (what & BEV_EVENT_CONNECTED) { - LogPrint("tor", "tor: Succesfully connected!\n"); + LogPrint("tor", "tor: Successfully connected!\n"); self->connected(*self); } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { if (what & BEV_EVENT_ERROR) @@ -380,7 +380,7 @@ private: void authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply); /** Callback for PROTOCOLINFO result */ void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply); - /** Callback after succesful connection */ + /** Callback after successful connection */ void connected_cb(TorControlConnection& conn); /** Callback after connection lost or failed connection attempt */ void disconnected_cb(TorControlConnection& conn); @@ -419,7 +419,7 @@ TorController::~TorController() void TorController::add_onion_cb(TorControlConnection& conn, const TorControlReply& reply) { if (reply.code == 250) { - LogPrint("tor", "tor: ADD_ONION succesful\n"); + LogPrint("tor", "tor: ADD_ONION successful\n"); BOOST_FOREACH(const std::string &s, reply.lines) { std::map m = ParseTorReplyMapping(s); std::map::iterator i; @@ -448,7 +448,7 @@ void TorController::add_onion_cb(TorControlConnection& conn, const TorControlRep void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& reply) { if (reply.code == 250) { - LogPrint("tor", "tor: Authentication succesful\n"); + LogPrint("tor", "tor: Authentication successful\n"); // Now that we know Tor is running setup the proxy for onion addresses // if -onion isn't set to something else. @@ -501,7 +501,7 @@ static std::vector ComputeResponse(const std::string &key, const std::v void TorController::authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply) { if (reply.code == 250) { - LogPrint("tor", "tor: SAFECOOKIE authentication challenge succesful\n"); + LogPrint("tor", "tor: SAFECOOKIE authentication challenge successful\n"); std::pair l = SplitTorReplyLine(reply.lines[0]); if (l.first == "AUTHCHALLENGE") { std::map m = ParseTorReplyMapping(l.second); -- cgit v1.2.3 From 9d263bd17c2bdd5ba9e31bd5fb110c332eb80691 Mon Sep 17 00:00:00 2001 From: Chris Wheeler Date: Sun, 17 Jan 2016 11:03:56 +0000 Subject: Typo fixes in comments --- src/torcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 4ebcb9b66..2fd20ae42 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -303,7 +303,7 @@ static std::map ParseTorReplyMapping(const std::string /** Read full contents of a file and return them in a std::string. * Returns a pair . - * If an error occured, status will be false, otherwise status will be true and the data will be returned in string. + * If an error occurred, status will be false, otherwise status will be true and the data will be returned in string. * * @param maxsize Puts a maximum size limit on the file that is read. If the file is larger than this, truncated data * (with len > maxsize) will be returned. -- cgit v1.2.3 From 37767fd46f673a06864df6e14d3030622b1cb2c9 Mon Sep 17 00:00:00 2001 From: jloughry Date: Fri, 12 Feb 2016 11:35:32 -0700 Subject: fix spelling of advertise in src and doc --- src/torcontrol.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 2c68526df..10170dbce 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -434,7 +434,7 @@ void TorController::add_onion_cb(TorControlConnection& conn, const TorControlRep } service = CService(service_id+".onion", GetListenPort(), false); - LogPrintf("tor: Got service ID %s, advertizing service %s\n", service_id, service.ToString()); + LogPrintf("tor: Got service ID %s, advertising service %s\n", service_id, service.ToString()); if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) { LogPrint("tor", "tor: Cached service private key to %s\n", GetPrivateKeyFile()); } else { @@ -615,7 +615,7 @@ void TorController::connected_cb(TorControlConnection& conn) void TorController::disconnected_cb(TorControlConnection& conn) { - // Stop advertizing service when disconnected + // Stop advertising service when disconnected if (service.IsValid()) RemoveLocal(service); service = CService(); -- cgit v1.2.3 From 110b62f06992d0fb989153afff2dc3aea62a674f Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Wed, 17 Feb 2016 22:44:32 -0800 Subject: Remove vfReachable and modify IsReachable to only use vfLimited. We do not know that a class of Network is reachable, only that it is not. --- src/torcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 10170dbce..6fa8ce9d5 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -459,7 +459,7 @@ void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& r if (GetArg("-onion", "") == "") { proxyType addrOnion = proxyType(CService("127.0.0.1", 9050), true); SetProxy(NET_TOR, addrOnion); - SetReachable(NET_TOR); + SetLimited(NET_TOR, false); } // Finally - now create the service -- cgit v1.2.3 From e2195037116f47b11b66452351dba4fe606423a2 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 3 Mar 2016 13:28:07 +0100 Subject: Fix memleak in TorController [rework] It looks like, TorController::disconnected_cb(TorControlConnection& conn) gets called multiple times which results in multiple event_new(). Avoid this by creating the event only once in the constructore, and deleting it only once in the destructor (thanks to Cory Fields for the idea). Replaces the fix by Jonas Schnelli in #7610, see discussion there. --- src/torcontrol.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 10170dbce..a04b5c302 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -398,6 +398,9 @@ TorController::TorController(struct event_base* base, const std::string& target) target(target), conn(base), reconnect(true), reconnect_ev(0), reconnect_timeout(RECONNECT_TIMEOUT_START) { + reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); + if (!reconnect_ev) + LogPrintf("tor: Failed to create event for reconnection: out of memory?\n"); // Start connection attempts immediately if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1), boost::bind(&TorController::disconnected_cb, this, _1) )) { @@ -413,8 +416,10 @@ TorController::TorController(struct event_base* base, const std::string& target) TorController::~TorController() { - if (reconnect_ev) - event_del(reconnect_ev); + if (reconnect_ev) { + event_free(reconnect_ev); + reconnect_ev = 0; + } if (service.IsValid()) { RemoveLocal(service); } @@ -626,8 +631,8 @@ void TorController::disconnected_cb(TorControlConnection& conn) // Single-shot timer for reconnect. Use exponential backoff. struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0)); - reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); - event_add(reconnect_ev, &time); + if (reconnect_ev) + event_add(reconnect_ev, &time); reconnect_timeout *= RECONNECT_TIMEOUT_EXP; } -- cgit v1.2.3 From 3d7e97376aad055de0af7dc09abf3ee80e734740 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 14 Mar 2016 16:07:42 +0100 Subject: Fix torcontrol.cpp unused private field warning --- src/torcontrol.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index f755992a3..1c7bc2dbe 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -393,8 +393,8 @@ private: static void reconnect_cb(evutil_socket_t fd, short what, void *arg); }; -TorController::TorController(struct event_base* base, const std::string& target): - base(base), +TorController::TorController(struct event_base* baseIn, const std::string& target): + base(baseIn), target(target), conn(base), reconnect(true), reconnect_ev(0), reconnect_timeout(RECONNECT_TIMEOUT_START) { -- cgit v1.2.3 From d39f5b425d8fc1bf3b7f33d35625ffd8d7a3cd77 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 12 Apr 2016 20:48:29 -0400 Subject: net: disable resolving from storage structures CNetAddr/CService/CSubnet can no longer resolve DNS. --- src/torcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 1c7bc2dbe..47d834c7b 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -438,7 +438,7 @@ void TorController::add_onion_cb(TorControlConnection& conn, const TorControlRep private_key = i->second; } - service = CService(service_id+".onion", GetListenPort(), false); + service = CService(service_id+".onion", GetListenPort()); LogPrintf("tor: Got service ID %s, advertising service %s\n", service_id, service.ToString()); if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) { LogPrint("tor", "tor: Cached service private key to %s\n", GetPrivateKeyFile()); -- cgit v1.2.3 From 2e494489c35499dbe7891d4c07b4c35b178341d1 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 17 Mar 2016 12:49:16 +0100 Subject: tor: Change auth order to only use HASHEDPASSWORD if -torpassword Change authentication order to make it more clear (see #7700). - If the `-torpassword` option is provided, force use of `HASHEDPASSWORD` auth. - Give error message if `-torpassword` provided, but `HASHEDPASSWORD` auth is not available. - Give error message if only `HASHEDPASSWORD` available, but `-torpassword` not given. --- src/torcontrol.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 1c7bc2dbe..6fabe54af 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -574,7 +574,15 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl * password: "password" */ std::string torpassword = GetArg("-torpassword", ""); - if (methods.count("NULL")) { + if (!torpassword.empty()) { + if (methods.count("HASHEDPASSWORD")) { + LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n"); + boost::replace_all(torpassword, "\"", "\\\""); + conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2)); + } else { + LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n"); + } + } else if (methods.count("NULL")) { LogPrint("tor", "tor: Using NULL authentication\n"); conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2)); } else if (methods.count("SAFECOOKIE")) { @@ -595,13 +603,7 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl } } } else if (methods.count("HASHEDPASSWORD")) { - if (!torpassword.empty()) { - LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n"); - boost::replace_all(torpassword, "\"", "\\\""); - conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2)); - } else { - LogPrintf("tor: Password authentication required, but no password provided with -torpassword\n"); - } + LogPrintf("tor: The only supported authentication mechanism left is password, but no password provided with -torpassword\n"); } else { LogPrintf("tor: No supported authentication method\n"); } -- cgit v1.2.3 From f96c7c4d91f3c09d26658bc9c15aa561689fa2d4 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 31 May 2016 13:51:11 -0400 Subject: net: Split resolving out of CService --- src/torcontrol.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 0d6b65567..d3d782747 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -437,8 +437,7 @@ void TorController::add_onion_cb(TorControlConnection& conn, const TorControlRep if ((i = m.find("PrivateKey")) != m.end()) private_key = i->second; } - - service = CService(service_id+".onion", GetListenPort()); + LookupNumeric(std::string(service_id+".onion").c_str(), service, GetListenPort()); LogPrintf("tor: Got service ID %s, advertising service %s\n", service_id, service.ToString()); if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) { LogPrint("tor", "tor: Cached service private key to %s\n", GetPrivateKeyFile()); @@ -462,7 +461,9 @@ void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& r // Now that we know Tor is running setup the proxy for onion addresses // if -onion isn't set to something else. if (GetArg("-onion", "") == "") { - proxyType addrOnion = proxyType(CService("127.0.0.1", 9050), true); + CService resolved; + assert(LookupNumeric("127.0.0.1", resolved, 9050)); + proxyType addrOnion = proxyType(resolved, true); SetProxy(NET_TOR, addrOnion); SetLimited(NET_TOR, false); } -- cgit v1.2.3 From 21ba407a7369a0229b8a8554dee0da63a64e6639 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 31 May 2016 17:42:38 -0400 Subject: net: narrow include scope after moving to netaddress Net functionality is no longer needed for CAddress/CAddrman/etc. now that CNetAddr/CService/CSubNet are dumb storage classes. --- src/torcontrol.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index d3d782747..c7f962700 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -4,6 +4,7 @@ #include "torcontrol.h" #include "utilstrencodings.h" +#include "netbase.h" #include "net.h" #include "util.h" #include "crypto/hmac_sha256.h" -- cgit v1.2.3 From 8945384bca00f74ba85c98a52925c254c49025a5 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 4 Aug 2016 16:37:49 -0400 Subject: net: Have LookupNumeric return a CService directly Also fix up a few small issues: - Lookup with "badip:port" now sets the port to 0 - Don't allow assert to have side-effects --- src/torcontrol.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index c7f962700..99c45d489 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -438,7 +438,7 @@ void TorController::add_onion_cb(TorControlConnection& conn, const TorControlRep if ((i = m.find("PrivateKey")) != m.end()) private_key = i->second; } - LookupNumeric(std::string(service_id+".onion").c_str(), service, GetListenPort()); + service = LookupNumeric(std::string(service_id+".onion").c_str(), GetListenPort()); LogPrintf("tor: Got service ID %s, advertising service %s\n", service_id, service.ToString()); if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) { LogPrint("tor", "tor: Cached service private key to %s\n", GetPrivateKeyFile()); @@ -462,8 +462,7 @@ void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& r // Now that we know Tor is running setup the proxy for onion addresses // if -onion isn't set to something else. if (GetArg("-onion", "") == "") { - CService resolved; - assert(LookupNumeric("127.0.0.1", resolved, 9050)); + CService resolved(LookupNumeric("127.0.0.1", 9050)); proxyType addrOnion = proxyType(resolved, true); SetProxy(NET_TOR, addrOnion); SetLimited(NET_TOR, false); -- cgit v1.2.3 From 4731cab8fbff51a8178c85d572e2482040278616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Jan=C3=ADk?= Date: Fri, 2 Sep 2016 18:19:01 +0200 Subject: Do not shadow variables --- src/torcontrol.cpp | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 99c45d489..1ca6b4656 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -122,8 +122,8 @@ private: static void eventcb(struct bufferevent *bev, short what, void *ctx); }; -TorControlConnection::TorControlConnection(struct event_base *base): - base(base), b_conn(0) +TorControlConnection::TorControlConnection(struct event_base *_base): + base(_base), b_conn(0) { } @@ -194,7 +194,7 @@ void TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ct } } -bool TorControlConnection::Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected) +bool TorControlConnection::Connect(const std::string &target, const ConnectionCB& _connected, const ConnectionCB& _disconnected) { if (b_conn) Disconnect(); @@ -213,8 +213,8 @@ bool TorControlConnection::Connect(const std::string &target, const ConnectionCB return false; bufferevent_setcb(b_conn, TorControlConnection::readcb, NULL, TorControlConnection::eventcb, this); bufferevent_enable(b_conn, EV_READ|EV_WRITE); - this->connected = connected; - this->disconnected = disconnected; + this->connected = _connected; + this->disconnected = _disconnected; // Finally, connect to target if (bufferevent_socket_connect(b_conn, (struct sockaddr*)&connect_to_addr, connect_to_addrlen) < 0) { @@ -394,18 +394,18 @@ private: static void reconnect_cb(evutil_socket_t fd, short what, void *arg); }; -TorController::TorController(struct event_base* baseIn, const std::string& target): - base(baseIn), - target(target), conn(base), reconnect(true), reconnect_ev(0), +TorController::TorController(struct event_base* _base, const std::string& _target): + base(_base), + target(_target), conn(base), reconnect(true), reconnect_ev(0), reconnect_timeout(RECONNECT_TIMEOUT_START) { reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); if (!reconnect_ev) LogPrintf("tor: Failed to create event for reconnection: out of memory?\n"); // Start connection attempts immediately - if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1), + if (!conn.Connect(_target, boost::bind(&TorController::connected_cb, this, _1), boost::bind(&TorController::disconnected_cb, this, _1) )) { - LogPrintf("tor: Initiating connection to Tor control port %s failed\n", target); + LogPrintf("tor: Initiating connection to Tor control port %s failed\n", _target); } // Read service private key if cached std::pair pkf = ReadBinaryFile(GetPrivateKeyFile()); @@ -426,7 +426,7 @@ TorController::~TorController() } } -void TorController::add_onion_cb(TorControlConnection& conn, const TorControlReply& reply) +void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlReply& reply) { if (reply.code == 250) { LogPrint("tor", "tor: ADD_ONION successful\n"); @@ -454,7 +454,7 @@ void TorController::add_onion_cb(TorControlConnection& conn, const TorControlRep } } -void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& reply) +void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply& reply) { if (reply.code == 250) { LogPrint("tor", "tor: Authentication successful\n"); @@ -474,7 +474,7 @@ void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& r // Request hidden service, redirect port. // Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient // choice. TODO; refactor the shutdown sequence some day. - conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, GetListenPort(), GetListenPort()), + _conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, GetListenPort(), GetListenPort()), boost::bind(&TorController::add_onion_cb, this, _1, _2)); } else { LogPrintf("tor: Authentication failed\n"); @@ -508,7 +508,7 @@ static std::vector ComputeResponse(const std::string &key, const std::v return computedHash; } -void TorController::authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply) +void TorController::authchallenge_cb(TorControlConnection& _conn, const TorControlReply& reply) { if (reply.code == 250) { LogPrint("tor", "tor: SAFECOOKIE authentication challenge successful\n"); @@ -530,7 +530,7 @@ void TorController::authchallenge_cb(TorControlConnection& conn, const TorContro } std::vector computedClientHash = ComputeResponse(TOR_SAFE_CLIENTKEY, cookie, clientNonce, serverNonce); - conn.Command("AUTHENTICATE " + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, _1, _2)); + _conn.Command("AUTHENTICATE " + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, _1, _2)); } else { LogPrintf("tor: Invalid reply to AUTHCHALLENGE\n"); } @@ -539,7 +539,7 @@ void TorController::authchallenge_cb(TorControlConnection& conn, const TorContro } } -void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply) +void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorControlReply& reply) { if (reply.code == 250) { std::set methods; @@ -579,23 +579,23 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl if (methods.count("HASHEDPASSWORD")) { LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n"); boost::replace_all(torpassword, "\"", "\\\""); - conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2)); + _conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2)); } else { LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n"); } } else if (methods.count("NULL")) { LogPrint("tor", "tor: Using NULL authentication\n"); - conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2)); + _conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2)); } else if (methods.count("SAFECOOKIE")) { // Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie LogPrint("tor", "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile); std::pair status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE); if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) { - // conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, _1, _2)); + // _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, _1, _2)); cookie = std::vector(status_cookie.second.begin(), status_cookie.second.end()); clientNonce = std::vector(TOR_NONCE_SIZE, 0); GetRandBytes(&clientNonce[0], TOR_NONCE_SIZE); - conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2)); + _conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2)); } else { if (status_cookie.first) { LogPrintf("tor: Authentication cookie %s is not exactly %i bytes, as is required by the spec\n", cookiefile, TOR_COOKIE_SIZE); @@ -613,15 +613,15 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl } } -void TorController::connected_cb(TorControlConnection& conn) +void TorController::connected_cb(TorControlConnection& _conn) { reconnect_timeout = RECONNECT_TIMEOUT_START; // First send a PROTOCOLINFO command to figure out what authentication is expected - if (!conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, _1, _2))) + if (!_conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, _1, _2))) LogPrintf("tor: Error sending initial protocolinfo command\n"); } -void TorController::disconnected_cb(TorControlConnection& conn) +void TorController::disconnected_cb(TorControlConnection& _conn) { // Stop advertising service when disconnected if (service.IsValid()) -- cgit v1.2.3 From 7d3b627395582ae7c9d54ebdbc68096d7042162b Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 28 Nov 2016 17:13:51 +0100 Subject: torcontrol: Explicitly request RSA1024 private key When generating a new service key, explicitly request a RSA1024 one. The bitcoin P2P protocol has no support for the longer hidden service names that will come with ed25519 keys, until it does, we depend on the old hidden service type so make this explicit. See #9214. --- src/torcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 1ca6b4656..ffb9993f9 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -470,7 +470,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply& // Finally - now create the service if (private_key.empty()) // No private key, generate one - private_key = "NEW:BEST"; + private_key = "NEW:RSA1024"; // Explicitly request RSA1024 - see issue #9214 // Request hidden service, redirect port. // Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient // choice. TODO; refactor the shutdown sequence some day. -- cgit v1.2.3 From 8c1dbc5e9ddbafb77e60e8c4e6eb275a3a76ac12 Mon Sep 17 00:00:00 2001 From: Karl-Johan Alm Date: Fri, 9 Dec 2016 12:01:37 +0900 Subject: Refactor: Removed begin/end_ptr functions. --- src/torcontrol.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index ffb9993f9..67a69363f 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -501,10 +501,10 @@ static std::vector ComputeResponse(const std::string &key, const std::v { CHMAC_SHA256 computeHash((const uint8_t*)key.data(), key.size()); std::vector computedHash(CHMAC_SHA256::OUTPUT_SIZE, 0); - computeHash.Write(begin_ptr(cookie), cookie.size()); - computeHash.Write(begin_ptr(clientNonce), clientNonce.size()); - computeHash.Write(begin_ptr(serverNonce), serverNonce.size()); - computeHash.Finalize(begin_ptr(computedHash)); + computeHash.Write(cookie.data(), cookie.size()); + computeHash.Write(clientNonce.data(), clientNonce.size()); + computeHash.Write(serverNonce.data(), serverNonce.size()); + computeHash.Finalize(computedHash.data()); return computedHash; } -- cgit v1.2.3 From 27765b6403cece54320374b37afb01a0cfe571c3 Mon Sep 17 00:00:00 2001 From: isle2983 Date: Sat, 31 Dec 2016 11:01:21 -0700 Subject: Increment MIT Licence copyright header year on files modified in 2016 Edited via: $ contrib/devtools/copyright_header.py update . --- src/torcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 67a69363f..5571b7de4 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015 The Bitcoin Core developers +// Copyright (c) 2015-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -- cgit v1.2.3 From cc16d99f1dc8305b1b255f1cc0f2b1516aa77ed0 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 18 Jan 2017 16:15:37 +0100 Subject: [trivial] Fix typos in comments --- src/torcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/torcontrol.cpp') diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 5571b7de4..c49c5d9eb 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -372,7 +372,7 @@ private: struct event *reconnect_ev; float reconnect_timeout; CService service; - /** Cooie for SAFECOOKIE auth */ + /** Cookie for SAFECOOKIE auth */ std::vector cookie; /** ClientNonce for SAFECOOKIE auth */ std::vector clientNonce; -- cgit v1.2.3