Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Policy Based Routing (pbr) action #3466

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Conversation

k0ste
Copy link

@k0ste k0ste commented Feb 22, 2023

More granular blocking compared with 'route' action

The main diffence is that possible to block single service port, instead of blocking whole IP address. How this works

When banaction is success, the <ip> will be added to ip rules:

[root@host /]# ip rule list | grep 211.245.106.55
185:    from all to 211.245.106.55 ipproto tcp sport 22 lookup 666

As we can see, only sshd service will be blocked for this <ip>
We can check this:

[root@host /]# ip route get 211.245.106.55
211.245.106.55 via 192.168.102.1 dev po1 src 192.168.102.254 uid 0

The output for this <ip> is not blocked, but sshd service for this <ip> will be banned:

[root@host /]# ip ro get 211.245.106.55 sport 22 ipproto tcp
RTNETLINK answers: No route to host

@k0ste
Copy link
Author

k0ste commented Dec 17, 2023

@sebres can you take a look? We use this action for a whole year. Works for us very effective, without netfilter

[root@host /]# ip -c rule show sport 22 ipproto tcp | wc -l
147 <---------
[root@host /]# fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 11
|  |- Total failed:     8383
|  `- Journal matches:  _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
   |- Currently banned: 147 <-----------
   |- Total banned:     1694
   `- Banned IP list:   43.153.109.215 157.230.91.199 27.71.16.216 205.185.127.188 43.128.89.189 121.7.250.114 178.174.14.131 154.12.177.47 51.38.112.61 43.153.30.11 43.156.114.195 68.116.41.2 138.197.31.240 103.77.214.9 43.153.168.2 43.156.101.55 14.63.162.98 43.156.109.253 138.68.240.114 102.218.10.141 43.154.207.124 43.155.175.9 43.159.45.214 115.166.142.18 134.209.153.189 138.68.239.113 142.171.217.16 61.7.241.146 45.189.108.220 43.163.234.214 103.148.29.248 111.231.144.100 101.36.108.106 186.121.240.39 146.190.58.73 211.101.232.14 51.195.119.0 20.141.110.74 159.65.136.44 43.153.186.220 188.121.178.115 193.187.175.201 197.5.145.73 49.51.107.203 128.140.108.193 189.206.165.62 34.133.86.38 132.145.115.97 103.26.136.173 20.141.64.165 165.154.163.202 188.36.123.6 52.183.128.237 117.6.44.221 147.189.130.53 185.255.90.36 222.252.21.30 202.88.228.179 43.156.83.163 118.70.127.71 102.220.23.35 103.47.184.2 204.145.0.177 162.14.98.48 113.190.252.110 184.18.211.199 43.155.159.250 103.96.151.81 143.202.210.33 199.188.203.161 5.42.78.98 43.134.230.150 43.159.147.253 43.156.35.214 124.156.203.239 43.159.62.25 170.106.196.12 43.134.129.107 189.190.59.161 190.153.249.99 161.132.219.115 137.184.5.137 181.49.50.202 185.162.235.231 124.156.204.21 143.110.247.138 107.182.20.3 159.89.178.230 61.155.106.101 23.94.200.220 43.155.143.22 43.134.184.137 43.163.208.33 154.222.227.97 62.74.140.248 222.223.152.90 106.251.237.171 14.63.62.165 43.157.29.245 103.176.78.202 180.101.72.226 129.226.193.194 103.9.36.169 175.178.57.106 103.140.194.87 14.18.101.30 51.195.255.20 165.154.236.203 43.134.65.145 189.225.33.68 159.89.163.158 23.95.189.186 43.131.57.46 49.0.87.123 190.144.14.170 209.38.232.83 170.106.195.172 103.147.242.96 43.153.77.20 103.59.95.164 36.103.227.136 162.240.110.53 125.209.85.187 31.24.200.23 43.156.225.133 185.162.235.138 104.248.119.237 159.223.193.55 43.134.237.73 93.177.103.50 136.233.27.164 154.68.39.6 194.163.145.51 209.126.86.224 61.99.254.192 27.254.235.2 210.187.80.132 43.135.146.18 125.209.73.250 95.242.100.118 89.44.137.80 79.137.202.87 170.106.141.190 37.32.14.139 43.135.182.209 49.247.214.126 123.96.94.205
Screenshot 2023-12-17 at 12 04 37

Copy link
Contributor

@sebres sebres left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excepting the mentioned blocktype parameter, looks good to me...
However I'd like to see single route action for both multiport and allports type, so it becomes more similar to other actions. Even all 3 variants possible:

Something like that
[Definition]
actionstart = %(def_<type>/actionstart)s
actionstop = %(def_<type>/actionstop)s
actionban = %(def_<type>/actionban)s
actionunban = %(def_<type>/actionunban)s

[def_simple]
actionstart =
actionstop =
actionban   = ip route add <blocktype> <ip>
actionunban = ip route del <blocktype> <ip>

[def_allports]
actionstart = ip route add <blocktype> 0.0.0.0/0 table <tableid>
actionstop = ip route delete <blocktype> 0.0.0.0/0 table <tableid>
actionban = ip rule add to <ip> ipproto <protocol> lookup <tableid>
actionunban = ip rule delete to <ip> ipproto <protocol> lookup <tableid>

