Refactor code about logging remote host info

This commit is contained in:
abitmore 2020-05-01 17:18:31 -04:00
parent e336649b8f
commit ba394e05b3
2 changed files with 78 additions and 72 deletions

View file

@ -31,9 +31,12 @@ namespace fc { namespace http {
boost::any& get_session_data() { return _session_data; } boost::any& get_session_data() { return _session_data; }
virtual std::string get_request_header(const std::string& key) = 0; virtual std::string get_request_header(const std::string& key) = 0;
virtual std::string get_remote_ip(const std::string& forward_header_key) = 0;
const std::string& get_remote_endpoint()const { return _remote_endpoint; }
fc::signal<void()> closed; fc::signal<void()> closed;
protected:
std::string _remote_endpoint; // for logging
private: private:
boost::any _session_data; boost::any _session_data;
std::function<void(const std::string&)> _on_message; std::function<void(const std::string&)> _on_message;
@ -46,7 +49,7 @@ namespace fc { namespace http {
class websocket_server class websocket_server
{ {
public: public:
websocket_server(); websocket_server(const std::string& forward_header_key);
~websocket_server(); ~websocket_server();
void on_connection( const on_connection_handler& handler); void on_connection( const on_connection_handler& handler);
@ -54,7 +57,6 @@ namespace fc { namespace http {
void listen( const fc::ip::endpoint& ep ); void listen( const fc::ip::endpoint& ep );
uint16_t get_listening_port(); uint16_t get_listening_port();
void start_accept(); void start_accept();
void set_forward_header_key(const std::string& key);
void stop_listening(); void stop_listening();
void close(); void close();
@ -68,15 +70,15 @@ namespace fc { namespace http {
class websocket_tls_server class websocket_tls_server
{ {
public: public:
websocket_tls_server( const std::string& server_pem = std::string(), websocket_tls_server( const std::string& server_pem,
const std::string& ssl_password = std::string()); const std::string& ssl_password,
const std::string& forward_header_key );
~websocket_tls_server(); ~websocket_tls_server();
void on_connection( const on_connection_handler& handler); void on_connection( const on_connection_handler& handler);
void listen( uint16_t port ); void listen( uint16_t port );
void listen( const fc::ip::endpoint& ep ); void listen( const fc::ip::endpoint& ep );
void start_accept(); void start_accept();
void set_forward_header_key(const std::string& key);
private: private:
friend class detail::websocket_tls_server_impl; friend class detail::websocket_tls_server_impl;
std::unique_ptr<detail::websocket_tls_server_impl> my; std::unique_ptr<detail::websocket_tls_server_impl> my;

View file

@ -20,6 +20,8 @@
#include <fc/thread/thread.hpp> #include <fc/thread/thread.hpp>
#include <fc/asio.hpp> #include <fc/asio.hpp>
#include <boost/algorithm/string.hpp>
#ifdef DEFAULT_LOGGER #ifdef DEFAULT_LOGGER
# undef DEFAULT_LOGGER # undef DEFAULT_LOGGER
#endif #endif
@ -144,8 +146,14 @@ namespace fc { namespace http {
class websocket_connection_impl : public websocket_connection class websocket_connection_impl : public websocket_connection
{ {
public: public:
websocket_connection_impl( T con ) websocket_connection_impl( T con, const std::string& forward_header_key ) : _ws_connection(con)
:_ws_connection(con){ {
// Firstly, try to extract remote address from a XFF-like header
if( !forward_header_key.empty() )
_remote_endpoint = get_request_header( forward_header_key );
// If the last step failed, retrieve the remote address from the connection
if( _remote_endpoint.empty() )
_remote_endpoint = con->get_remote_endpoint();
} }
virtual ~websocket_connection_impl() virtual ~websocket_connection_impl()
@ -154,7 +162,8 @@ namespace fc { namespace http {
virtual void send_message( const std::string& message )override virtual void send_message( const std::string& message )override
{ {
idump((message)); ilog( "[OUT] ${remote_endpoint} ${msg}",
("remote_endpoint",_remote_endpoint) ("msg",message) );
auto ec = _ws_connection->send( message ); auto ec = _ws_connection->send( message );
FC_ASSERT( !ec, "websocket send failed: ${msg}", ("msg",ec.message() ) ); FC_ASSERT( !ec, "websocket send failed: ${msg}", ("msg",ec.message() ) );
} }
@ -168,30 +177,7 @@ namespace fc { namespace http {
return _ws_connection->get_request_header(key); return _ws_connection->get_request_header(key);
} }
/****
* @brief retrieves the remote IP address
*
* @param forward_header_key the key to look at in the request header
* @returns the value in the header, otherwise the remote endpoint
*/
virtual std::string get_remote_ip(const std::string& forward_header_key) override
{
if (last_ip.empty() || last_forward_header_key != forward_header_key)
{
// refresh the cache
last_forward_header_key = forward_header_key;
if (!forward_header_key.empty())
last_ip = get_request_header(forward_header_key);
if (last_ip.empty())
last_ip = _ws_connection->get_remote_endpoint();
}
return last_ip;
}
T _ws_connection; T _ws_connection;
// cache the value of the remote IP
std::string last_forward_header_key;
std::string last_ip;
}; };
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr; typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
@ -199,8 +185,8 @@ namespace fc { namespace http {
class websocket_server_impl class websocket_server_impl
{ {
public: public:
websocket_server_impl() websocket_server_impl( const std::string& forward_header_key )
:_server_thread( fc::thread::current() ), fwd_header_key("") :_server_thread( fc::thread::current() ), _forward_header_key(forward_header_key)
{ {
_server.clear_access_channels( websocketpp::log::alevel::all ); _server.clear_access_channels( websocketpp::log::alevel::all );
_server.init_asio(&fc::asio::default_io_service()); _server.init_asio(&fc::asio::default_io_service());
@ -208,7 +194,8 @@ namespace fc { namespace http {
_server.set_open_handler( [&]( connection_hdl hdl ){ _server.set_open_handler( [&]( connection_hdl hdl ){
_server_thread.async( [this, hdl](){ _server_thread.async( [this, hdl](){
auto new_con = std::make_shared<websocket_connection_impl< auto new_con = std::make_shared<websocket_connection_impl<
websocket_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl) ); websocket_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl),
_forward_header_key );
_on_connection( _connections[hdl] = new_con ); _on_connection( _connections[hdl] = new_con );
}).wait(); }).wait();
}); });
@ -218,10 +205,14 @@ namespace fc { namespace http {
assert( current_con != _connections.end() ); assert( current_con != _connections.end() );
auto payload = msg->get_payload(); auto payload = msg->get_payload();
std::shared_ptr<websocket_connection> con = current_con->second; std::shared_ptr<websocket_connection> con = current_con->second;
wlog( "Websocket Server Remote: ${host} Payload: ${body}", wlog( "[IN] ${remote_endpoint} ${msg}",
("host", con->get_remote_ip(fwd_header_key)) ("body", msg->get_payload())); ("remote_endpoint",con->get_remote_endpoint()) ("msg",payload) );
++_pending_messages; ++_pending_messages;
auto f = fc::async([this,con,payload](){ if( _pending_messages ) --_pending_messages; con->on_message( payload ); }); auto f = fc::async([this,con,payload](){
if( _pending_messages )
--_pending_messages;
con->on_message( payload );
});
if( _pending_messages > 100 ) if( _pending_messages > 100 )
f.wait(); f.wait();
}).wait(); }).wait();
@ -234,17 +225,21 @@ namespace fc { namespace http {
_server.set_http_handler( [&]( connection_hdl hdl ){ _server.set_http_handler( [&]( connection_hdl hdl ){
_server_thread.async( [&](){ _server_thread.async( [&](){
auto current_con = std::make_shared<websocket_connection_impl<websocket_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl) ); auto con = _server.get_con_from_hdl(hdl);
auto current_con = std::make_shared<websocket_connection_impl<
websocket_server_type::connection_ptr>>( con, _forward_header_key );
_on_connection( current_con ); _on_connection( current_con );
auto con = _server.get_con_from_hdl(hdl);
con->defer_http_response(); con->defer_http_response();
std::string remote_endpoint = current_con->get_remote_endpoint();
std::string request_body = con->get_request_body(); std::string request_body = con->get_request_body();
wdump(("server")(request_body)); wlog( "[IN] ${remote_endpoint} ${msg}",
("remote_endpoint",remote_endpoint) ("msg",request_body) );
fc::async([current_con, request_body, con] { fc::async([current_con, request_body, con, remote_endpoint] {
fc::http::reply response = current_con->on_http(request_body); fc::http::reply response = current_con->on_http(request_body);
idump( (response) ); ilog( "[OUT] ${remote_endpoint} ${msg}",
("remote_endpoint",remote_endpoint) ("msg",response) );
con->set_body( std::move( response.body_as_string ) ); con->set_body( std::move( response.body_as_string ) );
con->set_status( websocketpp::http::status_code::value(response.status) ); con->set_status( websocketpp::http::status_code::value(response.status) );
con->send_http_response(); con->send_http_response();
@ -303,8 +298,6 @@ namespace fc { namespace http {
if( _closed ) _closed->wait(); if( _closed ) _closed->wait();
} }
void set_forward_header_key(const std::string& key) { fwd_header_key = key; }
typedef std::map<connection_hdl, websocket_connection_ptr,std::owner_less<connection_hdl> > con_map; typedef std::map<connection_hdl, websocket_connection_ptr,std::owner_less<connection_hdl> > con_map;
con_map _connections; con_map _connections;
@ -313,14 +306,15 @@ namespace fc { namespace http {
on_connection_handler _on_connection; on_connection_handler _on_connection;
fc::promise<void>::ptr _closed; fc::promise<void>::ptr _closed;
uint32_t _pending_messages = 0; uint32_t _pending_messages = 0;
std::string fwd_header_key; std::string _forward_header_key; // A header like "X-Forwarded-For" (XFF), with data IP:port
}; };
class websocket_tls_server_impl class websocket_tls_server_impl
{ {
public: public:
websocket_tls_server_impl( const string& server_pem, const string& ssl_password ) websocket_tls_server_impl( const string& server_pem, const string& ssl_password,
:_server_thread( fc::thread::current() ) const std::string& forward_header_key )
:_server_thread( fc::thread::current() ), _forward_header_key(forward_header_key)
{ {
{ {
_server.set_tls_init_handler( [=]( websocketpp::connection_hdl hdl ) -> context_ptr { _server.set_tls_init_handler( [=]( websocketpp::connection_hdl hdl ) -> context_ptr {
@ -345,7 +339,9 @@ namespace fc { namespace http {
_server.set_reuse_addr(true); _server.set_reuse_addr(true);
_server.set_open_handler( [&]( connection_hdl hdl ){ _server.set_open_handler( [&]( connection_hdl hdl ){
_server_thread.async( [&](){ _server_thread.async( [&](){
auto new_con = std::make_shared<websocket_connection_impl<websocket_tls_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl) ); auto new_con = std::make_shared<websocket_connection_impl<
websocket_tls_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl),
_forward_header_key );
_on_connection( _connections[hdl] = new_con ); _on_connection( _connections[hdl] = new_con );
}).wait(); }).wait();
}); });
@ -355,8 +351,8 @@ namespace fc { namespace http {
assert( current_con != _connections.end() ); assert( current_con != _connections.end() );
auto received = msg->get_payload(); auto received = msg->get_payload();
std::shared_ptr<websocket_connection> con = current_con->second; std::shared_ptr<websocket_connection> con = current_con->second;
wlog( "Websocket TLS Server Remote: ${host} Payload: ${body}", wlog( "[IN] ${remote_endpoint} ${msg}",
("host", con->get_remote_ip(fwd_header_key)) ("body", msg->get_payload())); ("remote_endpoint",con->get_remote_endpoint()) ("msg",received) );
fc::async([con,received](){ con->on_message( received ); }); fc::async([con,received](){ con->on_message( received ); });
}).wait(); }).wait();
}); });
@ -364,14 +360,19 @@ namespace fc { namespace http {
_server.set_http_handler( [&]( connection_hdl hdl ){ _server.set_http_handler( [&]( connection_hdl hdl ){
_server_thread.async( [&](){ _server_thread.async( [&](){
auto current_con = std::make_shared<websocket_connection_impl<websocket_tls_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl) ); auto con = _server.get_con_from_hdl(hdl);
auto current_con = std::make_shared<websocket_connection_impl<
websocket_tls_server_type::connection_ptr>>( con, _forward_header_key );
try{ try{
_on_connection( current_con ); _on_connection( current_con );
auto con = _server.get_con_from_hdl(hdl); std::string remote_endpoint = current_con->get_remote_endpoint();
wdump(("server")(con->get_request_body())); std::string request_body = con->get_request_body();
wlog( "[IN] ${remote_endpoint} ${msg}",
("remote_endpoint",remote_endpoint) ("msg",request_body) );
auto response = current_con->on_http( con->get_request_body() ); auto response = current_con->on_http( con->get_request_body() );
idump((response)); ilog( "[OUT] ${remote_endpoint} ${msg}",
("remote_endpoint",remote_endpoint) ("msg",response) );
con->set_body( std::move( response.body_as_string ) ); con->set_body( std::move( response.body_as_string ) );
con->set_status( websocketpp::http::status_code::value( response.status ) ); con->set_status( websocketpp::http::status_code::value( response.status ) );
} catch ( const fc::exception& e ) } catch ( const fc::exception& e )
@ -413,8 +414,6 @@ namespace fc { namespace http {
_server.close( item.first, 0, "server exit" ); _server.close( item.first, 0, "server exit" );
} }
void set_forward_header_key( const std::string& key ) { fwd_header_key = key; }
typedef std::map<connection_hdl, websocket_connection_ptr,std::owner_less<connection_hdl> > con_map; typedef std::map<connection_hdl, websocket_connection_ptr,std::owner_less<connection_hdl> > con_map;
con_map _connections; con_map _connections;
@ -422,7 +421,7 @@ namespace fc { namespace http {
websocket_tls_server_type _server; websocket_tls_server_type _server;
on_connection_handler _on_connection; on_connection_handler _on_connection;
fc::promise<void>::ptr _closed; fc::promise<void>::ptr _closed;
std::string fwd_header_key; std::string _forward_header_key; // A header like "X-Forwarded-For" (XFF), with data IP:port
}; };
typedef websocketpp::client<asio_with_stub_log> websocket_client_type; typedef websocketpp::client<asio_with_stub_log> websocket_client_type;
@ -558,8 +557,8 @@ namespace fc { namespace http {
} // namespace detail } // namespace detail
websocket_server::websocket_server() websocket_server::websocket_server( const std::string& forward_header_key )
:my( new detail::websocket_server_impl() ) {} :my( new detail::websocket_server_impl( forward_header_key ) ) {}
websocket_server::~websocket_server(){} websocket_server::~websocket_server(){}
void websocket_server::on_connection( const on_connection_handler& handler ) void websocket_server::on_connection( const on_connection_handler& handler )
@ -597,12 +596,11 @@ namespace fc { namespace http {
my->_server.close(connection.first, websocketpp::close::status::normal, "Goodbye"); my->_server.close(connection.first, websocketpp::close::status::normal, "Goodbye");
} }
void websocket_server::set_forward_header_key( const std::string& key ) websocket_tls_server::websocket_tls_server( const string& server_pem, const string& ssl_password,
{ const std::string& forward_header_key )
my->set_forward_header_key( key ); :my( new detail::websocket_tls_server_impl(server_pem, ssl_password, forward_header_key) )
} {}
websocket_tls_server::websocket_tls_server( const string& server_pem, const string& ssl_password ):my( new detail::websocket_tls_server_impl(server_pem, ssl_password) ) {}
websocket_tls_server::~websocket_tls_server(){} websocket_tls_server::~websocket_tls_server(){}
void websocket_tls_server::on_connection( const on_connection_handler& handler ) void websocket_tls_server::on_connection( const on_connection_handler& handler )
@ -629,7 +627,11 @@ namespace fc { namespace http {
websocket_client::websocket_client( const std::string& ca_filename ):my( new detail::websocket_client_impl() ),smy(new detail::websocket_tls_client_impl( ca_filename )) {} websocket_client::websocket_client( const std::string& ca_filename )
:my( new detail::websocket_client_impl() ),
smy(new detail::websocket_tls_client_impl( ca_filename ))
{}
websocket_client::~websocket_client(){ } websocket_client::~websocket_client(){ }
websocket_connection_ptr websocket_client::connect( const std::string& uri ) websocket_connection_ptr websocket_client::connect( const std::string& uri )
@ -646,7 +648,8 @@ namespace fc { namespace http {
my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){ my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){
my->_hdl = hdl; my->_hdl = hdl;
auto con = my->_client.get_con_from_hdl(hdl); auto con = my->_client.get_con_from_hdl(hdl);
my->_connection = std::make_shared<detail::websocket_connection_impl<detail::websocket_client_connection_type>>( con ); my->_connection = std::make_shared<detail::websocket_connection_impl<
detail::websocket_client_connection_type>>( con, "" );
my->_closed = promise<void>::create("websocket::closed"); my->_closed = promise<void>::create("websocket::closed");
my->_connected->set_value(); my->_connected->set_value();
}); });
@ -675,7 +678,8 @@ namespace fc { namespace http {
smy->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){ smy->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){
auto con = smy->_client.get_con_from_hdl(hdl); auto con = smy->_client.get_con_from_hdl(hdl);
smy->_connection = std::make_shared<detail::websocket_connection_impl<detail::websocket_tls_client_connection_type>>( con ); smy->_connection = std::make_shared<detail::websocket_connection_impl<
detail::websocket_tls_client_connection_type>>( con, "" );
smy->_closed = promise<void>::create("websocket::closed"); smy->_closed = promise<void>::create("websocket::closed");
smy->_connected->set_value(); smy->_connected->set_value();
}); });
@ -708,14 +712,14 @@ namespace fc { namespace http {
websocket_connection_ptr websocket_tls_client::connect( const std::string& uri ) websocket_connection_ptr websocket_tls_client::connect( const std::string& uri )
{ try { { try {
// wlog( "connecting to ${uri}", ("uri",uri));
websocketpp::lib::error_code ec; websocketpp::lib::error_code ec;
my->_connected = promise<void>::create("websocket::connect"); my->_connected = promise<void>::create("websocket::connect");
my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){ my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){
auto con = my->_client.get_con_from_hdl(hdl); auto con = my->_client.get_con_from_hdl(hdl);
my->_connection = std::make_shared<detail::websocket_connection_impl<detail::websocket_tls_client_connection_type>>( con ); my->_connection = std::make_shared<detail::websocket_connection_impl<
detail::websocket_tls_client_connection_type>>( con, "" );
my->_closed = promise<void>::create("websocket::closed"); my->_closed = promise<void>::create("websocket::closed");
my->_connected->set_value(); my->_connected->set_value();
}); });