Postado em 01.08.2011 00:00
Se não existe um filtro pronto para o log que você deseja monitorar em `filter.d`, será necessário criar seu próprio filtro. Mostrarei como fazer isso através do exemplo que descrevo abaixo:
Mantenho um wiki [moinmoin](http://moinmo.in/) e desejo bloquear o acesso à ele pelos hosts que tentarem login por mais de 3 vezes sem sucesso. Vamos fazer um filtro para fazer esse bloqueio. O log do wiki é escrito em `/var/log/moinmoin.log`. Segue trecho desse log:
2011-07-12 15:45:40,447 MoinMoin.Page WARNING The page "MissingPage" could not be found. Check your underlay directory setting. 2011-07-12 15:45:44,002 MoinMoin.auth WARNING moin: performing login action | request from 192.168.0.10 2011-07-12 15:45:44,003 MoinMoin.auth WARNING moin: could not authenticate user u'GuilhermeGall' (not valid) | request from 192.168.0.10 2011-07-12 15:45:44,030 MoinMoin.Page WARNING The page "MissingPage" could not be found. Check your underlay directory setting. 2011-07-12 15:45:47,705 MoinMoin.auth WARNING moin: performing login action | request from 192.168.0.10 2011-07-12 15:45:47,706 MoinMoin.auth WARNING moin: could not authenticate user u'GuilhermeGall' (not valid) | request from 192.168.0.10 2011-07-12 15:45:47,732 MoinMoin.Page WARNING The page "MissingPage" could not be found. Check your underlay directory setting. 2011-07-12 15:55:59,473 MoinMoin.Page WARNING The page "MissingPage" could not be found. Check your underlay directory setting. 2011-07-12 16:08:51,543 MoinMoin.Page WARNING The page "MissingPage" could not be found. Check your underlay directory setting. 2011-07-13 09:09:01,908 MoinMoin.auth WARNING moin: performing login action | request from 192.168.0.7
Não é difícil perceber que as linhas com `could not authenticate user u'GuilhermeGall' (not valid)` representam as tentativas de login malsucedidas. Se desejamos bloquear os hosts de origem dessas tentativas temos que fazer a regex do filtro casar essas linhas e usar o IP que aparece nelas para executar nossa ação (por *default*, bloquear via `iptables`).
Antes de criar nosso filtro, vamos entender a estrutura de um filtro e como desenvolver nossas próprias regexes.
Um filtro é simplesmente um arquivo com uma entrada `failregex`, que define as regexes que casam as linhas que representam as tentativas de login malsucedidas, e uma entrada `ignoreregex`, que define regexes que casam com linhas que devem ser ignoradas. Outras entradas podem existir, como `before` que faz um “import” de outro arquivo, mas `failregex` e `ignoreregex` são as essenciais e usadas na maioria dos casos.
Se for definir mais de uma regex para `failregex` ou `ignoreregex`, coloque uma por linha. Exemplo do arquivo `filter.d/apache-auth.conf` que já vem no pacote `fail2ban`:
[Definition] # Option: failregex # Notes.: regex to match the password failure messages in the logfile. The # host must be matched by a group named "host". The tag "<HOST>" can # be used for standard IP/hostname matching and is only an alias for # (?:::f{4,6}:)?(?P<host>[\w\-.^_]+) # Values: TEXT # failregex = [[]client <HOST>[]] user .* authentication failure [[]client <HOST>[]] user .* not found [[]client <HOST>[]] user .* password mismatch # Option: ignoreregex # Notes.: regex to ignore. If this regex matches, the line is ignored. # Values: TEXT # ignoreregex =
Conforme pode ser lido nos comentários do arquivo acima, a tag `<HOST>` deve aparecer dentro da regex na posição onde aparece o IP/hostname do host ofensor. Repare que mais de uma regex foi definida para `failregex` – uma em cada linha – e que `ignoreregex` pode ser vazio.
Para escrever suas próprias regexes para o `fail2ban` é preciso ter em mente o seguinte:
- Em toda linha de uma `failregex`, a parte que casa com o IP/hostname deve estar envolta pela estrutura `(?P<host> ... )`. Essa estrutura é uma extensão específica do Python que atribui o nome `<host>` ao que foi casado pelo grupo. A tag `<host>` é como você informa ao `fail2ban` qual host estava tentando logar.
- Como conveniência, é possível usar `<HOST>` nas suas regexes, conforme citei no tópico anterior. `<HOST>` é um alias para `(?:::f{4,6}:)?(?P<host>\S+)` que casa um IP/hostname dentro de um grupo chamado `<host>`. Vide item anterior.
- Nas ações, a tag `<ip>` será substituída pelo IP do host casado pela tag `<host>`, por isso sempre deve existir um grupo nomeado `<host>`.
- Para que uma linha de um log case com sua `failregex`, ela deve casar em duas partes: o início da linha tem que casar com um padrão de *timestamp* e o restante da linha deve casar com a regex definida em `failregex`. Se sua `failregex` possui a âncora `^`, então a âncora refere-se ao início do restante da linha, após o *timestamp*.
- Por último, mas não menos importante, o comando `fail2ban-regex` permite testar suas regexes antes de criar o filtro. Na realidade, como escrever suas próprias regexes pode envolver alguma – muita! – tentativa e erro no começo, eu diria que esse é o item mais importante. 🙂 Ele pode ser usado de duas maneiras:
fail2ban-regex /path/para/arquivo.log '^regex a ser testada