[def_multiport]
actionstart = ip route add <blocktype> 0.0.0.0/0 table <tableid>
actionstop = ip route delete <blocktype> 0.0.0.0/0 table <tableid>
actionban = ip rule add to <ip> ipproto <protocol> sport <port> lookup <tableid>
actionunban = ip rule delete to <ip> ipproto <protocol> sport <port> lookup <tableid>

[Init]
# Option:  type
# Notes.:  type of the action.
# Values:  [ simple | multiport | allports ]  Default: simple
#
type = simple

# Option:  blocktype
# Note:    Type can be blackhole, unreachable and prohibit. Unreachable and prohibit correspond to the ICMP reject messages.
# Values:  STRING
blocktype = unreachable

# Option:  tableid
# Note:    ip route table ID
# Values:  [ NUM | STRING ]
tableid = 666

# Option:  port
# Note:    service port number
# Values:  [ NUM ]
port = 22

# Option:  protocol
# Note:    service protocol
# Values:  [ STRING ]
protocol = tcp

This way we'd even have 3 actions in a single config and more similar to other actions defaults:

banaction_simple = route ; # backwards-compatible simple routing without lookup table

banaction = route[type=multiport]
banaction_allports = route[type=allports]

One note by the way - since it doesn't have a real "anchor" to the jail or its name, this action would be affected by issues like #2373 in the same way (if assigned to multiple jails), unless one would change tableid from jail to jail.

An interim question: I understand the approach to use route to do something tricky in case of ban (like route to another host/service/port aka honeypot, etc)... But for simple banning purposes? Why not native net-fiilter (iptables+ipset, nft, pf, whatever) instead?

config/action.d/pbr.conf Outdated Show resolved Hide resolved
@k0ste
Copy link
Author

k0ste commented Dec 26, 2023

Firstly, thanks for all your comments and suggestions. I haven’t found exactly such examples in existing implementations, and my experience with fail2ban isn't big.

Secondly, I tried to comprehend your suggestions and made the following implementation (added with the next commit). The only problem I encountered was %(def_<type>/actionstart)s this expression did not work for me:

Dec 26 18:06:18 k0ste.ru fail2ban-server[3229050]: 2023-12-26 18:06:18,668 fail2ban                [3229050]: ERROR   Failed during configura
tion: Error in action definition 'pbr[type="multiport",tableid="22",port="22",protocol="tcp"]': Bad value substitution: option 'actionstart'
in section 'Definition' contains an interpolation key 'def_<type>/actionstart' which is not a valid option name. Raw value: '%(def_<type>/act
ionstart)s

I changed it according to the example from "firewald-ipset" action

Thirdly, as far as I understand, you are inclined to replace the route action with this pbr implementation?

An interim question: I understand the approach to use route to do something tricky in case of ban (like route to another host/service/port aka honeypot, etc)... But for simple banning purposes? Why not native net-fiilter (iptables+ipset, nft, pf, whatever) instead?

And last but not least. The main goal, in fact, is well described in the route action

# PRO:
#   - Works on all kernel versions and as no compatibility problems (back to debian lenny and WAY further).
#   - It's FAST for very large numbers of blocked ips.
#   - It's FAST because it Blocks traffic before it enters common iptables chains used for filtering.
#   - It's per host, ideal as action against ssh password bruteforcing to block further attack attempts.
#   - No additional software required beside iproute/iproute2
#
# CON:
#   - Blocking is per IP and NOT per service, but ideal as action against ssh password bruteforcing hosts

To do not use the netfilter subsystem at all, because even loading kernel nf_ modules will force all traffic to pass through this subsystem, which will obviously make any data transfer operation more latent.
Further, if docker is used, a triple entry point for inject chains appears, namely:

  • admin rules
  • f2b rules
  • docker rules

I don’t really want to manage such a complex system

From the point of view of duplicates, that is, the problem described in #2373. We can add our own iproute2 protocol and place records covered by this protocol into the kernel. iproute2 also has the ability to add protocols through a file (rt_protos.d) and in user space the source of its origin will be obvious. For example, file from the FRRouting/frr project will produces output like this

Screenshot 2023-12-26 at 15 36 11

More granular blocking compared with 'route' action

The main diffence is that possible to block single service port,
instead of blocking whole IP address. How this works

When `banaction` is success, the `<ip>` will be added to ip rules:
```bash
[root@host /]# ip rule list | grep 211.245.106.55
185:    from all to 211.245.106.55 ipproto tcp sport 22 lookup 666
```
As we can see, only `sshd` service will be blocked for this `<ip>`
We can check this
```bash
[root@host /]# ip route get 211.245.106.55
211.245.106.55 via 192.168.102.1 dev po1 src 192.168.102.254 uid 0
```
The output for this `<ip>` is not blocked
But `sshd` service for this `<ip>` will be banned
```bash
[root@host /]# ip ro get 211.245.106.55 sport 22 ipproto tcp
RTNETLINK answers: No route to host
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants