• android 限制浏览器等应用访问某个网站


    前言

    最近有个需求,就是需要在服务器后台动态的禁止android 手机访问某些网址。

    一般来说,像禁止访问某些网址这个需求,我们会在公司的PC 端见过,例如公司内网可能访问不了一些云盘之类的网站。这些要么是it在PC 端动了手脚,要么是直接将连接的网络进行了某种过滤操作导致。

    拿到这个需求的时候。我心里想到了以下两种方法:

    1.通过android 源码,追http 网络请求,在请求处选择性的禁止屏蔽某些网络访问。
    2.使用android 原生提供的iptables。网络防火墙。
    
    • 1
    • 2

    最后选择使用后者,iptables 来实现。毕竟人家都已经实现了,光拿来用就好了。

    1.开始实现

    命令测试

    至于什么是iptables 。大家可以网上搜一搜。这里就不在赘述了。iptables 的命令这里也不再详细说了。这里主要说下我使用iptables 踩过的坑和遇到的问题,以及最后将问题迎刃而解的过程。

    我直接在shell 命令行,通过命令执行iptables 测试,以上需求,验证是可行的。

    首先  iptables -nvL   可以列出所有的规则
    
    • 1
    iptables -t filter -I INPUT -s 39.106.226.142 -j ACCEPT(允许访问39.106.226.142 网址)
    iptables -t filter -I INPUT -s 39.106.226.142 -j REJECT(拒绝访问39.106.226.142 网址)
    
    • 1
    • 2

    注:39.106.226.142 ip 对应的CSDN 网址的ip,如果想要禁止其他的网址,可以在PC 端ping 一下对应网址,就会看到其ip。不过后面我才知道,iptables 是支持直接过滤url 的。但是我测试没成功。先暂且绕一下路,先把网址转换为ip 吧。(某些大型网站,一个域名会对应好多ip,所以,能用url 过滤,最好还是用url 过滤)

    在shell 命令行执行以上命令后,再通过iptables -nvL 就可以看到我们禁止的网址被加入到iptables 规则中了。此时也已经生效了。我们的手机已经没有办法再响应39.106.226.142(CSDN)网址了。任何浏览器访问此网址都不行。

    再分享一个命令 iptables -F 清除掉所有规则。

    还要再说一点:网上查资料,iptables 共有INPUT,等几个链,但是用户也是可以自定义链的,光自定义一个链还不行,还需要将自定义的链与系统提供的原始链关联起来,否则在自定义链里面放任何规则都是不生效的。

    在这里插入图片描述

    2.代码执行命令

    通过以上在shell 行输入命令的方式,验证可行,接下来就是要用代码去执行这些命令了。接下来问题就来了。

    首先,用代码去执行命令,我们首先会想到 **Runtime.getRuntime().exec();**或者用以下的方法去执行

     /* 
         * args[0] : shell 命令  如"ls" 或"ls -1"; 
         * args[1] : 命令执行路径  如"/" ; 
         */
        public static String execute(String[] cmmand, String directory) throws IOException
        {
            String result = "";
            try
            {
                ProcessBuilder builder = new ProcessBuilder(cmmand);
                if (directory != null)
                {
                    builder.directory(new File(directory));
                }
    
                builder.redirectErrorStream(true);
                Process process = builder.start();
                InputStream is = process.getInputStream();
                byte[] buffer = new byte[256];
    
                int readlen = 0;
                while ((readlen = is.read(buffer)) != -1)
                {
                    byte[] str = new byte[readlen];
                    for (int i = 0; i < readlen; i++)
                    {
                        str[i] = buffer[i];
                    }
                    result = result + new String(str);
                }
                is.close();
            } catch (Exception e)
            {
                e.printStackTrace();
            }
            return result.substring(0, result.length() - 1);
        }
    
        public static List<String> newExecCmd(String[] arr)
        {
            List<String> result = null;
            Process proc = null;
            try
            {
                proc = Runtime.getRuntime().exec("/system/bin/sh", null, new File("/system/bin")); // android中使�?
            } catch (IOException e)
            {
                e.printStackTrace();
            }
            if (proc != null)
            {
                BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
                PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
                        proc.getOutputStream())), true);
                result = new ArrayList<String>();
                for (int i = 0; i < arr.length; i++)
                {
                    out.println(arr[i]);
                }
                out.println("exit");
                try
                {
                    String line;
                    while ((line = in.readLine()) != null)
                    {
                        result.add(line);
                    }
                    // proc.waitFor(); //上面读这个流是阻塞的,所以waitfor 没太大必要�?
                    in.close();
                    out.close();
                    proc.destroy();
                } catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
            return result;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    但是使用后,并没有什么卵用,我起初看log 中有avc 的提示,以为是selinux 的问题,没想到关掉selinux 的权限后,也没效果。我这条命令是在系统应用中执行的,权限我应该很大的。所以应该也不是应用的权限问题。

    我甚至写了个jni,在c中调用也不行。

    3.C 直接调用

    最后,说实话,我也没找到原因。应该还是权限的问题。这个iptables 命令,只能在底层执行。所以,就要从上层调用底层,换句话说,也就是底层要提供接口给上层调用。于是乎,我就在源码里面搜索与iptables 有关的代码。还真的搜索了(这里是MTK 封装实现的,是通过hidl 调用的)。

    1. 底层执行iptables 命令

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    2. 接口封装

    在这里插入图片描述

    3.应用调用

    在这里插入图片描述

    这样就可以将上层用户想要设置的命令执行成功。不过这个iptables 只一次生效。如果机器重启,则规则失效。是需要重新设置的。建议将需要的规则写在sh 脚本里面。然后在开机的时候重新执行下。像下面这样。

    在这里插入图片描述

  • 相关阅读:
    企业在线培训场景下讲师+ppt课件直播应用效果
    鸿蒙开发(四)-低代码开发
    Yii2 一个隐藏的小坑,致使我的组件的 bootstrap 方法执行了多次
    【计算框架】协程库Argobots
    Java项目:ssm毕业论文管理系统
    SimpleDateFormat线程安全问题排查
    药物与生物大分子的相互关系(分子与药物以及人体关系)
    自动生成图片及修改图片尺寸
    数据结构之洗牌算法
    UVA-1602 网格动物 题解答案代码 算法竞赛入门经典第二版
  • 原文地址:https://blog.csdn.net/xct841990555/article/details/126741155