|
|
@ -122,8 +122,8 @@ private: |
|
|
|
static void eventcb(struct bufferevent *bev, short what, void *ctx); |
|
|
|
static void eventcb(struct bufferevent *bev, short what, void *ctx); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
TorControlConnection::TorControlConnection(struct event_base *base): |
|
|
|
TorControlConnection::TorControlConnection(struct event_base *_base): |
|
|
|
base(base), b_conn(0) |
|
|
|
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) |
|
|
|
if (b_conn) |
|
|
|
Disconnect(); |
|
|
|
Disconnect(); |
|
|
@ -213,8 +213,8 @@ bool TorControlConnection::Connect(const std::string &target, const ConnectionCB |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
bufferevent_setcb(b_conn, TorControlConnection::readcb, NULL, TorControlConnection::eventcb, this); |
|
|
|
bufferevent_setcb(b_conn, TorControlConnection::readcb, NULL, TorControlConnection::eventcb, this); |
|
|
|
bufferevent_enable(b_conn, EV_READ|EV_WRITE); |
|
|
|
bufferevent_enable(b_conn, EV_READ|EV_WRITE); |
|
|
|
this->connected = connected; |
|
|
|
this->connected = _connected; |
|
|
|
this->disconnected = disconnected; |
|
|
|
this->disconnected = _disconnected; |
|
|
|
|
|
|
|
|
|
|
|
// Finally, connect to target
|
|
|
|
// Finally, connect to target
|
|
|
|
if (bufferevent_socket_connect(b_conn, (struct sockaddr*)&connect_to_addr, connect_to_addrlen) < 0) { |
|
|
|
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); |
|
|
|
static void reconnect_cb(evutil_socket_t fd, short what, void *arg); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
TorController::TorController(struct event_base* baseIn, const std::string& target): |
|
|
|
TorController::TorController(struct event_base* _base, const std::string& _target): |
|
|
|
base(baseIn), |
|
|
|
base(_base), |
|
|
|
target(target), conn(base), reconnect(true), reconnect_ev(0), |
|
|
|
target(_target), conn(base), reconnect(true), reconnect_ev(0), |
|
|
|
reconnect_timeout(RECONNECT_TIMEOUT_START) |
|
|
|
reconnect_timeout(RECONNECT_TIMEOUT_START) |
|
|
|
{ |
|
|
|
{ |
|
|
|
reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); |
|
|
|
reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); |
|
|
|
if (!reconnect_ev) |
|
|
|
if (!reconnect_ev) |
|
|
|
LogPrintf("tor: Failed to create event for reconnection: out of memory?\n"); |
|
|
|
LogPrintf("tor: Failed to create event for reconnection: out of memory?\n"); |
|
|
|
// Start connection attempts immediately
|
|
|
|
// 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) )) { |
|
|
|
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
|
|
|
|
// Read service private key if cached
|
|
|
|
std::pair<bool,std::string> pkf = ReadBinaryFile(GetPrivateKeyFile()); |
|
|
|
std::pair<bool,std::string> 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) { |
|
|
|
if (reply.code == 250) { |
|
|
|
LogPrint("tor", "tor: ADD_ONION successful\n"); |
|
|
|
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) { |
|
|
|
if (reply.code == 250) { |
|
|
|
LogPrint("tor", "tor: Authentication successful\n"); |
|
|
|
LogPrint("tor", "tor: Authentication successful\n"); |
|
|
@ -474,7 +474,7 @@ void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& r |
|
|
|
// Request hidden service, redirect port.
|
|
|
|
// 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
|
|
|
|
// 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.
|
|
|
|
// 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)); |
|
|
|
boost::bind(&TorController::add_onion_cb, this, _1, _2)); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
LogPrintf("tor: Authentication failed\n"); |
|
|
|
LogPrintf("tor: Authentication failed\n"); |
|
|
@ -508,7 +508,7 @@ static std::vector<uint8_t> ComputeResponse(const std::string &key, const std::v |
|
|
|
return computedHash; |
|
|
|
return computedHash; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void TorController::authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply) |
|
|
|
void TorController::authchallenge_cb(TorControlConnection& _conn, const TorControlReply& reply) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (reply.code == 250) { |
|
|
|
if (reply.code == 250) { |
|
|
|
LogPrint("tor", "tor: SAFECOOKIE authentication challenge successful\n"); |
|
|
|
LogPrint("tor", "tor: SAFECOOKIE authentication challenge successful\n"); |
|
|
@ -530,7 +530,7 @@ void TorController::authchallenge_cb(TorControlConnection& conn, const TorContro |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::vector<uint8_t> computedClientHash = ComputeResponse(TOR_SAFE_CLIENTKEY, cookie, clientNonce, serverNonce); |
|
|
|
std::vector<uint8_t> 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 { |
|
|
|
} else { |
|
|
|
LogPrintf("tor: Invalid reply to AUTHCHALLENGE\n"); |
|
|
|
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) { |
|
|
|
if (reply.code == 250) { |
|
|
|
std::set<std::string> methods; |
|
|
|
std::set<std::string> methods; |
|
|
@ -579,23 +579,23 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl |
|
|
|
if (methods.count("HASHEDPASSWORD")) { |
|
|
|
if (methods.count("HASHEDPASSWORD")) { |
|
|
|
LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n"); |
|
|
|
LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n"); |
|
|
|
boost::replace_all(torpassword, "\"", "\\\""); |
|
|
|
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 { |
|
|
|
} else { |
|
|
|
LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n"); |
|
|
|
LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
} else if (methods.count("NULL")) { |
|
|
|
} else if (methods.count("NULL")) { |
|
|
|
LogPrint("tor", "tor: Using NULL authentication\n"); |
|
|
|
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")) { |
|
|
|
} else if (methods.count("SAFECOOKIE")) { |
|
|
|
// Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie
|
|
|
|
// Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie
|
|
|
|
LogPrint("tor", "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile); |
|
|
|
LogPrint("tor", "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile); |
|
|
|
std::pair<bool,std::string> status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE); |
|
|
|
std::pair<bool,std::string> status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE); |
|
|
|
if (status_cookie.first && status_cookie.second.size() == 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<uint8_t>(status_cookie.second.begin(), status_cookie.second.end()); |
|
|
|
cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end()); |
|
|
|
clientNonce = std::vector<uint8_t>(TOR_NONCE_SIZE, 0); |
|
|
|
clientNonce = std::vector<uint8_t>(TOR_NONCE_SIZE, 0); |
|
|
|
GetRandBytes(&clientNonce[0], TOR_NONCE_SIZE); |
|
|
|
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 { |
|
|
|
} else { |
|
|
|
if (status_cookie.first) { |
|
|
|
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); |
|
|
|
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; |
|
|
|
reconnect_timeout = RECONNECT_TIMEOUT_START; |
|
|
|
// First send a PROTOCOLINFO command to figure out what authentication is expected
|
|
|
|
// 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"); |
|
|
|
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
|
|
|
|
// Stop advertising service when disconnected
|
|
|
|
if (service.IsValid()) |
|
|
|
if (service.IsValid()) |
|
|
|