diff --git a/apps/freelan/config/freelan.cfg b/apps/freelan/config/freelan.cfg index d97ab3b1..80b80fd8 100644 --- a/apps/freelan/config/freelan.cfg +++ b/apps/freelan/config/freelan.cfg @@ -333,12 +333,12 @@ public_endpoint=0.0.0.0 # Default: yes #upnp_enabled=yes -# Maximum PRESENTATION message from one host allowed per second. +# Maximum unauthenticated messages from one host allowed per second. # -# This is a way to mitigates PRESENTATION flood attack. +# This is a way to mitigates HELLO/PRESENTATION flood attack. # # Default: 1 -#max_presentation_per_second=1 +#max_unauthenticated_messages_per_second=1 [tap_adapter] diff --git a/apps/freelan/src/configuration_helper.cpp b/apps/freelan/src/configuration_helper.cpp index 121d5544..0592c43c 100644 --- a/apps/freelan/src/configuration_helper.cpp +++ b/apps/freelan/src/configuration_helper.cpp @@ -292,7 +292,7 @@ po::options_description get_fscp_options() ("fscp.cipher_suite_capability", po::value >()->multitoken()->zero_tokens()->default_value(fscp::get_default_cipher_suites(), ""), "A cipher suite to allow.") ("fscp.elliptic_curve_capability", po::value >()->multitoken()->zero_tokens()->default_value(fscp::get_default_elliptic_curves(), ""), "A elliptic curve to allow.") ("fscp.upnp_enabled", po::value()->default_value(true, "yes"), "Enable UPnP.") - ("fscp.max_presentation_per_second", po::value()->default_value(1, "1"), "Maximum PRESENTATION message from one host per second.") + ("fscp.max_unauthenticated_messages_per_second", po::value()->default_value(1, "1"), "Maximum unauthenticated messages from one host per second.") ; return result; @@ -465,7 +465,7 @@ void setup_configuration(const fscp::logger& logger, fl::configuration& configur configuration.fscp.cipher_suite_capabilities = vm["fscp.cipher_suite_capability"].as>(); configuration.fscp.elliptic_curve_capabilities = vm["fscp.elliptic_curve_capability"].as>(); configuration.fscp.upnp_enabled = vm["fscp.upnp_enabled"].as(); - configuration.fscp.max_presentation_per_second = vm["fscp.max_presentation_per_second"].as(); + configuration.fscp.max_unauthenticated_messages_per_second = vm["fscp.max_unauthenticated_messages_per_second"].as(); // Security options const std::string passphrase = vm["security.passphrase"].as(); diff --git a/libs/freelan/include/freelan/configuration.hpp b/libs/freelan/include/freelan/configuration.hpp index 79590552..341c6727 100644 --- a/libs/freelan/include/freelan/configuration.hpp +++ b/libs/freelan/include/freelan/configuration.hpp @@ -323,9 +323,9 @@ namespace freelan bool upnp_enabled; /* - * \brief Maximum PRESENTATION message from one host per second. + * \brief Maximum HELLO/PRESENTATION message from one host per second. */ - size_t max_presentation_per_second; + size_t max_unauthenticated_messages_per_second; }; /** diff --git a/libs/freelan/src/core.cpp b/libs/freelan/src/core.cpp index ab9a72a3..ce8aa110 100644 --- a/libs/freelan/src/core.cpp +++ b/libs/freelan/src/core.cpp @@ -632,7 +632,8 @@ namespace freelan { m_fscp_server->set_cipher_suites(m_configuration.fscp.cipher_suite_capabilities); m_fscp_server->set_elliptic_curves(m_configuration.fscp.elliptic_curve_capabilities); - m_fscp_server->set_presentation_max_per_second(m_configuration.fscp.max_presentation_per_second); + m_fscp_server->set_hello_max_per_second(m_configuration.fscp.max_unauthenticated_messages_per_second); + m_fscp_server->set_presentation_max_per_second(m_configuration.fscp.max_unauthenticated_messages_per_second); m_fscp_server->set_hello_message_received_callback(boost::bind(&core::do_handle_hello_received, this, _1, _2)); m_fscp_server->set_contact_request_received_callback(boost::bind(&core::do_handle_contact_request_received, this, _1, _2, _3, _4)); diff --git a/libs/fscp/include/fscp/server.hpp b/libs/fscp/include/fscp/server.hpp index a0b19ff0..43bff72b 100644 --- a/libs/fscp/include/fscp/server.hpp +++ b/libs/fscp/include/fscp/server.hpp @@ -421,6 +421,15 @@ namespace fscp m_hello_message_received_handler = callback; } + /** + * \brief Set maximum hello message from one host per second. + * \param max_per_second value to set. + */ + void set_hello_max_per_second(size_t max_per_second) + { + m_hello_max_per_second = max_per_second; + } + /** * \brief Set the hello message received callback. * \param callback The callback. @@ -1413,6 +1422,12 @@ namespace fscp void do_set_accept_hello_messages_default(bool, void_handler_type); void do_set_hello_message_received_callback(hello_message_received_handler_type, void_handler_type); + /** + * \brief Reset hello limit. + * \param ec error code. + */ + void do_hello_reset_limit(const boost::system::error_code& ec); + ep_hello_context_map m_ep_hello_contexts; #if BOOST_ASIO_VERSION >= 101200 // Boost 1.66+ boost::asio::io_context::strand m_greet_strand; @@ -1422,6 +1437,21 @@ namespace fscp bool m_accept_hello_messages_default; hello_message_received_handler_type m_hello_message_received_handler; + /** + * \brief Current number of session request sent per endpoint. + */ + std::map m_hello_requests_map; + + /** + * \brief Timer for reesting hello requests limit. + */ + boost::asio::deadline_timer m_hello_limit_timer; + + /** + * \brief Maximum hello message from one host per second. + */ + size_t m_hello_max_per_second; + private: // PRESENTATION messages typedef std::map presentation_store_map; @@ -1435,14 +1465,14 @@ namespace fscp void handle_presentation_message_from(const identity_store&, const presentation_message&, const ep_type&); void do_handle_presentation(const identity_store& identity, const ep_type&, bool, cert_type); + void do_set_presentation_message_received_callback(presentation_message_received_handler_type, void_handler_type); + /** * \brief Reset presentation limit. * \param ec error code. */ void do_presentation_reset_limit(const boost::system::error_code& ec); - void do_set_presentation_message_received_callback(presentation_message_received_handler_type, void_handler_type); - // This strand is also used by session requests and session messages during the cipherment/decipherment phase. #if BOOST_ASIO_VERSION >= 101200 // Boost 1.66+ boost::asio::io_context::strand m_presentation_strand; diff --git a/libs/fscp/src/server.cpp b/libs/fscp/src/server.cpp index 76a2e33a..d96d6804 100644 --- a/libs/fscp/src/server.cpp +++ b/libs/fscp/src/server.cpp @@ -225,6 +225,8 @@ namespace fscp m_greet_strand(io_service), m_accept_hello_messages_default(true), m_hello_message_received_handler(), + m_hello_limit_timer(io_service, boost::posix_time::seconds(10)), + m_hello_max_per_second(1), m_presentation_strand(io_service), m_presentation_message_received_handler(), m_presentation_limit_timer(io_service, boost::posix_time::seconds(10)), @@ -320,6 +322,7 @@ namespace fscp m_keep_alive_timer.cancel(); + m_hello_limit_timer.cancel(); m_presentation_limit_timer.cancel(); m_socket.close(); @@ -1255,6 +1258,27 @@ namespace fscp void server::do_handle_hello_request(const ep_type& sender, uint32_t hello_unique_number) { // All do_handle_hello_request() calls are done in the same strand so the following is thread-safe. + std::map::iterator sender_hello = m_hello_requests_map.find(sender); + + if(sender_hello == m_hello_requests_map.end()) + { + // new hello + m_hello_requests_map[sender] = 1; + } + else if(m_hello_requests_map[sender] >= (m_hello_max_per_second * 10)) + { + // in 10s we have reach limits! Presentation flood? + m_logger(log_level::warning) << + "Received too many HELLO messages from " << sender << + ", limit is " << (m_hello_max_per_second * 10) << + " messages per 10 seconds"; + return; + } + else + { + m_hello_requests_map[sender]++; + } + bool can_reply = m_accept_hello_messages_default; if (m_hello_message_received_handler) @@ -1295,6 +1319,21 @@ namespace fscp } } + void server::do_hello_reset_limit(const boost::system::error_code& ec) + { + // All do_hello_reset_limit calls are done in the same strand so the following is thread-safe. + if (ec != boost::asio::error::operation_aborted) + { + m_hello_requests_map.clear(); + + // rearm timer again + m_hello_limit_timer.expires_from_now(boost::posix_time::seconds(10)); + m_hello_limit_timer.async_wait(m_greet_strand.wrap( + boost::bind(&server::do_hello_reset_limit, this, + boost::asio::placeholders::error))); + } + } + void server::do_set_hello_message_received_callback(hello_message_received_handler_type callback, void_handler_type handler) { // All do_set_hello_message_received_callback() calls are done in the same strand so the following is thread-safe. @@ -1422,7 +1461,6 @@ namespace fscp void server::do_handle_presentation(const identity_store& identity, const ep_type& sender, bool has_session, cert_type signature_certificate) { // All do_handle_presentation() calls are done in the same strand so the following is thread-safe. - std::map::iterator sender_presentation = m_presentation_requests_map.find(sender); if(sender_presentation == m_presentation_requests_map.end()) @@ -1437,7 +1475,6 @@ namespace fscp "Received too many PRESENTATION messages from " << sender << ", limit is " << (m_presentation_max_per_second * 10) << " messages per 10 seconds"; - return; } else