diff --git a/include/maxscale/config.hh b/include/maxscale/config.hh index 1c78ad206..baa30bb7d 100644 --- a/include/maxscale/config.hh +++ b/include/maxscale/config.hh @@ -136,6 +136,7 @@ extern const char CN_LISTENERS[]; extern const char CN_LOCALHOST_MATCH_WILDCARD_HOST[]; extern const char CN_LOG_AUTH_WARNINGS[]; extern const char CN_LOG_THROTTLING[]; +extern const char CN_MAX_AUTH_FAILURES[]; extern const char CN_MAX_CONNECTIONS[]; extern const char CN_MAX_RETRY_INTERVAL[]; extern const char CN_MAXSCALE[]; @@ -549,6 +550,7 @@ struct MXS_CONFIG char peer_password[MAX_ADMIN_HOST_LEN]; /**< Password for maxscale-to-maxscale traffic */ mxb_log_target_t log_target; /**< Log type */ bool load_persisted_configs; /**< Load persisted configuration files on startup */ + int max_auth_failures; /**< Host is blocked once this limit is reached */ }; /** diff --git a/server/core/config.cc b/server/core/config.cc index 587f2e86a..38923b56e 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -127,6 +127,7 @@ const char CN_LOCALHOST_MATCH_WILDCARD_HOST[] = "localhost_match_wildcard_host"; const char CN_LOCAL_ADDRESS[] = "local_address"; const char CN_LOG_AUTH_WARNINGS[] = "log_auth_warnings"; const char CN_LOG_THROTTLING[] = "log_throttling"; +const char CN_MAX_AUTH_FAILURES[] = "max_auth_failures"; const char CN_MAXSCALE[] = "maxscale"; const char CN_MAX_CONNECTIONS[] = "max_connections"; const char CN_MAX_RETRY_INTERVAL[] = "max_retry_interval"; @@ -2753,6 +2754,20 @@ static int handle_global_item(const char* name, const char* value) return 0; } } + else if (strcmp(name, CN_MAX_AUTH_FAILURES) == 0) + { + char* endptr; + int intval = strtol(value, &endptr, 0); + if (*endptr == '\0' && intval > 0) + { + gateway.max_auth_failures = intval; + } + else + { + MXS_ERROR("Invalid value for '%s': %s", CN_MAX_AUTH_FAILURES, value); + return 0; + } + } else { bool found = false; @@ -2974,6 +2989,7 @@ void config_set_global_defaults() gateway.passive = false; gateway.promoted_at = 0; gateway.load_persisted_configs = true; + gateway.max_auth_failures = DEFAULT_MAX_AUTH_FAILURES; gateway.peer_hosts[0] = '\0'; gateway.peer_user[0] = '\0'; @@ -4709,6 +4725,7 @@ json_t* config_maxscale_to_json(const char* host) json_object_set_new(param, CN_RETAIN_LAST_STATEMENTS, json_integer(session_get_retain_last_statements())); json_object_set_new(param, CN_DUMP_LAST_STATEMENTS, json_string(session_get_dump_statements_str())); json_object_set_new(param, CN_LOAD_PERSISTED_CONFIGS, json_boolean(cnf->load_persisted_configs)); + json_object_set_new(param, CN_MAX_AUTH_FAILURES, json_integer(cnf->max_auth_failures)); json_t* attr = json_object(); time_t started = maxscale_started(); diff --git a/server/core/config_runtime.cc b/server/core/config_runtime.cc index c9f819107..1438b38f4 100644 --- a/server/core/config_runtime.cc +++ b/server/core/config_runtime.cc @@ -523,12 +523,12 @@ bool runtime_enable_server_ssl(Server* server, * @param value String value * @return 0 on error, otherwise a positive integer */ -static long get_positive_int(const char* value) +static int get_positive_int(const char* value) { char* endptr; long ival = strtol(value, &endptr, 10); - if (*endptr == '\0' && ival > 0) + if (*endptr == '\0' && ival > 0 && ival < std::numeric_limits::max()) { return ival; } @@ -605,7 +605,7 @@ bool runtime_alter_server(Server* server, const char* key, const char* value) } else if (strcmp(key, CN_PORT) == 0) { - if (long ival = get_positive_int(value)) + if (int ival = get_positive_int(value)) { server->update_port(ival); } @@ -1089,6 +1089,22 @@ bool runtime_alter_maxscale(const char* name, const char* value) CN_DUMP_LAST_STATEMENTS); } } + else if (key == CN_MAX_AUTH_FAILURES) + { + if (int intval = get_positive_int(value)) + { + MXS_NOTICE("Updated '%s' from %d to %d", + CN_MAX_AUTH_FAILURES, + cnf.max_auth_failures, + intval); + cnf.max_auth_failures = intval; + rval = true; + } + else + { + config_runtime_error("Invalid value for '%s': %s", CN_MAX_AUTH_FAILURES, value); + } + } else if (config_can_modify_at_runtime(key.c_str())) { config_runtime_error("Global parameter '%s' cannot be modified at runtime", name); diff --git a/server/core/internal/config.hh b/server/core/internal/config.hh index 1f6b2f790..515a218b7 100644 --- a/server/core/internal/config.hh +++ b/server/core/internal/config.hh @@ -32,6 +32,7 @@ #define DEFAULT_QUERY_RETRY_TIMEOUT 5 /**< Timeout for query retries */ #define MIN_WRITEQ_HIGH_WATER 4096UL /**< Min high water mark of dcb write queue */ #define MIN_WRITEQ_LOW_WATER 512UL /**< Min low water mark of dcb write queue */ +#define DEFAULT_MAX_AUTH_FAILURES 10 /**< Max allowed authentication failures */ /** * Maximum length for configuration parameter value. diff --git a/server/core/listener.cc b/server/core/listener.cc index da5963928..110e8bbe2 100644 --- a/server/core/listener.cc +++ b/server/core/listener.cc @@ -82,7 +82,7 @@ public: u.failures = 0; } - rval = u.failures >= MAX_FAILURES; + rval = u.failures >= config_get_global_options()->max_auth_failures; } return rval; @@ -92,7 +92,7 @@ private: struct Failure { Clock::time_point last_failure = Clock::now(); - uint32_t failures = 0; + int failures = 0; }; std::unordered_map m_failures;