mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-03-16 06:49:19 +08:00
When sending BAN IP messages to main receive a reply on whether further actions should continue
That allows to BAN a user even during an open connection.
This commit is contained in:
@@ -59,6 +59,10 @@ static char tmp[32];
|
||||
return "session info";
|
||||
case CMD_CLI_STATS:
|
||||
return "cli stats";
|
||||
case CMD_BAN_IP:
|
||||
return "ban IP";
|
||||
case CMD_BAN_IP_REPLY:
|
||||
return "ban IP reply";
|
||||
|
||||
case SM_CMD_CLI_STATS:
|
||||
return "sm: cli stats";
|
||||
@@ -76,6 +80,10 @@ static char tmp[32];
|
||||
return "sm: session close";
|
||||
case SM_CMD_AUTH_SESSION_OPEN:
|
||||
return "sm: session open";
|
||||
case SM_CMD_AUTH_BAN_IP:
|
||||
return "sm: ban IP";
|
||||
case SM_CMD_AUTH_BAN_IP_REPLY:
|
||||
return "sm: ban IP reply";
|
||||
default:
|
||||
snprintf(tmp, sizeof(tmp), "unknown (%u)", _cmd);
|
||||
return tmp;
|
||||
|
||||
@@ -144,6 +144,11 @@ message ban_ip_msg
|
||||
required uint32 score = 2;
|
||||
}
|
||||
|
||||
message ban_ip_reply_msg
|
||||
{
|
||||
/* whether to disconnect the user */
|
||||
required AUTH_REP reply = 1;
|
||||
}
|
||||
|
||||
/* Messages to and from the security module */
|
||||
|
||||
|
||||
@@ -92,7 +92,6 @@ void __attribute__ ((format(printf, 3, 4)))
|
||||
_oclog(const worker_st * ws, int priority, const char *fmt, ...)
|
||||
{
|
||||
char buf[512];
|
||||
char ipbuf[128];
|
||||
const char* ip;
|
||||
va_list args;
|
||||
|
||||
@@ -111,8 +110,7 @@ void __attribute__ ((format(printf, 3, 4)))
|
||||
priority = LOG_DEBUG;
|
||||
}
|
||||
|
||||
ip = human_addr((void*)&ws->remote_addr, ws->remote_addr_len,
|
||||
ipbuf, sizeof(ipbuf));
|
||||
ip = ws->remote_ip_str;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
|
||||
@@ -106,16 +106,18 @@ struct htable *db = s->ban_db;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void add_ip_to_ban_list(main_server_st *s, const char *ip, unsigned score)
|
||||
/* returns -1 if the user is already banned, and zero otherwise */
|
||||
int add_ip_to_ban_list(main_server_st *s, const char *ip, unsigned score)
|
||||
{
|
||||
struct htable *db = s->ban_db;
|
||||
struct ban_entry_st *e;
|
||||
ban_entry_st t;
|
||||
time_t now = time(0);
|
||||
time_t reset_time = now + s->config->min_reauth_time;
|
||||
int ret = 0;
|
||||
|
||||
if (db == NULL || ip == NULL || ip[0] == 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
/* check if the IP is already there */
|
||||
/* pass the current time somehow */
|
||||
@@ -125,7 +127,7 @@ void add_ip_to_ban_list(main_server_st *s, const char *ip, unsigned score)
|
||||
if (e == NULL) { /* new entry */
|
||||
e = talloc_zero(db, ban_entry_st);
|
||||
if (e == NULL) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
strlcpy(e->ip, ip, sizeof(e->ip));
|
||||
@@ -147,14 +149,16 @@ void add_ip_to_ban_list(main_server_st *s, const char *ip, unsigned score)
|
||||
|
||||
if (s->config->max_ban_score > 0 && e->score >= s->config->max_ban_score) {
|
||||
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));
|
||||
ret = -1;
|
||||
} else {
|
||||
mslog(s, NULL, LOG_DEBUG,"added %d points (total %d) for IP '%s' to ban list", score, e->score, ip);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
return ret;
|
||||
fail:
|
||||
talloc_free(e);
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void remove_ip_from_ban_list(main_server_st *s, const char *ip)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
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);
|
||||
int 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);
|
||||
|
||||
@@ -508,6 +508,7 @@ int handle_commands(main_server_st * s, struct proc_st *proc)
|
||||
switch (cmd) {
|
||||
case CMD_BAN_IP:{
|
||||
BanIpMsg *tmsg;
|
||||
BanIpReplyMsg reply = BAN_IP_REPLY_MSG__INIT;
|
||||
|
||||
tmsg = ban_ip_msg__unpack(&pa, raw_len, raw);
|
||||
if (tmsg == NULL) {
|
||||
@@ -515,11 +516,34 @@ int handle_commands(main_server_st * s, struct proc_st *proc)
|
||||
ret = ERR_BAD_COMMAND;
|
||||
goto cleanup;
|
||||
}
|
||||
add_ip_to_ban_list(s, tmsg->ip, tmsg->score);
|
||||
|
||||
ret = add_ip_to_ban_list(s, tmsg->ip, tmsg->score);
|
||||
|
||||
ban_ip_msg__free_unpacked(tmsg, &pa);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
reply.reply =
|
||||
AUTH__REP__FAILED;
|
||||
} else {
|
||||
reply.reply =
|
||||
AUTH__REP__OK;
|
||||
}
|
||||
|
||||
ret =
|
||||
send_msg_to_worker(s, NULL, CMD_BAN_IP_REPLY, &reply,
|
||||
(pack_size_func)
|
||||
ban_ip_reply_msg__get_packed_size,
|
||||
(pack_func)
|
||||
ban_ip_reply_msg__pack);
|
||||
|
||||
if (ret < 0) {
|
||||
mslog(s, NULL, LOG_ERR,
|
||||
"could not send reply cmd %d.",
|
||||
(unsigned)cmd);
|
||||
ret = ERR_BAD_COMMAND;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CMD_TUN_MTU:{
|
||||
TunMtuMsg *tmsg;
|
||||
|
||||
@@ -113,6 +113,7 @@ int handle_sec_mod_commands(main_server_st * s)
|
||||
switch (cmd) {
|
||||
case SM_CMD_AUTH_BAN_IP:{
|
||||
BanIpMsg *tmsg;
|
||||
BanIpReplyMsg reply = BAN_IP_REPLY_MSG__INIT;
|
||||
|
||||
tmsg = ban_ip_msg__unpack(&pa, raw_len, raw);
|
||||
if (tmsg == NULL) {
|
||||
@@ -120,9 +121,31 @@ int handle_sec_mod_commands(main_server_st * s)
|
||||
ret = ERR_BAD_COMMAND;
|
||||
goto cleanup;
|
||||
}
|
||||
add_ip_to_ban_list(s, tmsg->ip, tmsg->score);
|
||||
ret = add_ip_to_ban_list(s, tmsg->ip, tmsg->score);
|
||||
|
||||
ban_ip_msg__free_unpacked(tmsg, &pa);
|
||||
|
||||
if (ret < 0) {
|
||||
reply.reply =
|
||||
AUTH__REP__FAILED;
|
||||
} else {
|
||||
reply.reply =
|
||||
AUTH__REP__OK;
|
||||
}
|
||||
|
||||
|
||||
mslog(s, NULL, LOG_DEBUG, "sending msg %s to sec-mod", cmd_request_to_str(SM_CMD_AUTH_BAN_IP_REPLY));
|
||||
|
||||
ret = send_msg(NULL, s->sec_mod_fd, SM_CMD_AUTH_BAN_IP_REPLY,
|
||||
&reply, (pack_size_func)ban_ip_reply_msg__get_packed_size,
|
||||
(pack_func)ban_ip_reply_msg__pack);
|
||||
if (ret < 0) {
|
||||
mslog(s, NULL, LOG_ERR,
|
||||
"could not send reply cmd %d.",
|
||||
(unsigned)cmd);
|
||||
ret = ERR_BAD_COMMAND;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -72,19 +72,22 @@ void sec_auth_init(sec_mod_st * sec, struct cfg_st *config)
|
||||
config->acct.amod->global_init(sec, config->server_name, config->acct.additional);
|
||||
}
|
||||
|
||||
/* returns a negative number if we have reached the score for this client.
|
||||
*/
|
||||
static
|
||||
void sec_mod_add_score_to_ip(sec_mod_st *sec, void *pool, const char *ip, unsigned points)
|
||||
int sec_mod_add_score_to_ip(sec_mod_st *sec, void *pool, const char *ip, unsigned points)
|
||||
{
|
||||
void *lpool;
|
||||
void *lpool = talloc_new(pool);
|
||||
int ret, e;
|
||||
BanIpMsg msg = BAN_IP_MSG__INIT;
|
||||
BanIpReplyMsg *reply = NULL;
|
||||
PROTOBUF_ALLOCATOR(pa, lpool);
|
||||
|
||||
msg.ip = (char*)ip;
|
||||
msg.score = points;
|
||||
|
||||
lpool = talloc_new(pool);
|
||||
if (lpool == NULL) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = send_msg(lpool, sec->cmd_fd, SM_CMD_AUTH_BAN_IP, &msg,
|
||||
@@ -93,10 +96,30 @@ void sec_mod_add_score_to_ip(sec_mod_st *sec, void *pool, const char *ip, unsign
|
||||
if (ret < 0) {
|
||||
e = errno;
|
||||
seclog(sec, LOG_WARNING, "error in sending BAN IP message: %s", strerror(e));
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = recv_msg(lpool, sec->cmd_fd, SM_CMD_AUTH_BAN_IP_REPLY, (void*)&reply,
|
||||
(unpack_func) ban_ip_reply_msg__unpack);
|
||||
if (ret < 0) {
|
||||
seclog(sec, LOG_ERR, "error receiving BAN IP reply message");
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (reply->reply != AUTH__REP__OK) {
|
||||
/* we have exceeded the maximum score */
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
ban_ip_reply_msg__free_unpacked(reply, &pa);
|
||||
|
||||
fail:
|
||||
talloc_free(lpool);
|
||||
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int generate_cookie(sec_mod_st * sec, client_entry_st * entry)
|
||||
@@ -299,7 +322,11 @@ int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int resu
|
||||
if (result == ERR_AUTH_CONTINUE) {
|
||||
/* if the module allows multiple retries for the password */
|
||||
if (e->status != PS_AUTH_INIT && e->module && e->module->allows_retries) {
|
||||
sec_mod_add_score_to_ip(sec, e, e->auth_info.remote_ip, PASSWORD_POINTS);
|
||||
ret = sec_mod_add_score_to_ip(sec, e, e->auth_info.remote_ip, PASSWORD_POINTS);
|
||||
if (ret < 0) {
|
||||
e->status = PS_AUTH_FAILED;
|
||||
return send_sec_auth_reply(cfd, sec, e, AUTH__REP__FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
ret = send_sec_auth_reply_msg(cfd, sec, e);
|
||||
|
||||
@@ -145,6 +145,7 @@ typedef enum {
|
||||
CMD_SESSION_INFO = 13,
|
||||
CMD_CLI_STATS = 15,
|
||||
CMD_BAN_IP = 16,
|
||||
CMD_BAN_IP_REPLY = 17,
|
||||
|
||||
/* from worker to sec-mod */
|
||||
SM_CMD_AUTH_INIT = 120,
|
||||
@@ -155,10 +156,11 @@ typedef enum {
|
||||
SM_CMD_CLI_STATS,
|
||||
|
||||
/* from main to sec-mod and vice versa */
|
||||
SM_CMD_AUTH_SESSION_OPEN,
|
||||
SM_CMD_AUTH_SESSION_OPEN=240,
|
||||
SM_CMD_AUTH_SESSION_CLOSE,
|
||||
SM_CMD_AUTH_SESSION_REPLY,
|
||||
SM_CMD_AUTH_BAN_IP,
|
||||
SM_CMD_AUTH_BAN_IP_REPLY,
|
||||
} cmd_request_t;
|
||||
|
||||
#define MAX_IP_STR 46
|
||||
|
||||
@@ -1167,7 +1167,6 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
|
||||
char *username = NULL;
|
||||
char *password = NULL;
|
||||
char *groupname = NULL;
|
||||
char ipbuf[128];
|
||||
char *msg = NULL;
|
||||
unsigned def_group = 0;
|
||||
|
||||
@@ -1265,9 +1264,7 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
|
||||
}
|
||||
|
||||
ireq.hostname = req->hostname;
|
||||
ireq.ip =
|
||||
human_addr2((void *)&ws->remote_addr, ws->remote_addr_len,
|
||||
ipbuf, sizeof(ipbuf), 0);
|
||||
ireq.ip = ws->remote_ip_str;
|
||||
|
||||
sd = connect_to_secmod(ws);
|
||||
if (sd == -1) {
|
||||
@@ -1292,9 +1289,7 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
|
||||
|| ws->auth_state == S_AUTH_REQ) {
|
||||
SecAuthContMsg areq = SEC_AUTH_CONT_MSG__INIT;
|
||||
|
||||
areq.ip =
|
||||
human_addr2((void *)&ws->remote_addr, ws->remote_addr_len,
|
||||
ipbuf, sizeof(ipbuf), 0);
|
||||
areq.ip = ws->remote_ip_str;
|
||||
|
||||
if (ws->selected_auth->type & AUTH_TYPE_GSSAPI) {
|
||||
if (req->authorization == NULL || req->authorization_size <= 10) {
|
||||
|
||||
@@ -140,7 +140,7 @@ int post_kkdcp_handler(worker_st *ws, unsigned http_ver)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ws->ban_points += KKDCP_POINTS;
|
||||
ws_add_score_to_ip(ws, KKDCP_POINTS, 0);
|
||||
oclog(ws, LOG_HTTP_DEBUG, "HTTP processing kkdcp framed request: %u bytes", (unsigned)req->body_length);
|
||||
|
||||
ret = der_decode((uint8_t*)req->body, req->body_length, buf, &length, realm, sizeof(realm), &e);
|
||||
|
||||
@@ -240,29 +240,49 @@ static int setup_dtls_connection(struct worker_st *ws)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static
|
||||
void worker_add_score_to_ip(worker_st *ws, const char *ip, unsigned points)
|
||||
void ws_add_score_to_ip(worker_st *ws, unsigned points, unsigned final)
|
||||
{
|
||||
void *lpool;
|
||||
int ret, e;
|
||||
BanIpMsg msg = BAN_IP_MSG__INIT;
|
||||
BanIpReplyMsg *reply = NULL;
|
||||
PROTOBUF_ALLOCATOR(pa, ws);
|
||||
|
||||
msg.ip = (char*)ip;
|
||||
msg.score = points;
|
||||
|
||||
lpool = talloc_new(ws);
|
||||
if (lpool == NULL) {
|
||||
return;
|
||||
/* In final call, no score added, we simply send */
|
||||
if (final == 0) {
|
||||
ws->ban_points += points;
|
||||
/* do not use IPC for small values */
|
||||
if (points < PASSWORD_POINTS)
|
||||
return;
|
||||
}
|
||||
|
||||
ret = send_msg(lpool, ws->cmd_fd, CMD_BAN_IP, &msg,
|
||||
msg.ip = ws->remote_ip_str;
|
||||
msg.score = points;
|
||||
|
||||
ret = send_msg(ws, ws->cmd_fd, CMD_BAN_IP, &msg,
|
||||
(pack_size_func) ban_ip_msg__get_packed_size,
|
||||
(pack_func) ban_ip_msg__pack);
|
||||
if (ret < 0) {
|
||||
e = errno;
|
||||
oclog(ws, LOG_WARNING, "error in sending BAN IP message: %s", strerror(e));
|
||||
return;
|
||||
}
|
||||
talloc_free(lpool);
|
||||
|
||||
if (final != 0)
|
||||
return;
|
||||
|
||||
ret = recv_msg(ws, ws->cmd_fd, CMD_BAN_IP_REPLY,
|
||||
(void *)&reply, (unpack_func) ban_ip_reply_msg__unpack);
|
||||
if (ret < 0) {
|
||||
oclog(ws, LOG_ERR, "error receiving BAN IP reply message");
|
||||
return;
|
||||
}
|
||||
|
||||
if (reply->reply != AUTH__REP__OK) {
|
||||
/* we have exceeded the maximum score */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ban_ip_reply_msg__free_unpacked(reply, &pa);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -272,8 +292,6 @@ void worker_add_score_to_ip(worker_st *ws, const char *ip, unsigned points)
|
||||
*/
|
||||
void exit_worker(worker_st * ws)
|
||||
{
|
||||
char buf[MAX_IP_STR];
|
||||
|
||||
/* send statistics to parent */
|
||||
if (ws->auth_state == S_AUTH_COMPLETE) {
|
||||
CliStatsMsg msg = CLI_STATS_MSG__INIT;
|
||||
@@ -292,8 +310,8 @@ void exit_worker(worker_st * ws)
|
||||
(unsigned long)msg.bytes_out);
|
||||
}
|
||||
|
||||
if (ws->ban_points > 0 && human_addr2((void*)&ws->remote_addr, ws->remote_addr_len, buf, sizeof(buf), 0) != NULL)
|
||||
worker_add_score_to_ip(ws, buf, ws->ban_points);
|
||||
if (ws->ban_points > 0)
|
||||
ws_add_score_to_ip(ws, 0, 1);
|
||||
|
||||
talloc_free(ws->main_pool);
|
||||
closelog();
|
||||
@@ -402,6 +420,8 @@ void vpn_server(struct worker_st *ws)
|
||||
settings.on_body = http_body_cb;
|
||||
http_req_init(ws);
|
||||
|
||||
human_addr2((void*)&ws->remote_addr, ws->remote_addr_len, ws->remote_ip_str, sizeof(ws->remote_ip_str), 0);
|
||||
|
||||
ws->session = session;
|
||||
ws->parser = &parser;
|
||||
|
||||
|
||||
@@ -179,6 +179,8 @@ typedef struct worker_st {
|
||||
|
||||
struct sockaddr_storage remote_addr; /* peer's address */
|
||||
socklen_t remote_addr_len;
|
||||
char remote_ip_str[MAX_IP_STR];
|
||||
|
||||
int proto; /* AF_INET or AF_INET6 */
|
||||
|
||||
time_t session_start_time;
|
||||
@@ -332,6 +334,7 @@ void exit_worker(worker_st * ws);
|
||||
|
||||
int ws_switch_auth_to(struct worker_st *ws, unsigned auth);
|
||||
void ws_disable_auth(struct worker_st *ws, unsigned auth);
|
||||
void ws_add_score_to_ip(worker_st *ws, unsigned points, unsigned final);
|
||||
|
||||
int connect_to_secmod(worker_st * ws);
|
||||
inline static
|
||||
|
||||
Reference in New Issue
Block a user