VPN

Android menyediakan API bagi developer untuk membuat solusi virtual private network (VPN). Setelah membaca panduan ini, Anda akan mengetahui cara mengembangkan dan menguji klien VPN Anda sendiri untuk perangkat yang didukung Android.

Ringkasan

VPN memungkinkan perangkat yang secara fisik tidak berada di jaringan untuk mengakses jaringan dengan aman.

Android menyertakan klien VPN (PPTP dan L2TP/IPSec) bawaan, yang terkadang disebut VPN lama. Android 4.0 (API Level 14) memperkenalkan API agar developer aplikasi dapat menyediakan solusi VPN mereka sendiri. Anda mengemas solusi VPN ke dalam aplikasi yang diinstal pengguna ke perangkat. Developer biasanya membuat aplikasi VPN karena salah satu alasan berikut:

  • Untuk menawarkan protokol VPN yang tidak didukung oleh klien bawaan.
  • Untuk membantu orang terhubung ke layanan VPN tanpa konfigurasi yang rumit.

Bagian selanjutnya dari panduan ini menjelaskan cara mengembangkan aplikasi VPN (termasuk VPN selalu aktif dan per aplikasi) dan tidak membahas klien VPN bawaan.

Pengalaman pengguna

Android menyediakan antarmuka pengguna (UI) untuk membantu seseorang mengonfigurasi, memulai, dan menghentikan solusi VPN Anda. UI sistem juga membuat orang yang menggunakan perangkat mengetahui koneksi VPN yang aktif. Android menampilkan komponen UI berikut untuk koneksi VPN:

  • Sebelum aplikasi VPN dapat aktif untuk pertama kalinya, sistem akan menampilkan dialog permintaan koneksi. Dialog akan meminta orang yang menggunakan perangkat untuk mengonfirmasi bahwa mereka memercayai VPN dan menerima permintaan.
  • Layar setelan VPN (Setelan > Jaringan & Internet > VPN) menampilkan aplikasi VPN tempat seseorang menerima permintaan koneksi. Ada tombol untuk mengonfigurasi opsi sistem atau melupakan VPN.
  • Baki Setelan Cepat menampilkan panel informasi saat koneksi aktif. Mengetuk label akan menampilkan dialog dengan informasi selengkapnya dan link ke Setelan.
  • Status bar berisi ikon (kunci) VPN, menunjukkan bahwa koneksi sedang aktif.

Aplikasi Anda juga perlu menyediakan UI agar orang yang menggunakan perangkat dapat mengonfigurasi opsi layanan Anda. Misalnya, solusi Anda mungkin perlu mengambil setelan autentikasi akun. Aplikasi akan menampilkan UI berikut:

  • Kontrol untuk memulai dan menghentikan koneksi secara manual. VPN Selalu Aktif dapat terhubung saat diperlukan, tetapi memungkinkan pengguna mengonfigurasi koneksi saat pertama kali menggunakan VPN Anda.
  • Notifikasi yang tidak dapat ditutup saat layanan aktif. Notifikasi dapat menampilkan status koneksi atau memberikan informasi selengkapnya—seperti statistik jaringan. Mengetuk notifikasi akan membawa aplikasi ke latar depan. Hapus notifikasi setelah layanan menjadi tidak aktif.

Layanan VPN

Aplikasi Anda menghubungkan jaringan sistem untuk pengguna (atau profil kerja) ke gateway VPN. Setiap pengguna (atau profil kerja) dapat menjalankan aplikasi VPN yang berbeda. Anda membuat layanan VPN yang digunakan sistem untuk memulai dan menghentikan VPN, serta melacak status koneksi. Layanan VPN Anda diwarisi dari VpnService.

Layanan ini juga berfungsi sebagai container untuk koneksi gateway VPN dan antarmuka perangkat lokalnya. Instance layanan Anda memanggil metode VpnService.Builder untuk membuat antarmuka lokal baru.

Gambar 1. Cara VpnService menghubungkan jaringan Android ke gateway VPN
Diagram arsitektur blok yang menunjukkan cara VpnService membuat antarmuka TUN lokal
         dalam jaringan sistem.

Aplikasi Anda mentransfer data berikut untuk menghubungkan perangkat ke gateway VPN:

  • Membaca paket IP keluar dari deskriptor file antarmuka lokal, mengenkripsinya, dan mengirimkannya ke gateway VPN.
  • Menulis paket masuk (diterima dan didekripsi dari gateway VPN) ke deskriptor file antarmuka lokal.

Hanya ada satu layanan aktif per pengguna atau profil. Memulai layanan baru akan otomatis menghentikan layanan yang ada.

Menambahkan layanan

