diff --git a/apps/freelan/config/freelan.cfg b/apps/freelan/config/freelan.cfg index f0c4785e..d97ab3b1 100644 --- a/apps/freelan/config/freelan.cfg +++ b/apps/freelan/config/freelan.cfg @@ -333,6 +333,13 @@ public_endpoint=0.0.0.0 # Default: yes #upnp_enabled=yes +# Maximum PRESENTATION message from one host allowed per second. +# +# This is a way to mitigates PRESENTATION flood attack. +# +# Default: 1 +#max_presentation_per_second=1 + [tap_adapter] # The tap adapter type. diff --git a/apps/freelan/src/configuration_helper.cpp b/apps/freelan/src/configuration_helper.cpp index 4394fcaa..121d5544 100644 --- a/apps/freelan/src/configuration_helper.cpp +++ b/apps/freelan/src/configuration_helper.cpp @@ -292,6 +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.") ; return result; @@ -463,6 +464,8 @@ void setup_configuration(const fscp::logger& logger, fl::configuration& configur configuration.fscp.never_contact_list = vm["fscp.never_contact"].as>(); 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(); // 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 b8e1a9f3..79590552 100644 --- a/libs/freelan/include/freelan/configuration.hpp +++ b/libs/freelan/include/freelan/configuration.hpp @@ -321,6 +321,11 @@ namespace freelan * \brief State of UPnP. */ bool upnp_enabled; + + /* + * \brief Maximum PRESENTATION message from one host per second. + */ + size_t max_presentation_per_second; }; /** diff --git a/libs/freelan/src/core.cpp b/libs/freelan/src/core.cpp index 2f55cca5..ab9a72a3 100644 --- a/libs/freelan/src/core.cpp +++ b/libs/freelan/src/core.cpp @@ -632,6 +632,7 @@ 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_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 687d9023..a0b19ff0 100644 --- a/libs/fscp/include/fscp/server.hpp +++ b/libs/fscp/include/fscp/server.hpp @@ -553,6 +553,15 @@ namespace fscp m_presentation_message_received_handler = callback; } + /** + * \brief Set maximum presentation message from one host per second. + * \param max_per_second value to set. + */ + void set_presentation_max_per_second(size_t max_per_second) + { + m_presentation_max_per_second = max_per_second; + } + /** * \brief Set the presentation message received callback. * \param callback The callback. @@ -1444,9 +1453,9 @@ namespace fscp presentation_message_received_handler_type m_presentation_message_received_handler; /** - * \brief Current number of session request sent. + * \brief Current number of session request sent per endpoint. */ - size_t m_presentation_requests; + std::map m_presentation_requests_map; /** * \brief Timer for reesting presentation requests limit. @@ -1454,9 +1463,9 @@ namespace fscp boost::asio::deadline_timer m_presentation_limit_timer; /** - * \brief maximum number of session request. + * \brief Maximum presentation message from one host per second. */ - static const size_t MAX_PRESENTATION_REQUESTS; + size_t m_presentation_max_per_second; private: // SESSION_REQUEST messages diff --git a/libs/fscp/src/server.cpp b/libs/fscp/src/server.cpp index 3c69f5b8..76a2e33a 100644 --- a/libs/fscp/src/server.cpp +++ b/libs/fscp/src/server.cpp @@ -214,8 +214,6 @@ namespace fscp } } - const size_t server::MAX_PRESENTATION_REQUESTS = 512; - // Public methods server::server(boost::asio::io_service& io_service, fscp::logger& _logger, const identity_store& identity) : @@ -229,8 +227,8 @@ namespace fscp m_hello_message_received_handler(), m_presentation_strand(io_service), m_presentation_message_received_handler(), - m_presentation_requests(0), m_presentation_limit_timer(io_service, boost::posix_time::seconds(10)), + m_presentation_max_per_second(1), m_session_strand(io_service), m_accept_session_request_messages_default(true), m_cipher_suites(get_default_cipher_suites()), @@ -1424,15 +1422,28 @@ 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. - if(m_presentation_requests <= MAX_PRESENTATION_REQUESTS) + + std::map::iterator sender_presentation = m_presentation_requests_map.find(sender); + + if(sender_presentation == m_presentation_requests_map.end()) { - m_presentation_requests++; + // new presentation + m_presentation_requests_map[sender] = 1; } - else + else if(m_presentation_requests_map[sender] >= (m_presentation_max_per_second * 10)) { - // presentation flood? + // in 10s we have reach limits! Presentation flood? + m_logger(log_level::warning) << + "Received too many PRESENTATION messages from " << sender << + ", limit is " << (m_presentation_max_per_second * 10) << + " messages per 10 seconds"; + return; } + else + { + m_presentation_requests_map[sender]++; + } presentation_status_type presentation_status = PS_FIRST; @@ -1466,7 +1477,7 @@ namespace fscp // All do_presentation_reset_limit calls are done in the same strand so the following is thread-safe. if (ec != boost::asio::error::operation_aborted) { - m_presentation_requests = 0; + m_presentation_requests_map.clear(); // rearm timer again m_presentation_limit_timer.expires_from_now(boost::posix_time::seconds(10));