switching QString to std::string and QByteArray to ByteArray. Unfinished yet.

This commit is contained in:
csoler 2021-11-25 23:28:01 +01:00
parent 3845dc1ea7
commit e4ce32bef8
25 changed files with 312 additions and 899 deletions

View File

@ -369,6 +369,8 @@ HEADERS += pqi/authssl.h \
pqi/authgpg.h \
pgp/pgphandler.h \
pgp/pgpkeyutil.h \
pqi/pqifdbin.h \
pqi/rstcpsocket.h \
pgp/rscertificate.h \
pgp/pgpauxutils.h \
pqi/p3cfgmgr.h \
@ -545,6 +547,8 @@ SOURCES += pqi/authgpg.cc \
pqi/p3cfgmgr.cc \
pqi/p3peermgr.cc \
pqi/p3linkmgr.cc \
pqi/pqifdbin.cc \
pqi/rstcpsocket.cc \
pqi/p3netmgr.cc \
pqi/p3notify.cc \
pqi/pqiqos.cc \
@ -733,6 +737,7 @@ HEADERS += tor/AddOnionCommand.h \
tor/SetConfCommand.h \
tor/Settings.h \
tor/StrUtil.h \
tor/bytearray.h \
tor/TorControl.h \
tor/TorControlCommand.h \
tor/TorControlSocket.h \

View File

@ -38,27 +38,29 @@ AuthenticateCommand::AuthenticateCommand()
{
}
QByteArray AuthenticateCommand::build(const QByteArray &data)
ByteArray AuthenticateCommand::build(const ByteArray& data)
{
if (data.isNull())
return QByteArray("AUTHENTICATE\r\n");
return ByteArray("AUTHENTICATE\r\n");
return QByteArray("AUTHENTICATE ") + data.toHex() + "\r\n";
return ByteArray("AUTHENTICATE ") + data.toHex() + "\r\n";
}
void AuthenticateCommand::onReply(int statusCode, const QByteArray &data)
void AuthenticateCommand::onReply(int statusCode, const ByteArray &data)
{
TorControlCommand::onReply(statusCode, data);
m_statusMessage = QString::fromLatin1(data);
m_statusMessage = data.toString();
}
void AuthenticateCommand::onFinished(int statusCode)
{
if (statusCode == 515) {
m_statusMessage = QStringLiteral("Authentication failed - incorrect password");
} else if (statusCode != 250) {
if (m_statusMessage.isEmpty())
m_statusMessage = QStringLiteral("Authentication failed (error %1").arg(statusCode);
m_statusMessage = "Authentication failed - incorrect password";
}
else if (statusCode != 250)
{
if (m_statusMessage.empty())
m_statusMessage = "Authentication failed (error " + RsUtil::NumberToString(statusCode) + ")";
}
TorControlCommand::onFinished(statusCode);
}

View File

@ -33,6 +33,7 @@
#ifndef AUTHENTICATECOMMAND_H
#define AUTHENTICATECOMMAND_H
#include "bytearray.h"
#include "TorControlCommand.h"
namespace Tor
@ -45,17 +46,17 @@ class AuthenticateCommand : public TorControlCommand
public:
AuthenticateCommand();
QByteArray build(const QByteArray &data = QByteArray());
ByteArray build(const ByteArray& data = ByteArray());
bool isSuccessful() const { return statusCode() == 250; }
QString errorMessage() const { return m_statusMessage; }
std::string errorMessage() const { return m_statusMessage; }
protected:
virtual void onReply(int statusCode, const QByteArray &data);
virtual void onReply(int statusCode, const ByteArray &data);
virtual void onFinished(int statusCode);
private:
QString m_statusMessage;
std::string m_statusMessage;
};
}

View File