Untuk menambahkan layanan VPN ke aplikasi Anda, buat layanan Android yang diwarisi dari VpnService. Deklarasikan layanan VPN dalam file manifes aplikasi Anda dengan penambahan berikut:

  • Lindungi layanan dengan izin BIND_VPN_SERVICE sehingga hanya sistem yang dapat mengikat ke layanan Anda.
  • Beritahukan layanan dengan filter intent "android.net.VpnService" agar sistem dapat menemukan layanan Anda.

Contoh ini menunjukkan cara mendeklarasikan layanan di file manifes aplikasi Anda:

<service android:name=".MyVpnService"
         android:permission="android.permission.BIND_VPN_SERVICE">
     <intent-filter>
         <action android:name="android.net.VpnService"/>
     </intent-filter>
</service>

Setelah aplikasi Anda mendeklarasikan layanan, sistem dapat otomatis memulai dan menghentikan layanan VPN aplikasi Anda saat diperlukan. Misalnya, sistem mengontrol layanan Anda saat menjalankan VPN selalu aktif.

Menyiapkan layanan

Untuk menyiapkan aplikasi agar menjadi layanan VPN pengguna saat ini, panggil VpnService.prepare(). Jika orang yang menggunakan perangkat belum memberikan izin untuk aplikasi Anda, metode ini akan menampilkan intent aktivitas. Gunakan intent ini untuk memulai aktivitas sistem yang meminta izin. Sistem akan menampilkan dialog yang mirip dengan dialog izin lainnya, seperti akses kamera atau kontak. Jika aplikasi Anda sudah disiapkan, metode ini akan menampilkan null.

Hanya satu aplikasi yang dapat menjadi layanan VPN yang disiapkan saat ini. Selalu panggil VpnService.prepare() karena seseorang mungkin telah menetapkan aplikasi lain sebagai layanan VPN sejak aplikasi Anda terakhir kali memanggil metode tersebut. Untuk mempelajari lebih lanjut, lihat bagian Siklus proses layanan.

Menghubungkan layanan

Setelah layanan berjalan, Anda dapat membuat antarmuka lokal baru yang terhubung ke gateway VPN. Untuk meminta izin dan menghubungkan layanan Anda ke gateway VPN, Anda harus menyelesaikan langkah-langkah dalam urutan berikut:

  1. Panggil VpnService.prepare() untuk meminta izin (jika diperlukan).
  2. Panggil VpnService.protect() untuk menjaga soket tunnel aplikasi Anda di luar VPN sistem dan menghindari koneksi sirkular.
  3. Panggil DatagramSocket.connect() untuk menghubungkan soket tunnel aplikasi Anda ke gateway VPN.
  4. Panggil metode VpnService.Builder untuk mengonfigurasi antarmuka TUN lokal baru di perangkat untuk traffic VPN.
  5. Panggil VpnService.Builder.establish() agar sistem membuat antarmuka TUN lokal dan mulai merutekan traffic melalui antarmuka.

Gateway VPN biasanya menyarankan setelan untuk antarmuka TUN lokal selama handshake. Aplikasi Anda memanggil metode VpnService.Builder untuk mengonfigurasi layanan seperti yang ditunjukkan dalam contoh berikut:

// Configure a new interface from our VpnService instance. This must be done
// from inside a VpnService.
val builder = Builder()

// Create a local TUN interface using predetermined addresses. In your app,
// you typically use values returned from the VPN gateway during handshaking.
val localTunnel = builder
    .addAddress("192.168.2.2", 24)
    .addRoute("0.0.0.0", 0)
    .addDnsServer("192.168.1.1")
    .establish()

Contoh di bagian VPN per aplikasi menunjukkan konfigurasi IPv6 yang menyertakan lebih banyak opsi. Anda harus menambahkan nilai VpnService.Builder berikut sebelum dapat membuat antarmuka baru:

addAddress()
Tambahkan setidaknya satu alamat IPv4 atau IPv6 beserta subnet mask yang ditetapkan sistem sebagai alamat antarmuka TUN lokal. Aplikasi Anda biasanya menerima alamat IP dan subnet mask dari gateway VPN selama handshake.
addRoute()
Tambahkan setidaknya satu rute jika Anda ingin sistem mengirim traffic melalui antarmuka VPN. Merutekan filter berdasarkan alamat tujuan. Untuk menerima semua traffic, tetapkan rute terbuka seperti 0.0.0.0/0 atau ::/0.

Metode establish() menampilkan instance ParcelFileDescriptor yang digunakan aplikasi Anda untuk membaca dan menulis paket ke dan dari buffer antarmuka. Metode establish() menampilkan null jika aplikasi Anda tidak disiapkan atau seseorang mencabut izin.

