basic support for bittorrent connections over SSL

This commit is contained in:
Arvid Norberg 2011-09-10 05:52:07 +00:00
parent 38a4b58c3a
commit 675721d971
13 changed files with 177 additions and 23 deletions

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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
};

View File

@ -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:

View File

@ -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);

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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;