basic support for bittorrent connections over SSL
This commit is contained in:
parent
38a4b58c3a
commit
675721d971
|
@ -40,7 +40,11 @@ namespace libtorrent
|
|||
{
|
||||
struct proxy_settings;
|
||||
struct utp_socket_manager;
|
||||
struct socket_type;
|
||||
|
||||
// if from is specified, a new socket will be created
|
||||
// using the same underlying socket object as 'from'.
|
||||
// this can be used to "upgrade" a socket into an SSL socket
|
||||
TORRENT_EXPORT bool instantiate_connection(io_service& ios
|
||||
, proxy_settings const& ps, socket_type& s
|
||||
, void* ssl_context = 0
|
||||
|
|
|
@ -105,6 +105,18 @@ namespace libtorrent
|
|||
value = max3<temp1, temp2, temp3>::value
|
||||
};
|
||||
};
|
||||
|
||||
template<int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9>
|
||||
struct max9
|
||||
{
|
||||
enum
|
||||
{
|
||||
temp1 = max3<v1,v2, v3>::value,
|
||||
temp2 = max3<v4,v5,v6>::value,
|
||||
temp3 = max3<v7,v8,v9>::value,
|
||||
value = max3<temp1, temp2, temp3>::value
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -46,6 +46,7 @@ class proxy_base : boost::noncopyable
|
|||
{
|
||||
public:
|
||||
|
||||
typedef stream_socket next_layer_type;
|
||||
typedef stream_socket::lowest_layer_type lowest_layer_type;
|
||||
typedef stream_socket::endpoint_type endpoint_type;
|
||||
typedef stream_socket::protocol_type protocol_type;
|
||||
|
@ -217,6 +218,11 @@ public:
|
|||
return m_sock.lowest_layer();
|
||||
}
|
||||
|
||||
next_layer_type& next_layer()
|
||||
{
|
||||
return m_sock;
|
||||
}
|
||||
|
||||
bool is_open() const { return m_sock.is_open(); }
|
||||
|
||||
protected:
|
||||
|
|
|
@ -72,7 +72,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
case socket_type_int_impl<ssl_stream<socks5_stream> >::value: \
|
||||
get<ssl_stream<socks5_stream> >()->x; break; \
|
||||
case socket_type_int_impl<ssl_stream<http_stream> >::value: \
|
||||
get<ssl_stream<http_stream> >()->x; break;
|
||||
get<ssl_stream<http_stream> >()->x; break; \
|
||||
case socket_type_int_impl<ssl_stream<utp_stream> >::value: \
|
||||
get<ssl_stream<utp_stream> >()->x; break;
|
||||
|
||||
#define TORRENT_SOCKTYPE_SSL_FORWARD_RET(x, def) \
|
||||
case socket_type_int_impl<ssl_stream<stream_socket> >::value: \
|
||||
|
@ -80,7 +82,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
case socket_type_int_impl<ssl_stream<socks5_stream> >::value: \
|
||||
return get<ssl_stream<socks5_stream> >()->x; \
|
||||
case socket_type_int_impl<ssl_stream<http_stream> >::value: \
|
||||
return get<ssl_stream<http_stream> >()->x;
|
||||
return get<ssl_stream<http_stream> >()->x; \
|
||||
case socket_type_int_impl<ssl_stream<utp_stream> >::value: \
|
||||
return get<ssl_stream<utp_stream> >()->x;
|
||||
|
||||
#else
|
||||
|
||||
|
@ -160,6 +164,10 @@ namespace libtorrent
|
|||
template <>
|
||||
struct socket_type_int_impl<ssl_stream<http_stream> >
|
||||
{ enum { value = 8 }; };
|
||||
|
||||
template <>
|
||||
struct socket_type_int_impl<ssl_stream<utp_stream> >
|
||||
{ enum { value = 9 }; };
|
||||
#endif
|
||||
|
||||
struct TORRENT_EXPORT socket_type
|
||||
|
@ -260,7 +268,7 @@ namespace libtorrent
|
|||
|
||||
io_service& m_io_service;
|
||||
int m_type;
|
||||
enum { storage_size = max8<
|
||||
enum { storage_size = max9<
|
||||
sizeof(stream_socket)
|
||||
, sizeof(socks5_stream)
|
||||
, sizeof(http_stream)
|
||||
|
@ -274,8 +282,9 @@ namespace libtorrent
|
|||
, sizeof(ssl_stream<stream_socket>)
|
||||
, sizeof(ssl_stream<socks5_stream>)
|
||||
, sizeof(ssl_stream<http_stream>)
|
||||
, sizeof(ssl_stream<utp_stream>)
|
||||
#else
|
||||
, 0, 0, 0
|
||||
, 0, 0, 0, 0
|
||||
#endif
|
||||
>::value
|
||||
};
|
||||
|
|
|
@ -56,11 +56,11 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
typedef asio::ssl::stream<Stream> next_layer_type;
|
||||
typedef typename asio::ssl::stream<Stream> sock_type;
|
||||
typedef typename sock_type::next_layer_type next_layer_type;
|
||||
typedef typename Stream::lowest_layer_type lowest_layer_type;
|
||||
typedef typename Stream::endpoint_type endpoint_type;
|
||||
typedef typename Stream::protocol_type protocol_type;
|
||||
typedef typename asio::ssl::stream<Stream> sock_type;
|
||||
|
||||
typedef boost::function<void(error_code const&)> handler_type;
|
||||
|
||||
|
@ -79,6 +79,33 @@ public:
|
|||
, boost::bind(&ssl_stream::connected, this, _1, h));
|
||||
}
|
||||
|
||||
template <class Handler>
|
||||
void async_accept_handshake(Handler const& handler)
|
||||
{
|
||||
// this is used for accepting SSL connections
|
||||
boost::shared_ptr<handler_type> h(new handler_type(handler));
|
||||
m_sock.async_handshake(asio::ssl::stream_base::server
|
||||
, boost::bind(&ssl_stream::handshake, this, _1, h));
|
||||
}
|
||||
|
||||
void accept_handshake(error_code& ec)
|
||||
{
|
||||
// this is used for accepting SSL connections
|
||||
m_sock.handshake(asio::ssl::stream_base::server, ec);
|
||||
}
|
||||
|
||||
template <class Handler>
|
||||
void async_shutdown(Handler const& handler)
|
||||
{
|
||||
boost::shared_ptr<handler_type> h(new handler_type(handler));
|
||||
m_sock.async_shutdown( boost::bind(&ssl_stream::on_shutdown, this, _1, h));
|
||||
}
|
||||
|
||||
void shutdown(error_code& ec)
|
||||
{
|
||||
m_sock.shutdown(ec);
|
||||
}
|
||||
|
||||
template <class Mutable_Buffers, class Handler>
|
||||
void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
|
||||
{
|
||||
|
@ -222,7 +249,7 @@ public:
|
|||
|
||||
next_layer_type& next_layer()
|
||||
{
|
||||
return m_sock;
|
||||
return m_sock.next_layer();
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -838,6 +838,12 @@ namespace libtorrent
|
|||
void queue_torrent_check();
|
||||
void dequeue_torrent_check();
|
||||
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
void set_ssl_cert(std::string const& certificate, error_code& ec);
|
||||
bool is_ssl_torrent() const { return m_ssl_ctx; }
|
||||
boost::asio::ssl::context* ssl_ctx() const { return m_ssl_ctx.get(); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
void on_files_deleted(int ret, disk_io_job const& j);
|
||||
|
|
|
@ -252,6 +252,9 @@ namespace libtorrent
|
|||
bool resolve_countries() const;
|
||||
#endif
|
||||
|
||||
void set_ssl_certificates(std::string const& certificate
|
||||
, error_code& ec);
|
||||
|
||||
storage_interface* get_storage_impl() const;
|
||||
|
||||
// all these are deprecated, use piece
|
||||
|
|
|
@ -166,12 +166,15 @@ class TORRENT_EXPORT utp_stream
|
|||
{
|
||||
public:
|
||||
|
||||
typedef utp_stream lowest_layer_type;
|
||||
typedef stream_socket::endpoint_type endpoint_type;
|
||||
typedef stream_socket::protocol_type protocol_type;
|
||||
|
||||
explicit utp_stream(asio::io_service& io_service);
|
||||
~utp_stream();
|
||||
|
||||
lowest_layer_type& lowest_layer() { return *this; }
|
||||
|
||||
// used for incoming connections
|
||||
void set_impl(utp_socket_impl* s);
|
||||
utp_socket_impl* get_impl();
|
||||
|
@ -239,8 +242,7 @@ public:
|
|||
std::size_t available() const;
|
||||
std::size_t available(error_code& ec) const { return available(); }
|
||||
|
||||
asio::io_service& io_service()
|
||||
{ return m_io_service; }
|
||||
asio::io_service& get_io_service() { return m_io_service; }
|
||||
|
||||
template <class Handler>
|
||||
void async_connect(endpoint_type const& endpoint, Handler const& handler)
|
||||
|
@ -338,10 +340,33 @@ public:
|
|||
template <class Const_Buffers>
|
||||
std::size_t write_some(Const_Buffers const& buffers, error_code& ec)
|
||||
{
|
||||
TORRENT_ASSERT(false && "not implemented!");
|
||||
// TODO: implement
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
template <class Mutable_Buffers>
|
||||
std::size_t read_some(Mutable_Buffers const& buffers)
|
||||
{
|
||||
error_code ec;
|
||||
std::size_t ret = read_some(buffers, ec);
|
||||
if (ec)
|
||||
boost::throw_exception(boost::system::system_error(ec));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class Const_Buffers>
|
||||
std::size_t write_some(Const_Buffers const& buffers)
|
||||
{
|
||||
error_code ec;
|
||||
std::size_t ret = write_some(buffers, ec);
|
||||
if (ec)
|
||||
boost::throw_exception(boost::system::system_error(ec));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Const_Buffers, class Handler>
|
||||
void async_write_some(Const_Buffers const& buffers, Handler const& handler)
|
||||
{
|
||||
|
|
|
@ -300,12 +300,14 @@ void http_connection::start(std::string const& hostname, std::string const& port
|
|||
{
|
||||
if (m_ssl_ctx == 0)
|
||||
{
|
||||
m_ssl_ctx = new boost::asio::ssl::context(m_resolver.get_io_service(), asio::ssl::context::sslv23_client);
|
||||
m_ssl_ctx = new (std::nothrow) 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);
|
||||
TORRENT_ASSERT(!ec);
|
||||
}
|
||||
}
|
||||
userdata = m_ssl_ctx;
|
||||
|
@ -536,7 +538,7 @@ void http_connection::connect(int ticket, tcp::endpoint target_address)
|
|||
if (m_ssl)
|
||||
{
|
||||
TORRENT_ASSERT(m_sock.get<ssl_stream<socks5_stream> >());
|
||||
m_sock.get<ssl_stream<socks5_stream> >()->next_layer().next_layer().set_dst_name(m_hostname);
|
||||
m_sock.get<ssl_stream<socks5_stream> >()->next_layer().set_dst_name(m_hostname);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
|
|
@ -41,7 +41,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
TORRENT_EXPORT bool instantiate_connection(io_service& ios
|
||||
, proxy_settings const& ps, socket_type& s
|
||||
, void* ssl_context
|
||||
|
@ -50,12 +49,26 @@ namespace libtorrent
|
|||
{
|
||||
if (sm)
|
||||
{
|
||||
s.instantiate<utp_stream>(ios);
|
||||
s.get<utp_stream>()->set_impl(sm->new_utp_socket(s.get<utp_stream>()));
|
||||
utp_stream* str;
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
if (ssl_context)
|
||||
{
|
||||
s.instantiate<ssl_stream<utp_stream> >(ios, ssl_context);
|
||||
str = &s.get<ssl_stream<utp_stream> >()->next_layer();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
s.instantiate<utp_stream>(ios);
|
||||
str = s.get<utp_stream>();
|
||||
}
|
||||
str->set_impl(sm->new_utp_socket(str));
|
||||
}
|
||||
#if TORRENT_USE_I2P
|
||||
else if (ps.type == proxy_settings::i2p_proxy)
|
||||
{
|
||||
// it doesn't make any sense to try ssl over i2p
|
||||
TORRENT_ASSERT(ssl_context == 0);
|
||||
s.instantiate<i2p_stream>(ios);
|
||||
s.get<i2p_stream>()->set_proxy(ps.hostname, ps.port);
|
||||
}
|
||||
|
@ -63,12 +76,19 @@ namespace libtorrent
|
|||
else if (ps.type == proxy_settings::none
|
||||
|| (peer_connection && !ps.proxy_peer_connections))
|
||||
{
|
||||
stream_socket* str;
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
if (ssl_context)
|
||||
{
|
||||
s.instantiate<ssl_stream<stream_socket> >(ios, ssl_context);
|
||||
str = &s.get<ssl_stream<stream_socket> >()->next_layer();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
s.instantiate<stream_socket>(ios);
|
||||
str = s.get<stream_socket>();
|
||||
}
|
||||
}
|
||||
else if (ps.type == proxy_settings::http
|
||||
|| ps.type == proxy_settings::http_pw)
|
||||
|
@ -78,7 +98,7 @@ namespace libtorrent
|
|||
if (ssl_context)
|
||||
{
|
||||
s.instantiate<ssl_stream<http_stream> >(ios, ssl_context);
|
||||
str = &s.get<ssl_stream<http_stream> >()->next_layer().next_layer();
|
||||
str = &s.get<ssl_stream<http_stream> >()->next_layer();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -100,7 +120,7 @@ namespace libtorrent
|
|||
if (ssl_context)
|
||||
{
|
||||
s.instantiate<ssl_stream<socks5_stream> >(ios, ssl_context);
|
||||
str = &s.get<ssl_stream<socks5_stream> >()->next_layer().next_layer();
|
||||
str = &s.get<ssl_stream<socks5_stream> >()->next_layer();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
|
|
@ -71,6 +71,9 @@ namespace libtorrent
|
|||
case socket_type_int_impl<ssl_stream<http_stream> >::value:
|
||||
get<ssl_stream<http_stream> >()->~ssl_stream();
|
||||
break;
|
||||
case socket_type_int_impl<ssl_stream<utp_stream> >::value:
|
||||
get<ssl_stream<utp_stream> >()->~ssl_stream();
|
||||
break;
|
||||
#endif
|
||||
default: TORRENT_ASSERT(false);
|
||||
}
|
||||
|
@ -116,6 +119,11 @@ namespace libtorrent
|
|||
new ((ssl_stream<http_stream>*)m_data) ssl_stream<http_stream>(m_io_service
|
||||
, *((boost::asio::ssl::context*)userdata));
|
||||
break;
|
||||
case socket_type_int_impl<ssl_stream<utp_stream> >::value:
|
||||
TORRENT_ASSERT(userdata);
|
||||
new ((ssl_stream<utp_stream>*)m_data) ssl_stream<utp_stream>(m_io_service
|
||||
, *((boost::asio::ssl::context*)userdata));
|
||||
break;
|
||||
#endif
|
||||
default: TORRENT_ASSERT(false);
|
||||
}
|
||||
|
|
|
@ -1292,7 +1292,7 @@ namespace libtorrent
|
|||
// 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));
|
||||
new (std::nothrow) context(m_ses.m_io_service, context::sslv23));
|
||||
|
||||
if (!ctx)
|
||||
{
|
||||
|
@ -3972,6 +3972,26 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
// certificate is a filename to a .pem file which is our
|
||||
// certificate. root_cert is a filename to a certificate
|
||||
// on disk which is the trusted certificate authority (CA)
|
||||
// for this torrent. 'certificate' must be signed by the
|
||||
// 'root_cert', and any peer we connect to or that connect
|
||||
// to use must present a valid certificate signed by 'root_cert'
|
||||
void torrent::set_ssl_cert(std::string const& certificate, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
if (!m_ssl_ctx)
|
||||
{
|
||||
ec = asio::error::operation_not_supported;
|
||||
return;
|
||||
}
|
||||
using boost::asio::ssl::context;
|
||||
m_ssl_ctx->use_certificate_file(certificate, context::pem, ec);
|
||||
}
|
||||
#endif
|
||||
|
||||
void torrent::remove_peer(peer_connection* p)
|
||||
{
|
||||
// INVARIANT_CHECK;
|
||||
|
@ -4313,7 +4333,11 @@ namespace libtorrent
|
|||
bool ssl = string_begins_no_case("https://", web->url.c_str());
|
||||
void* userdata = 0;
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
if (ssl) userdata = &m_ses.m_ssl_ctx;
|
||||
if (ssl)
|
||||
{
|
||||
userdata = m_ssl_ctx.get();
|
||||
if (!userdata) userdata = &m_ses.m_ssl_ctx;
|
||||
}
|
||||
#endif
|
||||
bool ret = instantiate_connection(m_ses.m_io_service, m_ses.proxy(), *s, userdata, 0, true);
|
||||
(void)ret;
|
||||
|
@ -4335,13 +4359,11 @@ namespace libtorrent
|
|||
{
|
||||
// we're using a socks proxy and we're resolving
|
||||
// hostnames through it
|
||||
socks5_stream* str =
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
socks5_stream* str = ssl
|
||||
? &s->get<ssl_stream<socks5_stream> >()->next_layer().next_layer()
|
||||
: s->get<socks5_stream>();
|
||||
#else
|
||||
socks5_stream* str = s->get<socks5_stream>();
|
||||
ssl ? &s->get<ssl_stream<socks5_stream> >()->next_layer() :
|
||||
#endif
|
||||
s->get<socks5_stream>();
|
||||
TORRENT_ASSERT(str);
|
||||
|
||||
using boost::tuples::ignore;
|
||||
|
|
|
@ -375,6 +375,16 @@ namespace libtorrent
|
|||
TORRENT_ASYNC_CALL(flush_cache);
|
||||
}
|
||||
|
||||
void torrent_handle::set_ssl_certificates(
|
||||
std::string const& certificate, error_code& ec)
|
||||
{
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
TORRENT_ASYNC_CALL2(set_ssl_cert, certificate, boost::ref(ec));
|
||||
#else
|
||||
ec = boost::asio::error::operation_not_supported;
|
||||
#endif
|
||||
}
|
||||
|
||||
void torrent_handle::save_resume_data(int f) const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
|
Loading…
Reference in New Issue