Siklus proses layanan

Aplikasi Anda harus melacak status VPN yang dipilih sistem dan koneksi aktif apa pun. Perbarui antarmuka pengguna (UI) aplikasi Anda agar orang yang menggunakan perangkat mengetahui setiap perubahan.

Memulai layanan

Layanan VPN Anda dapat dimulai dengan cara berikut:

  • Aplikasi Anda memulai layanan—biasanya karena pengguna mengetuk tombol sambungkan.
  • Sistem memulai layanan karena VPN selalu aktif diaktifkan.

Aplikasi Anda memulai layanan VPN dengan meneruskan intent ke startService(). Untuk mempelajari lebih lanjut, baca Memulai layanan.

Sistem memulai layanan Anda di latar belakang dengan memanggil onStartCommand(). Namun, Android menerapkan batasan pada aplikasi latar belakang di versi 8.0 (level API 26) atau yang lebih tinggi. Jika Anda mendukung Level API ini, Anda harus mentransisikan layanan ke latar depan dengan memanggil Service.startForeground(). Untuk mempelajari lebih lanjut, baca Menjalankan layanan di latar depan.

Menghentikan layanan

Pengguna perangkat dapat menghentikan layanan Anda dengan menggunakan UI aplikasi Anda. Hentikan layanan, bukan hanya menutup koneksi. Sistem juga menghentikan koneksi aktif saat orang yang menggunakan perangkat melakukan hal berikut di layar VPN aplikasi Setelan:

  • memutus atau melupakan aplikasi VPN
  • menonaktifkan VPN selalu aktif untuk koneksi yang aktif

Sistem akan memanggil metode onRevoke() layanan Anda, tetapi panggilan ini mungkin tidak terjadi di thread utama. Saat sistem memanggil metode ini, antarmuka jaringan alternatif sudah merutekan traffic. Anda dapat membuang resource berikut dengan aman:

VPN selalu aktif

Android dapat memulai layanan VPN saat perangkat melakukan booting dan terus menjalankannya saat perangkat diaktifkan. Fitur ini disebut VPN selalu aktif dan tersedia di Android 7.0 (API Level 24) atau yang lebih tinggi. Meskipun Android mempertahankan siklus proses layanan, layanan VPN Anda bertanggung jawab atas koneksi gateway VPN. VPN selalu aktif juga dapat memblokir koneksi yang tidak menggunakan VPN.

Pengalaman pengguna

Di Android 8.0 atau yang lebih tinggi, sistem menampilkan dialog berikut untuk membuat pengguna perangkat mengetahui VPN selalu aktif:

  • Saat koneksi VPN selalu aktif terputus atau tidak dapat terhubung, pengguna akan melihat notifikasi yang tidak dapat ditutup. Mengetuk notifikasi akan menampilkan dialog yang menjelaskan lebih lanjut. Notifikasi akan hilang saat VPN terhubung kembali atau seseorang menonaktifkan opsi VPN selalu aktif.
  • VPN selalu aktif memungkinkan orang yang menggunakan perangkat untuk memblokir koneksi jaringan apa pun yang tidak menggunakan VPN. Saat mengaktifkan opsi ini, aplikasi Setelan akan memperingatkan pengguna bahwa mereka tidak memiliki koneksi internet sebelum VPN terhubung. Aplikasi Setelan akan meminta pengguna yang menggunakan perangkat untuk melanjutkan atau membatalkan.

Karena sistem (dan bukan orang) memulai dan menghentikan koneksi selalu aktif, Anda perlu menyesuaikan perilaku dan antarmuka pengguna aplikasi:

  1. Nonaktifkan UI apa pun yang memutuskan koneksi karena sistem dan aplikasi Setelan mengontrol koneksi.
  2. Simpan konfigurasi apa pun di antara setiap startup aplikasi dan konfigurasikan koneksi dengan setelan terbaru. Karena sistem memulai aplikasi Anda sesuai permintaan, pengguna perangkat mungkin tidak selalu ingin mengonfigurasi koneksi.

Anda juga dapat menggunakan konfigurasi terkelola untuk mengonfigurasi koneksi. Konfigurasi terkelola membantu admin IT mengonfigurasi VPN dari jarak jauh.

Mendeteksi selalu aktif

Android tidak menyertakan API untuk mengonfirmasi apakah sistem memulai layanan VPN Anda. Namun, saat aplikasi Anda menandai instance layanan apa pun yang dimulai, Anda dapat berasumsi bahwa sistem memulai layanan yang tidak ditandai untuk VPN selalu aktif. Berikut contohnya:

  1. Buat instance Intent untuk memulai layanan VPN.
  2. Tandai layanan VPN dengan menempatkan tambahan ke intent.
  3. Dalam metode onStartCommand() layanan, cari flag di tambahan argumen intent.

