
Script to implement Q-Feeds directly on NFtables or IPtables
在 tip.qfeeds.com 获取免费API密钥。
git clone https://github.com/Q-Feeds/NFtables-IPtables-integration-script.git cd NFtables-IPtables-integration-script chmod +x qfeeds-installer.sh qfeeds-uninstaller.sh
### 步骤 3:以 root 身份运行安装程序```bash
sudo ./qfeeds-installer.sh
安装程序将:
您的服务器现已受到保护。cron 任务每 20 分钟(可配置)检查一次更新,实际 API 调用仅在您的许可证允许时进行。
此解决方案会定期从 Q-Feeds 下载最新的威胁情报源,并将其应用为防火墙规则,使您能够:
安装程序自动检测可用的防火墙后端:
检测到的后端存储在配置文件中。更新程序和卸载程序脚本使用该信息来运行正确的防火墙命令。
两种后端均采用相同的拆分集合策略以实现最佳性能:
nftables 后端:``` ┌─────────────────────────────────────────────────────────┐ │ table ip qfeeds │ │ │ │ ┌─────────────────────────┐ ┌───────────────────────┐ │ │ │ qfeeds_blacklist_v4 │ │ qfeeds_blacklist_v4 │ │ │ │ (hash set) │ │ _nets (interval set) │ │ │ │ │ │ │ │ │ │ Individual IPs │ │ CIDR ranges │ │ │ │ ~99% of entries │ │ ~1% of entries │ │ │ │ O(1) lookup & insert │ │ O(log n) lookup │ │ │ └─────────────────────────┘ └───────────────────────┘ │ │ │ │ ┌─────────────────────────┐ │ │ │ qfeeds_whitelist_v4 │ │ │ │ (interval set) │ │ │ │ Your allowed IPs/CIDRs │ │ │ └─────────────────────────┘ │ │ │ │ chain input-chain (hook input, priority 0, accept) │ │ → ip saddr @qfeeds_whitelist_v4 accept │ │ → ip saddr @qfeeds_blacklist_v4 drop │ │ → ip saddr @qfeeds_blacklist_v4_nets drop │ │ │ │ chain output-chain (if enabled) │ │ → ip daddr @qfeeds_whitelist_v4 accept │ │ → ip daddr @qfeeds_blacklist_v4 drop │ │ → ip daddr @qfeeds_blacklist_v4_nets drop │ └─────────────────────────────────────────────────────────┘
**iptables+ipset 后端:**```
┌──────────────────────────────────────────────────────────┐
│ ipset sets │
│ │
│ ┌─────────────────────────┐ ┌────────────────────────┐ │
│ │ qfeeds_blacklist_v4 │ │ qfeeds_blacklist_v4 │ │
│ │ (hash:ip) │ │ _nets (hash:net) │ │
│ │ maxelem 1000000 │ │ maxelem 65536 │ │
│ │ │ │ │ │
│ │ Individual IPs │ │ CIDR ranges │ │
│ └─────────────────────────┘ └────────────────────────┘ │
│ │
│ ┌─────────────────────────┐ │
│ │ qfeeds_whitelist_v4 │ │
│ │ (hash:net) │ │
│ └─────────────────────────┘ │
│ │
│ iptables: INPUT/OUTPUT jump to a dedicated chain │
│ (jump rule tagged -m comment "qfeeds"): │
│ │
│ chain QFEEDS_INPUT (rebuilt each run, in order): │
│ -m set --match-set whitelist_v4 src -j ACCEPT │
│ -m set --match-set blacklist_v4 src -j DROP │
│ -m set --match-set blacklist_v4_nets src -j DROP │
│ (QFEEDS_OUTPUT mirrors this with dst, if enabled) │
└──────────────────────────────────────────────────────────┘
IPv6 (ip6 qfeeds 表或 ip6tables + family inet6 ipsets) 也存在相同的结构。
为什么有两种集合类型?
┌──────────────────────────────────────────────────────┐ │ 1. Check license schedule (licenses.php API) │ │ → Skip run if not yet time for next update │ │ 2. Determine sync mode (full or diff) │ │ 3. Fetch IPv4 feed (ipv6=0) and IPv6 feed │ │ (ipv6=only) separately │ │ 4. Separate IPs from CIDRs in awk │ │ 5. Batch-load into hash set (IPs) and net/interval │ │ set (CIDRs) │ │ 6. Update whitelist sets from config │ │ 7. Persist rules │ └──────────────────────────────────────────────────────┘
### 全量同步与增量同步
| 模式 | 触发时机 | 执行操作 |
|------|---------|---------|
| **全量同步** | 首次运行、强制更新、增量同步失败后、本地集合丢失基线(为空或远小于预期)、或上次同步时间早于 `FULL_SYNC_MAX_AGE`(默认24小时) | 先获取并验证每个数据源,然后清空并重新加载黑名单集合。仅在确认获得有效数据后才清空集合,因此一次失败的获取不会让你失去保护 |
| **增量同步** | 后续运行(仅限 `malware_ip` 数据源)且本地集合健康时 | 仅获取上次拉取以来的新增(`+`)和移除(`-`)条目 |
增量同步是**按 API 密钥**进行的——API 会记录你最后一次成功拉取的时间,并仅返回此后发生的变更。如果增量同步失败,脚本会自动回退到全量同步。
> **自愈机制:** 增量更新仅修补现有集合。如果该集合丢失或被截断——例如防火墙规则未持久化的重启、手动清空、或之前的局部同步——更新程序会检测到缺失的基线(实时元素计数为0或远低于上次记录的值),并强制进行完整重建,而不是在空集合上做增量。作为额外的安全网,它还会强制定期进行全量同步(默认每24小时,通过 `FULL_SYNC_MAX_AGE` 控制)。
### 基于许可证的调度
更新程序在每次运行前都会检查 Q-Feeds 许可证 API(`licenses.php`)。如果您的许可证的 `next_update` 时间戳尚未到达,脚本会提前退出,避免不必要的 API 调用。cron 任务运行频繁(默认每20分钟),但实际更新仅在许可证允许时发生。
---
## ✅ 前提条件
安装前,请确保满足以下条件:
- [x] **Linux 服务器**,支持 **nftables** 或 **iptables**(Debian、Ubuntu、CentOS、Fedora、Arch、Alpine)
- [x] **Root 权限**——安装程序和更新程序必须以 root 身份运行
- [x] **Q-Feeds API 令牌**——请在 [tip.qfeeds.com](https://tip.qfeeds.com/) 免费获取
- [x] **互联网访问**——服务器需能访问 `api.qfeeds.com`
安装程序会自动安装所需的依赖:
- **nftables 后端**:`nftables`、`curl`、`jq`、`util-linux`
- **iptables 后端**:`iptables`、`ipset`、`curl`、`jq`、`util-linux`
---
## 📝 详细安装指南
### 1. 获取您的 API 令牌
请访问 [tip.qfeeds.com](https://tip.qfeeds.com/) 获取免费的 Q-Feeds API 令牌。
### 2. 下载并运行```bash
git clone https://github.com/Q-Feeds/NFtables-IPtables-integration-script.git
cd NFtables-IPtables-integration-script
chmod +x qfeeds-installer.sh qfeeds-uninstaller.sh
sudo ./qfeeds-installer.sh
安装程序将询问以下问题:
Enter your Q-Feeds API Token:
来自 [tip.qfeeds.com](https://tip.qfeeds.com/) 的您的令牌。如果为空,安装程序将拒绝继续。
#### 订阅源类型```
Enter feed type [default: malware_ip]:
默认值是 malware_ip。仅当 Q-Feeds 为您提供了不同的源类型时才更改此项。
Enter the limit of IPs to fetch (leave empty for no limit):
按下 Enter 键表示无限制(推荐)。输入数字以限制馈送大小。
#### 定向阻塞```
Block INCOMING connections from malicious IPs? [Y/n]:
Block OUTGOING connections to malicious IPs? [y/N]:
Configure a whitelist of IPs/CIDRs that must NEVER be blocked? [y/N]: Enter IPv4 whitelist (comma-separated, e.g. 1.2.3.4,5.6.7.8): Enter IPv6 whitelist (comma-separated, e.g. 2001:db8::1):
添加您的管理IP地址在此处,以确保您永远不会被锁定,即使它们出现在源中。白名单规则总是在黑名单规则**之前**进行检查。
#### Cron 计划```
Enter cron schedule (e.g., '*/20 * * * *') [default: */20 * * * *]:
更新程序检查新数据的频率。默认每20分钟一次。基于许可证的调度确保仅在您的许可证允许更新时才调用API。
使用自定义crontab重新运行安装程序: 如果已存在Q-Feeds的cron条目,安装程序会在修改前询问:
在当前crontab中发现了一个现有的Q-Feeds cron条目。 是否用新的默认条目替换它?选择'no'保持您的crontab不变 [y/N]:回答
no(默认)以保留现有的crontab。全新的首次安装没有现有条目,会跳过此提示。对于无人值守安装,设置QFEEDS_SKIP_CRON=1可在不提示的情况下保持crontab不变。
所有设置存储在/etc/qfeeds/qfeeds_config.conf中。您可以直接编辑此文件而无需重新运行安装程序。更改将在下一次cron运行时生效。
nft list table ip qfeeds
nft list set ip qfeeds qfeeds_blacklist_v4 | grep -oP '\d+.\d+.\d+.\d+' | wc -l
nft list set ip qfeeds qfeeds_blacklist_v4_nets | head -20
nft list set ip6 qfeeds qfeeds_blacklist_v6 | wc -l
### iptables+ipset 后端```bash
# List all Q-Feeds ipsets and their sizes
ipset list -t | grep -A4 qfeeds
# Count loaded IPv4 IPs
ipset list qfeeds_blacklist_v4 | tail -n +9 | wc -l
# Show loaded CIDR ranges
ipset list qfeeds_blacklist_v4_nets | tail -n +9 | head -20
# Show the qfeeds jump rule in INPUT, then the dedicated chain's block rules
iptables -L INPUT -n --line-numbers | grep qfeeds
iptables -L QFEEDS_INPUT -n
ip6tables -L QFEEDS_INPUT -n
tail -20 /var/log/qfeeds_blocklist.log
grep -i "error" /var/log/qfeeds_blocklist.log
sudo /usr/local/bin/update_qfeeds_blocklist.sh
sudo QFEEDS_FORCE_UPDATE=1 /usr/local/bin/update_qfeeds_blocklist.sh
sudo crontab -l | grep qfeeds
---
## 🔍 故障排除
### 常规
**安装失败,提示"Unable to locate package"**
- 安装程序会自动检测你的发行版(Debian/Ubuntu, CentOS/RHEL, Fedora, Arch, Alpine)。如果检测失败,请手动安装依赖项:`curl`, `jq`, `util-linux`(用于 `flock`),以及 `nftables` 或 `iptables`+`ipset`。
**安装后集合为空**
- 检查日志:`tail -50 /var/log/qfeeds_blocklist.log`
- 验证你的 API 令牌是否正确
- 尝试强制更新:`sudo QFEEDS_FORCE_UPDATE=1 /usr/local/bin/update_qfeeds_blocklist.sh`
**"还没到时间。下次更新计划在..."**
- 更新程序遵循你的许可计划。此消息表示 cron 已运行,但你的许可证不允许现在更新。这是正常的 —— 下次 cron 运行时会再次检查。
- Linux 安装程序会在本地缓存 `licenses.php` 索引,并使用缓存的 `next_update` 作为计划门控。成功拉取后,它会刷新该本地索引以供下一个周期使用。
**重启后规则不持久化**
- 如果安装了 `netfilter-persistent`,规则会自动保存
- **nftables**:如果缺少 `netfilter-persistent`,更新程序现在会自动将完整的规则集写入 `/etc/nftables.conf` 并启用 `nftables` 服务;你仍然可以使用 `nft list ruleset > /etc/nftables.conf` 手动保存
- **iptables**:更新程序使用 `ipset save > /etc/ipset.conf` 和 `iptables-save` 保存;你也可以手动保存
- 即使持久化完全失败,更新程序也会自我修复:下次运行时,它会在重启后检测到空集合,并通过完全同步重建它。
### nftables 专属
**"批量 nft -f 失败。回退到逐个命令执行..."**
- 这是正常的,尤其是在 LXC 容器中,内核的 netlink 缓冲区(`wmem_max`)受限。逐个命令的回退方式能正确工作,并且速度很快(40万个IP约10秒)。
**语法错误:"unexpected string"**
- 确保你运行的是较新版本的 nftables。该脚本使用 `ip saddr`/`ip daddr` 语法,需要 nftables 0.9+。
**"错误:无法处理规则:消息太长"**
- 这是 netlink 缓冲区限制,通常出现在 LXC 容器中。脚本会自动回退到逐个命令执行。如果你在日志中看到此消息的同时规则成功加载,则属于正常现象。
### iptables+ipset 专属
**"ipset restore 失败"**
- 检查是否安装了 `ipset`:`command -v ipset`
- 检查日志中的具体错误:`grep -i "error" /var/log/qfeeds_blocklist.log`
- 确保 ipset 模块已加载:`lsmod | grep ip_set`
**iptables 规则未显示**
- 阻塞规则位于专用的 `QFEEDS_INPUT` / `QFEEDS_OUTPUT` 链中;`INPUT`/`OUTPUT` 链仅包含一个带有 `qfeeds` 注释的 `-j QFEEDS_INPUT` 跳转
- 验证命令:`iptables -L INPUT -n | grep qfeeds`(跳转规则)和 `iptables -L QFEEDS_INPUT -n`(阻塞规则)
- 跳转规则使用 `-m comment --comment "qfeeds"` 进行标识
- 确保 `xt_set` 模块已加载:`modprobe xt_set`
**"ipset create ... 失败"**
- 在非常旧的内核上,`hash:ip` 或 `hash:net` 类型可能不可用。请升级内核或从更新的仓库安装 `ipset`。
---
## 🗑️ 卸载```bash
sudo ./qfeeds-uninstaller.sh
卸载程序会根据检测到的后端移除所有内容:
nftables 后端:
ip qfeeds 和 ip6 qfeeds 表(包括所有链、规则和集合)iptables 后端:
qfeeds 注释标签的 iptables/ip6tables 规则(包括跳转规则)QFEEDS_INPUT / QFEEDS_OUTPUT 链qfeeds_blacklist_v4、qfeeds_blacklist_v4_nets、qfeeds_whitelist_v4 以及 IPv6 对应项)两个后端:
/etc/qfeeds/)/usr/local/bin/update_qfeeds_blocklist.sh)如果缺少配置文件,卸载程序会尝试清理两个后端。
注意: 卸载程序不会移除作为依赖项安装的系统包(curl、jq、ipset 等)。
本项目基于 Apache License 2.0 许可 - 详见 LICENSE 文件。
自行承担使用风险。
请在生产环境部署前,先在您的环境中测试这些脚本。作者不对因使用它们而产生的任何问题或损害负责。
AI 辅助: 本项目部分内容(代码、修复和文档)借助 AI 工具编写,并随后由维护者审核。虽然我们测试并审核了更改,但请在运行前自行审阅脚本,并报告任何异常情况。
| 优先级 |
|---|
| 检测方式 |
|---|
| 后端 |
|---|
| 第1 | 找到 nft 命令 | nftables |
| 第2 | 找到 iptables 命令 | iptables+ipset |
| — | 均未找到 | 错误(退出) |
| 变量 | 描述 | 默认值 |
|---|
BACKEND | 防火墙后端(nftables或iptables) | (自动检测) |
API_TOKEN | 您的Q-Feeds API令牌 | (必填) |
FEED_TYPE | 要获取的馈送类型 | malware_ip |
LIMIT | 最多获取的IP数量(空=无限制) | (空) |
BLOCK_INCOMING | 阻止来自黑名单IP的入站流量 | yes |
BLOCK_OUTGOING | 阻止发往黑名单IP的出站流量 | no |
WHITELIST_V4 | 逗号分隔的IPv4白名单 | (空) |
WHITELIST_V6 | 逗号分隔的IPv6白名单 | (空) |
LOG_FILE | 日志文件路径 | /var/log/qfeeds_blocklist.log |
FULL_SYNC_MAX_AGE | 强制完全重新同步前的最大秒数(纵深防御) | 86400(24小时) |
| 路径 | 用途 |
|---|
/etc/qfeeds/qfeeds_config.conf | 配置文件 |
/etc/qfeeds/.last_sync | 全量/差异同步跟踪的状态文件 |
/etc/qfeeds/.last_count | 上次成功的元素数量,用于检测丢失的基线 |
/usr/local/bin/update_qfeeds_blocklist.sh | 更新脚本(通过cron运行) |
/var/log/qfeeds_blocklist.log | 日志文件 |