@ -35,13 +35,18 @@
#include "CryptoKey.h"
#include "SecureRNG.h"
#include "Useful.h"
#include <QtDebug>
#include <QFile>
#include <QByteArray>
#include <openssl/bn.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include "stdio.h"
#include "util/rsdebug.h"
#include "util/rsrandom.h"
#include "util/rsdir.h"
#include "retroshare/rsids.h"
#include "bytearray.h"
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
{
@ -51,11 +56,6 @@ void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
#define RSA_bits(o) (BN_num_bits((o)->n))
#endif
#ifdef TO_REMOVE
void base32_encode(char *dest, unsigned destlen, const char *src, unsigned srclen);
bool base32_decode(char *dest, unsigned destlen, const char *src, unsigned srclen);
#endif
CryptoKey::CryptoKey()
{
}
@ -65,95 +65,50 @@ CryptoKey::~CryptoKey()
clear();
}
#ifdef TO_REMOVE
CryptoKey::Data::~Data()
{
if (key)
{
RSA_free(key);
key = 0;
}
}
#endif
void CryptoKey::clear()
{
key_data.clear();
}
#ifdef TO_REMOVE
bool CryptoKey::loadFromData(const QByteArray &data, KeyType type, KeyFormat format)
bool CryptoKey::loadFromFile(const std::string& path)
{
RSA *key = NULL;
clear();
FILE *file = fopen(path.c_str(),"r");
if (data.isEmpty())
return false;
if (format == PEM) {
BIO *b = BIO_new_mem_buf((void*)data.constData(), -1);
if (type == PrivateKey)
key = PEM_read_bio_RSAPrivateKey(b, NULL, NULL, NULL);
else
key = PEM_read_bio_RSAPublicKey(b, NULL, NULL, NULL);
BIO_free(b);
} else if (format == DER) {
const uchar *dp = reinterpret_cast<const uchar*>(data.constData());
if (type == PrivateKey)
key = d2i_RSAPrivateKey(NULL, &dp, data.size());
else
key = d2i_RSAPublicKey(NULL, &dp, data.size());
} else {
Q_UNREACHABLE();
}
if (!key) {
qWarning() << "Failed to parse" << (type == PrivateKey ? "private" : "public") << "key from data";
return false;
}
d = new Data(key);
return true;
}
#endif
bool CryptoKey::loadFromFile(const QString& path)
{
QFile file(path);
if (!file.open(QIODevice::ReadOnly))
if (!file)
{
qWarning() << "Failed to open Tor key file " << path << ": " << file.errorString();
RsWarn() << "Failed to open Tor key file " << path << ": errno = " << errno ;
return false;
}
QByteArray data = file.readAll();
file.close();
ByteArray data ;
int c;
while(EOF != (c=fgetc(file)))
data.append((unsigned char)c);
if(data.contains("-----BEGIN RSA PRIVATE KEY-----"))
fclose(file);
if(data.startsWith("-----BEGIN RSA PRIVATE KEY-----"))
{
std::cerr << "Note: Reading/converting Tor v2 key format." << std::endl;
// This to be compliant with old format. New format is oblivious to the type of key so we dont need a header
data = data.replace("-----BEGIN RSA PRIVATE KEY-----",nullptr);
data = data.replace("-----END RSA PRIVATE KEY-----",nullptr);
data = data.replace("\n",nullptr);
data = data.replace("\t",nullptr);
data = data.replace(ByteArray("-----BEGIN RSA PRIVATE KEY-----"),ByteArray());
data = data.replace(ByteArray("-----END RSA PRIVATE KEY-----"),ByteArray());
data = data.replace(ByteArray("\n"),ByteArray());
data = data.replace(ByteArray("\t"),ByteArray());
data = "RSA1024:"+data;
data = ByteArray("RSA1024:")+data;
}
std::cerr << "Have read the following key: " << std::endl;
std::cerr << QString(data).toStdString() << std::endl;
std::cerr << data.toString() << std::endl;
key_data = data;
return true;
}
bool CryptoKey::loadFromTorMessage(const QByteArray& b)
bool CryptoKey::loadFromTorMessage(const ByteArray& b)
{
// note: We should probably check the structure a bit more, for security.
@ -165,7 +120,7 @@ bool CryptoKey::loadFromTorMessage(const QByteArray& b)
std::cerr << " type: ED25519-V3 (Tor v3)" << std::endl;
else if(b.indexOf(':'))
{
std::cerr << " unknown type, or bad syntax in key: \"" << b.left(b.indexOf(':')).toStdString() << "\". Not accepted." << std::endl;
std::cerr << " unknown type, or bad syntax in key: \"" << b.left(b.indexOf(':')).toString() << "\". Not accepted." << std::endl;
return false;
}
@ -174,354 +129,15 @@ bool CryptoKey::loadFromTorMessage(const QByteArray& b)
}
/* Cryptographic hash of a password as expected by Tor's HashedControlPassword */
QByteArray torControlHashedPassword(const QByteArray &password)
ByteArray torControlHashedPassword(const ByteArray &password)
{
QByteArray salt = SecureRNG::random(8);
if (salt.isNull())
return QByteArray();
ByteArray salt(8);
RsRandom::random_bytes(&salt[0],8);
int count = ((quint32)16 + (96 & 15)) << ((96 >> 4) + 6);
uint32_t count = ((quint32)16 + (96 & 15)) << ((96 >> 4) + 6);
SHA_CTX hash;
SHA1_Init(&hash);
QByteArray tmp = salt + password;
while (count)
{
int c = qMin(count, tmp.size());
SHA1_Update(&hash, reinterpret_cast<const void*>(tmp.constData()), c);
count -= c;
}
unsigned char md[20];
SHA1_Final(md, &hash);
Sha1CheckSum md = RsDirUtil::sha1sum((salt+password).data(),count);
/* 60 is the hex-encoded value of 96, which is a constant used by Tor's algorithm. */
return QByteArray("16:") + salt.toHex().toUpper() + QByteArray("60") +
QByteArray::fromRawData(reinterpret_cast<const char*>(md), 20).toHex().toUpper();
return ByteArray("16:") + salt.toHex().toUpper() + ByteArray("60") + ByteArray(md.toByteArray(), md.SIZE_IN_BYTES).toHex().toUpper();
}
#ifdef TO_REMOVE
bool CryptoKey::isPrivate() const
{
if (!isLoaded()) {
return false;
} else {
const BIGNUM *p, *q;
RSA_get0_factors(d->key, &p, &q);
return (p != 0);
}
}
int CryptoKey::bits() const
{
return isLoaded() ? RSA_bits(d->key) : 0;
}
QByteArray CryptoKey::publicKeyDigest() const
{
if (!isLoaded())
return QByteArray();
QByteArray buf = encodedPublicKey(DER);
QByteArray re(20, 0);
bool ok = SHA1(reinterpret_cast<const unsigned char*>(buf.constData()), buf.size(),
reinterpret_cast<unsigned char*>(re.data())) != NULL;
if (!ok)
{
qWarning() << "Failed to hash public key data for digest";
return QByteArray();
}
return re;
}
QByteArray CryptoKey::encodedPublicKey(KeyFormat format) const
{
if (!isLoaded())
return QByteArray();
if (format == PEM) {
BIO *b = BIO_new(BIO_s_mem());
if (!PEM_write_bio_RSAPublicKey(b, d->key)) {
BUG() << "Failed to encode public key in PEM format";
BIO_free(b);
return QByteArray();
}
BUF_MEM *buf;
BIO_get_mem_ptr(b, &buf);
/* Close BIO, but don't free buf. */
(void)BIO_set_close(b, BIO_NOCLOSE);
BIO_free(b);
QByteArray re((const char *)buf->data, (int)buf->length);
BUF_MEM_free(buf);
return re;
} else if (format == DER) {
uchar *buf = NULL;
int len = i2d_RSAPublicKey(d->key, &buf);
if (len <= 0 || !buf) {
BUG() << "Failed to encode public key in DER format";
return QByteArray();
}
QByteArray re((const char*)buf, len);
OPENSSL_free(buf);
return re;
} else {
Q_UNREACHABLE();
}
return QByteArray();
}
QByteArray CryptoKey::encodedPrivateKey(KeyFormat format) const
{
if (!isLoaded() || !isPrivate())
return QByteArray();
if (format == PEM) {
BIO *b = BIO_new(BIO_s_mem());
if (!PEM_write_bio_RSAPrivateKey(b, d->key, NULL, NULL, 0, NULL, NULL)) {
BUG() << "Failed to encode private key in PEM format";
BIO_free(b);
return QByteArray();
}
BUF_MEM *buf;
BIO_get_mem_ptr(b, &buf);
/* Close BIO, but don't free buf. */
(void)BIO_set_close(b, BIO_NOCLOSE);
BIO_free(b);
QByteArray re((const char *)buf->data, (int)buf->length);
BUF_MEM_free(buf);
return re;
} else if (format == DER) {
uchar *buf = NULL;
int len = i2d_RSAPrivateKey(d->key, &buf);
if (len <= 0 || !buf) {
BUG() << "Failed to encode private key in DER format";
return QByteArray();
}
QByteArray re((const char*)buf, len);
OPENSSL_free(buf);
return re;
} else {
Q_UNREACHABLE();
}
return QByteArray();
}
QString CryptoKey::torServiceID() const
{
if (!isLoaded())
return QString();
QByteArray digest = publicKeyDigest();
if (digest.isNull())
return QString();
static const int hostnameDigestSize = 10;
static const int hostnameEncodedSize = 16;
QByteArray re(hostnameEncodedSize+1, 0);
base32_encode(re.data(), re.size(), digest.constData(), hostnameDigestSize);
// Chop extra null byte
re.chop(1);
return QString::fromLatin1(re);
}
QByteArray CryptoKey::signData(const QByteArray &data) const
{
QByteArray digest(32, 0);
bool ok = SHA256(reinterpret_cast<const unsigned char*>(data.constData()), data.size(),
reinterpret_cast<unsigned char*>(digest.data())) != NULL;
if (!ok) {
qWarning() << "Digest for RSA signature failed";
return QByteArray();
}
return signSHA256(digest);
}
QByteArray CryptoKey::signSHA256(const QByteArray &digest) const
{
if (!isPrivate())
return QByteArray();
QByteArray re(RSA_size(d->key), 0);
unsigned sigsize = 0;
int r = RSA_sign(NID_sha256, reinterpret_cast<const unsigned char*>(digest.constData()), digest.size(),
reinterpret_cast<unsigned char*>(re.data()), &sigsize, d->key);
if (r != 1) {
qWarning() << "RSA encryption failed when generating signature";
return QByteArray();
}
re.truncate(sigsize);
return re;
}
bool CryptoKey::verifyData(const QByteArray &data, QByteArray signature) const
{
QByteArray digest(32, 0);
bool ok = SHA256(reinterpret_cast<const unsigned char*>(data.constData()), data.size(),
reinterpret_cast<unsigned char*>(digest.data())) != NULL;
if (!ok) {
qWarning() << "Digest for RSA verify failed";
return false;
}
return verifySHA256(digest, signature);
}
bool CryptoKey::verifySHA256(const QByteArray &digest, QByteArray signature) const
{
if (!isLoaded())
return false;
int r = RSA_verify(NID_sha256, reinterpret_cast<const uchar*>(digest.constData()), digest.size(),
reinterpret_cast<uchar*>(signature.data()), signature.size(), d->key);
if (r != 1)
return false;
return true;
}
/* Copyright (c) 2001-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
* Copyright (c) 2007-2010, The Tor Project, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* Neither the names of the copyright owners nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
/* Implements base32 encoding as in rfc3548. Requires that srclen*8 is a multiple of 5. */
void base32_encode(char *dest, unsigned destlen, const char *src, unsigned srclen)
{
unsigned i, bit, v, u;
unsigned nbits = srclen * 8;
/* We need an even multiple of 5 bits, and enough space */
if ((nbits%5) != 0 || destlen > (nbits/5)+1) {
Q_ASSERT(false);
memset(dest, 0, destlen);
return;
}
for (i = 0, bit = 0; bit < nbits; ++i, bit += 5)
{
/* set v to the 16-bit value starting at src[bits/8], 0-padded. */
v = ((quint8) src[bit / 8]) << 8;
if (bit + 5 < nbits)
v += (quint8) src[(bit/8)+1];
/* set u to the 5-bit value at the bit'th bit of src. */
u = (v >> (11 - (bit % 8))) & 0x1F;
dest[i] = BASE32_CHARS[u];
}
dest[i] = '\0';
}
/* Implements base32 decoding as in rfc3548. Requires that srclen*5 is a multiple of 8. */
bool base32_decode(char *dest, unsigned destlen, const char *src, unsigned srclen)
{
unsigned int i, j, bit;
unsigned nbits = srclen * 5;
/* We need an even multiple of 8 bits, and enough space */
if ((nbits%8) != 0 || (nbits/8)+1 > destlen) {
Q_ASSERT(false);
return false;
}
char *tmp = new char[srclen];
/* Convert base32 encoded chars to the 5-bit values that they represent. */
for (j = 0; j < srclen; ++j)
{
if (src[j] > 0x60 && src[j] < 0x7B)
tmp[j] = src[j] - 0x61;
else if (src[j] > 0x31 && src[j] < 0x38)
tmp[j] = src[j] - 0x18;
else if (src[j] > 0x40 && src[j] < 0x5B)
tmp[j] = src[j] - 0x41;
else
{
delete[] tmp;
return false;
}
}
/* Assemble result byte-wise by applying five possible cases. */
for (i = 0, bit = 0; bit < nbits; ++i, bit += 8)
{
switch (bit % 40)
{
case 0:
dest[i] = (((quint8)tmp[(bit/5)]) << 3) + (((quint8)tmp[(bit/5)+1]) >> 2);
break;
case 8:
dest[i] = (((quint8)tmp[(bit/5)]) << 6) + (((quint8)tmp[(bit/5)+1]) << 1)
+ (((quint8)tmp[(bit/5)+2]) >> 4);
break;
case 16:
dest[i] = (((quint8)tmp[(bit/5)]) << 4) + (((quint8)tmp[(bit/5)+1]) >> 1);
break;
case 24:
dest[i] = (((quint8)tmp[(bit/5)]) << 7) + (((quint8)tmp[(bit/5)+1]) << 2)
+ (((quint8)tmp[(bit/5)+2]) >> 3);
break;
case 32:
dest[i] = (((quint8)tmp[(bit/5)]) << 5) + ((quint8)tmp[(bit/5)+1]);
break;
}
}
delete[] tmp;
return true;
}
#endif

