Android 网络防火墙的实现 Iptables解决方案

通过对Android SDK帮助文档的阅读,我没有发现Android的高层提供的API,于是通过更底层考虑,我发现了可以采用Iptables实现防火墙的功能。而且Linux下主流的防火墙也是Iptables。

     

Iptables的介绍:

iptables 是与最新的 2.6.x 版本 Linux 内核集成的 IP 信息包过滤系统。如果 Linux 系统连接到因特网或 LAN、服务器或连接 LAN 和因特网的代理服务器,则该系统有利于在 Linux 系统上更好地控制 IP 信息包过滤和防火墙配置。

其工作原理:

netfilter/iptables IP 信息包过滤系统是一种功能强大的工具, 可用于添加、编辑和除去规则,这些规则是在做信息包过滤决定时,防火墙所遵循和组成的规则。这些规则存储在专用的信息包过滤表中, 而这些表集成在 Linux 内核中。 在信息包过滤表中,规则被分组放在我们所谓的 链(chain)中。我马上会详细讨论这些规则以及如何建立这些规则并将它们分组在链中。

虽然 netfilter/iptables IP 信息包过滤系统被称为单个实体,但它实际上由两个组件 netfilter和 iptables 组成。

netfilter 组件也称为 内核空间(kernelspace),是内核的一部分,由一些信息包过滤表组成, 这些表包含内核用来控制信息包过滤处理的规则集。

iptables 组件是一种工具,也称为 用户空间(userspace),它使插入、修改和除去信息包过滤表中的规则变得容易。 除非您正在使用 Red Hat Linux 7.1或更高版本,否则需要从 netfilter.org 下载该工具并安装使用它。

通过使用用户空间,可以构建自己的定制规则,这些规则存储在内核空间的信息包过滤表中。 这些规则具有 目标,它们告诉内核对来自某些源、前往某些目的地或具有某些协议类型的信息包做些什么。 如果某个信息包与规则匹配,那么使用目标 ACCEPT 允许该信息包通过。还可以使用目标 DROP 或REJECT 来阻塞并杀死信息包。对于可对信息包执行的其它操作,还有许多其它目标。

根据规则所处理的信息包的类型,可以将规则分组在链中。处理入站信息包的规则被添加到 INPUT 链中。处理出站信息包的规则被添加到 OUTPUT 链中。处理正在转发的信息包的规则被添加到 FORWARD 链中。这三个链是基本信息包过滤表中内置的缺省主链。 另外,还有其它许多可用的链的类型(如 PREROUTING 和 POSTROUTING ), 以及提供用户定义的链。每个链都可以有一个 策略, 它定义“缺省目标”,也就是要执行的缺省操作,当信息包与链中的任何规则都不匹配时,执行此操作。

建立规则并将链放在适当的位置之后,就可以开始进行真正的信息包过滤工作了。 这时内核空间从用户空间接管工作。当信息包到达防火墙时,内核先 检查信息包的头信息,尤其是信息包的目的地。 我们将这个过程称为 路由。

如果信息包源自外界并前往系统,而且防火墙是打开的,那么内核将它传递到内核空间信息包过滤表的 INPUT 链。如果信息包源自系统内部或系统所连接的内部网上的其它源,并且此信息包要前往另一个外部系统, 那么信息包被传递到 OUTPUT 链。类似的,源自外部系统并前往外部系统的信息包被传递到 FORWARD 链。

接下来,将信息包的头信息与它所传递到的链中的每条规则进行比较,看它是否与某条规则完全匹配。 如果信息包与某条规则匹配,那么内核就对该信息包执行由该规则的目标指定的操作。 但是,如果信息包与这条规则不匹配,那么它将与链中的下一条规则进行比较。 最后,如果信息包与链中的任何规则都不匹配,那么内核将参考该链的策略来决定如何处理该信息包。 理想的策略应该告诉内核 DROP 该信息包。下图用图形说明了这个信息包过滤过程。

 

使用Iptables进行防火墙软件设计的解决方案。

由于Iptables已经有了完善的防火墙规则,我们只需要设计一个基于Iptables的Android前台即可,通过运行脚本,调用iptables设置防火墙规则即可。

 

  大家可以学习下Droid wall的源代码

[java]  view plain  copy
  1. package com.googlecode.droidwall;  
  2. /** 
  3.  * Contains shared programming interfaces. 
  4.  * All iptables "communication" is handled by this class. 
  5.  * 
  6.  * Copyright (C) 2009  Rodrigo Zechin Rosauro 
  7.  * 
  8.  * This program is free software: you can redistribute it and/or modify 
  9.  * it under the terms of the GNU General Public License as published by 
  10.  * the Free Software Foundation, either version 3 of the License, or 
  11.  * (at your option) any later version. 
  12.  * 
  13.  * This program is distributed in the hope that it will be useful, 
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  16.  * GNU General Public License for more details. 
  17.  * 
  18.  * You should have received a copy of the GNU General Public License 
  19.  * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  20.  * 
  21.  * @author Rodrigo Zechin Rosauro 
  22.  * @version 1.0 
  23.  */  
  24. import <a href="http://lib.csdn.net/base/javase" class='replace_word' title="Java SE知识库" target='_blank' style='color:#df3434; font-weight:bold;'>Java</a>.io.IOException;  
  25. import java.io.InputStreamReader;  
  26. import java.io.OutputStreamWriter;  
  27. import java.util.Arrays;  
  28. import java.util.HashMap;  
  29. import java.util.LinkedList;  
  30. import java.util.List;  
  31. import java.util.StringTokenizer;  
  32. import android.app.AlertDialog;  
  33. import android.content.Context;  
  34. import android.content.SharedPreferences;  
  35. import android.content.SharedPreferences.Editor;  
  36. import android.content.pm.ApplicationInfo;  
  37. import android.content.pm.PackageManager;  
  38. import android.util.Log;  
  39. /** 
  40.  * Contains shared programming interfaces. 
  41.  * All iptables "communication" is handled by this class. 
  42.  */  
  43. public final class Api {  
  44.         public static final String VERSION = "1.3.6";  
  45.         // Preferences  
  46.         public static final String PREFS_NAME           = "DroidWallPrefs";  
  47.         public static final String PREF_ALLOWEDUIDS = "AllowedUids";  
  48.         public static final String PREF_PASSWORD        = "Password";  
  49.         public static final String PREF_MODE            = "BlockMode";  
  50.         public static final String PREF_ITFS            = "Interfaces";  
  51.         // Modes  
  52.         public static final String MODE_WHITELIST = "whitelist";  
  53.         public static final String MODE_BLACKLIST = "blacklist";  
  54.         // Interfaces  
  55.         public static final String ITF_3G = "2G/3G";  
  56.         public static final String ITF_WIFI = "Wi-fi";  
  57.         // Cached applications  
  58.         public static DroidApp applications[] = null;  
  59.         // Do we have "Wireless Tether for Root Users" installed?  
  60.         public static String hastether = null;  
  61.         // Do we have root access?  
  62.         private static boolean hasroot = false;  
  63.     /** 
  64.      * Display a simple alert box 
  65.      * @param ctx context 
  66.      * @param msg message 
  67.      */  
  68.         public static void alert(Context ctx, CharSequence msg) {  
  69.         if (ctx != null) {  
  70.                 new AlertDialog.Builder(ctx)  
  71.                 .setNeutralButton(android.R.string.ok, null)  
  72.                 .setMessage(msg)  
  73.                 .show();  
  74.         }  
  75.     }  
  76.     /** 
  77.      * Purge and re-add all rules (internal implementation). 
  78.      * @param ctx application context (mandatory) 
  79.      * @param uids list of selected uids to allow or disallow (depending on the working mode) 
  80.      * @param showErrors indicates if errors should be alerted 
  81.      */  
  82.         private static boolean applyIptablesRulesImpl(Context ctx, List<Integer> uids, boolean showErrors) {  
  83.                 if (ctx == null) {  
  84.                         return false;  
  85.                 }  
  86.                 final SharedPreferences prefs = ctx.getSharedPreferences(PREFS_NAME, 0);  
  87.                 final boolean whitelist = prefs.getString(PREF_MODE, MODE_WHITELIST).equals(MODE_WHITELIST);  
  88.                 boolean wifi = false// Wi-fi selected ?  
  89.                 final String itfs = prefs.getString(PREF_ITFS, ITF_3G);  
  90.                 String itfFilter;  
  91.                 if (itfs.indexOf("|") != -1) {  
  92.                         itfFilter = ""// Block all interfaces  
  93.                         wifi = true;  
  94.                 } else if (itfs.indexOf(ITF_3G) != -1) {  
  95.                         itfFilter = "-o rmnet+";; // Block all rmnet interfaces  
  96.                 } else {  
  97.                         itfFilter = "-o tiwlan+";; // Block all tiwlan interfaces  
  98.                         wifi = true;  
  99.                 }  
  100.         final StringBuilder script = new StringBuilder();  
  101.                 try {  
  102.                         int code;  
  103.                         script.append("iptables -F || exit/n");  
  104.                         final String targetRule = (whitelist ? "ACCEPT" : "REJECT");  
  105.                         if (whitelist && wifi) {  
  106.                                 // When "white listing" Wi-fi, we need ensure that the dhcp and wifi users are allowed  
  107.                                 int uid = android.os.Process.getUidForName("dhcp");  
  108.                                 if (uid != -1) script.append("iptables -A OUTPUT " + itfFilter + " -m owner --uid-owner " + uid + " -j ACCEPT || exit/n");  
  109.                                 uid = android.os.Process.getUidForName("wifi");  
  110.                                 if (uid != -1) script.append("iptables -A OUTPUT " + itfFilter + " -m owner --uid-owner " + uid + " -j ACCEPT || exit/n");  
  111.                         }  
  112.                         for (Integer uid : uids) {  
  113.                                 script.append("iptables -A OUTPUT " + itfFilter + " -m owner --uid-owner " + uid + " -j " + targetRule + " || exit/n");  
  114.                         }  
  115.                         if (whitelist) {  
  116.                                 script.append("iptables -A OUTPUT " + itfFilter + " -j REJECT || exit/n");  
  117.                         }  
  118.                 StringBuilder res = new StringBuilder();  
  119.                         code = runScriptAsRoot(script.toString(), res);  
  120.                         if (showErrors && code != 0) {  
  121.                                 String msg = res.toString();  
  122.                                 Log.e("DroidWall", msg);  
  123.                                 // Search for common error messages  
  124.                                 if (msg.indexOf("Couldn't find match `owner'") != -1 || msg.indexOf("no chain/target match") != -1) {  
  125.                                         alert(ctx, "Error applying iptables rules./nExit code: " + code + "/n/n" +  
  126.                                                 "It seems your Linux kernel was not compiled with the netfilter /"owner/" module enabled, which is required for Droid Wall to work properly./n/n" +  
  127.                                                 "You should check if there is an updated version of your Android ROM compiled with this kernel module.");  
  128.                                 } else {  
  129.                                         // Remove unnecessary help message from output  
  130.                                         if (msg.indexOf("/nTry `iptables -h' or 'iptables --help' for more information.") != -1) {  
  131.                                                 msg = msg.replace("/nTry `iptables -h' or 'iptables --help' for more information.""");  
  132.                                         }  
  133.                                         // Try `iptables -h' or 'iptables --help' for more information.  
  134.                                         alert(ctx, "Error applying iptables rules. Exit code: " + code + "/n/n" + msg.trim());  
  135.                                 }  
  136.                         } else {  
  137.                                 return true;  
  138.                         }  
  139.                 } catch (Exception e) {  
  140.                         if (showErrors) alert(ctx, "error refreshing iptables: " + e);  
  141.                 }  
  142.                 return false;  
  143.     }  
  144.     /** 
  145.      * Purge and re-add all saved rules (not in-memory ones). 
  146.      * This is much faster than just calling "applyIptablesRules", since it don't need to read installed applications. 
  147.      * @param ctx application context (mandatory) 
  148.      * @param showErrors indicates if errors should be alerted 
  149.      */  
  150.         public static boolean applySavedIptablesRules(Context ctx, boolean showErrors) {  
  151.                 if (ctx == null) {  
  152.                         return false;  
  153.                 }  
  154.                 final String savedNames = ctx.getSharedPreferences(PREFS_NAME, 0).getString(PREF_ALLOWEDUIDS, "");  
  155.                 List<Integer> uids = new LinkedList<Integer>();  
  156.                 if (savedNames.length() > 0) {  
  157.                         // Check which applications are allowed  
  158.                         final StringTokenizer tok = new StringTokenizer(savedNames, "|");  
  159.                         while (tok.hasMoreTokens()) {  
  160.                                 uids.add(android.os.Process.getUidForName(tok.nextToken()));  
  161.                         }  
  162.                 }  
  163.                 return applyIptablesRulesImpl(ctx, uids, showErrors);  
  164.         }  
  165.     /** 
  166.      * Purge and re-add all rules. 
  167.      * @param ctx application context (mandatory) 
  168.      * @param showErrors indicates if errors should be alerted 
  169.      */  
  170.         public static boolean applyIptablesRules(Context ctx, boolean showErrors) {  
  171.                 if (ctx == null) {  
  172.                         return false;  
  173.                 }  
  174.                 final SharedPreferences prefs = ctx.getSharedPreferences(PREFS_NAME, 0);  
  175.                 List<Integer> uidsToApply = new LinkedList<Integer>();  
  176.                 final DroidApp[] apps = getApps(ctx);  
  177.                 // Builds a pipe-separated list of names  
  178.                 final StringBuilder newnames = new StringBuilder();  
  179.                 for (int i=0; i<apps.length; i++) {  
  180.                         if (apps[i].selected) {  
  181.                                 if (newnames.length() != 0) newnames.append('|');  
  182.                                 newnames.append(apps[i].username);  
  183.                                 uidsToApply.add(apps[i].uid);  
  184.                         }  
  185.                 }  
  186.                 // save the new list of names if necessary  
  187.                 if (!newnames.toString().equals(prefs.getString(PREF_ALLOWEDUIDS, ""))) {  
  188.                         Editor edit = prefs.edit();  
  189.                         edit.putString(PREF_ALLOWEDUIDS, newnames.toString());  
  190.                         edit.commit();  
  191.                 }  
  192.                 return applyIptablesRulesImpl(ctx, uidsToApply, showErrors);  
  193.     }  
  194.     /** 
  195.      * Purge all iptables rules. 
  196.      * @param ctx context optional context for alert messages 
  197.      * @return true if the rules were purged 
  198.      */  
  199.         public static boolean purgeIptables(Context ctx) {  
  200.         StringBuilder res = new StringBuilder();  
  201.                 try {  
  202.                         int code = runScriptAsRoot("iptables -F || exit/n", res);  
  203.                         if (code != 0) {  
  204.                                 alert(ctx, "error purging iptables. exit code: " + code + "/n" + res);  
  205.                                 return false;  
  206.                         }  
  207.                         return true;  
  208.                 } catch (Exception e) {  
  209.                         alert(ctx, "error purging iptables: " + e);  
  210.                         return false;  
  211.                 }  
  212.     }  
  213.         /** 
  214.          * Display iptables rules output 
  215.          * @param ctx application context 
  216.          */  
  217.         public static void showIptablesRules(Context ctx) {  
  218.                 try {  
  219.                 final StringBuilder res = new StringBuilder();  
  220.                         runScriptAsRoot("iptables -L/n", res);  
  221.                         alert(ctx, res);  
  222.                 } catch (Exception e) {  
  223.                         alert(ctx, "error: " + e);  
  224.                 }  
  225.         }  
  226.     /** 
  227.      * @param ctx application context (mandatory) 
  228.      * @return a list of applications 
  229.      */  
  230.         public static DroidApp[] getApps(Context ctx) {  
  231.                 if (applications != null) {  
  232.                         // return cached instance  
  233.                         return applications;  
  234.                 }  
  235.                 hastether = null;  
  236.                 // allowed application names separated by pipe '|' (persisted)  
  237.                 final String savedNames = ctx.getSharedPreferences(PREFS_NAME, 0).getString(PREF_ALLOWEDUIDS, "");  
  238.                 String allowed[];  
  239.                 if (savedNames.length() > 0) {  
  240.                         // Check which applications are allowed  
  241.                         final StringTokenizer tok = new StringTokenizer(savedNames, "|");  
  242.                         allowed = new String[tok.countTokens()];  
  243.                         for (int i=0; i<allowed.length; i++) {  
  244.                                 allowed[i] = tok.nextToken();  
  245.                         }  
  246.                         // Sort the array to allow using "Arrays.binarySearch" later  
  247.                         Arrays.sort(allowed);  
  248.                 } else {  
  249.                         allowed = new String[0];  
  250.                 }  
  251.                 try {  
  252.                         final PackageManager pkgmanager = ctx.getPackageManager();  
  253.                         final List<ApplicationInfo> installed = pkgmanager.getInstalledApplications(0);  
  254.                         final HashMap<Integer, DroidApp> map = new HashMap<Integer, DroidApp>();  
  255.                         String name;  
  256.                         DroidApp app;  
  257.                         for (final ApplicationInfo apinfo : installed) {  
  258.                                 app = map.get(apinfo.uid);  
  259.                                 name = pkgmanager.getApplicationLabel(apinfo).toString();  
  260.                                 // Check for the tethering application (which causes conflicts with Droid Wall)  
  261.                                 if (apinfo.packageName.equals("android.tether")) {  
  262.                                         hastether = name;  
  263.                                 }  
  264.                                 if (app == null) {  
  265.                                         app = new DroidApp();  
  266.                                         app.uid = apinfo.uid;  
  267.                                         app.username = pkgmanager.getNameForUid(apinfo.uid);  
  268.                                         app.names = new String[] { name };  
  269.                                         map.put(apinfo.uid, app);  
  270.                                 } else {  
  271.                                         final String newnames[] = new String[app.names.length + 1];  
  272.                                         System.arraycopy(app.names, 0, newnames, 0, app.names.length);  
  273.                                         newnames[app.names.length] = name;  
  274.                                         app.names = newnames;  
  275.                                 }  
  276.                                 // check if this application is allowed  
  277.                                 if (!app.selected && Arrays.binarySearch(allowed, app.username) >= 0) {  
  278.                                         app.selected = true;  
  279.                                 }  
  280.                         }  
  281.                         /* add special applications to the list */  
  282.                         final DroidApp special[] = {  
  283.                                 new DroidApp(android.os.Process.getUidForName("root"), "root""(Applications running as root)"false),  
  284.                                 new DroidApp(android.os.Process.getUidForName("media"), "media""Media server"false),  
  285.                         };  
  286.                         for (int i=0; i<special.length; i++) {  
  287.                                 app = special[i];  
  288.                                 if (app.uid != -1 && !map.containsKey(app.uid)) {  
  289.                                         // check if this application is allowed  
  290.                                         if (Arrays.binarySearch(allowed, app.username) >= 0) {  
  291.                                                 app.selected = true;  
  292.                                         }  
  293.                                         map.put(app.uid, app);  
  294.                                 }  
  295.                         }  
  296.                         applications = new DroidApp[map.size()];  
  297.                         int index = 0;  
  298.                         for (DroidApp application : map.values()) applications[index++] = application;  
  299.                         return applications;  
  300.                 } catch (Exception e) {  
  301.                         alert(ctx, "error: " + e);  
  302.                 }  
  303.                 return null;  
  304.         }  
  305.         /** 
  306.          * Check if we have root access 
  307.          * @param ctx optional context to display alert messages 
  308.          * @return boolean true if we have root 
  309.          */  
  310.         public static boolean hasRootAccess(Context ctx) {  
  311.                 if (hasroot) return true;  
  312.                 try {  
  313.                         // Run an empty script just to check root access  
  314.                         if (runScriptAsRoot("exit 0"null20000) == 0) {  
  315.                                 hasroot = true;  
  316.                                 return true;  
  317.                         }  
  318.                 } catch (Exception e) {  
  319.                 }  
  320.                 alert(ctx, "Could not acquire root access./n" +  
  321.                         "You need a rooted phone to run Droid Wall./n/n" +  
  322.                         "If this phone is already rooted, please make sure Droid Wall has enough permissions to execute the /"su/" command.");  
  323.                 return false;  
  324.         }  
  325.     /** 
  326.      * Runs a script as root (multiple commands separated by "/n"). 
  327.      * 
  328.      * @param script the script to be executed 
  329.      * @param res the script output response (stdout + stderr) 
  330.      * @param timeout timeout in milliseconds (-1 for none) 
  331.      * @return the script exit code 
  332.      */  
  333.         public static int runScriptAsRoot(String script, StringBuilder res, final long timeout) {  
  334.                 final ScriptRunner runner = new ScriptRunner(script, res);  
  335.                 runner.start();  
  336.                 try {  
  337.                         if (timeout > 0) {  
  338.                                 runner.join(timeout);  
  339.                         } else {  
  340.                                 runner.join();  
  341.                         }  
  342.                         if (runner.isAlive()) {  
  343.                                 // Timed-out  
  344.                                 runner.interrupt();  
  345.                                 runner.destroy();  
  346.                                 runner.join(50);  
  347.                         }  
  348.                 } catch (InterruptedException ex) {}  
  349.                 return runner.exitcode;  
  350.     }  
  351.     /** 
  352.      * Runs a script as root (multiple commands separated by "/n") with a default timeout of 5 seconds. 
  353.      * 
  354.      * @param script the script to be executed 
  355.      * @param res the script output response (stdout + stderr) 
  356.      * @param timeout timeout in milliseconds (-1 for none) 
  357.      * @return the script exit code 
  358.      * @throws IOException on any error executing the script, or writing it to disk 
  359.      */  
  360.         public static int runScriptAsRoot(String script, StringBuilder res) throws IOException {  
  361.                 return runScriptAsRoot(script, res, 15000);  
  362.         }  
  363.     /** 
  364.      * Small structure to hold an application info 
  365.      */  
  366.         public static final class DroidApp {  
  367.                 /** linux user id */  
  368.         int uid;  
  369.         /** application user name (Android actually uses a package name to identify) */  
  370.         String username;  
  371.         /** application names belonging to this user id */  
  372.         String names[];  
  373.         /** indicates if this application is selected (checked) */  
  374.         boolean selected;  
  375.         /** toString cache */  
  376.         String tostr;  
  377.         public DroidApp() {  
  378.         }  
  379.         public DroidApp(int uid, String username, String name, boolean selected) {  
  380.                 this.uid = uid;  
  381.                 this.username = username;  
  382.                 this.names = new String[] {name};  
  383.                 this.selected = selected;  
  384.         }  
  385.         /** 
  386.          * Screen representation of this application 
  387.          */  
  388.         @Override  
  389.         public String toString() {  
  390.                 if (tostr == null) {  
  391.                         final StringBuilder s = new StringBuilder(uid + ": ");  
  392.                         for (int i=0; i<names.length; i++) {  
  393.                                 if (i != 0) s.append(", ");  
  394.                                 s.append(names[i]);  
  395.                         }  
  396.                         tostr = s.toString();  
  397.                 }  
  398.                 return tostr;  
  399.         }  
  400.     }  
  401.         /** 
  402.          * Internal thread used to execute scripts as root. 
  403.          */  
  404.         private static final class ScriptRunner extends Thread {  
  405.                 private final String script;  
  406.                 private final StringBuilder res;  
  407.                 public int exitcode = -1;  
  408.                 private Process exec;  
  409.                 /** 
  410.                  * Creates a new script runner. 
  411.                  * @param script script to run 
  412.                  * @param res response output 
  413.                  */  
  414.                 public ScriptRunner(String script, StringBuilder res) {  
  415.                         this.script = script;  
  416.                         this.res = res;  
  417.                 }  
  418.                 @Override  
  419.                 public void run() {  
  420.                         try {  
  421.                                 // Create the "su" request to run the command  
  422.                                 // note that this will create a shell that we must interact to (using stdin/stdout)  
  423.                                 exec = Runtime.getRuntime().exec("su");  
  424.                                 final OutputStreamWriter out = new OutputStreamWriter(exec.getOutputStream());  
  425.                                 // Write the script to be executed  
  426.                                 out.write(script);  
  427.                                 // Ensure that the last character is an "enter"  
  428.                                 if (!script.endsWith("/n")) out.write("/n");  
  429.                                 out.flush();  
  430.                                 // Terminate the "su" process  
  431.                                 out.write("exit/n");  
  432.                                 out.flush();  
  433.                                 final char buf[] = new char[1024];  
  434.                                 // Consume the "stdout"  
  435.                                 InputStreamReader r = new InputStreamReader(exec.getInputStream());  
  436.                                 int read=0;  
  437.                                 while ((read=r.read(buf)) != -1) {  
  438.                                         if (res != null) res.append(buf, 0, read);  
  439.                                 }  
  440.                                 // Consume the "stderr"  
  441.                                 r = new InputStreamReader(exec.getErrorStream());  
  442.                                 read=0;  
  443.                                 while ((read=r.read(buf)) != -1) {  
  444.                                         if (res != null) res.append(buf, 0, read);  
  445.                                 }  
  446.                                 // get the process exit code  
  447.                                 if (exec != nullthis.exitcode = exec.waitFor();  
  448.                         } catch (InterruptedException ex) {  
  449.                                 if (res != null) res.append("/nOperation timed-out");  
  450.                         } catch (Exception ex) {  
  451.                                 if (res != null) res.append("/n" + ex);  
  452.                         } finally {  
  453.                                 destroy();  
  454.                         }  
  455.                 }  
  456.                 /** 
  457.                  * Destroy this script runner 
  458.                  */  
  459.                 public synchronized void destroy() {  
  460.                         if (exec != null) exec.destroy();  
  461.                         exec = null;  
  462.                 }  
  463.         }  
  464. }  
 

 

实质就是通过运行IPTABLES的脚本来实现防火墙规则的定制


1、简介

Droidwall是一个关于网络防火墙的开源项目,其最大的功能在于控制应用进程的上网权限,核心功能实现是通过调用linux iptables命令。

2、功能

现Droidwall开源项目提供的功能:

1)分为两种模式,blacklist和whitelist,blacklist中文释义“黑名单”,禁用的进程;whitelist也即是允许能上网的进程。

2)管理有使用网络权限的进程,最核心的功能,当我们选择好所有的进程后点击menu中的应用规则,iptables就会对相应的进程进行管理。

3)log管理

4)显示规则

5)自定义用户脚本

3、实现原理3.1 iptables 简介

防火墙分为硬件和软件,硬件cisco netscreen 联想 天融信 ,软件Iptables 包过滤防火墙。

3.1.1 iptables功能

它最核心功能就是根据预设的规则对包进行过滤,达到保护网络安全的目的,以下是过滤包的简单示意图。


当一个网络封包要进入到主机之前,会先经由Filter表进行检查, 检查通过则接受 (ACCEPT) 进入本机取得资源,如果检查不通过,则可能予以丢弃 (DROP) 。

3.1.2 版本发展

根据linux内核的发展,不同核心版本使用不同的防火墙软体

Version 2.0:使用 ipfwadm 这个防火墙机制;

Version 2.2:使用的是 ipchains 这个防火墙机制;

Version 2.4 与 2.6 :主要是使用 iptables 这个防火墙机制,不过在某些早期的 Version 2.4 版本亦同时支持 ipchains,好让用户仍然可以使用来自 2.2 版的 ipchains 的防火墙规则,现在基本上都是用iptables。

3.1.3相关命令

1)iptables表

