
Script to implement Q-Feeds directly on NFtables or IPtables
قائمة حظر IP للبرمجيات الخبيثة آلية لخوادم لينكس — تدعم nftables و iptables+ipset
احصل على مفتاح 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 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 (`licenses.php`) قبل كل تشغيل. إذا لم يتم الوصول إلى الطابع الزمني `next_update` الخاص بترخيصك بعد، يخرج السكريبت مبكرًا دون إجراء استدعاءات API غير ضرورية. تعمل مهمة cron بشكل متكرر (افتراضي: كل 20 دقيقة)، لكن التحديثات الفعلية تحدث فقط عندما يسمح بذلك ترخيصك.
---
## ✅ المتطلبات الأساسية
قبل التثبيت، تأكد من أن لديك:
- [ ] **خادم Linux** مزود بـ **nftables** أو **iptables** (Debian, Ubuntu, CentOS, Fedora, Arch, Alpine)
- [ ] **صلاحية الجذر** — يجب أن يعمل المثبت والمُحَدِّث كجذر
- [ ] **رمز API الخاص بـ Q-Feeds** — احصل على رمزك المجاني على [tip.qfeeds.com](https://tip.qfeeds.com/)
- [ ] **اتصال بالإنترنت** — يحتاج الخادم إلى الوصول إلى `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/) للحصول على رمز API المجاني الخاص بـ Q-Feeds.
### 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):
#### Directional Blocking
اضغط على 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 الإدارية الخاصة بك هنا لضمان عدم تعرضك للحظر أبدًا، حتى لو ظهرت في الخلاصة. يتم دائمًا التحقق من قواعد Whitelist **قبل** قواعد Blacklist.
#### جدول Cron```
Enter cron schedule (e.g., '*/20 * * * *') [default: */20 * * * *]:
كم مرة يتحقق المحدّث من البيانات الجديدة. الافتراضي هو كل 20 دقيقة. يضمن الجدولة القائمة على الترخيص استدعاء واجهة البرمجة فقط عندما يسمح ترخيصك بالتحديث.
إعادة تشغيل المثبّت مع جدول زمني مخصص (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(الافتراضي) للاحتفاظ بجدولك الزمني الحالي. التثبيت النظيف الأول ليس له إدخال موجود ويتجاوز هذا المطالبة. بالنسبة للتثبيتات غير المراقبة، قم بتعيين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`
**"Not time yet. Next update scheduled at..."**
- المحدِّث يحترم جدول الترخيص الخاص بك. تعني هذه الرسالة أن 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
**"Batch nft -f failed. Falling back to per-command execution..."**
- هذا أمر طبيعي، خاصة في حاويات LXC حيث يكون مخزن netlink المؤقت للنواة (`wmem_max`) مقيدًا. يعمل التنفيذ البديل لكل أمر بشكل صحيح وسريع (~10 ثوانٍ لأكثر من 400 ألف عنوان IP).
**خطأ في الصياغة: "unexpected string"**
- تأكد من تشغيل إصدار حديث من nftables. يستخدم البرنامج النصي صياغة `ip saddr`/`ip daddr` التي تتطلب nftables 0.9+.
**"Error: Could not process rule: Message too long"**
- هذا هو حد مخزن netlink المؤقت، عادةً في حاويات LXC. يقوم البرنامج النصي تلقائيًا بالرجوع إلى التنفيذ لكل أمر. إذا رأيت هذا في السجل بجانب تحميل ناجح، فهذا يعمل كما هو مقصود.
### خاص بـ iptables+ipset
**"ipset restore failed"**
- تحقق من تثبيت `ipset`: `command -v ipset`
- تحقق من السجل بحثًا عن أخطاء محددة: `grep -i "error" /var/log/qfeeds_blocklist.log`
- تأكد من تحميل وحدة ipset: `lsmod | grep ip_set`
**قواعد iptables لا تظهر**
- قواعد الحظر موجودة في السلاسل المخصصة `QFEEDS_INPUT` / `QFEEDS_OUTPUT`؛ تحتوي `INPUT`/`OUTPUT` فقط على قفزة `-j QFEEDS_INPUT` موسومة بتعليق `qfeeds`
- تحقق باستخدام: `iptables -L INPUT -n | grep qfeeds` (القفزة) و`iptables -L QFEEDS_INPUT -n` (قواعد الحظر)
- تستخدم قاعدة القفزة `-m comment --comment "qfeeds"` للتعريف
- تأكد من تحميل وحدة `xt_set`: `modprobe xt_set`
**"ipset create ... failed"**
- في النوى القديمة جدًا، قد لا تكون أنواع `hash:ip` أو `hash:net` متاحة. قم بترقية النواة أو تثبيت `ipset` من مستودع أحدث.
---
## 🗑️ إلغاء التثبيت```bash
sudo ./qfeeds-uninstaller.sh
يقوم أداة الإزالة بحذف كل شيء بناءً على الخلفية المكتشفة:
خلفية nftables:
ip qfeeds و ip6 qfeeds (بما في ذلك جميع السلاسل والقواعد والمجموعات)خلفية iptables:
qfeeds (بما في ذلك قواعد القفز)QFEEDS_INPUT / QFEEDS_OUTPUTqfeeds_blacklist_v4, qfeeds_blacklist_v4_nets, qfeeds_whitelist_v4، ومكافئات IPv6)كلا الخلفيتين:
/etc/qfeeds/)/usr/local/bin/update_qfeeds_blocklist.sh)إذا كان ملف الإعدادات مفقودًا، يحاول أداة الإزالة التنظيف لكلا الخلفيتين.
ملاحظة: لا تقوم أداة الإزالة بإزالة حزم النظام (curl, jq, ipset, إلخ) التي تم تثبيتها كتبعيات.
هذا المشروع مرخص بموجب رخصة Apache 2.0 - راجع ملف LICENSE للتفاصيل.
الاستخدام على مسؤوليتك الخاصة.
يرجى اختبار هذه السكريبتات في بيئتك قبل نشرها في الإنتاج. المؤلف غير مسؤول عن أي مشاكل أو أضرار قد تحدث نتيجة استخدامها.
مساعدة الذكاء الاصطناعي: تمت كتابة أجزاء من هذا المشروع (الكود، الإصلاحات، والوثائق) بمساعدة أدوات الذكاء الاصطناعي وتمت مراجعتها لاحقًا من قبل المشرفين. بينما نقوم باختبار ومراجعة التغييرات، يرجى مراجعة السكريبتات بنفسك قبل تشغيلها والإبلاغ عن أي شيء يبدو غير صحيح.
| 1 | وجود الأمر nft | nftables |
| 2 | وجود الأمر iptables | iptables+ipset |
| — | عدم وجود أي منهما | خطأ (خروج) |
| المتغير | الوصف | الافتراضي |
|---|
BACKEND | الخلفية لجدار الحماية (nftables أو iptables) | (يتم الكشف تلقائياً) |
API_TOKEN | رمز API الخاص بـ Q-Feeds | (مطلوب) |
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 | ملف السجل |