Android动态屏蔽IP地址

Posted Kevin张俊杰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android动态屏蔽IP地址相关的知识,希望对你有一定的参考价值。

我们想实现这样一个需求:当android设备假待机(屏幕休眠)的时候,屏蔽某些IP地址,唤醒时解除屏蔽。同时要屏蔽的IP可以动态配置。

一、如何屏蔽IP地址

这里就要使用到iptables防火墙工具。

iptables 是 Linux 防火墙系统的重要组成部分,iptables 的主要功能是实现对网络数据包进出设备及转发的控制。当数据包需要进入设备、从设备中流出或者由该设备转发、路由时,都可以使用 iptables 进行控制。

iptables 默认维护着 4 个表和 5 个链,所有的防火墙策略规则都被分别写入这些表与链中。

“四表”是指 iptables 的功能,默认的 iptable s规则表有 filter 表(过滤规则表)、nat 表(地址转换规则表)、mangle(修改数据标记位规则表)、raw(跟踪数据表规则表):

  • filter 表:控制数据包是否允许进出及转发,可以控制的链路有 INPUT、FORWARD 和 OUTPUT。
  • nat 表:控制数据包中地址转换,可以控制的链路有 PREROUTING、INPUT、OUTPUT 和 POSTROUTING。
  • mangle表:修改数据包中的原数据,可以控制的链路有 PREROUTING、INPUT、OUTPUT、FORWARD 和 POSTROUTING。
  • raw表:控制 nat 表中连接追踪机制的启用状况,可以控制的链路有 PREROUTING、OUTPUT。

“五链”是指内核中控制网络的 NetFilter 定义的 5 个规则链。每个规则表中包含多个数据链:INPUT(入站数据过滤)、OUTPUT(出站数据过滤)、FORWARD(转发数据过滤)、PREROUTING(路由前过滤)和POSTROUTING(路由后过滤),防火墙规则需要写入到这些具体的数据链中。

如果是外部主机发送数据包给防火墙本机,数据将会经过 PREROUTING 链与 INPUT 链;如果是防火墙本机发送数据包到外部主机,数据将会经过 OUTPUT 链与 POSTROUTING 链;如果防火墙作为路由负责转发数据,则数据将经过 PREROUTING 链、FORWARD 链以及 POSTROUTING 链。

iptables 命令触发动作及各自的功能如下所示:

触发动作功能

  • ACCEPT 允许数据包通过
  • DROP 丢弃数据包
  • REJECT 拒绝数据包通过
  • LOG 将数据包信息记录 syslog 曰志
  • DNAT 目标地址转换
  • SNAT 源地址转换
  • MASQUERADE 地址欺骗
  • REDIRECT 重定向

内核会按照顺序依次检查 iptables 防火墙规则,如果发现有匹配的规则目录,则立刻执行相关动作,停止继续向下查找规则目录;如果所有的防火墙规则都未能匹配成功,则按照默认策略处理。使用 -A 选项添加防火墙规则会将该规则追加到整个链的最后,而使用 -I 选项添加的防火墙规则则会默认插入到链中作为第一条规则。

对规则的查看需要使用如下命令:
iptables -nvL --line-number

-L 查看当前表的所有规则,默认查看的是filter表,如果要查看NAT表,可以加上-t NAT参数
-n 不对ip地址进行查,加上这个参数显示速度会快很多
-v 输出详细信息,包含通过该规则的数据包数量,总字节数及相应的网络接口
–line-number 显示规则的序列号,这个参数在删除或修改规则时会用到
eg: iptables -nvL wan_ip_filter

了解了iptables的知识后,现在就开始设计屏蔽规则:

#限制IP或主机
iptables -t filter -N wan_ip_filter
iptables -t filter -A wan_ip_filter -s $ipaddress/$hostname -j DROP
iptables -I INPUT -j wan_ip_filter
#解除限制
iptables -t filter -F wan_ip_filter

二、如何在程序中执行指令

这里我们采用shell脚本的方式,在shell脚本的开头往往有一句话来定义使用哪种sh解释器来解释脚本。
目前常见的shell脚本中主要有以下两种方式:
(1) #!/bin/sh
(2) #!/bin/bash