View File

@ -37,6 +37,8 @@
#include <QSharedData>
#include <QExplicitlySharedDataPointer>
#include "bytearray.h"
class CryptoKey
{
public:
@ -53,54 +55,17 @@ public:
CryptoKey();
~CryptoKey();
#ifdef TO_REMOVE
bool loadFromData(const QByteArray &data, KeyType type, KeyFormat format = PEM);
bool loadFromFile(const QString &path, KeyType type, KeyFormat format = PEM);
#endif
bool loadFromFile(const QString &path);
bool loadFromFile(const std::string &path);
void clear();
const QByteArray bytes() const { return key_data; }
bool loadFromTorMessage(const QByteArray& b);
const ByteArray bytes() const { return key_data; }
bool loadFromTorMessage(const ByteArray& b);
bool isLoaded() const { return !key_data.isNull(); }
#ifdef TO_REMOVE
bool isPrivate() const;
QByteArray publicKeyDigest() const;
QByteArray encodedPublicKey(KeyFormat format) const;
QByteArray encodedPrivateKey(KeyFormat format) const;
QString torServiceID() const;
int bits() const;
// Calculate and sign SHA-256 digest of data using this key and PKCS #1 v2.0 padding
QByteArray signData(const QByteArray &data) const;
// Verify a signature as per signData
bool verifyData(const QByteArray &data, QByteArray signature) const;
// Sign the input SHA-256 digest using this key and PKCS #1 v2.0 padding
QByteArray signSHA256(const QByteArray &digest) const;
// Verify a signature as per signSHA256
bool verifySHA256(const QByteArray &digest, QByteArray signature) const;
#endif
private:
#ifdef TO_REMOVE
struct Data : public QSharedData
{
typedef struct rsa_st RSA;
RSA *key;
Data(RSA *k = 0) : key(k) { }
~Data();
};
#endif
QByteArray key_data;
#ifdef TO_REMOVE
QExplicitlySharedDataPointer<Data> d;
#endif
ByteArray key_data;
};
QByteArray torControlHashedPassword(const QByteArray &password);
ByteArray torControlHashedPassword(const ByteArray &password);
#endif // CRYPTOKEY_H

View File

