Android12.0(S) 新增系统服务实现网络黑白名单(防火墙)功能

993 阅读9分钟

前言

这功能前前后后弄了得有两月吧,虽不是特别完美,还好最终还是搞定了,哈哈哈

本方案实现基于 iptables 管控,关于 iptables 的详细使用介绍可参考朱双印大佬的博文,那是相当的详细本文将不再介绍

本文实现过程中遇到的问题集锦

问题1、iptables 指令需要在 root 权限才能执行,adb shell 中执行提示

iptables v1.8.7 (legacy): can't initialize iptables table `filter': Permission denied (you must be root) Perhaps iptables or your kernel needs to be upgraded.

为了解决这个问题,我们需要在 init.rc 中配置一个服务,通过 prop 值来控制启动这个服务,达到提权的效果

问题2、iptables 指令生成的网络规则重启会失效,为了解决这个问题,我们需要重启后再次执行一遍上一次的指令,

通过 persist 开头 prop 可解决该问题。

问题3、persist 开头 prop 和新增加执行 sh 文件编译和运行对应 selinux 规则处理起来贼麻烦,

本文并没解决而是简单粗暴直接关闭 selinux 了。

问题4、iptables 中不识别域名,在设备联网的情况下增加域名会自动转换为 ip 在规则表中,

若设备没网络情况下,增加域名失败,所以最好增加 ip。获取域名对应 ip,可通过 ping 方式查看

问题5、设置 iptables 规则后,设备 wifi 或者 eth 可能会提示已连接但无法访问互联网

解决办法找到系统当前检测域名对应 ip 将其增加进白名单中

实现原理如下

x0VqG4.png

修改清单

	frameworks/base/core/api/current.txt
	frameworks/base/core/java/android/app/SystemServiceRegistry.java
	frameworks/base/core/java/android/content/Context.java
	frameworks/base/core/java/android/app/INetworkFireWallListManager.aidl
	frameworks/base/core/java/android/app/NetworkFireWallListManager.java
	frameworks/base/services/core/java/com/android/server/NetworkFireWallListManagerService.java	
	frameworks/base/services/java/com/android/server/SystemServer.java
	prebuilts/sdk/31/public/api/android.txt
	prebuilts/sdk/32/public/api/android.txt
	system/core/rootdir/init.rc
	system/sepolicy/prebuilts/api/31.0/private/file_contexts
	system/sepolicy/prebuilts/api/32.0/private/file_contexts
	system/sepolicy/private/file_contexts
	system/sepolicy/prebuilts/api/31.0/private/netfirewall.te
	system/sepolicy/prebuilts/api/32.0/private/netfirewall.te
	system/sepolicy/private/netfirewall.te

1、增加 INetworkFireWallListManager aidl 相关类

frameworks/base/core/java/android/app/INetworkFireWallListManager.aidl

package android.app;

interface INetworkFireWallListManager{

    void addBlackListRule(in List<String> ipList);

    void addWhiteListRule(in List<String> ipList);

    void clearRule(in String sheetName);
}

frameworks/base/core/java/android/app/NetworkFireWallListManager.java

package android.app;

import android.annotation.SystemService;
import android.compat.annotation.UnsupportedAppUsage;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.util.Singleton;
import android.util.Log;
import java.util.List;
import android.content.Context;
import android.app.INetworkFireWallListManager;

@SystemService(Context.NETWORKFIREWALLLISTMANAGER_SERVICE)
public class NetworkFireWallListManager {
	private static String TAG = "NetworkFireWallListManager";
    private INetworkFireWallListManager mService;
	private static NetworkFireWallListManager sInstance;

	/**
	*@hide
	*/
	public  NetworkFireWallListManager(INetworkFireWallListManager service){
		mService = service;
	}
	
	/**
	*@hide
	*/
	@NonNull
	@UnsupportedAppUsage
	public static NetworkFireWallListManager getInstance() {
		synchronized (NetworkFireWallListManager.class) {
	        if (sInstance == null) {
	            try {
	                IBinder b = ServiceManager.getServiceOrThrow(Context.NETWORKFIREWALLLISTMANAGER_SERVICE);
	                sInstance = new NetworkFireWallListManager(INetworkFireWallListManager.Stub
	                        .asInterface(ServiceManager.getServiceOrThrow(Context.NETWORKFIREWALLLISTMANAGER_SERVICE)));
	            } catch (ServiceNotFoundException e) {
	                throw new IllegalStateException(e);
	            }

	        }
	        Log.d(TAG,"NetworkFireWallListManager getInstance");
        	return sInstance;
    	}
	}

	public void addBlackListRule(@Nullable List<String> ipList){
        try{
           mService.addBlackListRule(ipList);
        } catch (RemoteException e){
           throw e.rethrowFromSystemServer();
        }
	}

	public void addWhiteListRule(@Nullable List<String> ipList){
        try{
           mService.addWhiteListRule(ipList);
        } catch (RemoteException e){
           throw e.rethrowFromSystemServer();
        }
	}

	public void clearRule(@Nullable String sheetName){
        try{
           mService.clearRule(sheetName);
        } catch (RemoteException e){
           throw e.rethrowFromSystemServer();
        }
	}
} 

frameworks/base/services/core/java/com/android/server/NetworkFireWallListManagerService.java

package com.android.server;

import android.app.INetworkFireWallListManager;
import android.os.RemoteException;
import android.util.Log;
import android.os.FileUtils;
import android.os.SystemProperties;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

public class NetworkFireWallListManagerService extends INetworkFireWallListManager.Stub {
        static final String TAG = "NetworkFireWallListManagerService";

        @Override
        public void addBlackListRule(List<String> ipList) throws RemoteException {
            Log.d(TAG,"addBlackListRule  ");
        }

        @Override
        public void addWhiteListRule(List<String> ipList) throws RemoteException{
             Log.d(TAG,"addWhiteListRule  ");
        }

        @Override
        public void clearRule(String sheetName) throws RemoteException{
             Log.d(TAG,"clearRule  "+sheetName);
        }
}

2、新增系统服务

frameworks/base/core/java/android/app/SystemServiceRegistry.java

@@ -233,6 +233,8 @@ import com.android.internal.net.INetworkWatchlistManager;
 import com.android.internal.os.IDropBoxManagerService;
 import com.android.internal.policy.PhoneLayoutInflater;
 import com.android.internal.util.Preconditions;
+//cczheng add
+import android.app.NetworkFireWallListManager;//end
 
 import java.util.Map;
 import java.util.Objects;
@@ -320,7 +322,14 @@ public final class SystemServiceRegistry {
                 IAlarmManager service = IAlarmManager.Stub.asInterface(b);
                 return new AlarmManager(service, ctx);
             }});
