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:
Nikos Mavrogiannopoulos
2015-02-25 19:55:47 +01:00
parent 874d0ce0e2
commit 7a675ff5e2
13 changed files with 151 additions and 42 deletions

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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;

View File

@@ -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