يمكن لمسارين أن يضعا واجهة IP أمام تطبيق Android، وكلاهما ينتهي عند النوع نفسه من واصف الملف مع مالكين مختلفين تمامًا. يمر أحدهما عبر VpnService وبانيها، ويمر الآخر عبر صدفة root و /dev/net/tun. كل قراءة على ذلك الواصف حزمة صادرة، وكل كتابة حزمة واردة. ما يفصل المسارين هو من يملك السياسة، ومن ينجو من ترقية نظام التشغيل، ومقدار جدول التوجيه الذي يُسمح لك بلمسه.

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

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

طريقتان للحصول على واجهة IP

مسار root هو الوصفة الأقدم. تفتح /dev/net/tun، وتستدعي TUNSETIFF مع IFF_TUN، وترفع الواجهة عبر ip link، وتضيف العناوين والمسارات يدويًا. كل خطوة عليك أن تُحسنها، بما فيها ما كان الإطار سيتولاه بصمت. مسار واحد ناقص يعطي المستخدم نفس التقرير الذي يعطيه خادم ميت.

التنقيح يختلف بقدر ما يختلف الإعداد. على مسار root تكون الواجهة موجودة أو أن ioctl أعاد خطأً يمكنك قراءته مباشرة. على مسار المنصة لا توجد الواجهة إلا بعد نجاح establish()، لذا يصل الفشل كاستثناء أو واصف null بدلًا من عقدة جهاز يمكنك العبث بها.

ما يعيده establish() فعليًا

لـ Builder.establish() ثلاث نتائج، وكل نتيجة تحتاج ردًّا مختلفًا. وجود واصف يعني أن الواجهة مهيأة وصارت لك لتستخدمها، وnull يعني أن الطلب لم يمر، والاستثناء المرفوض يعني أن خدمة النظام رفضته. دمج null والنجاح في قيمة منطقية واحدة هو أكثر طريقة شائعة يُبلّغ بها تطبيق عن نفق يعمل لا ينقل أي حزمة قط. ويذكر مرجع Builder شرط العنوان، وهو جدير بالقراءة قبل أن تلوم الخادم.

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

Binder خطوة واحدة، وJNI محور آخر

طلب الباني يعبر إلى النظام عبر Binder، وفي مكان ما تحت ذلك تستدعي المنصة شفرة أصلية لتهيئة الجهاز. هذان ميكانيزمان مختلفان متراكبان داخل نداء واحد. Binder هو تواصل بين العمليات بين تطبيقك وخدمة نظام، بينما JNI هو الجسر من Java إلى الشفرة الأصلية داخل العملية. قراءة شجرة AOSP لنظام Android 9 تجعل المكدس يبدو حرفيًا، ويستحق أن تتذكر أن أسماء الفئات ومسارات الملفات الداخلية تتحرك بين الإصدارات.

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

TUN يحمل IP وTAP يحمل Ethernet

TUN واجهة IP. TAP واجهة Ethernet، وهذا الفرق يحدد ما إذا كان الجسر ممكنًا أصلًا. جهاز TUN لا يملك عنوان MAC ولا ترويسة Ethernet ليعيد توجيهها، لذا لا يستطيع عميل TUN الانضمام إلى جسر layer-2 أياً كانت المسارات.

يمنحك VpnService النسخة الخاصة بـ IP، وهي ما يحتاجه VPN على مستوى التطبيق ويمكنه دعمه دون مكدس Ethernet خام. إن كان تصميمك يتطلب الجسر، فلن يوصلك مسار المنصة إلى هناك، ولن يوصلك مسار root إلا إذا تعاونا النواة وأذونات الجهاز.

حيث لا يزال مسار root يتفوق

ثلاث مهام تدفع الناس بعيدًا عن مسار المنصة. جسر الطبقة 2 يحتاج TAP. التقاط حركة التطبيقات خارج نطاق VPN الخاص بك يحتاج رؤية لا يمنحها الإطار. التوجيه بالسياسة الذي لا يكشفه الباني أبدًا، مثل جدول منفصل لوجهة واحدة، يحتاج قواعد تثبّتها بنفسك.

تأتي التكاليف لاحقًا: محمّل إقلاع مفتوح أو صورة ذات صلاحيات root، وسياسة SELinux تتغير تحتك، وجهاز يتوقف عن السلوك الصحيح بعد تحديث OTA. كما أن الوصفة ذات root لا يمكن شحنها عبر توزيع التطبيقات العادي، لذا تُبقي معظم الفرق عليها كمسار تشخيصي داخلي بدلًا من منتج.

الاختيار بينهما

ابدأ من الواجهة التي تحتاجها، لا من الشيفرة التي لديك. إذا كان الجواب جهاز TUN بمسارات محصورة بالتطبيقات، فمسار المنصة أقصر وينجو من الترقيات. وإذا كان الجواب يتضمن إطارات Ethernet، أو التقاط تطبيقات أخرى، أو قواعد توجيه يرفضها الباني، فأنت في أرض root وعليك أن تضع ميزانية لذلك كتكلفة تشغيلية.

فحص يحسم معظم الجدل: ابنِ مسار المنصة أولًا، وسجّل نتيجة establish() منفصلة عن حالة الجلسة البعيدة، وأكّد حزمة واحدة في كل اتجاه. بعد ذلك فقط قرر إن كانت القدرة الناقصة تبرر مغادرة المسار المدعوم.

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