Android之防火墙功能的实现

来源:互联网 发布:淘宝层级划分 编辑:程序博客网 时间:2024/05/22 06:39


http://blog.csdn.net/zhangyongfeiyong/article/details/52524220


需求:可以控制某个应用访问WIFI或移动网络的功能。

Android自带防火墙原理是:一旦开启防火墙,所有的应用都不能访问网络(包括WIFI和移动网络),所以不能满足需求,故需要在原生基础上新增两个方法来实现该功能,方法声明在frameworks/base/core/Java/android/os目录下的INetworkManagementService.aidl中:

[java] view plain copy
  1. interface INetworkManagementService  
  2. {  
  3.     . . .      
  4.     void setMobileDataUidRule(int uid, boolean allow); //根据应用的uid设置是否允许它访问移动网络  
  5.       
  6.     void setWifiDataUidRule(int uid, boolean allow); //根据应用的uid设置是否允许它访问WIFI网络  
  7.     . . .  
  8. }  


方法的实现是在frameworks/base/services/core/java/com/android/server目录下的NetworkManagementService.java中:

[java] view plain copy
  1. public class NetworkManagementService extends INetworkManagementService.Stub implements Watchdog.Monitor {  
  2.     . . .  
  3.     @Override  
  4.     public void setMobileDataUidRule(int uid, boolean allow) {  
  5.         enforceSystemUid(); // 校验调用者是否是系统uid  
  6.         try {  
  7.             mConnector.execute("firewall""set_mobile_data_uid_rule", uid, rule);  
  8.         } catch (NativeDaemonConnectorException e) {  
  9.             throw e.rethrowAsParcelableException();  
  10.         }  
  11.     }  
  12.     @Override  
  13.     public void setWifiDataUidRule(int uid, boolean allow) {  
  14.         enforceSystemUid();  
  15.         try {  
  16.             mConnector.execute("firewall""set_wifi_data_uid_rule", uid, rule);  
  17.         } catch (NativeDaemonConnectorException e) {  
  18.             throw e.rethrowAsParcelableException();  
  19.         }  
  20.     }  
  21.     . . .  
  22. }  


下面又通过socket通信方式调用到system/netd层的system/netd/server目录下的CommandListener.cpp中:

[cpp] view plain copy
  1. CommandListener::CommandListener() : FrameworkListener("netd"true) {  
  2.     . . .  
  3.     sFirewallCtrl->initIptableFirewall();// 开机初始化  
  4.     . . .  
  5. }  
  6.   
  7. int CommandListener::FirewallCmd::runCommand(SocketClient *cli, int argc, char **argv) {  
  8.     . . .  
  9.     if (!strcmp(argv[1], "set_mobile_data_uid_rule")) {  
  10.         if (argc != 4) {  
  11.             cli->sendMsg(ResponseCode::CommandSyntaxError,  
  12.                     "Usage: firewall set_mobile_data_uid_rule <1000> <allow|deny>",  
  13.                     false);  
  14.             return 0;  
  15.         }  
  16.         int uid = atoi(argv[2]);  
  17.         FirewallRule rule = parseRule(argv[3]);  
  18.         int res = sFirewallCtrl->setMobileDataUidRule(uid, rule);  
  19.         return sendGenericOkFail(cli, res);  
  20.     }  
  21.     if (!strcmp(argv[1], "set_wifi_data_uid_rule")) {  
  22.         if (argc != 4) {  
  23.             cli->sendMsg(ResponseCode::CommandSyntaxError,  
  24.                     "Usage: firewall set_wifi_data_uid_rule <1000> <allow|deny>",  
  25.                     false);  
  26.             return 0;  
  27.         }  
  28.         int uid = atoi(argv[2]);  
  29.         FirewallRule rule = parseRule(argv[3]);  
  30.         int res = sFirewallCtrl->setWifiDataUidRule(uid, rule);  
  31.         return sendGenericOkFail(cli, res);  
  32.     }  
  33.     . . .  
  34. }  


上面代码又调用到system/netd/server目录下的FirewallController.cpp中:

