iptables深入解析:filter应用篇

上一篇文章分析了iptables代码下发运作的流程细节,篇幅有限还有很多需要补充.关于netfilter的框架网上已经被讲烂了,框架很简单,但是实现却不简单.但不论什么都要最终归到实际应用上,才能体现其价值.

下面我们就以iptables1.4.21 ubuntu14 32位 内核版本 3.13.0为环境来开发一个最常规的扩展应用.

首先下载iptables源码:http://www.netfilter.org (这个网站有很多东西,可以好好看看)

关于linux kernel netfilter开启的配置,这里不多说,默认内核已经配置好了.(当然对于ubuntu14 系统默认把netfilter大部分都编译成了内核模块,需要什么自己手动安装即可)

先说说编译iptables,很简单 看看里面的说明文档即可,例INSTALL:
$./configure
$make
$make install

./configure 还可以支持一些选项参数 ,里面都有说明。例子如下:
./configure –prefix=/home/iptables –host=arm-linux // host可以不指定,自动判定,默认就是x86
这里还要补充点知识:动作的说明:

iptables动作———DROP、ACCEPT、REJECT

◆ACCEPT
一旦包满足了指定的匹配条件,就会被ACCEPT,并且不会再去匹配当前链中的其他规则或同一个表内的其他规则,但它还要通过其他表中的链

◆DROP
如果包符合条件,这个target就会把它丢掉,也就是说包的生命到此结束,不会再向前走一步,效果就是包被阻塞了。在某些情况下,这个target会引起意外的结果,因为它不会向发送者返回任何信息,也不会向路由器返回信息,这就可能会使连接的另一方的sockets因苦等回音而亡:)

解决这个问题的较好的办法是使用REJECT target,(注:因为它在丢弃包的同时还会向发送者返回一个错误信息,这样另一方就能正常结束),尤其是在阻止端口扫描工具获得更多的信息时,可以隐蔽被过滤掉的端口等等(译者注:因为扫描工具扫描一个端口时,如果没有返回信息,一般会认为端口未打开或被防火墙等设备过滤掉了)。还要注意如果包在子链中被DROP了,那么它在主链里也不会再继续前进,不管是在当前的表还是在其他表里。

◆REJECT
REJECT和DROP基本一样,区别在于它除了阻塞包之外,还向发送者返回错误信息。现在,此target还只能用在INPUT、FORWARD、OUTPUT和它们的子链里,而且包含 REJECT的链也只能被它们调用,否则不能发挥作用。它只有一个选项,是用来控制返回的错误信息的种类的。

还有其他的动作:
LOG             用来记录与数据包相关的信息
MARK          设置mark值,这个值是一个无符号的整数
MASQUERADE             和SNAT的作用相同,区别在于它不需要指定–to-source
SNAT             源网络地址转换
DNAT             目的网络地址转换
REDIRECT             转发数据包一另一个端口
REJECT             REJECT和DROP都会将数据包丢弃,区别在于REJECT除了丢弃数据包外,还向发送者返回错误信息
RETURN             使数据包返回上一层
TOS             用来设置IP头部中的Type Of Service字段
TTL             用于修改IP头部中Time To Live字段的值
ULOG             ULOG可以在用户空间记录被匹配的包的信息,这些信息和整个包都会通过netlink socket被多播
QUEUE             为用户空间的程序或应用软件管理包队列
MIRROR             颠倒IP头部中的源目地址,然后再转发包

先一个实际的命令应用:
IPT -A INPUT -m pkttype –pkt-type broadcast -j REJECT
这里我们自己注册一个match 传递自己的参数并解析处理。
功能是禁止大于特定长度的ip报文通过 size由我们指定。

需要两个部分的工作
1.用户空间match的注册
2.内核空间match的注册
根据代码里pkttype的实际例子作为参考,很快我们就能干一票了.

需要修改的文件:

用户空间
Xt_pktsize.c // 路径extensions下
Xt_pktsize.h // 路径 include/linux/netfilter/
内核:这里编译为模块的方式
Xt_pktsize.c
Xt_pktsize.h

注册match当然首先要初始化它各个节点的元素
用户空间代码如下:
xt_pktsize.h

xt_pktsize.c

通过代码我们看到主要工作就是初始化struct xtables_match,然后注册而已. 它的核心函数是x6_parse/parse

或者

例子中为 pktsize_parse函数,之前我们已经分析过如何调用到某一个match的parse函数.主要解析ipt_entry_match里data(其实就是解析命令参数赋值给它)
除了parse函数还有options,即解析–XXX的参数需要用到的东西,也需要我们去填写。

下面看看内核部分:
xt_pktsize.h

xt_pktsize.c

这里我们计算ip报文的有效载荷的长度即ip包的总长度-ip头的长度
size=ntohs(iph->tot_len) – (iph->ihl*4);
同样或许我们还需要判断协议类型 protocal字等,简单说几个常用:
Decimal  Keyword          Protocol                                 References
——-  —————  —————————————  ——————
1        ICMP             Internet Control Message                 [RFC792]
6        TCP              Transmission Control                     [RFC793]
17       UDP              User Datagram                            [RFC768][JBP]

ip报文格式如下:

版本:占4位(bit),指IP协议的版本号。目前的主要版本为IPV4,即第4版本号,也有一些教育网和科研机构在使用IPV6。在进行通信时,通信双方的IP协议版本号必须一致,否则无法直接通信。
首部长度:占4位(bit),指IP报文头的长度。最大的长度(即4个bit都为1时)为15个长度单位,每个长度单位为4字节(TCP/IP标准,DoubleWord),所以IP协议报文头的最大长度为60个字节,最短为上图所示的20个字节。
服务类型:占8位(bit),用来获得更好的服务。其中的前3位表示报文的优先级,后面的几位分别表示要求更低时延、更高的吞吐量、更高的可靠性、更低的路由代价等。对应位为1即有相应要求,为0则不要求。
总长度:16位(bit),指报文的总长度。注意这里的单位为字节,而不是4字节,所以一个IP报文的的最大长度为65535个字节。
标识(identification):该字段标记当前分片为第几个分片,在数据报重组时很有用。
标志(flag):该字段用于标记该报文是否为分片(有一些可能不需要分片,或不希望分片),后面是否还有分片(是否是最后一个分片)。
片偏移:指当前分片在原数据报(分片前的数据报)中相对于用户数据字段的偏移量,即在原数据报中的相对位置。
生存时间:TTL(Time to Live)。该字段表明当前报文还能生存多久。每经过1ms或者一个网关,TTL的值自动减1,当生存时间为0时,报文将被认为目的主机不可到达而丢弃。使用过Ping命令的用户应该有印象,在windows中输入ping命令,在返回的结果中即有TTL的数值。
协议:该字段指出在上层(网络7层结构或TCP/IP的传输层)使用的协议,可能的协议有UDP、TCP、ICMP、IGMP、IGP等。
首部校验和:用于检验IP报文头部在传播的过程中是否出错,主要校验报文头中是否有某一个或几个bit被污染或修改了。
源IP地址:32位(bit),4个字节,每一个字节为0~255之间的整数,及我们日常见到的IP地址格式。
目的IP地址:32位(bit),4个字节,每一个字节为0~255之间的整数,及我们日常见到的IP地址格式。

当然对ip理解的越深刻越好了,那么这样就完成了一个简单的match扩展的例子,仅仅作为抛砖引玉,一个小小的开始.

1 1 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部