fail2ban + ufw nem megy

/etc/fail2ban/filter.d/pizzaseo.conf -ban:

 

[INCLUDES]
before = common.conf

[Definition]
failregex = .*queries: client @0x.* <HOST>#.*\(pizzaseo.com\): query: pizzaseo.com
ignoreregex =

/etc/jail.local -ban:

 

[DEFAULT]
bantime   = 3600
banaction = ufw
blocktype = deny


[named-pizzaseo]
enabled  = true
filter   = pizzaseo
logpath  = /var/log/named/named-querylog
maxretry = 3
findtime = 60
bantime  = 1800
ignoreip = 127.0.0.1/8 ::1

Elvileg működik, mert bannolta őket:

# fail2ban-client status named-pizzaseo                                                                                                                                                                    130 ↵
Status for the jail: named-pizzaseo
|- Filter
|  |- Currently failed:	1
|  |- Total failed:	98
|  `- File list:	/var/log/named/named-querylog
`- Actions
   |- Currently banned:	5
   |- Total banned:	5
   `- Banned IP list:	165.73.94.72 51.210.48.107 74.207.29.61 77.96.28.197 193.201.64.182

A tűzfal szabályok között is látszódik, például:

# ufw status | grep 165.73.94.72       
Anywhere                   DENY        165.73.94.72              

Ennek ellenére továbbra is jönnek befelé a kérések, és a fail2ban panaszkodik is emiatt:

2021-08-05 18:24:35,616 fail2ban.actions        [12825]: WARNING [named-pizzaseo] 165.73.94.72 already banned

Az "ufw status numbered" az összes "ALLOW IN" szabályt a "DENY IN" szabályok után mutatja.

Hogy lehetséges ez?

Hozzászólások

Mondjuk az első tippem az lett volna, hogy UDP-t nem blokkol csak TCP-t. De a szabályban nem ez látszódik...

Az ufw,conf -ban ez van:

[Definition]

actionstart = 

actionstop = 

actioncheck = 

actionban = [ -n "<application>" ] && app="app <application>"
            ufw insert <insertpos> <blocktype> from <ip> to <destination> $app

actionunban = [ -n "<application>" ] && app="app <application>"
              ufw delete <blocktype> from <ip> to <destination> $app

Biztos ez lehet akkor a gond, hogy alapból csak TCP-t blokkol. De miért? :-(

részemről a firejail tűzfal generátorral kombináltam a fail2ban, különböző kombinációkban

a lényeg, hogy nem mindegy, hogy az iptables chain-ek közül melyik sorrendben veszi át, majd adja vissza a "folyamot" a fail2ban

iptables -L -n -el meg kell nézni, hogy a (ufw) tűzfal milyen rule-okat generált, utána a megfelelő sorba "beszúrni" a fail2ban chaineket

a "chain" paraméter a barátod, ami megmondja melyik chain hányadik sorába "insert"-eli a fail2ban az elágazását

kicsi példa:

[sshd]
enabled = true
backend=systemd
chain=in_world 3
maxretry = 2

[recidive]
enabled=true
chain=INPUT
banaction = iptables-allports
blocktype = DROP
logpath  = /var/log/fail2ban.log
bantime  = 2419200  ; 2 weeks
findtime = 1814400   ; 3 weeks
maxretry = 4

itt az sshd nálam az in_world 3.sorába van beszúrva, mert van előtte ami "univerzálisan érvényes", a recidive (ami magát a fail2ban logját vizsgálja ismétlődésekre), simán az INPUT chain legeljére kerül, még az ACCEPT elé, mivel univerzális DROP

Köszönöm, ez nagyon hasznos volt.

Igazából az "iptables -L -n -v" még jobb. A -v nélkül nem látszódik az input/output interface, és ez becsaphat (lásd alább).

Azt feltételeztem, hogy az ufw olyan sorrendben írja ki a szabályokat, ahogyan azok lefutnak.

Az "ufw status numbered" így kezdődik:

Status: active

     To                         Action      From
     --                         ------      ----
[ 1] Anywhere                   DENY IN     156.38.43.253
[ 2] Anywhere                   DENY IN     173.247.255.16
[ 3] Anywhere                   DENY IN     174.137.57.79
[ 4] Anywhere                   DENY IN     71.217.160.96
[ 5] Anywhere                   DENY IN     98.159.78.71
[ 6] Anywhere                   DENY IN     98.239.46.236
[ 7] Anywhere                   DENY IN     222.187.239.109
[ 8] Anywhere                   DENY IN     23.240.127.150

tehát a deny-ok vannak az elején, és az ACCEPT-ek csak jóval később:

[42] Anywhere                   DENY IN     222.186.42.7
[43] Anywhere                   DENY IN     98.222.63.40
[44] Anywhere                   DENY IN     73.121.33.180
[45] 22/tcp                     ALLOW IN    Anywhere
[46] 80/tcp                     ALLOW IN    Anywhere
[47] 443/tcp                    ALLOW IN    Anywhere
[48] 53                         ALLOW IN    Anywhere

Az iptables -L szerint így jönnek a chain-ek:

╭─root@ns1 ~
╰─# iptables -L INPUT
Chain INPUT (policy DROP)
target     prot opt source               destination
ufw-before-logging-input  all  --  anywhere             anywhere
ufw-before-input  all  --  anywhere             anywhere
ufw-after-input  all  --  anywhere             anywhere
ufw-after-logging-input  all  --  anywhere             anywhere
ufw-reject-input  all  --  anywhere             anywhere
ufw-track-input  all  --  anywhere             anywhere
╭─root@ns1 ~
╰─# iptables -L ufw-before-logging-input # ÜRES
Chain ufw-before-logging-input (1 references)
target     prot opt source               destination
╭─root@ns1 ~
╰─# iptables -L ufw-before-input -v # EZ ITT A LÉNYEG
Chain ufw-before-input (1 references)
 pkts bytes target     prot opt in     out     source               destination
 272K   22M ACCEPT     all  --  lo     any     anywhere             anywhere
 388K   31M ACCEPT     all  --  any    any     anywhere             anywhere             ctstate RELATED,ESTABLISHED
 2683  305K ufw-logging-deny  all  --  any    any     anywhere             anywhere             ctstate INVALID
 2683  305K DROP       all  --  any    any     anywhere             anywhere             ctstate INVALID
    0     0 ACCEPT     icmp --  any    any     anywhere             anywhere             icmp destination-unreachable
    0     0 ACCEPT     icmp --  any    any     anywhere             anywhere             icmp time-exceeded
    0     0 ACCEPT     icmp --  any    any     anywhere             anywhere             icmp parameter-problem
 3083  205K ACCEPT     icmp --  any    any     anywhere             anywhere             icmp echo-request
 620K  219M ACCEPT     udp  --  any    any     anywhere             anywhere             udp spt:bootps dpt:bootpc
 362K   20M ufw-not-local  all  --  any    any     anywhere             anywhere
    0     0 ACCEPT     udp  --  any    any     anywhere             224.0.0.251          udp dpt:mdns
    0     0 ACCEPT     udp  --  any    any     anywhere             239.255.255.250      udp dpt:1900
 362K   20M ufw-user-input  all  --  any    any     anywhere             anywhere

Szóval az ufw-before-logging-input üres. Minden az ufw-user-input -ba megy, és ott meg jól van a sorrend. Az elején vannak a droppok:

╭─root@ns1 ~
╰─# iptables -L ufw-user-input -n -v | head -10                                                                                              130 ↵
Chain ufw-user-input (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DROP       all  --  *      *       64.227.29.26         0.0.0.0/0
    9   540 DROP       all  --  *      *       61.177.172.13        0.0.0.0/0
    0     0 DROP       all  --  *      *       73.7.240.187         0.0.0.0/0
    0     0 DROP       all  --  *      *       122.4.249.171        0.0.0.0/0
    0     0 DROP       all  --  *      *       221.181.185.223      0.0.0.0/0
    0     0 DROP       all  --  *      *       71.50.223.162        0.0.0.0/0
    0     0 DROP       all  --  *      *       222.187.238.136      0.0.0.0/0
    0     0 DROP       all  --  *      *       75.129.100.82        0.0.0.0/0

A végén vannak az accept-ek:

╭─root@ns1 ~
╰─# iptables -L ufw-user-input -n -v | tail -10
    0     0 DROP       all  --  *      *       36.134.61.13         0.0.0.0/0
    0     0 DROP       all  --  *      *       49.235.61.62         0.0.0.0/0
    0     0 DROP       all  --  *      *       177.138.127.152      0.0.0.0/0
    3   180 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:443
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:53
    1    71 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:53

Szóval például ez is benne van:

╭─root@ns1 ~
╰─# iptables -L ufw-user-input -n -v | grep 177.138.127.152                                                                                  130 ↵
    0     0 DROP       all  --  *      *       177.138.127.152      0.0.0.0/0

Ennek ellenére még ma reggel is szorgalmasan jönnek:


2021-08-06 07:47:41,180 fail2ban.actions        [16781]: WARNING [named-pizzaseo] 177.138.127.152 already banned

Átnéztem újra a szabályokat, és jelenleg csak azt tudom elképzelni, hogy azért nincsen hatása a DENY rule-oknak, mert az ufw-before-input-ban itt van ez a sor, még az ufw-user-input chain-re való ugrás előtt:

 388K   31M ACCEPT     all  --  any    any     anywhere             anywhere             ctstate RELATED,ESTABLISHED

Az a gáz ezzel, hogy ezek valószínűleg UDP csomagok. Az pedig alapvetően stateless, a netstat-tal nem tudom megkeresni. Az iptables -nek van saját UDP connection tracking-je, de azt meg nem tudom hogy hogy lehet lekérdezni.

Vagy az is lehet hogy tévedek, és nem ez a baj. De más ötletem nincs. :-(

Akkor most megpróbálom átírni a fail2ban configot úgy, hogy ufw-before-logging-input chain-be tegye bele a szabályokat. Gondolom az működni fog. Viszont mivel így a szabályok a RELATED,ESTABLISHED elé kerülnek, ezért ez valószínűleg be fogja lassítani a tűzfalat. (Át kell mennie az összes DENY szabályon mielőtt a RELATED,ESTABLISHED -et megnézné.)

Sajnos ez nem nyert. Az "ufw insert" parancsnak nincs olyan beállítása, hogy melyik chain-be szúrja be a szabályt!

Helyette megpróbálom azt, hogy átállítom a fail2ban-t iptables -re, és annak mondom meg a chain-t.

Oké szóval a sima iptables action nem jó erre. A fail2ban-hoz alapból adott iptables action olyan, hogy kötelező megadni a protocol-t és a portot. A --dport paraméter csak akkor használható, ha a proto -ban megadsz egy konkrét protokolt. (Nyilván ha proto=all akkor a dport nem adható meg, mert vannak olyan protokollok amiknél nincs értelmezve a destination port.) Viszont a named lekérdezések bejöhetnek TCP-n és UDP-n is, és a fail2ban által elemezett naplóból nem látszódik, hogy hol jött be. Szóval TCP-t és UDP-t is blokkolni kellene. De ezt nem lehet, mert egy banaction nem tud egyszerre kétféle protocol-ra szabályt létrehozni. Kivéve ha proto=all -t adsz meg. De akkor meg nem tudsz dport -ot használni. Viszont az meg kötelező. (Nem iptables-ben hanem a fail2ban "iptables" action-jában.)

A következő lett a megoldás:

[DEFAULT]
bantime   = 3600
banaction = iptables

[named-pizzaseo]
enabled  = true
filter   = pizzaseo
banaction = iptables-allports
blocktype = DROP
protocol = all
logpath  = /var/log/named/named-querylog
maxretry = 3
findtime = 60
bantime  = 1800
ignoreip = 127.0.0.1/8 ::1

Szóval az "iptables-allports" action-t kell használni. Az nem ad hozzá destination port feltételt a szabályhoz. Emiatt használható a protocol=all.

A fenti beállítás hatására az alábbi szabályok képződtek. Egyrészt az ufw szabályok elé tette be ezeket:

╭─root@ns1 /etc/fail2ban
╰─# iptables -L INPUT -n -v                                                                                                                  130 ↵
Chain INPUT (policy DROP 1 packets, 40 bytes)
 pkts bytes target     prot opt in     out     source               destination
 2978  386K f2b-named-pizzaseo  all  --  *      *       0.0.0.0/0            0.0.0.0/0
 1737  139K f2b-sshd   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
1666K  295M ufw-before-logging-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0
1666K  295M ufw-before-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0
 202K 9707K ufw-after-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0
 120K 5527K ufw-after-logging-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0
 120K 5527K ufw-reject-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0
 120K 5527K ufw-track-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0

és megszűntek az "already banned" üzenetek, ez tök jó.

De még mindig van minimum egy probléma, az hogy a blocktype=DROP figyelmen kívül lett hagyva:

╭─root@ns1 /etc/fail2ban
╰─# iptables -L f2b-named-pizzaseo -n -v
Chain f2b-named-pizzaseo (1 references)
 pkts bytes target     prot opt in     out     source               destination
    3   174 REJECT     all  --  *      *       73.214.251.185       0.0.0.0/0            reject-with icmp-port-unreachable
   12   696 REJECT     all  --  *      *       24.4.97.106          0.0.0.0/0            reject-with icmp-port-unreachable
   25  1450 REJECT     all  --  *      *       68.104.72.27         0.0.0.0/0            reject-with icmp-port-unreachable
    9   522 REJECT     all  --  *      *       50.92.145.184        0.0.0.0/0            reject-with icmp-port-unreachable
   29  1682 REJECT     all  --  *      *       72.179.110.90        0.0.0.0/0            reject-with icmp-port-unreachable
   34  1972 REJECT     all  --  *      *       98.34.56.115         0.0.0.0/0            reject-with icmp-port-unreachable
    0     0 REJECT     all  --  *      *       76.22.203.50         0.0.0.0/0            reject-with icmp-port-unreachable
   23  1334 REJECT     all  --  *      *       177.138.127.152      0.0.0.0/0            reject-with icmp-port-unreachable
    0     0 REJECT     all  --  *      *       142.247.82.218       0.0.0.0/0            reject-with icmp-port-unreachable
   42  2436 REJECT     all  --  *      *       108.76.202.32        0.0.0.0/0            reject-with icmp-port-unreachable
 2860  386K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Még ezt jellene kitalálni, hogy DROP helyett miért reject-with-icmp-port-unreachable -t használ?

Oké kiderült hogy miért használ DROP helyett REJECT-et. Rossz helyre írtam a paramétert.

Helyesen így néz ki:

banaction=iptables_allports[blocktype=DROP,protocol=all]

Illetve a REJECT változata:

banaction=iptables_allports[blocktype=REJECT --reject-with icmp-port-unreachable"]

Ami még nagyon érdekes, hogy az iptables_allports -nak van egy protocol paramétere, de ha csak azt használod, akkor az nem fog működni. Ha minden protokollt bannolni akarsz, akkor a jail szintjén is be kell állítani, valahogy így:

banaction=iptables_allports[blocktype=DROP,protocol=all]
protocol=all

Ennek az a magyarázata, hogy a jail config egy új iptables chain-t hoz létre, és a banaction ezen belül külön DROP vagy REJECT rule-okat. Ha a jail szinten nem adod meg hogy protocol=all, akkor a chain így jön létre:

# iptables -L INPUT -n -v
Chain INPUT (policy DROP 22 packets, 952 bytes)
 pkts bytes target     prot opt in     out     source               destination         
 1371  229K f2b-named-pizzaseo  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           

Bár az igaz, hogy a f2b-named-pizzaseo chain-en belüli szabályok minden protokollra illeszkedni fognak. De maga a chain nem - az csak TCP-re lesz használva. Ha jail szinten is megadod a protocol=all -t, akkor jó lesz:

# iptables -L INPUT -n -v
Chain INPUT (policy DROP 22 packets, 952 bytes)
 pkts bytes target     prot opt in     out     source               destination         
 1371  229K f2b-named-pizzaseo  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Nem tudtam róla, hogy kétféle protocol nevű paraméter is van, ezért amikor próbálkoztam, akkor sehogy nem akart összejönni a szűrés. De most már jó. :-)

> Ha jail szinten is megadod a protocol=all -t, akkor jó lesz

Ez mondjuk túlzás. Nem jó lesz, csak működni fog. Jó akkor lesz, ha a chain-be ugrásnál is elő van írva a dst port feltétel, mert akkor hatékony is. De ahhoz hogy hatékony is legyen meg működjön is, saját action-t kell írni. Olyat mint az iptables, csak ezekkel a módosításokkal:

 

actionstart = <iptables> -N f2b-<name>
              <iptables> -A f2b-<name> -j <returntype>
              <iptables> -I <chain> -p tcp --dport <port> -j f2b-<name>
              <iptables> -I <chain> -p udp --dport <port> -j f2b-<name>

actionstop = <iptables> -D <chain> -p tcp --dport <port> -j f2b-<name>
             <iptables> -D <chain> -p udp --dport <port> -j f2b-<name>
             <actionflush>
             <iptables> -X f2b-<name>

Ez ilyet generál:

# iptables -L INPUT -n -v                 
Chain INPUT (policy DROP 8 packets, 336 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  171 11665 f2b-named-pizzaseo  udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:53
    0     0 f2b-named-pizzaseo  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:53

Ami jó, mert így a chain-be csak az a packet megy bele, aminél dst-port=53 és protocol=(tcp vagy udp). De ilyen feltételt a "gyári" action-ökkel nem lehet csinálni.