merged SSL fix from RC_0_16

This commit is contained in:
Arvid Norberg 2012-04-05 04:17:19 +00:00
parent 05aeda31c6
commit 6acde24799
8 changed files with 102 additions and 85 deletions

View File

@ -422,11 +422,11 @@ inline int snprintf(char* buf, int len, char const* fmt, ...)
#endif #endif
#if !defined(TORRENT_READ_HANDLER_MAX_SIZE) #if !defined(TORRENT_READ_HANDLER_MAX_SIZE)
# define TORRENT_READ_HANDLER_MAX_SIZE 256 # define TORRENT_READ_HANDLER_MAX_SIZE 300
#endif #endif
#if !defined(TORRENT_WRITE_HANDLER_MAX_SIZE) #if !defined(TORRENT_WRITE_HANDLER_MAX_SIZE)
# define TORRENT_WRITE_HANDLER_MAX_SIZE 256 # define TORRENT_WRITE_HANDLER_MAX_SIZE 300
#endif #endif
#if defined _MSC_VER && _MSC_VER <= 1200 #if defined _MSC_VER && _MSC_VER <= 1200

View File

@ -42,9 +42,7 @@ namespace libtorrent
struct utp_socket_manager; struct utp_socket_manager;
struct socket_type; struct socket_type;
// if from is specified, a new socket will be created // instantiate a socket_type (s) according to the specified criteria
// using the same underlying socket object as 'from'.
// this can be used to "upgrade" a socket into an SSL socket
TORRENT_EXTRA_EXPORT bool instantiate_connection(io_service& ios TORRENT_EXTRA_EXPORT bool instantiate_connection(io_service& ios
, proxy_settings const& ps, socket_type& s , proxy_settings const& ps, socket_type& s
, void* ssl_context = 0 , void* ssl_context = 0

View File

@ -295,8 +295,15 @@ namespace libtorrent
size_type m_data[(storage_size + sizeof(size_type) - 1) / sizeof(size_type)]; size_type m_data[(storage_size + sizeof(size_type) - 1) / sizeof(size_type)];
}; };
// returns true if this socket is an SSL socket
bool is_ssl(socket_type const& s); bool is_ssl(socket_type const& s);
// assuming the socket_type s is an ssl socket, make sure it
// verifies the hostname in its SSL handshake
void setup_ssl_hostname(socket_type& s, std::string const& hostname, error_code& ec);
// properly shuts down SSL sockets. holder keeps s alive
void async_shutdown(socket_type& s, boost::shared_ptr<void> holder);
} }
#endif #endif

View File