@ -41,14 +41,14 @@ GetConfCommand::GetConfCommand(Type t)
{
}
QByteArray GetConfCommand::build(const QByteArray &key)
ByteArray GetConfCommand::build(const ByteArray &key)
{
return build(QList<QByteArray>() << key);
return build(QList<ByteArray>() << key);
}
QByteArray GetConfCommand::build(const QList<QByteArray> &keys)
ByteArray GetConfCommand::build(const QList<ByteArray> &keys)
{
QByteArray out;
ByteArray out;
if (type == GetConf) {
out = "GETCONF";
} else if (type == GetInfo) {
@ -58,7 +58,7 @@ QByteArray GetConfCommand::build(const QList<QByteArray> &keys)
return out;
}
foreach (const QByteArray &key, keys) {
foreach (const ByteArray &key, keys) {
out.append(' ');
out.append(key);
}
@ -67,49 +67,29 @@ QByteArray GetConfCommand::build(const QList<QByteArray> &keys)
return out;
}
void GetConfCommand::onReply(int statusCode, const QByteArray &data)
void GetConfCommand::onReply(int statusCode, const ByteArray &data)
{
TorControlCommand::onReply(statusCode, data);
if (statusCode != 250)
return;
int kep = data.indexOf('=');
QString key = QString::fromLatin1(data.mid(0, kep));
QVariant value;
std::string key = data.mid(0, kep).toString();
std::string value;
if (kep >= 0)
value = QString::fromLatin1(unquotedString(data.mid(kep + 1)));
value = unquotedString(data.mid(kep + 1)).toString();
m_lastKey = key;
QVariantMap::iterator it = m_results.find(key);
if (it != m_results.end()) {
// Make a list of values
QVariantList results = it->toList();
if (results.isEmpty())
results.append(*it);
results.append(value);
*it = QVariant(results);
} else {
m_results.insert(key, value);
}
m_results[key].push_back(value);
}
void GetConfCommand::onDataLine(const QByteArray &data)
void GetConfCommand::onDataLine(const ByteArray &data)
{
if (m_lastKey.isEmpty()) {
if (m_lastKey.empty()) {
qWarning() << "torctrl: Unexpected data line in GetConf command";
return;
}
QVariantMap::iterator it = m_results.find(m_lastKey);
if (it != m_results.end()) {
QVariantList results = it->toList();
if (results.isEmpty() && !it->toByteArray().isEmpty())
results.append(*it);
results.append(data);
*it = QVariant(results);
} else {
m_results.insert(m_lastKey, QVariantList() << data);
}
m_results[m_lastKey].push_back(data.toString());
}
void GetConfCommand::onDataFinished()
@ -117,8 +97,13 @@ void GetConfCommand::onDataFinished()
m_lastKey.clear();
}
QVariant GetConfCommand::get(const QByteArray &key) const
std::list<std::string> GetConfCommand::get(const ByteArray& key) const
{
return m_results.value(QString::fromLatin1(key));
auto it = m_results.find(key.toString());
if(it != m_results.end())
return it->second;
else
return std::list<std::string>();
}

View File

@ -56,20 +56,20 @@ public:
GetConfCommand(Type type);
QByteArray build(const QByteArray &key);
QByteArray build(const QList<QByteArray> &keys);
ByteArray build(const ByteArray &key);
ByteArray build(const QList<ByteArray> &keys);
const QVariantMap &results() const { return m_results; }
QVariant get(const QByteArray &key) const;
const std::map<std::string,std::list<std::string> > &results() const { return m_results; }
std::list<std::string> get(const ByteArray &key) const;
protected:
virtual void onReply(int statusCode, const QByteArray &data);
virtual void onDataLine(const QByteArray &data);
virtual void onReply(int statusCode, const ByteArray &data);
virtual void onDataLine(const ByteArray &data);
virtual void onDataFinished();
private:
QVariantMap m_results;
QString m_lastKey;
std::map<std::string,std::list<std::string> > m_results;
std::string m_lastKey;
};
}

View File