注意:每个脚本开头都使用"#!",#!实际上是一个2字节魔法数字,这是指定一个文件类型的特殊标记,在这种情况下,指的就是一个可执行的脚本。在#!之后,接一个路径名,这个路径名指定了一个解释脚本命令的程序,这个程序可以是shell,程序语言或者任意一个通用程序。

sh是bash的一种特殊的模式,也就是 /bin/sh 相当于 /bin/bash --posix, 说白了sh就是开启了POSIX标准的bash.

start_ip_filter.sh
#!/system/bin/sh
echo "start ip filter"
ipgroup=`getprop persist.sys.tr069.ip_filter`
echo "orgin ipgroup = $ipgroup"
ipgroup=$ipgroup// / 
echo "final ipgroup = $ipgroup"
iptables -t filter -N wan_ip_filter
iptables -t filter -A wan_ip_filter -s $ipgroup -j DROP
iptables -I INPUT -j wan_ip_filter
echo "ip filter finished"
stop_ip_filter.sh
#!/system/bin/sh
echo "stop ip filter"
iptables -t filter -F wan_ip_filter
echo "ip filter stopped"

三、何时何地执行脚本命令

我们将脚本预置在/system/bin目录,然后在init.rc中定义两个服务。

init.rc脚本是由Android中linux的第一个用户级进程init进行解析的。init是由Android的Linux内核启动的第一个第一个进程,这个进程非常特殊,它的PID永远是1,并且这个进程是不会死亡的,如果它死亡,内核就会崩溃。init进程启动后会fork出很多及其重要的系统进程,比如我们做应用开发的时候都耳熟能详的zygote进程,我们所有的应用程序的进程都由zygote拉起。

init.rc 文件并不是普通的配置文件,而是由一种被称为Android初始化语言Android Init Language,这里简称为AIL)的脚本写成的文件。

init.rc是一个规定init进程行为和动作的配置文件。

init.rc文件中只包含两种声明,on和service,我们可以把on称为行为,把service称为服务。

该文件在ROM中是只读的,即使有了root权限,可以修改该文件也不会生效,因为我们在根目录看到的文件只是内存文件的镜像。

init.rc脚本包括了文件系统初始化、装载的许多过程。

init.rc的工作主要是:
1)设置一些环境变量
2)创建system、sdcard、data、cache等目录
3)把一些文件系统mount到一些目录去,如mount tmpfs tmpfs /sqlite_stmt_journals
4)设置一些文件的用户群组、权限
5)设置一些线程参数
6)设置TCP缓存大小

service ip_filter_start /system/bin/start_ip_filter.sh
	class main
	oneshot
	disabled
	
service ip_filter_stop /system/bin/stop_ip_filter.sh
	class main
	oneshot
	disabled

定义完脚本服务后,我们在待机属性所定义的行为那里启动对应的服务:

on property:sys.switch.screen=on
	start ip_filter_stop

on property:sys.switch.screen=off
	start ip_filter_start

待机property属性值在Android的PhoneWindowManager.java假待机按键事件中设置,这里因为不是真待机,不涉及到PowerManagerService.java调用。

四、如何做到动态配置

