Pendahuluan
Saya bekerja sebagai programmer di departemen pengembangan dan pengujian alat keamanan untuk platform seluler perusahaan Kode Keamanan. Tim pengembangan ponsel ditugaskan untuk mem-porting perpustakaan lintas-platform Continent-AP dari stasiun pelanggan, yang sudah berhasil beroperasi di iOS dan Android. Masalah utama adalah bahwa OS Sailfish tidak didokumentasikan dengan baik seperti Android atau iOS, tetapi berkat orang-orang dari Open Mobile Platforms yang berbagi dokumentasi.
Arsitektur VPN api di Sailfish OS
Untuk semua koneksi jaringan di OS Sailfish, layanan ConnMan bertanggung jawab, yaitu:
- Pindai jaringan Wi-Fi dan jaringan seluler dan sambungkan ke sana;
- koneksi berbagi (hotspot Wi-Fi);
- terjemahan, koneksi keluaran ke mode penerbangan;
- Manajemen koneksi VPN.
Saya akan berbicara tentang poin terakhir secara lebih rinci. ConnMan memiliki beberapa jenis plugin VPN yang telah ditentukan sebelumnya. Widget QML untuk membuat dan mengonfigurasi koneksi terintegrasi ke dalam firmware.
Fig. 1 Menu Sistem OS Sailfish untuk Mengonfigurasi dan Mengelola Koneksi VPNUI klien VPN kami adalah paket RPM dan selama instalasi tidak terintegrasi ke dalam jendela sistem VPN di bagian Pengaturan, tetapi terlihat seperti aplikasi terpisah. Mungkin akan ada artikel terpisah tentang pengembangan UI, jadi cerita selanjutnya adalah tentang pengembangan plug-in ConnMan di C / C ++.
Fig. 2 Continent-AP GUI oleh SailfishVPN-api Sailfish OS terdiri dari komponen-komponen berikut, kami akan tunjukkan dengan contoh klien VPN kami:
- ConnMan adalah proses yang dimulai ketika OS Sailfish dimulai.
- connman-vpnd adalah proses daemon yang diluncurkan oleh ConnMan dan digunakan untuk mengelola koneksi VPN dari berbagai penyedia, menginisialisasi dan de-inisialisasi antarmuka tun, menetapkan pengaturan jaringan (alamat IP, rute, server DNS) yang diterima melalui DBus. Dalam kasus kami, penyedia bernama benua.
- Plugin VPN benua-proto-plugin.so adalah pustaka yang memiliki deklarasi makro untuk memuat ke dalam runtime dan fungsi-fungsi yang dipanggil ketika metode antarmuka net.connman.vpn.Connection dipanggil.
- Aplikasi latar belakang (file biner / usr / sbin / benua) adalah klien konsol untuk menghubungkan ke CD (Continent Access Server), menerima pengaturan jaringan darinya, yang diteruskan ke connman-vpnd.
- Tugas ConnMan adalah proses untuk memulai, menghentikan, dan memantau klien konsol yang sedang berjalan.
- DBus-api - mewakili connman-vpnd, yaitu net.connman.vpn dengan antarmuka net.connman.vpn.Manager, net.connman.vpn.Connection.
Fig. 3 Interaksi komponen di antara mereka sendiri dalam "Continent-AP" SailfishPlugin VPN
Semua plugin pihak ketiga yang bukan bagian dari distribusi ConnMan mewakili perpustakaan dan harus ditempatkan di / usr / lib / connman / plugins-vpn / ketika menginstal melalui manajer paket.
Plugin mungkin memiliki file konfigurasi, di mana kami menunjukkan pengguna mana untuk menjalankan file biner, dan menentukan haknya. File tersebut harus terletak di sistem di sepanjang path /etc/connman/vpn-plugin/continent.conf, dan namanya harus sesuai dengan nama penyedia kami, dalam kasus kami, benua.conf.
Konten file misalnya:
[VPN Binary] User = nemo Group = vpn SupplementaryGroups = inet,net_admin
Plugin benua-proto-plugin.so di ConnMan terdaftar menggunakan CONNMAN_PLUGIN_DEFINE makro (nama, deskripsi, versi, init, keluar), dalam contoh kami, panggilan makro akan terlihat seperti ini:
CONNMAN_PLUGIN_DEFINE(continent, "continent VPN plugin", CONNMAN_VERSION, CONNMAN_PLUGIN_PRIORITY_DEFAULT, continent_init, continent_exit);
Argumen nama (benua) harus tanpa tanda kutip. Fungsi continental_init, continental_exit dipanggil ketika plugin dimuat dan dibongkar, misalnya, ketika systemctl restart connman dipanggil selama instalasi RPM. Fungsi continental_init memiliki panggilan ke fungsi vpn_register dan connman_dbus_get_connection.
vpn_register(name, driver, binary_path)
nama - nama penyedia terdaftar, dalam kasus kami itu adalah "benua";
driver - struct struktur vpn_driver yang berisi pointer ke fungsi callback, misalnya, ketika mengakses plugin melalui DBus;
binary_path - path ke file biner, dalam kasus kami ini adalah "/ usr / sbin / benua".
Fungsi connman_dbus_get_connection memungkinkan Anda untuk mendapatkan koneksi DBus yang mapan, koneksi DBusConnection *.
Fungsi continental_exit diperlukan untuk membatalkan registrasi plugin di ConnMan dan menutup koneksi DBus.
Contoh penyedia VPN dibuat ketika DBus memanggil metode net.connman.vpn.Manager.Create, file pengaturan secara otomatis dibuat untuk itu di /var/lib/connman/provider_${Hostasket_{VPN.Domain} direktori. Penyedia dihapus dengan memanggil net.connman.vpn.Manager.Remove. Ketika metode net.connman.vpn.Connection.Connect dipanggil, pengaturan dimuat ke penyedia vpn_provider * struct yang dibuat.
Saya juga ingin berbicara tentang beberapa fungsi dalam struct vpn_driver, beberapa di antaranya diperlukan untuk implementasi.
connect - callback, dipanggil ketika net.connman.vpn.Connection.Connect dipanggil dengan alamat yang sesuai dari objek DBus melalui DBus, memiliki tanda tangan:
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)
Argumen kedua untuk panggilan balik ini adalah tugas struct connman_task *, itu akan menjalankan file biner, tetapi Anda harus meneruskan argumen sebelum memulai, misalnya, host server dan port:
connman_task_add_argument(task, "--host", value); connman_task_add_argument(task, "--port", value);
Kami menyimpan beberapa parameter dalam file konfigurasi instance objek penyedia, dijelaskan di atas, dan kami mendapatkannya dengan memanggil fungsi vpn_provider_get_string, misalnya:
char * value = vpn_provider_get_string(provider , βHostβ)
di mana provider adalah turunan dari struct vpn_provider.
connman_task_add_argument(task, "--dev-name", if_name).
Baris di atas menggambarkan nama antarmuka virtual yang diinisialisasi dan disediakan oleh ConnMan-vpnd untuk membaca dan menulis paket IP dari instance antarmuka TUN yang dinaikkan untuk instance penyedia VPN saat ini. Dalam proses latar belakang, tetap bagi kami untuk membuka perangkat dan mendapatkan deskriptor file untuk membaca / menulis.
Catatan singkat: selama pengembangan plugin ternyata antarmuka TUN dinaikkan sebagai antarmuka rute default.
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));
Untuk umpan balik antara aplikasi latar belakang dan plugin VPN, kami meneruskan alamat dan jalur ConnManTask DBus ke instance saat ini, untuk ini kami perlu memanggil connman_dbus_get_connection dalam fungsi inisialisasi.
Kami memulai proses latar belakang:
err = connman_task_run(task, continent_died, data, &data->stdin_fd, NULL, NULL);
continental_died - panggilan balik dipanggil saat proses latar belakang berakhir. Di dalamnya, kami menemukan kode kesalahan untuk menghentikan proses, menyebarkan memori, menghapus rute yang ditambahkan.
notify - callback, dipanggil saat net.connman.Task.notify dipanggil melalui DBus, di dalamnya kami menerima pesan DBus dari aplikasi latar belakang yang berjalan. Yang utama adalah transmisi parameter jaringan: alamat antarmuka TUN, server DNS di jaringan virtual, dll. Parameter jaringan dikemas dalam DBusMessage dalam bentuk kamus dan ditransfer ke Tugas ConnMan, di mana parameter Dbus dikirim ketika aplikasi latar belakang diluncurkan.
Contoh menginisialisasi antarmuka TUN dalam fungsi notify:
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;
Kami juga memberikan nilai menengah, misalnya, jika kami ingin memberi tahu UI acara dengan menulis ke properti koneksi saat ini, yang dapat dipelajari oleh UI dari net.connman.vpn.Connection.GetProperties method, saat mengubah Properti, ConnMan mengirimkan sinyal DBus PropertyChanged, misalnya: vpn_provider_set_string (penyedia, kunci, nilai).
disconnect - callback yang dipanggil saat net.connman.vpn.Connection.Disconnect dipanggil melalui DBus
Proses penghentian terjadi dengan mengirimkan sinyal SIGTERM, jika tidak ada pemutusan yang terjadi dalam 3 detik, sinyal SIGKILL dikirim.
Mengembangkan dan men-debug plugin VPN
Perakitan plug-in Continent-AP VPN dan komponennya dilakukan pada mesin virtual Sailfish Build Engine OS (Virtual Box), yang merupakan bagian dari Sailfish SDK. Untuk membangun plugin, Anda memerlukan pustaka: connman-devel, dbus-1, glibs-2.0, yang kami instal dengan masuk melalui ssh:
ssh -p 2222 -i ~/SailfishOS/vmshare/ssh/private_keys/engine/mersdk mersdk@localhost
Kami menggunakan utilitas sb2 (Scratchbox 2) - toolkit untuk lintas-kompilasi. Kami menginstal paket yang diperlukan untuk platform i486 dan 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 dan systemd-devel diperlukan untuk output ke log sistem menggunakan fungsi sd_journal_print. Kami memasang Cmake, karena proyek kami menggunakannya, ini sangat menyederhanakan perakitan untuk platform yang berbeda.
Kami memulai perakitan plugin VPN dan komponennya melalui 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
Selanjutnya, kami menempatkan file biner yang dikumpulkan dan pustaka ke dalam proyek UI kami, yang berisi file SPEC untuk menghasilkan paket RPM distribusi ikan layar Continent-AP, sedikit menyesuaikan bagian untuk menginstal file kami di folder sistem perangkat dalam file SPEC, misalnya:
%files %defattr(-,root,root,-) %{_sbindir}/continent %{_libdir}/connman/plugins-vpn/continent-proto-plugin.so
Plug-in dikembangkan secara terpisah dari UI pada emulator, yang merupakan bagian dari Sailfish SDK, dan gdbus dan journalctl dengan opsi -f dalam mode log output konstan banyak membantu sebagai alat debugging.
Misalnya, membuat instance penyedia menggunakan gdbus:
gdbus call --system --dest=net.connman.vpn --object-path / --method net.connman.vpn.Manager.Create "{ 'Type': <'continent'>, β¦ }"
Perangkat uji adalah INOI R7 (telepon), INOI T8 (tablet) dan emulator berbasis VirtualBox
Tautan yang bermanfaat:
- Kode sumber ConnMan yang disesuaikan untuk Sailfish dapat ditemukan di sini .
- Skeleton - proyek plugin
- sailfishos.org/wiki