-
+        //cczheng add
+        registerService(Context.NETWORKFIREWALLLISTMANAGER_SERVICE, NetworkFireWallListManager.class,
+                new CachedServiceFetcher<NetworkFireWallListManager>() {
+            @Override
+            public NetworkFireWallListManager createService(ContextImpl ctx) {
+                return NetworkFireWallListManager.getInstance();
+            }});
+        //end
         registerService(Context.AUDIO_SERVICE, AudioManager.class,
                 new CachedServiceFetcher<AudioManager>() {
             @Override

frameworks/base/core/java/android/content/Context.java

@@ -3715,6 +3715,7 @@ public abstract class Context {
             //@hide: SPEECH_RECOGNITION_SERVICE,
             UWB_SERVICE,
             MEDIA_METRICS_SERVICE,
+            NETWORKFIREWALLLISTMANAGER_SERVICE,//cczheng add
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -5650,6 +5651,17 @@ public abstract class Context {
      */
     public static final String MEDIA_METRICS_SERVICE = "media_metrics";
 
+    //cczheng add
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.app.NetworkFireWallListManager} for manage netfirewall on the device.
+     *
+     * @see #getSystemService(String)
+     * @see android.app.NetworkFireWallListManager
+     */
+    public static final String NETWORKFIREWALLLISTMANAGER_SERVICE = "networkfirewalllistmanager";
+    //end
+

frameworks/base/services/java/com/android/server/SystemServer.java

@@ -1460,6 +1460,13 @@ public final class SystemServer implements Dumpable {
             ServiceManager.addService("dynamic_system", dynamicSystem);
             t.traceEnd();
 
+            //cczheng add 
+            t.traceBegin("StartNetworkFireWallListManagerService");
+            ServiceManager.addService(Context.NETWORKFIREWALLLISTMANAGER_SERVICE, 
+                new NetworkFireWallListManagerService());
+            t.traceEnd();
+            //end
+
             if (!isWatch) {
                 t.traceBegin("StartConsumerIrService");
                 consumerIr = new ConsumerIrService(context);

3、解决新增系统服务编译报错问题

out/srcjars/android/app/INetworkFireWallListManager.java:200: error: Missing nullability on parameter sheetName in method clearRule [MissingNullability] out/srcjars/android/app/INetworkFireWallListManager.java:10: error: Methods calling system APIs should rethrow RemoteException as RuntimeException (but do not list it in the throws clause) [RethrowRemoteException] out/srcjars/android/app/INetworkFireWallListManager.java:10: error: Missing nullability on parameter ipList in method addBlackListRule [MissingNullability] out/srcjars/android/app/INetworkFireWallListManager.java:13: error: Methods calling system APIs should rethrow RemoteException as RuntimeException (but do not list it in the throws clause) [RethrowRemoteException] out/srcjars/android/app/INetworkFireWallListManager.java:13: error: Missing nullability on parameter ipList in method addWhiteListRule [MissingNullability] 12 more error(s) omitted. Search the log for 'error:' to find all of them.


Your API changes are triggering API Lint warnings or errors. To make these errors go away, fix the code according to the error and/or warning messages above.

If it is not possible to do so, there are workarounds:

  1. You can suppress the errors with @SuppressLint("")
  2. You can add a baseline file of existing lint failures to the build rule of api-stubs-docs-non-updatable.

exit status 255 [ 30% 1641/5426] //frameworks/base:test-api-stubs-docs-non-updatable metalava merged [common]

frameworks/base/core/java/android/os/PackageTagsList.java:111: info: Method can be invoked as a "in" operator from Kotlin: contains (this is usually desirable; just make sure it makes sense for this type of object) [KotlinOperator] 10:04:37 ninja failed with: exit status 1

根据报错提示将代码中增加 Nullable 等关键字,没有新增直接 copy 我提供的就好

新增 api make 后报错,执行下面指令更新 current.txt

cp out/soong/.intermediates/frameworks/base/api-stubs-docs-non-updatable/android_common/metalava/api-stubs-docs-non-updatable_api.txt frameworks/base/core/api/current.txt

frameworks/base/core/api/current.txt

@@ -5378,6 +5378,30 @@ package android.app {
     field public static final int GAME_MODE_UNSUPPORTED = 0; // 0x0
   }
 
+  public interface INetworkFireWallListManager extends android.os.IInterface {
+    method public void addBlackListRule(java.util.List<java.lang.String>) throws android.os.RemoteException;
+    method public void addWhiteListRule(java.util.List<java.lang.String>) throws android.os.RemoteException;
+    method public void clearRule(String) throws android.os.RemoteException;
+    field public static final String DESCRIPTOR = "android.app.INetworkFireWallListManager";
+  }
+
+  public static class INetworkFireWallListManager.Default implements android.app.INetworkFireWallListManager {
+    ctor public INetworkFireWallListManager.Default();
+    method public void addBlackListRule(java.util.List<java.lang.String>) throws android.os.RemoteException;
+    method public void addWhiteListRule(java.util.List<java.lang.String>) throws android.os.RemoteException;
+    method public android.os.IBinder asBinder();
+    method public void clearRule(String) throws android.os.RemoteException;
+  }
+
+  public abstract static class INetworkFireWallListManager.Stub extends android.os.Binder implements android.app.INetworkFireWallListManager {
+    ctor public INetworkFireWallListManager.Stub();
+    method public android.os.IBinder asBinder();
+    method public static android.app.INetworkFireWallListManager asInterface(android.os.IBinder);
+    method public static android.app.INetworkFireWallListManager getDefaultImpl();
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
+    method public static boolean setDefaultImpl(android.app.INetworkFireWallListManager);
+  }
+
   public class Instrumentation {
     ctor public Instrumentation();
     method public android.os.TestLooperManager acquireLooperManager(android.os.Looper);
@@ -5623,6 +5647,12 @@ package android.app {
     field public static final String META_DATA_LIB_NAME = "android.app.lib_name";
   }
 
+  public class NetworkFireWallListManager {
+    method public void addBlackListRule(@Nullable java.util.List<java.lang.String>);
+    method public void addWhiteListRule(@Nullable java.util.List<java.lang.String>);
+    method public void clearRule(@Nullable String);
+  }
+
   public class Notification implements android.os.Parcelable {
     ctor public Notification();
     ctor @Deprecated public Notification(int, CharSequence, long);
@@ -10672,6 +10702,7 @@ package android.content {
     field public static final int MODE_PRIVATE = 0; // 0x0
     field @Deprecated public static final int MODE_WORLD_READABLE = 1; // 0x1
     field @Deprecated public static final int MODE_WORLD_WRITEABLE = 2; // 0x2
+    field public static final String NETWORKFIREWALLLISTMANAGER_SERVICE = "networkfirewalllistmanager";
     field public static final String NETWORK_STATS_SERVICE = "netstats";
     field public static final String NFC_SERVICE = "nfc";
     field public static final String NOTIFICATION_SERVICE = "notification";

将上面 current.txt 和 prebuilts 目录下文件对比差异新增 NetworkFireWall 部分

prebuilts/sdk/31/public/api/android.txt prebuilts/sdk/32/public/api/android.txt

@@ -5373,6 +5373,30 @@ package android.app {
     field public static final int GAME_MODE_UNSUPPORTED = 0; // 0x0
   }
 
+  public interface INetworkFireWallListManager extends android.os.IInterface {
+    method public void addBlackListRule(java.util.List<java.lang.String>) throws android.os.RemoteException;
+    method public void addWhiteListRule(java.util.List<java.lang.String>) throws android.os.RemoteException;
+    method public void clearRule(String) throws android.os.RemoteException;
+    field public static final String DESCRIPTOR = "android.app.INetworkFireWallListManager";
+  }
+
+  public static class INetworkFireWallListManager.Default implements android.app.INetworkFireWallListManager {
+    ctor public INetworkFireWallListManager.Default();
+    method public void addBlackListRule(java.util.List<java.lang.String>) throws android.os.RemoteException;
+    method public void addWhiteListRule(java.util.List<java.lang.String>) throws android.os.RemoteException;
+    method public android.os.IBinder asBinder();
+    method public void clearRule(String) throws android.os.RemoteException;
+  }
+
+  public abstract static class INetworkFireWallListManager.Stub extends android.os.Binder implements android.app.INetworkFireWallListManager {
+    ctor public INetworkFireWallListManager.Stub();
+    method public android.os.IBinder asBinder();
+    method public static android.app.INetworkFireWallListManager asInterface(android.os.IBinder);
+    method public static android.app.INetworkFireWallListManager getDefaultImpl();
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
+    method public static boolean setDefaultImpl(android.app.INetworkFireWallListManager);
+  }
+
   public class Instrumentation {
     ctor public Instrumentation();
     method public android.os.TestLooperManager acquireLooperManager(android.os.Looper);
@@ -5618,6 +5642,12 @@ package android.app {
     field public static final String META_DATA_LIB_NAME = "android.app.lib_name";
   }
 
+  public class NetworkFireWallListManager {
+    method public void addBlackListRule(@Nullable List<String>);
+    method public void addWhiteListRule(@Nullable List<String>);
+    method public void clearRule(@Nullable String);
+  }
+
   public class Notification implements android.os.Parcelable {
     ctor public Notification();
     ctor @Deprecated public Notification(int, CharSequence, long);
@@ -11142,6 +11172,7 @@ package android.content {
     field public static final int MODE_PRIVATE = 0; // 0x0
     field @Deprecated public static final int MODE_WORLD_READABLE = 1; // 0x1
     field @Deprecated public static final int MODE_WORLD_WRITEABLE = 2; // 0x2
+    field public static final String NETWORKFIREWALLLISTMANAGER_SERVICE = "networkfirewalllistmanager";
     field public static final String NETWORK_STATS_SERVICE = "netstats";
     field public static final String NFC_SERVICE = "nfc";
     field public static final String NOTIFICATION_SERVICE = "notification";
	 

4、新增 prop 改变监听执行 netfirewall.sh 并解决编译报错

system/core/rootdir/init.rc

@@ -834,6 +834,9 @@ on post-fs-data
     mkdir /data/app 0771 system system encryption=Require
     mkdir /data/property 0700 root root encryption=Require
 
+    #cczheng create directory for netfirewall files.
+    mkdir /data/netfirewall 0771 system system encryption=None
+
     # create directory for updated font files.
     mkdir /data/fonts/ 0771 root root encryption=Require
     mkdir /data/fonts/files 0771 system system
@@ -1203,6 +1206,17 @@ on property:sys.boot_completed=1
     exec - system system -- /bin/rm -rf /data/per_boot
     mkdir /data/per_boot 0700 system system encryption=Require key=per_boot_ref
 
+#cczheng add
+on property:persist.sys.runfire=1
+    start  netfirewall
+
+service netfirewall /system/bin/sh /data/netfirewall/netfirewall.sh
+    user root
+    group root
+    disabled
+    oneshot
+    seclabel u:object_r:netfirewall_exec:s0
+
 # system server cannot write to /proc/sys files,

system/sepolicy/private/file_contexts system/sepolicy/prebuilts/api/31.0/private/file_contexts system/sepolicy/prebuilts/api/32.0/private/file_contexts

@@ -646,6 +646,8 @@
 /data/vendor_ce(/.*)?           u:object_r:vendor_data_file:s0
 /data/vendor_de(/.*)?           u:object_r:vendor_data_file:s0
 
+#/data/netfirewall/netfirewall.sh   u:object_r:netfirewall_exec:s0
+/system/bin/netfirewall.sh   u:object_r:netfirewall_exec:s0
 # storaged proto files
 /data/misc_de/[0-9]+/storaged(/.*)?       u:object_r:storaged_data_file:s0
 /data/misc_ce/[0-9]+/storaged(/.*)?       u:object_r:storaged_data_file:s0

system/sepolicy/private/netfirewall.te system/sepolicy/prebuilts/api/32.0/private/netfirewall.te system/sepolicy/prebuilts/api/32.0/private/netfirewall.te

type netfirewall, coredomain;
type netfirewall_exec, system_file_type, exec_type, file_type;

#Allow cppreopts to execute itself using #!/system/bin/sh
#allow netfirewall shell_exec:file { r_file_perms execute };
init_daemon_domain(netfirewall);

至此 make 可成功编译,且服务正常启动,可通过编写测试脚本 netfirewall.sh

#!/system/bin/sh

echo "start add rule"
iptables -I OUTPUT -d 180.101.49.11 -j ACCEPT
iptables -I OUTPUT -d 180.101.49.12 -j ACCEPT
iptables -P OUTPUT DROP	
echo "add rule end"

将 netfirewall.sh 预制到 system/bin 目录下,

同时修改 init.rc 中 prop 对应文件为 system/bin/netfirewall.sh 测试,

最终测试效果为浏览器只能访问百度,其它网页均不能访问

5、最终构建黑名单和白名单规则

黑名单和白名单是互斥功能,均通过 iptables OUTPUT 表规则实现

黑名单,OUTPUT 默认为 ACCEPT,在其中增加禁止访问 ip 对应为 DROP

白名单,将 OUTPUT 修改为 DROP,在其中增加允许访问 ip 对应为 ACCEPT

iptables -nL OUTPUT 查询当前 OUTPUT 对应规则

改造后的 NetworkFireWallListManagerService.java

frameworks/base/services/core/java/com/android/server/NetworkFireWallListManagerService.java

package com.android.server;

import android.app.INetworkFireWallListManager;
import android.os.RemoteException;
import android.util.Log;
import android.os.FileUtils;
import android.os.SystemProperties;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

public class NetworkFireWallListManagerService extends INetworkFireWallListManager.Stub {
        static final String TAG = "NetworkFireWallListManagerService";
        static  final String PROP_CONTROL_FIRETYPE = "persist.sys.firetype";

        @Override
        public void addBlackListRule(List<String> ipList) throws RemoteException {
            Log.d(TAG,"addBlackListRule  ");
            SystemProperties.set(PROP_CONTROL_FIRETYPE, "addBlack");
            String cmd = makeIptableString(ipList);
            writeShFile(cmd);
        }

        @Override
        public void addWhiteListRule(List<String> ipList) throws RemoteException{
             Log.d(TAG,"addWhiteListRule  ");
			 SystemProperties.set(PROP_CONTROL_FIRETYPE, "addWhite");
             String cmd = makeIptableString(ipList);
             writeShFile(cmd);
        }

        @Override
        public void clearRule(String sheetName) throws RemoteException{
             Log.d(TAG,"clearRule  "+sheetName);
			 SystemProperties.set(PROP_CONTROL_FIRETYPE, "clear");
			 String cmd = makeIptableString(null);
			 writeShFile(cmd);
        }

        private String makeIptableString(List<String> ipList){
            StringBuilder sb = new StringBuilder();
            sb.append("echo start make rule\n");
            //clear
            sb.append("handleType=$(getprop persist.sys.firetype)\n");
            sb.append("if [ $handleType = \"clear\" ]; then\n");
                sb.append("echo handleType is clear\n");
                sb.append("iptables -F INPUT\n");
                sb.append("iptables -F OUTPUT\n");
            sb.append("fi\n");
            //addWhite
            sb.append("if [ $handleType = \"addWhite\" ]; then\n");
                if (ipList != null && ipList.size() > 0) {
                    sb.append("echo handleType is addWhite\n");
                    for (int i = 0; i < ipList.size(); i++) {
                        String ipname = ipList.get(i);
                        sb.append("iptables -I OUTPUT -d ");
                        sb.append(ipname);
                        sb.append(" -j ACCEPT\n");
                    }
                     sb.append("iptables -P OUTPUT DROP\n");
                }else {
                    sb.append("all White rule pass\n");
                }
            sb.append("fi\n");
            //addBlack
            sb.append("if [ $handleType = \"addBlack\" ]; then\n");
            if (ipList != null && ipList.size() > 0) {
                sb.append("echo handleType is addBlack \n");
                for (int i = 0; i < ipList.size(); i++) {
                    String ipname = ipList.get(i);
                    sb.append("iptables -I OUTPUT -d ");
                    sb.append(ipname);
                    sb.append(" -j DROP\n");
                }
            }else {
                sb.append("all Black rule pass\n");
            }
            sb.append("fi\n");
            sb.append("echo make rule end\n");
            return sb.toString();
        }

    private void writeShFile(String cmd){
        try {
            final File file = new File("/data/netfirewall/", "netfirewall.sh");
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();
            final String abspath = file.getAbsolutePath();
            FileUtils.setPermissions(abspath, 00700, -1, -1);
            Runtime.getRuntime().exec("chmod 777 " + abspath).waitFor();
            final OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file));
            if (new File("/system/bin/sh").exists()) {
                out.write("#!/system/bin/sh\n");
            }
            out.write(cmd);
            if (!cmd.endsWith("\n"))
                out.write("\n");
            out.write("exit 0\n");
            out.flush();
            out.close();
            SystemProperties.set("persist.sys.runfire", "1");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}	

客户端调用代码

       INetworkFireWallListManager fireWallListManager
                = INetworkFireWallListManager.Stub.asInterface(getService("networkfirewalllistmanager"));
        List<String> list = new ArrayList<String>();
        list.add("101.37.115.180");//www.cnblog.com
        list.add("116.62.84.58");
        list.add("180.101.49.11");///www.baidu.com
        list.add("180.101.49.12");

        try {
            fireWallListManager.addWhiteListRule(list);
        } catch (Exception e) {
            e.printStackTrace();
        }

参考文章

Android 12 (S) 新加系统服务 iptables详解(3):iptables规则管理 Android 利用Iptables实现网络黑白名单(防火墙)