这两天在学习iptables
,感觉这个东西实在是太牛逼!想用两篇博文来介绍一番。
第一篇会介绍下netfilter和iptables的关系,以及iptables的原理;第二篇希望通过libipq
和nfqueue-bindings-python
来介绍下user态如何利用C和Python来调用iptables的接口获得封包的信息。
netfilter
简单地说,netfilter是一套在计算机网络栈中过滤和修改封包的框架,它的做法是在Linux Kernel中插入了一系列的hook,并允许kernel在不同层的网络栈中注册回调函数,这些回调函数会在封包进入相应的hook的时候被调用到。
网络栈中对netfilter的支持如图所示:
可以看到在链路层和网络层中按照封包流的路径有五种类型的hooks: prerouting, input, forward, output, postrouting。这五种hooks会在封包到达之时按照封包流的顺序调用相应的回调函数,对四种类型的表中的chain(会在iptables中描述)进行过滤和修改:filter, nat, mangle, raw。而定义这些过滤的规则则是由一个用户态的命令iptables
进行配置,也就是我接下来要详细描述的命令。
iptables
这里有6篇系列的文章介绍iptables的,讲的挺清楚,蛮适合入门学习的。
前面说过iptables有四种类型的表:filter,nat,mangle,raw,这里只是对filter表进行介绍:
filter表主要用于对封包进行过滤,在该表中有三条默认的chain:INPUT,FORWARD,OUTPUT。
chain是做什么的呢?(转自这里)
所謂chain就是一組封包過濾規則,您可以在INPUT chain中加入一條防止所有外界封包進入的規則;您可以在OUTPUT chain中加入一條防止用戶連接某網頁伺服器。準備進入網絡的封包,會順著chain內的過濾規則被稽核,若果該封包並不符合任何規則,則會直接進入網 內,因為INPUT和OUTPUT在Linux kernel裡被預設為ACCEPT,而FORWARD則被預設為DROP。
比如说,如果要把发到某个地址(如192.168.1.2)的包丢弃,可以这样做:
$ sudo iptables -A OUTPUT -d 192.168.1.2 -j DROP
这里-A
指对OUTPUT这条链的规则进行修改,-d
表示这个封包的destination,-j
后加的是target,有五种选择:ACCEPT(不作任何操作,让封包流过),DROP(将封包丢弃),QUEUE(将封包插入队列,传递到用户态处理,这个会在第二篇中详细描述),RETURN(直接从该chain中返回,到前一个chain的下一条规则继续执行),以及自己定义的CHAIN,如下:
$ sudo iptables -N SELF_CHAIN
也就是说我们可以按照不同的源地址、目标地址、端口、协议等规则分类,由不同的chain进行处理,可以更合理地对过滤条件进行管理。
另外,有几个常用的选项这里提一下:
-A chain # modify a chain
-D chain rulenum # delete a specific rule of chain
-I chain rulenum rule # insert rule in rulenum of chain
-R chain rulenum rule # replace rule with rulenum of chain
-L [chain] # list rules of chain
-F [chain] # flush the rules of chain
-N chain # new a chain
-X [chain] # delete chain
-p protocol # e.g., tcp, udp, icmp...
-s source address # e.g., 192.168.1.22
-d destination address # e.g., 192.168.1.13
-j target # e.g., ACCEPT, DROP, RETURN, QUEUE, other-chain
-i in-interface # e.g., eth0
-o out-interface # e.g., eth0
下一篇主要介绍当iptables
的target是QUEUE或者NFQUEUE时,用户态要如何调用相关接口。
之前讲了关于netfilter和iptables的一些简单的原理和用法,对于iptables来说,如果只能对封包进行DROP、ACCEPT操作,那么就显得太弱了,其实在我看来iptables里面filter表中最牛逼的就在于QUEUE(NFQUEUE)这个target了。
那么当iptables将封包插入QUEUE后,用户态又能用什么方法才能读到queue中的数据呢?
这里介绍两种方法,一种是C语言中使用的libipq
,一种是python中使用的nfqueue
。
libipq
libipq
是一个对开发者提供的用于读取iptables queue的C库,具体的用法可以参看linux man page和这里的用法,需要注意的是在我的机器中必须得再加三个头文件:
#include
#include
#include
另外编译出来的文件必须得用sudo
执行!!!
这里主要用了一个数据结构
1 2 3 |
|
另外需要设置一个模式,这里是IPQ_COPY_PACKET
,即是将queue中的封包的payload和header一起拷贝到用户空间:
1
|
|
之后通过:
1
|
|
将queueu中的封包一个一个拷贝到用户空间,由用户进行操作,用户可以通过:
1
|
|
得到包的类型,可能是NLMSG_ERROR
,也有可能是IPQM_PACKET
,如果是后者,即为一个正常的封包,可以通过类似于如下的代码对封包进行操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
上段代码的意思是先从buf
中获得整个封包m,之后可以通过struct iphdr
和struct tcphdr
获得ip包头和tcp包头,最后有一个最关键的代码:
1
|
|
这里的意思相当于原来在规则中target设为ACCEPT,当然也可以设置成NF_DROP
等。
在这里我有一个疑问,就是这里除了获得struct tcphdr
之外,我没有找到和TCP的payload相关的结构,不知道该如何获得。
nfqueue
和C的libipq比起来,支持python的nfqueue会显得强大很多,特别是和scapy结合起来用的时候。
首先需要说明的是在iptables中的target除了之前提到的五项(ACCEPT,DROP,RETURN,QUEUE,other_chain)之外,还有一个叫NFQUEUE
,它是QUEUE的扩展。相比于QUEUE,它可以由用户指定不同的queue number。
在使用nfqueue之前,需要安装如下的包:
$ sudo aptitude install libnetfilter-queue-dev
$ sudo aptitude install nfqueue-bindings-python
$ sudo aptitude install python-scapy
之后就可以采用python对NFQUEUE进行操作了。
假设我们将封包从主机A(192.168.1.1
)传输到主机B(192.168.1.2
)时,需要对封包进行分析,如果是TCP协议的包,并且其flags为 ACK|PSH 的话,则将其payload进行修改(比如替换成“hack”):
首先,需要先在主机A中对iptables进行操作:
$ sudo iptables -A OUTPUT -d 192.168.1.2 -p tcp -j NFQUEUE
然后利用下面的代码:
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 |
|
这里用到了scapy
这个非常牛逼的模块,它可以直接通过如IP()
,TCP()
等直接对包进行解释和操作,非常方便,具体的可以参看它的文档。这里只是说明下它的安装方式:
$ wget scapy.net
$ mv index.html scapy-latest.zip
$ chmod +x scapy-latest.zip
$ mv scapy-latest.zip /usr/local/bin/scapy
然后就可以运行:
$ sudo scapy
直接开启scapy的交互模式了。
原文出自 : http://ytliu.github.io/blog/archives/ 里面的文章都不错。