Android系統中iptables的應用(二)BandwidthController

個人郵箱:[email protected]  歡迎大家直接發郵件給我共同交流學習
      BandwidthController字面意思是帶寬控制,實際模塊實現的是監控系統數據流量使用情況的,主要分爲流量閾值提醒(alert),流量使用上限(limite),限制app後臺流量等。因android系統演進,最初設計的命令和相關功能已經不再使用,所以,如下是在android5.0系統中,據framework層保留在用的API,得出全部在用的bandwidth相關Netd cmd
bandwidth        enable|disable
removeiquota|riq<iface>
setiquota|sq<interface><bytes>
addnaughtyapps|ana<appUid...>
removenaughtyapps|rna<appUid...>
setgolbalalert|sga<bytes>cd ..
setinterfacealert|sia<iface><bytes>
removeinterfacealert|ria<iface>
gettetherstats|gts<iface0><iface1>
      接下來根據系統啓動,到相關功能使用時code運行流程和iptables規則的改動來分析,只對相關功能的enable進行分析,相對應的disable的反向操作省略。
(1)Netd.CommanderListener初始化後
    createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT); 
    createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD); 
    createChildChains(V4V6, "filter", "OUTPUT", FILTER_OUTPUT); 
    sBandwidthCtrl->setupIptablesHooks(); 
    sBandwidthCtrl->enableBandwidthControl(false); 
filter表:
  //分別創建3條子鏈,位置正是filter表可掛的INPUT/OUTPUT/FORWARD三條鏈
  -N bw_FORWARD
  -N bw_INPUT
  -N bw_OUTPUT

  //創建3條子鏈,costly表付費iface一般就是常規的數據流量,
  //happy_box與penalty_box規則就是針對限制app的UID的黑白名單規則,
  //happy_box已不再使用,shared這條鏈原本是用做各條costly_[iface]鏈彙總路線
 
  -N bw_costly_shared

  -N bw_happy_box
  -N bw_penalty_box

  //添加默認jump規則,保證創建的子鏈中的規則被遍歷
  -A INPUT -j bw_INPUT
  -A FORWARD -j bw_FORWARD
  -A OUTPUT -j bw_OUTPUT
  //tracking rule沒啥作用
  -A bw_INPUT -m owner --socket-exists
  -A bw_OUTPUT -m owner --socket-exists

mangle表:

  //tracking rule
  -N bw_mangle_POSTROUTING
  -A POSTROUTING -j bw_mangle_POSTROUTING
  -A bw_mangle_POSTROUTING -m owner –socket-exists

raw表:

  //tracking rule
  -N bw_raw_PREROUTING
  -A PREROUTING -j bw_raw_PREROUTING
  -A bw_raw_PREROUTING -m owner --socket-exists
(2)Framework SystemReady後
    sBandwidthCtrl->enableBandwidthControl(true);
    sBandwidthCtrl->setGlobalAlert([argv]);
會在filter表新增2條規則:
-A bw_INPUT -m quota2 ! --name globalAlert  --quota 2097152
-A bw_OUTPUT -m quota2 ! --name globalAlert  --quota 2097152

   默認2M(2097152)的alert流量計數,動態記錄在/proc/net/xt_quota/globalAlert中,隨經過該鏈的的數據包增加計數遞減,減到0後觸發netlink事件,netd來handle並上報給framework,觸發framework去pollstate並重新更新規則中的alert計數,這兩條規則的意義並不是策略性,只是循環觸發framework和native的相關記錄func的update。
(3)開啓手機的流量:
    sBandwidthCtrl->setInterfaceQuota([iface], [java.Long.MAX_value = 9223372036854775807]);                                                        
在filter表中新增加表&規則:
-N bw_costly_ccmni0
-A bw_FORWARD -o ccmni0 -j bw_costly_ccmni0
-A bw_INPUT -i ccmni0 -j bw_costly_ccmni0
-A bw_OUTPUT -o ccmni0 -j bw_costly_ccmni0
-A bw_costly_ccmni0 -j bw_penalty_box
-A bw_costly_ccmni0 -m quota2 ! --name ccmni0  --quota 9223372036854775807  -j REJECT --reject-with icmp-port-unreachable

    以上新增加的規則實現了,經過ccmni0的數據統計,要經過鏈bw_penalty_box ,爲實現黑名單的功能鋪墊經過ccmni0的數據超過 9223372036854775807,將會直接reject掉數通過該鏈的所有據包。這個計數記錄在/proc/net/xt_quota/ccmni0中,是int64最大值,很難到達,而且計數會一直被framework來更新回2的64方,所以不用擔心reject被觸發。
(4)在setting設置界面開啓流量超值提醒(alert):
    sBandwidthCtrl->setGlobalAlert([argv]);
在filter表中新增加規則:
-A bw_INPUT -m quota2 ! --name globalAlert  --quota 131072
-A bw_OUTPUT -m quota2 ! --name globalAlert  --quota 131072

   只是更改了globalAlert的數值,從默認的2M改爲經過邏輯計算後的數值,以setting中選擇的值爲輸入,經過如下framework中的邏輯MathUtils.constrain(setting_val/1000,128KB,2MB)轉換後,寫入globalAlert中。例如設置20M超值提醒,globalAlert設置爲128K,設置1G提醒,globalAlert設爲1M。計算的邏輯是設置恰當的閾值節點觸發framework和native中相關記錄的循環update。在update的過程中framework會去比較setting中設置的流量閾值和當前流量使用值(記錄在/proc/net/xt_qtaguid下)
(5)在setting設置界面開啓流量超值提醒(limite):
    sBandwidthCtrl->setInterfaceQuota([iface], argv));
在filter表中新增加規則:
-A bw_costly_ccmni1 -m quota2 ! --name ccmni1  --quota 25694376  -j REJECT --reject-with icmp-port-unreachable
                                                        
    加入流量上限規則,本例中設置25M上限,超過後流量不可以使用,任何經過該鏈的數據包都會被reject掉,具體是將封包protocal改爲icmp的port-unreachable並返回給發送端。
(6)在setting中禁用個別應用的後臺流量(naughtapps):
        sBandwidthCtrl->addNaughtyApps([appUids]...);
在filter表中新增加規則:
    -A bw_penalty_box -m owner --uid-owner 10023 -j REJECT --reject-with icmp-port-unreachable

      這裏針對一個或者多個UID參數來禁用個別應用的後臺數據使用,關於所有應用的UID信息可以在package.xml中查:/data/system/packages.xml,注意,以上這條規則是禁用全部由UID=10023數據流量請求,那麼關於應用是否處於foreground/background是由framework進行判斷的,也就是當應用處於foreground的時候,這條規則會被remove掉,不用擔心應用無法使用流量。
關於android的擴展match功能可以quota2的幫助文檔,參考如下手冊:
$ adb shell iptables -m -quota2 -h
quota match options:
    --grow           provide an increasing counter
    --no-change      never change counter/quota value for matching packets
    --name name      name for the file in sysfs
[!] --quota quota    initial quota (bytes or packets)
    --packets        count packets instead of bytes

$ adb shell iptables -m owner -h
owner match options:
[!] --uid-owner userid[-userid]      Match local UID
[!] --gid-owner groupid[-groupid]    Match local GID
[!] --socket-exists                  Match if socket exists
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章