@ -32,11 +32,9 @@
#include "HiddenService.h"
#include "TorControl.h"
#include "TorSocket.h"
#include "CryptoKey.h"
#include "Useful.h"
#include <QDir>
#include <QFile>
#include <QTimer>
#include <QDebug>
@ -47,7 +45,7 @@ HiddenService::HiddenService(HiddenServiceClient *client)
{
}
HiddenService::HiddenService(HiddenServiceClient *client,const QString &path)
HiddenService::HiddenService(HiddenServiceClient *client,const std::string& path)
: m_dataPath(path), m_status(NotCreated), m_client(client)
{
/* Set the initial status and, if possible, load the hostname */
@ -58,7 +56,7 @@ HiddenService::HiddenService(HiddenServiceClient *client,const QString &path)
}
}
HiddenService::HiddenService(HiddenServiceClient *client,const CryptoKey &privateKey, const QString &path)
HiddenService::HiddenService(HiddenServiceClient *client,const CryptoKey &privateKey, const std::string &path)
: m_dataPath(path), m_status(NotCreated), m_client(client)
{
setPrivateKey(privateKey);
@ -92,7 +90,7 @@ void HiddenService::addTarget(quint16 servicePort, QHostAddress targetAddress, q
m_targets.append(t);
}
void HiddenService::setServiceId(const QByteArray& sid)
void HiddenService::setServiceId(const ByteArray& sid)
{
m_service_id = sid;
m_hostname = sid + ".onion";

View File

@ -38,11 +38,11 @@
#include <QList>
#include "CryptoKey.h"
#include "bytearray.h"
namespace Tor
{
class TorSocket;
// This class is used to receive synchroneous notifications from the hidden service.
// Each client should implement its own notification handling.
@ -77,20 +77,20 @@ public:
};
HiddenService(HiddenServiceClient *client);
HiddenService(HiddenServiceClient *client,const QString &dataPath);
HiddenService(HiddenServiceClient *client,const CryptoKey &privateKey, const QString &dataPath = QString());
HiddenService(HiddenServiceClient *client, const std::string &dataPath);
HiddenService(HiddenServiceClient *client, const CryptoKey &privateKey, const std::string &dataPath = QString());
Status status() const { return m_status; }
const QString& hostname() const { return m_hostname; }
const QString serviceId() const { return QString(m_service_id); }
const QString& dataPath() const { return m_dataPath; }
const std::string& hostname() const { return m_hostname; }
const std::string serviceId() const { return m_service_id.toString(); }
const std::string& dataPath() const { return m_dataPath; }
CryptoKey privateKey() { return m_privateKey; }
void setPrivateKey(const CryptoKey &privateKey);
void setServiceId(const QByteArray& sid);
void setServiceId(const ByteArray &sid);
const QList<Target> &targets() const { return m_targets; }
const std::list<Target> &targets() const { return m_targets; }
void addTarget(const Target &target);
void addTarget(quint16 servicePort, QHostAddress targetAddress, quint16 targetPort);
@ -98,12 +98,12 @@ private slots:
void servicePublished();
private:
QString m_dataPath;
QList<Target> m_targets;
QString m_hostname;
std::string m_dataPath;
std::list<Target> m_targets;
std::string m_hostname;
Status m_status;
CryptoKey m_privateKey;
QByteArray m_service_id;
ByteArray m_service_id;
void loadPrivateKey();
void setStatus(Status newStatus);

View File

@ -42,12 +42,12 @@ ProtocolInfoCommand::ProtocolInfoCommand(TorControl *m)
{
}
QByteArray ProtocolInfoCommand::build()
ByteArray ProtocolInfoCommand::build()
{
return QByteArray("PROTOCOLINFO 1\r\n");
return ByteArray("PROTOCOLINFO 1\r\n");
}
void ProtocolInfoCommand::onReply(int statusCode, const QByteArray &data)
void ProtocolInfoCommand::onReply(int statusCode, const ByteArray &data)
{
TorControlCommand::onReply(statusCode, data);
if (statusCode != 250)
@ -55,14 +55,14 @@ void ProtocolInfoCommand::onReply(int statusCode, const QByteArray &data)
if (data.startsWith("AUTH "))
{
QList<QByteArray> tokens = splitQuotedStrings(data.mid(5), ' ');
QList<ByteArray> tokens = splitQuotedStrings(data.mid(5), ' ');
foreach (QByteArray token, tokens)
foreach (ByteArray token, tokens)
{
if (token.startsWith("METHODS="))
{
QList<QByteArray> textMethods = unquotedString(token.mid(8)).split(',');
for (QList<QByteArray>::Iterator it = textMethods.begin(); it != textMethods.end(); ++it)
QList<ByteArray> textMethods = unquotedString(token.mid(8)).split(',');
for (QList<ByteArray>::Iterator it = textMethods.begin(); it != textMethods.end(); ++it)
{
if (*it == "NULL")
m_authMethods |= AuthNull;
@ -80,6 +80,6 @@ void ProtocolInfoCommand::onReply(int statusCode, const QByteArray &data)
}
else if (data.startsWith("VERSION Tor="))
{
m_torVersion = QString::fromLatin1(unquotedString(data.mid(12, data.indexOf(' ', 12))));
m_torVersion = std::string(unquotedString(data.mid(12, data.indexOf(' ', 12))));
}
}

View File

@ -57,14 +57,14 @@ public:
Q_DECLARE_FLAGS(AuthMethods, AuthMethod)
ProtocolInfoCommand(TorControl *manager);
QByteArray build();
ByteArray build();
AuthMethods authMethods() const { return m_authMethods; }
QString torVersion() const { return m_torVersion; }
QString cookieFile() const { return m_cookieFile; }
protected:
virtual void onReply(int statusCode, const QByteArray &data);
virtual void onReply(int statusCode, const ByteArray &data);
private:
TorControl *manager;

View File

@ -50,49 +50,55 @@ bool SetConfCommand::isSuccessful() const
return statusCode() == 250;
}
QByteArray SetConfCommand::build(const QByteArray &key, const QByteArray &value)
ByteArray SetConfCommand::build(const ByteArray &key, const ByteArray &value)
{
return build(QList<QPair<QByteArray, QByteArray> >() << qMakePair(key, value));
return build(std::list<std::pair<ByteArray, ByteArray> > { std::make_pair(key, value) } );
}
QByteArray SetConfCommand::build(const QVariantMap &data)
// ByteArray SetConfCommand::build(const std::list<std::pair<ByteArray,ByteArray> > &data)
// {
// QList<QPair<QByteArray, QByteArray> > out;
//
// for (QVariantMap::ConstIterator it = data.begin(); it != data.end(); it++) {
// QByteArray key = it.key().toLatin1();
//
// if (static_cast<QMetaType::Type>(it.value().type()) == QMetaType::QVariantList) {
// QVariantList values = it.value().value<QVariantList>();
// foreach (const QVariant &value, values)
// out.append(qMakePair(key, value.toString().toLatin1()));
// } else {
// out.append(qMakePair(key, it.value().toString().toLatin1()));
// }
// }
//
// return build(out);
// }
ByteArray SetConfCommand::build(const std::list<std::pair<ByteArray, ByteArray> >& data)
{
QList<QPair<QByteArray, QByteArray> > out;
ByteArray out(m_resetMode ? "RESETCONF" : "SETCONF");
for (QVariantMap::ConstIterator it = data.begin(); it != data.end(); it++) {
QByteArray key = it.key().toLatin1();
for (auto& p:data)
{
out += " " ;
out += p.first;
if (static_cast<QMetaType::Type>(it.value().type()) == QMetaType::QVariantList) {
QVariantList values = it.value().value<QVariantList>();
foreach (const QVariant &value, values)
out.append(qMakePair(key, value.toString().toLatin1()));
} else {
out.append(qMakePair(key, it.value().toString().toLatin1()));
if (!p.second.empty())
{
out += "=" ;
out += quotedString(p.second);
}
}
return build(out);
}
QByteArray SetConfCommand::build(const QList<QPair<QByteArray, QByteArray> > &data)
{
QByteArray out(m_resetMode ? "RESETCONF" : "SETCONF");
for (int i = 0; i < data.size(); i++) {
out += " " + data[i].first;
if (!data[i].second.isEmpty())
out += "=" + quotedString(data[i].second);
}
out.append("\r\n");
return out;
}
void SetConfCommand::onReply(int statusCode, const QByteArray &data)
void SetConfCommand::onReply(int statusCode, const ByteArray &data)
{
TorControlCommand::onReply(statusCode, data);
if (statusCode != 250)
m_errorMessage = QString::fromLatin1(data);
m_errorMessage = data.toString();
}
void SetConfCommand::onFinished(int statusCode)

View File

@ -54,11 +54,10 @@ public:
void setResetMode(bool resetMode);
QByteArray build(const QByteArray &key, const QByteArray &value);
QByteArray build(const QVariantMap &data);
QByteArray build(const QList<QPair<QByteArray, QByteArray> > &data);
ByteArray build(const ByteArray &key, const ByteArray &value);
ByteArray build(const std::list<std::pair<ByteArray, ByteArray> > &data);
QString errorMessage() const { return m_errorMessage; }
std::string errorMessage() const { return m_errorMessage; }
bool isSuccessful() const;
signals:
@ -66,10 +65,10 @@ signals:
void setConfFailed(int code);
protected:
QString m_errorMessage;
std::string m_errorMessage;
bool m_resetMode;
virtual void onReply(int statusCode, const QByteArray &data);
virtual void onReply(int statusCode, const ByteArray &data);
virtual void onFinished(int statusCode);
};

View File

@ -48,8 +48,8 @@ class SettingsFilePrivate : public QObject
public:
SettingsFile *q;
QString filePath;
QString errorMessage;
std::string filePath;
std::string errorMessage;
QTimer syncTimer;
QJsonObject jsonRoot;
SettingsObject *rootObject;
@ -58,17 +58,17 @@ public:
virtual ~SettingsFilePrivate();
void reset();
void setError(const QString &message);
bool checkDirPermissions(const QString &path);
void setError(const std::string &message);
bool checkDirPermissions(const std::string &path);
bool readFile();
bool writeFile();
static QStringList splitPath(const QString &input, bool &ok);
QJsonValue read(const QJsonObject &base, const QStringList &path);
bool write(const QStringList &path, const QJsonValue &value);
static std::list<std::string> splitPath(const std::string& input, bool &ok);
QJsonValue read(const QJsonObject &base, const std::list<std::string> &path);
bool write(const std::list<std::string> &path, const QJsonValue &value);
signals:
void modified(const QStringList &path, const QJsonValue &value);
void modified(const std::list<std::string> &path, const QJsonValue &value);
private slots:
void sync();

View File

@ -37,7 +37,6 @@
#include <QJsonValue>
#include <QJsonObject>
#include <QJsonArray>
#include <QStringList>
#include <QDateTime>
class SettingsObject;

View File

@ -32,14 +32,14 @@
#include "StrUtil.h"
QByteArray quotedString(const QByteArray &string)
ByteArray quotedString(const ByteArray &string)
{
QByteArray out;
ByteArray out;
out.reserve(string.size() * 2);
out.append('"');
for (int i = 0; i < string.size(); ++i)
for (uint i = 0; i < string.size(); ++i)
{
switch (string[i])
{
@ -59,15 +59,15 @@ QByteArray quotedString(const QByteArray &string)
return out;
}
QByteArray unquotedString(const QByteArray &string)
ByteArray unquotedString(const ByteArray &string)
{
if (string.size() < 2 || string[0] != '"')
return string;
QByteArray out;
ByteArray out;
out.reserve(string.size() - 2);
for (int i = 1; i < string.size(); ++i)
for (uint i = 1; i < string.size(); ++i)
{
switch (string[i])
{
@ -85,13 +85,13 @@ QByteArray unquotedString(const QByteArray &string)
return out;
}
QList<QByteArray> splitQuotedStrings(const QByteArray &input, char separator)
std::list<ByteArray> splitQuotedStrings(const ByteArray &input, char separator)
{
QList<QByteArray> out;
std::list<ByteArray> out;
bool inquote = false;
int start = 0;
uint start = 0;
for (int i = 0; i < input.size(); ++i)
for (uint i = 0; i < input.size(); ++i)
{
switch (input[i])
{
@ -106,13 +106,13 @@ QList<QByteArray> splitQuotedStrings(const QByteArray &input, char separator)
if (!inquote && input[i] == separator)
{
out.append(input.mid(start, i - start));
out.push_back(input.mid(start, i - start));
start = i+1;
}
}
if (start < input.size())
out.append(input.mid(start));
out.push_back(input.mid(start));
return out;
}

View File

@ -33,14 +33,15 @@
#ifndef STRINGUTIL_H
#define STRINGUTIL_H
#include <QByteArray>
#include <QList>
#include <list>
QByteArray quotedString(const QByteArray &string);
#include "bytearray.h"
ByteArray quotedString(const ByteArray &string);
/* Return the unquoted contents of a string, either until an end quote or an unescaped separator character. */
QByteArray unquotedString(const QByteArray &string);
ByteArray unquotedString(const ByteArray &string);
QList<QByteArray> splitQuotedStrings(const QByteArray &input, char separator);
std::list<ByteArray> splitQuotedStrings(const ByteArray& input, char separator);
#endif // STRINGUTIL_H

View File

@ -85,7 +85,7 @@ public:
QHostAddress torAddress;
QString errorMessage;
QString torVersion;
QByteArray authPassword;
ByteArray authPassword;
QHostAddress socksAddress;
QList<HiddenService*> services;
quint16 controlPort, socksPort;
@ -112,8 +112,8 @@ public slots:
void getTorInfoReply();
void setError(const QString &message);
void statusEvent(int code, const QByteArray &data);
void updateBootstrap(const QList<QByteArray> &data);
void statusEvent(int code, const ByteArray &data);
void updateBootstrap(const QList<ByteArray> &data);
};
}
@ -276,7 +276,7 @@ QVariantMap TorControl::bootstrapStatus() const
return d->bootstrapStatus;
}
void TorControl::setAuthPassword(const QByteArray &password)
void TorControl::setAuthPassword(const ByteArray &password)
{
d->authPassword = password;
}
@ -385,7 +385,7 @@ void TorControlPrivate::protocolInfoReply()
AuthenticateCommand *auth = new AuthenticateCommand;
connect(auth, &TorControlCommand::finished, this, &TorControlPrivate::authenticateReply);
QByteArray data;
ByteArray data;
ProtocolInfoCommand::AuthMethods methods = info->authMethods();
if (methods.testFlag(ProtocolInfoCommand::AuthNull))
@ -402,7 +402,7 @@ void TorControlPrivate::protocolInfoReply()
QFile file(cookieFile);
if (file.open(QIODevice::ReadOnly))
{
QByteArray cookie = file.readAll();
ByteArray cookie = file.readAll();
file.close();
/* Simple test to avoid a vulnerability where any process listening on what we think is
@ -458,8 +458,8 @@ void TorControlPrivate::getTorInfo()
GetConfCommand *command = new GetConfCommand(GetConfCommand::GetInfo);
connect(command, &TorControlCommand::finished, this, &TorControlPrivate::getTorInfoReply);
QList<QByteArray> keys;
keys << QByteArray("status/circuit-established") << QByteArray("status/bootstrap-phase");
QList<ByteArray> keys;
keys << ByteArray("status/circuit-established") << ByteArray("status/bootstrap-phase");
/* If these are set in the config, they override the automatic behavior. */
SettingsObject settings(QStringLiteral("tor"));
@ -479,7 +479,7 @@ void TorControlPrivate::getTorInfo()
rsEvents->sendEvent(ev);
}
} else
keys << QByteArray("net/listeners/socks");
keys << ByteArray("net/listeners/socks");
socket->sendCommand(command, command->build(keys));
}
@ -490,9 +490,9 @@ void TorControlPrivate::getTorInfoReply()
if (!command || !q->isConnected())
return;
QList<QByteArray> listenAddresses = splitQuotedStrings(command->get(QByteArray("net/listeners/socks")).toString().toLatin1(), ' ');
for (QList<QByteArray>::Iterator it = listenAddresses.begin(); it != listenAddresses.end(); ++it) {
QByteArray value = unquotedString(*it);
QList<ByteArray> listenAddresses = splitQuotedStrings(command->get(ByteArray("net/listeners/socks")).toString().toLatin1(), ' ');
for (QList<ByteArray>::Iterator it = listenAddresses.begin(); it != listenAddresses.end(); ++it) {
ByteArray value = unquotedString(*it);
int sepp = value.indexOf(':');
QHostAddress address(QString::fromLatin1(value.mid(0, sepp)));
quint16 port = (quint16)value.mid(sepp+1).toUInt();
@ -523,14 +523,14 @@ void TorControlPrivate::getTorInfoReply()
}
}
if (command->get(QByteArray("status/circuit-established")).toInt() == 1) {
if (command->get(ByteArray("status/circuit-established")).toInt() == 1) {
torCtrlDebug() << "torctrl: Tor indicates that circuits have been established; state is TorReady" << std::endl;
setTorStatus(TorControl::TorReady);
} else {
setTorStatus(TorControl::TorOffline);
}
QByteArray bootstrap = command->get(QByteArray("status/bootstrap-phase")).toString().toLatin1();
ByteArray bootstrap = command->get(ByteArray("status/bootstrap-phase")).toString().toLatin1();
if (!bootstrap.isEmpty())
updateBootstrap(splitQuotedStrings(bootstrap, ' '));
}
@ -580,7 +580,7 @@ void TorControlPrivate::publishServices()
} else {
torCtrlDebug() << "torctrl: Using legacy SETCONF hidden service configuration for tor" << torVersion.toStdString() << std::endl;
SetConfCommand *command = new SetConfCommand;
QList<QPair<QByteArray,QByteArray> > torConfig;
QList<QPair<ByteArray,ByteArray> > torConfig;
foreach (HiddenService *service, services)
{
@ -596,7 +596,7 @@ void TorControlPrivate::publishServices()
torCtrlDebug() << "torctrl: Configuring hidden service at" << service->dataPath().toStdString() << std::endl;
QDir dir(service->dataPath());
torConfig.append(qMakePair(QByteArray("HiddenServiceDir"), dir.absolutePath().toLocal8Bit()));
torConfig.append(qMakePair(ByteArray("HiddenServiceDir"), dir.absolutePath().toLocal8Bit()));
const QList<HiddenService::Target> &targets = service->targets();
for (QList<HiddenService::Target>::ConstIterator tit = targets.begin(); tit != targets.end(); ++tit)
@ -604,7 +604,7 @@ void TorControlPrivate::publishServices()
QString target = QString::fromLatin1("%1 %2:%3").arg(tit->servicePort)
.arg(tit->targetAddress.toString())
.arg(tit->targetPort);
torConfig.append(qMakePair(QByteArray("HiddenServicePort"), target.toLatin1()));
torConfig.append(qMakePair(ByteArray("HiddenServicePort"), target.toLatin1()));
}
QObject::connect(command, &SetConfCommand::setConfSucceeded, service, &HiddenService::servicePublished);
@ -640,11 +640,11 @@ void TorControl::shutdownSync()
}
}
void TorControlPrivate::statusEvent(int code, const QByteArray &data)
void TorControlPrivate::statusEvent(int code, const ByteArray &data)
{
Q_UNUSED(code);
QList<QByteArray> tokens = splitQuotedStrings(data.trimmed(), ' ');
QList<ByteArray> tokens = splitQuotedStrings(data.trimmed(), ' ');
if (tokens.size() < 3)
return;
@ -660,7 +660,7 @@ void TorControlPrivate::statusEvent(int code, const QByteArray &data)
}
}
void TorControlPrivate::updateBootstrap(const QList<QByteArray> &data)
void TorControlPrivate::updateBootstrap(const QList<ByteArray> &data)
{
bootstrapStatus.clear();
// WARN or NOTICE
@ -721,7 +721,7 @@ public:
Q_ASSERT(!command);
command = new GetConfCommand(GetConfCommand::GetInfo);
QObject::connect(command, &TorControlCommand::finished, this, &SaveConfigOperation::configTextReply);
socket->sendCommand(command, command->build(QList<QByteArray>() << "config-text" << "config-file"));
socket->sendCommand(command, command->build(QList<ByteArray>() << "config-text" << "config-file"));
}
private slots:
@ -763,7 +763,7 @@ private slots:
QVariantList configText = command->get("config-text").toList();
foreach (const QVariant &value, configText) {
QByteArray line = value.toByteArray();
ByteArray line = value.toByteArray();
bool skip = false;
for (const char **key = bannedKeys; *key; key++) {

View File

@ -40,7 +40,7 @@ TorControlCommand::TorControlCommand()
{
}
void TorControlCommand::onReply(int statusCode, const QByteArray &data)
void TorControlCommand::onReply(int statusCode, const ByteArray &data)
{
emit replyLine(statusCode, data);
}
@ -51,7 +51,7 @@ void TorControlCommand::onFinished(int statusCode)
emit finished();
}
void TorControlCommand::onDataLine(const QByteArray &data)
void TorControlCommand::onDataLine(const ByteArray &data)
{
Q_UNUSED(data);
}

View File

@ -34,7 +34,8 @@
#define TORCONTROLCOMMAND_H
#include <QObject>
#include <QByteArray>
#include "bytearray.h"
namespace Tor
{
@ -52,13 +53,13 @@ public:
int statusCode() const { return m_finalStatus; }
signals:
void replyLine(int statusCode, const QByteArray &data);
void replyLine(int statusCode, const ByteArray &data);
void finished();
protected:
virtual void onReply(int statusCode, const QByteArray &data);
virtual void onReply(int statusCode, const ByteArray &data);
virtual void onFinished(int statusCode);
virtual void onDataLine(const QByteArray &data);
virtual void onDataLine(const ByteArray &data);
virtual void onDataFinished();
private:

View File

@ -34,12 +34,11 @@
#include "TorControlSocket.h"
#include "TorControlCommand.h"
#include <QDebug>
using namespace Tor;
TorControlSocket::TorControlSocket(QObject *parent)
: QTcpSocket(parent), currentCommand(0), inDataReply(false)
TorControlSocket::TorControlSocket()
: currentCommand(0), inDataReply(false)
{
connect(this, SIGNAL(readyRead()), this, SLOT(process()));
connect(this, SIGNAL(disconnected()), this, SLOT(clear()));
@ -54,7 +53,7 @@ void TorControlSocket::sendCommand(TorControlCommand *command, const QByteArray
{
Q_ASSERT(data.endsWith("\r\n"));
commandQueue.append(command);
commandQueue.push_back(command);
write(data);
std::cerr << "[TOR CTRL] Sent: \"" << QString(data.trimmed()).toStdString() << "\"" << std::endl;
@ -84,7 +83,7 @@ void TorControlSocket::clear()
currentCommand = 0;
}
void TorControlSocket::setError(const QString &message)
void TorControlSocket::setError(const std::string &message)
{
m_errorMessage = message;
emit error(message);

View File

@ -30,29 +30,26 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORCONTROLSOCKET_H
#define TORCONTROLSOCKET_H
#pragma once
#include <QTcpSocket>
#include <QQueue>
#include "pqi/rstcpsocket.h"
namespace Tor
{
class TorControlCommand;
class TorControlSocket : public QTcpSocket
class TorControlSocket : public RsTcpSocket
{
Q_OBJECT
public:
explicit TorControlSocket(QObject *parent = 0);
explicit TorControlSocket();
virtual ~TorControlSocket();
QString errorMessage() const { return m_errorMessage; }
std::string errorMessage() const { return m_errorMessage; }
void registerEvent(const QByteArray &event, TorControlCommand *handler);
void sendCommand(const QByteArray &data) { sendCommand(0, data); }
void sendCommand(const std::string& data) { sendCommand(0, data); }
void sendCommand(TorControlCommand *command, const QByteArray &data);
signals:
@ -63,13 +60,13 @@ private slots:
void clear();
private:
QQueue<TorControlCommand*> commandQueue;
std::list<TorControlCommand*> commandQueue;
QHash<QByteArray,TorControlCommand*> eventCommands;
QString m_errorMessage;
std::string m_errorMessage;
TorControlCommand *currentCommand;
bool inDataReply;
void setError(const QString &message);
void setError(const std::string& message);
};
}

View File

@ -1,155 +0,0 @@
/* Ricochet - https://ricochet.im/
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* * Neither the names of the copyright owners nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "TorSocket.h"
#include "TorControl.h"
#include <QNetworkProxy>
using namespace Tor;
TorSocket::TorSocket(QObject *parent)
: QTcpSocket(parent)
, m_port(0)
, m_reconnectEnabled(true)
, m_maxInterval(900)
, m_connectAttempts(0)
{
connect(torControl, SIGNAL(connectivityChanged()), SLOT(connectivityChanged()));
connect(&m_connectTimer, SIGNAL(timeout()), SLOT(reconnect()));
connect(this, SIGNAL(disconnected()), SLOT(onFailed()));
connect(this, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(onFailed()));
m_connectTimer.setSingleShot(true);
connectivityChanged();
}
TorSocket::~TorSocket()
{
}
void TorSocket::setReconnectEnabled(bool enabled)
{
if (enabled == m_reconnectEnabled)
return;
m_reconnectEnabled = enabled;
if (m_reconnectEnabled) {
m_connectAttempts = 0;
reconnect();
} else {
m_connectTimer.stop();
}
}
void TorSocket::setMaxAttemptInterval(int interval)
{
m_maxInterval = interval;
}
void TorSocket::resetAttempts()
{
m_connectAttempts = 0;
if (m_connectTimer.isActive()) {
m_connectTimer.stop();
m_connectTimer.start(reconnectInterval() * 1000);
}
}
int TorSocket::reconnectInterval()
{
int delay = 0;
if (m_connectAttempts <= 4)
delay = 30;
else if (m_connectAttempts <= 6)
delay = 120;
else
delay = m_maxInterval;
return qMin(delay, m_maxInterval);
}
void TorSocket::reconnect()
{
if (!torControl->hasConnectivity() || !reconnectEnabled())
return;
m_connectTimer.stop();
if (!m_host.isEmpty() && m_port) {
std::cerr << "Attempting reconnection of socket to" << m_host.toStdString() << ":" << m_port << std::endl;
connectToHost(m_host, m_port);
}
}
void TorSocket::connectivityChanged()
{
if (torControl->hasConnectivity()) {
setProxy(torControl->connectionProxy());
if (state() == QAbstractSocket::UnconnectedState)
reconnect();
} else {
m_connectTimer.stop();
m_connectAttempts = 0;
}
}
void TorSocket::connectToHost(const QString &hostName, quint16 port, OpenMode openMode,
NetworkLayerProtocol protocol)
{
m_host = hostName;
m_port = port;
if (!torControl->hasConnectivity())
return;
if (proxy() != torControl->connectionProxy())
setProxy(torControl->connectionProxy());
QAbstractSocket::connectToHost(hostName, port, openMode, protocol);
}
void TorSocket::connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode)
{
TorSocket::connectToHost(address.toString(), port, openMode);
}
void TorSocket::onFailed()
{
// Make sure the internal connection to the SOCKS proxy is closed
// Otherwise reconnect attempts will fail (#295)
close();
if (reconnectEnabled() && !m_connectTimer.isActive()) {
m_connectAttempts++;
m_connectTimer.start(reconnectInterval() * 1000);
std::cerr << "Reconnecting socket to" << m_host.toStdString() << ":" << m_port << "in" << m_connectTimer.interval() / 1000 << "seconds" << std::endl;
}
}

View File

@ -1,97 +0,0 @@
/* Ricochet - https://ricochet.im/
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* * Neither the names of the copyright owners nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORSOCKET_H
#define TORSOCKET_H
#include <QTcpSocket>
#include <QTimer>
namespace Tor {
/* Specialized QTcpSocket which makes connections over the SOCKS proxy
* from a TorControl instance, automatically attempts reconnections, and
* reacts to Tor's connectivity state.
*
* Use normal QTcpSocket/QAbstractSocket API. When a connection fails, it
* will be retried automatically after the correct interval and when
* connectivity is available.
*
* To fully disconnect, destroy the object, or call
* setReconnectEnabled(false) and disconnect the socket with
* disconnectFromHost or abort.
*
* The caller is responsible for resetting the attempt counter if a
* connection was successful and reconnection will be used again.
*/
class TorSocket : public QTcpSocket
{
Q_OBJECT
public:
explicit TorSocket(QObject *parent = 0);
virtual ~TorSocket();
bool reconnectEnabled() const { return m_reconnectEnabled; }
void setReconnectEnabled(bool enabled);
int maxAttemptInterval() { return m_maxInterval; }
void setMaxAttemptInterval(int interval);
void resetAttempts();
virtual void connectToHost(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
virtual void connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode = ReadWrite);
QString hostName() const { return m_host; }
quint16 port() const { return m_port; }
protected:
virtual int reconnectInterval();
private slots:
void reconnect();
void connectivityChanged();
void onFailed();
private:
QString m_host;
quint16 m_port;
QTimer m_connectTimer;
bool m_reconnectEnabled;
int m_maxInterval;
int m_connectAttempts;
using QAbstractSocket::connectToHost;
};
}
#endif

View File

@ -0,0 +1,91 @@
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include "util/rsprint.h"
#include "util/rsdebug.h"
class ByteArray: public std::vector<unsigned char>
{
public:
ByteArray() =default;
ByteArray(int n) : std::vector<unsigned char>(n) {}
ByteArray(const unsigned char *d,int n) : std::vector<unsigned char>(n) { memcpy(data(),d,n); }
virtual ~ByteArray() =default;
ByteArray(const std::string& c) { resize(c.size()); memcpy(data(),c.c_str(),c.size()); }
const ByteArray& operator=(const std::string& c) { resize(c.size()); memcpy(data(),c.c_str(),c.size()); return *this; }
bool isNull() const { return empty(); }
ByteArray toHex() const { return ByteArray(RsUtil::BinToHex(data(),size(),0)); }
std::string toString() const { std::string res; for(auto c:*this) res += c; return res; }
ByteArray operator+(const ByteArray& b) const { auto res(*this); for(unsigned char c:b) res.push_back(c); return res; }
ByteArray operator+(const std::string& b) const { return operator+(ByteArray(b)); }
void append(const ByteArray& b) { for(auto c:b) push_back(c); }
void append(const char *b) { for(uint32_t n=0;b[n]!=0;++n) push_back(b[n]); }
ByteArray& operator+=(const ByteArray& b) { for(auto c:b) push_back(c); return *this; }
ByteArray& operator+=(const char *b) { for(uint32_t n=0;b[n]!=0;++n) push_back(b[n]); return *this;}
ByteArray left(uint32_t l) const { auto res = *this; res.resize(std::min((uint32_t)size(),l)); return res; }
ByteArray toUpper() const { auto res = *this; for(uint32_t i=0;i<size();++i) if( res[i]<='z' && res[i]>='a') res[i] += 'A'-'a'; return res; }
bool startsWith(const char *b) const
{
for(uint32_t n=0;b[n]!=0;++n)
if(n >= size() || b[n]!=(*this)[n])
return false;
return true;
}
bool operator==(const char *b) const
{
uint32_t n;
for(n=0;b[n]!=0;++n)
if(n >= size() || b[n]!=(*this)[n])
return false;
return n==size();
}
ByteArray mid(uint32_t n,int s=-1) const
{
ByteArray res((s>=0)?s:(size()-n));
memcpy(res.data(),&data()[n],res.size());
return res;
}
int indexOf(unsigned char c,int from=0) const
{
for(uint32_t i=from;i<size();++i)
if((*this)[i]==c)
return (int)i;
return -1;
}
ByteArray replace(const ByteArray& b1,const ByteArray& b2)
{
if(b1.empty())
{
RsErr() << "Attempting to replace an empty string!";
return *this;
}
ByteArray res ;
for(uint32_t i=0;i+b1.size()<=size();)
if(!memcmp(&(*this)[i],b1.data(),b1.size()))
{
res.append(b2);
i += b1.size();
}
else
res.push_back((*this)[i++]);
return res;
}
};