VPN

Android menyediakan API untuk developer guna membuat solusi jaringan pribadi maya (VPN). Setelah mempelajari panduan ini, Anda akan mengetahui cara mengembangkan dan menguji klien VPN Anda sendiri untuk perangkat Android.

Ringkasan

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

Android menyertakan klien VPN bawaan (PPTP dan L2TP/IPSec), yang terkadang disebut VPN lama. Android 4.0 (API Level 14) memperkenalkan API sehingga developer aplikasi dapat memberikan solusi VPN-nya sendiri. Kemas solusi VPN Anda ke aplikasi yang diinstal orang ke perangkatnya. Developer biasanya membuat aplikasi VPN karena salah satu alasan berikut:

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

Bagian lain panduan ini menjelaskan cara mengembangkan aplikasi VPN (termasuk VPN selalu aktif dan per aplikasi) dan tidak mencakup klien VPN bawaan.

Pengalaman pengguna

Android menyediakan antarmuka pengguna (UI) untuk membantu pengguna mengonfigurasi, memulai, dan menghentikan solusi VPN Anda. UI sistem juga membantu pengguna 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 meminta pengguna perangkat untuk mengonfirmasi bahwa mereka memercayai VPN dan menerima permintaan tersebut.
  • Layar setelan VPN (Setelan > Jaringan & Internet > VPN) menampilkan aplikasi VPN yang permintaan koneksinya diterima oleh pengguna. Terdapat tombol untuk mengonfigurasi opsi sistem atau melupakan VPN.
  • Antarmuka Setelan Cepat menampilkan panel informasi saat koneksi aktif. Saat label diketuk, dialog berisi informasi selengkapnya dan link ke Setelan akan muncul.
  • Status bar berisi ikon (kunci) VPN, menunjukkan bahwa koneksi sedang aktif.

Aplikasi Anda juga harus menyediakan UI sehingga pengguna perangkat dapat mengonfigurasi opsi layanan Anda. Misalnya, solusi Anda mungkin perlu mencatat setelan autentikasi akun. Aplikasi akan menampilkan UI berikut:

  • Kontrol untuk memulai dan menghentikan koneksi secara manual. VPN selalu aktif dapat disambungkan saat diperlukan, tetapi izinkan pengguna untuk mengonfigurasi koneksi saat pertama kali mereka menggunakan VPN Anda.
  • Notifikasi yang tidak dapat ditutup saat layanan aktif. Notifikasi dapat menampilkan status koneksi atau memberikan informasi lainnya, seperti statistik jaringan. Mengetuk notifikasi akan membawa aplikasi ke latar depan. Hapus notifikasi setelah layanan dinonaktifkan.

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 perlu membuat layanan VPN yang digunakan sistem untuk memulai dan menghentikan VPN, dan melacak status koneksinya. Layanan VPN Anda menerima koneksi 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 yang baru.

Gambar 1. Cara VpnService menghubungkan jaringan Android ke gateway VPN
Diagram blok-arsitektur 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, lalu mengirimnya 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, menghentikan layanan yang ada secara otomatis.

Menambahkan layanan

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

  • Lindungi layanan dengan izin BIND_VPN_SERVICE, sehingga hanya sistem yang dapat terikat ke layanan Anda.
  • Beri tahu layanan dengan filter intent "android.net.VpnService", sehingga 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 secara 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 untuk menjadi layanan VPN pengguna saat ini, panggil VpnService.prepare(). Jika pengguna perangkat belum memberikan izin untuk aplikasi Anda, metode tersebut akan menampilkan intent aktivitas. Gunakan intent ini untuk memulai aktivitas sistem yang meminta izin. Sistem menampilkan dialog yang sama dengan dialog izin lainnya, seperti akses kamera atau kontak. Jika aplikasi Anda sudah siap, metode 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 yang berbeda sebagai layanan VPN, karena aplikasi Anda memanggil metode tersebut di akhir. Untuk mempelajari lebih lanjut, lihat bagian Siklus proses layanan.

Menghubungkan layanan

Saat layanan berjalan, buat 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 membuat soket tunnel aplikasi Anda tetap 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 handshaking. Aplikasi Anda memanggil metode VpnService.Builder untuk mengonfigurasi layanan seperti yang ditunjukkan dalam contoh berikut:

Kotlin

// 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()

Java

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

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