首先从iptables 的名称说起,为什么称为ip"tables" 呢?因为这个防火墙软件里面有多个表格(table) ,每个表格都定义出自己的默认政策与规则。表格是怎么组织的?每个表格的组成单位就是“chain”规则链,类似于表格中一行数据,每个规则链中定义了一些基本的规则类似于单元格,我们可以自定义规则链。Linux 的iptables 至少有三个表格,管理本机进出的filter 、管理后端主机 的nat 、管理特殊旗标使用的mangle (较少使用) 。

1.1)filter:主要跟Linux 本机有关,这个是预设的过滤表,以下是其包含的规则链

INPUT:主要与封包想要进入我们Linux 本机有关;

OUTPUT:主要与我们Linux 本机所要送出的封包有关;

FORWARD:这个与Linux 本机比较没有关系,他可以封包『转递』到后端的计算机中,与nat 这个table 相关性很高。

1.2)nat:这个表格主要在用作来源与目的之IP 或port 的转换,与Linux 本机较无关,主要与Linux 主机后的局域网络内的计算机较有相关。以下是其包含的规则链

PREROUTING:在进行路由判断之前所要进行的规则(DNAT/REDIRECT)

POSTROUTING:在进行路由判断之后所要进行的规则(SNAT/MASQUERADE)

OUTPUT:与发送出去的封包有关

1.3)mangle:这个表格主要是与特殊的封包的路由旗标有关,早期仅有PREROUTING 及OUTPUT 链,不过从kernel 2.4.18 之后加入了INPUT 及FORWARD 链。由于这个表格与特殊旗标相关性较高,所以像较少使用mangle 这个表格。



表图

2)命令

这里简单介绍一些比较重要的命令,想知道所有的功能可以使用man查看该命令。

ü 对于规则链的操作

-F 清楚所有规则

iptables -t filter -F INPUT

-X 清除所有自定义规则

-L 列出当前所有规则

iptables -L INPUT -n --line-number -vvv

-A 在所选链的尾加一条规则

-N定义子链

不能与已有的链同名,自定义时,最好先清空所有规则

ü 定义规则的操作

-j 指定规则所做动作

ACCEPT 接受

DROP 丢弃别人可以判断你的系统使用防火墙

REJECT 弹回貌似根本没有打开这个端口

LOG 进行日志,/var/log/message

使用!号的时候 需要在两端加空格表示取反

-p 进行协议进行匹配

[!]tcp|udp|icmp 协议列表以英文逗号为分隔符如tcp,udp 协议前加!号表示取反如-p !tcp

根据端口进行匹配,必须指定协议必须是tcp|udp

