详细文档:https://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html
1 iptables的原理以及命令
首先,什么是包过滤?
包过滤是当一个数据包通过时,使用软件去查看包头信息并决定对该包的处理方式。你可以丢弃该数据包、接受该数据包亦或是其他更复杂的处理方式。
在Linux中包过滤已经集成到内核中了,甚至还可以做一些数据包欺骗,但基本原则还是查看数据包头并决定处理方式。
linux集成了netfilter库,netfilter工作在tcp/ip协议栈网络层(可以看到tcp头,ip头,mac地址等信息)。然后提供五个hook点,用其他内核模块注册使用,对于iptables内核模块,就注册了这些hook函数,进行工作,iptables工具是提供的操作iptables操作内核模块的工具,前者提供机制 是内核过滤的基础架构,后者是用户工具,用来编辑具体的过滤规则提供给内核netfilter。下面是五个hook点的示意图
五个hook点
这五个点就是一个数据包进入主机后要经过的路径,一种是发给本机的包,另一种是需要forward的包,流程图如下所示
iptables正式在这五个点根据用户配置的规则进行数据包的处理。大概就是这个原理。
对于数据包的处理可以分为三种类型
1 nat 转发(改变目标地址或源地址)
2 mangle 修改
3 filter 过滤
所以提供了三张表用于保存这些规则,三张表的名字分别是nat,filter和mangle,当请求进入主机的时候,经过的处理流程大致如吐下
iptables表规则执行流程
三张默认的表中包含一些规则链,默认的链有INPUT、OUTPUT、PREROUTING、POSTROUTING、FORWARD,分别用于保存五个hook点所执行的操作。
备注:Linux防火墙所有的规则被保存在表中,默认Iptables防火墙有4个表:filter表(实现过滤功能),nat表(实现地址转换功能), mangle表(修改数据包的TOS、TTL等信息),raw表(实现数据包跟踪功能)
每个表中有多个数据链,而我们的具体规则被分门别类的链中。以下是每个表中的默认链:
filter表:INPUT链(入站数据过滤),FORWARD链(转发数据过滤),OUTPUT链(出站数据过滤)
nat表:PREROUTING链,POSTROUTING链,OUTPUT链
mangle表:PREROUTING链,POSTROUTING链,INPUT链,OUTPUT链,FORWARD链
raw表:OUTPUT链,PREROUTING链
明白了大致流程后就可以进行规则编写了,就要说说iptables的基本命令
命令大致格式如下
iptables [-t table] command [match] [target/jump]
1 table
-t指定table,默认filter表
2 Commands 名令
表示要执行的操作,如添加链,增删改规则等
-A 追加新的规则
-D 删除旧的规则
-R 替换旧的规则(链中根据编号)
-I 指定序号插入,插入新的规则,默认序号是1 也就是插入到最前面,注意规则执行时是按照链中规则的顺序执行的
-L 显示规则链
-F 清除链中的规则
-Z 将包过滤统计信息清零
-X 删除链(保证不被引用)
-N 创建新的自定义规则链
-P 改变默认策略,默认的target(不符合规则默认的target,见后面target节)
3 match 匹配条件,满足匹配条件的包会执行后面的target,其他的走下链中下一个规则,否则返回父链
-p 协议
-s 源地址
-d 目的地址
-i 进入网卡
-o 出去网卡,用来比对封包要从哪片网卡送出,其中wifi有三种(参考droidwall):tiwlan+, wlan+, eth+
gprs有六种:rmnet+,pdp+,ppp+,uwbr+,wimax+,vsnet+
-f 分片
-sport 源端口
-dport 目的端口
--tcp-flags
--tcp-flags [!] mask comp
匹配指定的TCP标记。第一个参数是我们要检查的标记,一个用逗号分开的列表,第二个参数是用逗号分开的标记表,是必须被设置的。标记如下:SYN ACK FIN RST URG PSH ALL NONE。因此这条命令:iptables -A FORWARD -p tcp --tcp-flags SYN, ACK, FIN, RST SYN只匹配那些SYN标记被设置而ACK、FIN和RST标记没有设置的包。
[!] --syn
只匹配那些设置了SYN位而清除了ACK和FIN位的TCP包。这些包用于TCP连接初始化时发出请求;例如,大量的这种包进入一个接口发生堵塞时会阻止进入的TCP连接,而出去的TCP连接不会受到影响。这等于 --tcp-flags SYN, RST, ACK SYN。如果"--syn"前面有"!"标记,表示相反的意思。
--tcp-option [!] number
匹配设置了TCP选项的。
--limit 限制条件 如每小时三个请求
--limit-burst 待匹配包初始个数的最大值:若前面指定的极限还没达到这个数值,则概数字加1.默认值为5
--mac-source 匹配物理地址。必须是XX:XX:XX:XX:XX这样的格式。注意它只对来自以太设备并进入PREROUTING、 FORWORD和INPUT链的包有效。
--uid-owner 如果给出有效的user id,那么匹配它的进程产生的包。
--gid-owner 如果给出有效的group id,那么匹配它的进程产生的包。
--pid-owner
owner
此模块试为本地生成包匹配包创建者的不同特征。只能用于OUTPUT链,而且即使这样一些包(如ICMP ping应答)还可能没有所有者,因此永远不会匹配。
--state (INVALID,ESTABLISHED,NEW 和 RELATED) 这里state是一个逗号分割的匹配连接状态列表。可能的状态是:INVALID表示包是未知连接,ESTABLISHED表示是双向传送的连接,NEW表示包为新的连接,否则是非双向传送的,而RELATED表示包由新连接开始,但是和一个已存在的连接在一起,如FTP数据传送,或者一个ICMP错误。
--tos 这个参数可以是一个标准名称,(用iptables -m tos -h 察看该列表),或者数值。
tos
此模块匹配IP包首部的8位tos(服务类型)字段(也就是说,包含在优先位中)。
4 Targets/Jumps 后面有不同的参数,请查表
ACCEPT 之后不会匹配这个链的其他
DROP 直接丢弃,进行完此处理动作后,将不再比对其它规则,直接中断过滤程序。
REJECT 拒绝,不直接丢弃,返回错误给对方
DNET | SNET 转发
ULOG| NFLOG|LOG
MARK 用来设置包的netfilter标记值。只适用于mangle表
MASQUEREAD
QUEUE 排队
REJECT 拦阻该封包,并传送封包通知对方
REDIRECT 只适用于nat表的PREROUTING和OUTPUT链,和只调用它们的用户自定义链。它修改包的目标IP地址来发送包到机器自身(本地生成的包被安置为地址127.0.0.1)。它包含一个选项:
--to-ports <port>[<port>]
指定使用的目的端口或端口范围:不指定的话,目标端口不会被修改。只能用于指定了-p tcp 或 -p udp的规则。
RETURN 返回
TOS
TTL
日志记录,iptables提供三种方式,取决于编译选项。包括LOG(打印打/proc/dmesg)
ULOG 通过netlinker将log从内核发送给用户空间,单向
NFLOG通过netlinker将log从内核发送给用户空间,双向
netlinker在内核和用户空间创建socket通信,通过多播的形式将内核log送往用户空间。
对于android中的iptables只提供了ulog和nflog的方式读取log。需要写一个程序从nflog中读取数据,参考
http://www.netfilter.org/projects/libnetfilter_log/doxygen/nfulnl__test_8c_source.html
iptables:该工具可以添加删除具体的过滤规则至内核包过滤表。这也意味着无论你如何设置防火墙规则,一旦机器重启所有的规则将丢失。
永久保存规则:你设置的防火墙规则被保存在内核中,但重启会丢失。你可以使用iptables-save和iptables-restore脚本实现永久保存与恢复。
操作单条规则
这是最基本的包过滤操作。通常你需要使用-A或-D命令选项,有时你还会使用到-I与-R命令选项。
每条规则需要指定匹配条件以及匹配后的处理方式(ACCEPT允许,DROP丢弃,REJECT拒绝,LOG日志等),如:你可能希望丢弃素有本地回环(127.0.0.1)的ICMP数据包,这样我们的匹配条件是:ICMP协议并且源地址是127.0.0.1 匹配后做DROP处理。
127.0.0.1是本地回环接口,即使你没有物理网卡,该接口一样存在。你可以使用ping命令产生这类数据包。
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=21.9 ms
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 21.966/21.966/21.966/0.000 ms
# iptables -A INPUT -s 127.0.0.1 -p icmp -j DROP 添加一条规则
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
你可以看到第一次ping是成功的(-c 1 说明仅ping一次),然后我们追加了一条规则到INPUT链,该规则指定从127.0.0.1发送的ICMP协议的数据包将被丢弃。第二次再执行ping命令所有的数据100%丢失。
我们有两种方式可以删除规则,首先我们知道INPUT链中只有一条规则,我们可以使用编号删除:
#iptables -D INPUT 1 // 删除INPUT链中的第一条规则
第二种方法类似与-A选项,使用-D替换-A。当你的规则比较复杂并搞不清编号时可以使用这种方式:
#iptables -D INPUT -s 127.0.0.1 -p icmp -j DROP
特定过滤规则
源地址与目标地址
源地址(-s,--source或--src),目标地址(-d,--destination或--dst)有四种使用方式:
最常用的是使用名称,比如"localhost"或者"http://www.kernel.org"。
第二种方法是使用IP地址如"127.0.0.1"。
第三四种方法可以匹配IP地址区域,如"199.95.207.0/24"或"199.95.207.0/255.255.255.0"。它们都可以匹配199.95.207.0到199.95.207地址,可以使用0/0匹配所有地址。
# iptables -A INPUT -s 0/0 -j DROP 拒绝所有源地址访问本机
取反匹配
很多标签"-s","-d"等都可以在后面添加"!"以表示否定匹配,如"-s ! localhost"将匹配所有非本地源地址。
协议匹配
匹配协议可以使用-p标签,协议的指定可以使用数字编号(如果你知道协议的编号)或使用名称(如"TCP","UDP","ICMP"等)。协议名称前可以添加"!"如"-p ! TCP"匹配所有非TCP协议数据包。
接口匹配
"-i(--in-interface)"和"-o(--out-interface)"匹配指定的接口。接口是真实的物理网卡接口,-i(数据包从哪个网卡进来的),
-o(数据从哪个网卡出去的)。你可以使用ifconfig命令查看哪些接口是开启的。
注意:在INPUT链不可以使用-o选项,因为入站的数据不走出站接口。所以在INPUT链中的-o规则将无法匹配任何数据。
同理,在OUTPUT链中不可以使用-i选项。
数据段匹配
很多数据包因为太大无法一次完成数据的传输。此时数据包将被分割为数据片段再发送出去。接收端接受完数据后将把这些数据片段重新组合成完整的数据包。
但问题在于当数据被分割后,只有前面的初始数据片段包含全部的数据头部信息(IP,TCP,UDP,ICMP等),
后续的数据片段仅包含数据包头部信息的一部分信息。这时去再检查后续数据片段的头部信息是不可能的。
当然,如果你想匹配第二个及后面被分片的数据,可以使用"-f"选项。
# iptables -A OUTPUT -f -d 192.168.1.1 -j DROP //丢弃发送至192.168.1.1的所有数据以及分片数据
扩展iptables规则
iptables有很好的可扩展性,也就是说内核架构与iptables工具都可以添加扩展功能。
内核功能扩展一般放在内核模块子目录中:/lib/modules/2.6.32-220.el6.i686/kernel/net/netfilter(这里以CentOS6.2为例)。这些模块在你使用iptables时会自动加载。
mac
该模块需要使用"-m mac"选项启用,这对应过滤进站数据包的源MAC地址很用帮助。-m 即match匹配的意思。
#iptables -I INPUT -m mac --mac-source 00:60:08:91:CC:B7 -j REJECT //拒绝MAC地址为00:60:08:91:CC:B7的数据包进入
limit
该模块需要使用"-m limit"选项启用,该功能对限制网速很有效。
#iptables -A OUTPUT -p tcp -m limit --limit 100/s -j ACCEPT // 每秒包个数100以内将允许发送
#iptables -P OUTPUT REJECT // 默认拒绝所有
说明:以上两条可以实现,当每秒包个数大于100时,拒绝所有连接。
状态匹配
该模块需要使用"-m state"选项启用,数据包的状态包括:NEW,ESTABLISHED,RELATED,INVALID
NEW:创建连接的数据包
ESTABLISHED:通过已经创建的连接通道 传输的数据包
RELATED:与已经创建的连接相关的数据包,如ICMP错误数据包
INVALID:无法识别的数据包
#iptables -A INPUT -m state --state NEW -j DROP //拒绝进站的连接请求(外网无法访问本机)
#iptables -A INPUT -m state --state RESTABLISHED,RELATED -j ACCEPT //允许外网数据对本机的回应信息
#iptables -P OUTPUT ACCEPT //允许访问外网
mark模块介绍
MARK标记用于将特定的数据包打上标签,供iptables配合TC做QOS流量限制或应用策略路由。
mark字段的值是一个无符号的整数,在32位系统上最大可以是4294967296(就是2的32次方),这足够用的了。
比如,我们对一个流或从某台机子发出的所有的包设置了mark值,就可以利用高级路由功能来对它们进行流量控制等操作了。
mark值不是包本身的一部分,而是在包穿越计算机的过程中由内核分配的和它相关联的一个字段。它可能被用来改变包的传输路径或过滤。mark值只在本机有意义!
在本机给包设置关联的mark值后,可通过该值对包后续的传输进行控制(排队,流量控制等)。
看看和MARK相关的有哪些模块:
ls /usr/lib/iptables/|grep -i mark
libxt_CONNMARK.so
libxt_MARK.so
libxt_connmark.so
libxt_mark.so
其中大写的为标记模块,小写的为匹配模块,它们之间是相辅相成的,分别作用如下:
iptables -j MARK --help
--set-mark #标记数据包
iptables -t mangle -A PREROUTING -p tcp -j MARK --set-mark 1
#所有TCP数据标记1
iptables -m mark --help
--mark value #匹配数据包的MARK标记
iptables -t mangle -A PREROUTING -p tcp -m mark --mark 1 -j CONNMARK --save-mark
#匹配标记1的数据并保存数据包中的MARK到连接中
iptables -j CONNMARK --help
--set-mark #标记连接
--save-mark #保存数据包中的MARK到连接中
--restore-mark #将连接中的MARK设置到同一连接的其它数据包中
iptables -t mangle -A PREROUTING -p tcp -j CONNMARK --set-mark 1
iptables -m connmark --help
--mark value #匹配连接的MARK的标记
iptables -t mangle -A PREROUTING -p tcp -m connmark --mark 1 -j CONNMARK --restore-mark
#匹配连接标记1并将连接中的标记设置到数据包中
#mark的格式是--mark value[/mask],如上面的例子是没有掩码的,带掩码的例子如--mark 1/1。如果指定了掩码,就先把mark值和掩码取逻辑与,然后再和包的mark值比较。
说明:
1、以前MARK标记只能用在mangle表上,而现在可以使用在nat表上。
2、MARK标记不能作为扩路由的传递,只能在内核上传递。如果要实现,那么可以使用TOS标记。
3、使用时注意iptables的版本,不同的版本支持的方法不一样。
通过string匹配域名来过滤
iptables -I OUTPUT -p tcp -m string --string "qq.com" --algo bm -j DROP
iptables -I OUTPUT -p udp -m string --string "qq.com" --algo kmp -j DROP
--algo 设置字符匹配的查询算法,一般默认使用bm算法效果就可以了,另外还可以设置kmp算法,那是一种更复杂的算法
--string 指定要匹配的字符串
--from 指定搜索包的开始位置,默认0
--to ,默认包大小
排除建议
1.注意过滤规则的顺序,如果规则的第一条拒绝所有tcp连接,第二条允许192.168.1.1访问本机的tcp连接,则第二条将无效。
#iptables -A INPUT -p tcp -j DROP
#iptables -A INPUT -p tcp -s 192.168.1.1 -j ACCEPT
以上两条规则由于第一条规则已经丢弃所有的tcp数据包,所以不会再匹配第二条规则。
2.设置完规则后未保存,导致重启后所有规则丢失。解决方法:可以使用iptables-save,或service iptables save实现永久保存
#iptables-save > /etc/sysconfig/iptables
#service iptables save
以上以CentOS为例,两天命令任选其一即可永久保存。
3.无效的规则及时删除,否则影响效率。
4.匹配端口号时必须指定协议,否则会报错。
5.公司有FTP服务器时,提前加载ftp模块:#modprobe ip_nat_ftp
----------------------------------------------------------------------------------
app联网白名单实现思路:
通过iptables命令设置filter表,针对OUTPUT链,来源是wifi或是2g/3g的做REJECT或是DROP操作。
REJECT和DROP其效果都可以使app无法联网,所以两个任你选择使用。
iptables -t filter -A OUTPUT -o wlan+ -m owner --uid-owner 10042 -j DROP
说明:操作filter(-t filter可以省略,默认操作filter表)的OUTPUT链,封包出口是wlan+,并且来源是uid为10042的,丢弃数据包。
----------------------------------------------------------------------------------
app网络访问控制
以10060为UC使用的规则链(chain)名。
// 创建规则链,链名为10060
iptables -N 10060
// 执行下面命令将规则链10060与UC浏览器关联:
iptables -A OUTPUT -m owner --uid-owner 10060 -j 10060
语义说明:向OUTPUT规则链附加一条规则:如果IP信息报匹配到uid是10060,则跳转(-j)到规则链10060。
iptables支持区分不同的uid以跳转到不同的规则链。通过iptables -L可以查询到当前内核已有的规则链。
其中OUTPUT是内核自动创建的处理本地生成的IP信息包的规则链。
在具体配置规则链10060之前,可以运行下面命令将10060内容清掉:
iptables -F 10060
在OUTPUT中添加规则链,利用Http协议中的Host头域,只放行白名单域名的请求。能更好的地实现白名单需求。
第3步:配置访问规则
白名单功能:
// 允许访问某一域名(www.abc.com)禁止访问其他域名
iptables -A 10060 -p tcp -m string --string Host: --algo bm -j MARK --set-mark 1
iptables -A 10060 -p tcp -m mark --mark 1 -m string --string abc --algo bm -j ACCEPT
iptables -A 10060 -p tcp -m mark --mark 1 -j REJECT
黑名单功能:
//禁止访问某一域名(www.abc.com)允许访问其他域名
iptables -A 10060 -m string --string abc --algo bm -j REJECT
iptables -A 10060 -j ACCEPT
说明:对于黑名单,逻辑比较简单,只要把所有包含abc的IP包REJECT即可,其余的ACCEPT,即使没有第二条命令,默认也是ACCEPT。
对于白名单,针对Host头域,原因如上。对于包含Host的IP包先做一次mark(标记),然后对此标记的IP包判断是否包含abc。
二、Iptables网络黑白名单(防火墙)实现细节
因为考虑到一些权限的问题所以在实现方法上采用的是创建一个systemserver来运行这些方法。并提供出manager到三方应用,这样在调用时可以排除一些权限的限制。同时本文只是做一个简单的参考概述,所以在后文中只提供了增加黑白名单的方法和iptables规则,并没有提供相应的删除规则等,原理类似大家可自行补充添加。
2.1、创建systemserver
2.1.1、 在/system/sepolicy/service.te中添加
1 |
|
2.2.2、在/system/sepolicy/service_contexts中添加如下,
1 |
|
2.2.3、在frameworks/base/core/java/android/content/Context.java中添加
也可以不添加这个,只不过为了后面调用方便所以添加了。如果跳过此步,那么后面出现Context.FXJNET_SERVICE的地方都用字串代替即可。
1 |
|
2.2.4、在/frameworks/base/core/java/android/app/SystemServiceRegistry.java的静态代码块中添加如下代码注册service。
1 2 3 4 5 6 7 8 |
|
2.2.5、在frameworks/base/services/java/com/android/server/SystemServer.java中添加如下代码,将service加入systemserver中。
1 |
|
2.2.6 、在源码frameworks/base/core/java/android/os/ 下面新增 一个 AIDL文件
1 2 3 4 |
|
2.2.7、提供给外部的FXJNETManager,在frameworks/base/core/java/android/app/ 下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
2.2.8、系统服务即AIDL的实现server, frameworks/base/services/core/java/com/android/server/ 下
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 |
|
2.2.9、运行IPTABLES脚本命令的工具类
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 |
|
三、fxjmotnitor service的创建步骤如下。
3.1、在/system/core/rootdir/init.rc中添加如下,使得service在开机时就运行起来
1 2 3 4 |
|
3.2、在/sepolicy/目录下创建fxjmotnitor.te文件,内容如下
1 2 3 4 |
|
3.3、在/sepolicy/file_contexts中添加
1 |
|
3.4、在sepolicy/Android.mk中的
1 2 3 4 5 |
|
参考
https://www.jianshu.com/p/b96d7036e994
https://www.jianshu.com/p/c500dc5a13b0
https://blog.csdn.net/zhanglianyu00/article/details/50177873