Contoh pada bagian VPN Per-aplikasi menunjukkan konfigurasi IPv6 yang menyertakan opsi lainnya. Anda harus menambahkan nilai VpnService.Builder berikut sebelum 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 handshaking.
addRoute()
Tambahkan setidaknya satu rute jika Anda ingin sistem mengirimkan 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 belum siap atau seseorang mencabut izinnya.

Siklus proses layanan

Aplikasi Anda harus melacak status VPN yang dipilih sistem dan semua koneksi yang aktif. Update antarmuka pengguna (UI) aplikasi Anda agar pengguna perangkat mengetahui semua perubahan yang terjadi.

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 memberlakukan pembatasan pada aplikasi latar belakang dalam versi 8.0 (API Level 26) atau yang lebih tinggi. Jika Anda mendukung Level API ini, Anda harus memindah 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. Menghentikan layanan, bukan sekadar memutus koneksi. Sistem juga memutuskan koneksi yang aktif saat pengguna perangkat melakukan hal berikut di layar VPN pada aplikasi Setelan:

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

Sistem memanggil metode onRevoke() layanan Anda, tetapi panggilan ini mungkin tidak dilakukan pada thread utama. Saat sistem memanggil metode ini, antarmuka jaringan alternatif telah merutekan traffic. Anda dapat menghapus resource berikut dengan aman:

VPN selalu aktif

Android dapat memulai layanan VPN saat perangkat melakukan booting dan terus menjalankannya saat perangkat aktif. Fitur ini disebut VPN selalu aktif dan tersedia di Android 7.0 (level API 24) atau yang lebih tinggi. Meskipun Android mengelola siklus proses layanan, layanan VPN Anda-lah yang 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:

  • Jika koneksi VPN selalu aktif terputus atau tidak dapat tersambung, pengguna akan melihat notifikasi yang tidak dapat ditutup. Mengetuk notifikasi akan menampilkan dialog yang memberi penjelasan lebih lanjut. Notifikasi akan hilang saat VPN tersambung kembali atau pengguna menonaktifkan opsi VPN selalu aktif.
  • VPN selalu aktif memungkinkan pengguna perangkat memblokir semua koneksi jaringan yang tidak menggunakan VPN. Jika opsi ini diaktifkan, aplikasi Setelan akan memperingatkan pengguna bahwa mereka tidak memiliki koneksi internet sebelum VPN tersambung. Aplikasi Setelan akan meminta pengguna perangkat untuk melanjutkan atau membatalkan.

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

  1. Nonaktifkan UI yang memutuskan koneksi karena sistem dan aplikasi Setelan yang mengontrol koneksi.
  2. Simpan semua konfigurasi antara setiap aplikasi yang memulai dan mengonfigurasi koneksi dengan setelan terbaru. Karena sistem memulai aplikasi 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 menandai instance layanan apa pun yang dimulai, Anda dapat menganggap 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 dalam 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. Pengguna perangkat dapat menemukan tombol Blokir koneksi tanpa VPN di panel opsi VPN di Setelan.

Menghentikan penggunaan selalu aktif

Jika saat ini aplikasi tidak mendukung VPN selalu aktif, Anda dapat berhenti menggunakannya (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>
    

Saat aplikasi Anda berhenti menggunakan VPN selalu aktif, sistem akan menonaktifkan opsi kontrol UI di Setelan.

VPN per-aplikasi

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

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

Kotlin

// 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()

Java

// The apps that will have access to the VPN.
    String[] appPackages = {
        "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.
    VpnService.Builder builder = new VpnService.Builder();
    PackageManager packageManager = getPackageManager();
    for (String appPackage: appPackages) {
      try {
        packageManager.getPackageInfo(appPackage, 0);
        builder.addAllowedApplication(appPackage);
      } catch (PackageManager.NameNotFoundException e) {
        // The app isn't installed.
      }
    }

    // Complete the VPN interface config.
    ParcelFileDescriptor 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 mencakup satu atau beberapa aplikasi, hanya aplikasi dalam daftar yang dapat menggunakan VPN. Semua aplikasi lain (yang tidak ada dalam daftar) 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 seolah-olah VPN tidak berjalan—semua aplikasi lain dapat menggunakan VPN.

Mem-bypass VPN

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

Aplikasi yang terikat ke jaringan tertentu tidak memiliki koneksi saat pengguna 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.