
Script to implement Q-Feeds directly on NFtables or IPtables
無料のAPIキーを tip.qfeeds.com で取得します。
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 ipset)。
なぜ2種類のセットタイプがあるのか?
┌──────────────────────────────────────────────────────┐ │ 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 │ └──────────────────────────────────────────────────────┘
### フル同期 vs 差分同期
| モード | タイミング | 動作 |
|------|------|-------------|
| **フル同期** | 初回実行、強制更新、差分失敗後、ローカルセットのベースラインが失われた場合(空または想定より大幅に小さい)、または最終同期が `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):
#### Cronスケジュール
ここに管理IPアドレスを追加してください。フィードに表示されている場合でも、ロックアウトされることはありません。ホワイトリストルールはブラックリストルールの**前に**常にチェックされます。```
Enter cron schedule (e.g., '*/20 * * * *') [default: */20 * * * *]:
アップデーターが新しいデータをチェックする頻度。デフォルトは20分ごとです。ライセンスベースのスケジューリングにより、ライセンスが更新を許可する場合のみAPIが呼び出されます。
カスタマイズされたcrontabでインストーラーを再実行する: Q-Feedsのcronエントリが既に存在する場合、インストーラーは触れる前に確認を求めます:
An existing Q-Feeds cron entry was found in the current crontab. Replace it with a fresh default entry? Choosing 'no' keeps your crontab unchanged [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
---
## 🔍 トラブルシューティング
### 一般
**インストールが失敗し、「パッケージが見つかりません」と表示される場合**
- インストーラーは自動的にディストリビューション(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秒)。
**構文エラー:「予期しない文字列」**
- 最新バージョンの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 | ログファイル |