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
#if !defined(TORRENT_READ_HANDLER_MAX_SIZE)
# define TORRENT_READ_HANDLER_MAX_SIZE 256
# define TORRENT_READ_HANDLER_MAX_SIZE 300
#endif
#if !defined(TORRENT_WRITE_HANDLER_MAX_SIZE)
# define TORRENT_WRITE_HANDLER_MAX_SIZE 256
# define TORRENT_WRITE_HANDLER_MAX_SIZE 300
#endif
#if defined _MSC_VER && _MSC_VER <= 1200

View File

@ -42,9 +42,7 @@ namespace libtorrent
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
// instantiate a socket_type (s) according to the specified criteria
TORRENT_EXTRA_EXPORT bool instantiate_connection(io_service& ios
, proxy_settings const& ps, socket_type& s
, 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)];
};
// returns true if this socket is an SSL socket
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

View File

@ -37,15 +37,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/parse_url.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/socket_type.hpp" // for async_shutdown
#if defined TORRENT_ASIO_DEBUGGING
#include "libtorrent/debug.hpp"
#endif
#if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700
#include <boost/asio/ssl/rfc2818_verification.hpp>
#endif
#include <boost/bind.hpp>
#include <string>
#include <algorithm>
@ -92,10 +89,6 @@ http_connection::http_connection(io_service& ios, connection_queue& cc
, m_abort(false)
{
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()
@ -262,7 +255,7 @@ void http_connection::start(std::string const& hostname, std::string const& port
m_ssl = ssl;
m_bind_addr = bind_addr;
error_code ec;
m_sock.close(ec);
if (m_sock.is_open()) m_sock.close(ec);
#if TORRENT_USE_I2P
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
// 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)
}
setup_ssl_hostname(m_sock, hostname, ec);
if (ec)
{
m_resolver.get_io_service().post(boost::bind(&http_connection::callback
, me, ec, (char*)0, 0));
return;
}
#undef CASE
#endif
#if TORRENT_USE_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");
#endif
error_code ec;
c->m_sock.close(ec);
async_shutdown(c->m_sock, c);
c->m_timer.expires_at((std::min)(
c->m_last_receive + c->m_read_timeout
, 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()
{
if (m_abort) return;
error_code ec;
m_timer.cancel(ec);
m_resolver.cancel();
m_limiter_timer.cancel(ec);
m_sock.close(ec);
async_shutdown(m_sock, shared_from_this());
m_hostname.clear();
m_port.clear();
m_handler.clear();
@ -812,6 +792,10 @@ void http_connection::on_read(error_code const& e
}
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);
using boost::tuples::ignore;
boost::tie(ignore, ignore, ignore, ignore, ignore)

View File

@ -3489,15 +3489,6 @@ namespace libtorrent
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
// 1 means unexpected disconnect/error
// 2 protocol error (client sent something invalid)
@ -3711,29 +3702,7 @@ namespace libtorrent
m_disconnecting = true;
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 \
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
async_shutdown(*m_socket, m_socket);
m_ses.close_connection(this, ec);

View File

@ -34,6 +34,11 @@ POSSIBILITY OF SUCH DAMAGE.
#ifdef TORRENT_USE_OPENSSL
#include <boost/asio/ssl/context.hpp>
#if BOOST_VERSION >= 104700
#include <boost/asio/ssl/rfc2818_verification.hpp>
#endif
#endif
namespace libtorrent
@ -58,6 +63,76 @@ namespace libtorrent
#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()
{
switch (m_type)

View File

@ -86,7 +86,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/ssl_stream.hpp"
#include <boost/asio/ssl/context.hpp>
#if BOOST_VERSION >= 104700
#include <boost/asio/ssl/rfc2818_verification.hpp>
#include <boost/asio/ssl/verify_context.hpp>
#endif // BOOST_VERSION
#endif // TORRENT_USE_OPENSSL
@ -4655,28 +4654,13 @@ namespace libtorrent
str->set_dst_name(hostname);
}
#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); \
break;
switch(s->type())
{
CASE(stream_socket)
CASE(socks5_stream)
CASE(http_stream)
CASE(utp_stream)
}
setup_ssl_hostname(*s, hostname, ec);
if (ec)
{
if (m_ses.m_alerts.should_post<url_seed_alert>())
m_ses.m_alerts.post_alert(url_seed_alert(get_handle(), web->url, ec));
return;
}
#undef CASE
#endif
boost::intrusive_ptr<peer_connection> c;
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 company >> tmp");
system("echo test department >> tmp");
system("echo tester >> tmp");
system("echo 127.0.0.1 >> tmp");
system("echo test@test.com >> tmp");
system("openssl req -new -x509 -keyout server.pem -out server.pem "
"-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]
, sizeof(buf) - len), boost::bind(&on_read, _1, _2, &received, &ec, &done));
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));
while (!done && !timed_out)