مقدمة
أعمل كمبرمج في قسم تطوير واختبار أدوات الأمان لمنصات الأجهزة المحمولة التابعة لشركة Security Code. كلف فريق تطوير الأجهزة المحمولة بنقل مكتبة Continent-AP عبر منصة محطة المشتركين ، والتي كانت تعمل بالفعل بنجاح على IOS و Android. كانت المشكلة الرئيسية هي أن Sailfish OS غير موثق جيدًا مثل Android أو IOS ، ولكن بفضل اللاعبين من Open Mobile Platforms الذين شاركوا الوثائق.
VPN api architecture في Sailfish OS
بالنسبة لجميع اتصالات الشبكة في Sailfish OS ، تكون خدمة ConnMan مسؤولة ، وهي:
- مسح شبكات Wi-Fi والشبكات الخلوية والاتصال بها ؛
- مشاركة الاتصال (نقطة اتصال Wi-Fi) ؛
- الترجمة ، وصلات الإخراج إلى وضع الطيران.
- إدارة اتصال VPN.
سأتحدث عن النقطة الأخيرة بمزيد من التفاصيل. يحتوي ConnMan على عدة أنواع من إضافات VPN المحددة مسبقًا. يتم دمج أدوات QML لإنشاء الاتصالات وتكوينها في البرامج الثابتة.
التين. 1 قائمة نظام OS Sailfish OS لتكوين وإدارة اتصالات VPNUI لعميل VPN الخاص بنا عبارة عن حزمة RPM وأثناء التثبيت لا يتم دمجها في إطار نظام VPN في قسم "الإعدادات" ، لكن يبدو أنه تطبيق منفصل. من المحتمل أن يكون هناك مقال منفصل حول تطوير واجهة المستخدم ، وبالتالي فإن القصة التالية ستكون حول تطوير البرنامج المساعد ConnMan في C / C ++.
التين. 2 القارة- AP واجهة المستخدم الرسومية عن طريق البحريتكون VPN-api Sailfish OS من المكونات التالية ، وسوف نعرض على سبيل المثال عميل VPN الخاص بنا:
- ConnMan هي العملية التي تبدأ عند بدء تشغيل Sailfish OS.
- connman-vpnd هي عملية خفية أطلقتها شركة ConnMan وتستخدم لإدارة اتصالات VPN لمقدمي خدمات مختلفين ، وتهيئة واجهة tun وتهيئة التهيئة لها ، وتعيين إعدادات الشبكة (عناوين IP ، والطرق ، وخوادم DNS) المستلمة عبر DBus. في حالتنا ، مزود يسمى القارة.
- إن القارة-proto-plugin.so VPN هي مكتبة تحتوي على إعلان ماكرو للتحميل في وقت التشغيل والوظائف التي يتم استدعاؤها عند استدعاء أساليب واجهة net.connman.vpn.Connection.
- تطبيق الخلفية (الملف الثنائي / usr / sbin / القارة) هو عميل وحدة التحكم للاتصال بالقرص المضغوط (Continent Access Server) ، حيث يتلقى إعدادات الشبكة منه ، ويمررها إلى connman-vpnd.
- ConnMan Task هي عملية لبدء تشغيل وحدة التحكم قيد التشغيل وإيقافها ومراقبتها.
- DBus-api - يمثل connman-vpnd ، أي net.connman.vpn مع الواجهات net.connman.vpn.Manager ، net.connman.vpn.Connection.
التين. 3 تفاعل المكونات فيما بينها في "Continent-AP" SailfishVPN plugin
تمثل جميع المكونات الإضافية لجهات خارجية غير المدرجة في توزيع ConnMan المكتبة ويجب وضعها في / usr / lib / connman / plugins-vpn / عند التثبيت من خلال مدير الحزم.
يمكن أن يكون للمكوّن الإضافي ملف تكوين ، نشير فيه إلى أي مستخدم لتشغيل الملف الثنائي منه ، ويصف حقوقه. يجب أن يكون الملف موجودًا في النظام على طول المسار /etc/connman/vpn-plugin/continent.conf ، ويجب أن يتطابق اسمه مع اسم مزود الخدمة لدينا ، في الحالات الخاصة بنا.
محتويات الملف على سبيل المثال:
[VPN Binary] User = nemo Group = vpn SupplementaryGroups = inet,net_admin
يتم تسجيل المكون الإضافي القارة-proto-plugin.so في ConnMan باستخدام الماكرو CONNMAN_PLUGIN_DEFINE (الاسم والوصف والإصدار و init والخروج) ، في مثالنا ، ستبدو مكالمة الماكرو كما يلي:
CONNMAN_PLUGIN_DEFINE(continent, "continent VPN plugin", CONNMAN_VERSION, CONNMAN_PLUGIN_PRIORITY_DEFAULT, continent_init, continent_exit);
يجب أن تكون وسيطة الاسم (القارة) بدون علامات اقتباس. يتم استدعاء الدالتين ocean_init و contin_exit عندما يتم تحميل البرنامج المساعد وتفريغه ، على سبيل المثال ، عندما يتم استدعاء systemctl restart connman أثناء تثبيت RPM. تحتوي الدالة القارة_الاستدعاء على دالات vpn_register و connman_dbus_get_connection.
vpn_register(name, driver, binary_path)
الاسم - اسم المزود الذي يتم تسجيله ، في حالتنا هو "القارة" ؛
driver - بنية vpn_driver التي تحتوي على مؤشرات إلى وظائف رد الاتصال ، على سبيل المثال ، عند الوصول إلى البرنامج المساعد من خلال DBus ؛
binary_path - المسار إلى الملف الثنائي ، في حالتنا هو "/ usr / sbin / القارة".
تتيح لك وظيفة connman_dbus_get_connection الحصول على اتصال DBus الثابت ، اتصال DBusConnection *.
مطلوب من القاري وظيفة_إلغاء تسجيل المكوّن الإضافي في ConnMan وإغلاق اتصال DBus.
يتم إنشاء مثيل لموفر VPN عندما يستدعي DBus net.connman.vpn.Manager.Create ، يتم إنشاء ملف إعدادات تلقائيًا له في الدليل /var/lib/connman/provider_${Hostasket_{VPN.Domain}. يتم حذف الموفر عن طريق استدعاء net.connman.vpn.Manager.Remove. عند استدعاء طريقة net.connman.vpn.Connection.Connect ، يتم تحميل الإعدادات في موفر vpn_provider * الإنشاء الذي تم إنشاؤه.
أود أيضًا أن أتحدث عن بعض الوظائف في بنية vpn_driver ، بعضها مطلوب للتنفيذ.
اتصال - رد الاتصال ، يسمى عندما يتم استدعاء net.connman.vpn.Connection.Connect مع العنوان المقابل للكائن DBus عبر DBus ، التوقيع:
static int continent_connect( struct vpn_provider *provider, struct connman_task *task, const char *if_name, vpn_provider_connect_cb_t cb, const char *dbus_sender, void *user_data)
الوسيطة الثانية لهذا رد الاتصال هي مهمة connman_task * ، وسوف تقوم بتشغيل الملف الثنائي ، لكنك تحتاج إلى تمرير الوسائط قبل البدء ، على سبيل المثال ، المضيف ومنفذ الخادم:
connman_task_add_argument(task, "--host", value); connman_task_add_argument(task, "--port", value);
نقوم بتخزين بعض المعلمات في ملف التكوين الخاص بمثيل كائن الموفر ، وقد تم وصفه أعلاه ، ونحصل عليه من خلال استدعاء وظيفة vpn_provider_get_string ، على سبيل المثال:
char * value = vpn_provider_get_string(provider , “Host”)
حيث المزود هو مثيل لبنية vpn_provider.
connman_task_add_argument(task, "--dev-name", if_name).
يوضح السطر أعلاه اسم الواجهة الافتراضية التي يهيئها ConnMan-vpnd ويوفر قراءة وكتابة حزم IP من مثيل واجهة TUN المثارة للمثيل الحالي لموفر VPN. في عملية الخلفية ، يبقى لنا فتح الجهاز والحصول على واصف ملف للقراءة / الكتابة.
ملاحظة قصيرة: أثناء تطوير المكوّن الإضافي اتضح أن واجهة TUN يتم رفعها كواجهة توجيه افتراضية.
connman_task_add_argument(task, "--dbus-busname", dbus_bus_get_unique_name(connection)); connman_task_add_argument(task, "--dbus-interface", CONNMAN_TASK_INTERFACE); connman_task_add_argument(task, "--dbus-path", connman_task_get_path(task));
للحصول على تعقيبات بين تطبيق الخلفية والمكون الإضافي لـ VPN ، فإننا نمرر عنوان قاعدة بيانات ConnManTask ومسارها إلى المثيل الحالي ، ولهذا نحتاج إلى الاتصال بـ connman_dbus_get_connection في وظيفة التهيئة.
نبدأ عملية الخلفية:
err = connman_task_run(task, continent_died, data, &data->stdin_fd, NULL, NULL);
contin_died - رد الاتصال يسمى عند إنهاء عملية الخلفية. في ذلك ، اكتشفنا رمز الخطأ لإنهاء العملية ، ونشر الذاكرة ، وحذف الطرق المضافة.
إعلام - رد الاتصال ، يسمى عندما يتم استدعاء net.connman.Task.notify من خلال DBus ، حيث نتلقى رسائل DBus من تطبيق خلفية قيد التشغيل. الشيء الرئيسي هو نقل معلمات الشبكة: عنوان واجهة TUN ، خادم DNS في الشبكة الافتراضية ، إلخ. يتم حزم معلمات الشبكة في DBusMessage في شكل قاموس ويتم نقلها إلى مهمة ConnMan ، حيث يتم إرسال معلمات Dbus عند بدء تشغيل تطبيق الخلفية.
مثال على تهيئة واجهة TUN في وظيفة الإخطار:
struct connman_ipaddress * ipaddress = connman_ipaddress_alloc(AF_INET); connman_ipaddress_set_ipv4(ipaddress, address, netmask, remote_server_ip); connman_ipaddress_set_peer(ipaddress, peer); vpn_provider_set_ipaddress(provider, ipaddress); vpn_provider_set_nameservers(provider, “8.8.8.8”); return VPN_STATE_CONNECT;
نقوم أيضًا بتمرير قيم وسيطة ، على سبيل المثال ، إذا كنا نرغب في إخطار واجهة المستخدم بالحدث عن طريق الكتابة إلى خصائص الاتصال الحالي ، والتي يمكن أن تتعلمها واجهة المستخدم من net.connman.vpn.Connection.GetProperties ، عند تغيير الخصائص ، يرسل ConnMan إشارة DBus PropertyChanged ، على سبيل المثال: vpn_provider_set_string (مزود ، مفتاح ، قيمة).
قطع الاتصال - رد الاتصال الذي يسمى عندما يتم استدعاء net.connman.vpn.Connection.Disconnect عبر قاعدة بيانات
تحدث عملية التوقف عن طريق إرسال إشارة SIGTERM ، إذا لم يحدث انقطاع في غضون 3 ثوانٍ ، يتم إرسال إشارة SIGKILL.
تطوير وتصحيح مكون VPN
يتم تنفيذ تجميع المكون الإضافي Continent-AP VPN ومكوناته على الجهاز الظاهري Sailfish Build Engine OS (Virtual Box) ، وهو جزء من Sailfish SDK. لإنشاء المكون الإضافي ، تحتاج إلى المكتبات: connman-devel و dbus-1 و glibs-2.0 ، والتي نقوم بتثبيتها من خلال تسجيل الدخول عبر ssh:
ssh -p 2222 -i ~/SailfishOS/vmshare/ssh/private_keys/engine/mersdk mersdk@localhost
نستخدم الأداة المساعدة sb2 (Scratchbox 2) - مجموعة أدوات للتجميع المتقاطع. نقوم بتثبيت الحزم اللازمة لمنصات i486 و armv7hl:
sb2 -t SailfishOS-3.0.1.11-i486 -m sdk-install -R zypper -n in cmake patchelf chrpath connman-devel systemd-compat-libs systemd-devel
sb2 -t SailfishOS-3.0.1.11-armv7hl -m sdk-install -R zypper -n in cmake patchelf chrpath connman-devel systemd-compat-libs systemd-devel
هناك حاجة إلى Systemd-compat-libs و systemd-devel للإخراج إلى سجل النظام باستخدام دالة sd_journal_print. نقوم بتثبيت Cmake ، نظرًا لأن مشروعنا يستخدمه ، فهذا يبسط التجميع إلى حد كبير لأنظمة مختلفة.
نبدأ في تجميع مكون VPN الإضافي ومكوناته من خلال sb2 sdk-build:
sb2 -t SailfishOS-3.0.1.11-armv7hl -m sdk-build cmake . && make sb2 -t SailfishOS-3.0.1.11-i486 -m sdk-build cmake . && make
بعد ذلك ، نضع الملفات والمكتبات الثنائية التي تم جمعها في مشروع واجهة المستخدم الخاص بنا ، والذي يحتوي على ملف SPEC لإنشاء حزمة RPM الخاصة بتوزيع Continent-AP Sailfish ، مع ضبط القسم لتركيب ملفاتنا في مجلدات نظام الجهاز في ملف SPEC ، على سبيل المثال:
%files %defattr(-,root,root,-) %{_sbindir}/continent %{_libdir}/connman/plugins-vpn/continent-proto-plugin.so
تم تطوير المكون الإضافي بشكل منفصل عن واجهة المستخدم على المحاكي ، وهو جزء من Sailfish SDK ، وساعد gdbus و journalctl مع الخيار -f في وضع إخراج السجل الثابت كثيرًا كأدوات تصحيح الأخطاء.
على سبيل المثال ، إنشاء مثيل لموفر باستخدام gdbus:
gdbus call --system --dest=net.connman.vpn --object-path / --method net.connman.vpn.Manager.Create "{ 'Type': <'continent'>, … }"
أجهزة الاختبار هي INOI R7 (الهاتف) ، INOI T8 (الكمبيوتر اللوحي) ومحاكي يعتمد على VirtualBox
روابط مفيدة:
- يمكن العثور على كود مصدر ConnMan المتكيف مع سمكة الزعنفة الشراعية هنا .
- هيكل عظمي - مشروع البرنامج المساعد
- sailfishos.org/wiki