Crash with 1.1.1 when issuing ban command
Hello,
I downloaded the 1.1.1 deb file from the Release page:
$ dpkg -I reaction.deb
new Debian package, version 2.0.
size 1704528 bytes: control archive=1412 bytes.
261 bytes, 9 lines control
1527 bytes, 50 lines * postinst #!/bin/sh
1037 bytes, 40 lines * postrm #!/bin/sh
169 bytes, 6 lines * prerm #!/bin/sh
Package: reaction
Version: 1.1.1
Architecture: amd64
Maintainer: ppom <>
Sections: utils
Package-Type: deb
Priority: Optional
Homepage: https://framagit.org/ppom/reaction
Description: A daemon that scans program outputs for repeated patterns, and takes action.
And I got this crash with a fairly simple configuration:
Jan 10 21:24:07 vps systemd[1]: Started reaction.service - A daemon that scans program outputs for repeated patterns, and takes action..
Jan 10 21:24:07 vps reaction[11413]: 2024/01/10 21:24:07 INFO start command: run [iptables -w -N reaction]
Jan 10 21:24:07 vps reaction[11413]: 2024/01/10 21:24:07 ERROR start command: run [iptables -w -N reaction]: exit status 1
Jan 10 21:24:07 vps reaction[11413]: 2024/01/10 21:24:07 INFO start command: run [iptables -w -I INPUT -p all -j reaction]
Jan 10 21:24:07 vps reaction[11413]: 2024/01/10 21:24:07 INFO nginx.failedreq.ban: run []
Jan 10 21:24:07 vps reaction[11413]: panic: runtime error: slice bounds out of range [1:0]
Jan 10 21:24:07 vps reaction[11413]: goroutine 11 [running]:
Jan 10 21:24:07 vps reaction[11413]: framagit.org/ppom/reaction/app.(*Action).exec(0xc00005a6e0, {0xc000122a10?, 0xe?})
Jan 10 21:24:07 vps reaction[11413]: /tmp/code/app/daemon.go:119 +0x3cd
Jan 10 21:24:07 vps reaction[11413]: framagit.org/ppom/reaction/app.ActionsManager.func1()
Jan 10 21:24:07 vps reaction[11413]: /tmp/code/app/daemon.go:135 +0x4a
Jan 10 21:24:07 vps reaction[11413]: created by framagit.org/ppom/reaction/app.ActionsManager
Jan 10 21:24:07 vps reaction[11413]: /tmp/code/app/daemon.go:131 +0xc7e
Here is the configuration:
local banFor(time) = {
ban: {
cmd: ['ip46tables', '-w', '-A', 'reaction', '-s', '<ip>', '-j', 'DROP'],
},
unban: {
after: time,
cmd: ['ip46tables', '-w', '-D', 'reaction', '-s', '<ip>', '-j', 'DROP'],
},
};
{
patterns: {
ip: {
regex: @'(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}|(?:(?:[0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(?:ffff(?::0{1,4}){0,1}:){0,1}(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])|(?:[0-9a-fA-F]{1,4}:){1,4}:(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9]))',
ignore: ['127.0.0.1', '::1'],
},
dqs: {
regex: @'"((?:\\.|[^\\])*?)"',
},
},
start: [
['ip46tables', '-w', '-N', 'reaction'],
['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: {
nginx: {
cmd: ['tail', '-f', '/var/log/nginx/access.log'],
filters: {
failedreq: {
regex: [@'^<ip> [^"]*"(?:\\.|[^\\])*?" [45]\d\d '],
retry: 5,
retryperiod: '15m',
actions: banFor('1h'),
},
},
},
},
}
I then cloned the repo, checked out the v1.1.1 tag and investigated a little.
I removed most of the content of the config/server.jsonnet config file to only keep the filter "suspectRequests" for nginx. I also replaced the tail command by a cat of a sample log file.
I then compiled using the Makefile on fedora using go version go1.21.5 linux/amd64.
This reproduced the issue and, with the help of a lot of printf, as I'm not familiar with go, I ended-up with the following fix:
diff --git a/app/daemon.go b/app/daemon.go
index f249c83..f4b8e6e 100644
--- a/app/daemon.go
+++ b/app/daemon.go
@@ -105,7 +105,7 @@ func (a *Action) exec(match string) {
var computedCommand []string
if a.filter.pattern != nil {
- computedCommand := make([]string, 0, len(a.Cmd))
+ computedCommand = make([]string, 0, len(a.Cmd))
for _, item := range a.Cmd {
computedCommand = append(computedCommand, strings.ReplaceAll(item, a.filter.pattern.nameWithBraces, match))
Does that make sense? I do not know go.