Go to file
2023-10-22 12:00:00 +02:00
app new doc, new examples, support -help 2023-10-22 12:00:00 +02:00
config new doc, new examples, support -help 2023-10-22 12:00:00 +02:00
ip46tables.d ip46tables 2023-10-05 12:00:00 +02:00
logger Implement start/stop commands 2023-10-18 12:00:00 +02:00
logo order 🧹 2023-04-26 17:11:03 +02:00
.gitignore ip46tables 2023-10-05 12:00:00 +02:00
default.nix Standardize go project structure 2023-05-05 12:53:10 +02:00
go.mod support json, jsonnet, yaml formats 2023-10-05 12:00:00 +02:00
go.sum support json, jsonnet, yaml formats 2023-10-05 12:00:00 +02:00
LICENSE Add AGPL LICENSE 2023-04-11 11:03:50 +00:00
Makefile ip46tables 2023-10-05 12:00:00 +02:00
reaction.go New unified CLI design 2023-09-03 12:13:18 +02:00
README.md new doc, new examples, support -help 2023-10-22 12:00:00 +02:00

reaction

A daemon that scans program outputs for repeated patterns, and takes action.

A common usage is to scan ssh and webserver logs, and to ban hosts that cause multiple authentication errors.

🚧 This program hasn't received external audit. however, it already works well on my servers 🚧

Rationale

I was using the honorable fail2ban since quite a long time, but i was a bit frustrated by its cpu consumption and all its heavy default configuration.

In my view, a security-oriented program should be simple to configure and an always-running daemon should be implemented in a faster language.

reaction does not have all the features of the honorable fail2ban, but it's ~10x faster and has more manageable configuration.

📽️ french quick explanation 😉

Configuration

YAML and JSONnet (more powerful) are supported. both are extensions of JSON, so JSON is transitively supported.

/etc/reaction.yml
patterns:
  ip: '(([ 0-9 ]{1,3}\.){3}[0-9]{1,3})|([0-9a-fA-F:]{2,90})'

start:
  - [ 'ip46tables', '-w', '-N', 'reaction' ]
  - [ 'ip46tables', '-w', '-A', 'reaction', '-j', 'ACCEPT' ]
  - [ 'ip46tables', '-w', '-I', 'reaction', '1', '-s', '127.0.0.1', '-j', 'ACCEPT' ]
  - [ 'ip46tables', '-w', '-I', 'INPUT', '-p', 'all', '-j', 'reaction' ]

stop:
  - [ 'ip46tables', '-w', '-D', 'INPUT', '-p', 'all', '-j', 'reaction' ]
  - [ 'ip46tables', '-w', '-F', 'reaction' ]
  - [ 'ip46tables', '-w', '-X', 'reaction' ]

streams:
  ssh:
    cmd: [ 'journalctl', '-fu', 'sshd.service' ]
    filters:
      failedlogin:
        regex:
          - 'authentication failure;.*rhost=<ip>'
        retry: 3
        retryperiod: '6h'
        actions:
          ban:
            cmd: [ 'ip46tables', '-w', '-I', 'reaction', '1', '-s', '<ip>', '-j', 'block' ]
          unban:
            cmd: [ 'ip46tables', '-w', '-D', 'reaction', '1', '-s', '<ip>', '-j', 'block' ]
            after: '48h'
/etc/reaction.jsonnet
local iptables(args) = [ 'ip46tables', '-w' ] + args;
local banFor(time) = {
  ban: {
    cmd: iptables(['-A', 'reaction', '-s', '<ip>', '-j', 'reaction-log-refuse']),
  },
  unban: {
    after: time,
    cmd: iptables(['-D', 'reaction', '-s', '<ip>', '-j', 'reaction-log-refuse']),
  },
};
{
  patterns: {
    ip: {
      regex: @'(?:(?:[ 0-9 ]{1,3}\.){3}[0-9]{1,3})|(?:[0-9a-fA-F:]{2,90})',
    },
  },
  start: [
    iptables([ '-N', 'reaction' ]),
    iptables([ '-A', 'reaction', '-j', 'ACCEPT' ]),
    iptables([ '-I', 'reaction', '1', '-s', '127.0.0.1', '-j', 'ACCEPT' ]),
    iptables([ '-I', 'INPUT', '-p', 'all', '-j', 'reaction' ]),
  ],
  stop: [
    iptables([ '-D,', 'INPUT', '-p', 'all', '-j', 'reaction' ]),
    iptables([ '-F,', 'reaction' ]),
    iptables([ '-X,', 'reaction' ]),
  ],
  streams: {
    ssh: {
      cmd: [ 'journalctl', '-fu', 'sshd.service' ],
      filters: {
        failedlogin: {
          regex: [ @'authentication failure;.*rhost=<ip>' ],
          retry: 3,
          retryperiod: '6h',
          actions: banFor('48h'),
        },
      },
    },
  },
}

Database

The embedded database is stored in the working directory. If you don't know where to start reaction, /var/lib/reaction should be a sane choice.

CLI

  • reaction start runs the server
  • reaction show show pending actions (ie. bans)
  • reaction flush permits to run pending actions (ie. clear bans)
  • reaction test-regex permits to test regexes
  • reaction help for full usage.

ip46tables

ip46tables is a minimal c program present in its own subdirectory with only standard posix dependencies.

It permits to configure iptables and ip6tables at the same time. It will execute iptables when detecting ipv4, ip6tables when detecting ipv6 and both if no ip address is present on the command line.

Compilation

You'll need the go toolchain for reaction and a c compiler for ip46tables.

$ make

Alternatively,

# creates ./reaction
$ go build .
# creates ./ip46tables
$ gcc ip46tables.d/ip46tables.c -o ip46tables

NixOS