Skip to content

Block Reporting

Heisenbug edited this page Mar 5, 2026 · 1 revision

Home · Start Here · Reference Map

At a glance

  • LFD can execute external scripts on block and unblock events.
  • BLOCK_REPORT receives a rich event payload (IP, ports, reason, logs, trigger).
  • Hooks run as root and are forcibly terminated if they exceed runtime limits.

Related guide: Security-Features-Guide

What this feature does

When LFD blocks an IP/CIDR (for example after login-failure detection), it can call an external executable defined by BLOCK_REPORT.

A companion hook, UNBLOCK_REPORT, can run when temporary blocks are removed.

BLOCK_REPORT argument contract

LFD passes the following arguments in order:

  1. IP address — IP/CIDR being blocked
  2. ports — port, list of ports, or *
  3. permanent0 temporary, 1 permanent
  4. inout — direction: in, out, or inout
  5. timeout — TTL seconds for temporary blocks, otherwise 0
  6. message — block reason/context
  7. logs — triggering log lines (multi-line payload)
  8. trigger — configuration setting that triggered action

UNBLOCK_REPORT argument contract

For temporary unblock events:

  1. IP address — IP/CIDR being unblocked
  2. port — port context if original temporary rule was port-specific

Example hook scripts

Minimal logger

#!/bin/sh
# /usr/local/sbin/csf-block-report.sh

IP="$1"
PORTS="$2"
PERM="$3"
DIR="$4"
TTL="$5"
MSG="$6"
LOGS="$7"
TRIGGER="$8"

logger -t csf-block-report "ip=$IP ports=$PORTS permanent=$PERM dir=$DIR ttl=$TTL trigger=$TRIGGER"
exit 0

Webhook notification (Slack/Discord/PagerDuty)

#!/bin/sh
# /usr/local/sbin/csf-block-webhook.sh

IP="$1"
PERM="$3"
TTL="$5"
MSG="$6"
TRIGGER="$8"

TYPE="temporary"
[ "$PERM" = "1" ] && TYPE="permanent"

PAYLOAD=$(cat <<EOF
{"text":"CSF Block [$TYPE]: $IP$MSG (trigger: $TRIGGER, ttl: ${TTL}s)"}
EOF
)

curl -s -m 5 -X POST -H 'Content-Type: application/json' \
  -d "$PAYLOAD" \
  "https://hooks.slack.com/services/YOUR/WEBHOOK/URL" >/dev/null 2>&1

exit 0

Structured JSON log file

#!/bin/sh
# /usr/local/sbin/csf-block-json.sh

IP="$1"
PORTS="$2"
PERM="$3"
DIR="$4"
TTL="$5"
MSG="$6"
TRIGGER="$8"

printf '{"ts":"%s","ip":"%s","ports":"%s","permanent":%s,"dir":"%s","ttl":%s,"trigger":"%s","msg":"%s"}\n' \
  "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$IP" "$PORTS" "$PERM" "$DIR" "$TTL" "$TRIGGER" "$MSG" \
  >> /var/log/csf-blocks.json

exit 0

SIEM push (syslog forwarding)

#!/bin/sh
# /usr/local/sbin/csf-block-siem.sh

IP="$1"
PERM="$3"
TRIGGER="$8"

logger -p local0.warning -t csf-block "ip=$IP permanent=$PERM trigger=$TRIGGER"
exit 0

Then configure rsyslog/syslog-ng to forward local0.warning to your SIEM collector.

Configuration

  1. Create your hook script and make it executable:
chmod 700 /usr/local/sbin/csf-block-report.sh
chown root:root /usr/local/sbin/csf-block-report.sh
  1. Reference it in csf.conf:
BLOCK_REPORT = "/usr/local/sbin/csf-block-report.sh"
UNBLOCK_REPORT = "/usr/local/sbin/csf-unblock-report.sh"
  1. Restart LFD:
csf -lf

Testing: trigger a test block

To verify your hook fires correctly:

# Temporarily block a test IP
csf -td 198.51.100.99 60 -d in "Block report test"

# Check your hook output (logger example):
journalctl -t csf-block-report --since "1 minute ago"
# or
grep csf-block-report /var/log/messages

# Clean up
csf -tr 198.51.100.99

The test block will auto-expire after 60 seconds. Verify both the block hook and (after expiry or manual removal) the unblock hook.

Runtime and security constraints

  • Hook is launched in a forked process.
  • Runtime budget is approximately 10 seconds; longer tasks are terminated.
  • Execution context is root — treat scripts as privileged code.

Recommended design practices

  • Keep hook logic lightweight and non-blocking.
  • Offload heavy processing to queues/workers (write to file/socket, let a separate process handle delivery).
  • Validate/sanitize all arguments before using them in shell commands.
  • Log failures explicitly for auditability.
  • Use timeouts on external calls (curl -m 5, timeout 5 ...) to stay within the 10-second budget.

Common pitfalls

  • Long-running hook jobs that exceed the ~10s timeout and silently lose events.
  • Unsanitized argument handling causing command-injection risk — always quote variables.
  • No error logging when downstream integration fails — add explicit error handling.
  • Assuming permanent and temporary workflows are identical — different triggers may send different argument combinations.
  • Hook script not executable — must have execute permission (chmod +x).
  • Forgetting to restart LFD after changing BLOCK_REPORT / UNBLOCK_REPORT in csf.conf.

See also

Last reviewed: 2026-02-27


← Previous: Messenger Service · Next: Port Flood Protection

Clone this wiki locally