لماذا لا ترى قاعدة iptables الخاصة بك حركة VPN المُجسَّرة أبدًا
يمكن للإطارات المُجسَّرة أن تتجاوز سلسلة IP التي تراقبها. قارن عائلة الجسر الأصلية مع br_netfilter القديمة قبل إضافة قاعدة أخرى.
تصل جهازان افتراضيان على المضيف نفسه إلى الشبكة المحلية عبر جسر، ولكن قاعدة موضوعة في سلسلة ip forward تُظهر عدّادًا لا يتحرّك أبدًا. الإطارات حقيقية، والحركة تمرّ، بينما القاعدة ببساطة ليست على مسارها. إن مقارنة الطريقتين التي يعرض بهما Linux حركة الجسر تفسّر هذا الصمت، وتفسّر أيضًا لماذا يكون تحميل وحدة قديمة إجابة أسوأ مما تبدو.
مساران عبر مضيف واحد
يمكن للحزمة أن تغادر هذا المضيف بطريقتين مختلفتين تمامًا، والفرق بينهما يحدّد أيّ الخطّافات تراها. إذا كانت الوجهة وراء منفذ مادي وكان الإطار يُبدَّل بين منفذي جسر، فإن المضيف يمرّر إطار إيثرنت؛ ولا يُرجَع إلى شيفرة التوجيه، ولا تحدث أي قفزة موجّهة. وإذا كانت الوجهة هي المضيف نفسه، أو شبكة تُبلَغ عبر واجهة نفق، فإن الحزمة تُوجَّه وتنطبق عليها خطّافات طبقة IP فعلًا. احتفظ بهذا التفرّع في ذهنك، لأن كل سؤال لاحق عن السلاسل والعائلات يتبع من أيّ المسارين يتخذه الإطار.
هذا التمييز هو القصة كاملة وراء قاعدة لا تعدّ شيئًا. الإطار المُجسَّر من veth9a1 إلى enp3s0 يعبر الجسر، لا مكدّس IP، لذلك لا ترى سلسلة ip forward أي شيء لتطابقه. أسماء الواجهات في مثال أقدم لا تحدّد أيّ المسارين لديك، ولهذا تكون الخطوة الأولى هي النظر إلى الطوبولوجيا لا إلى مجموعة القواعد.
يضيف النفق حالة ثالثة تستحق التسمية. جهاز TUN يسلّم حزم IP إلى المضيف، لذلك تُوجَّه تلك الحزم وتمرّ فعلًا عبر سلاسل IP، أما جهاز TAP الموصول بجسر فيسلّم إطارات ويتصرّف مثل حالة الجسر. نوع الجهاز، لا اسم المنتج، هو الذي يحدّد.
قارن العائلتين اللتين تستطيعان رؤية إطار مُجسَّر
يدعم Linux تصفية الجسر الأصلية عبر عائلة bridge في nftables، وهو لا يحتاج إلى أي وحدة قديمة لفحص الإطارات وإسقاطها أثناء مرورها. وثائق الجسر الخاصة بالنواة تقدّم هذه التوصية مباشرة، وهذا أمر يستحق المعرفة قبل أن يخبرك نتيجة بحث بتحميل وحدة.
| Observation point | What it sees | What it costs |
|---|---|---|
nftables bridge family chains | Ethernet frames forwarded between bridge ports, in both directions | Rules must be written in bridge syntax with link-layer matches |
Legacy br_netfilter plus an ip chain | Bridged IPv4 and IPv6 packets, re-exposed through IP-layer hooks | Existing host rules may begin matching traffic they never saw before |
inet chain for routed traffic | Packets the host routes, including traffic arriving from a TUN device | No visibility into purely switched frames |
استخدام أمر nft بدلًا من iptables لا يضع، بحد ذاته، قاعدة في العائلة الصحيحة. السلسلة المعلنة في عائلة bridge ترى الإطارات؛ أما السلسلة المعلنة في ip أو ip6 أو inet فلا تراها، أيًّا كان الملف التنفيذي الذي أنشأها. العائلة خاصية للسلسلة، لا للأداة التي كتبتها.
المسار القديم يعمل بشكل مختلف، ولهذا السبب ينبغي المقارنة بدلًا من اختيار جانب بحكم العادة. تحميل br_netfilter وتمكين إعدادات bridge-nf-call يعيد عرض حركة IPv4 وIPv6 المُجسَّرة عبر خطّافات طبقة IP، بحيث تستطيع قاعدة iptables عادية مطابقتها أخيرًا. الإطارات لا تتغيّر؛ بل تتغيّر مجموعة الخطّافات التي تعبرها، وهذا يعني أن لكل قاعدة موجودة على المضيف جمهورًا جديدًا الآن.
اقرأ المسار الفعلي قبل إضافة قاعدة
ثلاثة أوامر تحدّد أين أنت: ما الذي يتصل به الجسر، وهل الوحدة القديمة نشطة، وأيّ السلاسل موجودة أصلًا في عائلة bridge. شغّلها قبل كتابة أي شيء، لأن الإجابة تحدّد أيّ التصميمين تمدّده. وتخطّي هذه الخطوة هو كيف تنتهي قاعدة صحيحة في سلسلة لا يعبرها شيء.
bridge link show
lsmod | grep br_netfilter
nft list ruleset | grep -A4 "chain forward"
يفصل الخرج الحالات بوضوح. المنافذ المدرجة تحت الجسر تخبرك أيّ الواجهات تُبدَّل؛ ونتيجة فارغة لـ lsmod تعني انعدام أي رؤية على طبقة IP للإطارات المُجسَّرة؛ وسلسلة forward موجودة في عائلة bridge تعني أن مالك سياسة موجود بالفعل وأن قاعدتك تنتمي إلى هناك لا إلى سلسلة جديدة خاصة بها.
ثم أضف قاعدة واحدة يسهل قراءتها، مع عدّاد ودون تغيير الحكم، وأرسل تدفّقًا تمثيليًا واحدًا عبر الجسر. العدّاد الذي يتحرّك يثبت أن الإطار وصل إلى القاعدة. وهذا كل ما يثبته، لذا تابع مع المسار المرفوض أيضًا، لأن سياسة تقبل كل شيء تنتج عدّادًا متحرّكًا هي أيضًا.
nft add rule bridge filter forward iifname "veth9a1" oifname "enp3s0" counter acceptأين تغيّر الوحدة القديمة السلوك
تمكين المسار القديم على جسر يعمل ليس فعلًا محايدًا لإضافة رؤية. القواعد التي كانت غير قابلة للوصول سابقًا لحركة الجسر تصبح قابلة للوصول، بما في ذلك قواعد المضيف المكتوبة لواجهة أخرى، وقد تنطبق سياسة drop الافتراضية في سلسلة ip forward فجأة على إطارات كانت تمرّ دون أن تُمسّ. على مضيف يُدار عبر ذلك الجسر، تكون النتيجة إغلاقًا بلا طرفية. وهذا ليس وضع فشل نظريًا؛ إنه النتيجة العادية لتوسيع مجموعة خطّافات على جهاز تصل إليه عبر المسار الذي وسّعته للتو.
التسلسل الأكثر أمانًا هو أن تحدّد أي عائلة تملك السياسة، وتكتب القواعد هناك، وتحتفظ بمسار استرجاع مستقل قبل تغيير أي sysctl. وإذا كانت عائلتان تحملان قواعد، فوثّق أيّهما هي المرجع؛ فسياستان متداخلتان هما الطريقة التي تُقبل بها حزمة في مكان وتُسقَط في مكان آخر دون ملف واحد تقرأه.
العزل نفسه لا يزال يحتاج تصميمًا كاملًا. السماح لمصدر واحد بالوصول إلى وجهة واحدة يثبت فقط أن تدفّقًا واحدًا يعمل، بينما المطلوب عادةً أن لا تستطيع آلة افتراضية الوصول إلى جيرانها أو إلى المضيف. العدّادات على قواعد الرفض أهم من العدّاد على قاعدة القبول، لأن عدّاد القبول هو الذي كنت تتوقع أصلًا أن يتحرّك.
أخيرًا، أبقِ حالة إدخال المضيف منفصلة. الحركة الموجّهة إلى عنوان IP الخاص بالجسر تصل إلى input لا إلى forward، ولن تراها قاعدة في forward أبدًا أيًّا كانت العائلة التي تختارها. ثلاث حالات، عائلتان، درس واحد: المسار يحدّد الخطّاف، والخطّاف يحدّد هل توجد قاعدتك أصلًا.