- Rust 94.1%
- Jsonnet 3.6%
- Python 1.8%
- Makefile 0.3%
- Shell 0.1%
reaction's configuration now has a state_directory optional member, which is where it will save its databases. defaults to cwd. added a lot of code necessary to properly test databases. The new tests are currently failing, which is good : they'll permit to hunt down this database consistency bug. also removed some indirect dependencies via features removal, and moved test dependencies to dedicated [dev-dependencies] also small fix on an nft46.c function type and empty conf file for ccls LSP server. |
||
|---|---|---|
| config | ||
| debian | ||
| export-go-db | ||
| go.old | ||
| helpers_c | ||
| import-rust-db | ||
| logo | ||
| src | ||
| tests | ||
| .ccls | ||
| .gitignore | ||
| .gitlab-ci.yml | ||
| ARCHITECTURE.md | ||
| build.rs | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| release.py | ||
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 🚧
Current project status
reaction just reached v2.0.0-rc1 version, which is a complete rust rewrite of reaction. It's in feature parity with the Go version, and breaking changes should be small.
See https://reaction.ppom.me/migrate-to-v2.html
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.
📽️ quick french name explanation 😉
🇬🇧 in-depth blog article / 🇫🇷 french version
Configuration
YAML and JSONnet (more powerful) are supported. both are extensions of JSON, so JSON is transitively supported.
- See reaction.yml or reaction.jsonnet for a fully explained reference
- See server.jsonnet for a real-world configuration
- See reaction.example.service for a systemd service file
- This minimal example shows what's needed to prevent brute force attacks on an ssh server (please take a look at more complete references before starting 🆙):
/etc/reaction.yml
patterns:
ip:
regex: '(([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 startruns the serverreaction showshow pending actions (ie. bans)reaction flushpermits to run pending actions (ie. clear bans)reaction test-regexpermits to test regexesreaction helpfor 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.
Wiki
You'll find more ressources, service configurations, etc. on the wiki!
We recommend that you read the Good Practices chapters before starting.
Installation
Binaries
Executables are provided here, for a standard x86-64 linux machine.
A standard place to put such executables is /usr/local/bin/.
Provided binaries in the previous section are compiled this way:
$ docker run -it --rm -e HOME=/tmp/ -v $(pwd):/tmp/code -w /tmp/code -u $(id -u) rust make clean reaction.deb
$ make signatures
Signature verification
Starting at v1.0.3, all binaries are signed with public key RWSpLTPfbvllNqRrXUgZzM7mFjLUA7PQioAItz80ag8uU4A2wtoT2DzX. You can check their authenticity with minisign:
minisign -VP RWSpLTPfbvllNqRrXUgZzM7mFjLUA7PQioAItz80ag8uU4A2wtoT2DzX -m nft46
minisign -VP RWSpLTPfbvllNqRrXUgZzM7mFjLUA7PQioAItz80ag8uU4A2wtoT2DzX -m ip46tables
minisign -VP RWSpLTPfbvllNqRrXUgZzM7mFjLUA7PQioAItz80ag8uU4A2wtoT2DzX -m reaction
# or
minisign -VP RWSpLTPfbvllNqRrXUgZzM7mFjLUA7PQioAItz80ag8uU4A2wtoT2DzX -m reaction.deb
Debian
The releases also contain a reaction*.deb file, which packages reaction & ip46tables.
You can install it using sudo apt install ./reaction*.deb.
You'll have to create a configuration at /etc/reaction.jsonnet.
If you want to use another configuration format (YAML or JSON), you can override systemd's ExecStart command in /etc/systemd/system/reaction.service like this:
[Service]
# First an empty directive to reset the default one
ExecStart=
# Then put what you want
ExecStart=/usr/bin/reaction start -c /etc/reaction.yml
NixOS
OpenBSD
Compilation
You'll need a recent rust toolchain for reaction and a c compiler for ip46tables.
$ make
Don't hesitate to take a look at the Makefile to understand what's happening!
Installation
To install the binaries
make install
To install the systemd file as well
make install_systemd
Development
Contributions are welcome. For any substantial feature, please file an issue first, to be assured that we agree on the feature, and to avoid unnecessary work.
I recommend reading ARCHITECTURE.md first. This is a tour of the codebase, which should save time to potential contributors.
Funding
This is a free time project, so I'm not working on schedule. However, if you're willing to fund the project, I can priorise and plan paid work. This includes features, documentation and specific JSONnet configurations.