ثلاثة مضيفات Linux وتصميم واحد: محور OpenVPN متاح علنًا، وحاسوب محمول للمستهلك، وجهاز مخرج خلف موجه منزلي عادي لا يمرّر أي شيء وارد. المخرج يتصل بالمحور بنفسه. ثم تدخل حركة إنترنت المستهلك النفق عند الحاسوب المحمول وتخرج عبر وصلة المخرج الصاعدة. كل ما يثير الدهشة في هذا الإعداد ينبع من تفصيل واحد: المخرج هو من بدأ الاتصال، لذا فإن المسار إلى الداخل موجود أصلًا ولا حاجة إلى تمرير منفذ لإنشائه.

ما يلي يتتبّع مسار الحزمة لا ترتيب الإعداد، لأن الإعداد لا يصبح منطقيًا إلا حين تعرف أي مكوّن يملك أي قرار. كل طبقة تملك قرارًا واحدًا بالضبط، والأخطاء تتجمّع حيث يُفترض أن طبقتين طبقة واحدة.

جلستان للنقل ومسار داخلي واحد

كل مضيف يحتفظ باتصاله الخارجي الخاص به إلى المحور، ولا يعرف أي من هذين الاتصالين شيئًا عن الآخر. حركة المستهلك إلى الإنترنت تدفق داخلي منفصل يُحمل داخل نفق المستهلك ثم يُعاد بثه من نفق المخرج. هذا التدفق الداخلي هو ما يجب على المحور توجيهه، وهو ما يجب على المخرج تمريره.

outer: consumer --TLS--> hub
outer: exit     --TLS--> hub
inner: consumer --tun--> hub --internal--> exit --tun--> uplink

لأن كلا الاتصالين الخارجيين صادر من جهة العميل، لا يرى موجه المخرج أبدًا حزمة SYN واردة ولا يحتاج أبدًا إلى قاعدة NAT للوجهة. عليه فقط إبقاء النقل القائم حيًا، وهو ما يفعله أصلًا مع أي اتصال طويل الأمد. لا شيء على الإنترنت العام يحتاج إلى الوصول إلى المخرج أولًا، ولهذا فإن العنوان الديناميكي على تلك الوصلة الصاعدة ليس مشكلة. لا يزال على الموجه السماح بالجلسة الصادرة، لكن هذا هو الإذن نفسه الذي يستخدمه المتصفح بالفعل.

ما الذي يثبّته iroute فعليًا داخل الخادم

المحور هو الجهاز الوحيد الذي يقرّر أي نظير يملك أي وجهة، وهو يتخذ ذلك القرار في جدول التوجيه الخاص بمساحة المستخدم لديه، لا في جدول النواة. يمكن لمدخل client-config-dir الخاص بالمخرج باسم exit-node أن يطالب بالبادئة الافتراضية هناك:

# /etc/openvpn/server/ccd/exit-node
iroute 0.0.0.0 0.0.0.0

هذا السطر يخبر عملية الخادم بأن "الحزم الداخلية بأي وجهة تنتمي إلى هذا العميل". وهو لا يضيف مسارًا افتراضيًا إلى نظام تشغيل المحور، ولا يجعل المحور بوابة إنترنت. مرجع OpenVPN 2.6 يحتفظ بالتوجيه الداخلي الخاص بالعميل والتوجيه في النواة كآليتين منفصلتين، وهذا الفصل هو سبب نجاح هذا التصميم دون لمس المسار الافتراضي للمحور.

يحتاج المستهلك إلى التعليمة المعاكسة، تُسلَّم كدفعة push، كي تدخل حركته الخاصة النفق بدلًا من الخروج عبر بوابته المحلية. مع طوبولوجيا الشبكة الفرعية يكون المجمّع مسارًا متصلًا على جهاز tun الخاص بالمخرج، لذا لا يحتاج اتجاه العودة إلى push إضافي؛ وما يجب ألا يتلقاه المخرج هو إعادة التوجيه أدناه، والتي ستعيد حركة وصلته الصاعدة إلى النفق الذي يحاول استخدامه. أرسلها إلى المستهلك فقط، واقرأ المسارات المطبّقة على العميل بدلًا من الوثوق بأن ملف CCD قد اختير.

# /etc/openvpn/server/ccd/consumer-01
push "redirect-gateway def1"

نواة المخرج هي التي تنفّذ التمرير