[cpp] view plain copy
  1. . . .  
  2. #include <cutils/properties.h>  
  3.   
  4. const char* op_3g;  
  5. const char* op_wifi;  
  6.   
  7. . . .  
  8.   
  9. int FirewallController::initIptableFirewall(void) {  
  10.     int res = 0;  
  11.     char property[PROPERTY_VALUE_MAX];  
  12.     property_get("ro.hardware", property, "qcom");  
  13.     if (strncmp("qcom", property, 4) == 0) { // 高通平台  
  14.         op_3g = "rmnet+";  
  15.         op_wifi = "wlan0";  
  16.     } else if (strncmp("mt", property, 2) == 0 || strncmp("MT", property, 2) == 0) {  
  17.         op_3g = "ccmni+"// MTK平台  
  18.         op_wifi = "wlan0";  
  19.     } else {  
  20.         op_3g = "rmnet+";  
  21.         op_wifi = "wlan0";  
  22.     }  
  23.     // 新建一个drop_wall链表  
  24.     res |= execIptables(V4V6, "-w""-N""drop_wall", NULL);  
  25.     // 把新建的drop_wall链表添加到OUTPUT链表目录下  
  26.     res |= execIptables(V4V6, "-w""-A""OUTPUT""-j""drop_wall", NULL);  
  27. }  
  28.   
  29. int FirewallController::setMobileDataUidRule(int uid, FirewallRule rule) {  
  30.     char uidStr[16];  
  31.     sprintf(uidStr, "%d", uid);  
  32.     const char* op;  
  33.     if (rule == ALLOW) {  
  34.         op = "-D";// 删除链表中的规则  
  35.     } else {  
  36.         op = "-A";// 添加规则到链表  
  37.     }  
  38.     int res = 0;  
  39.     res |= execIptables(V4V6, "-w", op, "drop_wall""-o", op_3g, "-m""owner",  
  40.             "--uid-owner", uidStr, "-j""REJECT", NULL);  
  41.     return res;  
  42. }  
  43.   
  44. int FirewallController::setWifiDataUidRule(int uid, FirewallRule rule) {  
  45.     char uidStr[16];  
  46.     sprintf(uidStr, "%d", uid);  
  47.     const char* op;  
  48.     if (rule == ALLOW) {  
  49.         op = "-D";// 删除链表中的规则  
  50.     } else {  
  51.         op = "-A";// 添加规则到链表  
  52.     }  
  53.     int res = 0;  
  54.     res |= execIptables(V4V6, "-w", op, "drop_wall""-o", op_wifi, "-m""owner",  
  55.             "--uid-owner", uidStr, "-j""REJECT", NULL);  
  56.     return res;  
  57. }  
  58. . . .  


方法声明在system/netd/server目录下的FirewallController.h中:

[cpp] view plain copy
  1. class FirewallController {  
  2.     public:  
  3.         . . .  
  4.         int initIptableFirewall(void);  
  5.         int setMobileDataUidRule(int, FirewallRule);  
  6.         int setWifiDataUidRule(int, FirewallRule);  
  7.         . . .  
  8. }  


到这里方法就添加完毕了,下面看调用,调用者必须是系统uid,要把aidl文件拷贝到android.os包下,由于NetworkManagementService是隐藏的,故需要使用方式的方式调用:

[java] view plain copy
  1. public static void setUidNetworkState(int uid, boolean enabled) {  
  2.     try {  
  3.         Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);  
  4.         IBinder binder = (IBinder) method.invoke(nullnew Object[] {"network_management"});  
  5.         INetworkManagementService service = INetworkManagementService.Stub.asInterface(binder);  
  6.         if (service != null) {  
  7.             service.setMobileDataUidRule(uid, enabled);  
  8.             service.setWifiDataUidRule(uid, enabled);  
  9.         }  
  10.     } catch (Exception e) {  
  11.         e.printStackTrace();  
  12.     }  
  13. }  


另外,网络端口的查看方式:

[java] view plain copy
  1. adb shell  
  2. netcfg  


代码实现方式:

[java] view plain copy
  1. ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);  
  2. Network[] networks = manager.getAllNetworks();  
  3. for (Network item : networks) {  
  4.     NetworkInfo info = manager.getNetworkInfo(item);  
  5.     if (info.getType() == ConnectivityManager.TYPE_WIFI) {  
  6.         String wifi = manager.getLinkProperties(item)  
  7.                 .getInterfaceName();  
  8.         System.out.println("zyf wifi:" + wifi);  
  9.     } else if (info.getType() == ConnectivityManager.TYPE_MOBILE) {  
  10.         String mobile = manager.getLinkProperties(item)  
  11.                 .getInterfaceName();  
  12.         System.out.println("zyf mobile:" + mobile);  
  13.     }  
  14. }  


 

2
2


原创粉丝点击