[Android開發思路]打造你的VPN app:Android VpnManager開發思路心得

前言

在這篇文章中,
我們將分享開發自己研究的Android VPN 應用的思路,
不論您是新手還是有經驗的開發者,
這些筆記都將提供實用的指引,
希望能對您有所幫助。

前期可以考慮的問題
思考要怎麼實作,所以先研究了原生有哪些VPN加密連線方式
  • 這邊看了原生Android AOSP source code內有的VPN連線加密方式:
    • PPTP
    • L2TP/IPSec PSK
    • IPSec Xauth Psk
    • IPSec IKEv2 PSK
    • L2TP/IPSec RSA
    • IPSec Xauth RSA
    • IPSec 混合 RSA
    • IPSec IKEv2 RSA
若是有個需求為,要實作VPN連線加密模式功能,則:
  • 官方原生提供的方法有:VpnManager、 VpnService 我研究後發現:
    • 如果用VpnManager ,僅提供部分Vpn連線模式,且高版本(api 30上)才有提供
    • 如果用VpnService ,僅提供基本的一些設定,無開放連線模式的接口給上層使用
  • VpnManager,需api 30才能使用,且只有開放部分protocol
    • 另外有看到google issue tracker的網站中,
      有其他開發者有類似問題,並詢問官方是否能開放下層的連線模式給上層使用,
      官方人員回覆 後續有望開放:點此查看
      表示也有其他人有類似需求,但目前官方暫無開發
  • 之前提到官方只支援部分加密方式,其他的就得靠自己實作或串接第三方的lib啦!
    這張圖列出了官方支援的三種加密方式:IPSec IKEv2 PSK、IPSec IKEv2 RSA、IPSec User Pass。
    vpn_limit.png
VPN實作的思路參考
  • 若使用官方提供的方法來實作,可以:
    • '連接類型':透過VpnManager (API level 30以上)的provisionVpnProfile方法設定PlatformVpnProfile
      • 官方定義一個新的類別 PlatformVpnProfile
        • 若搭配AOSP看的話,官方是提供這個類讓你設定部分連線procotol 最後到下層的Service時會幫你轉換成真正在Service用的VpnProfile類
        • 也就是VpnManager的 line 335 : provisionVpnProfile(@NonNull PlatformVpnProfile profile) 最後是用 toVpnProfile()幫你把PlatformVpnProfile轉為VpnProfile
      • 其中Ikev2VpnProfile.Builder 可以設定Ikev2相關連線設置,這個類其實就是實作PlatformVpnProfile讓你去設定開放的protocol模式
    • 'vpn設置相關' : 通過VpnService,在建立本地tunnel的時候加入VpnService.Builder()
      • 官方 VpnService架構圖
        • 此方法設定連線時的Tunnel,官方僅提供如下方example所示的方法 給開發者使用
        • 雖然AOSP內有提供相關protocol連線,但是尚未開放給上層使用, 故若需要相關protocol進行連線,則需自行開發
      • example :
        /***  Android level 14 up ***/
        val builder = VpnService.Builder()
        val localTunnel = builder
                         .setSession('VPN名字')  
                         .addAddress('服務器', 'prefix length')
                         .addRoute('轉發路由', 'prefix length')
                         .addDnsServer('DNS服務器')
                         .addSearchDomain('DNS 搜索域')
                         .establish()
        


透過其他或第三方方案來實作Vpn app
若官方提供開放的方法,還無法滿足需求,則可考慮:
  • AnyConnect:第三方VPN供應商,目前看到第三方廠商的VPN服務
  • (供參考) 看到網路上有一解法去設定VpnProfile,透過反射framework內的方法直接使用:Create VPN profile on Android
    • 但在Android 9.0以上此法已被修正,故推測有些較早期的手機可能使用這種方法 (若目標裝置在這之前,還能考慮)
    • 修正公告
  • (供參考) 第三方 openVpn 有提供Android開源


其餘知識點
  • 透過app開啟自定義VpnService時,在Android 8.0 以上service運作新增後台執行限制

  • 追蹤android-10.0.0_r1 aosp內的 VpnService.javaline:176~179使用了 IConnectivityManager.aidl,但目前在framework層找不到實作aidl的痕跡, 故推測有可能是放在binder之類的,若要了解它怎麼實作的,可能要再研究底層code

  • 追蹤 Android 12 aosp內的 VpnService.Java,其line:178~181使用的aidl改成IVpnManager.aidl, source code內有另一個檔案為VpnManagerService.Java

    其中line:293provisionVpnProfile(VpnProfile profile,...) 這個method要求提供一個變數VpnProfile

    點進去看VpnProfile的line:97得知其預設連線方案為:public int type = TYPE_PPTP

    且看到VpnProfile可設定的連線模式有:
    vpn_aosp_type.png
    不過這些目前僅在aosp內有支援這些連線模式
    且因為沒有開放出來,所以無法寫在app內直接使用
    總結來說
    一來非開發者只能從手機設定裡那邊修改
    二來開發者要自行實作只能從aosp那邊下手

You might also enjoy