mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 00:37:00 +08:00
Allow setting a reconnection delay time after a failed authentication attempt (added min-reauth-time option).
This commit is contained in:
2
NEWS
2
NEWS
@@ -8,6 +8,8 @@
|
||||
enable non-openconnect clients to connect. They are enabled with
|
||||
the configure option --enable-anyconnect-compat.
|
||||
- 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)
|
||||
|
||||
|
||||
@@ -85,6 +85,10 @@ tls-priorities = "PERFORMANCE:%SERVER_PRECEDENCE"
|
||||
# to authentication
|
||||
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)
|
||||
# Once a client is authenticated he's provided a cookie with
|
||||
# which he can reconnect. This option sets the maximum lifetime
|
||||
|
||||
@@ -176,6 +176,7 @@ unsigned j;
|
||||
READ_NUMERIC("cookie-validity", config->cookie_validity, 1);
|
||||
READ_NUMERIC("auth-timeout", config->auth_timeout, 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);
|
||||
|
||||
val = optionGetValue(pov, "run-as-user"); \
|
||||
|
||||
@@ -261,7 +261,7 @@ unsigned int entries = 1; /* that one */
|
||||
if (s->config->max_same_clients == 0)
|
||||
return 0; /* ok */
|
||||
|
||||
list_for_each(&s->clist->head, ctmp, list) {
|
||||
list_for_each(&s->clist.head, ctmp, list) {
|
||||
|
||||
if (ctmp != proc) {
|
||||
if (strcmp(proc->username, ctmp->username) == 0) {
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
char buf[128];
|
||||
uint8_t cmd;
|
||||
struct msghdr hdr;
|
||||
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;
|
||||
} cmd_data;
|
||||
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));
|
||||
|
||||
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);
|
||||
if (ret == -1) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
add_to_ip_ban_list(s, &proc->remote_addr, proc->remote_addr_len);
|
||||
}
|
||||
|
||||
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);
|
||||
ret = send_auth_reply( s, proc, REP_AUTH_FAILED, NULL);
|
||||
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;
|
||||
goto lease_cleanup;
|
||||
}
|
||||
@@ -301,3 +300,67 @@ lease_cleanup:
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
52
src/main.c
52
src/main.c
@@ -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)
|
||||
{
|
||||
struct listener_st *ltmp, *lpos;
|
||||
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);
|
||||
list_del(<mp->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)
|
||||
close(ctmp->fd);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -376,7 +383,7 @@ static void kill_children(main_server_st* s)
|
||||
{
|
||||
struct proc_st *ctmp;
|
||||
|
||||
list_for_each(&s->clist->head, ctmp, list) {
|
||||
list_for_each(&s->clist.head, ctmp, list) {
|
||||
if (ctmp->pid != -1) {
|
||||
kill(ctmp->pid, SIGTERM);
|
||||
user_disconnected(s, ctmp);
|
||||
@@ -455,7 +462,7 @@ int connected = 0;
|
||||
session_id = &buffer[RECORD_PAYLOAD_POS+HANDSHAKE_SESSION_ID_POS+1];
|
||||
|
||||
/* 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 &&
|
||||
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");
|
||||
expire_tls_sessions(s);
|
||||
expire_cookies(s);
|
||||
expire_banned(s);
|
||||
alarm(MAINTAINANCE_TIME(s));
|
||||
}
|
||||
|
||||
@@ -548,8 +556,6 @@ static int check_tcp_wrapper(int fd)
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int fd, pid, e;
|
||||
struct listen_list_st llist;
|
||||
struct proc_list_st clist;
|
||||
struct listener_st *ltmp;
|
||||
struct proc_st *ctmp, *cpos;
|
||||
struct tun_st tun;
|
||||
@@ -564,7 +570,8 @@ int main(int argc, char** argv)
|
||||
|
||||
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);
|
||||
tls_cache_init(&s.tls_db);
|
||||
|
||||
@@ -594,8 +601,6 @@ int main(int argc, char** argv)
|
||||
|
||||
s.config = &config;
|
||||
s.tun = &tun;
|
||||
s.llist = &llist;
|
||||
s.clist = &clist;
|
||||
|
||||
ret = cookie_db_init(&s);
|
||||
if (ret < 0) {
|
||||
@@ -604,7 +609,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
/* Listen to network ports */
|
||||
ret = listen_ports(&config, &llist, config.name);
|
||||
ret = listen_ports(&config, &s.llist, config.name);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Cannot listen to specified ports\n");
|
||||
exit(1);
|
||||
@@ -645,7 +650,7 @@ int main(int argc, char** argv)
|
||||
/* initialize select */
|
||||
FD_ZERO(&rd);
|
||||
|
||||
list_for_each(&llist.head, ltmp, list) {
|
||||
list_for_each(&s.llist.head, ltmp, list) {
|
||||
if (ltmp->fd == -1) continue;
|
||||
|
||||
val = fcntl(ltmp->fd, F_GETFL, 0);
|
||||
@@ -661,7 +666,7 @@ int main(int argc, char** argv)
|
||||
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);
|
||||
n = MAX(n, ctmp->fd);
|
||||
}
|
||||
@@ -680,7 +685,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (set && ltmp->socktype == SOCK_STREAM) {
|
||||
/* connection on TCP port */
|
||||
@@ -693,6 +698,15 @@ int main(int argc, char** argv)
|
||||
}
|
||||
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) {
|
||||
close(fd);
|
||||
mslog(&s, NULL, LOG_INFO, "Reached maximum client limit (active: %u)", active_clients);
|
||||
@@ -756,7 +770,7 @@ fork_failed:
|
||||
ctmp->fd = cmd_fd[0];
|
||||
set_cloexec_flag (cmd_fd[0], 1);
|
||||
|
||||
list_add(&clist.head, &(ctmp->list));
|
||||
list_add(&s.clist.head, &(ctmp->list));
|
||||
active_clients++;
|
||||
}
|
||||
close(cmd_fd[1]);
|
||||
@@ -777,7 +791,7 @@ fork_failed:
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
ret = handle_commands(&s, ctmp);
|
||||
if (ret < 0) {
|
||||
|
||||
20
src/main.h
20
src/main.h
@@ -62,6 +62,17 @@ struct proc_list_st {
|
||||
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 {
|
||||
struct cfg_st *config;
|
||||
struct tun_st *tun;
|
||||
@@ -71,8 +82,9 @@ typedef struct main_server_st {
|
||||
/* tls credentials */
|
||||
struct tls_st creds;
|
||||
|
||||
struct listen_list_st* llist;
|
||||
struct proc_list_st* clist;
|
||||
struct listen_list_st llist;
|
||||
struct proc_list_st clist;
|
||||
struct ban_list_st ban_list;
|
||||
} main_server_st;
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* 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
|
||||
* and the template file options
|
||||
*
|
||||
|
||||
@@ -150,6 +150,10 @@ tls-priorities = "PERFORMANCE:%SERVER_PRECEDENCE"
|
||||
# to authentication
|
||||
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)
|
||||
# Once a client is authenticated he's provided a cookie with
|
||||
# which he can reconnect. This option sets the maximum lifetime
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* 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
|
||||
* and the template file options
|
||||
*
|
||||
|
||||
@@ -72,6 +72,7 @@ struct cfg_st {
|
||||
char *chroot_dir; /* where the xml files are served from */
|
||||
char *banner;
|
||||
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 keepalive;
|
||||
unsigned dpd;
|
||||
|
||||
Reference in New Issue
Block a user