Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 一種實現android免root防火牆的方法

一種實現android免root防火牆的方法

編輯:關於Android編程

在使用android手機過程中,發現自己手機的流量經常被一些不小心下載的帶廣告的應用偷走了。自己在各個市場上搜了下,絕大部分防火牆都是需要手機root的。其中多數又是修改自著名的Droidwall,例如github上這個項目:https://github.com/skullone/android_firewall。其原理是在root後的機器使用root權限來配置iptable,利用linux這個自帶的防火牆實行流量控制。

但root本身破壞了android的安全機制,反而容易導致系統被惡意代碼利用。在googleplay上,終於找到一款noroot firewall。它利用了android的vpnservice技術,實現了免root的防火牆。很感興趣,於是在網上找了些資料,又自己實現了一個免root防火牆,這裡分享下自己的經驗。

Android系統支持配置VPN service。可以在設置->更多->VPN中添加。但系統只支持部分VPN協議。如果用戶想實現自己的VPN協議,那怎麼辦呢?為了支持這種擴展,Android提供了VpnService類。這是一個Service的子類。一旦start了該service,它會創建一個類似於應用代理的服務。任何應用外出的包,都會先發給該服務,然後該服務再轉發到網絡上。於是這個VpnService就成為需要使用網絡的應用和網絡服務器之間的一個中間人。這就提供了一個機會來控制外出流量。

VpnService和client交互

那VpnService是如何跟client應用通信的呢?這裡利用了linux的TUN/TAP機制。TUN/TAP提供了一種虛擬的軟網絡接口(相對於物理網卡而言)。開發人員可以打開這個軟接口設備,獲取一個文件描述符(設備即文件),然後read就是從其中讀數據,write就是向其中寫數據。不同於物理網卡接口是把數據發送到網上或者接收自網上(其實是寫/讀到內核裡,然後網卡驅動發/收到網上),該虛擬網絡接口是讀/寫到應用空間。當建立其TUN/TAP後,client應用本來要發送到實際網卡的包,都會發送給這個虛擬的tun/tap,此時vpnservice就可以read到client發送的數據;vpnservice可以寫數據到tun/tap中,此時client如果recv或read,那就會讀取這個虛擬網口,獲取vpnservice寫的數據。這個我估計是通過修改路由表實現的,使得所有的網樓包都優先走tun/tap虛擬網口。

tun和tap的區別是前者這有IP頭和IP負載(即三層和以上),而tap包括數據鏈路層頭(二層和以上)。在Android中,實際是一個tun,讀寫的數據是IP原始報文。為了驗證vpnservice創建了一個虛擬網口,可以下載noroot filewall,然後通過adb shell netcfg。如果已經打開了vpnservice,則名字是tun0的接口,其狀態是UP。

關於tun/tap可以參考http://backreference.org/2010/03/26/tuntap-interface-tutorial/和https://www.kernel.org/doc/Documentation/networking/tuntap.txt。這是linux的機制,而不僅僅是android的。

VpnService和網絡服務器交互

那VpnService如果把收到的數據發送到網上呢?不同於普通linux允許用戶發送原始ip報文,Android安全機制只允許socket發送普通的tcp/udp報文。這就要求我們把通過tun收到的ip報文進行解包,獲取其tcp/udp payload(即應用層數據),然後通過send發送到服務器。在接收的時候,需要把服務器過來的recv的數據,添加tcp/udp頭和ip頭,然後write到tun中。對於tcp具體而言要復雜很多:

  • 如果受到的是syn包,則要connect
  • 如果connect成功,則需要返回給tun一個syn ack。這樣子三次握手結束(因為不用處理最後一個ack)。
  • 傳輸的時候要記錄雙向的seq,以生成seq和ack序號。
  • 收到fin包的時候需要close,並返回fin ack。有時候是服務器發起連接終止,此時需要向客戶端發fin。
  • 收到rst同樣要close連接。

    某種程度上,這裡要重現實現一個tcp協議棧,不過要比完整的簡單很多。

    實現

    首先要start service,這一般在activity提供一個button實現。並不是直接startservice,而是要先打開一個需要用戶同意的activity,當用戶同意時,才能打開service。這是為了防止惡意vpnservice偷窺網絡數據。

    參考這段代碼(在activity中):

        public void enableVpnService() {
            Intent intent = MyVpnService.prepare(getApplicationContext());
            if (intent != null) {
                startActivityForResult(intent, 0);
            } else {
                onActivityResult(0, RESULT_OK, null);
            }
        }
    
        @Override
        protected void onActivityResult(int request, int result, Intent data) {
            if (result == RESULT_OK) {
                Intent intent = new Intent(this, MyVpnService.class);
                startService(intent);
            }
        }

    然後在service的onstartcommand中,需要創建tun。

    為了方便VpnService創建tun,Android提供了一個Builder類VpnService.Builder。例如我們可以調用:

    Builder builder = new Builder();
    builder.addAddress("10.0.8.1", 32).addRoute("0.0.0.0", 0).setSession("Firewall")
                    .setMtu(1500);
    ParcelFileDescriptor interface = builder.establish();

    此interface就代表著tun。只可以對其進行讀寫。為了避免ANR,最好是創建一個thread來做。

    對於真實跟外界交互的socket,如果你對其不做任何處理,那數據會再次發送到tun中,造成死循環。所以此時要調用VpnService.protect保證該socket發送的數據都直接發到物理網卡。

    Android提供了一個ToyVpn的sample project,可以搜索看其代碼,也可以在eclipse創建android sample code來看。另外可以參考下這篇介紹文章。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved