From: Martin Mares Date: Sat, 5 Nov 2016 10:19:15 +0000 (+0100) Subject: More configurability X-Git-Tag: v1.0~15 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=3218fda60265b9944c34e55fa3f8b91293991721;p=bouncer.git More configurability --- diff --git a/bouncer.c b/bouncer.c index d747a3a..25e3e30 100644 --- a/bouncer.c +++ b/bouncer.c @@ -6,6 +6,8 @@ * FIXME: ipset create bouncer4 hash:ip family inet * FIXME: ipset create bouncer6 hash:ip family inet6 * FIXME: sshd_config: UseDNS no + * FIXME: PAM module names should be made configurable + * FIXME: Parse "N more failures" messages */ #define LOCAL_DEBUG @@ -13,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -21,7 +24,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -87,27 +92,27 @@ static bool addr_parse(struct addr *addr, const char *src) /*** Configuration ***/ +static char *listen_on = "/var/run/bouncer.sock"; static uns max_failures = ~0U; static uns max_suspect_time = 86400; static uns max_banned_time = 86400; static uns max_suspects = ~0U; static uns max_banned = ~0U; - -/* - * FIXME: - * - names of ipsets - * - name of socket - * - logging - * - PAM module name(s) to match - */ +static char *ipv4_set; +static char *ipv6_set; +static char *config_log_stream; static struct cf_section bouncer_cf = { CF_ITEMS { + CF_STRING("ListenOn", &listen_on), CF_UNS("MaxSuspects", &max_suspects), CF_UNS("MaxBanned", &max_banned), CF_UNS("MaxSuspectTime", &max_suspect_time), CF_UNS("MaxBannedTime", &max_banned_time), CF_UNS("MaxFailures", &max_failures), + CF_STRING("IPv4Set", &ipv4_set), + CF_STRING("IPv6Set", &ipv6_set), + CF_STRING("LogStream", &config_log_stream), CF_END } }; @@ -116,16 +121,6 @@ static struct cf_section bouncer_cf = { static struct ipset_session *is_sess; -enum is_index { - IS_IPV4, - IS_IPV6, -}; - -static const char * const is_names[] = { - "bouncer4", - "bouncer6", -}; - static const char *trim_eol(const char *msg) { int len = strlen(msg); @@ -170,24 +165,31 @@ static void is_init(void) die("Unable to initialize ipset session"); } -static void is_setup(int set) +static bool is_setup(char *set) { - if (ipset_parse_setname(is_sess, IPSET_SETNAME, is_names[set]) < 0) + if (!set) + return 0; + + if (ipset_parse_setname(is_sess, IPSET_SETNAME, set) < 0) is_die("ipset_parse_setname"); + return 1; } -static void is_flush(int set) +static void is_flush(char *set) { - is_setup(set); + if (!is_setup(set)) + return; if (ipset_cmd(is_sess, IPSET_CMD_FLUSH, 0) < 0) return is_err("IPSET_CMD_FLUSH"); } -static void is_modify(bool add, struct addr addr) +static bool is_modify(bool add, struct addr addr) { - is_setup(addr_is_v4(addr) ? IS_IPV4 : IS_IPV6); int cmd = add ? IPSET_CMD_ADD : IPSET_CMD_DEL; + char *set = addr_is_v4(addr) ? ipv4_set : ipv6_set; + if (!is_setup(set)) + return 0; if (ipset_envopt_parse(is_sess, IPSET_ENV_EXIST, NULL) < 0) is_die("IPSET_ENV_EXIST"); @@ -202,10 +204,18 @@ static void is_modify(bool add, struct addr addr) char buf[ADDR_BUFSIZE]; addr_format(buf, addr); if (ipset_parse_elem(is_sess, 0, buf) < 0) - return is_err("ipset_parse_elem"); + { + is_err("ipset_parse_elem"); + return 0; + } if (ipset_cmd(is_sess, cmd, 0) < 0) - return is_err(add ? "IPSET_CMD_ADD" : "IPSET_CMD_DEL"); + { + is_err(add ? "IPSET_CMD_ADD" : "IPSET_CMD_DEL"); + return 0; + } + + return 1; } /*** Handling of login failures ***/ @@ -249,7 +259,15 @@ static void cleanup_list(clist *list, uns *counter, timestamp_t max_time, uns ma timestamp_t expire_in = c->last_fail + max_time - now; if (*counter > max_count) { - // FIXME: Warn with rate limit + static timestamp_t last_overflow_warning; + if (last_overflow_warning + 60000 < now) + { + last_overflow_warning = now; + if (c->banned) + msg(L_WARN, "Too many bans, dropping some. Try increasing MaxBanned."); + else + msg(L_WARN, "Too many suspects, dropping some. Try increasing MaxSuspects."); + } expire_in = 0; } @@ -261,13 +279,11 @@ static void cleanup_list(clist *list, uns *counter, timestamp_t max_time, uns ma if (c->banned) { - DBG("%s: unbanned", AFMT(c->addr)); + msg(L_INFO, "Unbanning %s", AFMT(c->addr)); is_modify(0, c->addr); } else - { - DBG("%s: removed from LRU", AFMT(c->addr)); - } + msg(L_DEBUG, "Suspect %s: acquitted", AFMT(c->addr)); clist_remove(&c->n); culprit_remove(c); @@ -296,7 +312,7 @@ static void handle_failed_login(struct addr addr) c->banned = 0; clist_add_tail(&suspect_list, &c->n); num_suspects++; - DBG("%s: first fail", AFMT(addr)); + msg(L_DEBUG, "Suspect %s: new", AFMT(addr)); } else if (!c->banned) { @@ -304,12 +320,12 @@ static void handle_failed_login(struct addr addr) c->fail_count++; clist_remove(&c->n); clist_add_tail(&suspect_list, &c->n); - DBG("%s: next fail, cnt=%u", AFMT(addr), c->fail_count); + msg(L_DEBUG, "Suspect %s: failures=%u", AFMT(addr), c->fail_count); } if (!c->banned && c->fail_count >= max_failures) { - DBG("%s: banned", AFMT(addr)); + msg(L_INFO, "Banning %s: failures=%u", AFMT(addr), c->fail_count); c->banned = 1; clist_remove(&c->n); num_suspects--; @@ -374,7 +390,7 @@ static void process_msg(char *line) return; DBG("Parse 2: <%s>", p); - // pam_unix(something), colon, space (FIXME: make configurable) + // pam_unix(something), colon, space if (!check_next(&p, "pam_unix(")) return; do @@ -433,7 +449,6 @@ static void process_msg(char *line) /*** Socket for receiving messages from rsyslog ***/ -static const char sk_name[] = "/var/run/bouncer.sock"; struct main_file sk_file; static int sk_read(struct main_file *mf) @@ -465,22 +480,23 @@ static int sk_read(struct main_file *mf) static void sk_init(void) { - unlink(sk_name); + unlink(listen_on); + mode_t old_umask = umask(0077); int fd; if ((fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) die("Cannot create PF_UNIX socket: %m"); struct sockaddr_un sa = { .sun_family = AF_UNIX }; - strcpy(sa.sun_path, sk_name); + strcpy(sa.sun_path, listen_on); if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) - die("Cannot bind socket %s: %m", sk_name); - - // FIXME: Permissions + die("Cannot bind socket %s: %m", listen_on); sk_file.fd = fd; sk_file.read_handler = sk_read; file_add(&sk_file); + + umask(old_umask); } /*** Main ***/ @@ -502,16 +518,18 @@ int main(int argc UNUSED, char **argv) cf_declare_section("Bouncer", &bouncer_cf, 0); opt_parse(&options, argv+1); + if (config_log_stream) + log_configured(config_log_stream); + main_init(); is_init(); fail_init(); - - // FIXME msg(L_INFO, "Clearing previous state"); - is_flush(IS_IPV4); - is_flush(IS_IPV6); - sk_init(); + is_flush(ipv4_set); + is_flush(ipv6_set); + + msg(L_INFO, "Starting"); main_loop(); return 0; }