Browse Source

* update jail for use score instead maxcount (see #9)

master
Alex 'AdUser' Z 3 years ago
parent
commit
28093ba0f8
  1. 70
      src/jail.c
  2. 4
      src/jail.h

70
src/jail.c

@ -20,7 +20,7 @@
#define DEFAULT_BANTIME 3600 /* in seconds, 1 hour */ #define DEFAULT_BANTIME 3600 /* in seconds, 1 hour */
#define DEFAULT_FINDTIME 300 /* in seconds, 5 min */ #define DEFAULT_FINDTIME 300 /* in seconds, 5 min */
#define DEFAULT_EXPIRETIME 14400 /* in seconds, 4 hours */ #define DEFAULT_EXPIRETIME 14400 /* in seconds, 4 hours */
#define DEFAULT_MAXRETRY 5 #define DEFAULT_BANSCORE 50
f2b_jail_t *jails = NULL; f2b_jail_t *jails = NULL;
@ -28,7 +28,7 @@ static f2b_jail_t defaults = {
.bantime = DEFAULT_BANTIME, .bantime = DEFAULT_BANTIME,
.findtime = DEFAULT_FINDTIME, .findtime = DEFAULT_FINDTIME,
.expiretime = DEFAULT_EXPIRETIME, .expiretime = DEFAULT_EXPIRETIME,
.maxretry = DEFAULT_MAXRETRY, .banscore = DEFAULT_BANSCORE,
}; };
static struct opt_remap { static struct opt_remap {
@ -37,6 +37,7 @@ static struct opt_remap {
} deprecated[] = { } deprecated[] = {
{ .old = "incr_bantime", .new = "bantime_extend" }, { .old = "incr_bantime", .new = "bantime_extend" },
{ .old = "incr_findtime", .new = "findtime_extend" }, { .old = "incr_findtime", .new = "findtime_extend" },
{ .old = "maxretry", .new = "banscore" },
{ .old = NULL } /* end of list */ { .old = NULL } /* end of list */
}; };
@ -103,10 +104,10 @@ f2b_jail_set_param(f2b_jail_t *jail, const char *param, const char *value) {
jail->expiretime = DEFAULT_EXPIRETIME; jail->expiretime = DEFAULT_EXPIRETIME;
return true; return true;
} }
if (strcmp(param, "maxretry") == 0) { if (strcmp(param, "banscore") == 0) {
jail->maxretry = atoi(value); jail->banscore = atoi(value);
if (jail->maxretry == 0) if (jail->banscore == 0)
jail->maxretry = DEFAULT_MAXRETRY; jail->banscore = DEFAULT_BANSCORE;
return true; return true;
} }
if (strcmp(param, "bantime_extend") == 0) { if (strcmp(param, "bantime_extend") == 0) {
@ -266,12 +267,12 @@ f2b_jail_process(f2b_jail_t *jail) {
unsigned int hostc = 0; unsigned int hostc = 0;
char line[LOGLINE_MAX] = ""; char line[LOGLINE_MAX] = "";
char matchbuf[IPADDR_MAX] = ""; char matchbuf[IPADDR_MAX] = "";
time_t now = time(NULL);
time_t findtime = 0; time_t findtime = 0;
time_t expiretime = 0; time_t expiretime = 0;
time_t now = time(NULL);
bool remove = false; bool remove = false;
bool reset = true; /* source reset */ bool reset = true; /* source reset */
uint32_t stag, ftag; unsigned int stag, ftag;
short int score; short int score;
assert(jail != NULL); assert(jail != NULL);
@ -279,22 +280,18 @@ f2b_jail_process(f2b_jail_t *jail) {
f2b_log_msg(log_debug, "jail '%s': processing", jail->name); f2b_log_msg(log_debug, "jail '%s': processing", jail->name);
f2b_backend_ping(jail->backend); f2b_backend_ping(jail->backend);
while ((stag = f2b_source_next(jail->source, line, sizeof(line), reset)) > 0) { while ((stag = f2b_source_next(jail->source, line, sizeof(line), reset)) > 0) {
reset = false; reset = false;
if (!match) match = f2b_match_create(now);
match->stag = stag;
if (jail->flags & JAIL_HAS_FILTER) { if (jail->flags & JAIL_HAS_FILTER) {
if ((ftag = f2b_filter_match(jail->filter, line, matchbuf, sizeof(matchbuf), &score)) == 0) if ((ftag = f2b_filter_match(jail->filter, line, matchbuf, sizeof(matchbuf), &score)) == 0)
continue; continue; /* no match in filter */
match->ftag = ftag;
} else { } else {
/* without filter: 1) value always matches, 2) passed as-is */ /* without filter: 1) value always matches, 2) passed as-is */
memcpy(matchbuf, line, sizeof(matchbuf)); memcpy(matchbuf, line, sizeof(matchbuf));
match->ftag = 0; ftag = 0;
} }
/* some regex matches the line */ /* find-or-create matched address in jail known hosts list */
jail->stats.matches++;
addr = f2b_addrlist_lookup(jail->ipaddrs, matchbuf); addr = f2b_addrlist_lookup(jail->ipaddrs, matchbuf);
if (!addr) { if (!addr) {
addr = f2b_ipaddr_create(matchbuf); addr = f2b_ipaddr_create(matchbuf);
@ -302,29 +299,34 @@ f2b_jail_process(f2b_jail_t *jail) {
f2b_log_msg(log_debug, "jail '%s': found new ip %s", jail->name, matchbuf); f2b_log_msg(log_debug, "jail '%s': found new ip %s", jail->name, matchbuf);
} }
addr->lastseen = now; addr->lastseen = now;
/* create, fill and append new match to found host history */
jail->stats.matches++;
if ((match = f2b_match_create(now)) == NULL) {
f2b_log_msg(log_error, "can't allocate memory for new match");
continue;
}
match->time = now;
match->stag = stag;
match->ftag = ftag;
match->score = score;
f2b_matches_prepend(&addr->matches, match); f2b_matches_prepend(&addr->matches, match);
match = NULL; /* will create new object on next run */ /* host is banned? */
if (addr->banned) { if (addr->banned) {
if (addr->banned_at != now) if (addr->banned_at != now)
f2b_log_msg(log_warn, "jail '%s': ip %s was already banned", jail->name, matchbuf); f2b_log_msg(log_warn, "jail '%s': ip %s was already banned", jail->name, matchbuf);
continue; continue;
} }
match = f2b_match_create(now); /* how deep should we look inside host's history? */
if (jail->findtime_extend > 0 && addr->matches.count > jail->maxretry) { findtime = jail->findtime + jail->findtime * (jail->findtime_extend * addr->bancount);
findtime = now - jail->findtime; f2b_matches_expire(&addr->matches, now - findtime - 600);
findtime -= (int) ((addr->matches.count - jail->maxretry) * /* ...so, check host score */
(jail->findtime * jail->findtime_extend)); score = f2b_matches_score(&addr->matches, findtime);
} else { if (score < jail->banscore) {
findtime = now - jail->findtime; f2b_log_msg(log_info, "jail '%s': new match for ip %s (%u/%u)",
} jail->name, matchbuf, score, jail->banscore);
f2b_matches_expire(&addr->matches, findtime); continue; /* lucky bastard */
f2b_matches_prepend(&addr->matches, match);
if (addr->matches.count < jail->maxretry) {
f2b_log_msg(log_info, "jail '%s': new match for ip %s (%zu/%zu)",
jail->name, matchbuf, addr->matches.count, jail->maxretry);
continue;
} }
/* limit reached, ban ip */ /* score limit reached, ban ip */
f2b_jail_ban(jail, addr); f2b_jail_ban(jail, addr);
if (jail->flags & JAIL_HAS_STATE) if (jail->flags & JAIL_HAS_STATE)
jail->sfile->need_save = true; jail->sfile->need_save = true;
@ -535,7 +537,7 @@ void
f2b_jail_cmd_status(char *res, size_t ressize, f2b_jail_t *jail) { f2b_jail_cmd_status(char *res, size_t ressize, f2b_jail_t *jail) {
const char *fmt = const char *fmt =
"name: %s\n" "name: %s\n"
"maxretry: %d\n" "banscore: %d\n"
"flags:\n" "flags:\n"
" enabled: %s\n" " enabled: %s\n"
" state: %s\n" " state: %s\n"
@ -553,7 +555,7 @@ f2b_jail_cmd_status(char *res, size_t ressize, f2b_jail_t *jail) {
assert(jail != NULL); assert(jail != NULL);
snprintf(res, ressize, fmt, jail->name, snprintf(res, ressize, fmt, jail->name,
jail->maxretry, jail->banscore,
jail->flags & JAIL_ENABLED ? "yes" : "no", jail->flags & JAIL_ENABLED ? "yes" : "no",
jail->flags & JAIL_HAS_STATE ? "yes" : "no", jail->flags & JAIL_HAS_STATE ? "yes" : "no",
jail->flags & JAIL_HAS_FILTER ? "yes" : "no", jail->flags & JAIL_HAS_FILTER ? "yes" : "no",

4
src/jail.h

@ -21,8 +21,8 @@
typedef struct f2b_jail_t { typedef struct f2b_jail_t {
struct f2b_jail_t *next; /**< pointer to next jail */ struct f2b_jail_t *next; /**< pointer to next jail */
char name[CONFIG_KEY_MAX]; /**< name of the jail */ char name[CONFIG_KEY_MAX]; /**< name of the jail */
int flags; /**< jail flags, see above */ unsigned int flags; /**< jail flags, see above */
size_t maxretry; /**< option: maximum count of matches before ban */ short int banscore; /**< option: minimum amount of score to ban host */
/* duration of misc time periods */ /* duration of misc time periods */
time_t findtime; /**< option: length of time period for estimating recent host activity (in seconds) */ time_t findtime; /**< option: length of time period for estimating recent host activity (in seconds) */
time_t bantime; /**< option: host ban time on excess activity (seconds) */ time_t bantime; /**< option: host ban time on excess activity (seconds) */

Loading…
Cancel
Save