sadeq-n-yazdi/simple-blocker
GitHub: sadeq-n-yazdi/simple-blocker
一个基于 Go 的动态 IP 黑名单守护进程,通过监控日志自动在防火墙层面封禁恶意探测与暴力破解 IP。
Stars: 1 | Forks: 0
# simple-blocker
一个小巧、轻依赖的 daemon,用于监控你的日志以防范恶意探测
和暴力破解尝试,然后通过防火墙封禁违规 IP,
并实施逐步升级的限时封禁。
它会追踪日志源(systemd journal、Docker 容器日志),将每一行
与可配置的 regular expressions 进行匹配,当某个地址在滑动窗口内
达到违规阈值时,就会通过 **ipset + iptables**
或 **nftables** 将其丢弃——具体取决于你的主机上安装了哪个。封禁会自动过期。
这是原始 Python 原型的 Go 重写版本,经过了重构以提高
可配置性和可扩展性。
## 功能
- **配置驱动** — YAML *或* JSON(通过文件扩展名选择),无需重新编译。
- **内部或外部执行** — 防火墙以 **基于 netlink 的纯 Go
nftables**(无需外部二进制文件)运行,或者通过 shell 调用主机上的
工具;通过 `firewall.mode` 或 `-firewall-mode` 为每个部署进行选择。
- **可插拔防火墙后端**(外部模式) — `ipset`+`iptables`(支持
`DOCKER-USER`)或原生 `nftables`,自动检测。
- **可插拔日志源** — 目前支持 `journal` (systemd) 和 `docker`;每一个都是
带有命名 `(?P...)` 捕获组的 regex,因此添加新的日志格式
只需修改配置,无需更改代码。
- **逐步升级的封禁** — 窗口内的违规次数越多 ⇒ 封禁时间越长。
- **滑动窗口** — 旧的违规记录会自动老化失效。
- **重启安全** — 规则和集合以幂等方式创建;现有的封禁
在重启后依然有效。
## 工作原理
```
log source ──▶ regex (?P…) ──▶ offense tracker ──▶ ban schedule ──▶ firewall
(journal, per line sliding window offenses→time ipset/iptables
docker) or nftables
```
## 安装
需要一台装有 **systemd** 和 **Go 工具链**(用于构建)的 Linux 主机。
如果不存在防火墙后端,安装程序会为你获取一个。
```
git clone https://code.sadeq.uk/simple-blocker.git # or your fork
cd simple-blocker
sudo ./scripts/install.sh
```
安装程序(幂等 — 可安全重复运行):
1. 检查 `systemd`;如果缺失则中止。
2. 解析防火墙后端(`--backend auto|iptables|nftables`),如果缺失,则通过你的包管理器(`apt`、`dnf`、
`yum`、`pacman`、`zypper` 或 `apk`)安装
`ipset`+`iptables` 或 `nftables`。
3. 将二进制文件构建到 `/usr/local/bin/simple-blocker`。
4. 将默认配置安装到 `/etc/simple-blocker/config.yaml`(从不
覆盖现有文件)。
5. 安装、启用并启动 `simple-blocker.service` systemd unit。
选项:
```
sudo ./scripts/install.sh --backend nftables # force a backend
sudo ./scripts/install.sh --no-enable # install but don't start
```
安装后,**为你的主机编辑 `/etc/simple-blocker/config.yaml`** 并
重启:`sudo systemctl restart simple-blocker`。
### 从预构建包安装 (.deb / .rpm)
每个带标签的发布版本都会在
[发布页面](https://github.com/sadeq-n-yazdi/simple-blocker/releases) 上为 Linux **amd64**、**arm64** 和 **armv7** 发布静态二进制文件和软件包。
```
# Debian / Ubuntu(选择你的架构)
curl -LO https://github.com/sadeq-n-yazdi/simple-blocker/releases/latest/download/simple-blocker__linux_amd64.deb
sudo apt install ./simple-blocker__linux_amd64.deb
# Fedora / RHEL / openSUSE
sudo rpm -i simple-blocker__linux_amd64.rpm
```
该软件包会将二进制文件安装到 `/usr/bin`,systemd unit 安装到系统中,以及
示例配置安装到 `/etc/simple-blocker` 下。首次安装时,它会初始化生成
`/etc/simple-blocker/config.yaml` 并启用(但不启动)该服务。
编辑配置,然后执行 `sudo systemctl start simple-blocker`。
### 手动构建
```
make build # -> dist/simple-blocker (embeds version + commit hash)
make test # run the test suite
sudo ./dist/simple-blocker -config /etc/simple-blocker/config.yaml
```
随时检查构建元数据:
```
simple-blocker version # or: simple-blocker -version
# simple-blocker v0.1.0(commit 1a2b3c4...,构建于 2026-06-28T...,go1.26.4)
```
发布的二进制文件通过链接器标志进行标记;普通的 `go build` 仍然会
通过 Go 嵌入的 VCS 标记显示提交记录。
## 配置
YAML 和 JSON 是可互换的 — 通过文件扩展名进行选择。参见
[`config.example.yaml`](config.example.yaml) 和
[`config.example.json`](config.example.json)。
```
ipset_name: simple_blacklist # name of the ipset / nft set
window: 3h # sliding window for counting offenses
firewall:
mode: internal # internal (pure-Go nftables) | external
backend: auto # external only: auto | iptables | nftables
chains: [INPUT, DOCKER-USER] # external+iptables only
ban_schedule: # highest matching tier wins
- { offenses: 2, ban: 10m }
- { offenses: 3, ban: 30m }
- { offenses: 5, ban: 1h }
- { offenses: 7, ban: 24h }
sources:
- type: journal # journal | docker
name: ssh # label shown in logs
target: ssh # systemd unit (journal) or container (docker)
since: -1d # journal lookback
pattern: 'Invalid user \S+ from (?P\d{1,3}(?:\.\d{1,3}){3})'
```
### 防火墙:内部 vs 外部
`firewall.mode: internal`(默认值)直接从进程内部通过 netlink 管理 nftables
— 无需 `nft`、`iptables` 或 `ipset` 二进制文件,只需
带有 nftables 的内核。它会创建一个带有超时
集合和 `ip saddr @set drop` 规则的 `inet simple_blocker` 表。
`firewall.mode: external` 通过 shell 调用主机上的工具,并遵循 `backend`
(`auto`/`iptables`/`nftables`) — 可在没有 nftables 的主机上使用,或者当你
需要 iptables `DOCKER-USER` 集成时使用。可在运行时使用
标志覆盖配置:
```
simple-blocker -firewall-mode external -config /etc/simple-blocker/config.yaml
```
无论哪种方式,进程都需要 `CAP_NET_ADMIN`(以 root 身份或通过 systemd
unit 运行)。在关闭时,丢弃规则会被移除,但封禁集合会被保留,因此生效中的
封禁在重启后依然有效。
持续时间使用 Go 语法(`10m`、`3h`、`24h`)。每个源 `pattern` 都必须
包含用于地址的捕获组 — 将其命名为 `(?P...)`;未命名的
第一个组可作为后备被接受。
### 源模式:内部 vs 外部
每个源都有一个 `mode`:
- **docker** — `internal`(默认)仅使用 Go 标准库直接从
**基于 unix socket 的 Docker Engine API**(`/var/run/docker.sock`,使用
`docker_host` 覆盖)读取容器日志 — 无需 `docker`
CLI。`external` 则通过 shell 调用 `docker logs -f`。
- **journal** — 始终为 `external`(`journalctl`);`internal` 会被拒绝。
可在运行时使用 `-docker-mode internal|external` 覆盖 docker 源。
### 添加源
在 `sources` 下追加另一个条目。例如,要封禁在 nginx 容器(内部 docker 模式,默认)中
探测 `.php`/`.env` 文件的 IP:
```
- type: docker
name: nginx
target: my-nginx-1
mode: internal # or external to use the docker CLI
pattern: '(?P\d{1,3}(?:\.\d{1,3}){3})\s.*?"[A-Z]+\s+\S*\.(?:php|env|xml)\S*\s+HTTP/\d\.\d".*\s404\s'
```
## 运维操作
```
systemctl status simple-blocker # service health
journalctl -u simple-blocker -f # live logs (bans are logged here)
```
### `status` — 查看被封禁的内容
```
sudo simple-blocker status # human table
sudo simple-blocker status -json # machine-readable
```
`status` 显示**当前被封禁的 IP**(及剩余时间),并且当
daemon 运行时,显示其**违规追踪器**以及它们之间的**差异** — 最
有用的是找出任何超过封禁阈值但不知何故*不*在防火墙
集合中的 IP。它读取 daemon 的只读控制 socket
(`control_socket`,默认为 `/run/simple-blocker.sock`);如果 daemon 未
运行,它会退回到直接读取防火墙集合(需要 root 权限)并
予以说明。你仍然可以自己检查原始集合:
```
sudo ipset list simple_blacklist # iptables backend
sudo nft list set inet simple_blocker simple_blacklist # nftables backend
```
### `check` — 模拟运行日志匹配
```
simple-blocker check # scan recent logs, then exit
simple-blocker check -follow # stream live until Ctrl-C
simple-blocker check -source nginx # only one source
simple-blocker check -actions=false # lines only, no action
simple-blocker check -color never # disable IP highlighting
```
`check` 读取每个已配置的源,打印出与
其 pattern 匹配的每一行,并高亮显示**捕获的 IP**,而且 — 默认开启 — 根据你真实的封禁计划模拟出 daemon 将采取的
**行动**(升级违规计数,无实际封禁):
```
[nginx] 45.9.1.2 … "GET /wp-login.php HTTP/1.1" 404 …
→ offense #2 from 45.9.1.2 within 3h → would ban 10m
```
它不会封禁任何 IP 且不需要任何权限 — 纯粹用于诊断。
关闭时,服务会移除其丢弃规则但**保留封禁集合**,因此
处理中的封禁在重启后依然有效。
## 卸载
```
sudo systemctl disable --now simple-blocker
sudo rm /etc/systemd/system/simple-blocker.service /usr/local/bin/simple-blocker
sudo rm -r /etc/simple-blocker
sudo systemctl daemon-reload
# 可选地移除 ban set:
sudo ipset destroy simple_blacklist # iptables backend
sudo nft delete table inet simple_blocker # nftables backend
```
## 项目结构
```
cmd/simple-blocker/ entrypoint (flags, wiring, signal handling)
internal/config/ YAML/JSON loading, defaults, validation
internal/blocker/ offense tracker (sliding window) + ban engine
internal/firewall/ Firewall interface + iptables and nftables backends
internal/source/ Source interface + journal and docker tailers
scripts/install.sh installer (deps, build, systemd)
```
扩展点是 `firewall.Firewall` 和 `source.Source` 接口 —
实现其中任意一个即可添加一个后端或一个日志源。
## 需求
- 带有 systemd 的 Linux
- Go(仅构建时需要;二进制文件是静态的,`CGO_ENABLED=0`)
- 防火墙:带有 nftables 的内核(内部模式),或 `ipset`+`iptables` / `nftables` 工具(外部模式)
- `docker` CLI 仅用于 `external` 模式下的 `docker` 源(内部模式直接使用 API socket)
## 许可证
MIT
标签:EVTX分析, Go, IP封禁, nftables, Ruby工具, 入侵防御, 日志审计, 请求拦截, 运维工具, 防火墙