@ -37,15 +37,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/parse_url.hpp" #include "libtorrent/parse_url.hpp"
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
#include "libtorrent/connection_queue.hpp" #include "libtorrent/connection_queue.hpp"
#include "libtorrent/socket_type.hpp" // for async_shutdown
#if defined TORRENT_ASIO_DEBUGGING #if defined TORRENT_ASIO_DEBUGGING
#include "libtorrent/debug.hpp" #include "libtorrent/debug.hpp"
#endif #endif
#if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700
#include <boost/asio/ssl/rfc2818_verification.hpp>
#endif
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
@ -92,10 +89,6 @@ http_connection::http_connection(io_service& ios, connection_queue& cc
, m_abort(false) , m_abort(false)
{ {
TORRENT_ASSERT(!m_handler.empty()); TORRENT_ASSERT(!m_handler.empty());
// TODO: if we were handed an SSL context, we should really
// verify the hostname of the web server as well. This is supported
// in boost starting with version 1.47.0. See ssl::rfc2818_verification
// and ssl::context::set_verify_callback
} }
http_connection::~http_connection() http_connection::~http_connection()
@ -262,7 +255,7 @@ void http_connection::start(std::string const& hostname, std::string const& port
m_ssl = ssl; m_ssl = ssl;
m_bind_addr = bind_addr; m_bind_addr = bind_addr;
error_code ec; error_code ec;
m_sock.close(ec); if (m_sock.is_open()) m_sock.close(ec);
#if TORRENT_USE_I2P #if TORRENT_USE_I2P
bool is_i2p = false; bool is_i2p = false;
@ -340,30 +333,13 @@ void http_connection::start(std::string const& hostname, std::string const& port
} }
} }
#if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700 setup_ssl_hostname(m_sock, hostname, ec);
// for SSL connections, make sure to authenticate the hostname
// of the certificate
#define CASE(t) case socket_type_int_impl<ssl_stream<t> >::value: \
m_sock.get<ssl_stream<t> >()->set_verify_callback(asio::ssl::rfc2818_verification(hostname), ec); \
break;
switch(m_sock.type())
{
CASE(stream_socket)
CASE(socks5_stream)
CASE(http_stream)
CASE(utp_stream)
}
if (ec) if (ec)
{ {
m_resolver.get_io_service().post(boost::bind(&http_connection::callback m_resolver.get_io_service().post(boost::bind(&http_connection::callback
, me, ec, (char*)0, 0)); , me, ec, (char*)0, 0));
return; return;
} }
#undef CASE
#endif
#if TORRENT_USE_I2P #if TORRENT_USE_I2P
if (is_i2p) if (is_i2p)
@ -443,7 +419,7 @@ void http_connection::on_timeout(boost::weak_ptr<http_connection> p
add_outstanding_async("http_connection::on_timeout"); add_outstanding_async("http_connection::on_timeout");
#endif #endif
error_code ec; error_code ec;
c->m_sock.close(ec); async_shutdown(c->m_sock, c);
c->m_timer.expires_at((std::min)( c->m_timer.expires_at((std::min)(
c->m_last_receive + c->m_read_timeout c->m_last_receive + c->m_read_timeout
, c->m_start_time + c->m_completion_timeout), ec); , c->m_start_time + c->m_completion_timeout), ec);
@ -470,11 +446,15 @@ void http_connection::on_timeout(boost::weak_ptr<http_connection> p
void http_connection::close() void http_connection::close()
{ {
if (m_abort) return;
error_code ec; error_code ec;
m_timer.cancel(ec); m_timer.cancel(ec);
m_resolver.cancel(); m_resolver.cancel();
m_limiter_timer.cancel(ec); m_limiter_timer.cancel(ec);
m_sock.close(ec);
async_shutdown(m_sock, shared_from_this());
m_hostname.clear(); m_hostname.clear();
m_port.clear(); m_port.clear();
m_handler.clear(); m_handler.clear();
@ -812,6 +792,10 @@ void http_connection::on_read(error_code const& e
} }
error_code ec; error_code ec;
// it would be nice to gracefully shut down SSL here
// but then we'd have to do all the reconnect logic
// in its handler. For now, just kill the connection.
// async_shutdown(m_sock, shared_from_this());
m_sock.close(ec); m_sock.close(ec);
using boost::tuples::ignore; using boost::tuples::ignore;
boost::tie(ignore, ignore, ignore, ignore, ignore) boost::tie(ignore, ignore, ignore, ignore, ignore)

View File

@ -3489,15 +3489,6 @@ namespace libtorrent
return; return;
} }
void on_close_socket(boost::shared_ptr<socket_type> const& s)
{
#if defined TORRENT_ASIO_DEBUGGING
complete_async("on_close_socket");
#endif
error_code ec;
s->close(ec);
}
// the error argument defaults to 0, which means deliberate disconnect // the error argument defaults to 0, which means deliberate disconnect
// 1 means unexpected disconnect/error // 1 means unexpected disconnect/error
// 2 protocol error (client sent something invalid) // 2 protocol error (client sent something invalid)
@ -3711,29 +3702,7 @@ namespace libtorrent
m_disconnecting = true; m_disconnecting = true;
error_code e; error_code e;
#ifdef TORRENT_USE_OPENSSL async_shutdown(*m_socket, m_socket);
// for SSL connections, first do an async_shutdown, before closing the socket
#if defined TORRENT_ASIO_DEBUGGING
#define MAYBE_ASIO_DEBUGGING add_outstanding_async("on_close_socket");
#else
#define MAYBE_ASIO_DEBUGGING
#endif
#define CASE(t) case socket_type_int_impl<ssl_stream<t> >::value: \
MAYBE_ASIO_DEBUGGING \
m_socket->get<ssl_stream<t> >()->async_shutdown(boost::bind(&on_close_socket, m_socket)); \
break;
switch(m_socket->type())
{
CASE(stream_socket)
CASE(socks5_stream)
CASE(http_stream)
CASE(utp_stream)
default: m_socket->close(e); break;
}
#undef CASE
#else
m_socket->close(e);
#endif // TORRENT_USE_OPENSSL
m_ses.close_connection(this, ec); m_ses.close_connection(this, ec);

View File

@ -34,6 +34,11 @@ POSSIBILITY OF SUCH DAMAGE.
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
#include <boost/asio/ssl/context.hpp> #include <boost/asio/ssl/context.hpp>
#if BOOST_VERSION >= 104700
#include <boost/asio/ssl/rfc2818_verification.hpp>
#endif
#endif #endif
namespace libtorrent namespace libtorrent
@ -58,6 +63,76 @@ namespace libtorrent
#endif #endif
} }
void setup_ssl_hostname(socket_type& s, std::string const& hostname, error_code& ec)
{
#if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700
// for SSL connections, make sure to authenticate the hostname
// of the certificate
#define CASE(t) case socket_type_int_impl<ssl_stream<t> >::value: \
s.get<ssl_stream<t> >()->set_verify_callback(asio::ssl::rfc2818_verification(hostname), ec); \
ctx = SSL_get_SSL_CTX(s.get<ssl_stream<t> >()->native_handle()); \
break;
SSL_CTX* ctx = 0;
switch(s.type())
{
CASE(stream_socket)
CASE(socks5_stream)
CASE(http_stream)
CASE(utp_stream)
}
#undef CASE
if (ctx)
{
SSL_CTX_set_tlsext_servername_callback(ctx, 0);
SSL_CTX_set_tlsext_servername_arg(ctx, 0);
}
#endif
}
void on_close_socket(socket_type* s, boost::shared_ptr<void> holder)
{
#if defined TORRENT_ASIO_DEBUGGING
complete_async("on_close_socket");
#endif
error_code ec;
s->close(ec);
}
// the second argument is a shared pointer to an object that
// will keep the socket (s) alive for the duration of the async operation
void async_shutdown(socket_type& s, boost::shared_ptr<void> holder)
{
error_code e;
#ifdef TORRENT_USE_OPENSSL
// for SSL connections, first do an async_shutdown, before closing the socket
#if defined TORRENT_ASIO_DEBUGGING
#define MAYBE_ASIO_DEBUGGING add_outstanding_async("on_close_socket");
#else
#define MAYBE_ASIO_DEBUGGING
#endif
#define CASE(t) case socket_type_int_impl<ssl_stream<t> >::value: \
MAYBE_ASIO_DEBUGGING \
s.get<ssl_stream<t> >()->async_shutdown(boost::bind(&on_close_socket, &s, holder)); \
break;
switch(s.type())
{
CASE(stream_socket)
CASE(socks5_stream)
CASE(http_stream)
CASE(utp_stream)
default: s.close(e); break;
}
#undef CASE
#else
s.close(e);
#endif // TORRENT_USE_OPENSSL
}
void socket_type::destruct() void socket_type::destruct()
{ {
switch (m_type) switch (m_type)

View File

@ -86,7 +86,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/ssl_stream.hpp" #include "libtorrent/ssl_stream.hpp"
#include <boost/asio/ssl/context.hpp> #include <boost/asio/ssl/context.hpp>
#if BOOST_VERSION >= 104700 #if BOOST_VERSION >= 104700
#include <boost/asio/ssl/rfc2818_verification.hpp>
#include <boost/asio/ssl/verify_context.hpp> #include <boost/asio/ssl/verify_context.hpp>
#endif // BOOST_VERSION #endif // BOOST_VERSION
#endif // TORRENT_USE_OPENSSL #endif // TORRENT_USE_OPENSSL
@ -4655,28 +4654,13 @@ namespace libtorrent
str->set_dst_name(hostname); str->set_dst_name(hostname);
} }
#if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700 setup_ssl_hostname(*s, hostname, ec);
// for SSL connections, make sure to authenticate the hostname
// of the certificate
#define CASE(t) case socket_type_int_impl<ssl_stream<t> >::value: \
s->get<ssl_stream<t> >()->set_verify_callback(asio::ssl::rfc2818_verification(hostname), ec); \
break;
switch(s->type())
{
CASE(stream_socket)
CASE(socks5_stream)
CASE(http_stream)
CASE(utp_stream)
}
if (ec) if (ec)
{ {
if (m_ses.m_alerts.should_post<url_seed_alert>()) if (m_ses.m_alerts.should_post<url_seed_alert>())
m_ses.m_alerts.post_alert(url_seed_alert(get_handle(), web->url, ec)); m_ses.m_alerts.post_alert(url_seed_alert(get_handle(), web->url, ec));
return; return;
} }
#undef CASE
#endif
boost::intrusive_ptr<peer_connection> c; boost::intrusive_ptr<peer_connection> c;
if (web->type == web_seed_entry::url_seed) if (web->type == web_seed_entry::url_seed)