--sport [!] port 包的源端口

--dport [!] port 包的目的端口

port 可以用/etc/services 中的协议名来代替 不指定此项,则暗示所用端口, 连续的端口 20:80表示从20到80所用端口包括20和80 :20 0到20 80:从80到65535 !20 非20端口

多端口匹配 -m multiport 如 iptables -A INPUT -p tcp -m multiport --sport 20,21,22,23,80 最多可以指定15的端口,以英文逗号分隔,没有空格,使用是必须指定协议

-i 以包进入本地所使用的网络接口来匹配

-i 参数指定网卡,适用于INPUT 和PREROUGING

-o 参数指定网卡,适用于OUTPUT 和POSTROUGING

-o 以包离开本地所使用的网络接口来匹配

另外重点介绍--m参数

1) 基于状态的匹配 -m state

NEW 初始包或源自于您的机器并要发送到目的IP的包都处于 NEW状态 分为OUTPUT和INPUT NEW包

ESTABLISHED 一旦连接看到两个方向上都有通信流,与此附加相关的其它包都被看作处于ESTABLISHED 状态 NEW和ESTABLISHED 之间的区别很重要

RELATED 是那些启动新连接,但有与当前现有连接相关的包。RELATED状态可以用于调整组成多重连接协议(如ftp)的连接,以及与现有连接相关的错误包(如与现有连接相关的 ICMP 错误包)

