initial attempt at verifying the certificate of ssl trackers, by including the certificate in the .torrent file
This commit is contained in:
@@ -85,6 +85,8 @@ void print_usage()
|
|||||||
" If this is not specified, the torrent file is\n"
|
" If this is not specified, the torrent file is\n"
|
||||||
" printed to the standard out, except on windows\n"
|
" printed to the standard out, except on windows\n"
|
||||||
" where the filename defaults to a.torrent\n"
|
" where the filename defaults to a.torrent\n"
|
||||||
|
"-c add root certificate to the torrent, to make\n"
|
||||||
|
" it an SSL torrent\n"
|
||||||
, stderr);
|
, stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +111,7 @@ int main(int argc, char* argv[])
|
|||||||
int pad_file_limit = -1;
|
int pad_file_limit = -1;
|
||||||
int piece_size = 0;
|
int piece_size = 0;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
std::string root_cert;
|
||||||
|
|
||||||
std::string outfile;
|
std::string outfile;
|
||||||
std::string merklefile;
|
std::string merklefile;
|
||||||
@@ -160,6 +163,10 @@ int main(int argc, char* argv[])
|
|||||||
case 'l':
|
case 'l':
|
||||||
flags |= create_torrent::symlinks;
|
flags |= create_torrent::symlinks;
|
||||||
break;
|
break;
|
||||||
|
case 'c':
|
||||||
|
++i;
|
||||||
|
root_cert = argv[i];
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
print_usage();
|
print_usage();
|
||||||
return 1;
|
return 1;
|
||||||
@@ -198,6 +205,20 @@ int main(int argc, char* argv[])
|
|||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
t.set_creator(creator_str);
|
t.set_creator(creator_str);
|
||||||
|
|
||||||
|
if (!root_cert.empty())
|
||||||
|
{
|
||||||
|
FILE* cert = fopen(root_cert.c_str(), "rb");
|
||||||
|
if (cert)
|
||||||
|
{
|
||||||
|
std::string pem;
|
||||||
|
pem.resize(5000);
|
||||||
|
int s = fread(&pem[0], 1, pem.size(), cert);
|
||||||
|
pem.resize(s);
|
||||||
|
t.set_root_cert(pem);
|
||||||
|
fclose(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// create the torrent and print it to stdout
|
// create the torrent and print it to stdout
|
||||||
std::vector<char> torrent;
|
std::vector<char> torrent;
|
||||||
bencode(back_inserter(torrent), t.generate());
|
bencode(back_inserter(torrent), t.generate());
|
||||||
|
@@ -89,6 +89,7 @@ namespace libtorrent
|
|||||||
void add_http_seed(std::string const& url);
|
void add_http_seed(std::string const& url);
|
||||||
void add_node(std::pair<std::string, int> const& node);
|
void add_node(std::pair<std::string, int> const& node);
|
||||||
void add_tracker(std::string const& url, int tier = 0);
|
void add_tracker(std::string const& url, int tier = 0);
|
||||||
|
void set_root_cert(std::string const& pem);
|
||||||
void set_priv(bool p) { m_private = p; }
|
void set_priv(bool p) { m_private = p; }
|
||||||
|
|
||||||
int num_pieces() const { return m_files.num_pieces(); }
|
int num_pieces() const { return m_files.num_pieces(); }
|
||||||
@@ -145,6 +146,9 @@ namespace libtorrent
|
|||||||
// to create the torrent file
|
// to create the torrent file
|
||||||
std::string m_created_by;
|
std::string m_created_by;
|
||||||
|
|
||||||
|
// this is the root cert for SSL torrents
|
||||||
|
std::string m_root_cert;
|
||||||
|
|
||||||
// this is used when creating a torrent. If there's
|
// this is used when creating a torrent. If there's
|
||||||
// only one file there are cases where it's impossible
|
// only one file there are cases where it's impossible
|
||||||
// to know if it should be written as a multifile torrent
|
// to know if it should be written as a multifile torrent
|
||||||
|
@@ -78,40 +78,13 @@ struct TORRENT_EXPORT http_connection : boost::enable_shared_from_this<http_conn
|
|||||||
http_connection(io_service& ios, connection_queue& cc
|
http_connection(io_service& ios, connection_queue& cc
|
||||||
, http_handler const& handler, bool bottled = true
|
, http_handler const& handler, bool bottled = true
|
||||||
, http_connect_handler const& ch = http_connect_handler()
|
, http_connect_handler const& ch = http_connect_handler()
|
||||||
, http_filter_handler const& fh = http_filter_handler())
|
, http_filter_handler const& fh = http_filter_handler()
|
||||||
: m_sock(ios)
|
|
||||||
#if TORRENT_USE_I2P
|
|
||||||
, m_i2p_conn(0)
|
|
||||||
#endif
|
|
||||||
, m_read_pos(0)
|
|
||||||
, m_resolver(ios)
|
|
||||||
, m_handler(handler)
|
|
||||||
, m_connect_handler(ch)
|
|
||||||
, m_filter_handler(fh)
|
|
||||||
, m_timer(ios)
|
|
||||||
, m_last_receive(time_now())
|
|
||||||
, m_bottled(bottled)
|
|
||||||
, m_called(false)
|
|
||||||
#ifdef TORRENT_USE_OPENSSL
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
, m_ssl_ctx(ios, asio::ssl::context::sslv23_client)
|
, boost::asio::ssl::context* ssl_ctx = 0
|
||||||
#endif
|
#endif
|
||||||
, m_rate_limit(0)
|
);
|
||||||
, m_download_quota(0)
|
|
||||||
, m_limiter_timer_active(false)
|
~http_connection();
|
||||||
, m_limiter_timer(ios)
|
|
||||||
, m_redirects(5)
|
|
||||||
, m_connection_ticket(-1)
|
|
||||||
, m_cc(cc)
|
|
||||||
, m_ssl(false)
|
|
||||||
, m_priority(0)
|
|
||||||
, m_abort(false)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(!m_handler.empty());
|
|
||||||
#ifdef TORRENT_USE_OPENSSL
|
|
||||||
error_code ec;
|
|
||||||
m_ssl_ctx.set_verify_mode(asio::ssl::context::verify_none, ec);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void rate_limit(int limit);
|
void rate_limit(int limit);
|
||||||
|
|
||||||
@@ -191,7 +164,8 @@ private:
|
|||||||
|
|
||||||
std::list<tcp::endpoint> m_endpoints;
|
std::list<tcp::endpoint> m_endpoints;
|
||||||
#ifdef TORRENT_USE_OPENSSL
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
asio::ssl::context m_ssl_ctx;
|
asio::ssl::context* m_ssl_ctx;
|
||||||
|
bool m_own_ssl_context;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// the current download limit, in bytes per second
|
// the current download limit, in bytes per second
|
||||||
|
@@ -921,6 +921,10 @@ namespace libtorrent
|
|||||||
// the object.
|
// the object.
|
||||||
piece_manager* m_storage;
|
piece_manager* m_storage;
|
||||||
|
|
||||||
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
boost::shared_ptr<asio::ssl::context> m_ssl_ctx;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
public:
|
public:
|
||||||
#endif
|
#endif
|
||||||
|
@@ -333,6 +333,8 @@ namespace libtorrent
|
|||||||
// ------- end deprecation -------
|
// ------- end deprecation -------
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
std::string const& ssl_cert() const { return m_ssl_root_cert; }
|
||||||
|
|
||||||
bool is_valid() const { return m_files.is_valid(); }
|
bool is_valid() const { return m_files.is_valid(); }
|
||||||
|
|
||||||
bool priv() const { return m_private; }
|
bool priv() const { return m_private; }
|
||||||
@@ -456,6 +458,11 @@ namespace libtorrent
|
|||||||
// to create the torrent file
|
// to create the torrent file
|
||||||
std::string m_created_by;
|
std::string m_created_by;
|
||||||
|
|
||||||
|
// for ssl-torrens, this contains the root
|
||||||
|
// certificate, in .pem format (i.e. ascii
|
||||||
|
// base64 encoded with head and tails)
|
||||||
|
std::string m_ssl_root_cert;
|
||||||
|
|
||||||
// the info section parsed. points into m_info_section
|
// the info section parsed. points into m_info_section
|
||||||
// parsed lazily
|
// parsed lazily
|
||||||
mutable lazy_entry m_info_dict;
|
mutable lazy_entry m_info_dict;
|
||||||
|
@@ -63,6 +63,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/intrusive_ptr_base.hpp"
|
#include "libtorrent/intrusive_ptr_base.hpp"
|
||||||
#include "libtorrent/size_type.hpp"
|
#include "libtorrent/size_type.hpp"
|
||||||
#include "libtorrent/union_endpoint.hpp"
|
#include "libtorrent/union_endpoint.hpp"
|
||||||
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
#include <boost/asio/ssl/context.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
@@ -90,6 +93,9 @@ namespace libtorrent
|
|||||||
, num_want(0)
|
, num_want(0)
|
||||||
, send_stats(true)
|
, send_stats(true)
|
||||||
, apply_ip_filter(true)
|
, apply_ip_filter(true)
|
||||||
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
, ssl_ctx(0)
|
||||||
|
#endif
|
||||||
{}
|
{}
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@@ -125,6 +131,9 @@ namespace libtorrent
|
|||||||
address bind_ip;
|
address bind_ip;
|
||||||
bool send_stats;
|
bool send_stats;
|
||||||
bool apply_ip_filter;
|
bool apply_ip_filter;
|
||||||
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
boost::asio::ssl::context* ssl_ctx;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT request_callback
|
struct TORRENT_EXPORT request_callback
|
||||||
|
@@ -298,6 +298,9 @@ namespace libtorrent
|
|||||||
|
|
||||||
info["name"] = m_files.name();
|
info["name"] = m_files.name();
|
||||||
|
|
||||||
|
if (!m_root_cert.empty())
|
||||||
|
info["ssl-cert"] = m_root_cert;
|
||||||
|
|
||||||
if (m_private) info["private"] = 1;
|
if (m_private) info["private"] = 1;
|
||||||
|
|
||||||
if (!m_multifile)
|
if (!m_multifile)
|
||||||
@@ -446,6 +449,11 @@ namespace libtorrent
|
|||||||
, boost::bind(&announce_entry::second, _1) < boost::bind(&announce_entry::second, _2));
|
, boost::bind(&announce_entry::second, _1) < boost::bind(&announce_entry::second, _2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void create_torrent::set_root_cert(std::string const& cert)
|
||||||
|
{
|
||||||
|
m_root_cert = cert;
|
||||||
|
}
|
||||||
|
|
||||||
void create_torrent::set_hash(int index, sha1_hash const& h)
|
void create_torrent::set_hash(int index, sha1_hash const& h)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(index >= 0);
|
TORRENT_ASSERT(index >= 0);
|
||||||
|
@@ -50,6 +50,52 @@ namespace libtorrent {
|
|||||||
|
|
||||||
enum { max_bottled_buffer = 1024 * 1024 };
|
enum { max_bottled_buffer = 1024 * 1024 };
|
||||||
|
|
||||||
|
http_connection::http_connection(io_service& ios, connection_queue& cc
|
||||||
|
, http_handler const& handler, bool bottled
|
||||||
|
, http_connect_handler const& ch
|
||||||
|
, http_filter_handler const& fh
|
||||||
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
, boost::asio::ssl::context* ssl_ctx
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
: m_sock(ios)
|
||||||
|
#if TORRENT_USE_I2P
|
||||||
|
, m_i2p_conn(0)
|
||||||
|
#endif
|
||||||
|
, m_read_pos(0)
|
||||||
|
, m_resolver(ios)
|
||||||
|
, m_handler(handler)
|
||||||
|
, m_connect_handler(ch)
|
||||||
|
, m_filter_handler(fh)
|
||||||
|
, m_timer(ios)
|
||||||
|
, m_last_receive(time_now())
|
||||||
|
, m_bottled(bottled)
|
||||||
|
, m_called(false)
|
||||||
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
, m_ssl_ctx(ssl_ctx)
|
||||||
|
, m_own_ssl_context(false)
|
||||||
|
#endif
|
||||||
|
, m_rate_limit(0)
|
||||||
|
, m_download_quota(0)
|
||||||
|
, m_limiter_timer_active(false)
|
||||||
|
, m_limiter_timer(ios)
|
||||||
|
, m_redirects(5)
|
||||||
|
, m_connection_ticket(-1)
|
||||||
|
, m_cc(cc)
|
||||||
|
, m_ssl(false)
|
||||||
|
, m_priority(0)
|
||||||
|
, m_abort(false)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(!m_handler.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
http_connection::~http_connection()
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
if (m_own_ssl_context) delete m_ssl_ctx;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void http_connection::get(std::string const& url, time_duration timeout, int prio
|
void http_connection::get(std::string const& url, time_duration timeout, int prio
|
||||||
, proxy_settings const* ps, int handle_redirects, std::string const& user_agent
|
, proxy_settings const* ps, int handle_redirects, std::string const& user_agent
|
||||||
, address const& bind_addr
|
, address const& bind_addr
|
||||||
@@ -250,7 +296,20 @@ void http_connection::start(std::string const& hostname, std::string const& port
|
|||||||
|
|
||||||
void* userdata = 0;
|
void* userdata = 0;
|
||||||
#ifdef TORRENT_USE_OPENSSL
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
if (m_ssl) userdata = &m_ssl_ctx;
|
if (m_ssl)
|
||||||
|
{
|
||||||
|
if (m_ssl_ctx == 0)
|
||||||
|
{
|
||||||
|
m_ssl_ctx = new boost::asio::ssl::context(m_resolver.get_io_service(), asio::ssl::context::sslv23_client);
|
||||||
|
if (m_ssl_ctx)
|
||||||
|
{
|
||||||
|
m_own_ssl_context = true;
|
||||||
|
error_code ec;
|
||||||
|
m_ssl_ctx->set_verify_mode(asio::ssl::context::verify_none, ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userdata = m_ssl_ctx;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
instantiate_connection(m_resolver.get_io_service()
|
instantiate_connection(m_resolver.get_io_service()
|
||||||
, proxy ? *proxy : null_proxy, m_sock, userdata);
|
, proxy ? *proxy : null_proxy, m_sock, userdata);
|
||||||
|
@@ -216,7 +216,11 @@ namespace libtorrent
|
|||||||
, boost::bind(&http_tracker_connection::on_response, self(), _1, _2, _3, _4)
|
, boost::bind(&http_tracker_connection::on_response, self(), _1, _2, _3, _4)
|
||||||
, true
|
, true
|
||||||
, boost::bind(&http_tracker_connection::on_connect, self(), _1)
|
, boost::bind(&http_tracker_connection::on_connect, self(), _1)
|
||||||
, boost::bind(&http_tracker_connection::on_filter, self(), _1, _2)));
|
, boost::bind(&http_tracker_connection::on_filter, self(), _1, _2)
|
||||||
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
, tracker_req().ssl_ctx
|
||||||
|
#endif
|
||||||
|
));
|
||||||
|
|
||||||
int timeout = tracker_req().event==tracker_request::stopped
|
int timeout = tracker_req().event==tracker_request::stopped
|
||||||
?settings.stop_tracker_timeout
|
?settings.stop_tracker_timeout
|
||||||
|
108
src/torrent.cpp
108
src/torrent.cpp
@@ -84,6 +84,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
#ifdef TORRENT_USE_OPENSSL
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
#include "libtorrent/ssl_stream.hpp"
|
#include "libtorrent/ssl_stream.hpp"
|
||||||
|
#include <boost/asio/ssl/context.hpp>
|
||||||
|
#include <boost/asio/ssl/verify_context.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TORRENT_USE_IOSTREAM
|
#if TORRENT_USE_IOSTREAM
|
||||||
@@ -1261,6 +1263,15 @@ namespace libtorrent
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
bool verify_function(bool preverified, boost::asio::ssl::verify_context& ctx)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
// this may not be called from a constructor because of the call to
|
// this may not be called from a constructor because of the call to
|
||||||
// shared_from_this()
|
// shared_from_this()
|
||||||
void torrent::init()
|
void torrent::init()
|
||||||
@@ -1270,6 +1281,98 @@ namespace libtorrent
|
|||||||
TORRENT_ASSERT(m_torrent_file->num_files() > 0);
|
TORRENT_ASSERT(m_torrent_file->num_files() > 0);
|
||||||
TORRENT_ASSERT(m_torrent_file->total_size() >= 0);
|
TORRENT_ASSERT(m_torrent_file->total_size() >= 0);
|
||||||
|
|
||||||
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
std::string cert = m_torrent_file->ssl_cert();
|
||||||
|
if (!cert.empty())
|
||||||
|
{
|
||||||
|
using boost::asio::ssl::context;
|
||||||
|
|
||||||
|
// create the SSL context for this torrent. We need to
|
||||||
|
// inject the root certificate, and no other, to
|
||||||
|
// verify other peers against
|
||||||
|
boost::shared_ptr<context> ctx(
|
||||||
|
new (std::nothrow) context(m_ses.m_io_service, context::tlsv1));
|
||||||
|
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
set_error(asio::error::no_memory, "SSL context");
|
||||||
|
pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
ctx->set_verify_mode(context::verify_peer
|
||||||
|
| context::verify_fail_if_no_peer_cert, ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
set_error(ec, "SSL context");
|
||||||
|
pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is used for debugging
|
||||||
|
/*
|
||||||
|
ctx->set_verify_callback(verify_function, ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
set_error(ec, "SSL verify callback");
|
||||||
|
pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
SSL_CTX* ssl_ctx = ctx->impl();
|
||||||
|
|
||||||
|
// we don't want regular peers to be able to invite others
|
||||||
|
// by in turn signing new certificates. So, break the verification
|
||||||
|
// chain at depth 2. This is just a precaution in case the
|
||||||
|
// issuer of the peer certificates made a mistake and issued them
|
||||||
|
// as CA certs.
|
||||||
|
SSL_CTX_set_verify_depth(ssl_ctx, 0);
|
||||||
|
|
||||||
|
// create a new x.509 certificate store
|
||||||
|
X509_STORE* cert_store = X509_STORE_new();
|
||||||
|
if (!cert_store)
|
||||||
|
{
|
||||||
|
set_error(asio::error::no_memory, "x.509 certificate store");
|
||||||
|
pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap the PEM certificate in a BIO, for openssl to read
|
||||||
|
BIO* bp = BIO_new_mem_buf((void*)cert.c_str(), cert.size());
|
||||||
|
|
||||||
|
// parse the certificate into OpenSSL's internal
|
||||||
|
// representation
|
||||||
|
X509* certificate = PEM_read_bio_X509_AUX(bp, 0, 0, 0);
|
||||||
|
|
||||||
|
BIO_free(bp);
|
||||||
|
|
||||||
|
if (!certificate)
|
||||||
|
{
|
||||||
|
X509_STORE_free(cert_store);
|
||||||
|
set_error(asio::error::no_memory, "x.509 certificate");
|
||||||
|
pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add cert to cert_store
|
||||||
|
X509_STORE_add_cert(cert_store, certificate);
|
||||||
|
|
||||||
|
// and lastly, replace the default cert store with ours
|
||||||
|
SSL_CTX_set_cert_store(ssl_ctx, cert_store);
|
||||||
|
#if 0
|
||||||
|
char filename[100];
|
||||||
|
snprintf(filename, sizeof(filename), "/tmp/%d.pem", rand());
|
||||||
|
FILE* f = fopen(filename, "w+");
|
||||||
|
fwrite(cert.c_str(), cert.size(), 1, f);
|
||||||
|
fclose(f);
|
||||||
|
ctx->load_verify_file(filename);
|
||||||
|
#endif
|
||||||
|
// if all went well, set the torrent ssl context to this one
|
||||||
|
m_ssl_ctx = ctx;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
m_file_priority.resize(m_torrent_file->num_files(), 1);
|
m_file_priority.resize(m_torrent_file->num_files(), 1);
|
||||||
m_file_progress.resize(m_torrent_file->num_files(), 0);
|
m_file_progress.resize(m_torrent_file->num_files(), 0);
|
||||||
|
|
||||||
@@ -1941,6 +2044,11 @@ namespace libtorrent
|
|||||||
req.corrupt = m_total_failed_bytes;
|
req.corrupt = m_total_failed_bytes;
|
||||||
req.left = bytes_left();
|
req.left = bytes_left();
|
||||||
if (req.left == -1) req.left = 16*1024;
|
if (req.left == -1) req.left = 16*1024;
|
||||||
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
// if this torrent contains an SSL certificate, make sure
|
||||||
|
// any SSL tracker presents a certificate signed by it
|
||||||
|
req.ssl_ctx = m_ssl_ctx.get();
|
||||||
|
#endif
|
||||||
|
|
||||||
// exclude redundant bytes if we should
|
// exclude redundant bytes if we should
|
||||||
if (!settings().report_true_downloaded)
|
if (!settings().report_true_downloaded)
|
||||||
|
@@ -932,6 +932,9 @@ namespace libtorrent
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_private = info.dict_find_int_value("private", 0);
|
m_private = info.dict_find_int_value("private", 0);
|
||||||
|
|
||||||
|
m_ssl_root_cert = info.dict_find_string_value("ssl-cert");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user