Koneksi diblokir

Pengguna perangkat (atau admin IT) dapat memaksa semua traffic untuk menggunakan VPN. Sistem memblokir semua traffic jaringan yang tidak menggunakan VPN. Orang yang menggunakan perangkat dapat menemukan tombol Blokir koneksi tanpa VPN di panel opsi VPN di Setelan.

Menghentikan penggunaan selalu aktif

Jika aplikasi Anda saat ini tidak dapat mendukung VPN selalu aktif, Anda dapat memilih tidak ikut (di Android 8.1 atau yang lebih tinggi) dengan menetapkan metadata layanan SERVICE_META_DATA_SUPPORTS_ALWAYS_ON ke false. Contoh manifes aplikasi berikut menunjukkan cara menambahkan elemen metadata:

<service android:name=".MyVpnService"
         android:permission="android.permission.BIND_VPN_SERVICE">
     <intent-filter>
         <action android:name="android.net.VpnService"/>
     </intent-filter>
     <meta-data android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
             android:value=false/>
</service>

Jika aplikasi Anda memilih tidak ikut VPN selalu aktif, sistem akan menonaktifkan kontrol UI opsi di Setelan.

VPN per aplikasi

Aplikasi VPN dapat memfilter aplikasi terinstal mana yang diizinkan untuk mengirim traffic melalui koneksi VPN. Anda dapat membuat daftar yang diizinkan, atau, daftar yang tidak diizinkan, namun tidak keduanya. Jika Anda tidak membuat daftar yang diizinkan atau tidak diizinkan, sistem akan mengirim semua traffic jaringan melalui VPN.

Aplikasi VPN Anda harus menetapkan daftar sebelum koneksi dibuat. Jika Anda perlu mengubah daftar, buat koneksi VPN baru. Aplikasi harus diinstal di perangkat saat Anda menambahkannya ke daftar.

// The apps that will have access to the VPN.
val appPackages = arrayOf(
    "com.android.chrome",
    "com.google.android.youtube",
    "com.example.a.missing.app"
)

// Loop through the app packages in the array and confirm that the app is
// installed before adding the app to the allowed list.
val builder = Builder()
for (appPackage in appPackages) {
    try {
        packageManager.getPackageInfo(appPackage, 0)
        builder.addAllowedApplication(appPackage)
    } catch (e: PackageManager.NameNotFoundException) {
        // The app isn't installed.
    }
}

// Complete the VPN interface config.
val localTunnel = builder
    .addAddress("2001:db8::1", 64)
    .addRoute("::", 0)
    .establish()

Aplikasi yang diizinkan

Untuk menambahkan aplikasi ke daftar yang diizinkan, panggil VpnService.Builder.addAllowedApplication(). Jika daftar menyertakan satu atau beberapa aplikasi, hanya aplikasi dalam daftar tersebut yang dapat menggunakan VPN. Semua aplikasi lain (yang tidak ada dalam daftar) akan menggunakan jaringan sistem seolah-olah VPN tidak berjalan. Jika daftar yang diizinkan kosong, semua aplikasi dapat menggunakan VPN.

Aplikasi yang tidak diizinkan

Untuk menambahkan aplikasi ke daftar yang tidak diizinkan, panggil VpnService.Builder.addDisallowedApplication(). Aplikasi yang tidak diizinkan akan menggunakan jaringan sistem seakan-akan VPN tidak berjalan—semua aplikasi lainnya menggunakan VPN.

Mem-bypass VPN

VPN dapat mengizinkan aplikasi untuk mem-bypass VPN dan memilih jaringannya sendiri. Untuk mengabaikan VPN, panggil VpnService.Builder.allowBypass() saat membuat antarmuka VPN. Anda tidak dapat mengubah nilai ini setelah memulai layanan VPN. Jika aplikasi tidak mengikat proses atau soketnya ke jaringan tertentu, traffic jaringan aplikasi akan terus melalui VPN.

Aplikasi yang terikat ke jaringan tertentu tidak memiliki koneksi saat seseorang memblokir traffic yang tidak melalui VPN. Untuk mengirim traffic melalui jaringan tertentu, aplikasi memanggil metode, seperti ConnectivityManager.bindProcessToNetwork() atau Network.bindSocket() sebelum menghubungkan soket.

Kode contoh

Proyek Open Source Android mencakup aplikasi contoh yang disebut ToyVPN. Aplikasi ini menunjukkan cara menyiapkan dan menghubungkan layanan VPN.