INVALID 这种包不会被自动废弃;因此您需要插入适当的规则,并设置链策略,以便可以正确处理这些包。

允许主动发出的包iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

2) 基于MAC地址的匹配-m mac 仅对于PREROUTING和INPUT链起作用

如: iptables -A INPUT -p tcp --dport 23 -m mac --mac-source00:0C:29:BC:BBB -j REJECT

3) 基于封包数量的匹配 -m limit

允许每秒通过一个icmp包,默认触发条件是5个

iptables -A INPUT -p icmp -m limit --limit 1/s -j ACCEPT

超过部分全部拒绝

iptables -A INPUT -p icmp -j DROP

4) 基于UID,GID的限制-m owner

iptables -A OUTPUT -p tcp --dport 23-m owner --uid-owner 500 -j REJECT

iptables -A OUTPUT -p tcp --dport 23 -m owner –gid-owner 500 -jREJECT

注意:-m owner 仅仅输出的封包有用,这个在droidwall开源项目中有使用到。

3.2 android iptables rules设计

droidwall根据上面的规则和命令,在filter表中自定义了4个规则链droidwall、droidwall-3g、droidwall-wifi、droidwall-reject。

3.2.1 droidwall

该规则链非常重要,它定义了不同的网口执行不同的规则链

1)规定与数据流量相关的网口的包执行droidwall-3g规则链

iptables -A droidwall -o rmnet+ -j droidwall-3g

iptables -A droidwall -o pdp+ -j droidwall-3g

iptables -A droidwall -o ppp+ -j droidwall-3g

iptables -A droidwall -o uwbr+ -j droidwall-3g

iptables -A droidwall -o wimax+ -j droidwall-3g

iptables -A droidwall -o vsnet+ -j droidwall-3g

iptables -A droidwall -o ccmni+ -j droidwall-3g

iptables -A droidwall -o usb+ -j droidwall-3g

2)规定与wifi相关网口的包执行droidwall-wifi规则链

iptables -A droidwall -o tiwlan+ -j droidwall-wifi

iptables -A droidwall -o wlan+ -j droidwall-wifi

iptables -A droidwall -o eth+ -j droidwall-wifi

iptables -A droidwall -o ra+ -j droidwall


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值