这里就要使用到TR069网管协议,TR069是CPE和 ACS 之间沟通的通讯协定,CPE 可以借着这个协定完成服务开通、功能设定、档案上传下载、系统检测等运营管理的必须动作。

  • 定义节点数据模型

    <schema name="FirstLevel" type="object">
         <schema name="SecondLevel" type="object">
    		<schema name="IpFilter" type="string" constraint="92" write="W" inform="true" getter="tr069_get_ip_filter" setter="tr069_set_ip_filter"/>			
    	 </schema> 
    </schema>
    
  • CPE端实现get/set方法

    DLLEXPORT_API int tr069_get_ip_filter(struct evcpe_attr *attr, const char **value, unsigned int *len)
    
    	static char buffer[92] = 0;
    	memset(buffer, 0, sizeof(buffer));
    	property_get("persist.sys.tr069.ip_filter", buffer, "0");
    
    	*value = buffer;
    
    	if(*value != NULL) 
    		*len = strlen(*value);
    	
    	else 
    		*len = 0;
    	
    	evcpe_info(__func__ , ">>>, [%s:%d] get buf:%s", __FUNCTION__, __LINE__, buffer);
    	return 0;
    
    
    DLLEXPORT_API int tr069_set_ip_filter(struct evcpe_attr *attr, const char *buffer, unsigned int len)
    
    	char buffer_local[92] = 0;
    	int  len_local = sizeof(buffer_local);
    	evcpe_info(__func__ , ">>>, [%s:%d] set buffer: %p, len: %d", __FUNCTION__, __LINE__, buffer, len);
    	if ((buffer == NULL) || (len < 0)) 
    		return -1;
    	
    
    	len_local = len_local > len ? len : len_local - 1;
    	strncpy(buffer_local, buffer, len_local);
    	property_set("persist.sys.tr069.ip_filter", buffer_local);
    	
    	evcpe_info(__func__ , ">>>, [%s:%d] set buffer_local: %s, len_local: %d", __FUNCTION__, __LINE__, buffer_local, len_local);
    	
    	return 0;
    
    

五、如何预置屏蔽的IP

我们可以在系统预置一些黑名单IP,这里就要用到Android的build.prop,该文件是在Android编译时收集的各种property,编译完成后,文件生成在out/target/product/<board>/system/目录下。在Android运行时可以通过property_get()[c/c++域] / SystemProperties_get*()[Java域]读取这些属性值。

buildinfo.sh脚本就是专门用于生成build.prop文件,build.prop的生成是由make系统解析build/core/Makefile完成,并把系统默认的system.prop以及定制的system.prop中的设定追加到build.prop文件中。

buildinfo.sh很简单,只是echo一些属性。

  • Makefile中首先定义各种变量,这在下一步执行时会用到,比如:

    PRODUCT_DEFAULT_LANGUAGE="$(calldefault-locale-language,$(PRODUCT_LOCALES))" \\
    PRODUCT_DEFAULT_REGION="$(calldefault-locale-region,$(PRODUCT_LOCALES))" \\
    
  • Makefile中调用build/tools/buildinfo.sh执行脚本,并输出到build.prop

    buildinfo.sh很简单,只是echo一些属性,比如:

    echo"ro.product.locale.language=$PRODUCT_DEFAULT_LANGUAGE"
    echo"ro.product.locale.region=$PRODUCT_DEFAULT_REGION"
    

    ro.product.locale.language/ ro.product.locale.region就是定义的某些属性,等号后面是值。

  • Makefile中直接把$(TARGET_DEVICE_DIR)/system.prop的内容追加到build.prop中

  • 收集ADDITIONAL_BUILD_PROPERTIES中的属性,追加到build.prop中

    ADDITIONAL_BUILD_PROPERTIES又会收集PRODUCT_PROPERTY_OVERRIDES中定义的属性

    ADDITIONAL_BUILD_PROPERTIES:= \\
            $(ADDITIONAL_BUILD_PROPERTIES)\\
            $(PRODUCT_PROPERTY_OVERRIDES)
    

通过build.prop生成过程的分析,我们可以知道哪里能修改原有的属性或加入自定义属性,那就是buildinfo.sh, system.prop, ADDITIONAL_BUILD_PROPERTIESPRODUCT_PROPERTY_OVERRIDES.

不过个人建议在system.propPRODUCT_PROPERTY_OVERRIDES修改,这对应于具体特定的平台或产品。

这里具体实现,是在system.prop添加如下语句:

#prevent report by ip
persist.sys.tr069.ip_filter=192.168.1.1,www.baidu.com

以上是关于Android动态屏蔽IP地址的主要内容,如果未能解决你的问题,请参考以下文章

手机安装器糟攻击怎么办

关于 Apache 屏蔽 IP 地址

自己家用电脑做站点server,解决动态IP无公网IP80port被封HTTP被屏蔽

Android 如何从设备中查找动态 IP? [复制]

如何在Linux下大量屏蔽恶意IP地址

Android 设备是不是有静态 IP 地址?