داخل المخرج، تصل حزمة من المستهلك على واجهة tun موجّهة إلى مضيف إنترنت ما. تستشير النواة جدول توجيهها، فتجد الوصلة الصاعدة الحقيقية كأفضل تطابق، ثم تطبّق سياستين مستقلتين: هل يجوز تمرير هذه الحزمة أصلًا، وهل يجوز أن تخرج عبر تلك الواجهة بذلك العنوان المصدر. التمرير هو sysctl، وهو معطّل افتراضيًا في توزيعات كثيرة.

لذا يحتاج المخرج إلى تمكين تمرير IPv4 بشكل دائم، وإلى قاعدة تمرير تقبل مصادر نفق المستهلك نحو الوصلة الصاعدة، وإلى مسار الرد عائدًا عبر tun. وتمكين التمرير للمضيف كله يغيّر أيضًا سلوك أي شيء آخر يوجّه عبره، ولهذا ينبغي للقاعدة أن تسمّي المصادر والواجهات بدلًا من قبول كل شيء.

ترجمة المصدر هي ما يشتري مسار العودة

لا يملك مضيف إنترنت أي مسار إلى عنوان 10.90.0.x، لذا ستُسقط الردود قبل أن تصل إلى المخرج أصلًا. إعادة كتابة المصدر أثناء خروج الحزمة من الوصلة الصاعدة تحل ذلك، ويعكس تتبّع الاتصالات إعادة الكتابة في طريق العودة.

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 10.90.0.0/24 -o enp1s0 -j MASQUERADE
ip -4 route get 10.90.0.9   # run on the exit: must point at the tun

القاعدة أعلاه نقطة بداية لواجهة صاعدة واحدة، وليست سياسة جدار حماية. ضيّق المصدر إلى التعيينات التي أذنت بها فعلًا، وأبقِ سياسة الإدخال الخاصة بالمخرج منفصلة كي لا يكشف التمويه masquerade لحركة النفق خدمات محلية بهدوء. وعلى مضيف ذي عنوان وصلة صاعدة ديناميكي، يعفيك masquerade أيضًا من تتبّع العنوان يدويًا.

أين يستطيع المحور أن يفرض وأين لا يستطيع

مع client-to-client ومسار البيانات التقليدي في مساحة المستخدم، يمرّر المحور الحزم الداخلية بين النظائر داخل عملية الخادم. وهي لا تعبر أبدًا سلسلة FORWARD في نواة المحور، لذا لا يمكن لقاعدة في النواة أن تقيّد المرور بين النظائر، مهما كُتبت بعناية. يجب أن يعيش الفرض في سياسة الخادم نفسه: من يُسمح له بالاتصال، وأي ملف CCD يحصل عليه، وهل تُمنح ملكية المخرج الافتراضية أصلًا.

ولهذا أيضًا فإن iroute الافتراضي قرار ثقة واسع. على المخرج أن يقبل شرعًا حركة عائدة من عناوين إنترنت عشوائية، وعليه أن يكون جهازًا تتحكم فيه وتُحدّثه وتراقبه. ومنح الملكية نفسها إلى نظير لا تسلّمه موجهًا هو الخطأ الذي يدعو إليه هذا التصميم.

العضوية هي الضابط الحقيقي. أي عميل يستطيع ضبط مساراته الخاصة يمكنه أن يحاول استخدام المخرج، لذا فإن تقييد من يجوز له الاتصال، أو أي النظائر سيخدمها المخرج، جزء من التصميم لا فكرة لاحقة.

الفشل الآمن عندما يختفي المخرج

أوقف المخرج عن العمل فتختفي الملكية الافتراضية الداخلية مع جلسته. ما يجب ألا يحدث هو أن يصبح المحور بهدوء المخرج البديل: لا مسار افتراضي من مجمّع VPN إلى وصلة المحور الصاعدة، ولا قاعدة masquerade واسعة على المحور تمرّر بسرور الحركة نفسها. اختبر ذلك الفشل عمدًا، ثم اختبر الاستعادة بتدفق جديد لا بصفحة كانت مفتوحة بالفعل.

# on the consumer, with the exit up and then down
ip -4 route get 1.1.1.1
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com

إذا كانت حركة المستهلك لا تزال تصل إلى الإنترنت بعد اختفاء المخرج، فشيء آخر يحملها والحد الذي قصدته غير موجود. تعامل مع DNS وIPv6 كقرارين منفصلين كذلك: مسار IPv4 مع masquerade لا يقول شيئًا عن حركة AAAA، والمحلّل الذي يدفعه المحور سيجيب من حيث يخرج الاستعلام فعلًا.

مقالات ذات صلة