Allow setting a reconnection delay time after a failed authentication attempt (added min-reauth-time option).

This commit is contained in:
Nikos Mavrogiannopoulos
2013-03-04 19:42:10 +01:00
parent 2674af5aec
commit 432a2da897
11 changed files with 135 additions and 30 deletions
+2
View File
@@ -8,6 +8,8 @@
enable non-openconnect clients to connect. They are enabled with enable non-openconnect clients to connect. They are enabled with
the configure option --enable-anyconnect-compat. the configure option --enable-anyconnect-compat.
- Allow setting a rate limit on the number of connections. - Allow setting a rate limit on the number of connections.
- Allow setting a reconnection delay time after a failed authentication
attempt (added min-reauth-time option).
* Version 0.0.1 (released 2013-02-20) * Version 0.0.1 (released 2013-02-20)
+4
View File
@@ -85,6 +85,10 @@ tls-priorities = "PERFORMANCE:%SERVER_PRECEDENCE"
# to authentication # to authentication
auth-timeout = 40 auth-timeout = 40
# The time (in seconds) that a client is not allowed to reconnect after a failed
# authentication attempt.
min-reauth-time = 10
# Cookie validity time (in seconds) # Cookie validity time (in seconds)
# Once a client is authenticated he's provided a cookie with # Once a client is authenticated he's provided a cookie with
# which he can reconnect. This option sets the maximum lifetime # which he can reconnect. This option sets the maximum lifetime
+1
View File
@@ -176,6 +176,7 @@ unsigned j;
READ_NUMERIC("cookie-validity", config->cookie_validity, 1); READ_NUMERIC("cookie-validity", config->cookie_validity, 1);
READ_NUMERIC("auth-timeout", config->auth_timeout, 0); READ_NUMERIC("auth-timeout", config->auth_timeout, 0);
READ_NUMERIC("max-clients", config->max_clients, 0); READ_NUMERIC("max-clients", config->max_clients, 0);
READ_NUMERIC("min-reauth-time", config->min_reauth_time, 0);
READ_NUMERIC("max-same-clients", config->max_same_clients, 0); READ_NUMERIC("max-same-clients", config->max_same_clients, 0);
val = optionGetValue(pov, "run-as-user"); \ val = optionGetValue(pov, "run-as-user"); \
+1 -1
View File
@@ -261,7 +261,7 @@ unsigned int entries = 1; /* that one */
if (s->config->max_same_clients == 0) if (s->config->max_same_clients == 0)
return 0; /* ok */ return 0; /* ok */
list_for_each(&s->clist->head, ctmp, list) { list_for_each(&s->clist.head, ctmp, list) {
if (ctmp != proc) { if (ctmp != proc) {
if (strcmp(proc->username, ctmp->username) == 0) { if (strcmp(proc->username, ctmp->username) == 0) {
+69 -6
View File
@@ -111,7 +111,6 @@ int send_udp_fd(main_server_st* s, struct proc_st * proc, int fd)
int handle_commands(main_server_st *s, struct proc_st* proc) int handle_commands(main_server_st *s, struct proc_st* proc)
{ {
struct iovec iov[2]; struct iovec iov[2];
char buf[128];
uint8_t cmd; uint8_t cmd;
struct msghdr hdr; struct msghdr hdr;
struct lease_st *lease; struct lease_st *lease;
@@ -123,10 +122,8 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
struct cmd_tun_mtu_st tmtu; struct cmd_tun_mtu_st tmtu;
} cmd_data; } cmd_data;
int ret, cmd_data_len, e; int ret, cmd_data_len, e;
const char* peer_ip, *group; const char* group;
peer_ip = human_addr((void*)&proc->remote_addr, proc->remote_addr_len, buf, sizeof(buf));
memset(&cmd_data, 0, sizeof(cmd_data)); memset(&cmd_data, 0, sizeof(cmd_data));
iov[0].iov_base = &cmd; iov[0].iov_base = &cmd;
@@ -142,7 +139,7 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
ret = recvmsg( proc->fd, &hdr, 0); ret = recvmsg( proc->fd, &hdr, 0);
if (ret == -1) { if (ret == -1) {
e = errno; e = errno;
mslog(s, proc, LOG_ERR, "cannot obtain data from command socket (pid: %d, peer: %s): %s", proc->pid, peer_ip, strerror(e)); mslog(s, proc, LOG_ERR, "cannot obtain data from command socket: %s", strerror(e));
return -1; return -1;
} }
@@ -241,6 +238,8 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
mslog(s, proc, LOG_INFO, "user '%s' disconnected due to script", proc->username); mslog(s, proc, LOG_INFO, "user '%s' disconnected due to script", proc->username);
} }
} }
} else {
add_to_ip_ban_list(s, &proc->remote_addr, proc->remote_addr_len);
} }
if (ret == 0) { if (ret == 0) {
@@ -275,7 +274,7 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
mslog(s, proc, LOG_INFO, "failed authentication attempt for user '%s'", proc->username); mslog(s, proc, LOG_INFO, "failed authentication attempt for user '%s'", proc->username);
ret = send_auth_reply( s, proc, REP_AUTH_FAILED, NULL); ret = send_auth_reply( s, proc, REP_AUTH_FAILED, NULL);
if (ret < 0) { if (ret < 0) {
mslog(s, proc, LOG_ERR, "could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip); mslog(s, proc, LOG_ERR, "could not send reply cmd.");
ret = -2; ret = -2;
goto lease_cleanup; goto lease_cleanup;
} }
@@ -301,3 +300,67 @@ lease_cleanup:
return 0; return 0;
} }
int check_if_banned(main_server_st* s, struct sockaddr_storage *addr, socklen_t addr_len)
{
time_t now = time(0);
struct banned_st *btmp, *bpos;
if (s->config->min_reauth_time == 0)
return 0;
list_for_each_safe(&s->ban_list.head, btmp, bpos, list) {
if (now-btmp->failed_time > s->config->min_reauth_time) {
/* invalid entry. Clean it up */
list_del(&btmp->list);
free(btmp);
}
if (SA_IN_SIZE(btmp->addr_len) == SA_IN_SIZE(addr_len) &&
memcmp(SA_IN_P_GENERIC(&btmp->addr, btmp->addr_len),
SA_IN_P_GENERIC(addr, addr_len),
SA_IN_SIZE(btmp->addr_len)) == 0) {
return -1;
}
}
return 0;
}
void expire_banned(main_server_st* s)
{
time_t now = time(0);
struct banned_st *btmp, *bpos;
if (s->config->min_reauth_time == 0)
return;
list_for_each_safe(&s->ban_list.head, btmp, bpos, list) {
if (now-btmp->failed_time > s->config->min_reauth_time) {
/* invalid entry. Clean it up */
list_del(&btmp->list);
free(btmp);
}
}
return;
}
void add_to_ip_ban_list(main_server_st* s, struct sockaddr_storage *addr, socklen_t addr_len)
{
struct banned_st *btmp;
if (s->config->min_reauth_time == 0)
return;
btmp = malloc(sizeof(*btmp));
if (btmp == NULL)
return;
btmp->failed_time = time(0);
memcpy(&btmp->addr, addr, addr_len);
btmp->addr_len = addr_len;
list_add(&s->ban_list.head, &(btmp->list));
}
+33 -19
View File
@@ -350,25 +350,32 @@ static void drop_privileges(main_server_st* s)
} }
} }
/* clears the server llist and clist. To be used after fork() */ /* clears the server llist and clist. To be used after fork().
* It frees unused memory and descriptors.
*/
void clear_lists(main_server_st *s) void clear_lists(main_server_st *s)
{ {
struct listener_st *ltmp, *lpos; struct listener_st *ltmp, *lpos;
struct proc_st *ctmp, *cpos; struct proc_st *ctmp, *cpos;
struct banned_st *btmp, *bpos;
list_for_each_safe(&s->llist->head, ltmp, lpos, list) { list_for_each_safe(&s->llist.head, ltmp, lpos, list) {
close(ltmp->fd); close(ltmp->fd);
list_del(&ltmp->list); list_del(&ltmp->list);
s->llist->total--; s->llist.total--;
} }
list_for_each_safe(&s->clist->head, ctmp, cpos, list) { list_for_each_safe(&s->clist.head, ctmp, cpos, list) {
if (ctmp->fd >= 0) if (ctmp->fd >= 0)
close(ctmp->fd); close(ctmp->fd);
list_del(&ctmp->list); list_del(&ctmp->list);
s->clist->total--; s->clist.total--;
} }
list_for_each_safe(&s->ban_list.head, btmp, bpos, list) {
list_del(&btmp->list);
}
tls_cache_deinit(s->tls_db); tls_cache_deinit(s->tls_db);
} }
@@ -376,7 +383,7 @@ static void kill_children(main_server_st* s)
{ {
struct proc_st *ctmp; struct proc_st *ctmp;
list_for_each(&s->clist->head, ctmp, list) { list_for_each(&s->clist.head, ctmp, list) {
if (ctmp->pid != -1) { if (ctmp->pid != -1) {
kill(ctmp->pid, SIGTERM); kill(ctmp->pid, SIGTERM);
user_disconnected(s, ctmp); user_disconnected(s, ctmp);
@@ -455,7 +462,7 @@ int connected = 0;
session_id = &buffer[RECORD_PAYLOAD_POS+HANDSHAKE_SESSION_ID_POS+1]; session_id = &buffer[RECORD_PAYLOAD_POS+HANDSHAKE_SESSION_ID_POS+1];
/* search for the IP and the session ID in all procs */ /* search for the IP and the session ID in all procs */
list_for_each(&s->clist->head, ctmp, list) { list_for_each(&s->clist.head, ctmp, list) {
if (session_id_size == ctmp->session_id_size && if (session_id_size == ctmp->session_id_size &&
memcmp(session_id, ctmp->session_id, session_id_size) == 0) { memcmp(session_id, ctmp->session_id, session_id_size) == 0) {
@@ -519,6 +526,7 @@ static void check_other_work(main_server_st *s)
mslog(s, NULL, LOG_INFO, "Performing maintainance"); mslog(s, NULL, LOG_INFO, "Performing maintainance");
expire_tls_sessions(s); expire_tls_sessions(s);
expire_cookies(s); expire_cookies(s);
expire_banned(s);
alarm(MAINTAINANCE_TIME(s)); alarm(MAINTAINANCE_TIME(s));
} }
@@ -548,8 +556,6 @@ static int check_tcp_wrapper(int fd)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
int fd, pid, e; int fd, pid, e;
struct listen_list_st llist;
struct proc_list_st clist;
struct listener_st *ltmp; struct listener_st *ltmp;
struct proc_st *ctmp, *cpos; struct proc_st *ctmp, *cpos;
struct tun_st tun; struct tun_st tun;
@@ -564,7 +570,8 @@ int main(int argc, char** argv)
memset(&s, 0, sizeof(s)); memset(&s, 0, sizeof(s));
list_head_init(&clist.head); list_head_init(&s.clist.head);
list_head_init(&s.ban_list.head);
tun_st_init(&tun); tun_st_init(&tun);
tls_cache_init(&s.tls_db); tls_cache_init(&s.tls_db);
@@ -594,8 +601,6 @@ int main(int argc, char** argv)
s.config = &config; s.config = &config;
s.tun = &tun; s.tun = &tun;
s.llist = &llist;
s.clist = &clist;
ret = cookie_db_init(&s); ret = cookie_db_init(&s);
if (ret < 0) { if (ret < 0) {
@@ -604,7 +609,7 @@ int main(int argc, char** argv)
} }
/* Listen to network ports */ /* Listen to network ports */
ret = listen_ports(&config, &llist, config.name); ret = listen_ports(&config, &s.llist, config.name);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Cannot listen to specified ports\n"); fprintf(stderr, "Cannot listen to specified ports\n");
exit(1); exit(1);
@@ -645,7 +650,7 @@ int main(int argc, char** argv)
/* initialize select */ /* initialize select */
FD_ZERO(&rd); FD_ZERO(&rd);
list_for_each(&llist.head, ltmp, list) { list_for_each(&s.llist.head, ltmp, list) {
if (ltmp->fd == -1) continue; if (ltmp->fd == -1) continue;
val = fcntl(ltmp->fd, F_GETFL, 0); val = fcntl(ltmp->fd, F_GETFL, 0);
@@ -661,7 +666,7 @@ int main(int argc, char** argv)
n = MAX(n, ltmp->fd); n = MAX(n, ltmp->fd);
} }
list_for_each(&clist.head, ctmp, list) { list_for_each(&s.clist.head, ctmp, list) {
FD_SET(ctmp->fd, &rd); FD_SET(ctmp->fd, &rd);
n = MAX(n, ctmp->fd); n = MAX(n, ctmp->fd);
} }
@@ -680,7 +685,7 @@ int main(int argc, char** argv)
} }
/* Check for new connections to accept */ /* Check for new connections to accept */
list_for_each(&llist.head, ltmp, list) { list_for_each(&s.llist.head, ltmp, list) {
set = FD_ISSET(ltmp->fd, &rd); set = FD_ISSET(ltmp->fd, &rd);
if (set && ltmp->socktype == SOCK_STREAM) { if (set && ltmp->socktype == SOCK_STREAM) {
/* connection on TCP port */ /* connection on TCP port */
@@ -693,6 +698,15 @@ int main(int argc, char** argv)
} }
set_cloexec_flag (fd, 1); set_cloexec_flag (fd, 1);
/* Check if the client is on the banned list */
ret = check_if_banned(&s, &ws.remote_addr, ws.remote_addr_len);
if (ret < 0) {
/* banned */
close(fd);
mslog(&s, NULL, LOG_INFO, "dropping client connection due to a previous failed authentication attempt");
break;
}
if (config.max_clients > 0 && active_clients >= config.max_clients) { if (config.max_clients > 0 && active_clients >= config.max_clients) {
close(fd); close(fd);
mslog(&s, NULL, LOG_INFO, "Reached maximum client limit (active: %u)", active_clients); mslog(&s, NULL, LOG_INFO, "Reached maximum client limit (active: %u)", active_clients);
@@ -756,7 +770,7 @@ fork_failed:
ctmp->fd = cmd_fd[0]; ctmp->fd = cmd_fd[0];
set_cloexec_flag (cmd_fd[0], 1); set_cloexec_flag (cmd_fd[0], 1);
list_add(&clist.head, &(ctmp->list)); list_add(&s.clist.head, &(ctmp->list));
active_clients++; active_clients++;
} }
close(cmd_fd[1]); close(cmd_fd[1]);
@@ -777,7 +791,7 @@ fork_failed:
} }
/* Check for any pending commands */ /* Check for any pending commands */
list_for_each_safe(&clist.head, ctmp, cpos, list) { list_for_each_safe(&s.clist.head, ctmp, cpos, list) {
if (FD_ISSET(ctmp->fd, &rd)) { if (FD_ISSET(ctmp->fd, &rd)) {
ret = handle_commands(&s, ctmp); ret = handle_commands(&s, ctmp);
if (ret < 0) { if (ret < 0) {
+18 -2
View File
@@ -62,6 +62,17 @@ struct proc_list_st {
unsigned int total; unsigned int total;
}; };
struct banned_st {
struct list_node list;
time_t failed_time; /* The time authentication failed */
struct sockaddr_storage addr; /* local socket address */
socklen_t addr_len;
};
struct ban_list_st {
struct list_head head;
};
typedef struct main_server_st { typedef struct main_server_st {
struct cfg_st *config; struct cfg_st *config;
struct tun_st *tun; struct tun_st *tun;
@@ -71,8 +82,9 @@ typedef struct main_server_st {
/* tls credentials */ /* tls credentials */
struct tls_st creds; struct tls_st creds;
struct listen_list_st* llist; struct listen_list_st llist;
struct proc_list_st* clist; struct proc_list_st clist;
struct ban_list_st ban_list;
} main_server_st; } main_server_st;
void clear_lists(main_server_st *s); void clear_lists(main_server_st *s);
@@ -117,4 +129,8 @@ int handle_auth_req(main_server_st *s, struct proc_st* proc,
int check_multiple_users(main_server_st *s, struct proc_st* proc); int check_multiple_users(main_server_st *s, struct proc_st* proc);
void add_to_ip_ban_list(main_server_st* s, struct sockaddr_storage *addr, socklen_t addr_len);
void expire_banned(main_server_st* s);
int check_if_banned(main_server_st* s, struct sockaddr_storage *addr, socklen_t addr_len);
#endif #endif
+1 -1
View File
@@ -2,7 +2,7 @@
* *
* DO NOT EDIT THIS FILE (ocserv-args.c) * DO NOT EDIT THIS FILE (ocserv-args.c)
* *
* It has been AutoGen-ed March 4, 2013 at 06:18:05 AM by AutoGen 5.16 * It has been AutoGen-ed March 4, 2013 at 07:36:47 PM by AutoGen 5.16
* From the definitions ocserv-args.def * From the definitions ocserv-args.def
* and the template file options * and the template file options
* *
+4
View File
@@ -150,6 +150,10 @@ tls-priorities = "PERFORMANCE:%SERVER_PRECEDENCE"
# to authentication # to authentication
auth-timeout = 40 auth-timeout = 40
# The time (in seconds) that a client is not allowed to reconnect after a failed
# authentication attempt.
min-reauth-time = 2
# Cookie validity time (in seconds) # Cookie validity time (in seconds)
# Once a client is authenticated he's provided a cookie with # Once a client is authenticated he's provided a cookie with
# which he can reconnect. This option sets the maximum lifetime # which he can reconnect. This option sets the maximum lifetime
+1 -1
View File
@@ -2,7 +2,7 @@
* *
* DO NOT EDIT THIS FILE (ocserv-args.h) * DO NOT EDIT THIS FILE (ocserv-args.h)
* *
* It has been AutoGen-ed March 4, 2013 at 06:18:05 AM by AutoGen 5.16 * It has been AutoGen-ed March 4, 2013 at 07:36:47 PM by AutoGen 5.16
* From the definitions ocserv-args.def * From the definitions ocserv-args.def
* and the template file options * and the template file options
* *
+1
View File
@@ -72,6 +72,7 @@ struct cfg_st {
char *chroot_dir; /* where the xml files are served from */ char *chroot_dir; /* where the xml files are served from */
char *banner; char *banner;
time_t cookie_validity; /* in seconds */ time_t cookie_validity; /* in seconds */
time_t min_reauth_time; /* after a failed auth, how soon one can reauthenticate -> in seconds */
unsigned auth_timeout; /* timeout of HTTP auth */ unsigned auth_timeout; /* timeout of HTTP auth */
unsigned keepalive; unsigned keepalive;
unsigned dpd; unsigned dpd;