From 5cc61aca75be4138949962499962576504fe1884 Mon Sep 17 00:00:00 2001 From: d3m0k1d Date: Tue, 24 Feb 2026 18:03:17 +0300 Subject: [PATCH] feat: integration actions to judge logic and update docs for this --- README.md | 15 ++++- docs/config.md | 120 +++++++++++++++++++++++++++++++++++++++ docs/man/banforge.1 | 2 + docs/man/banforge.5 | 110 ++++++++++++++++++++++++++++------- internal/config/types.go | 2 +- internal/judge/judge.go | 12 ++++ 6 files changed, 236 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 7e00c85..cafa2a3 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ If you have any questions or suggestions, create issue on [Github](https://githu - [x] Nginx and Sshd support - [x] Working with ufw/iptables/nftables/firewalld - [x] Prometheus metrics +- [x] Actions (email, webhook, script) - [ ] Add support for most popular web-service - [ ] User regexp for custom services - [ ] TUI interface @@ -112,10 +113,20 @@ For first steps use this commands banforge init # Create config files and database banforge daemon # Start BanForge daemon (use systemd or another init system to create a service) ``` -You can edit the config file with examples in +You can edit the config file with examples in - `/etc/banforge/config.toml` main config file -- `/etc/banforge/rules.toml` ban rules +- `/etc/banforge/rules.d/*.toml` individual rule files with actions support + For more information see the [docs](https://github.com/d3m0k1d/BanForge/docs). +## Actions + +BanForge supports actions that are executed after a successful IP ban: +- **Email** - Send email notifications via SMTP +- **Webhook** - Send HTTP requests to external services (Slack, Telegram, etc.) +- **Script** - Execute custom scripts + +See [configuration docs](https://github.com/d3m0k1d/BanForge/blob/main/docs/config.md#actions) for detailed setup instructions. + # License The project is licensed under the [GPL-3.0](https://github.com/d3m0k1d/BanForge/blob/master/LICENSE) diff --git a/docs/config.md b/docs/config.md index 52b45d0..67e0841 100644 --- a/docs/config.md +++ b/docs/config.md @@ -43,9 +43,129 @@ Example: max_retry = 3 method = "" ban_time = "1m" + + # Actions are executed after successful ban + [[rule.action]] + type = "email" + enabled = true + email = "admin@example.com" + email_sender = "banforge@example.com" + email_subject = "BanForge Alert: IP Banned" + smtp_host = "smtp.example.com" + smtp_port = 587 + smtp_user = "user@example.com" + smtp_password = "password" + smtp_tls = true + body = "IP {ip} has been banned for rule {rule}" + + [[rule.action]] + type = "webhook" + enabled = true + url = "https://hooks.example.com/alert" + method = "POST" + headers = { "Content-Type" = "application/json", "Authorization" = "Bearer token" } + body = "{\"ip\": \"{ip}\", \"rule\": \"{rule}\", \"service\": \"{service}\"}" + + [[rule.action]] + type = "script" + enabled = true + script = "/usr/local/bin/notify.sh" + interpretator = "bash" ``` **Description** The [[rule]] section require name and one of the following parameters: service, path, status, method. To add a rule, create a [[rule]] block and specify the parameters. ban_time require in format "1m", "1h", "1d", "1M", "1y". If you want to ban all requests to PHP files (e.g., path = "*.php") or requests to the admin panel (e.g., path = "/admin/*"). If max_retry = 0 ban on first request. + +## Actions + +Actions are executed after a successful IP ban. You can configure multiple actions per rule. + +### Action Types + +#### 1. Email Notification + +Send email alerts when an IP is banned. + +```toml +[[rule.action]] + type = "email" + enabled = true + email = "admin@example.com" + email_sender = "banforge@example.com" + email_subject = "BanForge Alert" + smtp_host = "smtp.example.com" + smtp_port = 587 + smtp_user = "user@example.com" + smtp_password = "password" + smtp_tls = true + body = "IP {ip} has been banned" +``` + +| Field | Required | Description | +|-------|----------|-------------| +| `type` | + | Must be "email" | +| `enabled` | + | Enable/disable this action | +| `email` | + | Recipient email address | +| `email_sender` | + | Sender email address | +| `email_subject` | - | Email subject (default: "BanForge Alert") | +| `smtp_host` | + | SMTP server host | +| `smtp_port` | + | SMTP server port | +| `smtp_user` | + | SMTP username | +| `smtp_password` | + | SMTP password | +| `smtp_tls` | - | Use TLS connection (default: false) | +| `body` | - | Email body text | + +#### 2. Webhook Notification + +Send HTTP webhook requests when an IP is banned. + +```toml +[[rule.action]] + type = "webhook" + enabled = true + url = "https://hooks.example.com/alert" + method = "POST" + headers = { "Content-Type" = "application/json", "Authorization" = "Bearer token" } + body = "{\"ip\": \"{ip}\", \"rule\": \"{rule}\"}" +``` + +| Field | Required | Description | +|-------|----------|-------------| +| `type` | + | Must be "webhook" | +| `enabled` | + | Enable/disable this action | +| `url` | + | Webhook URL | +| `method` | - | HTTP method (default: "POST") | +| `headers` | - | HTTP headers as key-value pairs | +| `body` | - | Request body (supports variables) | + +#### 3. Script Execution + +Execute a custom script when an IP is banned. + +```toml +[[rule.action]] + type = "script" + enabled = true + script = "/usr/local/bin/notify.sh" + interpretator = "bash" +``` + +| Field | Required | Description | +|-------|----------|-------------| +| `type` | + | Must be "script" | +| `enabled` | + | Enable/disable this action | +| `script` | + | Path to script file | +| `interpretator` | - | Script interpretator (e.g., "bash", "python"). If empty, script runs directly | + +### Variables + +The following variables can be used in `body` fields (email, webhook): + +| Variable | Description | +|----------|-------------| +| `{ip}` | Banned IP address | +| `{rule}` | Rule name that triggered the ban | +| `{service}` | Service name | +| `{ban_time}` | Ban duration | diff --git a/docs/man/banforge.1 b/docs/man/banforge.1 index 4ff35bd..72b5215 100644 --- a/docs/man/banforge.1 +++ b/docs/man/banforge.1 @@ -214,6 +214,8 @@ Configuration files are stored in \fI/etc/banforge/\fR: .IP \(bu 2 \fIrules.d/*.toml\fR \- individual rule files .RE +.PP +See \fBbanforge(5)\fR for configuration file format details including actions setup. . .SH "EXIT STATUS" .PP diff --git a/docs/man/banforge.5 b/docs/man/banforge.5 index 9de837b..95c1790 100644 --- a/docs/man/banforge.5 +++ b/docs/man/banforge.5 @@ -198,9 +198,36 @@ Use the following suffixes for ban duration: \fBy\fR \- Years (365 days) .RE . -.SH "ACTIONS(NOT WORKING ON THIS VERSION)" +.SH "ACTIONS" .PP Rules can trigger custom actions when an IP is banned. +Multiple actions can be configured per rule. +Actions are executed after successful ban at firewall level. +. +.SS "Supported Action Types" +.PP +.RS +.IP \(bu 2 +\fBemail\fR \- Send email notification via SMTP +.IP \(bu 2 +\fBwebhook\fR \- Send HTTP request to external service +.IP \(bu 2 +\fBscript\fR \- Execute custom script +.RE +. +.SS "Variables" +.PP +The following variables can be used in \fBbody\fR fields: +.RS +.IP \(bu 2 +\fB{ip}\fR \- Banned IP address +.IP \(bu 2 +\fB{rule}\fR \- Rule name that triggered the ban +.IP \(bu 2 +\fB{service}\fR \- Service name +.IP \(bu 2 +\fB{ban_time}\fR \- Ban duration +.RE . .SS "Script Action" .PP @@ -213,7 +240,7 @@ Execute a custom script when an IP is banned. .IP \(bu 2 \fBenabled\fR \- Enable/disable action (true/false) .IP \(bu 2 -\fBinterpretator\fR \- Script interpretator (e.g., "/bin/bash") +\fBinterpretator\fR \- Script interpretator (e.g., "bash", "python") .IP \(bu 2 \fBscript\fR \- Path to script file .RE @@ -226,11 +253,11 @@ Execute a custom script when an IP is banned. service = "nginx" status = "403" ban_time = "1h" - + [[rule.action]] type = "script" enabled = true - interpretator = "/bin/bash" + interpretator = "bash" script = "/opt/banforge/scripts/notify.sh" .fi .RE @@ -246,13 +273,13 @@ Send HTTP webhook when an IP is banned. .IP \(bu 2 \fBenabled\fR \- Enable/disable action (true/false) .IP \(bu 2 -\fBurl\fR \- Webhook URL +\fBurl\fR \- Webhook URL \fI(required)\fR .IP \(bu 2 -\fBmethod\fR \- HTTP method (POST, GET) +\fBmethod\fR \- HTTP method (POST, GET, etc.) .IP \(bu 2 \fBheaders\fR \- Custom headers (key-value pairs) .IP \(bu 2 -\fBbody\fR \- Request body (supports templates) +\fBbody\fR \- Request body (supports variables) .RE .PP \fBExample:\fR @@ -263,14 +290,8 @@ Send HTTP webhook when an IP is banned. enabled = true url = "https://hooks.example.com/ban" method = "POST" - - [rule.action.headers] - Content-Type = "application/json" - Authorization = "Bearer TOKEN" - - [rule.action.body] - ip = "{{.IP}}" - reason = "{{.Rule}}" + headers = { "Content-Type" = "application/json", "Authorization" = "Bearer TOKEN" } + body = "{\\\"ip\\\": \\\"{ip}\\\", \\\"rule\\\": \\\"{rule}\\\"}" .fi .RE . @@ -285,21 +306,23 @@ Send email notification when an IP is banned. .IP \(bu 2 \fBenabled\fR \- Enable/disable action (true/false) .IP \(bu 2 -\fBemail\fR \- Recipient email address +\fBemail\fR \- Recipient email address \fI(required)\fR .IP \(bu 2 -\fBemail_sender\fR \- Sender email address +\fBemail_sender\fR \- Sender email address \fI(required)\fR .IP \(bu 2 -\fBemail_subject\fR \- Email subject +\fBemail_subject\fR \- Email subject (default: "BanForge Alert") .IP \(bu 2 -\fBsmtp_host\fR \- SMTP server host +\fBsmtp_host\fR \- SMTP server host \fI(required)\fR .IP \(bu 2 -\fBsmtp_port\fR \- SMTP server port +\fBsmtp_port\fR \- SMTP server port \fI(required)\fR .IP \(bu 2 -\fBsmtp_user\fR \- SMTP username +\fBsmtp_user\fR \- SMTP username \fI(required)\fR .IP \(bu 2 -\fBsmtp_password\fR \- SMTP password +\fBsmtp_password\fR \- SMTP password \fI(required)\fR .IP \(bu 2 \fBsmtp_tls\fR \- Enable TLS (true/false) +.IP \(bu 2 +\fBbody\fR \- Email body text (supports variables) .RE .PP \fBExample:\fR @@ -316,6 +339,49 @@ Send email notification when an IP is banned. smtp_user = "banforge" smtp_password = "secret" smtp_tls = true + body = "IP {ip} has been banned for rule {rule}" +.fi +.RE +. +.SH "COMPLETE RULE EXAMPLE WITH ACTIONS" +.PP +.RS +.nf +[[rule]] + name = "nginx-403" + service = "nginx" + status = "403" + max_retry = 3 + ban_time = "1h" + + # Email notification + [[rule.action]] + type = "email" + enabled = true + email = "admin@example.com" + email_sender = "banforge@example.com" + smtp_host = "smtp.example.com" + smtp_port = 587 + smtp_user = "banforge" + smtp_password = "secret" + smtp_tls = true + body = "IP {ip} banned by rule {rule}" + + # Slack webhook + [[rule.action]] + type = "webhook" + enabled = true + url = "https://hooks.slack.com/services/XXX/YYY/ZZZ" + method = "POST" + headers = { "Content-Type" = "application/json" } + body = "{\\\"text\\\": \\\"IP {ip} banned for rule {rule}\\\"}" + + # Custom script + [[rule.action]] + type = "script" + enabled = true + script = "/usr/local/bin/ban-notify.sh" + interpretator = "bash" .fi .RE . diff --git a/internal/config/types.go b/internal/config/types.go index 240e2c4..c630b6d 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -31,7 +31,7 @@ type Rule struct { Method string `toml:"method"` MaxRetry int `toml:"max_retry"` BanTime string `toml:"ban_time"` - Action []Action + Action []Action `toml:"action"` } type Metrics struct { diff --git a/internal/judge/judge.go b/internal/judge/judge.go index 0dd82be..3fa997f 100644 --- a/internal/judge/judge.go +++ b/internal/judge/judge.go @@ -5,6 +5,7 @@ import ( "strings" "time" + "github.com/d3m0k1d/BanForge/internal/actions" "github.com/d3m0k1d/BanForge/internal/blocker" "github.com/d3m0k1d/BanForge/internal/config" "github.com/d3m0k1d/BanForge/internal/logger" @@ -124,6 +125,17 @@ func (j *Judge) Tribunal() { metrics.IncError() break } + + for _, action := range rule.Action { + executor := &actions.Executor{Action: action} + if err := executor.Execute(); err != nil { + j.logger.Error("Action execution failed", + "rule", rule.Name, + "action_type", action.Type, + "error", err) + } + } + j.logger.Info( "IP banned successfully", "ip",