ip banning: entries hold in raw IP format rather than textual

This commit is contained in:
Nikos Mavrogiannopoulos
2015-11-10 13:47:51 +01:00
parent 518d8679d1
commit aed34ebd62
7 changed files with 108 additions and 55 deletions
+2 -2
View File
@@ -66,7 +66,7 @@ message id_req
message ban_info_rep
{
required string ip = 1;
required bytes ip = 1;
required uint32 score = 2;
optional uint32 expires = 3;
}
@@ -78,6 +78,6 @@ message ban_list_rep
message unban_req
{
required string ip = 1;
required bytes ip = 1;
}
+69 -31
View File
@@ -40,14 +40,14 @@
#include <tlslib.h>
#include <main.h>
#include <main-ban.h>
#include <arpa/inet.h>
#include <ccan/hash/hash.h>
#include <ccan/htable/htable.h>
static size_t rehash(const void *_e, void *unused)
{
ban_entry_st *e = (void*)_e;
return hash_any(e->ip, strlen(e->ip), 0);
return hash_any(e->ip.ip, e->ip.size, 0);
}
/* The first argument is the entry from the hash, and
@@ -58,7 +58,7 @@ static bool ban_entry_cmp(const void *_c1, void *_c2)
const struct ban_entry_st *c1 = _c1;
struct ban_entry_st *c2 = _c2;
if (strcmp(c1->ip, c2->ip) == 0)
if (c1->ip.size == c2->ip.size && memcmp(c1->ip.ip, c2->ip.ip, c1->ip.size) == 0)
return 1;
return 0;
}
@@ -99,7 +99,7 @@ struct htable *db = s->ban_db;
}
/* 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)
int add_ip_to_ban_list(main_server_st *s, const unsigned char *ip, unsigned ip_size, unsigned score)
{
struct htable *db = s->ban_db;
struct ban_entry_st *e;
@@ -109,12 +109,11 @@ int add_ip_to_ban_list(main_server_st *s, const char *ip, unsigned score)
int ret = 0;
unsigned print_msg;
if (db == NULL || s->config->max_ban_score == 0 || ip == NULL || ip[0] == 0)
if (db == NULL || s->config->max_ban_score == 0 || ip == NULL || (ip_size != 4 && ip_size != 16))
return 0;
/* check if the IP is already there */
/* pass the current time somehow */
strlcpy(t.ip, ip, sizeof(t.ip));
memcpy(t.ip.ip, ip, ip_size);
t.ip.size = ip_size;
e = htable_get(db, rehash(&t, NULL), ban_entry_cmp, &t);
if (e == NULL) { /* new entry */
@@ -123,7 +122,7 @@ int add_ip_to_ban_list(main_server_st *s, const char *ip, unsigned score)
return 0;
}
strlcpy(e->ip, ip, sizeof(e->ip));
memcpy(&e->ip, &t.ip, sizeof(e->ip));
e->last_reset = now;
if (htable_add(db, rehash(e, NULL), e) == 0) {
@@ -163,25 +162,55 @@ int add_ip_to_ban_list(main_server_st *s, const char *ip, unsigned score)
return ret;
}
int add_str_ip_to_ban_list(main_server_st *s, const char *ip, unsigned score)
{
struct htable *db = s->ban_db;
ban_entry_st t;
int ret = 0;
if (db == NULL || s->config->max_ban_score == 0 || ip == NULL || ip[0] == 0)
return 0;
if (strchr(ip, ':') != 0) {
ret = inet_pton(AF_INET6, ip, t.ip.ip);
t.ip.size = 16;
} else {
ret = inet_pton(AF_INET, ip, t.ip.ip);
t.ip.size = 4;
}
if (ret != 1) {
mslog(s, NULL, LOG_INFO,
"could not read IP: %s", ip);
return 0;
}
return add_ip_to_ban_list(s, t.ip.ip, t.ip.size, score);
}
/* returns non-zero if there is an IP removed */
int remove_ip_from_ban_list(main_server_st *s, const char *ip)
int remove_ip_from_ban_list(main_server_st *s, const uint8_t *ip, unsigned size)
{
struct htable *db = s->ban_db;
struct ban_entry_st *e;
ban_entry_st t;
char txt_ip[MAX_IP_STR];
if (db == NULL || ip == NULL || ip[0] == 0)
if (db == NULL || ip == NULL || size == 0)
return 0;
/* check if the IP is already there */
/* pass the current time somehow */
strlcpy(t.ip, ip, sizeof(t.ip));
if (size == 4 || size == 16) {
if (inet_ntop(size==16?AF_INET6:AF_INET, ip, txt_ip, sizeof(txt_ip)) != NULL)
mslog(s, NULL, LOG_INFO,
"unbanning IP '%s'", txt_ip);
e = htable_get(db, rehash(&t, NULL), ban_entry_cmp, &t);
if (e != NULL) { /* new entry */
e->score = 0;
e->expires = 0;
return 1;
memcpy(&t.ip.ip, ip, size);
e = htable_get(db, rehash(&t, NULL), ban_entry_cmp, &t);
if (e != NULL) { /* new entry */
e->score = 0;
e->expires = 0;
return 1;
}
}
return 0;
@@ -192,24 +221,33 @@ unsigned check_if_banned(main_server_st *s, struct sockaddr_storage *addr, sockl
struct htable *db = s->ban_db;
time_t now;
ban_entry_st t, *e;
unsigned in_size;
char txt[MAX_IP_STR];
if (db == NULL || s->config->max_ban_score == 0)
return 0;
if (human_addr2((struct sockaddr*)addr, addr_size, t.ip, sizeof(t.ip), 0) != NULL) {
/* add its current connection points */
add_ip_to_ban_list(s, t.ip, s->config->ban_points_connect);
in_size = SA_IN_SIZE(addr_size);
if (in_size != 4 && in_size != 16) {
mslog(s, NULL, LOG_ERR, "unknown address type for %s", human_addr2((struct sockaddr*)addr, addr_size, txt, sizeof(txt), NULL));
return 0;
}
now = time(0);
e = htable_get(db, rehash(&t, NULL), ban_entry_cmp, &t);
if (e != NULL) {
if (now > e->expires)
return 0;
memcpy(t.ip.ip, SA_IN_P_GENERIC(addr, addr_size), SA_IN_SIZE(addr_size));
t.ip.size = SA_IN_SIZE(addr_size);
if (e->score >= s->config->max_ban_score) {
mslog(s, NULL, LOG_INFO, "rejected connection from banned IP: %s", t.ip);
return 1;
}
/* add its current connection points */
add_ip_to_ban_list(s, t.ip.ip, t.ip.size, s->config->ban_points_connect);
now = time(0);
e = htable_get(db, rehash(&t, NULL), ban_entry_cmp, &t);
if (e != NULL) {
if (now > e->expires)
return 0;
if (e->score >= s->config->max_ban_score) {
mslog(s, NULL, LOG_INFO, "rejected connection from banned IP: %s", human_addr2((struct sockaddr*)addr, addr_size, txt, sizeof(txt), NULL));
return 1;
}
}
return 0;
+9 -3
View File
@@ -23,8 +23,13 @@
# include "main.h"
typedef struct inaddr_st {
uint8_t ip[16];
unsigned size; /* 4 or 16 */
} inaddr_st;
typedef struct ban_entry_st {
char ip[MAX_IP_STR];
inaddr_st ip;
unsigned score;
time_t last_reset; /* the time its score counting started */
@@ -33,8 +38,9 @@ typedef struct 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);
int remove_ip_from_ban_list(main_server_st *s, const char *ip);
int add_ip_to_ban_list(main_server_st *s, const unsigned char *ip, unsigned ip_size, unsigned score);
int add_str_ip_to_ban_list(main_server_st *s, const char *ip, unsigned score);
int remove_ip_from_ban_list(main_server_st *s, const uint8_t *ip, unsigned size);
unsigned main_ban_db_elems(main_server_st *s);
void main_ban_db_deinit(main_server_st *s);
void *main_ban_db_init(main_server_st *s);
+3 -5
View File
@@ -466,7 +466,8 @@ static int append_ban_info(method_ctx *ctx,
ban_info_rep__init(rep);
rep->ip = e->ip;
rep->ip.data = e->ip.ip;
rep->ip.len = e->ip.size;
rep->score = e->score;
if (ctx->s->config->max_ban_score > 0 && e->score >= ctx->s->config->max_ban_score) {
@@ -621,10 +622,7 @@ static void method_unban_ip(method_ctx *ctx,
return;
}
if (remove_ip_from_ban_list(ctx->s, req->ip) != 0) {
if (req->ip)
mslog(ctx->s, NULL, LOG_INFO,
"unbanning IP '%s' due to ctl request", req->ip);
if (remove_ip_from_ban_list(ctx->s, req->ip.data, req->ip.len) != 0) {
rep.status = 1;
}
+1 -1
View File
@@ -370,7 +370,7 @@ int handle_commands(main_server_st * s, struct proc_st *proc)
goto cleanup;
}
ret = add_ip_to_ban_list(s, tmsg->ip, tmsg->score);
ret = add_str_ip_to_ban_list(s, tmsg->ip, tmsg->score);
ban_ip_msg__free_unpacked(tmsg, &pa);
+1 -1
View File
@@ -125,7 +125,7 @@ int handle_sec_mod_commands(main_server_st * s)
ret = ERR_BAD_COMMAND;
goto cleanup;
}
ret = add_ip_to_ban_list(s, tmsg->ip, tmsg->score);
ret = add_str_ip_to_ban_list(s, tmsg->ip, tmsg->score);
if (ret < 0) {
reply.reply =
AUTH__REP__FAILED;
+23 -12
View File
@@ -359,9 +359,8 @@ int handle_unban_ip_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *pa
BoolMsg *rep;
unsigned status;
UnbanReq req = UNBAN_REQ__INIT;
char txt[MAX_IP_STR];
int af;
struct sockaddr_storage st;
unsigned char tmp[16];
PROTOBUF_ALLOCATOR(pa, ctx);
if (arg == NULL || need_help(arg)) {
@@ -378,12 +377,16 @@ int handle_unban_ip_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st *pa
af = AF_INET;
}
ret = inet_pton(af, arg, &st);
ret = inet_pton(af, arg, tmp);
if (ret == 1) {
inet_ntop(af, &st, txt, sizeof(txt));
req.ip = txt;
req.ip.data = tmp;
if (af == AF_INET)
req.ip.len = 4;
else
req.ip.len = 16;
} else {
req.ip = (char*)arg;
fprintf(stderr, "Cannot parse IP: %s", arg);
return 1;
}
ret = send_cmd(ctx, CTL_CMD_UNBAN_IP, &req,
@@ -628,6 +631,8 @@ int handle_list_banned_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st
struct tm *tm;
time_t t;
PROTOBUF_ALLOCATOR(pa, ctx);
char txt_ip[MAX_IP_STR];
const char *tmp_str;
init_reply(&raw);
@@ -647,9 +652,15 @@ int handle_list_banned_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st
print_array_block(out, params);
for (i=0;i<rep->n_info;i++) {
if (rep->info[i]->ip == NULL)
if (rep->info[i]->ip.len <= 4)
continue;
if (rep->info[i]->ip.len == 16)
tmp_str = inet_ntop(AF_INET6, rep->info[i]->ip.data, txt_ip, sizeof(txt_ip));
else
tmp_str = inet_ntop(AF_INET, rep->info[i]->ip.data, txt_ip, sizeof(txt_ip));
if (tmp_str == NULL)
strlcpy(txt_ip, "(unknown)", sizeof(txt_ip));
/* add header */
if (points == 0) {
@@ -670,12 +681,12 @@ int handle_list_banned_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st
print_time_ival7(tmpbuf, t, time(0));
if (HAVE_JSON(params)) {
print_single_value(out, params, "IP", rep->info[i]->ip, 1);
print_single_value(out, params, "IP", txt_ip, 1);
print_single_value_ex(out, params, "Since", str_since, tmpbuf, 1);
print_single_value_int(out, params, "Score", rep->info[i]->score, 0);
} else {
fprintf(out, "%14s %14u %30s (%s)\n",
rep->info[i]->ip, (unsigned)rep->info[i]->score, str_since, tmpbuf);
txt_ip, (unsigned)rep->info[i]->score, str_since, tmpbuf);
}
} else {
if (i == 0 && NO_JSON(params)) {
@@ -685,17 +696,17 @@ int handle_list_banned_cmd(struct unix_ctx *ctx, const char *arg, cmd_params_st
print_start_block(out, params);
if (HAVE_JSON(params)) {
print_single_value(out, params, "IP", rep->info[i]->ip, 1);
print_single_value(out, params, "IP", txt_ip, 1);
print_single_value_int(out, params, "Score", rep->info[i]->score, 0);
} else {
fprintf(out, "%14s %14u\n",
rep->info[i]->ip, (unsigned)rep->info[i]->score);
txt_ip, (unsigned)rep->info[i]->score);
}
}
print_end_block(out, params, i<(rep->n_info-1)?1:0);
ip_entries_add(ctx, rep->info[i]->ip, strlen(rep->info[i]->ip));
ip_entries_add(ctx, txt_ip, strlen(txt_ip));
}
print_end_array_block(out, params);