mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-10-14 02:22:03 +08:00
enforce of IP banning was moved to main
This commit is contained in:
+9
-4
@@ -211,11 +211,16 @@ auth-timeout = 40
|
|||||||
|
|
||||||
# The time (in seconds) that a client is not allowed to reconnect after
|
# The time (in seconds) that a client is not allowed to reconnect after
|
||||||
# a failed authentication attempt.
|
# a failed authentication attempt.
|
||||||
min-reauth-time = 120
|
min-reauth-time = 300
|
||||||
|
|
||||||
# The maximum number of password retries before applying the min-reauth-time
|
# Banning clients in ocserv works with a point system. IP addresses
|
||||||
# delay. Set to zero to disable.
|
# that get a score over that configured number are banned for
|
||||||
max-password-retries = 5
|
# min-reauth-time seconds. A wrong password attempt is 5 points.
|
||||||
|
# Set to zero to disable.
|
||||||
|
max-ban-score = 30
|
||||||
|
|
||||||
|
# The time (in seconds) that all score kept for a client is reset.
|
||||||
|
ban-reset-time = 300
|
||||||
|
|
||||||
# Cookie timeout (in seconds)
|
# Cookie timeout (in seconds)
|
||||||
# Once a client is authenticated he's provided a cookie with
|
# Once a client is authenticated he's provided a cookie with
|
||||||
|
|||||||
+2
-1
@@ -74,7 +74,7 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
|
|||||||
config.c worker-resume.c worker.h main-resume.c main.h \
|
config.c worker-resume.c worker.h main-resume.c main.h \
|
||||||
worker-extras.c html.c html.h worker-http.c \
|
worker-extras.c html.c html.h worker-http.c \
|
||||||
main-user.c worker-misc.c route-add.c route-add.h worker-privs.c \
|
main-user.c worker-misc.c route-add.c route-add.h worker-privs.c \
|
||||||
sec-mod.c sec-mod-db.c sec-mod-auth.c sec-mod-auth.h sec-mod.h sec-mod-ban.c \
|
sec-mod.c sec-mod-db.c sec-mod-auth.c sec-mod-auth.h sec-mod.h \
|
||||||
script-list.h $(COMMON_SOURCES) $(AUTH_SOURCES) $(ACCT_SOURCES) \
|
script-list.h $(COMMON_SOURCES) $(AUTH_SOURCES) $(ACCT_SOURCES) \
|
||||||
icmp-ping.c icmp-ping.h worker-kkdcp.c subconfig.c \
|
icmp-ping.c icmp-ping.h worker-kkdcp.c subconfig.c \
|
||||||
sec-mod-sup-config.c sec-mod-sup-config.h \
|
sec-mod-sup-config.c sec-mod-sup-config.h \
|
||||||
@@ -83,6 +83,7 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
|
|||||||
worker-bandwidth.c worker-bandwidth.h ctl.h main-ctl.h \
|
worker-bandwidth.c worker-bandwidth.h ctl.h main-ctl.h \
|
||||||
vasprintf.c vasprintf.h lzs.c lzs.h cfg.h \
|
vasprintf.c vasprintf.h lzs.c lzs.h cfg.h \
|
||||||
proc-search.c proc-search.h http-heads.h \
|
proc-search.c proc-search.h http-heads.h \
|
||||||
|
main-ban.c main-ban.h \
|
||||||
str.c str.h gettime.h $(CCAN_SOURCES) $(HTTP_PARSER_SOURCES) \
|
str.c str.h gettime.h $(CCAN_SOURCES) $(HTTP_PARSER_SOURCES) \
|
||||||
$(PROTOBUF_SOURCES) kkdcp.asn kkdcp_asn1_tab.c sec-mod-acct.h
|
$(PROTOBUF_SOURCES) kkdcp.asn kkdcp_asn1_tab.c sec-mod-acct.h
|
||||||
|
|
||||||
|
|||||||
+10
-5
@@ -80,7 +80,7 @@ static struct cfg_options available_options[] = {
|
|||||||
{ .name = "compression", .type = OPTION_BOOLEAN, .mandatory = 0 },
|
{ .name = "compression", .type = OPTION_BOOLEAN, .mandatory = 0 },
|
||||||
{ .name = "no-compress-limit", .type = OPTION_NUMERIC, .mandatory = 0 },
|
{ .name = "no-compress-limit", .type = OPTION_NUMERIC, .mandatory = 0 },
|
||||||
{ .name = "tcp-port", .type = OPTION_NUMERIC, .mandatory = 0 },
|
{ .name = "tcp-port", .type = OPTION_NUMERIC, .mandatory = 0 },
|
||||||
{ .name = "max-password-retries", .type = OPTION_NUMERIC, .mandatory = 0 },
|
{ .name = "max-ban-score", .type = OPTION_NUMERIC, .mandatory = 0 },
|
||||||
{ .name = "udp-port", .type = OPTION_NUMERIC, .mandatory = 0 },
|
{ .name = "udp-port", .type = OPTION_NUMERIC, .mandatory = 0 },
|
||||||
{ .name = "keepalive", .type = OPTION_NUMERIC, .mandatory = 0 },
|
{ .name = "keepalive", .type = OPTION_NUMERIC, .mandatory = 0 },
|
||||||
{ .name = "dpd", .type = OPTION_NUMERIC, .mandatory = 0 },
|
{ .name = "dpd", .type = OPTION_NUMERIC, .mandatory = 0 },
|
||||||
@@ -137,6 +137,7 @@ static struct cfg_options available_options[] = {
|
|||||||
{ .name = "mobile-idle-timeout", .type = OPTION_NUMERIC, .mandatory = 0 },
|
{ .name = "mobile-idle-timeout", .type = OPTION_NUMERIC, .mandatory = 0 },
|
||||||
{ .name = "max-clients", .type = OPTION_NUMERIC, .mandatory = 0 },
|
{ .name = "max-clients", .type = OPTION_NUMERIC, .mandatory = 0 },
|
||||||
{ .name = "min-reauth-time", .type = OPTION_NUMERIC, .mandatory = 0 },
|
{ .name = "min-reauth-time", .type = OPTION_NUMERIC, .mandatory = 0 },
|
||||||
|
{ .name = "ban-reset-time", .type = OPTION_NUMERIC, .mandatory = 0 },
|
||||||
{ .name = "max-same-clients", .type = OPTION_NUMERIC, .mandatory = 0 },
|
{ .name = "max-same-clients", .type = OPTION_NUMERIC, .mandatory = 0 },
|
||||||
|
|
||||||
{ .name = "rx-data-per-sec", .type = OPTION_NUMERIC, .mandatory = 0 },
|
{ .name = "rx-data-per-sec", .type = OPTION_NUMERIC, .mandatory = 0 },
|
||||||
@@ -818,11 +819,15 @@ unsigned urlfw_size = 0;
|
|||||||
|
|
||||||
READ_NUMERIC("max-clients", config->max_clients);
|
READ_NUMERIC("max-clients", config->max_clients);
|
||||||
READ_NUMERIC("min-reauth-time", config->min_reauth_time);
|
READ_NUMERIC("min-reauth-time", config->min_reauth_time);
|
||||||
|
config->ban_reset_time = -1;
|
||||||
|
READ_NUMERIC("ban-reset-time", config->ban_reset_time);
|
||||||
|
if (config->ban_reset_time == -1)
|
||||||
|
config->ban_reset_time = DEFAULT_BAN_RESET_TIME;
|
||||||
|
|
||||||
config->max_password_retries = -1;
|
config->max_ban_score = -1;
|
||||||
READ_NUMERIC("max-password-retries", config->max_password_retries);
|
READ_NUMERIC("max-ban-score", config->max_ban_score);
|
||||||
if (config->max_password_retries == -1)
|
if (config->max_ban_score == -1)
|
||||||
config->max_password_retries = MAX_PASSWORD_TRIES;
|
config->max_ban_score = DEFAULT_MAX_BAN_SCORE;
|
||||||
|
|
||||||
READ_NUMERIC("max-same-clients", config->max_same_clients);
|
READ_NUMERIC("max-same-clients", config->max_same_clients);
|
||||||
|
|
||||||
|
|||||||
@@ -255,3 +255,10 @@ message sec_auth_session_reply_msg
|
|||||||
optional string explicit_ipv6 = 27;
|
optional string explicit_ipv6 = 27;
|
||||||
repeated string no_routes = 28;
|
repeated string no_routes = 28;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SEC_BAN_IP: sent from sec-mod to main */
|
||||||
|
message sec_auth_ban_ip
|
||||||
|
{
|
||||||
|
required string ip = 1;
|
||||||
|
required uint32 score = 2;
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,14 +38,16 @@
|
|||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <vpn.h>
|
#include <vpn.h>
|
||||||
#include <tlslib.h>
|
#include <tlslib.h>
|
||||||
#include <sec-mod.h>
|
#include <main.h>
|
||||||
|
#include <main-ban.h>
|
||||||
#include <ccan/hash/hash.h>
|
#include <ccan/hash/hash.h>
|
||||||
#include <ccan/htable/htable.h>
|
#include <ccan/htable/htable.h>
|
||||||
|
|
||||||
typedef struct ban_entry_st {
|
typedef struct ban_entry_st {
|
||||||
char ip[MAX_IP_STR];
|
char ip[MAX_IP_STR];
|
||||||
unsigned failed_attempts;
|
unsigned score;
|
||||||
|
|
||||||
|
time_t last_reset; /* the time its score counting started */
|
||||||
time_t expires; /* the time after the client is allowed to login */
|
time_t expires; /* the time after the client is allowed to login */
|
||||||
} ban_entry_st;
|
} ban_entry_st;
|
||||||
|
|
||||||
@@ -70,21 +72,23 @@ static bool ban_entry_cmp(const void *_c1, void *_c2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *sec_mod_ban_db_init(sec_mod_st *sec)
|
void *main_ban_db_init(main_server_st *s)
|
||||||
{
|
{
|
||||||
struct htable *db = talloc(sec, struct htable);
|
struct htable *db = talloc(s, struct htable);
|
||||||
if (db == NULL)
|
if (db == NULL) {
|
||||||
return NULL;
|
fprintf(stderr, "error initializing ban DB\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
htable_init(db, rehash, NULL);
|
htable_init(db, rehash, NULL);
|
||||||
sec->ban_db = db;
|
s->ban_db = db;
|
||||||
|
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sec_mod_ban_db_deinit(sec_mod_st *sec)
|
void main_ban_db_deinit(main_server_st *s)
|
||||||
{
|
{
|
||||||
struct htable *db = sec->ban_db;
|
struct htable *db = s->ban_db;
|
||||||
|
|
||||||
if (db != NULL) {
|
if (db != NULL) {
|
||||||
htable_clear(db);
|
htable_clear(db);
|
||||||
@@ -92,9 +96,9 @@ struct htable *db = sec->ban_db;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned sec_mod_ban_db_elems(sec_mod_st *sec)
|
unsigned main_ban_db_elems(main_server_st *s)
|
||||||
{
|
{
|
||||||
struct htable *db = sec->ban_db;
|
struct htable *db = s->ban_db;
|
||||||
|
|
||||||
if (db)
|
if (db)
|
||||||
return db->elems;
|
return db->elems;
|
||||||
@@ -102,12 +106,13 @@ struct htable *db = sec->ban_db;
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_ip_to_ban_list(sec_mod_st *sec, const char *ip, unsigned attempts, time_t reset_time)
|
void add_ip_to_ban_list(main_server_st *s, const char *ip, unsigned score)
|
||||||
{
|
{
|
||||||
struct htable *db = sec->ban_db;
|
struct htable *db = s->ban_db;
|
||||||
struct ban_entry_st *e;
|
struct ban_entry_st *e;
|
||||||
ban_entry_st t;
|
ban_entry_st t;
|
||||||
time_t now = time(0);
|
time_t now = time(0);
|
||||||
|
time_t reset_time = now + s->config->min_reauth_time;
|
||||||
|
|
||||||
if (db == NULL || ip == NULL || ip[0] == 0)
|
if (db == NULL || ip == NULL || ip[0] == 0)
|
||||||
return;
|
return;
|
||||||
@@ -124,24 +129,26 @@ void add_ip_to_ban_list(sec_mod_st *sec, const char *ip, unsigned attempts, time
|
|||||||
}
|
}
|
||||||
|
|
||||||
strlcpy(e->ip, ip, sizeof(e->ip));
|
strlcpy(e->ip, ip, sizeof(e->ip));
|
||||||
|
e->last_reset = now;
|
||||||
|
|
||||||
if (htable_add(db, rehash(e, NULL), e) == 0) {
|
if (htable_add(db, rehash(e, NULL), e) == 0) {
|
||||||
seclog(sec, LOG_INFO,
|
mslog(s, NULL, LOG_INFO,
|
||||||
"could not add ban entry to hash table");
|
"could not add ban entry to hash table");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (now > e->expires) {
|
if (now > e->last_reset + s->config->ban_reset_time) {
|
||||||
e->failed_attempts = 0;
|
e->score = 0;
|
||||||
|
e->last_reset = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e->failed_attempts += attempts;
|
e->score += score;
|
||||||
e->expires = reset_time;
|
e->expires = reset_time;
|
||||||
|
|
||||||
if (sec->config->max_password_retries > 0 && e->failed_attempts >= sec->config->max_password_retries) {
|
if (s->config->max_ban_score > 0 && e->score >= s->config->max_ban_score) {
|
||||||
seclog(sec, LOG_INFO,"added IP '%s' (with failed attempts %d) to ban list, will be reset at: %s", ip, e->failed_attempts, ctime(&reset_time));
|
mslog(s, NULL, LOG_INFO,"added IP '%s' (with score %d) to ban list, will be reset at: %s", ip, e->score, ctime(&reset_time));
|
||||||
} else {
|
} else {
|
||||||
seclog(sec, LOG_DEBUG,"added failed attempt for IP '%s' to ban list, will be reset at: %s", ip, ctime(&reset_time));
|
mslog(s, NULL, LOG_DEBUG,"added failed attempt for IP '%s' to ban list", ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -150,9 +157,9 @@ void add_ip_to_ban_list(sec_mod_st *sec, const char *ip, unsigned attempts, time
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_ip_from_ban_list(sec_mod_st *sec, const char *ip)
|
void remove_ip_from_ban_list(main_server_st *s, const char *ip)
|
||||||
{
|
{
|
||||||
struct htable *db = sec->ban_db;
|
struct htable *db = s->ban_db;
|
||||||
struct ban_entry_st *e;
|
struct ban_entry_st *e;
|
||||||
ban_entry_st t;
|
ban_entry_st t;
|
||||||
|
|
||||||
@@ -165,41 +172,42 @@ void remove_ip_from_ban_list(sec_mod_st *sec, const char *ip)
|
|||||||
|
|
||||||
e = htable_get(db, rehash(&t, NULL), ban_entry_cmp, &t);
|
e = htable_get(db, rehash(&t, NULL), ban_entry_cmp, &t);
|
||||||
if (e != NULL) { /* new entry */
|
if (e != NULL) { /* new entry */
|
||||||
e->failed_attempts = 0;
|
e->score = 0;
|
||||||
e->expires = 0;
|
e->expires = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned check_if_banned(sec_mod_st *sec, const char *ip)
|
unsigned check_if_banned(main_server_st *s, struct sockaddr_storage *addr, socklen_t addr_size)
|
||||||
{
|
{
|
||||||
struct htable *db = sec->ban_db;
|
struct htable *db = s->ban_db;
|
||||||
time_t now;
|
time_t now;
|
||||||
ban_entry_st t, *e;
|
ban_entry_st t, *e;
|
||||||
|
|
||||||
if (db == NULL || ip == NULL || ip[0] == 0)
|
if (db == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (human_addr2((struct sockaddr*)addr, addr_size, t.ip, sizeof(t.ip), 0) != NULL) {
|
||||||
/* pass the current time somehow */
|
/* pass the current time somehow */
|
||||||
now = time(0);
|
now = time(0);
|
||||||
strlcpy(t.ip, ip, sizeof(t.ip));
|
|
||||||
|
|
||||||
e = htable_get(db, rehash(&t, NULL), ban_entry_cmp, &t);
|
e = htable_get(db, rehash(&t, NULL), ban_entry_cmp, &t);
|
||||||
if (e != NULL) {
|
if (e != NULL) {
|
||||||
if (now > e->expires)
|
if (now > e->expires)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (sec->config->max_password_retries > 0 &&
|
if (s->config->max_ban_score > 0 &&
|
||||||
e->failed_attempts >= sec->config->max_password_retries)
|
e->score >= s->config->max_ban_score) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_banned_entries(sec_mod_st *sec)
|
void cleanup_banned_entries(main_server_st *s)
|
||||||
{
|
{
|
||||||
struct htable *db = sec->ban_db;
|
struct htable *db = s->ban_db;
|
||||||
ban_entry_st *t;
|
ban_entry_st *t;
|
||||||
struct htable_iter iter;
|
struct htable_iter iter;
|
||||||
time_t now = time(0);
|
time_t now = time(0);
|
||||||
@@ -209,7 +217,7 @@ void cleanup_banned_entries(sec_mod_st *sec)
|
|||||||
|
|
||||||
t = htable_first(db, &iter);
|
t = htable_first(db, &iter);
|
||||||
while (t != NULL) {
|
while (t != NULL) {
|
||||||
if (now >= t->expires) {
|
if (now >= t->expires && now > t->last_reset + s->config->ban_reset_time) {
|
||||||
htable_delval(db, &iter);
|
htable_delval(db, &iter);
|
||||||
talloc_free(t);
|
talloc_free(t);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Nikos Mavrogiannopoulos
|
||||||
|
*
|
||||||
|
* Author: Nikos Mavrogiannopoulos
|
||||||
|
*
|
||||||
|
* This file is part of ocserv.
|
||||||
|
*
|
||||||
|
* The GnuTLS is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
#ifndef MAIN_BAN_H
|
||||||
|
# define MAIN_BAN_H
|
||||||
|
|
||||||
|
# include "main.h"
|
||||||
|
|
||||||
|
void cleanup_banned_entries(main_server_st *s);
|
||||||
|
unsigned check_if_banned(main_server_st *s, struct sockaddr_storage *addr, socklen_t addr_size);
|
||||||
|
void add_ip_to_ban_list(main_server_st *s, const char *ip, unsigned score);
|
||||||
|
void remove_ip_from_ban_list(main_server_st *s, const char *ip);
|
||||||
|
unsigned main_ban_db_elems(main_server_st *s);
|
||||||
|
void main_ban_db_deinit(main_server_st *s);
|
||||||
|
void *main_ban_db_init(main_server_st *s);
|
||||||
|
|
||||||
|
#endif
|
||||||
+17
-3
@@ -35,8 +35,6 @@
|
|||||||
#include <gnutls/gnutls.h>
|
#include <gnutls/gnutls.h>
|
||||||
#include <gnutls/crypto.h>
|
#include <gnutls/crypto.h>
|
||||||
#include <tlslib.h>
|
#include <tlslib.h>
|
||||||
#include <sys/un.h>
|
|
||||||
#include <cloexec.h>
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
#include "setproctitle.h"
|
#include "setproctitle.h"
|
||||||
@@ -47,6 +45,7 @@
|
|||||||
|
|
||||||
#include <vpn.h>
|
#include <vpn.h>
|
||||||
#include <main.h>
|
#include <main.h>
|
||||||
|
#include <main-ban.h>
|
||||||
#include <ccan/list/list.h>
|
#include <ccan/list/list.h>
|
||||||
|
|
||||||
int handle_sec_mod_commands(main_server_st * s)
|
int handle_sec_mod_commands(main_server_st * s)
|
||||||
@@ -58,7 +57,7 @@ int handle_sec_mod_commands(main_server_st * s)
|
|||||||
uint8_t *raw;
|
uint8_t *raw;
|
||||||
int ret, raw_len, e;
|
int ret, raw_len, e;
|
||||||
void *pool = talloc_new(s);
|
void *pool = talloc_new(s);
|
||||||
//PROTOBUF_ALLOCATOR(pa, pool);
|
PROTOBUF_ALLOCATOR(pa, pool);
|
||||||
|
|
||||||
if (pool == NULL)
|
if (pool == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -112,6 +111,21 @@ int handle_sec_mod_commands(main_server_st * s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
case SM_CMD_AUTH_BAN_IP:{
|
||||||
|
SecAuthBanIp *tmsg;
|
||||||
|
|
||||||
|
tmsg = sec_auth_ban_ip__unpack(&pa, raw_len, raw);
|
||||||
|
if (tmsg == NULL) {
|
||||||
|
mslog(s, NULL, LOG_ERR, "error unpacking sec-mod data");
|
||||||
|
ret = ERR_BAD_COMMAND;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
add_ip_to_ban_list(s, tmsg->ip, tmsg->score);
|
||||||
|
|
||||||
|
sec_auth_ban_ip__free_unpacked(tmsg, &pa);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
mslog(s, NULL, LOG_ERR, "unknown CMD from sec-mod 0x%x.", (unsigned)cmd);
|
mslog(s, NULL, LOG_ERR, "unknown CMD from sec-mod 0x%x.", (unsigned)cmd);
|
||||||
ret = ERR_BAD_COMMAND;
|
ret = ERR_BAD_COMMAND;
|
||||||
|
|||||||
+12
-2
@@ -52,6 +52,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <main.h>
|
#include <main.h>
|
||||||
#include <main-ctl.h>
|
#include <main-ctl.h>
|
||||||
|
#include <main-ban.h>
|
||||||
#include <route-add.h>
|
#include <route-add.h>
|
||||||
#include <worker.h>
|
#include <worker.h>
|
||||||
#include <cookies.h>
|
#include <cookies.h>
|
||||||
@@ -633,6 +634,7 @@ void clear_lists(main_server_st *s)
|
|||||||
ip_lease_deinit(&s->ip_leases);
|
ip_lease_deinit(&s->ip_leases);
|
||||||
proc_table_deinit(s);
|
proc_table_deinit(s);
|
||||||
ctl_handler_deinit(s);
|
ctl_handler_deinit(s);
|
||||||
|
main_ban_db_deinit(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kill_children(main_server_st* s)
|
static void kill_children(main_server_st* s)
|
||||||
@@ -863,11 +865,12 @@ unsigned total = 10;
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we need to expire any cookies */
|
/* Check if we need to expire any data */
|
||||||
if (need_maintenance != 0) {
|
if (need_maintenance != 0) {
|
||||||
need_maintenance = 0;
|
need_maintenance = 0;
|
||||||
mslog(s, NULL, LOG_DEBUG, "performing maintenance");
|
mslog(s, NULL, LOG_DEBUG, "performing maintenance (banned IPs: %d)", main_ban_db_elems(s));
|
||||||
expire_tls_sessions(s);
|
expire_tls_sessions(s);
|
||||||
|
cleanup_banned_entries(s);
|
||||||
alarm(MAINTAINANCE_TIME(s));
|
alarm(MAINTAINANCE_TIME(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -943,6 +946,7 @@ int main(int argc, char** argv)
|
|||||||
tls_cache_init(s, &s->tls_db);
|
tls_cache_init(s, &s->tls_db);
|
||||||
ip_lease_init(&s->ip_leases);
|
ip_lease_init(&s->ip_leases);
|
||||||
proc_table_init(s);
|
proc_table_init(s);
|
||||||
|
main_ban_db_init(s);
|
||||||
|
|
||||||
sigemptyset(&blockset);
|
sigemptyset(&blockset);
|
||||||
sigemptyset(&emptyset);
|
sigemptyset(&emptyset);
|
||||||
@@ -1156,6 +1160,12 @@ int main(int argc, char** argv)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check_if_banned(s, &ws->remote_addr, ws->remote_addr_len) != 0) {
|
||||||
|
close(fd);
|
||||||
|
mslog(s, NULL, LOG_INFO, "Rejected connection from banned IP");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a command socket */
|
/* Create a command socket */
|
||||||
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, cmd_fd);
|
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, cmd_fd);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|||||||
@@ -181,6 +181,8 @@ typedef struct main_server_st {
|
|||||||
struct cookie_entry_db_st cookies;
|
struct cookie_entry_db_st cookies;
|
||||||
|
|
||||||
tls_sess_db_st tls_db;
|
tls_sess_db_st tls_db;
|
||||||
|
struct htable *ban_db;
|
||||||
|
|
||||||
tls_st *creds;
|
tls_st *creds;
|
||||||
|
|
||||||
uint8_t cookie_key[COOKIE_KEY_SIZE];
|
uint8_t cookie_key[COOKIE_KEY_SIZE];
|
||||||
|
|||||||
+8
-3
@@ -288,9 +288,14 @@ auth-timeout = 40
|
|||||||
# a failed authentication attempt.
|
# a failed authentication attempt.
|
||||||
min-reauth-time = 120
|
min-reauth-time = 120
|
||||||
|
|
||||||
# The maximum number of password retries before applying the min-reauth-time
|
# Banning clients in ocserv works with a point system. IP addresses
|
||||||
# delay. Set to zero to disable.
|
# that get a score over that configured number are banned for
|
||||||
max-password-retries = 5
|
# min-reauth-time seconds. A wrong password attempt is 5 points.
|
||||||
|
# Set to zero to disable.
|
||||||
|
max-ban-score = 30
|
||||||
|
|
||||||
|
# The time (in seconds) that all score kept for a client is reset.
|
||||||
|
ban-reset-time = 300
|
||||||
|
|
||||||
# Cookie timeout (in seconds)
|
# Cookie timeout (in seconds)
|
||||||
# Once a client is authenticated he's provided a cookie with
|
# Once a client is authenticated he's provided a cookie with
|
||||||
|
|||||||
+29
-15
@@ -72,6 +72,33 @@ void sec_auth_init(sec_mod_st * sec, struct cfg_st *config)
|
|||||||
config->acct.amod->global_init(sec, config->server_name, config->acct.additional);
|
config->acct.amod->global_init(sec, config->server_name, config->acct.additional);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void sec_mod_add_score_to_ip(sec_mod_st *sec, void *pool, const char *ip, unsigned points)
|
||||||
|
{
|
||||||
|
void *lpool;
|
||||||
|
int ret, e;
|
||||||
|
SecAuthBanIp msg = SEC_AUTH_BAN_IP__INIT;
|
||||||
|
|
||||||
|
msg.ip = (char*)ip;
|
||||||
|
msg.score = points;
|
||||||
|
|
||||||
|
lpool = talloc_new(pool);
|
||||||
|
if (lpool == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = send_msg(lpool, sec->cmd_fd, SM_CMD_AUTH_BAN_IP, &msg,
|
||||||
|
(pack_size_func) sec_auth_ban_ip__get_packed_size,
|
||||||
|
(pack_func) sec_auth_ban_ip__pack);
|
||||||
|
if (ret < 0) {
|
||||||
|
e = errno;
|
||||||
|
seclog(sec, LOG_WARNING, "error in sending BAN IP message: %s", strerror(e));
|
||||||
|
}
|
||||||
|
talloc_free(lpool);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static int generate_cookie(sec_mod_st * sec, client_entry_st * entry)
|
static int generate_cookie(sec_mod_st * sec, client_entry_st * entry)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@@ -272,7 +299,7 @@ int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int resu
|
|||||||
if (result == ERR_AUTH_CONTINUE) {
|
if (result == ERR_AUTH_CONTINUE) {
|
||||||
/* if the module allows multiple retries for the password */
|
/* if the module allows multiple retries for the password */
|
||||||
if (e->status != PS_AUTH_INIT && e->module && e->module->allows_retries) {
|
if (e->status != PS_AUTH_INIT && e->module && e->module->allows_retries) {
|
||||||
add_ip_to_ban_list(sec, e->auth_info.remote_ip, 1, time(0) + sec->config->min_reauth_time);
|
sec_mod_add_score_to_ip(sec, e, e->auth_info.remote_ip, PASSWORD_POINTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = send_sec_auth_reply_msg(cfd, sec, e);
|
ret = send_sec_auth_reply_msg(cfd, sec, e);
|
||||||
@@ -296,13 +323,12 @@ int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int resu
|
|||||||
seclog(sec, LOG_ERR, "could not send reply auth cmd.");
|
seclog(sec, LOG_ERR, "could not send reply auth cmd.");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
remove_ip_from_ban_list(sec, e->auth_info.remote_ip);
|
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
e->status = PS_AUTH_FAILED;
|
e->status = PS_AUTH_FAILED;
|
||||||
|
|
||||||
add_ip_to_ban_list(sec, e->auth_info.remote_ip, 1, time(0) + sec->config->min_reauth_time);
|
sec_mod_add_score_to_ip(sec, e, e->auth_info.remote_ip, PASSWORD_POINTS);
|
||||||
|
|
||||||
ret = send_sec_auth_reply(cfd, sec, e, AUTH__REP__FAILED);
|
ret = send_sec_auth_reply(cfd, sec, e, AUTH__REP__FAILED);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -484,12 +510,6 @@ int handle_sec_auth_cont(int cfd, sec_mod_st * sec, const SecAuthContMsg * req)
|
|||||||
client_entry_st *e;
|
client_entry_st *e;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (check_if_banned(sec, req->ip) != 0) {
|
|
||||||
seclog(sec, LOG_INFO,
|
|
||||||
"IP '%s' is banned", req->ip);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req->sid.len != SID_SIZE) {
|
if (req->sid.len != SID_SIZE) {
|
||||||
seclog(sec, LOG_ERR, "auth cont but with illegal sid size (%d)!",
|
seclog(sec, LOG_ERR, "auth cont but with illegal sid size (%d)!",
|
||||||
(int)req->sid.len);
|
(int)req->sid.len);
|
||||||
@@ -569,12 +589,6 @@ int handle_sec_auth_init(int cfd, sec_mod_st * sec, const SecAuthInitMsg * req)
|
|||||||
client_entry_st *e;
|
client_entry_st *e;
|
||||||
unsigned need_continue = 0;
|
unsigned need_continue = 0;
|
||||||
|
|
||||||
if (check_if_banned(sec, req->ip) != 0) {
|
|
||||||
seclog(sec, LOG_INFO,
|
|
||||||
"IP '%s' is banned", req->ip);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
e = new_client_entry(sec, req->ip);
|
e = new_client_entry(sec, req->ip);
|
||||||
if (e == NULL) {
|
if (e == NULL) {
|
||||||
seclog(sec, LOG_ERR, "cannot initialize memory");
|
seclog(sec, LOG_ERR, "cannot initialize memory");
|
||||||
|
|||||||
+3
-10
@@ -368,7 +368,6 @@ static void check_other_work(sec_mod_st *sec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
sec_mod_client_db_deinit(sec);
|
sec_mod_client_db_deinit(sec);
|
||||||
sec_mod_ban_db_deinit(sec);
|
|
||||||
talloc_free(sec);
|
talloc_free(sec);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
@@ -382,10 +381,8 @@ static void check_other_work(sec_mod_st *sec)
|
|||||||
if (need_maintainance) {
|
if (need_maintainance) {
|
||||||
seclog(sec, LOG_DEBUG, "performing maintenance");
|
seclog(sec, LOG_DEBUG, "performing maintenance");
|
||||||
cleanup_client_entries(sec);
|
cleanup_client_entries(sec);
|
||||||
cleanup_banned_entries(sec);
|
seclog(sec, LOG_DEBUG, "active sessions %d",
|
||||||
seclog(sec, LOG_DEBUG, "active sessions %d, banned entries %d",
|
sec_mod_client_db_elems(sec));
|
||||||
sec_mod_client_db_elems(sec),
|
|
||||||
sec_mod_ban_db_elems(sec));
|
|
||||||
alarm(MAINTAINANCE_TIME);
|
alarm(MAINTAINANCE_TIME);
|
||||||
need_maintainance = 0;
|
need_maintainance = 0;
|
||||||
}
|
}
|
||||||
@@ -492,7 +489,6 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f
|
|||||||
#ifdef DEBUG_LEAKS
|
#ifdef DEBUG_LEAKS
|
||||||
talloc_enable_leak_report_full();
|
talloc_enable_leak_report_full();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sigemptyset(&blockset);
|
sigemptyset(&blockset);
|
||||||
sigemptyset(&emptyset);
|
sigemptyset(&emptyset);
|
||||||
sigaddset(&blockset, SIGALRM);
|
sigaddset(&blockset, SIGALRM);
|
||||||
@@ -538,6 +534,7 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f
|
|||||||
alarm(MAINTAINANCE_TIME);
|
alarm(MAINTAINANCE_TIME);
|
||||||
|
|
||||||
sec_auth_init(sec, config);
|
sec_auth_init(sec, config);
|
||||||
|
sec->cmd_fd = cmd_fd;
|
||||||
|
|
||||||
#ifdef HAVE_PKCS11
|
#ifdef HAVE_PKCS11
|
||||||
ret = gnutls_pkcs11_reinit();
|
ret = gnutls_pkcs11_reinit();
|
||||||
@@ -552,10 +549,6 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->min_reauth_time > 0)
|
|
||||||
sec_mod_ban_db_init(sec);
|
|
||||||
|
|
||||||
|
|
||||||
sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (sd == -1) {
|
if (sd == -1) {
|
||||||
e = errno;
|
e = errno;
|
||||||
|
|||||||
+1
-9
@@ -34,7 +34,7 @@ typedef struct sec_mod_st {
|
|||||||
gnutls_privkey_t *key;
|
gnutls_privkey_t *key;
|
||||||
unsigned key_size;
|
unsigned key_size;
|
||||||
struct htable *client_db;
|
struct htable *client_db;
|
||||||
struct htable *ban_db;
|
int cmd_fd;
|
||||||
|
|
||||||
struct config_mod_st *config_module;
|
struct config_mod_st *config_module;
|
||||||
} sec_mod_st;
|
} sec_mod_st;
|
||||||
@@ -127,12 +127,4 @@ void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e);
|
|||||||
void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_file,
|
void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_file,
|
||||||
uint8_t cookie_key[COOKIE_KEY_SIZE], int cmd_fd);
|
uint8_t cookie_key[COOKIE_KEY_SIZE], int cmd_fd);
|
||||||
|
|
||||||
void cleanup_banned_entries(sec_mod_st *sec);
|
|
||||||
unsigned check_if_banned(sec_mod_st *sec, const char *ip);
|
|
||||||
void add_ip_to_ban_list(sec_mod_st *sec, const char *ip, unsigned attempts, time_t reset_time);
|
|
||||||
void remove_ip_from_ban_list(sec_mod_st *sec, const char *ip);
|
|
||||||
void *sec_mod_ban_db_init(sec_mod_st *sec);
|
|
||||||
void sec_mod_ban_db_deinit(sec_mod_st *sec);
|
|
||||||
unsigned sec_mod_ban_db_elems(sec_mod_st *sec);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <minmax.h>
|
#include <minmax.h>
|
||||||
|
#include <auth/common.h>
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
# define _OCSERV_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
# define _OCSERV_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||||
@@ -56,6 +57,14 @@ typedef enum {
|
|||||||
OC_COMP_LZS,
|
OC_COMP_LZS,
|
||||||
} comp_type_t;
|
} comp_type_t;
|
||||||
|
|
||||||
|
/* Banning works with a point system. A wrong password
|
||||||
|
* attempt gives you PASSWORD_POINTS, and you are banned
|
||||||
|
* when the maximum ban score is reached.
|
||||||
|
*/
|
||||||
|
#define PASSWORD_POINTS 5
|
||||||
|
#define DEFAULT_MAX_BAN_SCORE (MAX_PASSWORD_TRIES*PASSWORD_POINTS)
|
||||||
|
#define DEFAULT_BAN_RESET_TIME 300
|
||||||
|
|
||||||
#define MIN_NO_COMPRESS_LIMIT 64
|
#define MIN_NO_COMPRESS_LIMIT 64
|
||||||
#define DEFAULT_NO_COMPRESS_LIMIT 256
|
#define DEFAULT_NO_COMPRESS_LIMIT 256
|
||||||
|
|
||||||
@@ -134,15 +143,19 @@ typedef enum {
|
|||||||
CMD_SESSION_INFO = 13,
|
CMD_SESSION_INFO = 13,
|
||||||
CMD_CLI_STATS = 15,
|
CMD_CLI_STATS = 15,
|
||||||
|
|
||||||
|
/* from worker to sec-mod */
|
||||||
SM_CMD_AUTH_INIT = 120,
|
SM_CMD_AUTH_INIT = 120,
|
||||||
SM_CMD_AUTH_CONT,
|
SM_CMD_AUTH_CONT,
|
||||||
SM_CMD_AUTH_REP,
|
SM_CMD_AUTH_REP,
|
||||||
SM_CMD_DECRYPT,
|
SM_CMD_DECRYPT,
|
||||||
SM_CMD_SIGN,
|
SM_CMD_SIGN,
|
||||||
|
SM_CMD_CLI_STATS,
|
||||||
|
|
||||||
|
/* from main to sec-mod and vice versa */
|
||||||
SM_CMD_AUTH_SESSION_OPEN,
|
SM_CMD_AUTH_SESSION_OPEN,
|
||||||
SM_CMD_AUTH_SESSION_CLOSE,
|
SM_CMD_AUTH_SESSION_CLOSE,
|
||||||
SM_CMD_AUTH_SESSION_REPLY,
|
SM_CMD_AUTH_SESSION_REPLY,
|
||||||
SM_CMD_CLI_STATS,
|
SM_CMD_AUTH_BAN_IP,
|
||||||
} cmd_request_t;
|
} cmd_request_t;
|
||||||
|
|
||||||
#define MAX_IP_STR 46
|
#define MAX_IP_STR 46
|
||||||
@@ -307,7 +320,8 @@ struct cfg_st {
|
|||||||
unsigned rekey_method; /* REKEY_METHOD_ */
|
unsigned rekey_method; /* REKEY_METHOD_ */
|
||||||
|
|
||||||
time_t min_reauth_time; /* after a failed auth, how soon one can reauthenticate -> in seconds */
|
time_t min_reauth_time; /* after a failed auth, how soon one can reauthenticate -> in seconds */
|
||||||
int max_password_retries; /* the number of retries allowed prior to applying min_reauth_time */
|
int max_ban_score; /* the score allowed before a user is banned (see vpn.h) */
|
||||||
|
int ban_reset_time;
|
||||||
|
|
||||||
unsigned isolate; /* whether seccomp should be enabled or not */
|
unsigned isolate; /* whether seccomp should be enabled or not */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user