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.propbuildinfo.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_PROPERTIES
或PRODUCT_PROPERTY_OVERRIDES
.
不过个人建议在system.prop
或PRODUCT_PROPERTY_OVERRIDES
修改,这对应于具体特定的平台或产品。
这里具体实现,是在system.prop
添加如下语句:
#prevent report by ip
persist.sys.tr069.ip_filter=192.168.1.1,www.baidu.com
以上是关于Android动态屏蔽IP地址的主要内容,如果未能解决你的问题,请参考以下文章