Compare commits
16 Commits
2f15996b91
...
5846157eed
Author | SHA1 | Date |
---|---|---|
Alex 'AdUser' Z | 5846157eed | 1 year ago |
Alex 'AdUser' Z | 67438b8bba | 1 year ago |
Alex 'AdUser' Z | f134060773 | 2 years ago |
Alex 'AdUser' Z | aa32f7c82e | 2 years ago |
Alex 'AdUser' Z | 7789256ca2 | 2 years ago |
Alex 'AdUser' Z | f263c064a7 | 2 years ago |
Alex 'AdUser' Z | 680bd57e3f | 2 years ago |
Alex 'AdUser' Z | 11e50d4f53 | 2 years ago |
Alex 'AdUser' Z | a21de1547c | 2 years ago |
Alex 'AdUser' Z | fc2d27caa6 | 2 years ago |
Alex 'AdUser' Z | 2dfe4a1a88 | 2 years ago |
Alex 'AdUser' Z | 751fc7fada | 2 years ago |
Alex 'AdUser' Z | 6f23fc3e38 | 2 years ago |
Alex 'AdUser' Z | 7d13d93c86 | 2 years ago |
Alex 'AdUser' Z | dab15ee505 | 2 years ago |
Alex 'AdUser' Z | cf53cf0e92 | 3 years ago |
30 changed files with 322 additions and 153 deletions
@ -1,3 +1,6 @@ |
|||||||
CMakeCache.txt |
CMakeCache.txt |
||||||
CMakeFiles/ |
CMakeFiles/ |
||||||
*.cmake |
*.cmake |
||||||
|
# generated configs: |
||||||
|
configs/f2b.conf |
||||||
|
configs/conf-available/20-jail-*.conf |
||||||
|
@ -1,6 +1,8 @@ |
|||||||
|
# -q option stops a ipfw table add or delete from failing if the entry |
||||||
|
# already exists or is not present. |
||||||
[backend:exec-ipfw] |
[backend:exec-ipfw] |
||||||
load = backend_exec.so |
load = backend_exec.so |
||||||
ban = /sbin/ipfw table <ID> add <IP> |
ban = /sbin/ipfw -q table <ID> add <IP> |
||||||
unban = /sbin/ipfw table <ID> delete <IP> |
unban = /sbin/ipfw -q table <ID> delete <IP> |
||||||
timeout = 2 |
timeout = 2 |
||||||
shared = yes |
shared = yes |
||||||
|
@ -0,0 +1,3 @@ |
|||||||
|
[jail:dovecot] |
||||||
|
source = files:/var/log/mail.log |
||||||
|
filter = preg:${CMAKE_INSTALL_FULL_DATAROOTDIR}/f2b/filters/dovecot.preg |
@ -0,0 +1,3 @@ |
|||||||
|
[jail:nginx] |
||||||
|
source = files:/var/log/nginx/*access*.log |
||||||
|
filter = pcre:${CMAKE_INSTALL_FULL_DATAROOTDIR}/f2b/filters/nginx-bots.pcre |
@ -0,0 +1,3 @@ |
|||||||
|
[jail:postfix] |
||||||
|
source = files:/var/log/mail.log |
||||||
|
filter = preg:${CMAKE_INSTALL_FULL_DATAROOTDIR}/f2b/filters/postfix.preg |
@ -0,0 +1,3 @@ |
|||||||
|
[jail:ssh] |
||||||
|
source = files:/var/log/auth.log |
||||||
|
filter = preg:${CMAKE_INSTALL_FULL_DATAROOTDIR}/f2b/filters/ssh.preg |
@ -1 +1,2 @@ |
|||||||
|
usr/share/f2b/filters |
||||||
var/lib/f2b |
var/lib/f2b |
||||||
|
@ -0,0 +1,2 @@ |
|||||||
|
- Where have all filters gone? |
||||||
|
- Now it located in their own repository, for convinient maintenance |
@ -1,4 +0,0 @@ |
|||||||
SECURITY.* SecurityEvent="FailedACL".*RemoteAddress="IPV[46]/[TU][CD]P/<HOST>/[0-9]+" |
|
||||||
SECURITY.* SecurityEvent="InvalidAccountID".*RemoteAddress="IPV[46]/[TU][CD]P/<HOST>/[0-9+]+" |
|
||||||
SECURITY.* SecurityEvent="ChallengeResponseFailed".*RemoteAddress="IPV[46]/[TU][CD]P/<HOST>/[0-9]+" |
|
||||||
SECURITY.* SecurityEvent="InvalidPassword".*RemoteAddress="IPV[46]/[TU][CD]P/<HOST>/[0-9]+" |
|
@ -1,2 +0,0 @@ |
|||||||
# set: defscore=5 |
|
||||||
closed \(2nd stage\), user <> .* remote <HOST>:[0-9]+, reason: allocation watchdog determined stale session state |
|
@ -1,6 +0,0 @@ |
|||||||
pop3-login: Aborted login \(auth failed, [0-9]+ attempts in [0-9]+ secs\): .* rip=<HOST> |
|
||||||
imap-login: Aborted login \(auth failed, [0-9]+ attempts in [0-9]+ secs\): .* rip=<HOST> |
|
||||||
pop3-login: Disconnected \(auth failed, [0-9]+ attempts in [0-9]+ secs\): .* rip=<HOST> |
|
||||||
imap-login: Disconnected \(auth failed, [0-9]+ attempts in [0-9]+ secs\): .* rip=<HOST> |
|
||||||
# set: defscore=5 |
|
||||||
submission-login: Client has quit the connection \(tried to use disallowed plaintext auth\): .* rip=<HOST> |
|
@ -1,10 +0,0 @@ |
|||||||
# set: defscore=10 |
|
||||||
SMTP protocol synchronization error \(input sent without waiting for greeting\): rejected connection from .*\[<HOST>\] |
|
||||||
SMTP protocol synchronization error \(next input sent too soon: pipelining was not advertised\): rejected .*\[<HOST>\] |
|
||||||
rejected [HE][EH]HLO from \[<HOST>\]: syntactically invalid argument |
|
||||||
\[<HOST>\] .* host is listed in .+ |
|
||||||
\[<HOST>\] .* relay not permitted |
|
||||||
\[<HOST>\] .* rejected after DATA: This message was detected as possible malware |
|
||||||
# set: defscore=5 |
|
||||||
\[<HOST>\] .* too many connections from that IP address |
|
||||||
\[<HOST>\] .* temporarily rejected RCPT \<\S+\>: lowest numbered MX record points to local host |
|
@ -1,3 +0,0 @@ |
|||||||
Failed authentication attempt for [[:print:]]+ from <HOST> |
|
||||||
Failed authentication attempt from <HOST> |
|
||||||
invalid credentials from <HOST> |
|
@ -1,6 +0,0 @@ |
|||||||
# set: defscore=10 |
|
||||||
<HOST>#[0-9]+ .* query \(cache\) '[0-9.]+.in-addr.arpa/(PTR|SOA)/IN' denied |
|
||||||
# requests to '.' or top-level domains |
|
||||||
<HOST>#[0-9]+ .* query \(cache\) '[a-z.]+/ANY/IN' denied |
|
||||||
# set: defscore=1 |
|
||||||
<HOST>#[0-9]+ .* query \(cache\) '[0-9a-z.-]+/RRSIG/IN' denied |
|
@ -1,32 +0,0 @@ |
|||||||
# set: defscore=15 |
|
||||||
# h4x0rs |
|
||||||
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/(shell|cmd|x)\.(php|cgi) |
|
||||||
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/w00tw00t |
|
||||||
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+Ringing\.at\.your\.dorbell |
|
||||||
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/.*(wget|curl)(\\x|%)20https?:// |
|
||||||
<HOST> .* "(GET|HEAD|POST) .*/bin/(ba|c|z)?sh( |\\x20|%20)-c |
|
||||||
<HOST> .* "(\\x[0-9a-z]{2,6})+" 400 |
|
||||||
# set: defscore=10 |
|
||||||
# phpmyadmin and variations |
|
||||||
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+(php|sqlite)-?(manager)? |
|
||||||
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+(php|pg|sql)-?my-?admin |
|
||||||
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+pma[0-9]* |
|
||||||
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+((my|pg)(sql)?|db|msd?)-?(admin|dumper|dump|manager) |
|
||||||
# set: defscore=5 |
|
||||||
# open proxy search |
|
||||||
<HOST> .* "(GET|HEAD|POST) https?://[a-z-\.]+proxyradar\.com |
|
||||||
<HOST> .* "CONNECT [a-z-\.]*proxyradar\.com |
|
||||||
<HOST> .* "CONNECT [a-z-\.]*proxytest\.zmap\.io |
|
||||||
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+testproxy\.php |
|
||||||
# set: defscore=2 |
|
||||||
# search bots |
|
||||||
<HOST> .* "(GET|HEAD|POST) .* "python-(requests|urllib)/[0-9\.]+ |
|
||||||
<HOST> .* "(GET|HEAD|POST) .* "AhrefsBot/[0-9a-z\.]+ |
|
||||||
<HOST> .* "(GET|HEAD|POST) .* "DotBot/[0-9a-z\.]+ |
|
||||||
<HOST> .* "(GET|HEAD|POST) .* "MauiBot |
|
||||||
<HOST> .* "(GET|HEAD|POST) .* SiteExplorer/[0-9a-z\.]+ |
|
||||||
<HOST> .* "(GET|HEAD|POST) .* MJ12bot |
|
||||||
<HOST> .* "(GET|HEAD|POST) .* WebIndex |
|
||||||
# shit-coded php cms |
|
||||||
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/.*/wp-login.php |
|
||||||
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+(joomla|cms)/administrator |
|
@ -1,11 +0,0 @@ |
|||||||
# set: defscore=10 |
|
||||||
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 450 4\.7\.1 Client host rejected |
|
||||||
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 454 4\.7\.1 Service unavailable; Client host \[[[:print:]]+\] blocked |
|
||||||
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 454 4\.7\.1 <[[:print:]]+>: Relay access denied |
|
||||||
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 554 5\.7\.1 <[[:print:]]+>: Relay access denied |
|
||||||
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 550 5\.1\.1 <[[:print:]]+>: Recipient address rejected: undeliverable address |
|
||||||
warning: [[:print:]]+\[<HOST>\]: SASL [A-Z0-9-]+ authentication failed |
|
||||||
# set: defscore=5 |
|
||||||
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 450 4\.7\.1 <[[:print:]]+>: Helo command rejected: Host not found |
|
||||||
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 504 5\.5\.2 <[[:print:]]+>: Helo command rejected: need fully-qualified hostname |
|
||||||
lost connection after AUTH from [[:print:]]+\[<HOST>\] |
|
@ -1,17 +0,0 @@ |
|||||||
# set: defscore=15 |
|
||||||
User [[:print:]]+ from <HOST> not allowed because listed in DenyUsers |
|
||||||
User [[:print:]]+ from <HOST> not allowed because a group is listed in DenyGroups |
|
||||||
# set: defscore=10 |
|
||||||
User [[:print:]]+ from <HOST> not allowed because not listed in AllowUsers |
|
||||||
User [[:print:]]+ from <HOST> not allowed because not in any group |
|
||||||
User [[:print:]]+ from <HOST> not allowed because none of user's groups are listed in AllowGroups |
|
||||||
[Aa]uthentication failure for .* from <HOST>( via [[:print:]]*)? |
|
||||||
[Aa]uthentication error for .* from <HOST>( via [[:print:]]*)? |
|
||||||
Failed password for .* from <HOST> |
|
||||||
# set: defscore=5 |
|
||||||
User not known to the underlying authentication module for .* from <HOST> |
|
||||||
Invalid user [[:print:]]+ from <HOST> |
|
||||||
# set: defscore=3 |
|
||||||
refused connect from [[:print:]]+ \(<HOST>\) |
|
||||||
Did not receive identification string from <HOST> |
|
||||||
Connection closed by <HOST>( port [0-9]+)? \[preauth\] |
|
@ -0,0 +1,192 @@ |
|||||||
|
/* Copyright 2017 Alex 'AdUser' Z (ad_user@runbox.com)
|
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License version 2 as |
||||||
|
* published by the Free Software Foundation. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <assert.h> |
||||||
|
#include <stdbool.h> |
||||||
|
#include <stdint.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
#include <unistd.h> |
||||||
|
|
||||||
|
#include <libipset/ipset.h> |
||||||
|
|
||||||
|
#include "../strlcpy.h" |
||||||
|
|
||||||
|
#include "backend.h" |
||||||
|
#define MODNAME "ipset" |
||||||
|
|
||||||
|
#define IP_LEN_MAX 46 /* ipv6 in mind */ |
||||||
|
|
||||||
|
struct _config { |
||||||
|
char name[ID_MAX + 1]; |
||||||
|
void (*logcb)(enum loglevel lvl, const char *msg); |
||||||
|
struct ipset *ipset; |
||||||
|
enum ipset_cmd last_cmd; |
||||||
|
int flags; |
||||||
|
bool shared; |
||||||
|
}; |
||||||
|
|
||||||
|
#include "backend.c" |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wrapper to get last ipset error and send to log |
||||||
|
* @note Called from this module */ |
||||||
|
inline static bool |
||||||
|
my_ipset_error(cfg_t *cfg, const char *func) { |
||||||
|
struct ipset_data *data = NULL; |
||||||
|
struct ipset_session *sess = ipset_session(cfg->ipset); |
||||||
|
|
||||||
|
if (ipset_session_report_type(sess) != IPSET_NO_ERROR) { |
||||||
|
log_msg(cfg, error, "%s: %s", func, ipset_session_report_msg(sess)); |
||||||
|
ipset_session_report_reset(sess); |
||||||
|
} |
||||||
|
|
||||||
|
if ((data = ipset_session_data(sess)) != NULL) |
||||||
|
ipset_data_reset(data); |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* @note Called from library internals |
||||||
|
*/ |
||||||
|
int |
||||||
|
my_ipset_std_error_cb(struct ipset *ipset, void *cfg) { |
||||||
|
struct ipset_session *sess = ipset_session(ipset); |
||||||
|
|
||||||
|
switch (ipset_session_report_type(sess)) { |
||||||
|
case IPSET_NOTICE : |
||||||
|
case IPSET_WARNING : |
||||||
|
if (!ipset_envopt_test(sess, IPSET_ENV_QUIET)) |
||||||
|
log_msg(cfg, error, "warning: %s", ipset_session_report_msg(sess)); |
||||||
|
break; |
||||||
|
case IPSET_ERROR : |
||||||
|
default: |
||||||
|
if (((cfg_t *) cfg)->last_cmd != IPSET_CMD_TEST) { |
||||||
|
log_msg(cfg, error, "error: %s", ipset_session_report_msg(sess)); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
ipset_session_report_reset(sess); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
cfg_t * |
||||||
|
create(const char *id) { |
||||||
|
cfg_t *cfg = NULL; |
||||||
|
|
||||||
|
assert(id != NULL); |
||||||
|
|
||||||
|
if ((cfg = calloc(1, sizeof(cfg_t))) == NULL) |
||||||
|
return NULL; |
||||||
|
strlcpy(cfg->name, id, sizeof(cfg->name)); |
||||||
|
cfg->logcb = &logcb_stub; |
||||||
|
cfg->flags |= MOD_IS_READY; |
||||||
|
cfg->flags |= MOD_TYPE_BACKEND; |
||||||
|
cfg->last_cmd = IPSET_CMD_NONE; |
||||||
|
return cfg; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
config(cfg_t *cfg, const char *key, const char *value) { |
||||||
|
assert(cfg != NULL); |
||||||
|
assert(key != NULL); |
||||||
|
assert(value != NULL); |
||||||
|
|
||||||
|
(void)(cfg); |
||||||
|
(void)(key); |
||||||
|
(void)(value); |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
start(cfg_t *cfg) { |
||||||
|
assert(cfg != NULL); |
||||||
|
|
||||||
|
if (cfg->shared && usage_inc(cfg->name) > 1) |
||||||
|
return true; |
||||||
|
|
||||||
|
ipset_load_types(); |
||||||
|
|
||||||
|
if ((cfg->ipset = ipset_init()) == NULL) { |
||||||
|
log_msg(cfg, error, "can't init ipset library"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (ipset_session_output(ipset_session(cfg->ipset), IPSET_LIST_NONE) < 0) |
||||||
|
return my_ipset_error(cfg, "ipset_session_output()"); |
||||||
|
|
||||||
|
if (ipset_envopt_parse(cfg->ipset, IPSET_ENV_EXIST, NULL) < 0) |
||||||
|
return my_ipset_error(cfg, "ipset_envopt_parse()"); |
||||||
|
ipset_custom_printf(cfg->ipset, NULL, &my_ipset_std_error_cb, NULL, (void *) cfg); |
||||||
|
ipset_envopt_set(ipset_session(cfg->ipset), IPSET_ENV_QUIET); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
stop(cfg_t *cfg) { |
||||||
|
assert(cfg != NULL); |
||||||
|
|
||||||
|
if (cfg->shared && usage_dec(cfg->name) > 0) |
||||||
|
return true; |
||||||
|
|
||||||
|
if (cfg->ipset) { |
||||||
|
ipset_fini(cfg->ipset); |
||||||
|
cfg->ipset = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
ban(cfg_t *cfg, const char *ip) { |
||||||
|
char ipw[IP_LEN_MAX] = ""; |
||||||
|
char *argv[] = { "ignored", "add", cfg->name, ipw, NULL }; |
||||||
|
assert(cfg != NULL); |
||||||
|
strlcpy(ipw, ip, sizeof(ipw)); |
||||||
|
cfg->last_cmd = IPSET_CMD_ADD; |
||||||
|
return ipset_parse_argv(cfg->ipset, 4, argv) == 0; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
unban(cfg_t *cfg, const char *ip) { |
||||||
|
char ipw[IP_LEN_MAX] = ""; |
||||||
|
char *argv[] = { "ignored", "del", cfg->name, ipw, NULL }; |
||||||
|
assert(cfg != NULL); |
||||||
|
strlcpy(ipw, ip, sizeof(ipw)); |
||||||
|
cfg->last_cmd = IPSET_CMD_DEL; |
||||||
|
return ipset_parse_argv(cfg->ipset, 4, argv) == 0; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
check(cfg_t *cfg, const char *ip) { |
||||||
|
char ipw[IP_LEN_MAX] = ""; |
||||||
|
char *argv[] = { "ignored", "test", cfg->name, ipw, NULL }; |
||||||
|
assert(cfg != NULL); |
||||||
|
strlcpy(ipw, ip, sizeof(ipw)); |
||||||
|
cfg->last_cmd = IPSET_CMD_TEST; |
||||||
|
return ipset_parse_argv(cfg->ipset, 4, argv) == 0; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
ping(cfg_t *cfg) { |
||||||
|
assert(cfg != NULL); |
||||||
|
|
||||||
|
(void)(cfg); /* silence warning about unused variable */ |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
void |
||||||
|
destroy(cfg_t *cfg) { |
||||||
|
assert(cfg != NULL); |
||||||
|
|
||||||
|
free(cfg); |
||||||
|
} |
Loading…
Reference in new issue