Commit 23e6a7ad authored by louiz’'s avatar louiz’

Implement TLS connections

And use it between the master server and the menu client
We still need to use that between the slaves and the master server (with
client certificate verification), but all the work is basically done

fix #2352
parent 878c353a
......@@ -86,7 +86,6 @@ endif()
if(BUILD_SERVER)
add_executable(batajelo_game_server src/main/batajelo_game_server.cpp)
target_link_libraries(batajelo_game_server
network
game_server
)
......@@ -237,6 +236,7 @@ add_library(network STATIC ${source_network})
target_link_libraries(network
${Boost_LIBRARIES}
${OPENSSL_LIBRARIES}
logging
config
)
......
......@@ -8,10 +8,11 @@
#include <functional>
#include <network/remote_client_base.hpp>
#include <network/tcp_socket.hpp>
class GameServer;
class RemoteGameClient: public RemoteClientBase
class RemoteGameClient: public RemoteClientBase<TCPSocket>
{
public:
RemoteGameClient();
......
......@@ -7,6 +7,14 @@ int main()
{
std::ios_base::sync_with_stdio(false);
MenuClient::context.set_options( boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::no_sslv3);
MenuClient::context.set_verify_mode(boost::asio::ssl::verify_peer);
MenuClient::context.load_verify_file("../bata_test.cert");
MenuClient::context.set_verify_callback(boost::asio::ssl::rfc2818_verification("bata.gg"));
MenuClient client;
client.run();
......
......@@ -6,6 +6,15 @@ MasterToClientServer::MasterToClientServer(MasterServer* master,
Server<RemoteClient>(port),
master(master)
{
RemoteClient::context.set_options( boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::no_sslv3);
RemoteClient::context.set_verify_mode(boost::asio::ssl::verify_none);
RemoteClient::context.use_certificate_file("../bata_test.cert",
boost::asio::ssl::context::pem);
RemoteClient::context.use_private_key_file("../bata_test.key",
boost::asio::ssl::context::pem);
}
const RemoteClient* MasterToClientServer::find_client_by_login(const std::string& login) const
......
......@@ -4,7 +4,10 @@
#include <database/database.hpp>
#include "master.pb.h"
boost::asio::ssl::context RemoteClient::context(boost::asio::ssl::context::tlsv1);
RemoteClient::RemoteClient():
RemoteClientBase<TLSSocket>(RemoteClient::context),
user(nullptr),
server(nullptr),
senders{}
......@@ -16,6 +19,22 @@ RemoteClient::~RemoteClient()
log_info("Deleting remote client " << this->id);
}
void RemoteClient::start()
{
log_debug("Doing handshake now " << this->get_id());
this->get_stream().async_handshake(TLSSocket::ssl_socket_type::server,
[this](const boost::system::error_code& error)
{
if (error)
{
log_error("Handshake failed: " << error << " (id)" << this->get_id());
this->get_stream().shutdown();
}
else
RemoteClientBase::start();
});
}
void RemoteClient::set_server(MasterToClientServer* server)
{
this->server = server;
......
......@@ -17,19 +17,22 @@
#include <network/remote_client_base.hpp>
#include <network/tcp_socket.hpp>
#include <network/tls_socket.hpp>
class MasterToClientServer;
class Message;
class TransferSender;
class RemoteClient: public RemoteClientBase<TCPSocket>
class RemoteClient: public RemoteClientBase<TLSSocket>
{
public:
static boost::asio::ssl::context context;
RemoteClient();
~RemoteClient();
void on_connection_closed() override final;
void set_server(MasterToClientServer* server);
void start() override final;
/**
* Sends a file to the remote client.
* @param filename The file to send.
......
......@@ -4,8 +4,10 @@
#include "master.pb.h"
boost::asio::ssl::context MenuClient::context(boost::asio::ssl::context::tlsv1);
MenuClient::MenuClient():
ClientBase(),
ClientBase<TLSSocket>(MenuClient::context),
connected(false)
{
}
......@@ -21,14 +23,30 @@ void MenuClient::run()
void MenuClient::connect()
{
ClientBase::connect("127.0.0.1", 7878,
[this]()
{
this->on_connection_success();
},
[this](const boost::system::error_code& error)
{
this->on_connection_failed(error);
});
[this](const boost::system::error_code& error)
{
if (error)
this->on_connection_failed(error);
else
{
log_debug("Connected. Doing the handshake now");
this->get_stream().async_handshake(TLSSocket::ssl_socket_type::client,
[this](const boost::system::error_code& error)
{
if (error)
{
log_error("Handshake failed: " << error);
this->get_stream().shutdown();
}
else
{
log_debug("Handshake successful");
this->when_connected();
this->on_connection_success();
}
});
}
});
}
void MenuClient::on_connection_success()
......
......@@ -2,10 +2,13 @@
#define MENU_CLIENT_HPP_INCLUDED
#include <network/client_base.hpp>
#include <network/tls_socket.hpp>
class MenuClient: public ClientBase
class MenuClient: public ClientBase<TLSSocket>
{
public:
static boost::asio::ssl::context context;
MenuClient();
~MenuClient() = default;
void run();
......
......@@ -20,6 +20,7 @@
#include <network/timed_event_handler.hpp>
#include <network/message.hpp>
#include <network/timed_event.hpp>
#include <network/ioservice.hpp>
#include <logging/logging.hpp>
#include <utils/time.hpp>
......@@ -33,7 +34,10 @@ class ClientBase: public MessageHandler<SocketType>, public TimedEventHandler,
public PingHandler
{
public:
ClientBase() = default;
template <typename... SocketArgs>
ClientBase(SocketArgs&&... socket_args):
MessageHandler<SocketType>(std::forward<SocketArgs>(socket_args)...)
{}
~ClientBase()
{
if (this->get_socket().is_open())
......@@ -50,15 +54,23 @@ public:
*/
void connect(const std::string& host,
const short& port,
std::function<void(void)> on_success=nullptr,
std::function<void(const boost::system::error_code&)> on_failure=nullptr)
std::function<void(const boost::system::error_code&)> handler=nullptr)
{
// TODO use resolve and DNS
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(host), port);
this->get_socket().async_connect(endpoint,
std::bind(&ClientBase::connect_handler, this,
on_success, on_failure,
std::placeholders::_1));
[this, handler](const boost::system::error_code& error)
{
if (handler)
handler(error);
else
{
if (!error)
this->when_connected();
else
log_debug("Connection failed");
}
});
log_info("Connecting to " << host << ":" << port);
}
......@@ -77,29 +89,16 @@ public:
virtual void on_connection_closed() = 0;
private:
void connect_handler(std::function<void(void)> on_success,
std::function<void(const boost::system::error_code&)> on_failure,
const boost::system::error_code& error)
protected:
void when_connected()
{
if (error)
{
log_info("Connection failed: " << error);
if (on_failure)
on_failure(error);
}
else
{
log_info("Connected.");
this->install_callback("PING", std::bind(&ClientBase::ping_callback,
this, std::placeholders::_1));
this->install_callbacks();
this->install_read_handler();
if (on_success)
on_success();
}
log_info("Connected.");
this->install_callback("PING", std::bind(&ClientBase::ping_callback,
this, std::placeholders::_1));
this->install_callbacks();
this->install_read_handler();
}
private:
/**
* Called when the server sends us a PING request. Sends a PONG back.
*/
......
......@@ -30,14 +30,16 @@ template <typename SocketType>
class MessageHandler: public SocketType
{
public:
MessageHandler():
template <typename... SocketArgs>
MessageHandler(SocketArgs&&... socket_args):
SocketType(std::forward<SocketArgs>(socket_args)...),
writing(false)
{ }
virtual ~MessageHandler() = default;
void install_read_handler()
{
boost::asio::async_read_until(this->get_socket(),
boost::asio::async_read_until(this->get_stream(),
this->data,
':',
std::bind(&MessageHandler::read_handler, this,
......@@ -102,7 +104,7 @@ public:
// We check what we need to read on the socket to have the rest of the binary datas
const std::size_t length_to_read = this->data.size() >= size ? 0 : size - this->data.size();
boost::asio::async_read(this->get_socket(),
boost::asio::async_read(this->get_stream(),
this->data,
boost::asio::transfer_at_least(length_to_read),
std::bind(&MessageHandler::binary_read_handler, this,
......@@ -272,7 +274,7 @@ protected:
std::vector<boost::asio::const_buffer> buffs;
buffs.push_back(boost::asio::buffer(message->header.data(), message->header.length()));
buffs.push_back(boost::asio::buffer(message->body, message->body_size));
async_write(this->get_socket(),
async_write(this->get_stream(),
buffs,
std::bind(&MessageHandler::send_handler, this,
std::placeholders::_1,
......
#include <network/remote_client_base.hpp>
#include <network/tls_socket.hpp>
#include <network/tcp_socket.hpp>
template <>
unsigned long int RemoteClientBase<TCPSocket>::clients_number = 0;
template <>
unsigned long int RemoteClientBase<TLSSocket>::clients_number = 0;
......@@ -37,7 +37,9 @@ template <typename SocketType>
class RemoteClientBase: public MessageHandler<SocketType>, public TimedEventHandler, public PingHandler
{
public:
RemoteClientBase():
template <typename... SocketArgs>
RemoteClientBase(SocketArgs&&... socket_args):
MessageHandler<SocketType>(std::forward<SocketArgs>(socket_args)...),
id(RemoteClientBase<SocketType>::clients_number++)
{ }
......@@ -46,7 +48,7 @@ public:
/**
* starts the client (install the read handler, etc)
*/
void start()
virtual void start()
{
log_debug("Starting RemoteClientBase " << this->id);
this->install_callbacks();
......
......@@ -25,6 +25,10 @@ public:
{
return this->socket;
}
boost::asio::ip::tcp::socket& get_stream()
{
return this->socket;
}
private:
boost::asio::ip::tcp::socket socket;
......
#ifndef TLS_SOCKET_HPP_INCLUDED
#define TLS_SOCKET_HPP_INCLUDED
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <network/ioservice.hpp>
#include <logging/logging.hpp>
class TLSSocket
{
public:
using ssl_socket_type = boost::asio::ssl::stream<boost::asio::ip::tcp::socket>;
TLSSocket(boost::asio::ssl::context& context):
ssl_socket(IoService::get(), context)
{
log_debug("ssl_socket init with context");
}
~TLSSocket() = default;
const ssl_socket_type::lowest_layer_type& get_socket() const
{
return this->ssl_socket.lowest_layer();
}
ssl_socket_type::lowest_layer_type& get_socket()
{
return this->ssl_socket.lowest_layer();
}
ssl_socket_type& get_stream()
{
return this->ssl_socket;
}
static boost::asio::ssl::context context;
private:
ssl_socket_type ssl_socket;
TLSSocket(const TLSSocket&) = delete;
TLSSocket(TLSSocket&&) = delete;
TLSSocket& operator=(const TLSSocket&) = delete;
TLSSocket& operator=(TLSSocket&&) = delete;
};
#endif /* TLS_SOCKET_HPP_INCLUDED */
......@@ -13,13 +13,15 @@ SlaveClient::SlaveClient(Slave* slave):
void SlaveClient::start()
{
this->connect("127.0.0.1", 7877,
[this]()
{
this->on_connection_success();
},
[this](const boost::system::error_code& error)
{
this->on_connection_failed(error);
if (error)
this->on_connection_failed(error);
else
{
this->when_connected();
this->on_connection_success();
}
});
}
......
......@@ -8,10 +8,11 @@
*/
#include <network/client_base.hpp>
#include <network/tcp_socket.hpp>
class Slave;
class SlaveClient: public ClientBase
class SlaveClient: public ClientBase<TCPSocket>
{
public:
SlaveClient(Slave* slave);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment