occtl: added ability to list banned, and unban IPs

This commit is contained in:
Nikos Mavrogiannopoulos
2015-02-26 14:33:33 +01:00
parent bbee3767dc
commit 0326ec168b
8 changed files with 257 additions and 8 deletions

View File

@@ -12,6 +12,8 @@ enum {
CTL_CMD_ID_INFO,
CTL_CMD_DISCONNECT_NAME,
CTL_CMD_DISCONNECT_ID,
CTL_CMD_LIST_BANNED,
CTL_CMD_UNBAN_IP,
CTL_CMD_STATUS_REP = 101,
CTL_CMD_RELOAD_REP,
@@ -19,6 +21,8 @@ enum {
CTL_CMD_LIST_REP,
CTL_CMD_DISCONNECT_NAME_REP,
CTL_CMD_DISCONNECT_ID_REP,
CTL_CMD_UNBAN_IP_REP,
CTL_CMD_LIST_BANNED_REP,
};
#endif

View File

@@ -61,3 +61,21 @@ message id_req
{
required sint32 id = 1;
}
message ban_info_rep
{
required string ip = 1;
required uint32 score = 2;
optional uint32 expires = 3;
}
message ban_list_rep
{
repeated ban_info_rep info = 1;
}
message unban_req
{
required string ip = 1;
}

View File

@@ -43,14 +43,6 @@
#include <ccan/hash/hash.h>
#include <ccan/htable/htable.h>
typedef struct ban_entry_st {
char ip[MAX_IP_STR];
unsigned score;
time_t last_reset; /* the time its score counting started */
time_t expires; /* the time after the client is allowed to login */
} ban_entry_st;
static size_t rehash(const void *_e, void *unused)
{
ban_entry_st *e = (void*)_e;
@@ -232,3 +224,4 @@ void cleanup_banned_entries(main_server_st *s)
}
}

View File

@@ -23,6 +23,14 @@
# include "main.h"
typedef struct ban_entry_st {
char ip[MAX_IP_STR];
unsigned score;
time_t last_reset; /* the time its score counting started */
time_t expires; /* the time after the client is allowed to login */
} ban_entry_st;
void cleanup_banned_entries(main_server_st *s);
unsigned check_if_banned(main_server_st *s, struct sockaddr_storage *addr, socklen_t addr_size);
int add_ip_to_ban_list(main_server_st *s, const char *ip, unsigned score);

View File

@@ -50,6 +50,8 @@ static void method_disconnect_user_name(method_ctx *ctx, int cfd,
uint8_t * msg, unsigned msg_size);
static void method_disconnect_user_id(method_ctx *ctx, int cfd,
uint8_t * msg, unsigned msg_size);
static void method_unban_ip(method_ctx *ctx, int cfd,
uint8_t * msg, unsigned msg_size);
static void method_stop(method_ctx *ctx, int cfd, uint8_t * msg,
unsigned msg_size);
static void method_reload(method_ctx *ctx, int cfd, uint8_t * msg,
@@ -58,6 +60,8 @@ static void method_user_info(method_ctx *ctx, int cfd, uint8_t * msg,
unsigned msg_size);
static void method_id_info(method_ctx *ctx, int cfd, uint8_t * msg,
unsigned msg_size);
static void method_list_banned(method_ctx *ctx, int cfd, uint8_t * msg,
unsigned msg_size);
typedef void (*method_func) (method_ctx *ctx, int cfd, uint8_t * msg,
unsigned msg_size);
@@ -76,8 +80,10 @@ static const ctl_method_st methods[] = {
ENTRY(CTL_CMD_RELOAD, method_reload),
ENTRY(CTL_CMD_STOP, method_stop),
ENTRY(CTL_CMD_LIST, method_list_users),
ENTRY(CTL_CMD_LIST_BANNED, method_list_banned),
ENTRY(CTL_CMD_USER_INFO, method_user_info),
ENTRY(CTL_CMD_ID_INFO, method_id_info),
ENTRY(CTL_CMD_UNBAN_IP, method_unban_ip),
ENTRY(CTL_CMD_DISCONNECT_NAME, method_disconnect_user_name),
ENTRY(CTL_CMD_DISCONNECT_ID, method_disconnect_user_id),
{NULL, 0, NULL}
@@ -425,6 +431,68 @@ static void method_list_users(method_ctx *ctx, int cfd, uint8_t * msg,
return;
}
static int append_ban_info(method_ctx *ctx,
BanListRep *list,
struct ban_entry_st *e)
{
BanInfoRep *rep;
list->info =
talloc_realloc(ctx->pool, list->info, BanInfoRep *, (1 + list->n_info));
if (list->info == NULL)
return -1;
rep = list->info[list->n_info] = talloc(ctx->pool, BanInfoRep);
if (rep == NULL)
return -1;
list->n_info++;
ban_info_rep__init(rep);
rep->ip = e->ip;
rep->score = e->score;
if (ctx->s->config->max_ban_score > 0 && e->score >= ctx->s->config->max_ban_score) {
rep->expires = e->expires;
rep->has_expires = 1;
}
return 0;
}
static void method_list_banned(method_ctx *ctx, int cfd, uint8_t * msg,
unsigned msg_size)
{
BanListRep rep = BAN_LIST_REP__INIT;
struct ban_entry_st *e = NULL;
struct htable *db = ctx->s->ban_db;
int ret;
struct htable_iter iter;
mslog(ctx->s, NULL, LOG_DEBUG, "ctl: list-banned-ips");
e = htable_first(db, &iter);
while (e != NULL) {
ret = append_ban_info(ctx, &rep, e);
if (ret < 0) {
mslog(ctx->s, NULL, LOG_ERR,
"error appending ban info to reply");
goto error;
}
e = htable_next(db, &iter);
}
ret = send_msg(ctx->pool, cfd, CTL_CMD_LIST_BANNED_REP, &rep,
(pack_size_func) ban_list_rep__get_packed_size,
(pack_func) ban_list_rep__pack);
if (ret < 0) {
mslog(ctx->s, NULL, LOG_ERR, "error sending ban list reply");
}
error:
return;
}
static void single_info_common(method_ctx *ctx, int cfd, uint8_t * msg,
unsigned msg_size, const char *user, unsigned id)
{
@@ -519,6 +587,42 @@ static void method_id_info(method_ctx *ctx, int cfd, uint8_t * msg,
return;
}
static void method_unban_ip(method_ctx *ctx,
int cfd, uint8_t * msg,
unsigned msg_size)
{
UnbanReq *req;
BoolMsg rep = BOOL_MSG__INIT;
int ret;
mslog(ctx->s, NULL, LOG_DEBUG, "ctl: unban IP");
req = unban_req__unpack(NULL, msg_size, msg);
if (req == NULL) {
mslog(ctx->s, NULL, LOG_ERR,
"error parsing unban IP request");
return;
}
if (req->ip) {
remove_ip_from_ban_list(ctx->s, req->ip);
rep.status = 1;
mslog(ctx->s, NULL, LOG_INFO,
"unbanning IP '%s' due to ctl request", req->ip);
}
unban_req__free_unpacked(req, NULL);
ret = send_msg(ctx->pool, cfd, CTL_CMD_UNBAN_IP_REP, &rep,
(pack_size_func) bool_msg__get_packed_size,
(pack_func) bool_msg__pack);
if (ret < 0) {
mslog(ctx->s, NULL, LOG_ERR, "error sending unban IP ctl reply");
}
return;
}
static void method_disconnect_user_name(method_ctx *ctx,
int cfd, uint8_t * msg,
unsigned msg_size)

View File

@@ -50,10 +50,12 @@ static uint8_t msg_map[] = {
[CTL_CMD_RELOAD] = CTL_CMD_RELOAD_REP,
[CTL_CMD_STOP] = CTL_CMD_STOP_REP,
[CTL_CMD_LIST] = CTL_CMD_LIST_REP,
[CTL_CMD_LIST_BANNED] = CTL_CMD_LIST_BANNED_REP,
[CTL_CMD_USER_INFO] = CTL_CMD_LIST_REP,
[CTL_CMD_ID_INFO] = CTL_CMD_LIST_REP,
[CTL_CMD_DISCONNECT_NAME] = CTL_CMD_DISCONNECT_NAME_REP,
[CTL_CMD_DISCONNECT_ID] = CTL_CMD_DISCONNECT_ID_REP,
[CTL_CMD_UNBAN_IP] = CTL_CMD_UNBAN_IP_REP,
};
struct cmd_reply_st {
@@ -339,6 +341,56 @@ int handle_stop_cmd(struct unix_ctx *ctx, const char *arg)
return ret;
}
int handle_unban_ip_cmd(struct unix_ctx *ctx, const char *arg)
{
int ret;
struct cmd_reply_st raw;
BoolMsg *rep;
unsigned status;
UnbanReq req = UNBAN_REQ__INIT;
PROTOBUF_ALLOCATOR(pa, ctx);
if (arg == NULL || need_help(arg)) {
check_cmd_help(rl_line_buffer);
return 1;
}
init_reply(&raw);
req.ip = (void*)arg;
ret = send_cmd(ctx, CTL_CMD_UNBAN_IP, &req,
(pack_size_func)unban_req__get_packed_size,
(pack_func)unban_req__pack, &raw);
if (ret < 0) {
goto error;
}
rep = bool_msg__unpack(&pa, raw.data_size, raw.data);
if (rep == NULL)
goto error;
status = rep->status;
bool_msg__free_unpacked(rep, &pa);
if (status != 0) {
printf("IP '%s' was unbanned\n", arg);
} else {
printf("could not unban IP '%s'\n", arg);
}
ret = 0;
goto cleanup;
error:
fprintf(stderr, ERR_SERVER_UNREACHABLE);
ret = 1;
cleanup:
free_reply(&raw);
return ret;
}
int handle_disconnect_user_cmd(struct unix_ctx *ctx, const char *arg)
{
int ret;
@@ -533,6 +585,70 @@ int handle_list_users_cmd(struct unix_ctx *ctx, const char *arg)
return ret;
}
int handle_list_banned_cmd(struct unix_ctx *ctx, const char *arg)
{
int ret;
struct cmd_reply_st raw;
BanListRep *rep = NULL;
unsigned i;
char str_since[64];
FILE *out;
struct tm *tm;
time_t t;
PROTOBUF_ALLOCATOR(pa, ctx);
init_reply(&raw);
out = pager_start();
ret = send_cmd(ctx, CTL_CMD_LIST_BANNED, NULL, NULL, NULL, &raw);
if (ret < 0) {
goto error;
}
rep = ban_list_rep__unpack(&pa, raw.data_size, raw.data);
if (rep == NULL)
goto error;
for (i=0;i<rep->n_info;i++) {
if (rep->info[i]->ip == NULL)
continue;
/* add header */
if (i == 0) {
fprintf(out, "%14s %14s %30s\n",
"IP", "score", "expires");
}
if (rep->info[i]->has_expires) {
t = rep->info[i]->expires;
tm = localtime(&t);
strftime(str_since, sizeof(str_since), DATE_TIME_FMT, tm);
} else {
str_since[0] = 0;
}
fprintf(out, "%14s %14u %30s\n",
rep->info[i]->ip, (unsigned)rep->info[i]->score, str_since);
}
ret = 0;
goto cleanup;
error:
ret = 1;
fprintf(stderr, ERR_SERVER_UNREACHABLE);
cleanup:
if (rep != NULL)
ban_list_rep__free_unpacked(rep, &pa);
free_reply(&raw);
pager_stop(out);
return ret;
}
int print_list_entries(FILE* out, const char* name, char **val, unsigned vsize)
{
const char * tmp;

View File

@@ -51,12 +51,16 @@ static const commands_st commands[] = {
"Disconnect the specified user", 1, 1),
ENTRY("disconnect id", "[ID]", handle_disconnect_id_cmd,
"Disconnect the specified ID", 1, 1),
ENTRY("unban", "[IP]", handle_unban_ip_cmd,
"Unban the specified IP", 1, 1),
ENTRY("reload", NULL, handle_reload_cmd,
"Reloads the server configuration", 1, 1),
ENTRY("show status", NULL, handle_status_cmd,
"Prints the status of the server", 1, 1),
ENTRY("show users", NULL, handle_list_users_cmd,
"Prints the connected users", 1, 1),
ENTRY("show banned", NULL, handle_list_banned_cmd,
"Prints the banned IP addresses", 1, 1),
ENTRY("show user", "[NAME]", handle_show_user_cmd,
"Prints information on the specified user", 1, 1),
ENTRY("show id", "[ID]", handle_show_id_cmd,

View File

@@ -53,9 +53,11 @@ typedef int (*cmd_func) (CONN_TYPE * conn, const char *arg);
int handle_status_cmd(CONN_TYPE * conn, const char *arg);
int handle_list_users_cmd(CONN_TYPE * conn, const char *arg);
int handle_list_banned_cmd(CONN_TYPE * conn, const char *arg);
int handle_show_user_cmd(CONN_TYPE * conn, const char *arg);
int handle_show_id_cmd(CONN_TYPE * conn, const char *arg);
int handle_disconnect_user_cmd(CONN_TYPE * conn, const char *arg);
int handle_unban_ip_cmd(CONN_TYPE * conn, const char *arg);
int handle_disconnect_id_cmd(CONN_TYPE * conn, const char *arg);
int handle_reload_cmd(CONN_TYPE * conn, const char *arg);
int handle_stop_cmd(CONN_TYPE * conn, const char *arg);