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 |
||||
CMakeFiles/ |
||||
*.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] |
||||
load = backend_exec.so |
||||
ban = /sbin/ipfw table <ID> add <IP> |
||||
unban = /sbin/ipfw table <ID> delete <IP> |
||||
ban = /sbin/ipfw -q table <ID> add <IP> |
||||
unban = /sbin/ipfw -q table <ID> delete <IP> |
||||
timeout = 2 |
||||
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 |
@ -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