
Skript zur Implementierung von Q-Feeds direkt auf NFtables oder IPtables
Automatisierte Malware-IP-Blocklist für Linux-Server – unterstützt nftables und iptables+ipset
Holen Sie sich einen kostenlosen API-Schlüssel unter 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
### Schritt 3: Führen Sie das Installationsprogramm als root aus```bash
sudo ./qfeeds-installer.sh
Der Installateur wird:
Dein Server ist nun geschützt. Der Cron-Job prüft alle 20 Minuten auf Aktualisierungen (konfigurierbar), und tatsächliche API-Aufrufe erfolgen nur, wenn es deine Lizenz zulässt.
Diese Lösung lädt regelmäßig den neuesten Bedrohungsinformations-Feed von Q-Feeds herunter und wendet ihn als Firewall-Regeln an, sodass du:
Der Installateur erkennt automatisch, welches Firewall-Backend verfügbar ist:
| Priorität | Erkennung | Backend |
|---|---|---|
| 1. | nft-Befehl gefunden | nftables |
| 2. | iptables-Befehl gefunden | iptables+ipset |
| — | Keines gefunden | Fehler (Abbruch) |
Das erkannte Backend wird in der Konfigurationsdatei gespeichert. Die Aktualisierungs- und Deinstallationsskripte verwenden es, um die korrekten Firewall-Befehle auszuführen.
Beide Backends verwenden dieselbe Split-Set-Strategie für maximale Leistung:
nftables-Backend:``` ┌─────────────────────────────────────────────────────────┐ │ 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 Backend:**```
┌──────────────────────────────────────────────────────────┐
│ 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) │
└──────────────────────────────────────────────────────────┘
Die gleiche Struktur existiert für IPv6 (ip6 qfeeds table oder ip6tables + family inet6 ipsets).
Warum zwei Set-Typen?
┌──────────────────────────────────────────────────────┐ │ 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 vs Diff Sync
| Modus | Wann | Was es tut |
|------|------|-------------|
| **Full Sync** | Erster Durchlauf, erzwungenes Update, nach einem fehlgeschlagenen Diff, wenn die lokale Menge ihre Basis verloren hat (leer oder viel kleiner als erwartet), oder wenn die letzte Synchronisation älter als `FULL_SYNC_MAX_AGE` (Standard 24h) ist | Ruft zuerst jeden Feed ab und validiert ihn, dann werden die Blacklist-Sets geleert und neu geladen. Das Set wird erst geleert, wenn gültige Daten vorliegen, sodass ein fehlgeschlagener Abruf Sie nie ungeschützt zurücklässt |
| **Diff Sync** | Nachfolgende Durchläufe (nur `malware_ip`-Feed) mit einer intakten lokalen Menge | Ruft nur Hinzufügungen (`+`) und Entfernungen (`-`) seit dem letzten Abruf ab |
Der Diff-Sync erfolgt **pro API-Key** – die API verfolgt Ihren letzten erfolgreichen Abruf und gibt nur Änderungen seitdem zurück. Wenn ein Diff fehlschlägt, fällt das Skript automatisch auf einen Full Sync zurück.
> **Selbstheilung:** Diff-Updates patchen nur das bestehende Set. Wenn dieses Set jemals verloren geht oder abgeschnitten wird – z. B. bei einem Neustart, bei dem die Firewall-Regeln nicht dauerhaft gespeichert wurden, einem manuellen Leeren oder einer vorherigen teilweisen Synchronisation – erkennt der Updater die fehlende Basis (Live-Elementanzahl ist 0 oder weit unter der zuletzt aufgezeichneten Anzahl) und erzwingt einen vollständigen Neuaufbau, anstatt ein leeres Set zu differenzieren. Als zusätzliches Sicherheitsnetz erzwingt er außerdem eine regelmäßige vollständige Synchronisation (standardmäßig alle 24h über `FULL_SYNC_MAX_AGE`).
### Lizenzbasiertes Zeitplanmanagement
Der Updater prüft vor jedem Durchlauf die Q-Feeds-Lizenz-API (`licenses.php`). Wenn der `next_update`-Zeitstempel Ihrer Lizenz noch nicht erreicht ist, beendet sich das Skript frühzeitig, ohne unnötige API-Aufrufe zu tätigen. Der Cron-Job läuft häufig (Standard: alle 20 Minuten), aber tatsächliche Updates erfolgen nur, wenn Ihre Lizenz es erlaubt.
---
## ✅ Voraussetzungen
Stellen Sie vor der Installation sicher, dass Sie Folgendes haben:
- [x] **Linux-Server** mit **nftables** oder **iptables** (Debian, Ubuntu, CentOS, Fedora, Arch, Alpine)
- [x] **Root-Zugriff** – der Installer und Updater müssen als Root ausgeführt werden
- [x] **Q-Feeds-API-Token** – kostenlos erhältlich unter [tip.qfeeds.com](https://tip.qfeeds.com/)
- [x] **Internet-Zugriff** – der Server muss `api.qfeeds.com` erreichen können
Der Installer installiert automatisch die erforderlichen Abhängigkeiten:
- **nftables-Backend**: `nftables`, `curl`, `jq`, `util-linux`
- **iptables-Backend**: `iptables`, `ipset`, `curl`, `jq`, `util-linux`
---
## 📝 Detaillierte Installationsanleitung
### 1. API-Token abrufen
Besuchen Sie [tip.qfeeds.com](https://tip.qfeeds.com/), um Ihr kostenloses Q-Feeds-API-Token zu erhalten.
### 2. Herunterladen und ausführen```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
Der Installer wird die folgenden Fragen stellen:
Enter your Q-Feeds API Token:
Ihr Token von [tip.qfeeds.com](https://tip.qfeeds.com/). Der Installer verweigert die Fortsetzung, wenn dieses Feld leer ist.
#### Feed-Typ```
Enter feed type [default: malware_ip]:
Standard ist malware_ip. Ändern Sie dies nur, wenn Q-Feeds Ihnen einen anderen Feed-Typ bereitgestellt hat.
Enter the limit of IPs to fetch (leave empty for no limit):
Drücken Sie die Eingabetaste für keine Begrenzung (empfohlen). Geben Sie eine Zahl ein, um die Feed-Größe zu begrenzen.
#### Richtungsblockierung```
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):
Fügen Sie hier Ihre Verwaltungs-IP(s) hinzu, um sicherzustellen, dass Sie nie ausgesperrt werden, selbst wenn sie im Feed erscheinen. Whitelist-Regeln werden immer **vor** Blacklist-Regeln überprüft.
#### Cron Schedule```
Enter cron schedule (e.g., '*/20 * * * *') [default: */20 * * * *]:
Wie oft der Updater nach neuen Daten sucht. Standardmäßig alle 20 Minuten. Die lizenzbasierte Planung stellt sicher, dass die API nur aufgerufen wird, wenn Ihre Lizenz ein Update erlaubt.
Erneutes Ausführen des Installationsprogramms mit einer angepassten Crontab: Wenn bereits ein Q-Feeds-Cron-Eintrag existiert, fragt das Installationsprogramm vor der Änderung nach:
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]:Antworten Sie
no(Standardeinstellung), um Ihre vorhandene Crontab zu behalten. Eine saubere Ersterstellung hat keinen vorhandenen Eintrag und überspringt diese Eingabeaufforderung. Für unbeaufsichtigte Installationen setzen SieQFEEDS_SKIP_CRON=1, um die Crontab unverändert zu lassen, ohne nachzufragen.
Alle Einstellungen werden in /etc/qfeeds/qfeeds_config.conf gespeichert. Sie können diese Datei direkt bearbeiten, ohne das Installationsprogramm erneut auszuführen. Änderungen werden beim nächsten Cron-Durchlauf wirksam.
| Variable | Beschreibung | Standard |
|---|---|---|
BACKEND | Firewall-Backend (nftables oder iptables) | (automatisch erkannt) |
API_TOKEN | Ihr Q-Feeds-API-Token | (erforderlich) |
FEED_TYPE | Abzurufender Feed-Typ | malware_ip |
LIMIT | Maximale Anzahl abzurufender IPs (leer = kein Limit) | (leer) |
BLOCK_INCOMING | Eingehende Verbindungen von blockierten IPs unterbinden | yes |
BLOCK_OUTGOING | Ausgehende Verbindungen zu blockierten IPs unterbinden | no |
WHITELIST_V4 | Kommagetrennte IPv4-Whitelist | (leer) |
WHITELIST_V6 | Kommagetrennte IPv6-Whitelist | (leer) |
LOG_FILE | Pfad zur Logdatei | /var/log/qfeeds_blocklist.log |
FULL_SYNC_MAX_AGE | Maximales Alter in Sekunden, bevor eine vollständige Neusynchronisierung erzwungen wird (Defense in Depth) | 86400 (24h) |
| Pfad | Zweck |
|---|---|
/etc/qfeeds/qfeeds_config.conf | Konfigurationsdatei |
/etc/qfeeds/.last_sync | Statusdatei zur Nachverfolgung vollständiger/differenzieller Synchronisation |
/etc/qfeeds/.last_count | Letzte erfolgreiche Elementanzahl, dient zur Erkennung einer verlorenen Basislinie |
/usr/local/bin/update_qfeeds_blocklist.sh | Updater-Skript (läuft über Cron) |
/var/log/qfeeds_blocklist.log | Logdatei |
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 Backend```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
---
## 🔍 Fehlerbehebung
### Allgemein
**Installation schlägt fehl mit "Unable to locate package"**
- Der Installer erkennt Ihre Distribution automatisch (Debian/Ubuntu, CentOS/RHEL, Fedora, Arch, Alpine). Falls die Erkennung fehlschlägt, installieren Sie die Abhängigkeiten manuell: `curl`, `jq`, `util-linux` (für `flock`), sowie `nftables` oder `iptables`+`ipset`.
**Sets sind nach der Installation leer**
- Überprüfen Sie das Log: `tail -50 /var/log/qfeeds_blocklist.log`
- Stellen Sie sicher, dass Ihr API-Token korrekt ist
- Versuchen Sie ein erzwungenes Update: `sudo QFEEDS_FORCE_UPDATE=1 /usr/local/bin/update_qfeeds_blocklist.sh`
**"Not time yet. Next update scheduled at..."**
- Das Update-Tool respektiert Ihren Lizenzzeitplan. Diese Meldung bedeutet, dass der Cron-Job ausgeführt wurde, Ihre Lizenz aber noch kein Update erlaubt. Dies ist normal – der nächste Cron-Durchlauf wird erneut prüfen.
- Der Linux-Installer speichert einen lokalen zwischengespeicherten `licenses.php`-Index und verwendet das gecachte `next_update` als Zeitsteuerung. Nach einem erfolgreichen Pull wird der lokale Index für den nächsten Zyklus aktualisiert.
**Regeln bleiben nach einem Neustart nicht bestehen**
- Wenn `netfilter-persistent` installiert ist, werden die Regeln automatisch gespeichert
- **nftables**: Falls `netfilter-persistent` fehlt, schreibt das Update-Tool nun das vollständige Regelset automatisch in `/etc/nftables.conf` und aktiviert den `nftables`-Dienst; Sie können weiterhin manuell speichern mit `nft list ruleset > /etc/nftables.conf`
- **iptables**: Das Update-Tool speichert mit `ipset save > /etc/ipset.conf` und `iptables-save`; Sie können auch manuell speichern
- Selbst wenn die Persistenz vollständig fehlschlägt, heilt das Update-Tool sich selbst: Beim nächsten Lauf erkennt es das leere Set nach einem Neustart und baut es mit einer vollständigen Synchronisation neu auf.
### nftables-spezifisch
**"Batch nft -f fehlgeschlagen. Rückfall auf befehlsweise Ausführung..."**
- Dies ist normal, insbesondere auf LXC-Containern, bei denen der Netlink-Puffer des Kernels (`wmem_max`) eingeschränkt ist. Der Rückfall auf befehlsweise Ausführung funktioniert korrekt und ist schnell (~10 Sekunden für über 400k IPs).
**Syntaxfehler: "unerwartete Zeichenkette"**
- Stellen Sie sicher, dass Sie eine aktuelle Version von nftables verwenden. Das Skript verwendet die Syntax `ip saddr`/`ip daddr`, die nftables 0.9+ erfordert.
**"Fehler: Regel konnte nicht verarbeitet werden: Nachricht zu lang"**
- Dies ist die Netlink-Puffergrenze, typisch in LXC-Containern. Das Skript fällt automatisch auf befehlsweise Ausführung zurück. Wenn Sie dies im Log zusammen mit einem erfolgreichen Laden sehen, funktioniert es wie vorgesehen.
### iptables+ipset-spezifisch
**"ipset restore fehlgeschlagen"**
- Überprüfen Sie, ob `ipset` installiert ist: `command -v ipset`
- Überprüfen Sie das Log auf spezifische Fehler: `grep -i "error" /var/log/qfeeds_blocklist.log`
- Stellen Sie sicher, dass das ipset-Modul geladen ist: `lsmod | grep ip_set`
**iptables-Regeln werden nicht angezeigt**
- Die Blockierungsregeln befinden sich in den dedizierten Ketten `QFEEDS_INPUT` / `QFEEDS_OUTPUT`; `INPUT`/`OUTPUT` enthalten nur einen `-j QFEEDS_INPUT`-Sprung mit dem `qfeeds`-Kommentar
- Überprüfen Sie mit: `iptables -L INPUT -n | grep qfeeds` (der Sprung) und `iptables -L QFEEDS_INPUT -n` (die Blockregeln)
- Die Sprungregel verwendet `-m comment --comment "qfeeds"` zur Identifikation
- Stellen Sie sicher, dass das Modul `xt_set` geladen ist: `modprobe xt_set`
**"ipset create ... fehlgeschlagen"**
- Auf sehr alten Kerneln sind die Typen `hash:ip` oder `hash:net` möglicherweise nicht verfügbar. Aktualisieren Sie Ihren Kernel oder installieren Sie `ipset` aus einem neueren Repository.
---
## 🗑️ Deinstallation```bash
sudo ./qfeeds-uninstaller.sh
Das Deinstallationsprogramm entfernt alles basierend auf dem erkannten Backend:
nftables-Backend:
ip qfeeds und ip6 qfeeds (einschließlich aller Chains, Regeln und Sets)iptables-Backend:
qfeeds-Kommentar versehen sind (einschließlich der Sprungregeln)QFEEDS_INPUT / QFEEDS_OUTPUTqfeeds_blacklist_v4, qfeeds_blacklist_v4_nets, qfeeds_whitelist_v4 und IPv6-Äquivalente)Beide Backends:
/etc/qfeeds/)/usr/local/bin/update_qfeeds_blocklist.sh)Fehlt die Konfigurationsdatei, versucht das Deinstallationsprogramm eine Bereinigung für beide Backends.
Hinweis: Das Deinstallationsprogramm entfernt nicht die als Abhängigkeiten installierten Systempakete (curl, jq, ipset usw.).
Dieses Projekt ist lizenziert unter der Apache License 2.0 – siehe die Datei LICENSE für Details.
Nutzung auf eigene Gefahr.
Bitte testen Sie diese Skripte in Ihrer Umgebung, bevor Sie sie in der Produktion einsetzen. Der Autor übernimmt keine Verantwortung für etwaige Probleme oder Schäden, die durch deren Verwendung entstehen.
KI-Unterstützung: Teile dieses Projekts (Code, Korrekturen und Dokumentation) wurden mit Hilfe von KI-Tools erstellt und anschließend von den Betreuern überprüft. Obwohl wir Änderungen testen und überprüfen, sollten Sie die Skripte vor der Ausführung selbst durchsehen und melden, wenn etwas ungewöhnlich erscheint.