View File

@ -600,7 +600,7 @@ int start_web_server(bool ssl, bool chunked_encoding)
system("echo test city >> tmp"); system("echo test city >> tmp");
system("echo test company >> tmp"); system("echo test company >> tmp");
system("echo test department >> tmp"); system("echo test department >> tmp");
system("echo tester >> tmp"); system("echo 127.0.0.1 >> tmp");
system("echo test@test.com >> tmp"); system("echo test@test.com >> tmp");
system("openssl req -new -x509 -keyout server.pem -out server.pem " system("openssl req -new -x509 -keyout server.pem -out server.pem "
"-days 365 -nodes <tmp"); "-days 365 -nodes <tmp");
@ -876,7 +876,7 @@ void web_server_thread(int* port, bool ssl, bool chunked)
s.async_read_some(boost::asio::buffer(&buf[len] s.async_read_some(boost::asio::buffer(&buf[len]
, sizeof(buf) - len), boost::bind(&on_read, _1, _2, &received, &ec, &done)); , sizeof(buf) - len), boost::bind(&on_read, _1, _2, &received, &ec, &done));
deadline_timer timer(ios); deadline_timer timer(ios);
timer.expires_at(time_now_hires() + seconds(100)); timer.expires_at(time_now_hires() + seconds(2));
timer.async_wait(boost::bind(&on_read_timeout, _1, &timed_out)); timer.async_wait(boost::bind(&on_read_timeout, _1, &timed_out));
while (!done && !timed_out) while (!done && !timed_out)